Overview
LiveKit Agents has first-class support for Model Context Protocol (MCP) servers.
To use MCP, install the optional dependencies:
uv add livekit-agents[mcp]~=1.5
Wrap an MCP server in an MCPToolset and pass it to the agent's tools parameter:
from livekit.agents import Agent, mcpclass MyAgent(Agent):def __init__(self):super().__init__(instructions="You are a helpful assistant.",tools=[mcp.MCPToolset(id="my-mcp-server",mcp_server=mcp.MCPServerHTTP("https://your-mcp-server.com/mcp"),)],)
The mcp_servers parameter on AgentSession and Agent is deprecated and will be removed in a future version. Use MCPToolset in the tools parameter instead. When mcp_servers is used, the SDK auto-generates toolset IDs that aren't stable across sessions, so switching to explicit MCPToolset gives you predictable IDs.
HTTP servers
Use MCPServerHTTP to connect to a remote MCP server over HTTP:
from livekit.agents import AgentSession, mcpsession = AgentSession(# ... other arguments ...tools=[mcp.MCPToolset(id="my-api",mcp_server=mcp.MCPServerHTTP("https://your-mcp-server.com/tools",transport_type="streamable_http",),)],)
The transport type is auto-detected from the URL path: URLs ending in /mcp use streamable HTTP transport, and URLs ending in /sse use Server-Sent Events transport. To override auto-detection, pass transport_type explicitly as shown above.
Local servers (stdio)
Use MCPServerStdio to launch a local MCP server process and communicate over stdin/stdout. This is useful for MCP servers distributed as CLI tools:
from livekit.agents import AgentSession, mcpsession = AgentSession(# ... other arguments ...tools=[mcp.MCPToolset(id="filesystem",mcp_server=mcp.MCPServerStdio(command="npx",args=["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"],),)],)
The env and cwd parameters let you customize the child process environment and working directory.
Authentication
Pass authentication headers to an MCP server with the headers parameter:
import osfrom livekit.agents import AgentSession, mcpsession = AgentSession(# ... other arguments ...tools=[mcp.MCPToolset(id="zapier",mcp_server=mcp.MCPServerHTTP("https://actions.zapier.com/mcp/sse",headers={"Authorization": f"Bearer {os.environ['ZAPIER_API_KEY']}"},),)],)
Filtering tools
Limit which tools from an MCP server are exposed to the LLM. Use server-level filtering when you know the exact tool names, or toolset-level filtering when you need to inspect tools after they load.
Server-level filtering
Use the allowed_tools parameter on the MCP server to filter by tool name. Tools not in the list are excluded.
The following example creates an MCPToolset, wrapping MCPServerHTTP with allowed_tools=["search_products", "get_product_details"]. Only those two tools are available, and everything else the server exposes is excluded.
from livekit.agents import AgentSession, mcpsession = AgentSession(# ... other arguments ...tools=[mcp.MCPToolset(id="products",mcp_server=mcp.MCPServerHTTP("https://your-mcp-server.com/mcp",allowed_tools=["search_products", "get_product_details"],),)],)
Toolset-level filtering
Use MCPToolset.filter_tools() for more control. It accepts a predicate function and filters tools in-place after setup.
The following example creates an MCPToolset, manually calls setup() to connect and fetch tools, then calls filter_tools() with a lambda that only keeps tools with IDs containing "search".
from livekit.agents import mcptoolset = mcp.MCPToolset(id="my-api",mcp_server=mcp.MCPServerHTTP("https://your-mcp-server.com/mcp"),)# When using outside of AgentSession, call setup() manuallyawait toolset.setup()toolset.filter_tools(lambda tool: "search" in tool.id)
Transforming tool results
Use the tool_result_resolver parameter to transform MCP tool results before they reach the LLM. The resolver receives an MCPToolResultContext with tool_name, arguments, and result. It can be sync or async.
By default, the SDK serializes content items to JSON. This example truncates large results instead:
import jsonfrom livekit.agents import mcpMAX_CHARS = 4000async def truncating_resolver(ctx: mcp.MCPToolResultContext) -> str:"""Truncate large MCP tool results to avoid excessive LLM context usage."""if len(ctx.result.content) == 1:text = str(ctx.result.content[0].model_dump_json())elif len(ctx.result.content) > 1:text = json.dumps([item.model_dump() for item in ctx.result.content])else:return "Tool returned no content."if len(text) > MAX_CHARS:text = text[:MAX_CHARS] + "\n... [truncated]"return textsession = AgentSession(# ... other arguments ...tools=[mcp.MCPToolset(id="my-api",mcp_server=mcp.MCPServerHTTP("https://your-mcp-server.com/mcp",tool_result_resolver=truncating_resolver,),)],)
The resolver is available on all MCP server types and is only called for successful tool calls. Errors raise a ToolError before the resolver runs.
Per-tool options
MCPToolset is an async toolset, so you can configure individual MCP tools the same way you configure a function tool. Pass tool_options, a dictionary keyed by tool name, with an MCPToolOptions value for each tool you want to configure. Tools you don't list run as plain blocking calls.
The following example makes a long-running book_flight tool cancellable, requires confirmation before a duplicate call runs, and forwards the server's progress notifications to the user:
from livekit.agents import AgentSession, mcpfrom livekit.agents.llm import ToolFlagsession = AgentSession(# ... other arguments ...tools=[mcp.MCPToolset(id="mcp",mcp_server=mcp.MCPServerHTTP("https://your-mcp-server.com/mcp",# book_flight runs longer than the default per-request timeout.client_session_timeout_seconds=120,),tool_options={"book_flight": mcp.MCPToolOptions(flags=ToolFlag.CANCELLABLE,on_duplicate="confirm",report_progress=True,),},)],)
MCPToolOptions accepts three independent options:
flagsToolFlagDefault: ToolFlag.NONETool flags, mirroring the @function_tool decorator. Use ToolFlag.CANCELLABLE to let the LLM cancel the tool while it runs, or ToolFlag.IGNORE_ON_ENTER to skip the tool during on_enter.
When any tool is ToolFlag.CANCELLABLE, the lk_agents_get_running_tasks and lk_agents_cancel_task tools are automatically exposed to the LLM so it can list and cancel running calls. See Cancellation for details.
on_duplicateDuplicateModeDefault: allowControls how duplicate calls to a running tool are handled. Valid values are: allow, reject, replace, or confirm. Uses the same values as the @function_tool decorator. To learn more, see Duplicate-call handling.
report_progressboolDefault: FalseWhen true, forwards the MCP server's report_progress notifications to ctx.update(). The tool runs in the background so the agent can narrate progress while it works. See Progress updates.
For a complete example, including an MCP server that emits progress notifications, see examples/voice_agents/mcp/ .
Multiple servers
Pass multiple MCPToolset instances in the tools list. You can combine different server types, and all servers are initialized in parallel:
from livekit.agents import AgentSession, mcpsession = AgentSession(# ... other arguments ...tools=[mcp.MCPToolset(id="api-server",mcp_server=mcp.MCPServerHTTP("https://api.example.com/mcp"),),mcp.MCPToolset(id="filesystem",mcp_server=mcp.MCPServerStdio(command="npx",args=["-y", "@modelcontextprotocol/server-filesystem", "/data"],),),],)
If an individual server fails to connect, the error is logged but does not prevent the agent from starting.
Combining MCP tools with function tools
Your agent can use both MCP-provided tools and locally defined function tools. Pass them together in the tools list.
In the following example, the LLM can call both the MCP server's tools and the save_note function tool.
from livekit.agents import Agent, function_tool, RunContext, mcpclass MyAgent(Agent):def __init__(self):super().__init__(instructions="You are a helpful assistant with access to a knowledge base and local tools.",tools=[mcp.MCPToolset(id="knowledge-base",mcp_server=mcp.MCPServerHTTP("https://your-mcp-server.com/sse"),)],)@function_tool()async def save_note(self, context: RunContext, text: str) -> str:"""Save a note for the user.Args:text: The note content to save."""# your custom logic herereturn "Note saved successfully."
In this example, the LLM can call both the MCP server's tools and the save_note function tool.
Agent vs AgentSession placement
MCPToolset follows the same tools override pattern as other tools. If an Agent specifies tools, those tools replace (not merge with) any tools set on the AgentSession. The toolset lifecycle depends on where you place it. Agent toolsets close when switching to a different agent, and session toolsets close when the session ends. See Toolsets for details.
Set toolsets on the AgentSession for shared defaults across multiple agents in a workflow. Set toolsets on a specific Agent only when that agent needs a different set of tools. This is the same override pattern used by stt, llm, tts, and other agent properties.