Rebasely Beta: data may be purged

examples/MCP-tools Public

Expand the README with each tool, client setup and the layout

1 check passed
Someone landing on the repository should be able to call a tool within a few minutes. Each tool gets a real call and its result, followed by setup for the Inspector, Claude Code, Claude Desktop and curl, the design in four points, and a map of the files.
fcaf000d2cb82d7d041163bce3c3adaf1f7b9748
Parent 2d86268 Browse filesHistory

Changed files

1 file changed140 additions3 deletionsagainst 2d86268

  1. ChangedREADME.md+140−3
ChangedREADME.md+140−3
@@ -1,9 +1,146 @@
# mcp-tools
-A small MCP server with exact, read-only helpers for models, running as a Cloudflare Worker. Tools: `convert_units`, `time_in_zone` and `text_stats`. It serves MCP over Streamable HTTP at `/mcp`.
+A small [Model Context Protocol](https://modelcontextprotocol.io) 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`.
+
+```json
+{ "value": 26.2, "from": "miles", "to": "km" }
+```
+
+```json
+{ "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.
+
+```json
+{ "zone": "tokyo", "at": "2026-10-14T17:00:00Z" }
+```
+
+```json
+{
+ "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.
+
+```json
+{ "text": "MCP gives models tools. This server has three of them." }
+```
+
+```json
+{
+ "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.**
+
```sh
+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`:
+
+```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:
+
+```sh
+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.
+
+```sh
npm install
-npm test
-npm run dev # http://localhost:8787/mcp
+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 `McpServer` and a `WebStandardStreamableHTTPServerTransport` with 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.ts` is the only file that knows about MCP.
+- **Errors are results.** A tool throws `ToolError` with advice ("Use an IANA name such as Europe/Paris"), and the server returns it with `isError: true` so 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
View file

Checks

1 check passed
StatusCheckReported byDescriptionDetails
Successduragit/ci/testRebasely ActionssucceededRun

Runs

StatusWorkflowEventStarted
SuccessciPush