mcp.vanshul.com

A public Model Context Protocol (MCP) server, running as a Cloudflare
Worker, that lets any AI agent read the live web as clean Markdown. It builds on
the same extraction pipeline as the sibling reader/ project
(Mozilla Readability + Turndown), exposed over the MCP Streamable HTTP
transport so agentic clients can plug straight in.
Endpoint
POST https://mcp.vanshul.com/mcp # JSON-RPC 2.0 (MCP)
GET https://mcp.vanshul.com/health # { ok: true, tools: [...] }
| Tool | Input | Returns |
|---|
fetch_markdown | { url, max_chars? } | The page's main content as clean Markdown (optionally truncated to max_chars) |
search_page | { url, query, max_matches?, context_chars? } | Only the passages matching query, each with its heading breadcrumb, ranked by relevance โ token-efficient alternative to fetch_markdown |
fetch_metadata | { url } | JSON: title, byline, siteName, excerpt, wordCount |
extract_links | { url, limit? } | JSON: all outbound http(s) links + anchor text |
Connect from an MCP client
Remote/HTTP-capable clients (Claude Desktop, Cursor, Continue, โฆ):
{
"mcpServers": {
"web-reader": { "url": "https://mcp.vanshul.com/mcp" }
}
}
Stdio-only clients can bridge with mcp-remote:
npx mcp-remote https://mcp.vanshul.com/mcp
Add it to your client
- Cursor โ Settings โ MCP โ Add new server, or drop this into
~/.cursor/mcp.json:
{ "mcpServers": { "web-reader": { "url": "https://mcp.vanshul.com/mcp" } } }
- Claude Desktop โ add the same block to
claude_desktop_config.json (Settings โ Developer โ Edit Config). If your version is stdio-only, use:
{ "mcpServers": { "web-reader": { "command": "npx", "args": ["mcp-remote", "https://mcp.vanshul.com/mcp"] } } }
- Continue / VS Code โ add
web-reader with URL https://mcp.vanshul.com/mcp to your MCP servers config.
Try it with curl
curl -s https://mcp.vanshul.com/mcp \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
curl -s https://mcp.vanshul.com/mcp \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call",
"params":{"name":"fetch_markdown","arguments":{"url":"https://example.com"}}}'
curl -s https://mcp.vanshul.com/mcp \
-H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call",
"params":{"name":"search_page","arguments":{"url":"https://example.com","query":"more information"}}}'
Layout
mcp/
โโโ src/
โ โโโ worker.ts # entry: routes /mcp, /health, rate limit, CORS
โ โโโ mcp.ts # JSON-RPC dispatch + tool definitions
โ โโโ extract.ts # HTML -> Markdown / links (Readability + Turndown)
โ โโโ search.ts # query-focused passage search over extracted Markdown
โ โโโ fetcher.ts # fetch with timeout, size cap, re-validated redirects
โ โโโ security.ts # SSRF guard (block private/internal addresses)
โโโ public/
โ โโโ index.html # landing page (served for non-API paths)
โ โโโ og.png # social share image (1200ร630)
โ โโโ og.svg # social image source
โ โโโ robots.txt
โ โโโ sitemap.xml
โโโ tests/ # vitest: security, extract, search, mcp dispatch, fetcher, worker
โโโ wrangler.toml
โโโ package.json
โโโ tsconfig.json
โโโ README.md
Develop & deploy
cd mcp
npm install
npm run typecheck
npm test
npm run dev
npm run deploy
After the first deploy, attach the custom domain mcp.vanshul.com in the
Cloudflare dashboard (Workers & Pages โ this worker โ Settings โ Domains), or
uncomment the [[routes]] block in wrangler.toml.
Security
- SSRF-safe: only public
http(s) URLs; localhost, private ranges, cloud
metadata and every redirect hop are blocked/re-validated.
- Bounded: 10s fetch timeout, ~3 MB page cap, max 5 redirects, per-IP rate
limit.
- Stateless & private: no page content is stored; extraction is
deterministic with no LLM in the loop.
MCP protocol
Implements initialize, ping, tools/list, tools/call and notifications
(protocol version 2025-06-18). Tool failures are returned as
{ content, isError: true } so the agent can read the message and recover;
malformed requests use standard JSON-RPC error codes.
Documentation
License
MIT ยฉ Vanshul Goyal