How to Intermediate · 3 min read

How to build a multi-tool MCP server

Quick answer
Use the official mcp Python SDK to create a multi-tool MCP server by registering multiple tools and exposing them via the Server class. The server can be run with stdio_server for standard I/O communication, enabling AI agents to access various tools seamlessly.

PREREQUISITES

  • Python 3.8+
  • pip install mcp
  • Basic knowledge of Python async programming

Setup

Install the official mcp Python SDK and prepare your environment to build the MCP server.

bash
pip install mcp

Step by step

Create a multi-tool MCP server by defining multiple tool handlers and registering them with the Server class. Use stdio_server to run the server over standard input/output, which is the common transport for MCP servers.

python
import asyncio
from mcp.server import Server
from mcp.server.stdio import stdio_server

# Define async tool handlers
async def tool_one(params):
    # Example tool logic
    return {"result": f"Tool One received: {params.get('input', '')}"}

async def tool_two(params):
    # Another tool logic
    return {"result": f"Tool Two processed: {params.get('input', '')}"}

async def main():
    # Create MCP server instance
    server = Server()

    # Register multiple tools
    server.register_tool("tool_one", tool_one)
    server.register_tool("tool_two", tool_two)

    # Run the server using stdio transport
    await stdio_server(server)

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

Common variations

You can run the MCP server with different transports like SSE or TCP, or implement synchronous tool handlers if needed. Also, you can extend the server to handle authentication or logging.

python
import asyncio
from mcp.server import Server
from mcp.server.stdio import stdio_server

# Synchronous tool example
def sync_tool(params):
    return {"result": f"Sync tool got: {params.get('input', '')}"}

async def main():
    server = Server()
    # Register sync tool (wrap with async)
    server.register_tool("sync_tool", lambda params: asyncio.to_thread(sync_tool, params))
    await stdio_server(server)

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

Troubleshooting

  • If the server does not respond, ensure you run it with proper stdio pipes or use a compatible client.
  • For import errors, verify mcp is installed in your Python environment.
  • If tools do not register, confirm you call register_tool before starting the server.

Key Takeaways

  • Use the official mcp Python SDK to build multi-tool MCP servers efficiently.
  • Register each tool with Server.register_tool before running the server.
  • Run the server with stdio_server for standard I/O communication.
  • Async tool handlers are preferred but synchronous tools can be wrapped with asyncio.to_thread.
  • Troubleshoot by verifying environment setup and transport compatibility.
Verified 2026-04
Verify ↗