Skip to main content
Glama
mcpkit

mcpkit

by EuKennedy

mcpkit

ci release license node

用于构建 MCP 服务器且无需样板代码的 TypeScript 工具包。

只需定义一个 Zod 模式和一个处理程序,即可获得一个可用的 Model Context Protocol 服务器——模式生成、输入验证、错误封装、传输连接,一切都已完成。

import { defineServer, defineTool } from 'mcpkit';
import { z } from 'zod';

const server = defineServer({
  name: 'demo',
  version: '0.1.0',
  tools: [
    defineTool({
      name: 'add',
      description: 'Add two numbers.',
      input: z.object({ a: z.number(), b: z.number() }),
      handler: ({ a, b }) => `${a + b}`,
    }),
  ],
});

await server.start();

这是一个真实、功能完备的 MCP 服务器。使用 mcpkit dev 运行它,并将任何支持 MCP 的客户端指向它即可。


为什么存在这个项目

使用官方 SDK 编写 MCP 服务器是可以的,但你每次都需要做同样的繁琐工作:

  • 在一处声明工具列表

  • 为每个工具声明单独的 JSON Schema

  • 在调用处理程序中编写针对工具名称的 switch 语句

  • 将处理程序的返回值强制转换为协议的内容信封

  • 连接传输层

  • 捕获错误并将其转换为正确的 isError 格式

mcpkit 将所有这些简化为 defineTool + defineServer。模式由你的 Zod 类型生成,验证在处理程序之前运行,错误会转换为正确的协议响应,字符串返回值会变成文本内容块。你只需专注于真正重要的事情——工具的功能——而跳过那些不重要的层级。

Related MCP server: xmcp Application

对比:使用 vs 不使用

同一个工具,分别使用原生 SDK 和 mcpkit 编写:

const server = new Server(
  { name: 'demo', version: '0.1.0' },
  { capabilities: { tools: {} } },
);

server.setRequestHandler(
  ListToolsRequestSchema,
  async () => ({
    tools: [
      {
        name: 'add',
        description: 'Add two numbers.',
        inputSchema: {
          type: 'object',
          properties: {
            a: { type: 'number' },
            b: { type: 'number' },
          },
          required: ['a', 'b'],
        },
      },
    ],
  }),
);

server.setRequestHandler(
  CallToolRequestSchema,
  async (req) => {
    if (req.params.name === 'add') {
      const { a, b } = req.params.arguments as {
        a: number; b: number;
      };
      return {
        content: [{ type: 'text', text: `${a + b}` }],
      };
    }
    throw new Error('unknown tool');
  },
);

await server.connect(new StdioServerTransport());
const server = defineServer({
  name: 'demo',
  version: '0.1.0',
  tools: [
    defineTool({
      name: 'add',
      description: 'Add two numbers.',
      input: z.object({
        a: z.number(),
        b: z.number(),
      }),
      handler: ({ a, b }) => `${a + b}`,
    }),
  ],
});

await server.start();

右侧列具有相同的底层行为,此外还增加了输入验证、类型化的处理程序参数,以及在未捕获异常时的 isError 信封。

安装

npm install mcpkit zod

或者搭建一个全新的项目(推荐用于第一个服务器):

npx mcpkit create my-server
cd my-server
npm run dev

你将获得一个包含可用 stdio 服务器、三个示例工具以及为严格模式配置的 tsconfig.json 的小型项目。用你的工具替换示例工具即可发布。

CLI

mcpkit create [target]   scaffold a new server from a template
mcpkit dev               run with hot reload (uses tsx under the hood)
mcpkit build             compile to dist/
mcpkit inspect           launch the official inspector against your server

create 目前提供四个模板:

模板

你将获得

stdio-basic

基于 stdio 的本地 MCP 服务器。大多数客户端需要此项。

http-streaming

基于可流式传输 HTTP 协议的网络可访问服务器。

with-fetch

带有 HTTP 获取工具(已内置超时)的 stdio 服务器。

with-sqlite

带有 SQLite 后端 CRUD 示例(better-sqlite3, WAL)的 stdio 服务器。

API

defineTool

defineTool({
  name: string,            // [a-zA-Z0-9_-]+
  description: string,     // shown to the client / LLM
  input: z.ZodType,        // Zod schema; converted to JSON Schema for you
  handler: (input) => string | ToolContent | ToolContent[] | { content, isError? }
})

处理程序输入通过 z.infer 完全类型化。返回字符串会将其包装为单个文本内容块——这是常见情况。在处理程序内部抛出异常会自动转换为 isError: true 响应;如果你想自定义错误消息,请向 defineServer 传递一个 onToolError 处理程序。

defineServer

defineServer({
  name: string,
  version: string,
  description?: string,
  tools?: ToolDefinition[],
  resources?: ResourceDefinition[],
  prompts?: PromptDefinition[],
  onToolError?: (err, toolName) => ToolResult,
  onEvent?: (event: ServerEvent) => void,
})

返回一个 DefinedServer,包含:

  • .start({ transport: 'stdio' }) — 连接传输层并启动服务。

  • .connect(transport) — 连接你自己构建的传输实例(HTTP、自定义,任何像 Transport 的对象)。

  • .stop() — 关闭活动的传输层和底层服务器。

  • .raw — 如果你需要执行某些特殊操作,可获取底层的 SDK Server。

资源与提示词

相同的声明式结构:

defineResource({
  uri: 'file:///etc/hosts',
  name: 'hosts',
  mimeType: 'text/plain',
  read: async () => ({ text: await fs.readFile('/etc/hosts', 'utf8') }),
});

definePrompt({
  name: 'summarize',
  description: 'Summarize a chunk of text.',
  arguments: z.object({ text: z.string() }),
  build: ({ text }) => ({
    messages: [{ role: 'user', content: { type: 'text', text: `Summarize:\n${text}` } }],
  }),
});

可观测性

onEvent 为每个工具调用、资源读取和提示词获取提供结构化回调——开始时间、结束时间、延迟、错误,以及用于关联的每个调用的 requestId。你可以将其插入任何系统:pino、console、OpenTelemetry 或你自制的聚合器。对于简单情况,还内置了一个功能:

import { defineServer, consoleLogger, jsonLogger } from 'mcpkit';

const server = defineServer({
  name: 'demo',
  version: '0.1.0',
  onEvent: consoleLogger(),    // → pretty stderr lines
  // or: onEvent: jsonLogger() // → one JSON object per line, on stderr
  tools: [...]
});

日志始终输出到 stderr —— stdout 保留用于 stdio 传输上的协议流量。

测试

mcpkit/testing 公开了一个进程内客户端,通过内存传输与你的服务器通信——无需子进程,无需 stdio 管道,无需不稳定的进程销毁。与真实消费者使用的客户端相同,只是通过 RAM 路由。

import { describe, it, expect } from 'vitest';
import { createTestClient, expectToolError, snapshotTools } from 'mcpkit/testing';
import { server } from '../src/index.js';

describe('add', () => {
  it('adds', async () => {
    const client = await createTestClient(server);
    const result = await client.callTool('add', { a: 2, b: 3 });
    expect(result.text).toBe('5');
    expect(result.isError).toBe(false);
    await client.close();
  });

  it('rejects bad input', async () => {
    const client = await createTestClient(server);
    const text = await expectToolError(client, 'add', { a: 'nope', b: 1 });
    expect(text).toMatch(/invalid/i);
    await client.close();
  });

  it("doesn't drift its public surface", () => {
    expect(snapshotTools(server)).toMatchSnapshot();
  });
});

值得了解的设计选择

使用 Zod,而非原始 JSON Schema。 你只需编写一次类型。验证、为协议生成的 JSON Schema 以及处理程序的 TypeScript 推断都源自同一个来源。试图保持三个定义同步正是本项目旨在消除的样板工作。

错误是值,而非异常。 抛出异常的处理程序会变成 isError: true 内容信封。客户端看到的是合理的响应,而不是传输层级的失败。如果你想自己格式化错误,请覆盖 onToolError。

传输无关的核心。 同一个 defineServer 可在 stdio、可流式传输的 HTTP 传输、内存测试传输或任何实现 SDK Transport 接口的系统上工作。http-streaming 模板展示了连接方式。

默认严格模式。 模板默认带有 strict: true 和 noUncheckedIndexedAccess。库本身也在相同的设置下编译。如果你发现类型中有漏洞,那就是一个 bug。

监听器错误会被吞掉。 如果你的 onEvent 处理程序抛出异常,你的工具调用仍会继续工作。可观测性 bug 不应成为负载负担。

常见问题

这会让我永远被锁定在 mcpkit 中吗? 不会。每个辅助函数都有逃生舱 —— server.raw 会给你底层的 SDK Server,如果你需要 kit 尚未建模的功能,可以直接在其上调用 setRequestHandler。该 kit 是顶层的一层,而不是替代品。

为什么是 Zod 3 而不是 4? Zod 4 很棒,但生态系统(特别是 zod-to-json-schema)仍在追赶。当它在生产环境中稳定时,我们会迁移。如果你已经在用 Zod 4,模式接口足够兼容 —— 如果遇到问题,请提交 issue。

它是否支持资源和提示词,而不仅仅是工具? 是的。defineResource 和 definePrompt 是一等公民。它们的使用频率不如工具,因此大多数示例以工具为主 —— 但连接方式是相同的。

支持流式 HTTP、SSE,还是两者都支持? 流式 HTTP。旧的 HTTP+SSE 风格仍在 SDK 中,但正在被逐步淘汰 —— 如果你有理由需要它,defineServer 是传输无关的,你可以通过 .connect() 传递任何 Transport 实例。

生产就绪吗? 该库很小,且范围是有意缩小的。官方 SDK 在底层完成了繁重的工作。锁定版本,为你的工具编写测试(进程内客户端使这变得容易),你就准备好了。

这不是什么

  • 不是托管服务。你需要自己构建、自己部署。

  • 不是代理框架。它构建的是 MCP 的服务器端,而不是客户端。

  • 不会对你的领域有偏见。工具就是函数;它们做什么取决于你。

路线图

  • 更多模板(OAuth 保护、边缘运行时、drizzle/postgres)。

  • 一个 mcpkit publish 命令,用于 lint + 打包 + 标记发布。

  • 更丰富的测试辅助工具(模糊测试工具输入、针对基准的模式差异对比)。

  • 可选的 onEvent OpenTelemetry 适配器。

如果缺少某些功能,请提交 issue 并附上你想要的 API 草图。

许可证

MIT。

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    A TypeScript-based template for rapidly developing MCP servers with modular tool architecture, built-in validation using Zod schemas, and comprehensive error handling.
    2 npm
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A template for building MCP servers with automatic tool discovery using TypeScript and Zod schemas, supporting HTTP and STDIO transports.
    21,338 npm
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    A production-ready boilerplate for building MCP servers, featuring TypeScript, Zod validation, rate limiting, and example tools like echo and fetch_url, enabling quick setup of custom MCP servers.
    2
    1
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    A starter template for building MCP servers with Zod-validated tools, unit tests, and MCP Inspector integration. It enables developers to quickly scaffold and develop protocol-compliant servers with a one-command dev loop.
    2
    62 npm
    MIT