How Kervan works
Three libraries, a command line and a project generator. This page shows which does what, and the path a tool call takes.
Where this fits: Concepts. Read it after the quickstart, before choosing between YAML and TypeScript.
On this page
The packages
| Package | Responsibility | Depends on |
|---|---|---|
@kervan/core | createApp, tool definitions, input and output validation, timeouts, error masking, middleware, the tool registry and its change notifications. No transport, no network, no files. | the official MCP SDK (@modelcontextprotocol/server) |
@kervan/transport | Serves an app: stdio and Streamable HTTP on Node, a standard fetch handler (tested on Node), Host and Origin checks, authenticate and resolveServer, and createTestClient for tests. | @kervan/core |
@kervan/spec-runtime | Reads a kervan.yaml and turns each entry into an ordinary tool definition that makes an HTTP request: templates, SSRF protection, secret redaction, select in a separate process, a rate limit per tool. | @kervan/core |
kervan | The command line: kervan create (a new project), kervan dev (hot reload and a terminal inspector) and kervan run (serve a spec). | the three libraries |
create-kervan | What npm create kervan runs: it calls kervan create. | kervan |
@kervan/core knows nothing about specs, HTTP or stdio, so a tool written in TypeScript and a
tool loaded from YAML are the same thing once registered.
The path of a tool call
- The client sends
tools/call. Over stdio as a line on stdin; over Streamable HTTP as aPOSTto/mcp. A 2026-07-28 request carries its protocol version and capabilities in_meta; a 2025-era client first sendsinitialize. See MCP 2026-07-28 notes. - The transport accepts it, or not. Over HTTP: the
Hostheader must be an allowed host and anOrigin, when there is one, an allowed origin; yourauthenticateruns, thenresolveServerpicks the tool set for that caller. On Node,serveHttpalso limits requests per minute (300 by default). See transports and authentication. - The SDK server finds the tool in the registry the transport chose.
- Core validates the arguments against the tool’s input schema. Arguments that do not fit are refused before any of your code runs.
- Middleware and the handler run inside one timeout (30 seconds unless the app or the tool
sets another) and with the client’s cancellation signal: app middleware first, then the tool’s,
then the handler. See middleware.
- A TypeScript tool’s handler is your function.
- A spec tool’s handler is generated: it fills the URL template, checks the address the
host name resolves to, makes the request with the spec’s limits, redacts secret values from
the response, and runs
selectin a separate process.
- The result goes back. With an output schema, the result becomes
structuredContentand is checked against the schema. AToolError’s message reaches the client; any other error is logged with a reference and the client sees onlyInternal error in tool "x" (ref: ...). See errors.
What every tool gets, and what spec tools add
| Every tool | Spec tools also |
|---|---|
| Arguments validated before the handler | SSRF protection: public addresses only, DNS resolved once and the connection pinned to the checked address |
| A timeout on every call, and the client’s cancellation | Secret values redacted from results, errors and logs |
Errors masked unless they are a ToolError | A rate limit per tool (60 calls a minute, 10 at once, unless the spec says otherwise) |
| Output checked against the output schema, when there is one | select in a separate process without network or environment |
A TypeScript tool that calls an API does so with your own fetch: the spec-tool protections do
not apply to it. To give one code server both, load a spec into it.
Tools that change while the server runs
The tools an app serves live in its registry. app.tool(), app.replaceTool() and
app.removeTool() change it at any time, also while clients are connected; kervan dev and
kervan run --watch do the same when a file changes. Connected clients are told with
notifications/tools/list_changed, once per batch of changes and only when the list really
changed. 2025-era clients over HTTP are the exception: they are served without a session, so
they see the change on their next tools/list. See a registry that changes at runtime.