Skip to main content
Glama
EuKennedy

mcpkit

by EuKennedy

mcpkit

ci release license node

TypeScript-инструментарий для создания MCP-серверов без лишнего шаблонного кода.

Определите инструмент с помощью схемы 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-совместимый клиент.


зачем это нужно

Написание MCP-сервера с использованием официального SDK — это нормально, но вам приходится выполнять одну и ту же рутинную работу каждый раз:

  • объявление списка инструментов в одном месте

  • объявление отдельной JSON-схемы для каждого инструмента

  • написание конструкции 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

локальный MCP-сервер через stdio. большинство клиентов хотят именно это.

http-streaming

доступный по сети сервер через потоковый HTTP-транспорт.

with-fetch

stdio-сервер с инструментами для HTTP-запросов (тайм-ауты настроены).

with-sqlite

stdio-сервер с примером CRUD на базе SQLite (better-sqlite3, WAL).

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; если вы хотите настроить сообщение об ошибке, передайте обработчик onToolError в defineServer.

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 — базовый Server из SDK, если вам нужно сделать что-то нестандартное.

ресурсы и промпты

Такая же декларативная форма:

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-схема. Вы пишете тип один раз. Валидация, сгенерированная JSON-схема для протокола и вывод типов TypeScript для обработчика — всё это получается из одного источника. Попытка синхронизировать три определения — это тот самый шаблонный код, который этот проект призван удалить.

Ошибки — это значения, а не исключения. Обработчик, который выбрасывает исключение, становится конвертом содержимого isError: true. Клиент видит разумный ответ вместо сбоя на уровне транспорта. Если вы предпочитаете форматировать ошибку самостоятельно, переопределите onToolError.

Ядро, не зависящее от транспорта. Один и тот же defineServer работает через stdio, потоковый HTTP-транспорт, внутрипроцессный тестовый транспорт или что угодно другое, что реализует интерфейс Transport из SDK. Шаблон http-streaming показывает, как это настроить.

Строгий режим по умолчанию. Шаблоны поставляются с strict: true и noUncheckedIndexedAccess. Сама библиотека компилируется с теми же настройками. Если вы найдете дыру в типах, это баг.

Ошибки слушателей игнорируются. Если ваш обработчик onEvent выбрасывает исключение, ваши вызовы инструментов продолжают работать. Баги наблюдаемости не должны быть критическими.

faq

Привязывает ли меня это к mcpkit навсегда? Нет. У каждого помощника есть «аварийный выход» — server.raw дает вам базовый Server из SDK, и вы можете напрямую вызвать setRequestHandler на нем, если вам нужно что-то, что комплект еще не моделирует. Комплект — это слой поверх, а не замена.

Почему Zod 3, а не 4? Zod 4 великолепен, но экосистема (в частности zod-to-json-schema) всё еще догоняет. Мы перейдем, когда он станет стабильным в продакшене. Если вы уже используете Zod 4, интерфейсы схем достаточно совместимы — создайте issue, если столкнетесь с проблемой.

Поддерживает ли он ресурсы и промпты, а не только инструменты? Да. defineResource и definePrompt являются первоклассными гражданами. Они используются реже, чем инструменты, поэтому большинство примеров начинаются с инструментов, но настройка идентична.

Потоковый HTTP, SSE, оба? Потоковый HTTP. Старый вариант HTTP+SSE все еще есть в SDK, но он постепенно выводится из эксплуатации — если у вас есть причина использовать его, defineServer не зависит от транспорта, и вы можете передать любой экземпляр Transport через .connect().

Готов к продакшену? Библиотека небольшая, и область применения намеренно узкая. Официальный SDK выполняет всю тяжелую работу под капотом. Зафиксируйте версию, напишите тесты для своих инструментов (внутрипроцессный клиент делает это простым), и вы готовы.

чем это не является

  • не хостинговый сервис. вы создаете, вы развертываете.

  • не агентский фреймворк. он создает серверную сторону MCP, а не клиентскую.

  • не навязывает мнение о вашей предметной области. инструменты — это функции; что они делают — ваша проблема.

дорожная карта

  • больше шаблонов (защищенные oauth, edge runtime, drizzle/postgres).

  • команда mcpkit publish, которая выполняет линтинг + упаковку + тегирование релиза.

  • более богатые помощники для тестирования (фаззинг входных данных инструмента, сравнение схемы с базовой линией).

  • опциональный адаптер OpenTelemetry для onEvent.

Если чего-то не хватает, откройте 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.
    5 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.
    8,467 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
    24 npm
    MIT