# Managing Multiple MCP Server Tools in a Single Server: A Complete Guide

> Learn to manage multiple MCP server tools on one server using a shared FastMCP instance. Discover and invoke capabilities through a single endpoint with this complete guide.

- Repository: [CSK/mcp-wordle-python](https://github.com/cr2007/mcp-wordle-python)
- Tags: how-to-guide
- Published: 2026-02-28

---

**You can host unlimited MCP tools on a single server by registering them to a shared FastMCP instance, allowing clients to discover and invoke multiple capabilities through one endpoint.**

The **cr2007/mcp-wordle-python** repository demonstrates this pattern by implementing a lightweight MCP server that exposes Wordle puzzle data alongside extensible tool registration. By leveraging the **FastMCP** library, developers can consolidate multiple services—read-only queries, data transformations, and external API calls—within a single Python runtime.

## Understanding the FastMCP Architecture

### The FastMCP Instance as Central Dispatcher

At the heart of multi-tool management lies the **FastMCP** class, which acts as a central dispatcher for tool registration and request routing. In [`src/mcp_wordle/main.py`](https://github.com/cr2007/mcp-wordle-python/blob/main/src/mcp_wordle/main.py), the server initializes a single instance that coordinates all subsequent tool definitions:

```python
from fastmcp import FastMCP

mcp = FastMCP("WordleMCP")

```

This instance, named `WordleMCP`, maintains an internal registry of available tools. When an MCP-compatible client (such as Claude Desktop) connects, it queries this registry to discover all exposed capabilities, enabling multiple tools to coexist under one server identity.

### Tool Registration via Decorators

The `@mcp.tool()` decorator transforms Python coroutines into discoverable MCP tools. The Wordle server registers its primary functionality—fetching puzzle solutions—using this pattern in [`src/mcp_wordle/main.py`](https://github.com/cr2007/mcp-wordle-python/blob/main/src/mcp_wordle/main.py):

```python
@mcp.tool(
    name="get_wordle_solution",
    description="Fetches the Wordle solution for a specific date.",
)
async def get_wordle_data(target_date: str) -> dict:
    # Implementation details...

```

Metadata parameters like `name`, `description`, and hints (e.g., `readOnlyHint`) provide clients with semantic context. This declarative approach allows you to register dozens of tools without modifying server infrastructure—simply add new decorated functions to the same file.

## Implementing Multiple Tools in One Server

### Adding a Second Tool to the Wordle Server

To demonstrate extensibility, you can register additional tools alongside the existing Wordle fetcher. The following example adds an echo utility to [`src/mcp_wordle/main.py`](https://github.com/cr2007/mcp-wordle-python/blob/main/src/mcp_wordle/main.py), sharing the same FastMCP instance:

```python
@mcp.tool(
    name="echo_message",
    description="Returns the same string that was sent, useful for testing.",
)
async def echo(message: str) -> str:
    return message

```

Because both tools attach to the `mcp` instance, clients receive a unified tool catalog containing `get_wordle_solution` and `echo_message`. The FastMCP runtime handles routing each invocation to the appropriate coroutine based on the tool name specified in client requests.

### Type Safety with TypedDict Definitions

Robust multi-tool servers require strict type contracts to prevent runtime errors. The Wordle repository defines **TypedDict** structures in [`src/mcp_wordle/main.py`](https://github.com/cr2007/mcp-wordle-python/blob/main/src/mcp_wordle/main.py) to validate API responses:

```python
from typing import TypedDict

class WordleAPIData(TypedDict):
    solution: str
    print_date: str
    days_since_launch: int
    editor: str

class WordleError(TypedDict):
    error: str

```

These definitions ensure that `get_wordle_solution` returns predictable structures, while allowing other tools in the same server to define their own TypedDict contracts. Type safety becomes critical when managing multiple tools, as it prevents cross-tool contamination of data schemas.

## Deployment Strategies for Multi-Tool Servers

### Docker Containerization

Containerizing multi-tool MCP servers enables horizontal scaling and environment consistency. The repository provides a **Dockerfile** that packages the FastMCP application:

```dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY . .
RUN pip install -e .
CMD ["python", "-m", "mcp_wordle"]

```

When building multi-tool deployments, you can extend this base image to include additional tool modules. A Docker Compose configuration orchestrates multiple MCP servers on the same host, each exposing distinct toolsets:

```yaml
services:
  wordle:
    image: ghcr.io/cr2007/mcp-wordle-python:latest
    environment:
      - DOCKER_CONTAINER=true

  another-mcp:
    build: ./another-mcp
    depends_on:
      - wordle

```

### UVX Quick Deployment

For rapid prototyping, the **uvx** package manager allows zero-installation execution of MCP servers. The repository supports this pattern via [`pyproject.toml`](https://github.com/cr2007/mcp-wordle-python/blob/main/pyproject.toml) configuration:

```bash
uvx mcp-wordle-python

```

This command downloads and executes the server without permanent installation, ideal for testing multi-tool configurations. When managing multiple servers, you can chain uvx commands or configure Claude Desktop's `mcpServers` settings to point to various uvx invocations, effectively running disparate tool collections within isolated processes.

## Summary

- **FastMCP instances** serve as centralized registries for multiple tools, enabling single-server deployment of diverse capabilities.
- The **`@mcp.tool()` decorator** registers Python functions as discoverable endpoints, supporting unlimited tool additions without infrastructure changes.
- **TypedDict definitions** enforce type safety across multiple tools, preventing schema conflicts in shared servers.
- **Docker and uvx** provide flexible deployment paths for multi-tool architectures, from containerized clusters to lightweight process isolation.

## Frequently Asked Questions

### How many tools can a single MCP server host?

A single FastMCP instance can host **unlimited tools** limited only by system resources and Python's concurrency model. Each tool registered via `@mcp.tool()` consumes minimal memory overhead, allowing production servers to expose dozens of endpoints—from data queries to computational utilities—within one process.

### Can I mix read-only and write tools in the same server?

Yes, FastMCP supports heterogeneous tool types in one registry. You can combine **read-only** tools (marked with `readOnlyHint=True`) like the Wordle fetcher with **mutating** tools that modify external state. The MCP protocol handles permission scopes at the client level, while the server simply exposes available capabilities.

### How do clients distinguish between tools on the same server?

Clients receive a **tool catalog** upon connection containing unique names and descriptions for each registered tool. When invoking `get_wordle_solution` versus `echo_message`, the client specifies the exact tool name in the request payload, and FastMCP routes execution to the corresponding Python coroutine automatically.

### Is FastMCP the only library for building multi-tool MCP servers?

While **FastMCP** is the dominant Python SDK for MCP implementations, the protocol itself is language-agnostic. Alternative implementations exist for TypeScript, Rust, and Go. However, FastMCP's decorator-based registration and automatic type inference make it the most ergonomic choice for Python developers building multi-tool servers.