REST API → MCP Server Bridge

A small Python example of wrapping a REST API as MCP tools that Claude, Cursor and other MCP clients can call with validated input.

⭐ View on GitHub Get Started →

How It Works

🌐

Your REST API

Any HTTP API: SaaS, internal backend, or third-party service

→
🔌

MCP Bridge

Pydantic validation, error handling, dual-format responses

→
🤖

AI Assistant

Claude, Cursor, or any MCP-compatible client

The Tools

Four tools over JSONPlaceholder: list, get, create and update.

GET

api_list_posts

List with filtering + pagination

GET

api_get_post

Fetch with optional related data

POST

api_create_post

Create with validated input

PATCH

api_update_post

Partial update, marked destructive

Quick Start

Clone, install from the lock file, run the offline tests.

git clone https://github.com/BryceEWatson/mcp-api-bridge.gitcd mcp-api-bridgeuv sync --extra devuv run pytest -m "not live"  # HTTP mocked, no networkuv run api-bridge  # MCP server over stdio

Claude Desktop: add the server to claude_desktop_config.json as shown in the README. CI runs lint and tests on every push and pull request.

Adapt For Your API

The point of this project is the pattern. JSONPlaceholder is a stand-in: swap the API client and the tool functions, and the FastMCP wiring, validation and error handling carry over.

What You Change

  1. Update api_client.py: base URL, auth headers
  2. Write your tools: same @mcp.tool pattern, with Annotated[type, Field(...)] parameters for your domain
  3. Set the annotations to match what each tool really does
  4. Update Claude Desktop config

The README has the full steps with code.

# Before (JSONPlaceholder)
- base_url = "https://jsonplaceholder.typicode.com"
- async def api_list_posts(user_id: Annotated[...], ...)

# After (Your API)
+ base_url = "https://api.your-service.com/v1"
+ async def orders_search(status: Annotated[...], ...)
+ headers = {"Authorization": "Bearer YOUR_KEY"}

Security notes

The base URL is fixed in code, so tool input can't redirect requests. Input is checked against the schema before any HTTP call, and API failures come back as MCP errors. Prompt injection through tool output and response size limits are out of scope. The README lists both sides.