MCP server by v-checha
MCPKit
Developer-friendly toolkit for building Model Context Protocol (MCP) servers with minimal boilerplate.
MCPKit provides a decorator-based, type-safe API for creating MCP servers that work with Claude, ChatGPT, Cursor, and other AI assistants.
Features
- Decorator-based API - Clean, declarative syntax with
@MCPServer,@Tool,@Resource,@Prompt, and@Param - Type-safe - Full TypeScript support with automatic type inference
- Multiple transports - Support for stdio, HTTP/SSE, and Streamable HTTP
- CLI tooling - Project scaffolding and development tools
- Testing utilities - Mock clients and helpers for testing your servers
- Zod integration - Runtime validation with automatic JSON Schema generation
- MCP SDK compatible - Built on top of the official
@modelcontextprotocol/sdk
Packages
| Package | Description | |-------------------------------------------|--------------------------------------| | @mcpkit-dev/core | Core decorators and server framework | | @mcpkit-dev/cli | CLI tool for project scaffolding | | @mcpkit-dev/testing | Testing utilities and mock clients |
Quick Start
Using the CLI (Recommended)
# Install the CLI globally
npm install -g @mcpkit-dev/cli
# Create a new project
mcpkit init my-server
# Navigate and start development
cd my-server
npm run dev
Manual Installation
npm install @mcpkit-dev/core zod
import {MCPServer, Tool, Param} from '@mcpkit-dev/core';
@MCPServer({
name: 'my-server',
version: '1.0.0',
})
class MyServer {
@Tool({description: 'Greet someone by name'})
async greet(
@Param({description: 'Name to greet'}) name: string
): Promise<string> {
return `Hello, ${name}!`;
}
}
// Start the server
const server = new MyServer();
await server.listen();
Decorators
@MCPServer
Class decorator that marks a class as an MCP server.
@MCPServer({
name: 'weather-server',
version: '1.0.0',
description: 'Get weather information',
})
class WeatherServer {}
@Tool
Method decorator that exposes a method as an MCP tool.
// Using @Param decorators
@Tool({ description: 'Get current weather' })
async getWeather(
@Param({ name: 'city', description: 'City name' }) city: string,
@Param({ name: 'unit', optional: true }) unit?: 'celsius' | 'fahrenheit',
): Promise<WeatherData> {
// implementation
}
// Using explicit Zod schema
@Tool({
description: 'Get forecast',
schema: z.object({
city: z.string(),
days: z.number().min(1).max(7),
}),
})
async getForecast(args: { city: string; days: number }) {
// implementation
}
@Param
Parameter decorator for tool and prompt arguments.
@Param({
name: 'city', // Optional - defaults to parameter name
description: 'City', // Optional - shown to AI
schema: z.string(), // Optional - explicit Zod schema
optional: true, // Optional - is parameter optional?
})
@Resource
Method decorator that exposes data as an MCP resource.
// URI template with parameters
@Resource('weather://cities/{city}/current')
async getCityWeather(city: string) {
return {
contents: [{
uri: `weather://cities/${city}/current`,
mimeType: 'application/json',
text: JSON.stringify({ temperature: 22 }),
}],
};
}
// Static resource with options
@Resource({
uri: 'docs://readme',
name: 'README',
mimeType: 'text/markdown',
})
async getReadme() {
return { contents: [{ uri: 'docs://readme', text: '# README' }] };
}
@Prompt
Method decorator for reusable prompt templates.
@Prompt({ description: 'Generate a weather report' })
async weatherReport(
@Param({ name: 'city' }) city: string,
) {
return {
messages: [{
role: 'user',
content: { type: 'text', text: `Write a weather report for ${city}` },
}],
};
}
@Monitor
Method decorator for per-method monitoring and logging.
@Tool({ description: 'Process important data' })
@Monitor({
logArgs: true, // Log input arguments
logResult: true, // Log return value
logDuration: true, // Log execution time (default: true)
logErrors: true, // Log errors (default: true)
logger: customLogger, // Optional custom logger
})
async processData(@Param({ name: 'data' }) data: string) {
return `Processed: ${data}`;
}
Note:
@Monitoronly works whenhooksare configured on@MCPServer.
Lifecycle Hooks
Add logging, monitoring, and observability to your server with hooks:
import { MCPServer, Tool, Param, type ServerHooks } from '@mcpkit-dev/core';
@MCPServer({
name: 'monitored-server',
version: '1.0.0',
hooks: {
// Whether to await hook execution (default: true)
awaitHooks: true,
// Server lifecycle
// Note: Use console.error (stderr) for logging - stdout is reserved for MCP protocol
onServerStart: () => console.error('Server started'),
onServerStop: () => console.error('Server stopped'),
// Tool hooks
onToolCall: ({ toolName, args }) => {
console.error(`Tool ${toolName} called with`, args);
},
onToolSuccess: ({ toolName, duration, result }) => {
console.error(`Tool ${toolName} completed in ${duration}ms`);
},
onToolError: ({ toolName, error, duration }) => {
console.error(`Tool ${toolName} failed after ${duration}ms:`, error.message);
},
// Resource hooks
onResourceRead: ({ uri }) => console.error(`Reading resource: ${uri}`),
onResourceSuccess: ({ uri, duration }) => console.error(`Resource read in ${duration}ms`),
onResourceError: ({ uri, error }) => console.error(`Resource error: ${uri}`, error),
// Prompt hooks
onPromptGet: ({ promptName }) => console.error(`Getting prompt: ${promptName}`),
onPromptSuccess: ({ promptName, duration }) => console.error(`Prompt ready in ${duration}ms`),
onPromptError: ({ promptName, error }) => console.error(`Prompt error:`, error),
},
})
class MonitoredServer {
@Tool({ description: 'Example tool' })
async example(@Param({ name: 'input' }) input: string) {
return `Result: ${input}`;
}
}
Transport Options
MCPKit supports multiple transport protocols:
stdio (Default)
Standard input/output transport for CLI tools and Claude Desktop integration.
const server = new MyServer();
await server.listen(); // Uses stdio by default
Streamable HTTP (Recommended for Web)
Modern HTTP transport with session support and SSE streaming.
const server = new MyServer();
await server.listen({
transport: 'streamable-http',
port: 3000,
host: 'localhost',
path: '/mcp',
});
// Server available at http://localhost:3000/mcp
SSE (Legacy HTTP)
Server-Sent Events transport for backward compatibility.
const server = new MyServer();
await server.listen({
transport: 'sse',
port: 3000,
host: 'localhost',
ssePath: '/sse',
messagePath: '/message',
});
CLI Tool
The @mcpkit-dev/cli package provides project scaffolding and development tools.
npm install -g @mcpkit-dev/cli
Commands
# Create a new project
mcpkit init [name]
--template <template> Template to use (basic, advanced)
--no-git Skip git initialization
--no-install Skip installing dependencies
# Start development server
mcpkit dev
--port <port> Port for HTTP transport (default: 3000)
--transport <type> Transport type (stdio, http, streamable-http)
--watch Watch for file changes (default: true)
# Build for production
mcpkit build
--output <dir> Output directory (default: dist)
Testing
The @mcpkit-dev/testing package provides utilities for testing MCP servers.
npm install -D @mcpkit-dev/testing
Mock Client
import {MockMcpClient} from '@mcpkit-dev/testing';
import {bootstrapServer, MetadataStorage} from '@mcpkit-dev/core';
describe('MyServer', () => {
it('should greet users', async () => {
// Create mock client
const {client, serverTransport} = MockMcpClient.create();
// Bootstrap server with test transport
const instance = new MyServer();
const options = MetadataStorage.getServerOptions(MyServer);
const server = await bootstrapServer(instance, options!);
await server.server.connect(serverTransport);
await client.connect();
// Test the tool
const result = await client.callTool('greet', {name: 'World'});
expect(result.content[0].text).toBe('Hello, World!');
// Cleanup
await client.close();
await server.close();
});
});
In-Memory Transport
import {InMemoryTransport} from '@mcpkit-dev/testing';
const {clientTransport, serverTransport} = InMemoryTransport.createPair();
// Use transports for direct client-server communication
Using with Claude Desktop
Add your server to Claude Desktop's configuration (~/Library/Application Support/Claude/claude_desktop_config.json on
macOS):
{
"mcpServers": {
"my-server": {
"command": "node",
"args": [
"/path/to/your/server/dist/index.js"
]
}
}
}
TypeScript Configuration
MCPKit requires the following TypeScript settings:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext"
}
}
Examples
See the examples directory for complete working examples:
- weather-server - Demonstrates tools, resources, and prompts
API Reference
Listen Options
interface ListenOptions {
transport?: 'stdio' | 'http' | 'sse' | 'streamable-http';
port?: number; // HTTP port (default: 3000)
host?: string; // HTTP host (default: 'localhost')
path?: string; // Streamable HTTP endpoint path
ssePath?: string; // SSE stream path
messagePath?: string; // SSE message path
stateless?: boolean; // Disable session management
enableJsonResponse?: boolean; // Use JSON instead of SSE
onSessionInitialized?: (sessionId: string) => void;
onSessionClosed?: (sessionId: string) => void;
}
Server Instance
interface BootstrappedServer {
server: McpServer; // Underlying MCP server
transport: Transport; // Active transport
connect(): Promise<void>; // Start the server
close(): Promise<void>; // Stop the server
}
Requirements
- Node.js 18+
- TypeScript 5.0+
Contributing
Contributions are welcome! Please read our contributing guidelines before submitting a PR.
License
MIT