Building an MCP server for AI signals data — and the Cloudflare 403 that silently broke it
I wanted my coding agent to answer "what's happening in AI today?" without me pasting links into the chat. So I wrote a small MCP server for the AI signals data I collect. Two things came out of it that might save you time. 1. The MCP server (single file, stdlib only, no API key) Five tools, all re

Posted on Oct 14 • Originally published at data.jiangzhang.ca
I wanted my coding agent to answer "what's happening in AI today?" without me pasting links into the chat. So I wrote a small MCP server for the AI signals data I collect. Two things came out of it that might save you time.
Every ranked row includes a citation string, so the agent cites a number instead of inventing one. Rows whose number can't be derived come back as unranked with the reason — I'd rather return "not ranked" than a plausible-looking guess.
Install is one file plus a config block:
{ "mcpServers": { "signals": { "command": "python3", "args": [ "/absolute/path/to/mcp_server.py" ] } } } Enter fullscreen mode Exit fullscreen mode Repo: https://github.com/jiangzhangcc-glitch/signals-api-mcp (MIT, Python 3.9+, no dependencies)
My first version called the API with plain urllib.request.urlopen(url). Every tool failed with HTTP 403. The API was fine — the CDN in front of it rejects the bare Python-urllib/… User-Agent (and empty User-Agents) before the request ever reaches the origin.
The nasty part: because the request is blocked at the edge, the origin server has no log of it. If you only look at your own access logs, you conclude "nobody is calling my API". I measured it across clients:
So requests is fine — but the zero-dependency example that a reader will copy-paste is exactly the one that breaks. If you publish an API, test it with the dumbest client you can write, and set a real User-Agent in every sample:
curl -H 'User-Agent: my-app/1.0' https://data.jiangzhang.ca/signals4/api/today.json Enter fullscreen mode Exit fullscreen mode The server now sends SignalsAPI-MCP/1.0 (+https://…) on every request, and the 403 case returns an error message that names the likely cause instead of a bare status code.
I run a small daily pipeline that collects from public sources (GitHub trending, Hugging Face, YouTube, arXiv, arena boards, tech news, hardware/chips), dedupes and archives it. The newest daily delta is public, plus a machine-readable dataset:
The free tier is one edition a day from four core sources. There's a paid feed if you need eight sources, four updates a day, and the full history as an API — it's linked from the repo README. Everything in the MCP server stays free.
If you build something with it, I'd genuinely like to know what breaks — the 403 above only surfaced because I used my own server as a user.