One command to a production-ready remote MCP server
Project description
remote-mcp
One command to a production-ready remote MCP server.
Building a remote MCP server means solving the same hard problems every time: OAuth pass-through, RFC 8414/9728 discovery endpoints, middleware stack, telemetry, retry logic, and a test suite that passes on day one.
remote-mcp scaffolds all of it from two prompts. Generated projects have zero runtime dependency on this package — every file is yours to read, audit, and modify.
Install
pipx install remote-mcp # recommended
# or
pip install remote-mcp
Usage
remote-mcp new my-project
FastMCP Remote Server Generator
Project name [my-project]:
Service name [My Project]:
Scaffolding my-project... ✓
Done! Next steps:
cd my-project
python -m venv venv && source venv/bin/activate
pip install -e ".[dev]"
cp env.example .env
uvicorn asgi:application --reload --port 8001 --lifespan on
Server is live at http://localhost:8001. MCP endpoint: http://localhost:8001/sse.
What you get
my-project/
├── src/
│ ├── server.py # FastMCP("My Project") + middleware stack + OAuth discovery
│ ├── config/settings.py # Pydantic BaseSettings — all config via env vars
│ ├── core/
│ │ ├── auth.py # extract_bearer_token() — OAuth pass-through
│ │ ├── errors.py # MyProjectError hierarchy
│ │ ├── http_client.py # api_get, api_post + tenacity retry
│ │ ├── telemetry.py # anonymized SHA-256 JSONL event log
│ │ └── handlers.py # @tool_handler decorator, get_client_and_token()
│ └── tools/example.py # echo tool — your first tool, ready to replace
├── tests/
│ ├── test_auth.py # extract_bearer_token edge cases
│ ├── test_middleware.py # auth bypass, 401 on missing token
│ └── test_telemetry.py # hash_token stability, record_event never raises
├── templates/index.html # landing page served at /
├── asgi.py # production ASGI entrypoint
├── env.example # all env vars with safe defaults
├── pyproject.toml
└── DEPLOYMENT.md # Render / Railway / Fly.io deploy guide
Included infrastructure
| Module | What it provides |
|---|---|
core/auth.py |
extract_bearer_token(ctx) — forward Bearer token verbatim to your backend |
core/http_client.py |
api_get, api_post — pooled httpx client with tenacity retry |
core/errors.py |
MyProjectError + Auth, Forbidden, Validation, Backend, RateLimit subclasses |
core/telemetry.py |
Rotating JSONL log, user IDs hashed (SHA-256, non-reversible) |
core/handlers.py |
@tool_handler — catches errors, formats responses, records telemetry |
server.py |
CORS → Auth → Telemetry middleware, RFC 8414 + RFC 9728 discovery, landing page |
Nothing is forced on you. Delete what you don't need.
Adding a tool
Open src/tools/example.py — it's already wired up as a working echo tool. Replace it or add alongside it:
# src/tools/my_tool.py
from fastmcp import FastMCP, Context
from src.core.handlers import tool_handler, get_client_and_token
my_router = FastMCP("my-tool")
@my_router.tool()
@tool_handler
async def my_tool(param: str, ctx: Context) -> str:
client, auth_header = await get_client_and_token(ctx)
response = await client.get("/some/endpoint", headers={"Authorization": auth_header})
return response.json()
Mount it in src/server.py:
from src.tools.my_tool import my_router
mcp.mount(my_router)
Connecting to Claude
Claude.ai (web): Settings → Connectors → Add → Custom → Web
- URL:
https://your-server.example.com/mcp/sse
Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"my-project": {
"command": "npx",
"args": ["-y", "mcp-remote@latest", "https://your-server.example.com/mcp/sse"]
}
}
}
Claude Code:
claude mcp add my-project --transport http https://your-server.example.com/mcp/sse
Configuration
Copy env.example to .env and edit. Key variables:
| Variable | Default | Description |
|---|---|---|
API_BASE_URL |
https://api.example.com |
Your upstream API |
MCP_PUBLIC_URL |
http://localhost:8001/mcp |
Public MCP URL (in landing page) |
OAUTH_ISSUER_URL |
http://localhost:8001 |
OAuth issuer for RFC 8414 discovery |
AUTH_PROBE_ENABLED |
false |
Validate token against backend on SSE connect |
AUTH_PROBE_PATH |
/health/ |
Endpoint used for token probe |
LOGO_URI |
`` | Logo shown in OAuth discovery (optional) |
ALLOWED_ORIGINS |
https://claude.ai,... |
CORS origins |
Full variable list and deploy instructions in DEPLOYMENT.md.
How it works
remote-mcp renders Jinja2 templates into your project directory at scaffold time. After that, it's gone — no version pinning, no update command, no hidden runtime. You own every line.
Requirements
- Python ≥ 3.12
- FastMCP ≥ 3.0 (installed in the generated project, not this package)
License
MIT — see LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file remote_mcp-0.1.1.tar.gz.
File metadata
- Download URL: remote_mcp-0.1.1.tar.gz
- Upload date:
- Size: 51.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ea2d8f8d173666ca9f0f4a0a2fd9a5a8769a592efc59328d5483df8d82221834
|
|
| MD5 |
4ff86bab9af3444393399d41c8a2d6e2
|
|
| BLAKE2b-256 |
8c5bafbf17f34dcec79656ed51fb2b1c014d1bad00d719b21690af4d5718522e
|
Provenance
The following attestation bundles were made for remote_mcp-0.1.1.tar.gz:
Publisher:
publish.yml on pushpendra-tripathi/remote-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
remote_mcp-0.1.1.tar.gz -
Subject digest:
ea2d8f8d173666ca9f0f4a0a2fd9a5a8769a592efc59328d5483df8d82221834 - Sigstore transparency entry: 1703865102
- Sigstore integration time:
-
Permalink:
pushpendra-tripathi/remote-mcp@2f4851a07fd15367e1d894e7b9585e347bf0d4bd -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/pushpendra-tripathi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2f4851a07fd15367e1d894e7b9585e347bf0d4bd -
Trigger Event:
push
-
Statement type:
File details
Details for the file remote_mcp-0.1.1-py3-none-any.whl.
File metadata
- Download URL: remote_mcp-0.1.1-py3-none-any.whl
- Upload date:
- Size: 40.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bb765637a84f794065c564a3ee7b06fd9af9599380febcc9806ac9630ef8da7e
|
|
| MD5 |
ff7714ba2887a7fc43260a0d735b85e9
|
|
| BLAKE2b-256 |
c0cc1fe3a1542799a18c3030557cd78d0e0a41cfbbbb0ae01ce102a046065390
|
Provenance
The following attestation bundles were made for remote_mcp-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on pushpendra-tripathi/remote-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
remote_mcp-0.1.1-py3-none-any.whl -
Subject digest:
bb765637a84f794065c564a3ee7b06fd9af9599380febcc9806ac9630ef8da7e - Sigstore transparency entry: 1703865134
- Sigstore integration time:
-
Permalink:
pushpendra-tripathi/remote-mcp@2f4851a07fd15367e1d894e7b9585e347bf0d4bd -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/pushpendra-tripathi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2f4851a07fd15367e1d894e7b9585e347bf0d4bd -
Trigger Event:
push
-
Statement type: