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¶
- Letta, connecting remote MCP servers: https://docs.letta.com/guides/mcp/sse
- Letta, MCP setup: https://docs.letta.com/guides/mcp/setup
- Letta, tool execution: https://docs.letta.com/guides/agents/tool-execution-overview