A minimal Python MCP server over Streamable HTTP using FastAPI + fastmcp, ready to deploy on Render with HTTPS. It exposes a ping tool plus two demo tools (get_positions, list_upcoming_corporate_actions) you can replace with read‑only adapters to your custody data.
Why Streamable HTTP? It is the recommended transport for remote/hosted MCP servers, simplifying bidirectional streaming to a single
POST /mcpendpoint and making cloud deployment straightforward. See the MCP HTTP quickstart and SDK docs for the canonical patterns.
- Streamable HTTP endpoint at
POST /mcp - Bearer auth via
AUTH_TOKEN /healthendpoint for uptime checks- Minimal code footprint, easy to extend with more MCP tools
- One‑click deploy to Render via
render.yaml
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts�ctivate
pip install -r requirements.txt
export AUTH_TOKEN=devtoken123
export PORT=3000
uvicorn app:app --host 0.0.0.0 --port $PORTTest with cURL:
# tools/list
curl -s -X POST http://localhost:3000/mcp -H "Content-Type: application/json" -H "Authorization: Bearer devtoken123" -d '{"jsonrpc":"2.0","id":"1","method":"tools/list","params":{}}' | jq
# tools/call ping
curl -s -X POST http://localhost:3000/mcp -H "Content-Type: application/json" -H "Authorization: Bearer devtoken123" -d '{"jsonrpc":"2.0","id":"2","method":"tools/call","params":{"name":"ping","arguments":{}}}' | jqOr run helper script:
chmod +x scripts/test_locally.sh
AUTH_TOKEN=devtoken123 PORT=3000 ./scripts/test_locally.sh- Fork or push this repo to your GitHub.
- In Render: New → Web Service → Connect repo.
- Review settings from
render.yaml(Python env, free plan). Render auto‑provisions HTTPS. - Set
AUTH_TOKENin Render Environment (generated automatically if you use the blueprint). - Deploy → your public MCP endpoint is:
https://<your-app>.onrender.com/mcp.
Test remote:
APP_URL=https://<your-app>.onrender.com AUTH_TOKEN=<token> ./scripts/test_remote.shAdd a relay entry to claude_desktop_config.json:
{
"mcpServers": {
"custodyops-mcp": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://<your-app>.onrender.com/mcp"],
"env": { "AUTH_TOKEN": "<same-token>" }
}
}
}Restart the app, then ask Claude to list available tools.
Replace demo tools with read‑only adapters to your data mart or API. Keep responses small and typed, and add field provenance where possible.
Example skeleton:
@mcp_tool
def get_positions(account_id: str) -> str:
rows = query_positions(account_id) # your adapter
return json.dumps(rows)- Keep
AUTH_TOKENsecret; rotate regularly. For enterprise use, move to OAuth/JWT and add per‑account authorization. - With HTTP transport, normal logging is fine, but redact sensitive data and add request IDs.
MIT