Skip to content

Commit 0d9ddba

Browse files
committed
feat: add mcp server implementation with tool handling capabilities
1 parent 6756caa commit 0d9ddba

File tree

5 files changed

+96
-0
lines changed

5 files changed

+96
-0
lines changed

src/definitions/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './mcp-transport-type';
2+
export * from './mcp-tool';

src/definitions/mcp-tool.ts

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { z, ZodObject, type ZodRawShape } from 'zod';
2+
3+
export type McpToolExecute<Args extends ZodRawShape> = (
4+
request: z.infer<ZodObject<Args>>,
5+
) => Promise<{ content: { type: string; text: string }[] }>;
6+
7+
export type McpTool<Args extends ZodRawShape = ZodRawShape> = {
8+
execute: McpToolExecute<Args>;
9+
parameters: Args;
10+
name: string;
11+
};

src/definitions/mcp-transport-type.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { z } from 'zod';
2+
3+
export const MCP_TRANSPORT_TYPE_SCHEMA = z.literal('stdio');
4+
5+
export type McpTransportType = z.infer<typeof MCP_TRANSPORT_TYPE_SCHEMA>;

src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './definitions';
2+
export * from './mcp-server';

src/mcp-server.ts

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3+
import {
4+
CallToolRequestSchema,
5+
ListToolsRequestSchema,
6+
} from '@modelcontextprotocol/sdk/types.js';
7+
import { z, type ZodRawShape } from 'zod';
8+
import zodToJsonSchema from 'zod-to-json-schema';
9+
10+
import {
11+
MCP_TRANSPORT_TYPE_SCHEMA,
12+
type McpTool,
13+
McpToolExecute,
14+
} from './definitions';
15+
16+
export class McpServer {
17+
private readonly server: Server;
18+
private readonly tools: McpTool<ZodRawShape>[] = [];
19+
20+
constructor({ name, version }: { name: string; version?: string }) {
21+
this.server = new Server(
22+
{ name, version: version ?? '1.0.0' },
23+
{
24+
capabilities: {
25+
tools: {},
26+
},
27+
},
28+
);
29+
}
30+
31+
public tool<Args extends ZodRawShape>({
32+
parameters,
33+
execute,
34+
name,
35+
}: McpTool<Args>) {
36+
this.tools.push({
37+
execute: execute as McpToolExecute<ZodRawShape>,
38+
parameters,
39+
name,
40+
});
41+
}
42+
43+
public async start(dto: { transportType: string }) {
44+
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
45+
return {
46+
tools: this.tools.map((tool) => ({
47+
inputSchema: zodToJsonSchema(z.object(tool.parameters)),
48+
name: tool.name,
49+
})),
50+
};
51+
});
52+
53+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
54+
for (const tool of this.tools) {
55+
if (tool.name === request.params.name) {
56+
return await tool.execute(request.params.arguments as ZodRawShape);
57+
}
58+
}
59+
60+
throw new Error('Tool not found');
61+
});
62+
63+
const transportType = MCP_TRANSPORT_TYPE_SCHEMA.parse(dto.transportType);
64+
65+
if (transportType === 'stdio') {
66+
return this.startStdio();
67+
}
68+
69+
throw new Error(`Unknown transport type: ${transportType}`);
70+
}
71+
72+
private async startStdio() {
73+
const transport = new StdioServerTransport();
74+
await this.server.connect(transport);
75+
}
76+
}

0 commit comments

Comments
 (0)