Integrations

Use a tool server as your CRM or calendar

When your CRM or calendar vendor offers an MCP server instead of an API: map each step the assistant takes to one of its tools, prove it, and point a playbook at it.

Many CRM and calendar vendors now ship an MCP server before, or instead of, a documented API. If AnswerStack has no connector for your system but its vendor has an MCP server, you can use that server as your CRM, your calendar, or both.

You tell AnswerStack which of the server's tools does each step the assistant takes, such as "find a caller" or "book a meeting", and where the values go in and come out. AnswerStack then calls those tools at the same fixed moments it would call WelcomeHome. The assistant never sees these tools and never decides to use them.

Only owners and admins can set this up.

Before you start#

  1. Add the vendor's server under Tools and approve the tools you will use. See Add tool servers. A server from the AnswerStack catalog arrives with its tools approved.
  2. Have the vendor's description of each tool to hand: what it takes and what it answers. The server's page under Tools shows both.

Map each step#

On Connections, find A tool server under Add a connection and press Use a tool server. Give the connection a name and pick the Tool server.

Tick each step the server can do, pick the approved tool for it, and fill in its Arguments and its Answer.

StepRoleArguments can readThe answer gives
Find a callerCRM$.phone, $.email, $.locationIdid (required), displayName, firstName, lastName, stage, status
Save a contactCRM$.contactId, $.caller.firstName, $.caller.lastName, $.caller.phone, $.caller.email, $.source.callIdcontactId (required), created
Log a callCRM$.contactId, $.event.callId, $.event.summary, $.event.outcome, $.event.durationSecondsactivityId
Read a contact's historyCRM, optional$.contactId, $.lookbackDaysitems: a list of kind, occurredAt, summary
Create a follow-up taskCRM, optional$.contactId, $.title, $.notes, $.dueAttaskId
Find open timesCalendar$.from, $.to, $.timeZone, $.durationMinutes, $.locationIdslots (required): a list of start, end, staffId
Book a meetingCalendar$.contactId, $.slot.start, $.slot.end, $.meetingType, $.notesconfirmationId (required)
Cancel a bookingCalendar, optional$.contactId, $.confirmationIdNothing

The mapping decides the role. Map Find a caller, Save a contact and Log a call and the connection can be your CRM. Map Find open times and Book a meeting and it can be your calendar. Map all five for both.

How the mapping is written#

Both fields are small JSON objects.

Arguments name the tool's own fields. Each value is either a $.path into what AnswerStack is passing for that step (the "Arguments can read" column), or a literal: text that does not start with $, a number, true, false or null.

Answer names the fields AnswerStack needs. Each value is a $.path into the tool's structured answer. For a list, use { "each": "$.path to the list", "fields": { ... } }, where the paths inside fields start from each item.

Paths are simple: $.a, $.a.b, $.results[0].id.

A worked example#

Say the vendor's search_people tool takes phone_number and email_address and answers { "people": [{ "person_id": "p_81", "full_name": "Ruth Alvarez" }] }. Find a caller is:

json
{
  "args": { "phone_number": "$.phone", "email_address": "$.email" },
  "result": { "id": "$.people[0].person_id", "displayName": "$.people[0].full_name" }
}

Put the args object in Arguments and the result object in Answer. Here is the rest of a CRM and calendar mapping, as the API stores it. upsertContact is Save a contact, logCallEvent is Log a call, getSlots is Find open times and createBooking is Book a meeting:

json
{
  "upsertContact": {
    "tool": "save_person",
    "args": {
      "person_id": "$.contactId",
      "first_name": "$.caller.firstName",
      "last_name": "$.caller.lastName",
      "phone_number": "$.caller.phone",
      "email_address": "$.caller.email",
      "lead_source": "AI phone assistant"
    },
    "result": { "contactId": "$.person_id", "created": "$.was_created" }
  },
  "logCallEvent": {
    "tool": "add_activity",
    "args": { "person_id": "$.contactId", "type": "call", "notes": "$.event.summary" },
    "result": { "activityId": "$.activity_id" }
  },
  "getSlots": {
    "tool": "list_openings",
    "args": {
      "location": "$.locationId",
      "from": "$.from",
      "to": "$.to",
      "minutes": "$.durationMinutes"
    },
    "result": {
      "slots": {
        "each": "$.openings",
        "fields": { "start": "$.starts_at", "end": "$.ends_at", "staffId": "$.host_id" }
      }
    }
  },
  "createBooking": {
    "tool": "book_opening",
    "args": { "person_id": "$.contactId", "starts_at": "$.slot.start", "ends_at": "$.slot.end" },
    "result": { "confirmationId": "$.booking.reference" }
  }
}

"type": "call" and "lead_source": "AI phone assistant" are literals, sent as they are. An open time without both a start and an end is ignored.

Save it: the checks#

Press Check and save. Before anything is saved, AnswerStack runs checks that only read:

  • the server answers, and every tool in the mapping is approved and unchanged since;
  • as a CRM, a made-up caller finds no contact (a mapping that matches everyone fails here);
  • as a calendar, open times come back in the right shape.

If a check fails, nothing is saved and the dialog says which one and why. On success, the connection can be picked as a CRM or calendar in a playbook.

The guided test#

The checks cannot prove the steps that write. On the connection's card, press Run the guided test. The dialog says exactly what it will do, and nothing happens until you press Run the test.

It writes to your real system: it creates a contact named AnswerStack Test and, for a calendar, books the first open time and cancels it again. Each step is listed as passed or failed. Delete the test contact afterwards. If no step cancels bookings, cancel the test booking by hand.

Templates from the AnswerStack catalog#

For some catalog servers, AnswerStack publishes a ready-made mapping. Pick such a server and the steps fill themselves in: Filled in from the template published for this server. Check it, then save.

Use it#

Open your playbook's CRM & calendar tab and choose the connection for CRM, Calendar for booking, or both. Publish. See Connect WelcomeHome for what happens at each moment of a call; it is the same here.

Change the mapping on the card edits it. One mapping serves every playbook that uses the connection.

When something goes wrong#

A failure here is treated like any CRM or calendar outage. The call carries on: if the assistant cannot book, it takes a callback, and writes such as the call log are retried after the call. Every write carries a key, so a retry never saves a contact or books a meeting twice.

If the vendor changes a tool the mapping uses, the tool stops running until someone approves the new version under Tools, and the connection's checks fail until then.

When a tool reports an error, it can say which kind by returning code (or error.code) in its answer: conflict (for example, the time was just taken), not_found, validation, rate_limited (retried), unauthorized or forbidden. Anything else counts as the system being unavailable.