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

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 at line 13, the server initializes:

mcp = FastMCP("WordleMCP")

The metadata and external dependencies are declared in fastmcp.json, which specifies the entry point and required packages:

{
  "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 lines 30-38, the Wordle solution fetcher is defined:

@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 lines 64-67, the implementation constructs the target URL from the user-provided date and executes the HTTP GET request:

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 contain the execution guard:

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:

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):

{
  "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:

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:

{
  "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 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

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 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →