# Integrating External REST APIs into MCP Servers: A Complete Guide Using the Wordle MCP Server

> Integrate external REST APIs into MCP servers easily. Learn how to define FastMCP instances, register tools, and execute HTTP requests for real-time data retrieval with LLM clients.

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

---

**You can integrate any external REST API into an MCP server by defining a FastMCP instance, registering tools with the `@mcp.tool` decorator, and executing HTTP requests inside async functions, allowing LLM clients to invoke real-time data retrieval through standardized tool calls.**

Integrating external REST APIs into MCP servers enables LLM applications to access real-time data beyond their training cutoff. The `cr2007/mcp-wordle-python` repository demonstrates a production-ready pattern for connecting FastMCP-based servers to third-party HTTP endpoints. This guide walks through the exact implementation details, from dependency configuration to async request handling.

## FastMCP Server Configuration and Dependencies

Every MCP server starts with a FastMCP instance and proper dependency management. In [`src/mcp_wordle/main.py`](https://github.com/cr2007/mcp-wordle-python/blob/main/src/mcp_wordle/main.py) at line 13, the server initializes:

```python
mcp = FastMCP("WordleMCP")

```

The metadata and external dependencies are declared in [`fastmcp.json`](https://github.com/cr2007/mcp-wordle-python/blob/main/fastmcp.json), which specifies the entry point and required packages:

```json
{
  "dependencies": ["requests"]
}

```

When the container or `uvx` runner starts, FastMCP reads this configuration, installs the listed dependencies, and prepares the server for incoming tool invocations.

## Registering REST API Tools with @mcp.tool

Tools expose external APIs to LLM clients through decorated functions. The `@mcp.tool` decorator registers the callable as an MCP tool with specific metadata that helps the LLM decide when to invoke it.

In [`src/mcp_wordle/main.py`](https://github.com/cr2007/mcp-wordle-python/blob/main/src/mcp_wordle/main.py) lines 30-38, the Wordle solution fetcher is defined:

```python
@mcp.tool(
    name="get_wordle_solution",
    description=(
        "Fetches the Wordle of a particular date provided "
        "between 2021-05-19 to 23 days future"
    ),
    annotations={"readOnlyHint": True},
)
async def get_wordle_data(...):

```

### Tool Metadata Best Practices

The `name` parameter exposes the tool to clients, while `description` provides the semantic context for LLM routing. The `annotations` dictionary includes `"readOnlyHint": True` to indicate the tool does not modify server state, which optimizes client-side caching and permission handling.

## Implementing HTTP Requests in Async Tool Functions

The actual REST integration occurs inside the async tool function. In [`src/mcp_wordle/main.py`](https://github.com/cr2007/mcp-wordle-python/blob/main/src/mcp_wordle/main.py) lines 64-67, the implementation constructs the target URL from the user-provided date and executes the HTTP GET request:

```python
url = f"https://www.nytimes.com/svc/wordle/v2/{target_date}.json"
return requests.get(url, timeout=300).json()

```

The function returns the JSON response directly, letting FastMCP handle serialization back to the LLM client. This pattern is reusable for any REST endpoint—simply replace the URL construction and parsing logic while maintaining the async function signature.

## Running and Deploying the MCP Server

The server entry point follows standard Python conventions. Lines 70-71 in [`src/mcp_wordle/main.py`](https://github.com/cr2007/mcp-wordle-python/blob/main/src/mcp_wordle/main.py) contain the execution guard:

```python
if __name__ == "__main__":
    mcp.run()

```

This starts the FastMCP HTTP/WebSocket listener when launched via Docker, `uvx`, or direct Python execution.

### Local Testing with Python

For local validation, invoke the tool function directly:

```python
import asyncio
from src.mcp_wordle.main import get_wordle_data

async def demo():
    data = await get_wordle_data("2023-03-15")
    print(data)

asyncio.run(demo())

```

### Docker and Claude Desktop Integration

Deploy the server using the configuration from the README (lines 32-48):

```json
{
  "mcpServers": {
    "Wordle MCP (Python)": {
      "command": "docker",
      "args": [
        "run", "--rm", "-i", "--init",
        "-e", "DOCKER_CONTAINER=true",
        "ghcr.io/cr2007/mcp-wordle-python:latest"
      ]
    }
  }
}

```

## Testing REST API Integration via HTTP

Once running, test the REST integration using curl:

```bash
curl -X POST http://localhost:8000/tools/get_wordle_solution \
     -H "Content-Type: application/json" \
     -d '{"target_date":"2023-03-15"}'

```

The response returns the raw JSON from the NYT Wordle API:

```json
{
  "id": 342,
  "solution": "CRANE",
  "print_date": "2023-03-15",
  "days_since_launch": 665,
  "editor": "NYTimes"
}

```

## Summary

Integrating external REST APIs into MCP servers follows a predictable pattern demonstrated by the cr2007/mcp-wordle-python implementation:

- **Dependency Management**: Declare HTTP libraries like `requests` in [`fastmcp.json`](https://github.com/cr2007/mcp-wordle-python/blob/main/fastmcp.json) to ensure automatic installation when the server starts
- **Tool Registration**: Use `@mcp.tool` with descriptive metadata and `readOnlyHint` annotations to optimize LLM tool selection and client-side caching
- **Async Implementation**: Perform HTTP requests inside async functions and return JSON responses directly for automatic serialization by FastMCP
- **Deployment Flexibility**: Run via standard Python execution, `uvx`, or containerized environments using the `mcp.run()` entry point defined in [`src/mcp_wordle/main.py`](https://github.com/cr2007/mcp-wordle-python/blob/main/src/mcp_wordle/main.py)

## Frequently Asked Questions

### How do I add authentication headers to REST API calls in an MCP server?

Add headers directly to the `requests.get()` or `requests.post()` call within your tool function. Store sensitive tokens in environment variables accessed via `os.environ`, and pass them as the `headers` parameter. FastMCP inherits the process environment, so variables set in your Docker container or host system are available to the tool implementation.

### Can I use async HTTP libraries like aiohttp instead of requests?

Yes. While the Wordle MCP server uses the synchronous `requests` library inside async functions (which works due to FastMCP's threading model), you can substitute `aiohttp` or `httpx` for native async I/O. Simply `await` the async request methods and ensure the library is listed in [`fastmcp.json`](https://github.com/cr2007/mcp-wordle-python/blob/main/fastmcp.json) dependencies.

### How does FastMCP handle JSON serialization of API responses?

FastMCP automatically serializes Python dictionaries and lists returned by tool functions into JSON for the MCP protocol. When you return `requests.get(url).json()`, the dictionary passes through FastMCP's JSON encoder before transmission to the client. For non-JSON responses, explicitly parse the content and return a dictionary structure that conforms to your tool's response schema.

### What is the purpose of the readOnlyHint annotation in MCP tools?

The `readOnlyHint` annotation signals to MCP clients that invoking the tool does not modify server state or external resources. This allows clients to safely cache results, retry failed requests, and execute tools in parallel without side-effect concerns. Set this to `True` for GET requests and data retrieval operations, and omit or set to `False` for POST, PUT, or DELETE operations that change state.