mcpField
M
MCP TypeScript Template 🚀

MCP TypeScript Template 🚀

本地服务
npmjs.com开发工具1522 天前更新

关于 MCP TypeScript Template 🚀

MCP TypeScript Template 是面向 MCP 服务开发者的 TypeScript 框架,可将 API、数据集或工作流接入 MCP。它提供类型化定义、运行时基础设施和 Agent 技能,支持构建、测试与维护服务。

主要功能

  1. 01用于工具、资源、提示词和 MCP Apps 的类型化构建器
  2. 02JWT/OAuth 权限范围与租户级存储
  3. 03支持 stdio、HTTP 和 Cloudflare Workers
  4. 04定义检查、测试、日志及可选 OpenTelemetry

适用场景

  1. 01将 API 或数据集开放给 MCP 客户端
  2. 02构建带权限控制和状态存储的服务
  3. 03在开发时检查定义与工具行为

MCP 相关

它提供创建 MCP 服务所需的框架和运行时。创建的服务通过 stdio 或 HTTP 向 MCP 客户端开放工具、资源、提示词和 MCP Apps。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

暂未收录安装方式

我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。

代码仓库

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

@cyanheads/mcp-ts-core

用于构建 MCP 服务的 Agent 原生 TypeScript 框架。

为服务提供运行时基础设施,并提供用于构建、测试和发布服务的 Agent 技能。


为任何你能描述的需求构建 AI 工具

通过模型上下文协议(MCP),将 API、数据集或工作流连接到 AI Agent。项目负责领域代码;@cyanheads/mcp-ts-core 则负责底层的身份验证、存储、日志记录和传输。

Agent 原生。 每个脚手架都附带框架参考资料和一组 Agent Skills:涵盖工具设计、测试编写、安全审查和发布的工作流。你决定服务要做什么;你的 Agent 会遵循这些技能来构建服务。

框架始终作为依赖项使用。 基础设施修复通过升级包即可获取。运行 maintenance 技能,你的 Agent 就会升级 core、同步最新技能并采用更新内容。

快速开始

服务可运行于 Bun、Node.js 24+ 或 Cloudflare Workers。

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

脚手架包含源代码目录树、构建和测试配置、CLAUDE.md/AGENTS.md、Agent Skills,以及适用于 Claude Code 和 Codex 的插件元数据。在 Claude Code、Codex 或其他 Agent 中打开项目,并描述你的需求:

为我团队的库存 API 构建一个 MCP 服务。我们需要查找产品、检查各仓库的库存、调查库存变动,以及记录库存调整和转移。开始吧。

已经有 TypeScript 项目?运行 bun add @cyanheads/mcp-ts-core,然后使用 createApp() 注册你的定义。

工具由架构和函数组成

这是一个完整的服务,用于搜索包含三个项目的目录。要试用它,请将脚手架中的 src/index.ts 替换为以下内容:

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

const catalog = ['Notebook', 'Mechanical pencil', 'Desk lamp'];

const search = tool('catalog_search', {
  description: 'Search catalog item names. An empty query lists all items.',
  annotations: { readOnlyHint: true },
  input: z.object({
    query: z.string().describe('Text to find in an item name'),
  }),
  output: z.object({
    items: z.array(z.string()).describe('Matching item names'),
  }),
  async handler({ query }) {
    return {
      items: catalog.filter((name) =>
        name.toLowerCase().includes(query.toLowerCase()),
      ),
    };
  },
});

await createApp({ name: 'catalog-mcp-server', title: 'catalog-mcp-server', tools: [search] });

构建并通过 HTTP 运行:

bun run rebuild
bun run start:http

将 MCP 客户端指向 http://127.0.0.1:3010/mcp(Streamable HTTP),或者让客户端通过 bun /absolute/path/to/dist/index.js 使用 stdio 启动服务。

功能一览

你的需求…框架提供的功能
为助手提供实用能力用于工具、资源、提示词和交互式 MCP Apps 的类型化构建器
帮助 Agent 正确使用这些能力服务说明、结果增强,以及附带恢复指导的已声明错误
控制访问并保留状态JWT/OAuth、按定义配置的作用域,以及支持切换后端的租户隔离存储
在本地运行或托管服务Bun/Node.js 上的 stdio 和 HTTP;用于 Cloudflare Workers 的独立入口点
了解故障并发现问题结构化日志、可选的 OpenTelemetry、定义检查、契约测试和模糊测试

可选集成(DuckDB、Supabase、OpenTelemetry SDK)属于对等依赖;需要时再安装。

为 Agent 提供有用的结果

两个声明式契约决定了 Agent 会收到什么内容。enrichment 携带成功路径的上下文(总数、解析后的查询、无结果提示),通过 ctx.enrich() 填充。errors 列出每种预期失败及其恢复指南,处理程序通过类型化的 ctx.fail() 抛出其中一种错误。

runSearch(query, limit) 代表你的搜索后端。它返回 { items, total, parsed },如果索引不可用则返回 null:

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().int().min(1).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');
    ctx.enrich({ effectiveQuery: res.parsed, totalCount: res.total });
    if (res.items.length === 0) {
      ctx.enrich({ notice: `No matches for "${input.query}". Try broader terms.` });
    }
    return { items: res.items }; // enrichment never rides in the domain return
  },
});

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

这两个契约都会在 tools/list 中公布,因此客户端在调用前就能看到它们;定义检查器也会据此检查处理程序。带有已声明原因的失败会到达客户端,并附上对应条目的恢复提示;每个工具错误还会携带请求 ID,服务器日志中也会记录该 ID。

客户端界面上的数据保持一致

不同 MCP 宿主会将工具结果的不同部分交给 Agent:structuredContent(JSON)、content[](文本),或两者都有。框架会用相同的数据填充两者,因此 Agent 在任何宿主上看到的结果都相同。

format() 用于呈现文本内容;如果没有提供,content[] 中会放入 JSON。如果任何输出字段未出现在呈现的文本中,格式一致性 lint 规则就会使 lint:mcp 失败。enrichment 无需配置 format() 项,因为框架会将其添加到两个界面中。这个格式化器会将条目呈现为 Markdown 列表:

format: (result) => [{
  type: 'text',
  text: result.items.length > 0
    ? result.items.map((name) => `- ${name}`).join('\n')
    : 'No matching items.',
}],
资源

资源通过 URI 暴露数据。此资源从你自己的 getItem() 服务读取数据:

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) {
    return await getItem(params.itemId);
  },
});

所有内容都通过入口点中的 createApp() 注册:

await createApp({
  name: 'my-mcp-server',
  title: 'my-mcp-server', // display name in client UIs
  tools: allToolDefinitions,
  resources: allResourceDefinitions,
  prompts: allPromptDefinitions,
  instructions: 'Brief composition hints for the model.', // optional, sent on every `initialize`
  skills: 'skills', // optional, serves root skills/ over the SEP-2640 Skills extension
});

在 Cloudflare Workers 上,createWorkerHandler() 会从单独的入口点接收相同的定义。

运行时和集成详情

  • 身份验证和存储: 在定义上声明 auth: ['scope'],即可在处理程序运行前,通过 JWT 或 OAuth 检查相应作用域。ctx.state 是按租户隔离的存储,可使用内存、文件系统、Supabase 或 Cloudflare D1/KV/R2,由配置决定。
  • 客户端交互: 返回 ctx.requestInput(...),即可向用户请求输入、向客户端的模型请求示例,或向客户端请求其根目录。处理程序会在 ctx.inputs 中收到答案后再次运行。
  • 协议兼容性: HTTP 支持 2026-07-28 客户端(每个请求均使用 _meta 信封)以及基于会话的 2025 年代客户端。对于旧版客户端,SDK 的兼容层会处理输入请求。
  • 服务呈现: instructions 可在 initialize 时向模型提供一次服务级指导,而不必将其写入每个工具的描述中。身份字段(title、websiteUrl、description、icons)会填充客户端的服务信息、/.well-known/mcp.json 服务卡片和 HTTP 着陆页。skills: 'skills' 会通过 SEP-2640 Skills 扩展(skills/list、skills/get)提供服务在根目录 skills/ 中发布的 Agent Skills,并由 lint:packaging 在构建时检查。
  • 定义检查: lint:mcp 会检查名称、架构、作用域、注解、格式一致性和 JSON Schema 可移植性。它在构建时运行,而非启动时运行,因此新增规则不会导致已部署的服务无法运行。
  • DataCanvas: 可选的 DuckDB 工作区,Agent 可在其中对暂存的 API 结果运行 SQL,并导出 CSV、Parquet 或 JSON。Agent 通过传递画布令牌来共享工作区。使用 CANVAS_PROVIDER_TYPE=duckdb 和 @duckdb/node-api 启用(仅限 Bun 或 Node.js)。brapi-mcp-server 演示了如何将 API 结果加载到数据框并进行查询。
  • 镜像: /mirror 模块会将上游的大型数据集持久化为本地副本,存储在嵌入式 SQLite 中,并可选配 FTS5 索引。这样工具就能在本地查询,而无需每次调用都对实时 API 分页请求。你需要编写 sync 导入器和架构;框架负责存储、可恢复的初始加载和增量刷新。仅限 Bun 或 Node.js(Node 上的 better-sqlite3 是可选的对等依赖项)。faa-aircraft-registry-mcp-server 以此方式提供完整的 FAA 注册信息。

配置和处理程序模式请参阅框架参考,Pino 日志记录以及 OpenTelemetry 跟踪和指标请参阅可观测性指南。

服务结构

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                   # Server conventions; points to core's framework reference

框架基础设施位于 node_modules 中;源代码树则存放服务的定义、配置和领域服务。

配置

核心配置来自环境变量,并使用 Zod 进行验证。每个服务专属变量都有自己的 schema,并采用延迟解析,以便 Workers 在请求时注入环境变量。

变量描述默认值
MCP_TRANSPORT_TYPEstdio 或 httpstdio
MCP_HTTP_PORTHTTP 服务端口3010
MCP_HTTP_HOSTHTTP 服务主机名127.0.0.1
MCP_AUTH_MODEnone、jwt 或 oauthnone
MCP_AUTH_SECRET_KEYJWT 签名密钥(jwt 模式必需)—
MCP_REQUEST_STATE_KEY可选密钥(≥ 32 字节,所有实例都必须相同),用于封装处理程序返回的 requestState,并拒绝客户端未从此服务获取的任何值—
STORAGE_PROVIDER_TYPEin-memory、filesystem、supabase、cloudflare-d1/kv/r2in-memory
CANVAS_PROVIDER_TYPEnone 或 duckdb(可选的对等依赖项 @duckdb/node-api)none
OTEL_ENABLED启用 OpenTelemetryfalse
LOG_TOOL_FAILURE_PAYLOADS记录每次失败工具调用的参数和结果,并按键名进行脱敏(自由格式值中的密钥不会被检测到)false
LOG_TOOL_FAILURE_PAYLOAD_MAX_BYTES限制每条已记录负载的大小,以 UTF-8 字节数计16384
OPENROUTER_API_KEY可选 OpenRouter 大模型提供商(/services)的 API 密钥—

完整配置参考请参阅 CLAUDE.md/AGENTS.md。

API 概览

入口点
函数用途
createApp(options)Bun 或 Node.js 服务端;管理启动和关闭
createWorkerHandler(options)Cloudflare Workers — 返回一个 ExportedHandler
构建器
构建器用法
tool(name, options)使用 handler(input, ctx) 定义工具
resource(uriTemplate, options)使用 handler(params, ctx) 定义资源
prompt(name, options)使用 generate(args) 定义提示词
appTool(name, options)定义 MCP Apps 工具,并自动填充 _meta.ui
appResource(uriTemplate, options)定义 MCP Apps HTML 资源,使用正确的 MIME 类型,并为读取内容镜像设置 _meta.ui
上下文

工具和资源处理程序会接收一个 Context。ctx.enrich 和 ctx.fail 的类型根据定义中声明的契约确定:

属性类型描述
ctx.logContextLogger请求级日志记录器(自动关联 requestId、traceId、tenantId);同时会镜像到客户端,作为 notifications/message
ctx.stateContextState租户级键值存储
ctx.requestInput(spec) => never暂停并向调用方请求更多输入;处理程序会携带回答重新进入
ctx.inputsContextInputs此请求的响应,仅限客户端声明的类型 — .accepted()、.view()、.state()、.dropped
ctx.clientCapabilitiesClientCapabilities | undefined客户端为此请求声明的能力;决定是否请求可选上下文,而不是是否跳过同意提示
ctx.enrichEnrich / TypedEnrich<E>将已声明的结果上下文添加到结构化输出和文本内容中
ctx.contentContentCollect将图像/音频块附加到 content[] — content.image(data, mimeType)、content.audio(...) 或原始块
ctx.fail(reason, msg?, data?) => McpError创建供 throw ctx.fail(...) 使用的错误;需声明 errors 契约后方可使用
ctx.recoveryFor(reason) => object将已声明的恢复提示解析为 { recovery: { hint } };框架会自动将其与任何携带该原因且自身未提供提示的失败一并发送
ctx.signalAbortSignal取消信号
ctx.notifyResourceUpdatedFunction?通知已订阅的客户端资源已更改
ctx.notifyResourceListChangedFunction?通知客户端资源列表已更改
ctx.notifyPromptListChangedFunction?通知客户端提示词列表已更改
ctx.notifyToolListChangedFunction?通知客户端工具列表已更改
ctx.requestIdstring请求 ID — 由该调用的日志记录共享,并在其错误中作为 data.requestId 返回
ctx.tenantIdstring?租户 ID(JWT tid 声明;对于 stdio 和 HTTP+MCP_AUTH_MODE=none,则为 'default')
ctx.authAuthContext?请求经过身份验证时的令牌声明和作用域
ctx.sessionIdstring?有状态/auto 会话模式下的 HTTP 会话 ID — 用作作用域键,而非授权主体
ctx.uriURL?已解析的资源 URI;仅在资源处理程序中设置
子路径导出
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 { defineMirror, sqliteMirrorStore } from '@cyanheads/mcp-ts-core/mirror';
import { validateDefinitions } from '@cyanheads/mcp-ts-core/linter';
import { createMockContext } from '@cyanheads/mcp-ts-core/testing';
import { mcpTest, toolContractSuite } from '@cyanheads/mcp-ts-core/testing/vitest';
import { fuzzTool, fuzzResource, fuzzPrompt } from '@cyanheads/mcp-ts-core/testing/fuzz';
import { renderAppTool } from '@cyanheads/mcp-ts-core/testing/apps';

完整的导出参考请参阅 CLAUDE.md/AGENTS.md。

示例

examples/ 包含一个仅使用公共导出的参考服务。examples/index.ts(Node/Bun)和 examples/worker.ts(Cloudflare Workers)注册相同的 definitions/index.ts 汇总导出。

类型名称模式
工具template_echo_message使用 ctx.fail 的 errors[] 契约、inputAliases、保真度完整的 format()
工具template_cat_factfetchWithTimeout、类型化的未找到契约、增强回显
工具template_image_testctx.content.image
工具template_madlibs_elicitationreturn ctx.requestInput、包含 severity 的拒绝输入契约
工具template_data_explorerappTool/appResource、宿主主题、cacheHint
资源echo://{message}模板化资源
资源ui://template-data-explorer/app.html与 template_data_explorer 配对的 UI 资源
提示词code_reviewcompletable() 参数、code 参数

测试

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() 会提供一个记录日志的 log、一个 signal,以及一个由内存提供程序上的真实 StorageService 支撑的 state,因此键验证、TTL 过期和存储值的 JSON 往返行为都与生产环境一致:Date 读取时会变为 ISO 字符串,而 JSON 无法编码的值则会被拒绝。除非传入 { tenantId },否则它使用租户 'default'。传入 { errors: myTool.errors } 可获得类型安全的 ctx.fail;传入 { inputResponses, requestState } 可让多轮往返处理程序从第二轮开始;传入 { clientCapabilities } 可设置客户端声明的能力(预置响应随后会按声明的类型筛选,与生产环境一致)。

/testing 还导出用于会话绑定上下文的 createMockSession()、用于上游 HTTP 的严格模拟对象 createFetchMock(),以及 runToolContract(),后者会针对模式、处理程序、格式化和错误封装检查运行定义。/testing/vitest 添加了 mcpTest 测试夹具(ctx、session、fetchMock、storage)和 toolContractSuite()。

/testing/fuzz 使用 fast-check 根据你的 Zod 模式生成有效输入和对抗性载荷,然后检查是否发生崩溃、堆栈跟踪泄露和原型污染:

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);

它还导出 fuzzResource、fuzzPrompt、zodToArbitrary 和 ADVERSARIAL_STRINGS,供自定义基于属性的测试使用。

/testing/apps 是一个无头 MCP Apps 宿主。renderAppTool 会以 MCP Apps 客户端身份连接到你的服务,调用应用工具,在沙箱和 MCP Apps 规范所规定的 CSP 中将其 ui:// 视图加载到 chrome-headless-shell,针对该视图运行脚本化步骤,并返回报告:

import { renderAppTool } from '@cyanheads/mcp-ts-core/testing/apps';

const run = await renderAppTool({
  server: { command: 'bun', args: ['run', 'dist/index.js'] }, // or { url }
  tool: 'my_app_tool',
  arguments: { query: 'probe' },
  steps: [{ click: '#action-btn' }, { screenshot: 'after-click' }],
});
expect(run.initialized).toBe(true);
expect(run.errors).toHaveLength(0);
expect(run.cspViolations).toHaveLength(0);

报告还包含视图与宿主之间的所有消息、视图渲染出的文本,以及截图路径。也可以从命令行运行相同流程,将 report.json 和截图写入 --out 指定的目录:

bunx @cyanheads/mcp-ts-core app-render --tool my_app_tool --args '{"query":"probe"}' \
  --click '#action-btn' --out ./app-run -- bun run dist/index.js

它需要可选的对等依赖 @modelcontextprotocol/client 和 @modelcontextprotocol/ext-apps,以及 chrome-headless-shell 构建版本:可以使用 Puppeteer 缓存中最新的版本(npx @puppeteer/browsers install chrome-headless-shell@stable --path ~/.cache/puppeteer),也可以通过 browserPath、--browser 或 MCP_APPS_BROWSER_PATH 指定可执行文件路径。它不会搜索已安装的 Chrome、Edge、Brave 或 Chromium。

文档

  • CLAUDE.md/AGENTS.md:框架参考文档,涵盖导出内容、模式、Context、错误代码、身份验证、配置和测试。该文件随 npm 包发布,因此你的 Agent 会在 init 后从 node_modules 中读取它。
  • docs/telemetry/:框架发出的每个跨度、指标和属性(observability.md),以及 Grafana 仪表板示例和适用于 Datadog、New Relic 和 Honeycomb 的查询示例(dashboards.md)。
  • CHANGELOG.md:版本历史,每个版本在 changelog/ 下对应一个文件。每个文件都包含摘要、迁移说明,以及指向提交和问题的链接;需要下游更改的版本会附带 agent-notes,供 maintenance 技能处理。

开发

bun run rebuild        # clean + build (scripts/clean.ts + scripts/build.ts)
bun run devcheck       # full gate: lint/format, typecheck, MCP defs, packaging, framework antipatterns, docs/skills/changelog sync, audit, outdated, tracked-secrets and to-do marker scans
bun run lint:mcp       # validate MCP definitions against spec
bun run test:all       # rebuild + coverage + Node.js + Workers + integration
bun run test:package   # pack the tarball and consume it as an external project would
bun run test:soak      # sustained HTTP load; fails when the server heap grows per request

许可证

Apache 2.0 — 详见 LICENSE。


评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。