What this is
The Model Context Protocol is a standard way for an assistant to call something that is not itself. A client connects to a server, asks what tools it has, and from then on the model can call them — with arguments it chose, and results it reads before answering you.
You: decode this JWT and tell me when it expires → the assistant calls toolforge_jwt_decode → it answers from the real claims, not from a guess
That last part is the difference worth understanding. A model asked to base64-decode a string will often produce something that looks right and is wrong in the middle. A model that calls a decoder gets the actual bytes. The same holds for a hash, a cron expression, a diff, or the expiry on a certificate.
Everything here runs on the ToolForge server rather than in your browser, which is a real departure from how the rest of this site works — the tool pages do their work in the tab and upload nothing. Over MCP, whatever you pass as an argument reaches this server, and the tools that reach the network reach it from here.
The address
One endpoint, for every client and every tool. It speaks Streamable HTTP and it is stateless: no session to open, nothing to keep alive, and no id to lose when a serverless instance is recycled.
/api/mcpSet the transport to HTTP, not SSE — the older Server-Sent Events transport is a different shape and this endpoint does not answer it.
Connecting a client
Every offline tool works with nothing but the address. A token is only needed for the tools that make outbound requests, and those are named further down.
Claude Code
Run this once; the server is remembered for the project.
claude mcp add --transport http toolforge https://toolforge-dev.vercel.app/api/mcpClaude Desktop
Add it to claude_desktop_config.json and restart the app. On claude.ai, add it as a custom connector and paste the address instead.
{
"mcpServers": {
"toolforge": {
"type": "http",
"url": "https://toolforge-dev.vercel.app/api/mcp"
}
}
}ChatGPT
Settings → Connectors → Add. Paste the address as the MCP server URL. Developer mode has to be on for a custom connector to appear.
https://toolforge-dev.vercel.app/api/mcpCursor and other editors
Add it to .cursor/mcp.json in the project, or to the global config for every project.
{
"mcpServers": {
"toolforge": {
"url": "https://toolforge-dev.vercel.app/api/mcp"
}
}
}Checking it by hand
One request, no client. A working endpoint answers with its name, version and protocol version.
curl -sS https://toolforge-dev.vercel.app/api/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":"1.0.0"}}}'The access token
Most of what ToolForge exposes is arithmetic on your own input — encoding, hashing, parsing — and costs this deployment a few milliseconds of CPU. Those tools are open to anyone, bounded by the rate limit rather than by a password.
One tool is different. The domain inspector reaches other people's hosts, from this server's address, with this site's name on the packets. Left open, that is a scanner a stranger's assistant can drive. So it is gated on a bearer token — and when no token is configured it is refused rather than served, because a gate that opens when its configuration is missing is not a gate.
This deployment has a token configured. Networked tools will work for a client that sends it.
Minting one
# 32 random bytes, base64url — long enough that guessing is not a strategy
openssl rand -base64 32 | tr '+/' '-_' | tr -d '='
# then, in the deployment's environment
MCP_ACCESS_TOKEN=<the value you just generated>Claude Code
claude mcp add --transport http toolforge https://toolforge-dev.vercel.app/api/mcp \
--header "Authorization: Bearer YOUR_TOKEN"Claude Desktop
{
"mcpServers": {
"toolforge": {
"type": "http",
"url": "https://toolforge-dev.vercel.app/api/mcp",
"headers": {
"Authorization": "Bearer YOUR_TOKEN"
}
}
}
}Cursor and other editors
{
"mcpServers": {
"toolforge": {
"url": "https://toolforge-dev.vercel.app/api/mcp",
"headers": {
"Authorization": "Bearer YOUR_TOKEN"
}
}
}
}Rotating it is a one-line change and takes effect on the next request — the value is read from the environment per call, not captured at startup. Clients holding the old token start failing immediately, which is the point.
The token is only ever sent as an Authorization header to /api/mcp. It never appears in a URL, so it cannot end up in browser history, a proxy log or a Referer header.
What is exposed
39 tools, all running on the server. Every one of them is the same code the tool page runs, so an answer here and an answer there cannot disagree.
| MCP tool | ToolForge tool | Access |
|---|---|---|
toolforge_aes_cryptEncrypt or decrypt with AES | AES Encryption / Decryption | Open |
toolforge_base64_convertEncode or decode Base64 | Base64 Encoder / Decoder | Open |
toolforge_bson_convertConvert between JSON, BSON and TOON | BSON / JSON / TOON Converter | Open |
toolforge_catalog_listList ToolForge tools | The catalogue itself | Open |
toolforge_color_convertConvert a colour between formats | Color Converter | Open |
toolforge_cron_explainExplain a cron expression | Cron Parser | Open |
toolforge_curl_convertConvert between curl and code | cURL ↔ Fetch Converter | Open |
toolforge_diff_compareCompare two texts | Diff Checker | Open |
toolforge_domain_inspector_inspectInspect a domain | DNS & Domain Inspector | Token |
toolforge_equation_convertConvert plain-text maths to LaTeX | Equation to LaTeX Converter | Open |
toolforge_hash_compareVerify a hash | Hash Generator / Verifier | Open |
toolforge_hash_detectIdentify a hash | Hash Generator / Verifier | Open |
toolforge_hash_generateHash text | Hash Generator / Verifier | Open |
toolforge_hex_editor_dumpDump bytes as hex | Hex Editor | Open |
toolforge_hex_editor_findFind bytes in a blob | Hex Editor | Open |
toolforge_hex_editor_inspectDecode bytes at an offset | Hex Editor | Open |
toolforge_html_markdown_convertConvert between HTML and Markdown | HTML to Markdown | Open |
toolforge_ip_globe_mapLocate the hops of a route | IP & Route Globe | Token |
toolforge_json_formatFormat, minify or validate JSON | JSON Formatter | Open |
toolforge_jwt_decodeDecode a JWT | JWT Encoder / Decoder | Open |
toolforge_jwt_signSign a JWT | JWT Encoder / Decoder | Open |
toolforge_jwt_verifyVerify a JWT signature | JWT Encoder / Decoder | Open |
toolforge_lorem_generateGenerate placeholder text | Random Text Generator | Open |
toolforge_markdown_analyzeAnalyse a Markdown document | Markdown Preview | Open |
toolforge_password_generateGenerate a password | Password Generator | Open |
toolforge_pdf_converter_convertConvert a document to PDF | Document to PDF | Open |
toolforge_qr_generateGenerate a QR code | QR Code Generator / Reader | Open |
toolforge_regex_testTest a regular expression | Regex Tester | Open |
toolforge_rsa_encrypt_cryptEncrypt or decrypt with an RSA key | RSA Encrypt / Decrypt | Open |
toolforge_rsa_generateGenerate an RSA key pair | RSA Key Generator | Open |
toolforge_secret_generateGenerate a secret key | Secret Key Generator | Open |
toolforge_slug_createSlugify text | Slug Generator | Open |
toolforge_sort_linesSort and list lines | Text Sorter | Open |
toolforge_subdomain_lookup_lookupFind subdomains of a domain | Subdomain Lookup | Token |
toolforge_text_case_convertConvert text case | Text Case Converter | Open |
toolforge_timestamp_convertConvert a timestamp | Timestamp Converter | Open |
toolforge_url_convertPercent-encode or decode a URL | URL Encoder / Decoder | Open |
toolforge_url_parser_parseBreak a URL into its parts | URL Parser | Open |
toolforge_uuid_generateGenerate UUIDs | UUID Generator | Open |
What asking looks like
You do not name the tool. You ask for the thing, and the assistant picks — which is why every tool here carries a description written for a model choosing between thirty of them.
Is this token expired?Calls toolforge_jwt_decode, reads exp against the clock, and warns you if the token is unsigned.
Hash this password with Argon2id at the OWASP settingsCalls toolforge_hash_generate with a freshly generated salt, and returns the encoded hash with its parameters inside it.
When does 0 3 * * 1-5 next fire in Dhaka?Calls toolforge_cron_explain, which returns real instants in that zone — and flags any run a daylight-saving jump would erase.
What changed between these two config files?Calls toolforge_diff_compare and gets a unified patch back, which is far cheaper to read than two files side by side.
Is example.com's certificate about to expire?Calls toolforge_domain_inspector_inspect — the one tool that needs the token, because it reaches the host to find out.
Limits
60 calls a minute per caller, and 600 a minute per tool across everyone. The first bounds one client in a loop; the second bounds a flood spread across many, which no per-caller limit can do.
A refusal clears inside a minute and says when, in a Retry-After header and in the rate-limit headers on every answer. A client watching those sees its budget counting down before anything breaks.
Individual tools keep their own ceilings — the diff refuses documents past its line count, the QR encoder past what the specification can carry — and those are the same ceilings the tool pages hold.
What is not here, and why
Five groups are missing on purpose. Each one is a fact about the tool rather than a gap in the endpoint, and toolforge_catalog_list returns the web address of every one of them so an assistant can send you to the page instead of reporting a dead end.
- The image tools
- The compressor, converter, resizer, blur placeholder and background remover decode pixels in a canvas and re-encode them through WebAssembly codecs built for a browser. There is no canvas in a request handler, and a server-side reimplementation would be a second encoder to keep in step with the first. The background remover adds a second reason: its segmentation weights are fetched into the reader's own browser and cached there, so running it here would move a hundred-megabyte download and the inference behind it onto this deployment for every call.
- The server studios and the shortener
- Each of them mints a public address and stores what is posted to it, against an ownership model built on browser cookies. An MCP client has no cookie jar and no way to prove it owns what it created, so creating one here would mint something nobody could ever reclaim.
- The AI tools
- The watermark remover's picture tab spends a third-party API budget on every call. That is a decision about money rather than about capability, and it belongs to whoever is paying. The watermark remover's video tab is absent for the images' reason instead: it demuxes, decodes, repaints and re-encodes a clip through the browser's own codecs, none of which exists in a request handler. Text to Speech is absent for a neighbouring reason: every generation is a request to Microsoft's speech service from this site's one address, and the page shares that service's patience between readers with a bot check and an hourly ceiling that a single token-holding caller would exhaust.
- The port scanner
- Its whole function is to touch somebody else's host on ports they did not offer. Behind a model that can be talked into things, a token is not the protection it looks like.
- The hardware testers
- The mouse and keyboard testers measure a physical device in a browser: the gaps between presses, the wheel, the keys held at once. An MCP call has no mouse or keyboard on the other end of it, and a tool that took a list of timestamps instead would be one nobody had a reason to call.
Frequently asked questions
MCP_ACCESS_TOKEN on the deployment and send it as Authorization: Bearer./api/mcp at the end. Or the deployment has no database and no MCP_IP_SALT, in which case the endpoint refuses every request — the banner at the top of this page says so when that is the case.