Skip to main content
TurnCall supports the Model Context Protocol (MCP) for connecting agents to external tool servers. Tools are auto-discovered at call start via tools/list and registered alongside webhook and built-in tools.
For Slack and Google Calendar specifically, the Agent Builder can handle the authorization for you and run an action after a call ends — see Connected apps. Everything below is the manual path, and stays the escape hatch for anything else.

Configuration

Add mcp_servers to your agent config:

Transport Types

Server Config Fields

How It Works

1

Call starts

TurnCall connects to each configured MCP server.
2

Tool discovery

Calls tools/list on each server to discover available tools.
3

Registration

MCP tools are merged with webhook and built-in tools in the pipeline.
4

Execution

When the LLM calls an MCP tool, TurnCall routes it through the MCP client.
5

Cleanup

MCP sessions are cleaned up when the call ends.

stdio Transport

stdio transport requires MCP_STDIO_ENABLED=true and the command must be listed in MCP_STDIO_ALLOWED_COMMANDS.

Where MCP tools are available

MCP servers are connected at the start of a voice call — Twilio, WebRTC and WhatsApp voice alike — and disconnected when it ends. Discovery adds one tools/list round trip per server to call setup, so keep timeout_seconds tight and use tool_filter to trim a large catalogue down to the handful the agent actually needs. MCP also works on the text channels — SMS, the Chat API and WhatsApp text — where servers are connected per inbound message and closed once the reply is sent.
That handshake is per message, not per conversation: every inbound text pays a connect plus tools/list for each server. It’s fine at SMS latencies, but it makes timeout_seconds and tool_filter matter more than they do on a voice call, where the cost is paid once at the start.

Server URLs are allowlisted

An MCP server URL is an outbound target chosen in the agent config and reached from inside your network, so it goes through the same allowlist as custom LLM and S2S gateway endpoints: BYOM_ALLOWED_URL_PATTERNS. An empty list allows everything, which keeps local development and a self-hosted server on the same docker network working. Set it in production:
A server whose URL is rejected is skipped with a logged error; the rest of the agent’s tools still load. stdio is gated separately by MCP_STDIO_ENABLED and MCP_STDIO_ALLOWED_COMMANDS.

Tool names must be unique

Tool names are advertised flat, so a name can only belong to one place. The precedence is: built-in, then the agent’s own tools, then MCP in server order. A discovered tool whose name is already taken is skipped and logged rather than shadowing the winner. A server may not claim a built-in name at all — end_call, transfer_call, handoff_to_agent, send_dtmf, do_not_call. Dispatch checks built-ins first, so an MCP tool called end_call would have been advertised to the model and then hung up the call instead of running. Two MCP servers exposing a common name — search, get — is the usual way this happens. Use tool_filter to keep each server to the tools you want, or rename on the server side.
handoff_to_agent moves the prompt and the agent’s own tools, but does not re-connect MCP servers: the sessions belong to the agent the call started as and stay open until it ends. If the target agent defines mcp_servers, those tools are unavailable for the rest of the call, and a warning is logged.

Limits

Custom webhook tools are capped the same way under their own TOOL_MAX_RESPONSE_BYTES. The per-server cap doesn’t compose — ten servers at it would put 500 tools in every request — so the total is the one that protects the context window. Servers are consumed in config order; once the total is reached, later ones contribute nothing. Discovery is also bounded in time. Past MCP_CONNECT_TIMEOUT_SECONDS the agent starts with no MCP tools at all rather than keeping the caller waiting — an unreachable server costs you its tools, never the call. A result over the size cap doesn’t reach the model. It gets a JSON error with a short preview of what the tool started to say, so it can narrow the request and try again rather than dying on context length.

SDK versions

TurnCall requires the 2.x line of the Python MCP SDK, mcp>=2.1.1,<3 — Pipecat 1.12’s mcp extra forces it, so 1.x is unreachable. Nothing about your agent config depends on the SDK version.
TurnCall briefly read both lines’ spellings of two renamed model fields (Tool.inputSchema, CallToolResult.isError). Those reads are gone: under the 2.x pin they could never match, and on 2.x the old names survive as pydantic aliases anyway. The reason they existed is worth knowing — reading only one spelling failed per tool, and server connection logs and continues per server, so the symptom was every MCP server returning no tools at all with nothing in the response to say why. An integration test opens a real server and calls a real tool over each transport — HTTP, SSE and stdio — precisely because a mocked test can’t see a field rename.