Architecture
The codebase is intentionally small, explicit, and grouped by API resource so it is easy to maintain and to regenerate when the upstream API evolves.
Layout
src/
config.ts Env -> validated Config (throws ConfigError).
logger.ts Leveled logger; writes to stderr only.
errors.ts Typed API errors mapped from HTTP status.
rate-limiter.ts Sliding-window limiter (~55/min).
client.ts HTTP client: auth header, rate limit, retry/backoff, error mapping.
server.ts Builds the McpServer and registers tools.
index.ts Programmatic exports.
cli.ts Executable entry (serve | login | ping | list-tools).
tools/
types.ts ToolDefinition, defineTool(), ToolContext.
helpers.ts Shared Zod fragments + result helpers.
registry.ts Read-only + write-confirmation policy; error -> result mapping.
index.ts allTools[] — the implemented surface.
<domain>.ts One module per API tag.
tests/ Vitest unit tests (mock fetch / fake client; virtual clock).
scripts/ docs + spec-fingerprint generators.
docs/ This site.
openapi-specs/ fingerprint.json — derived metadata of the upstream OpenAPI doc
(the verbatim spec is third-party IP and is not committed).
Request lifecycle
MCP host
│ tool call (name, args)
▼
registry wrapper ── Zod validate ──► read-only? ──► confirm gate (writes)
│ │
▼ ▼
tool.handler(args, ctx) preview result (no API call)
│
▼
RentecClient.get/post ── rate limit ── retry/backoff ── error mapping
│
▼
Rentec Direct API ──► jsonResult(...) | typed error ──► isError result
Key design choices
- Tool definitions are declarative. Each tool is a
defineTool({...})object with a ZodinputSchema, optionalwrite/previewMessage, and a thinhandler. The registry applies all cross-cutting policy, so individual tools stay tiny. allTools[]is the single source of truth. The CLI, the server, and the docs generator all read from it.- The client owns reliability. Rate limiting, retries, timeouts, and error typing live
in one place (
client.ts), so tools never deal with HTTP concerns. - Everything is injectable for tests.
fetch, the clock, andsleepcan all be supplied, so the suite is deterministic and offline.
Adding a tool
See the step-by-step guide in
CLAUDE.md
and Maintaining the Server.