@MCP¶
Spec
Full specification: specs/mcp.md
· Item: AJ-7
Purpose¶
@MCP is a class decorator that declares one or more external MCP
servers an agent or workflow wants to consume. The decorated class is a
declaration, not a live object — no processes spawn, no connections
open at decoration time. Eager discovery happens at factory boot: the
framework spawns / connects each server once per process (shared pool),
discovers their tools, namespaces them as <server_key>__<tool_name>,
and injects them into every @Agent / @Workflow
that references the @MCP class via integrations=.
Reach for @MCP whenever your agent needs to talk to an existing MCP
ecosystem — GitHub, Linear, Stripe, internal company servers — instead
of hand-rolling each integration.
Signature¶
def MCP(
*,
servers: dict[str, ServerSpec] | list[ServerSpec],
auth: dict[str, AuthSpec] | None = None,
timeout: float = 30.0,
) -> Callable[[type[T]], type[T]]: ...
ServerSpec is str | MCPClient; AuthSpec is dict[str, Any].
Quick example¶
from ajolopy import Agent, MCP
@MCP(
servers={
"github": "stdio:npx -y @modelcontextprotocol/server-github",
"linear": "https://api.linear.app/mcp",
},
auth={
"github": {"env": {"GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"}},
"linear": {"token": "${LINEAR_API_KEY}"},
},
)
class Integrations: ...
@Agent(
model="claude-opus-4-7",
system="You are an engineering on-call assistant.",
integrations=[Integrations],
)
class OnCall:
"""Handle incidents: open Linear bugs, look up GitHub PRs, ..."""
Kwargs¶
| Kwarg | Type | Default | Description |
|---|---|---|---|
servers |
dict[str, ServerSpec] \| list[ServerSpec] |
required | Non-empty. Dict form recommended (keys = server_key for namespacing). |
auth |
dict[str, AuthSpec] \| None |
None |
Per-server auth dict. Keys must match servers=. ${ENV_VAR} substitution supported. |
timeout |
float |
30.0 |
Per-tool-call timeout in seconds. Connect / list-tools use a separate 10 s handshake budget. |
Escape hatches¶
- Custom transport. Subclass
MCPClient(the ABC), implementconnect/list_tools/call_tool/aclose, and pass an instance intoservers=. The framework uses your client verbatim; auth lives inside the instance. - List form for quick demos.
servers=["stdio:..."]auto-derives keysserver_0,server_1, ... — dict form is recommended for anything non-trivial. - Inspect the registry.
from ajolopy.mcp import get_mcp_registryexposesdiscovered_tools(),get_or_open(), andshutdown()for test setup and advanced introspection.
Common gotchas¶
- The
mcpSDK is an opt-in dependency.from ajolopy import MCPworks without it, but actually connecting raisesMCPDependencyError— install withpip install ajolopy[mcp]. - Unknown scheme prefixes (anything other than
stdio:,http://,https://,sse://,mcp+sse://) raiseMCPConfigErrorat decoration time. Pick a supported transport. - Per-server failures are isolated: a broken server logs a
WARNand contributes zero tools; the rest of the app boots normally. v0.1 does not auto-retry unhealthy servers —ajolopy doctor(AJ-40) surfaces them. - Local
@Toolmethods always win over MCP tools on a namespaced collision. The MCP tool is dropped at injection time with aWARN. ${VAR}substitutions resolve at boot time againstos.environ. Missing vars mark the server unhealthy (not a fatal error). Useajolopy env validateto catch them at deploy time.
See also¶
@Agent/@Workflow— the consumers of MCP tools viaintegrations=.@MCPServer— publish your own@Toolmethods as an MCP server.@Tool— local tools that coexist with MCP tools on the same agent.- Spec:
specs/mcp.md.