Building AI Agents from Scratch

Working with Multiple MCP Servers

Let one agent use several MCP servers without hard-coding every integration.

One server is one capability. A useful agent talks to a repo server, a ticket server, and a docs server. You do not merge those codebases. You load each server and namespace the tools.

A small catalog

SERVERS = [
    {"id": "hello", "command": ".venv/bin/python", "args": ["hello_server.py"]},
    {"id": "http", "command": ".venv/bin/python", "args": ["http_server.py"]},
]

all_tools = []
all_registry = {}
for spec in SERVERS:
    try:
        tools, registry = asyncio.run(load_mcp_tools(spec["command"], spec["args"]))
    except Exception as exc:
        print(f"skip {spec['id']}: {exc}")
        continue
    for advertised, (name, fn) in zip(tools, registry.items()):
        public = f"{spec['id']}_{name.removeprefix('mcp_')}"
        advertised["function"]["name"] = public
        advertised["function"]["description"] = f"[{spec['id']}] " + advertised["function"]["description"]
        all_registry[public] = fn
        all_tools.append(advertised)

Do not hard-code the product

  • A JSON or YAML list of servers is the integration surface — not a new Python module per vendor.
  • If a server is down at startup, skip it and log. The agent should still run with the others.
  • Cap how many tools you advertise (for example 20). Too many names and the model picks at random. See Designing MCP for AI.

Check it

Load two hello-style servers with different names. Ask a question that needs one ping from each. The log should show two prefixed tool names. Unplug one command path; startup should warn and the other server should still work. Next: treat tool output as hostile.