Benchline is now open source under MIT. It's a directory of 71 browser tools (JSON, PDFs, images, tokens, headers, DNS, llms.txt) where every tool is also exposed on a public MCP server. One URL gives Cursor, Claude or VS Code 72 tools, with no API key and no session.
- Live: https://benchline.fabwaseem.com
- MCP guide: https://benchline.fabwaseem.com/mcp/guide
- Source: https://github.com/fabwaseem/benchline
I wrote about the architecture in an earlier post. This one is the practical version: how to plug it into your agent, how to call it without a client, and how to add a tool.
Connect it to your agent
Cursor (~/.cursor/mcp.json):
{
"mcpServers": {
"benchline": { "url": "https://benchline.fabwaseem.com/mcp" }
}
}
VS Code (.vscode/mcp.json):
{
"servers": {
"benchline": { "type": "http", "url": "https://benchline.fabwaseem.com/mcp" }
}
}
Claude Desktop builds that only launch local commands can bridge through mcp-remote:
{
"mcpServers": {
"benchline": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://benchline.fabwaseem.com/mcp"]
}
}
}
Then ask for things like "decode this JWT and tell me when it expires", "check the security headers on example.com", or "merge these two PDFs". The agent picks decode_jwt, check_http_headers or merge_pdf from the list.
Call it with plain curl
The server is stateless, so you don't need an initialize handshake first. Send JSON-RPC with these two headers:
curl -sS -X POST https://benchline.fabwaseem.com/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"generate_uuid","arguments":{"version":"v7","count":2}}}'
The response carries result.structuredContent plus a text copy of the same JSON:
{"ids":["01a1501a-9348-768a-b5d4-169352f4128c","01a1501a-9349-7734-9a2d-090e213e2507"],"version":7,"variant":"RFC 4122"}
Swap tools/call for tools/list to see all 72 tools with their input schemas. The same functions also answer at POST /api/v1/tools/<slug>, with an OpenAPI 3.1 document at /openapi.json.
What's in the box
| Area | Examples |
|---|---|
| Data & formats | JSON formatter, JSON/YAML/TOML/XML converter, JSON Schema, JSON to TypeScript/Zod/Pydantic/Go types, CSV/JSON, SQL formatter |
| Merge, split, compress, image to PDF, PDF to text, PDF to image, protect/unlock | |
| Images | Convert (HEIC, WebP, AVIF), compress, resize, crop, EXIF strip, OCR, background removal |
| Security | JWT decoder, hashes and HMAC, bcrypt/argon2id, key pairs, AES-GCM, TOTP, CSP builder |
| Network | DNS over HTTPS, CIDR, HTTP header grade, SSL checker, HAR analyzer, cURL converter, GraphQL client |
| SEO & AI search | llms.txt generator, AI SEO checker, robots.txt checker, JSON-LD, sitemap validator, OG images, token counter |
On the website, 60 of the 71 tools run entirely in the browser, so your files stay on your device. The 11 that read a public URL go through a server route that refuses private, loopback and link-local addresses, re-checks every redirect hop, and rate-limits each address.
Limits worth knowing
-
/mcpallows 60 requests a minute per address, and a 429 comes withretry-after. - File arguments take
urlor base64data(not both), capped at 10 MB. - URL inputs must be public
http/httpson port 80 or 443. The server resolves the host and refuses private ranges, CGNAT and metadata hosts.
Add a tool
Each tool is one folder under src/tools/<slug>/:
meta.ts # name, category, FAQs, SEO copy
tool.tsx # the page UI
lib/ # pure functions + a vitest file
mcp.ts # zod input/output schema and run()
This is the whole mcp.ts for the JSON formatter, minus the output schema:
export const inputSchema = z.object({
json: z.string().describe("JSON text to format or validate."),
indent: z.enum(indents).default("2"),
sortKeys: z.boolean().default(false),
minify: z.boolean().default(false),
});
export const tool: BenchTool = {
slug: "json-formatter",
name: "format_json",
title: "Format and validate JSON",
description: "Pretty-print or minify JSON. Returns the formatted text when it is valid, or the line and column of each syntax error.",
openWorld: false,
inputSchema,
outputSchema,
run,
};
pnpm gen:registry scans every folder and fails the build when a tool has no MCP entry, so the website and the server can't drift apart. Tool requests go through the issue template in the repo, and PRs are welcome.
If you use it from an agent, I'd like to hear which tools you reach for and which are missing.
Top comments (0)