market-data-mcp
market-data-mcp
A tiny remote MCP server that serves live US stock quotes, for use as a custom connector in Claude / Cowork (claude.ai).
Cowork only accepts remote MCP connectors — a public https:// URL. The local
claude_desktop_config.json method does not work in Cowork. This server uses
streamable-HTTP transport so it can be deployed to a public URL and added as a
custom connector.
Tool name:
get_quotes(keep this exact — your dashboard calls it)Endpoint path:
/mcp→ the connector URL is<public-url>/mcp
Tool contract
get_quotes
Input
{ "symbols": "AMD,MSFT,MU" }Comma-separated tickers, case-insensitive.
Output — JSON keyed by UPPERCASE ticker:
{
"AMD": {"price": 552.05, "currency": "USD", "asof": "2026-07-06T20:00:00Z", "source": "Yahoo Finance"},
"MSFT": {"price": 498.10, "currency": "USD", "asof": "2026-07-06T20:00:00Z", "source": "Yahoo Finance"}
}A per-ticker failure returns {"TICKER": {"error": "..."}} and the rest still succeed.
get_quote_history (optional, for charts)
{ "symbol": "AMD", "range": "1mo", "interval": "1d" }Returns parallel arrays:
{ "symbol": "AMD", "dates": ["2026-06-09", "..."], "closes": [548.2, "..."] }range: 1d,5d,1mo,3mo,6mo,1y,2y,5y,max · interval: 1m,5m,15m,30m,1h,1d,1wk,1mo.
History is always sourced from Yahoo Finance (keyless).
Calling it from the dashboard
const quotes = await window.cowork.callMcpTool("get_quotes", { symbols: "AMD,MSFT" });
// quotes.AMD.price, quotes.AMD.asof, ...Configuration (environment variables)
Var | Default | Purpose |
|
| Port to bind. Most hosts inject this. |
|
|
|
| — | Key for |
| — | If set, requests must send |
1. Run locally
pip install -r requirements.txt
python server.py
# -> Serving MCP at http://0.0.0.0:8000/mcpQuick health check:
curl http://localhost:8000/health # -> okProve the tool returns the contract shape (curl)
MCP is a JSON-RPC handshake, so a raw quote call is two steps. Easiest proof is the
test suite (below). To exercise the transport directly, initialize then call the tool
(streamable-HTTP requires the text/event-stream accept header):
curl -sN http://localhost:8000/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'(The tests call the tools directly and assert the exact shape — that's the fastest check.)
2. Quick public test (Cloudflare tunnel, ~2 min, no account)
With python server.py running, in another terminal:
# install cloudflared first (https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/)
cloudflared tunnel --url http://localhost:8000It prints a public URL like https://random-words.trycloudflare.com.
Your connector URL is that + /mcp:
https://random-words.trycloudflare.com/mcpThe tunnel URL dies when you close the terminal — great for testing, not permanent. For an always-on URL, deploy (next section).
3. Deploy to a public https URL (always-on, free tier)
You need a public URL Claude can reach. Any of these free tiers work; each gives you
https://<something> — your connector URL is that + /mcp.
Render (simplest — uses render.yaml)
Push this repo to GitHub.
Render → New + → Blueprint → pick the repo. It reads
render.yaml.(Optional) In the service's Environment, set
AUTH_TOKENand, if using a paid provider,DATA_PROVIDER+API_KEY.Deploy. Your URL is
https://<name>.onrender.com→ connector =.../mcp. (Free instances sleep when idle; the first request after a nap wakes it in ~30s.)
Railway
Push to GitHub → Railway → New Project → Deploy from repo.
It detects the
Dockerfile. Set env vars as needed. Railway setsPORTfor you.Settings → Networking → Generate Domain → connector =
https://<domain>/mcp.
Fly.io (uses fly.toml + Dockerfile)
fly launch --no-deploy # accept the included fly.toml
fly secrets set AUTH_TOKEN=your-long-random-token # optional but recommended
fly deployConnector = https://<app>.fly.dev/mcp.
Start command everywhere: python server.py (the Docker image already runs it).
4. Add it in Claude → Settings → Connectors
Claude → Settings → Connectors → Add custom connector.
Name:
Market Data(anything).URL: paste your endpoint — the public URL plus
/mcp, e.g.https://your-app.onrender.com/mcp.If you set
AUTH_TOKEN: open Advanced settings and put the token where it asks for the bearer token /Authorizationheader (send headerAuthorization: Bearer <token>). Leave OAuth Client ID/Secret blank — this server uses a static bearer token, not OAuth.Save. Then ask Claude to "refresh live quotes" — it will call
get_quotes.
5. Tests
pip install -r requirements.txt pytest
pytest -qThe suite asserts the exact get_quotes contract (uppercase keys; price/currency/asof/source;
per-ticker error isolation) and that history returns equal-length dates/closes.
Tests skip automatically if there's no network.
Security
Read-only public quotes. No account, no brokerage credentials, ever. Do not extend this server to touch trading or account APIs.
Lock it down by setting
AUTH_TOKEN— every request then needsAuthorization: Bearer <token>, which you configure once in the connector's Advanced settings./healthstays open for platform health checks.Store
API_KEY/AUTH_TOKENas host secrets/env vars, never in the repo.Optionally restrict inbound traffic to Anthropic's IP ranges at your host/proxy for defense in depth.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/lukegohwb-ctrl/market-data-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server