Skip to content

Connect: Letta

Recipe · through our MCP server · their docs checked 2026-10-30

Letta is a server platform. You register our MCP URL once; Letta's server then forwards each tool call to us. Letta's own sandbox cannot run our executor, so do not paste our tools in as Letta "server tools".

Our side

Letta Cloud, or a Letta server on another host, reaches us over the network, so serve the public app with the hosted registry:

def public_app(tools: Registry, host: str, agent_token: str, reviewer_token: str) -> Any:
    """REST at /, MCP at /mcp, one bearer check for both: for a host on the internet."""
    from mcp.server.transport_security import TransportSecuritySettings

    from agent_adapter.server import create_app

    tokens = {
        agent_token: Principal("hosted-agent"),  # the token the remote framework sends
        reviewer_token: Principal("reviewer@example.com", scopes=frozenset({APPROVER_SCOPE})),
    }
    security = TransportSecuritySettings(allowed_hosts=[host], allowed_origins=[f"https://{host}"])
    return create_app(
        tools,
        authenticate=bearer_auth(tokens),
        host="0.0.0.0",  # a public bind: the public-host checks apply
        allowed_hosts=[host],  # REST: any other Host header gets 421
        mcp_options={"transport_security": security},  # MCP: the same rule
    )


hosted = registry.subset(tags=["hosted"])  # no confirm tools: hosted runtimes cannot resume them

Serve public_app(hosted, host, agent_token, reviewer_token).

Their side

Python SDK (letta-client):

server = client.mcp_servers.create(
    server_name="shop_tools",
    config={
        "mcp_server_type": "streamable_http",
        "server_url": "https://tools.example.com/mcp",
        "auth_header": "Authorization",
        "auth_token": "Bearer <AA_AGENT_TOKEN>",
    },
)
tools = client.mcp_servers.list_tools(server.id)
agent = client.agents.create(tool_ids=[tool.id for tool in tools], ...)

TypeScript SDK: client.mcpServers.create({ server_name, config: { … } }) with the same config keys, then client.mcpServers.listTools(server.id).

Key Meaning
mcp_server_type: "streamable_http" our transport
server_url our /mcp endpoint
auth_header, auth_token the header name and its full value (Bearer …)
tool_ids on agents.create which of the listed tools the agent may call

Letta adds an x-agent-id header to each call. It is not auth: our principal comes from the bearer token only.

Checklist

Check Why
serve hosted, or leave confirm tools out of tool_ids Letta does not send our resume keys back
one token per Letta deployment one principal per tenant
a self-hosted Letta in Docker still uses public_app a container is not loopback: local_app refuses it
everything on the public-host checklist

Sources