Skip to main content
Glama
lukegohwb-ctrl

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

8000

Port to bind. Most hosts inject this.

DATA_PROVIDER

yahoo

yahoo (no key) · finnhub · alphavantage.

API_KEY

Key for finnhub / alphavantage.

AUTH_TOKEN

If set, requests must send Authorization: Bearer <token>.


1. Run locally

pip install -r requirements.txt
python server.py
# -> Serving MCP at http://0.0.0.0:8000/mcp

Quick health check:

curl http://localhost:8000/health          # -> ok

Prove 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:8000

It prints a public URL like https://random-words.trycloudflare.com. Your connector URL is that + /mcp:

https://random-words.trycloudflare.com/mcp

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

  1. Push this repo to GitHub.

  2. Render → New + → Blueprint → pick the repo. It reads render.yaml.

  3. (Optional) In the service's Environment, set AUTH_TOKEN and, if using a paid provider, DATA_PROVIDER + API_KEY.

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

  1. Push to GitHub → Railway → New Project → Deploy from repo.

  2. It detects the Dockerfile. Set env vars as needed. Railway sets PORT for you.

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

Connector = https://<app>.fly.dev/mcp.

Start command everywhere: python server.py (the Docker image already runs it).


4. Add it in Claude → Settings → Connectors

  1. Claude → Settings → Connectors → Add custom connector.

  2. Name: Market Data (anything).

  3. URL: paste your endpoint — the public URL plus /mcp, e.g. https://your-app.onrender.com/mcp.

  4. If you set AUTH_TOKEN: open Advanced settings and put the token where it asks for the bearer token / Authorization header (send header Authorization: Bearer <token>). Leave OAuth Client ID/Secret blank — this server uses a static bearer token, not OAuth.

  5. Save. Then ask Claude to "refresh live quotes" — it will call get_quotes.


5. Tests

pip install -r requirements.txt pytest
pytest -q

The 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 needs Authorization: Bearer <token>, which you configure once in the connector's Advanced settings. /health stays open for platform health checks.

  • Store API_KEY / AUTH_TOKEN as 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

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