mcpkit
mcpkit
El kit de herramientas de TypeScript para crear servidores MCP sin código repetitivo.
Define una herramienta con un esquema de Zod y un manejador. Obtén un servidor del Model Context Protocol funcional: generación de esquemas, validación de entradas, sobres de error, configuración de transporte, todo hecho.
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();Eso es un servidor MCP real y funcional. Ejecútalo con mcpkit dev y apunta cualquier cliente compatible con MCP hacia él.
por qué existe esto
Escribir un servidor MCP con el SDK oficial está bien, pero terminas haciendo la misma fontanería cada vez:
declarar la lista de herramientas en un lugar
declarar un JSON Schema separado para cada herramienta
escribir un switch sobre los nombres de las herramientas en el manejador de llamadas
forzar los retornos del manejador dentro del sobre de contenido del protocolo
configurar un transporte
capturar errores y convertirlos a la forma
isErrorcorrecta
mcpkit colapsa todo eso en defineTool + defineServer. El esquema se genera a partir de tu tipo Zod, la validación se ejecuta antes de tu manejador, los errores se convierten en respuestas de protocolo adecuadas y un retorno de cadena se convierte en un bloque de contenido de texto. Te mantienes en la capa que realmente importa —lo que hace la herramienta— y te saltas la capa que no.
Related MCP server: xmcp Application
con vs sin
La misma herramienta, escrita contra el SDK básico y contra 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();La columna de la derecha tiene el mismo comportamiento a nivel de red, además de validación de entrada, argumentos de manejador tipados y un sobre isError en lanzamientos no capturados.
instalación
npm install mcpkit zodO crea un proyecto nuevo (recomendado para un primer servidor):
npx mcpkit create my-server
cd my-server
npm run devObtendrás un proyecto pequeño con un servidor stdio funcional, tres herramientas de ejemplo y un tsconfig.json configurado para modo estricto. Reemplaza las herramientas de ejemplo con las tuyas y publica.
la 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 servercreate se envía con cuatro plantillas hoy:
plantilla | qué obtienes |
| servidor MCP local sobre stdio. la mayoría de los clientes quieren esto. |
| servidor accesible por red sobre el transporte HTTP transmitible. |
| servidor stdio con herramientas de obtención HTTP (tiempos de espera configurados). |
| servidor stdio con un ejemplo CRUD respaldado por SQLite (better-sqlite3, WAL). |
la 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? }
})La entrada del manejador está totalmente tipada mediante z.infer. Devolver una cadena la envuelve como un bloque de contenido de texto único —ese es el caso común. Lanzar un error dentro de un manejador se convierte automáticamente en una respuesta isError: true; si deseas dar forma al mensaje de error, pasa un manejador onToolError a defineServer.
defineServer
defineServer({
name: string,
version: string,
description?: string,
tools?: ToolDefinition[],
resources?: ResourceDefinition[],
prompts?: PromptDefinition[],
onToolError?: (err, toolName) => ToolResult,
onEvent?: (event: ServerEvent) => void,
})Devuelve un DefinedServer con:
.start({ transport: 'stdio' })— conecta un transporte y sirve..connect(transport)— conecta una instancia de transporte que construiste tú mismo (HTTP, personalizado, cualquier cosa que actúe como unTransport)..stop()— cierra el transporte activo y el servidor subyacente..raw— elServerdel SDK subyacente si necesitas hacer algo exótico.
recursos y prompts
La misma forma declarativa:
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}` } }],
}),
});observabilidad
onEvent obtiene una devolución de llamada estructurada para cada llamada de herramienta, lectura de recurso y obtención de prompt — hora de inicio, hora de finalización, latencia, error, un requestId por llamada para correlacionar. Puedes conectarlo a cualquier cosa: pino, console, OpenTelemetry, tu agregador casero. También hay uno integrado para el caso simple:
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: [...]
});El registro siempre va a stderr — stdout está reservado para el tráfico del protocolo en transportes stdio.
pruebas
mcpkit/testing expone un cliente en proceso que habla con tu servidor a través de un transporte en memoria — sin subprocesos, sin tuberías stdio, sin cierres de proceso inestables. El mismo cliente que usaría un consumidor real, solo que enrutado a través de la 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();
});
});decisiones de diseño que vale la pena conocer
Zod, no JSON Schema crudo. Escribes el tipo una vez. La validación, el JSON Schema generado para el protocolo y la inferencia de TypeScript para el manejador surgen de la misma fuente. Intentar mantener tres definiciones sincronizadas es el código repetitivo que este proyecto existe para eliminar.
Los errores son valores, no excepciones. Un manejador que lanza un error se convierte en un sobre de contenido isError: true. El cliente ve una respuesta sensata en lugar de un fallo a nivel de transporte. Si prefieres formatear el error tú mismo, sobrescribe onToolError.
Núcleo agnóstico al transporte. El mismo defineServer funciona sobre stdio, el transporte HTTP transmitible, el transporte de prueba en memoria o cualquier otra cosa que implemente la interfaz Transport del SDK. La plantilla http-streaming muestra la configuración.
Modo estricto por defecto. Las plantillas se envían con strict: true y noUncheckedIndexedAccess. La biblioteca misma se compila bajo la misma configuración. Si encuentras un agujero en los tipos, eso es un error.
Los errores del oyente son ignorados. Si tu manejador onEvent lanza un error, tus llamadas a herramientas siguen funcionando. Los errores de observabilidad no deberían ser críticos.
preguntas frecuentes
¿Esto me bloquea en mcpkit para siempre?
No. Cada ayudante tiene una salida de emergencia — server.raw te da el Server del SDK subyacente, y puedes hacer setRequestHandler en él directamente si necesitas algo que el kit aún no modela. El kit es una capa superior, no un reemplazo.
¿Por qué Zod 3 y no 4?
Zod 4 es genial, pero el ecosistema (notablemente zod-to-json-schema) todavía se está poniendo al día. Nos moveremos cuando sea estable en producción. Si ya estás en Zod 4, las interfaces de esquema son lo suficientemente compatibles — abre un problema si te encuentras con un muro.
¿Soporta recursos y prompts, no solo herramientas?
Sí. defineResource y definePrompt son de primera clase. Se usan menos comúnmente que las herramientas, por lo que la mayoría de los ejemplos comienzan con herramientas, pero la configuración es idéntica.
¿HTTP transmitible, SSE, ambos?
HTTP transmitible. El sabor anterior HTTP+SSE todavía está en el SDK pero se está eliminando gradualmente; si tienes una razón para necesitarlo, defineServer es agnóstico al transporte y puedes pasar cualquier instancia de Transport a través de .connect().
¿Listo para producción? La biblioteca es pequeña y la superficie es intencionalmente estrecha. El SDK oficial hace el trabajo pesado debajo. Fija una versión, escribe pruebas para tus herramientas (el cliente en proceso facilita esto) y estarás listo.
lo que esto no es
no es un servicio alojado. tú construyes, tú despliegas.
no es un marco de trabajo de agentes. construye el lado del servidor de MCP, no el cliente.
no tiene opiniones sobre tu dominio. las herramientas son funciones; lo que hacen es tu problema.
hoja de ruta
más plantillas (protegidas por oauth, tiempo de ejecución edge, drizzle/postgres).
un comando
mcpkit publishque analiza + empaqueta + etiqueta una versión.ayudantes de prueba más ricos (fuzzing de la entrada de una herramienta, diferencia de esquema contra una línea base).
adaptador opcional de OpenTelemetry para
onEvent.
Si falta algo, abre un problema con un boceto de la API que desearías.
licencia
MIT.
This server cannot be deployed
Maintenance
Related MCP Connectors
MCP server for progressive tool usage at any scale (see https://klavis.ai)
Build your own tools from chat: design, test and host them on a shareable MCP server URL.
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
MCP-first toolbox for agents: KV storage, auth, queue, and utility tools. Free in early access.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA TypeScript-based template for rapidly developing MCP servers with modular tool architecture, built-in validation using Zod schemas, and comprehensive error handling.5 npmMIT
- AlicenseNot gradedqualityDmaintenanceA template for building MCP servers with automatic tool discovery using TypeScript and Zod schemas, supporting HTTP and STDIO transports.8,467 npmMIT
- AlicenseAqualityAmaintenanceA 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.21MIT
- AlicenseAqualityDmaintenanceA 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.224 npmMIT