MCP and client tools
Connect Letta Agent SDK sessions to stdio, HTTP, and SSE MCP servers
The Agent SDK can expose two kinds of tools through your Node.js process:
- Client tools are JavaScript functions supplied through
toolsand executed by the SDK host. - MCP tools are discovered from servers supplied through
mcpServersand proxied by the SDK host to the MCP server.
Both are scoped to the SDK session and use the same external-tool protocol. They are not persisted on the Letta agent: their implementations, processes, credentials, and filesystem access belong to the application hosting the session.
Configure MCP servers
Section titled “Configure MCP servers”Pass MCP servers by name when creating or resuming a session. The SDK supports local stdio processes, Streamable HTTP, and legacy SSE:
import { LettaAgentClient } from "@letta-ai/letta-agent-sdk";
const client = new LettaAgentClient({ backend: "cloud", apiKey: process.env.LETTA_API_KEY,});
await using session = client.resumeSession("agent-123", { mcpServers: { filesystem: { command: "npx", args: ["-y", "@modelcontextprotocol/server-filesystem", process.cwd()], }, exa: { type: "http", url: "https://mcp.exa.ai/mcp", }, github: { type: "http", url: "https://api.githubcopilot.com/mcp/", headers: { Authorization: `Bearer ${process.env.GITHUB_TOKEN}`, }, }, legacy: { type: "sse", url: "https://example.com/sse", }, },});The object key becomes the server name. Discovered tools use this namespace:
mcp__<server>__<tool>For example, Exa may expose mcp__exa__web_search_exa and mcp__exa__web_fetch_exa.
Connections start concurrently during session initialization. One unavailable server does not prevent healthy servers from connecting.
Combine MCP and client tools
Section titled “Combine MCP and client tools”Use tools and mcpServers together when some capabilities are application functions and others come from MCP:
import { type AnyAgentTool, LettaAgentClient } from "@letta-ai/letta-agent-sdk";
const lookupCustomer = { name: "lookup_customer", label: "Look up customer", description: "Fetch a customer record from the application database.", parameters: { type: "object", properties: { customerId: { type: "string" }, }, required: ["customerId"], }, async execute(_toolCallId, input, signal) { const { customerId } = input as { customerId: string }; const response = await fetch( `https://internal.example.com/customers/${customerId}`, { signal }, );
if (!response.ok) { return { isError: true, content: [ { type: "text" as const, text: `Customer lookup failed: ${response.status}`, }, ], }; }
const customer = await response.json(); return { content: [ { type: "text" as const, text: JSON.stringify(customer), }, ], details: customer, }; },} satisfies AnyAgentTool;
const client = new LettaAgentClient({ backend: "cloud", apiKey: process.env.LETTA_API_KEY,});
await using session = client.resumeSession("agent-123", { tools: [lookupCustomer], mcpServers: { exa: { type: "http", url: "https://mcp.exa.ai/mcp", }, }, allowedTools: ["lookup_customer", "mcp__exa__*", "Read", "Grep"],});
await session.send( "Look up customer cust_123 and research recent news about their company.",);
for await (const message of session.stream()) { if (message.type === "assistant") console.log(message.content);}allowedTools is an availability filter in the Letta Agent SDK. If you provide it, include every client, MCP, and built-in tool the session should expose. If you omit it, registered client and MCP tools remain available alongside the harness defaults.
MCP allowlist entries support server-scoped wildcards such as mcp__exa__*. Client tools use their exact names.
Authentication
Section titled “Authentication”Supply bearer tokens or other remote credentials through headers:
mcpServers: { internal: { type: "http", url: "https://mcp.example.com/mcp", headers: { Authorization: `Bearer ${process.env.MCP_ACCESS_TOKEN}`, "X-Organization": process.env.MCP_ORGANIZATION_ID!, }, },}The Agent SDK does not open an interactive OAuth browser flow. Complete OAuth in your host application and pass the resulting access token to the session. Keep credentials in environment variables or a secret manager rather than source code.
Execution and lifecycle
Section titled “Execution and lifecycle”MCP connections and client tools run in the SDK’s Node.js process, including for Cloud and remote sessions. This has several consequences:
- A stdio filesystem server sees the SDK host filesystem, not a managed Cloud sandbox.
- Local executables and environment variables must exist on the SDK host.
- Different sessions on the same persistent agent may use different MCP servers and credentials.
- Closing or asynchronously disposing the session closes all of its MCP connections and child processes.
Use await using so asynchronous MCP shutdown completes before the surrounding scope exits:
await using session = client.resumeSession(agentId, { mcpServers,});
await session.send("Complete the task using the configured tools.");for await (const message of session.stream()) { // Handle streamed messages.}MCP requires the Node.js package entry point. It is not available from the portable @letta-ai/letta-agent-sdk/client entry point used by browser and React Native applications.