examples/MCP-tools Public
MCP-tools
| Name | Size |
|---|---|
| .rebasely (folder) | |
| src (folder) | |
| test (folder) | |
| .gitignore | 35 B |
| LICENSE | 1.0 KiB |
| README.md | 4.8 KiB |
| package-lock.json | 55.1 KiB |
| package.json | 652 B |
| tsconfig.json | 390 B |
| wrangler.jsonc | 363 B |
README.md
mcp-tools
A small Model Context Protocol server on Cloudflare Workers. It gives models three exact, read-only tools for things they tend to get wrong: unit arithmetic, the current time somewhere else, and counting words.
The server speaks Streamable HTTP at /mcp, holds no sessions, and counts tool calls per day in a KV namespace.
Tools
convert_units
Converts between units of length, mass, volume (US customary) and temperature. Units can be symbols or names: km, kilometres, °F, pounds.
{ "value": 26.2, "from": "miles", "to": "km" }
{ "quantity": "length", "value": 26.2, "from": "mi", "result": 42.1648128, "to": "km" }
Converting between quantities, an unknown unit, or a temperature below absolute zero returns an error result that says what to send instead.
time_in_zone
The local date, time, weekday and UTC offset in an IANA time zone, now or at a given instant. A city that names one zone (tokyo, new york) works too.
{ "zone": "tokyo", "at": "2026-10-14T17:00:00Z" }
{
"zone": "Asia/Tokyo",
"instant": "2026-10-14T17:00:00.000Z",
"date": "2026-10-15",
"time": "02:00:00",
"weekday": "Thursday",
"utc_offset": "+09:00",
"utc_offset_minutes": 540,
"formatted": "Thursday, October 15, 2026 at 2:00:00 AM GMT+9"
}
Leave out at for the current time. An instant without Z or an offset is refused, since it would be read in the server's own zone.
text_stats
Characters (as a reader sees them, so an emoji counts once), words, sentences, paragraphs and reading time.
{ "text": "MCP gives models tools. This server has three of them." }
{
"characters": 54,
"characters_excluding_spaces": 45,
"words": 10,
"sentences": 2,
"paragraphs": 1,
"reading_time_seconds": 3,
"reading_time": "under a minute"
}
words_per_minute sets the reading speed (default 238).
Connecting a client
The endpoint is http://localhost:8787/mcp locally, or https://mcp-tools.<your subdomain>.workers.dev/mcp once deployed. No auth.
MCP Inspector. Run npx @modelcontextprotocol/inspector, choose the Streamable HTTP transport, and enter the URL.
Claude Code.
claude mcp add --transport http mcp-tools http://localhost:8787/mcp
Claude Desktop. Desktop starts local servers over stdio, so bridge with mcp-remote in claude_desktop_config.json:
{
"mcpServers": {
"mcp-tools": { "command": "npx", "args": ["-y", "mcp-remote", "http://localhost:8787/mcp"] }
}
}
curl. Each message is its own POST, and Accept must list both types:
curl -s http://localhost:8787/mcp \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"convert_units","arguments":{"value":100,"from":"C","to":"F"}}}'
GET /stats?days=7 returns calls and errors per tool for the last seven UTC days.
Running it
Node 24 or later.
npm install
npm test # node:test, no Workers runtime needed
npm run typecheck
npm run dev # wrangler dev on http://localhost:8787
npx wrangler deploy deploys it. The USAGE namespace in wrangler.jsonc has no id, so the first deploy creates it.
Design notes
- Stateless. Every POST gets a fresh
McpServerand aWebStandardStreamableHTTPServerTransportwith no session id and JSON responses. Any isolate can answer any request; nothing needs a Durable Object. - Tools are pure. Each tool in
src/tools/is a name, a description written for the model, zod input and output schemas, and a function from input to output.src/server.tsis the only file that knows about MCP. - Errors are results. A tool throws
ToolErrorwith advice ("Use an IANA name such as Europe/Paris"), and the server returns it withisError: trueso the model can read it and try again. - Counting stays off the request path. Usage writes go through
ctx.waitUntil, after the response. The counts are approximate, which is fine for seeing what gets used.
The longer versions are in the knowledge base under .rebasely/kb/, and the component map is .rebasely/architecture/system.yaml.
Layout
src/
index.ts Worker entry
worker.ts routes: /mcp, /stats, CORS
server.ts createServer(): registers the tools with McpServer
usage.ts per-day counters in KV
tools/
convert-units.ts
time-in-zone.ts
text-stats.ts
errors.ts ToolError
types.ts defineTool and the Tool type
test/ node:test suites, plus an in-memory client and KV fakes
.rebasely/
architecture/ components, views and flows
kb/ concepts, decisions and guides
workflows/ci.yml typecheck and tests on every push
License
MIT