Model Context Protocol (MCP)

Agent Substrate includes native client and server integration for the Model Context Protocol (MCP) via the mcp extra (uv sync --extra mcp).


Connecting External MCP Servers

Any Model Context Protocol server (GitHub, PostgreSQL, Slack, Brave Search, etc.) can be discovered dynamically and attached to an agent as first-class tools:

python
import asyncio
from substrate.agents import ReActAgent
from substrate.integrations.tools.mcp import MCPClient, MCPTool
from substrate.runtime import Runtime
from substrate.tools import ToolRisk

async def main() -> None:
    # 1. Connect via stdio or SSE transport
    client = MCPClient()
    await client.connect_stdio(
        command="npx",
        args=["-y", "@modelcontextprotocol/server-github"],
        env={"GITHUB_PERSONAL_ACCESS_TOKEN": "ghp_..."}
    )
    # Over the network, connect via SSE:
    # await client.connect_sse(url="http://mcp-server.internal:8000/sse")

    try:
        # 2. Discover tools and declare safety risk defaults
        tools = await MCPTool.from_mcp_client(client, risk=ToolRisk.SAFE, idempotent=True)
        print("Discovered MCP tools:", [t.name for t in tools])

        # 3. Mount tools to an agent definition
        agent = ReActAgent(
            "github_assistant",
            model=my_chat_model,
            tools=tools,
            system_instructions="You are a repository management assistant.",
        )

        async with Runtime.open("./.substrate") as runtime:
            outcome = await runtime.run(agent, "List open pull requests with label 'bug'.")
            print(outcome.output)
    finally:
        await client.disconnect()

if __name__ == "__main__":
    asyncio.run(main())

Risk & Idempotency Guarantees

Because remote MCP servers execute code outside your application process:

  • By default, discovered MCP tools are assigned risk=ToolRisk.HIGH and idempotent=False unless explicitly overridden.
  • When risk=ToolRisk.HIGH, the Substrate runtime automatically pauses execution and awaits human confirmation before sending commands to the remote server.
  • Remote tools that are pure queries can safely be marked idempotent=True and concurrency_safe=True to allow concurrent execution during multi-tool turns.
Was this page helpful?