mcpServers and its tools join the
agent’s registry namespaced as <server>__<tool>.
Two shapes
- Remote (HTTP) —
{ url, headers?, oauth? }. This is what Google Docs, Slack, Notion and most Claude-style connectors are: a hosted MCP endpoint. - Local (stdio) —
{ command, args?, env? }. Community and in-house connectors shipped as npm packages:{ command: 'npx', args: ['-y', 'their-mcp-server'] }.
Auth
- OAuth connectors (Slack, Google Docs, Notion): set
oauthon the server entry. One operator signs the agent in once viaagent.oauth.mcpSignInUrl('slack'); the grant belongs to the app and every run reuses it. A tokenstoreoncreateAgentkeeps grants durable. - Token connectors (GitHub PAT, internal APIs): pass a static
Authorizationheader; keep the token in env, never in source. - stdio connectors: secrets go in
env, e.g.{ command: 'npx', args: [...], env: { GITHUB_TOKEN: process.env.GITHUB_TOKEN! } }.
Approval for connector writes
Reads should run free; writes should ask. MCP tools carryreadOnlyHint/destructiveHint annotations, and the default
approval: 'annotations' turns those into the SDK’s approval gate: a
slack.post_message pauses the run until approved, docs.get_document does
not. Tune it per server:
mcp.slack.* matchers apply to the namespaced tool names.
Try it offline
examples/connectors runs the whole pattern against a mock stdio MCP server (written withserveMcp) — fake docs_*/slack_*
tools, no credentials, real MCP round-trip. Swap the mcpServers entry for a
real endpoint and nothing else changes.
Serving your own connector
serveMcp() (see MCP) exposes an agent
or a set of defineTool() tools as a stdio/HTTP MCP server — that is how a
Lousho agent becomes a connector for Claude Code or another harness.