Main
Use this framework to standardize “how tools fail”:
- Keep tool schemas strict (Zod) and define recovery hints for expected failures.
- Emit telemetry by default so you can answer: which tools are slow, which inputs are large, where errors cluster.
- Treat the scaffolded
CLAUDE.md/ agent skills as the shared operating system for contributors.
README excerpt (verbatim)
@cyanheads/mcp-ts-core
Agent-native TypeScript framework for building MCP servers. Build tools, not infrastructure. Declarative definitions with auth, multi-backend storage, OpenTelemetry, and first-class support for Bun/Node/Cloudflare Workers.
What is this?
@cyanheads/mcp-ts-core is the infrastructure layer for TypeScript MCP servers. Install it as a dependency — don't fork it. Your agent collaborates with you to design and build the tools, resources, and prompts for your server.
The framework handles the plumbing: transports, auth, config, logging, telemetry, & more. Define your domain logic with the builders and let the framework take care of the rest.
import { createApp, tool, z } from '@cyanheads/mcp-ts-core';
const greet = tool('greet', {
description: 'Greet someone by name and return a personalized message.',
annotations: { readOnlyHint: true },
input: z.object({
name: z.string().describe('Name of the person to greet'),
}),
output: z.object({
message: z.string().describe('The greeting message'),
}),
errors: [
{
reason: 'name_blocked',
code: JsonRpcErrorCode.Forbidden,
when: 'The provided name is on the configured block list.',
recovery: 'Use a different name.',
},
],
handler: async (input, ctx) => {
if (isBlocked(input.name)) throw ctx.fail('name_blocked', `"${input.name}" is blocked`);
return { message: `Hello, ${input.name}!` };
},
});
await createApp({ tools: [greet] });FAQ
Q: Should I fork the repo? A: README suggests installing as a dependency rather than forking.
Q: What runtime is preferred? A: README highlights first-class Bun support; Node is also supported.
Q: What’s the main benefit? A: It handles transports/auth/telemetry so your server code stays domain-focused.