mcp-ts-template

作者 cyanheads已验证

TypeScript template for building Model Context Protocol (MCP) servers. Ships with declarative tools/resources, pluggable auth, multi-backend storage, OpenTelemetry observability, and first-class support for both local and edge (Cloudflare Workers) runtimes.

119
Stars
20
Forks
TypeScript
语言
2026/8/23
添加时间

⚠️ 第三方软件声明

本 Skill 为第三方开源软件,独立托管于 GitHub。SkillTip 仅为信息目录,不控制或维护底层仓库。所显示的安全检查为自动化且范围有限,安装前请自行审查源码。

阅读服务条款

安装

添加到你的 Claude Code skills 目录:

# Add to your Claude Code skills
git clone https://github.com/cyanheads/mcp-ts-template

快速入门

使用 mcp-ts-template 等 Skills 的指南。

安全报告

已验证

上次扫描:—

{
  "status": "PASSED",
  "issues": []
}

README.md

@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.

Version License MCP Spec

MCP SDK TypeScript Bun

Framework


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.

import { createApp, tool, z } from '@cyanheads/mcp-ts-core';
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';

const search = tool('search', {
  description: 'Search the catalog and return ranked matches.',
  annotations: { readOnlyHint: true },
  input: z.object({
    query: z.string().describe('Search terms'),
    limit: z.number().default(10).describe('Max results'),
  }),
  output: z.object({
    items: z.array(z.string()).describe('Matching item names, best first'),
  }),
  enrichment: {
    effectiveQuery: z.string().describe('Query as the server parsed it'),
    totalCount: z.number().describe('Total matches before the limit'),
    notice: z.string().optional().describe('Guidance when nothing matched'),
  },
  errors: [
    {
      reason: 'index_unavailable',
      code: JsonRpcErrorCode.ServiceUnavailable,
      when: 'The upstream search index is unreachable.',
      retryable: true,
      recovery: 'Retry in a few seconds — the index may be briefly unavailable.',
    },
  ],
  handler: async (input, ctx) => {
    const res = await runSearch(input.query, input.limit);
    if (!res) throw ctx.fail('index_unavailable'); // genuine failure → typed error contract
    ctx.enrich({ effectiveQuery: res.parsed, totalCount: res.total });
    if (res.items.length === 0) {
      ctx.enrich({ notice: `No matches for "${input.query}". Try broader terms.` }); // empty result → notice, not a throw
    }
    return { items: res.items }; // enrichment never rides in the domain return
  },
});

await createApp({ tools: [search] });

That's a complete MCP server, and it shows both of the framework's core contracts.

enrichment carries the context an agent reasons with (the parsed query, the true total, an empty-result notice); the framework merges it into structuredContent and mirrors it into content[], so structuredContent-only clients (Claude Code) and content[]-only clients (Claude Desktop) both see it, no format() needed. The typed errors[] contract handles genuine failures (an empty result is a notice, not a throw), and the linter cross-checks both against the handler body. Both publish in tools/list, so clients preview a tool's success and failure shapes.

The rest is automatic: every tool call is logged with duration, payload sizes, and request correlation, and createApp() handles config parsing, logger init, transport startup, signal handlers, and graceful shutdown.

Quick start

bunx @cyanheads/mcp-ts-core init my-mcp-server
cd my-mcp-server
bun install

You get a scaffolded project with CLAUDE.md/AGENTS.md, Agent Skills, plugin metadata (Codex + Claude Code), and a src/ tree ready for your tools. Infrastructure (transports, auth, storage, telemetry, lifecycle, linting) lives in node_modules. What's left is domain: which APIs to wrap, which workflows to expose.

Start your coding agent (e.g. Claude Code, Codex) and describe what you want. The agent knows what to do from there. The included Agent Skills cover the full cycle: setup, design-mcp-server, scaffolding, testing, security-pass, release-and-publish, maintenance, & more.

What you get

The headline tool returns structured output. Clients that read structuredContent (Claude Code) get it directly. To also render markdown for clients that read content[] (Claude Desktop), add a format(). The format-parity linter checks it renders every output field, so the two surfaces never drift:

import { tool, z } from '@cyanheads/mcp-ts-core';

export const itemSearch = tool('item_search', {
  description: 'Search for items by query.',
  input: z.object({
    query: z.string().describe('Search query'),
    limit: z.number().default(10).describe('Max results'),
  }),
  output: z.object({
    items: z.array(z.string()).describe('Search results'),
  }),
  async handler(input) {
    const results = await doSearch(input.query, input.limit);
    return { items: results };
  },
  format: (result) => [
    { type: 'text', text: result.items.map((name) => `- ${name}`).join('\n') },
  ],
});

And resources:

import { resource, z } from '@cyanheads/mcp-ts-core';

export const itemData = resource('items://{itemId}', {
  description: 'Retrieve item data by ID.',
  params: z.object({
    itemId: z.string().describe('Item ID'),
  }),
  async handler(params, ctx) {
    return await getItem(params.itemId);
  },
});

Everything registers through createApp() in your entry point:

await createApp({
  name: 'my-mcp-server',
  version: '0.1.0',
  tools: allToolDefinitions,
  resources: allResourceDefinitions,
  prompts: allPromptDefinitions,
  instructions: 'Brief composition hints for the model.', // optional, sent on every `initialize`
});

It also works on Cloudflare Workers with createWorkerHandler() — same definitions, different entry point.

Features

  • Declarative definitionstool(), resource(), prompt() builders with Zod schemas; appTool()/appResource() add interactive HTML UIs.
  • Server-level orientationinstructions on createApp/createWorkerHandler rides every initialize for the model. Cross-tool composition hints, regional notes, scope guidance — without leaking text into every tool description.
  • Server identity — optional title, websiteUrl, description, icons (SEP-973) on createApp/createWorkerHandler flow to initialize serverInfo, the /.well-known/mcp.json server card, and the landing page.
  • Unified Context — one ctx for logging, tenant-scoped storage, multi-round-trip input collection, and cancellation. Context extends RequestContext, so a handler's ctx goes straight into any service or storage call.
  • Authauth: ['scope'] on definitions, checked before dispatch (no wrapper code). Modes: none, jwt, or oauth (local secret or JWKS).
  • Two protocol revisions, one handler — HTTP serves both the 2026-07-28 revision (per-request _meta envelope, no session) and the initialize-negotiated 2025 era (sessionful, identity-bound). Handlers are written once; the SDK's legacy shim fulfils multi-round-trip input for 2025-era clients.
  • Multi-round-trip input — a handler returns ctx.requestInput(...) for a confirmation, a sampling call, or the client's roots, and is re-entered with the answers on ctx.inputs.
  • Definition linter — validates names, schemas, auth scopes, annotations, format-parity, and cross-vendor JSON Schema portability at build time. Run via lint:mcp or devcheck — not invoked at server startup.
  • Typed error contracts — declare errors: [{ reason, code, when, recovery, retryable? }] and handlers get a typed ctx.fail(reason, …). Contracts publish in tools/list so clients preview failure modes; the linter cross-checks the handler. Factories (notFound(), httpErrorFromResponse(), …) cover ad-hoc throws; plain Error auto-classifies.
  • Multi-backend storagein-memory, filesystem, Supabase, Cloudflare D1/KV/R2. Swap via env var; handlers don't change.
  • DataCanvas (optional) — Tier 3 SQL/analytical workspace backed by DuckDB. Register tabular data from upstream APIs, run SQL across registered tables, export CSV/Parquet/JSON. Token-sharing model (opaque canvas_id) for multi-agent collaboration; sliding TTL + per-tenant scoping. Opt-in via CANVAS_PROVIDER_TYPE=duckdb; fails closed on Workers.
  • Observability — Pino logging + optional OpenTelemetry traces/metrics. Request correlation and tool metrics automatic.
  • Tiered dependencies — parsers, OTEL SDK, Supabase, OpenAI as optional peers. Install what you use.
  • Agent-first DX — ships CLAUDE.md / AGENTS.md and Agent Skills that give your coding agent full framework knowledge — it can scaffold tools, write tests, run security audits, and ship releases without you writing the boilerplate.

Server structure

my-mcp-server/
  src/
    index.ts                              # createApp() entry point
    worker.ts                             # createWorkerHandler() (optional)
    config/
      server-config.ts                    # Server-specific env vars
    services/
      [domain]/                           # Domain services (init/accessor pattern)
    mcp-server/
      tools/definitions/                  # Tool definitions (.tool.ts)
      resources/definitions/              # Resource definitions (.resource.ts)
      prompts/definitions/                # Prompt definitions (.prompt.ts)
  package.json
  tsconfig.json                           # extends @cyanheads/mcp-ts-core/tsconfig.base.json
  CLAUDE.md / AGENTS.md                   # Point to core's CLAUDE.md / AGENTS.md for framework docs

No src/utils/, no src/storage/, no src/types-global/, no src/mcp-server/transports/ — infrastructure lives in node_modules.

Configuration

All core config is Zod-validated from environment variables. Server-specific config uses a separate Zod schema with lazy parsing.

VariableDescriptionDefault
MCP_TRANSPORT_TYPEstdio or httpstdio
MCP_HTTP_PORTHTTP server port3010
MCP_HTTP_HOSTHTTP server hostname127.0.0.1
MCP_AUTH_MODEnone, jwt, or oauthnone
MCP_AUTH_SECRET_KEYJWT signing secret (required for jwt mode)
STORAGE_PROVIDER_TYPEin-memory, filesystem, supabase, cloudflare-d1/kv/r2in-memory
CANVAS_PROVIDER_TYPEnone or duckdb (Tier 3, optional peer dep @duckdb/node-api)none
OTEL_ENABLEDEnable OpenTelemetryfalse
OPENROUTER_API_KEYOpenRouter LLM API key

See CLAUDE.md/AGENTS.md for the full configuration reference.

API overview

Entry points

FunctionPurpose
createApp(options)Node.js server — handles full lifecycle
createWorkerHandler(options)Cloudflare Workers — returns an ExportedHandler

Builders

BuilderUsage
tool(name, options)Define a tool with handler(input, ctx)
resource(uriTemplate, options)Define a resource with handler(params, ctx)
prompt(name, options)Define a prompt with generate(args)
appTool(name, options)Define an MCP Apps tool with auto-populated _meta.ui
appResource(uriTemplate, options)Define an MCP Apps HTML resource with the correct MIME type and _meta.ui mirroring for read content

Context

Handlers receive a unified Context object:

PropertyTypeDescription
ctx.logContextLoggerRequest-scoped logger (auto-correlates requestId, traceId, tenantId); also mirrored to the client as notifications/message
ctx.stateContextStateTenant-scoped key-value storage
ctx.requestInput(spec) => neverSuspend and ask the caller for more input; the handler is re-entered with the answers
ctx.inputsContextInputsReader over a retried request's responses — .accepted(), .view(), .state(), .dropped
ctx.fail(reason, msg?, data?) => McpErrorTyped error throw — reason checked against errors[] contract at compile time
ctx.signalAbortSignalCancellation signal
ctx.notifyResourceUpdatedFunction?Notify subscribed clients a resource changed
ctx.notifyResourceListChangedFunction?Notify clients the resource list changed
ctx.notifyPromptListChangedFunction?Notify clients the prompt list changed
ctx.notifyToolListChangedFunction?Notify clients the tool list changed
ctx.requestIdstringUnique request ID
ctx.tenantIdstring?Tenant ID (JWT tid claim, or 'default' for stdio and HTTP+MCP_AUTH_MODE=none)

Subpath exports

import { createApp, tool, resource, prompt } from '@cyanheads/mcp-ts-core';
import { createWorkerHandler } from '@cyanheads/mcp-ts-core/worker';
import { McpError, JsonRpcErrorCode, notFound, serviceUnavailable } from '@cyanheads/mcp-ts-core/errors';
import { checkScopes } from '@cyanheads/mcp-ts-core/auth';
import { markdown, fetchWithTimeout } from '@cyanheads/mcp-ts-core/utils';
import { OpenRouterProvider, GraphService } from '@cyanheads/mcp-ts-core/services';
import type { DataCanvas, CanvasInstance } from '@cyanheads/mcp-ts-core/canvas';
import { validateDefinitions } from '@cyanheads/mcp-ts-core/linter';
import { createMockContext } from '@cyanheads/mcp-ts-core/testing';
import { fuzzTool, fuzzResource, fuzzPrompt } from '@cyanheads/mcp-ts-core/testing/fuzz';

See CLAUDE.md/AGENTS.md for the complete exports reference.

Examples

The examples/ directory contains a reference server consuming core through public exports, demonstrating all patterns:

ToolPattern
template_echo_messageBasic tool with format, auth
template_cat_factExternal API call, error factories
template_madlibs_elicitationctx.requestInput / ctx.inputs for multi-round-trip input
template_image_testImage content blocks
template_data_explorerMCP Apps with linked UI resource via appTool()/appResource() builders

Testing

import { createMockContext } from '@cyanheads/mcp-ts-core/testing';
import { myTool } from '@/mcp-server/tools/definitions/my-tool.tool.js';

const ctx = createMockContext();
const input = myTool.input.parse({ query: 'test' });
const result = await myTool.handler(input, ctx);

createMockContext() provides a recording log, a working state, and a signal. State runs on a real StorageService over an in-memory provider — the same key validation and TTL expiry a deployed server applies — scoped to tenant 'default' unless { tenantId } says otherwise. Pass { errors: myTool.errors } for a typed ctx.fail matching the definition's contract, and { inputResponses, requestState } to drive a multi-round-trip handler into its second round.

/testing also exports createMockSession() for session-bound contexts, createFetchMock() for upstream HTTP boundaries, and runToolContract() to drive a definition through schema, handler, formatting, and error-envelope checks. /testing/vitest adds the mcpTest fixtures (ctx, session, fetchMock, storage) and toolContractSuite().

Fuzz testing

Schema-aware fuzz testing via fast-check. Generates valid inputs from Zod schemas and adversarial payloads (prototype pollution, injection strings, type confusion) to verify handler invariants.

import { fuzzTool } from '@cyanheads/mcp-ts-core/testing/fuzz';

const report = await fuzzTool(myTool, { numRuns: 100 });
expect(report.crashes).toHaveLength(0);
expect(report.leaks).toHaveLength(0);
expect(report.prototypePollution).toBe(false);

Also exports fuzzResource, fuzzPrompt, zodToArbitrary, and ADVERSARIAL_STRINGS for custom property-based tests.

Documentation

  • CLAUDE.md/AGENTS.md — Framework reference: exports catalog, patterns, Context interface, error codes, auth, config, testing. Ships in the npm package and is auto-accessible in your project after init.
  • docs/telemetry/ — OpenTelemetry: full catalog of spans, metrics, and attributes the framework emits (observability.md), plus an example Grafana dashboard and vendor-agnostic query recipes for Datadog, New Relic, Honeycomb (dashboards.md).
  • CHANGELOG.md — Version history. Each entry includes a summary, migration notes, and links to commits/issues.

Development

bun run rebuild        # clean + build (scripts/clean.ts + scripts/build.ts)
bun run devcheck       # full gate: lint/format, typecheck, MCP defs, framework antipatterns, docs/skills/changelog sync, tests, audit, outdated, secrets/TODO scan
bun run lint:mcp       # validate MCP definitions against spec
bun run test:all       # vitest: unit + Workers pool + integration

License

Apache 2.0 — see LICENSE.


常见问题

What is mcp-ts-template?

mcp-ts-template is an open-source ai agents skill for AI coding assistants such as Claude Code, Codex CLI, and ChatGPT, built by cyanheads. TypeScript template for building Model Context Protocol (MCP) servers. Ships with declarative tools/resources, pluggable auth, multi-backend storage, OpenTelemetry observability, and first-class support for both local and edge (Cloudflare Workers) runtimes. It has 119 GitHub stars.

Is mcp-ts-template safe to use?

Yes. mcp-ts-template passed SkillsLLM's automated security scan — a dependency vulnerability audit plus prompt-injection heuristics — with no high-severity issues. You can read the full report in the Security Report section on this page.

How do I install mcp-ts-template?

Clone the repository with "git clone https://github.com/cyanheads/mcp-ts-template" and add it to your Claude Code skills directory (see the Installation section above).

What programming language is mcp-ts-template written in?

mcp-ts-template is primarily written in TypeScript. It is open-source under cyanheads on GitHub, so you can review or fork the full source.

Are there alternatives to mcp-ts-template?

Yes. SkillsLLM lists many other AI Agents skills you can browse and compare side by side. Open the AI Agents category from the badge at the top of this page, or use the Related Skills and comparison links further down to weigh mcp-ts-template against similar tools.

评论 (0)

暂无评论,成为第一个分享想法的人!

ECC

by affaan-m

10

The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.

242,21936,702JavaScript
AI 智能体ai-agentsanthropicclaude-code
查看详情
15

An agentic skills framework & software development methodology that works.

234,96620,863Shell
AI 智能体ai-agentsbrainstorming
查看详情

hermes-agent

by NousResearch

10

The agent that grows with you

234,43747,175Python
AI 智能体ai-agentsagent-orchestration
查看详情

The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.

185,94028,768JavaScript
AI 智能体ai-agentsanthropicclaude-code
查看详情

cc-switch

by farion1231

3

A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io

128,8688,826Rust
AI 智能体claude-codeai-tools
查看详情

claude-code

by anthropics

Claude Code is an agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster by executing routine tasks, explaining complex code, and handling git workflows - all through natural language commands.

120,03119,897Shell
AI 智能体
查看详情

开发者还喜欢

基于喜欢此 Skill 的开发者投票和收藏

ECC

by affaan-m

10

The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.

242,21936,702JavaScript
AI 智能体ai-agentsanthropicclaude-code
查看详情
15

An agentic skills framework & software development methodology that works.

234,96620,863Shell
AI 智能体ai-agentsbrainstorming
查看详情

hermes-agent

by NousResearch

10

The agent that grows with you

234,43747,175Python
AI 智能体ai-agentsagent-orchestration
查看详情

n8n

by n8n-io

12

Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.

201,88160,308TypeScript
MCP 服务器apisai-tools
查看详情

The agent harness performance optimization system. Skills, instincts, memory, security, and research-first development for Claude Code, Codex, Opencode, Cursor and beyond.

185,94028,768JavaScript
AI 智能体ai-agentsanthropicclaude-code
查看详情

cc-switch

by farion1231

3

A cross-platform desktop All-in-One assistant for Claude Code, Codex, OpenCode, OpenClaw, Grok Build & Hermes Agent. Only official website: ccswitch.io

128,8688,826Rust
AI 智能体claude-codeai-tools
查看详情