@karashiiro/mcp 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,3 +1,168 @@
1
- # mcp
1
+ # @karashiiro/mcp
2
2
 
3
- (WIP) MCP utilities in TypeScript
3
+ Lightweight utilities for serving [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) servers in TypeScript.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @karashiiro/mcp @modelcontextprotocol/sdk
9
+ ```
10
+
11
+ ### For HTTP transport
12
+
13
+ If you plan to use HTTP transport, you'll also need Hono:
14
+
15
+ ```bash
16
+ npm install hono @hono/node-server
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ### Stdio Transport
22
+
23
+ The simplest way to serve an MCP server. Great for CLI tools and local integrations.
24
+
25
+ ```ts
26
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
27
+ import { serveStdio } from "@karashiiro/mcp/stdio";
28
+
29
+ function createServer() {
30
+ const server = new McpServer({
31
+ name: "my-server",
32
+ version: "1.0.0",
33
+ });
34
+
35
+ server.registerTool(
36
+ "hello",
37
+ { description: "Says hello" },
38
+ async () => ({
39
+ content: [{ type: "text", text: "Hello from MCP!" }],
40
+ }),
41
+ );
42
+
43
+ return server;
44
+ }
45
+
46
+ await serveStdio(createServer);
47
+ ```
48
+
49
+ ### HTTP Transport
50
+
51
+ Serve your MCP server over HTTP using the Streamable HTTP transport.
52
+
53
+ ```ts
54
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
55
+ import { serveHttp } from "@karashiiro/mcp/http";
56
+
57
+ function createServer() {
58
+ const server = new McpServer({
59
+ name: "my-server",
60
+ version: "1.0.0",
61
+ });
62
+
63
+ server.registerTool(
64
+ "hello",
65
+ { description: "Says hello" },
66
+ async () => ({
67
+ content: [{ type: "text", text: "Hello from MCP!" }],
68
+ }),
69
+ );
70
+
71
+ return server;
72
+ }
73
+
74
+ const handle = await serveHttp(createServer, {
75
+ port: 8080,
76
+ host: "127.0.0.1",
77
+ endpoint: "/mcp",
78
+ });
79
+
80
+ // Later, to shut down:
81
+ await handle.close();
82
+ ```
83
+
84
+ #### Stateless vs Stateful Mode
85
+
86
+ By default, `serveHttp` runs in **stateless mode** where all clients share a single server instance.
87
+
88
+ For **stateful mode** with per-client sessions, provide the `sessions` option:
89
+
90
+ ```ts
91
+ const handle = await serveHttp(createServer, {
92
+ port: 8080,
93
+ sessions: {}, // Enable stateful mode
94
+ });
95
+ ```
96
+
97
+ In stateful mode, `createServer` is called once per client session, allowing each client to have isolated state.
98
+
99
+ #### Custom Session IDs
100
+
101
+ ```ts
102
+ const handle = await serveHttp(createServer, {
103
+ port: 8080,
104
+ sessions: {
105
+ sessionIdGenerator: () => `session-${Date.now()}`,
106
+ },
107
+ });
108
+ ```
109
+
110
+ #### Legacy SSE Support
111
+
112
+ For backwards compatibility with older MCP clients that use SSE transport:
113
+
114
+ ```ts
115
+ const handle = await serveHttp(createServer, {
116
+ port: 8080,
117
+ sessions: {
118
+ legacySse: {
119
+ sseEndpoint: "/sse", // default: "/sse"
120
+ messagesEndpoint: "/messages", // default: "/messages"
121
+ },
122
+ },
123
+ });
124
+ ```
125
+
126
+ ## Entry Points
127
+
128
+ This package provides multiple entry points for optimal bundle size:
129
+
130
+ | Entry Point | Description | Requires Hono |
131
+ |-------------|-------------|---------------|
132
+ | `@karashiiro/mcp` | Everything (re-exports all) | Yes |
133
+ | `@karashiiro/mcp/stdio` | Stdio transport only | No |
134
+ | `@karashiiro/mcp/http` | HTTP transport only | Yes |
135
+
136
+ If you only need stdio transport, import from `@karashiiro/mcp/stdio` to avoid bundling Hono.
137
+
138
+ ## API Reference
139
+
140
+ ### `serveStdio(serverFactory)`
141
+
142
+ Serves an MCP server over stdin/stdout.
143
+
144
+ - `serverFactory: () => McpServer` - Factory function that creates the server instance
145
+ - Returns: `Promise<ServerHandle>`
146
+
147
+ ### `serveHttp(serverFactory, options?)`
148
+
149
+ Serves an MCP server over HTTP.
150
+
151
+ - `serverFactory: () => McpServer` - Factory function that creates server instances
152
+ - `options.port` - Port to listen on (default: `8080`)
153
+ - `options.host` - Host to bind to (default: `"127.0.0.1"`)
154
+ - `options.endpoint` - MCP endpoint path (default: `"/mcp"`)
155
+ - `options.sessions` - Enable stateful mode with per-client sessions
156
+ - `options.sessions.sessionIdGenerator` - Custom session ID generator function
157
+ - `options.sessions.legacySse` - Enable legacy SSE transport endpoints
158
+ - Returns: `Promise<ServerHandle>`
159
+
160
+ ### `ServerHandle`
161
+
162
+ Handle for controlling the server lifecycle.
163
+
164
+ - `close(): Promise<void>` - Gracefully shut down the server
165
+
166
+ ## License
167
+
168
+ UNLICENSED
package/dist/http.d.ts ADDED
@@ -0,0 +1,40 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ServerHandle } from "./types.js";
3
+ export type { ServerHandle } from "./types.js";
4
+ /**
5
+ * Options for legacy SSE transport compatibility.
6
+ * @deprecated SSE transport is deprecated in favor of Streamable HTTP.
7
+ */
8
+ export interface LegacySseOptions {
9
+ /** Endpoint for SSE stream. Defaults to "/sse". */
10
+ sseEndpoint?: string;
11
+ /** Endpoint for messages. Defaults to "/messages". */
12
+ messagesEndpoint?: string;
13
+ }
14
+ export interface HttpServerSessionOptions {
15
+ sessionIdGenerator?: () => string;
16
+ /**
17
+ * Enable legacy SSE transport compatibility.
18
+ * When provided, adds /sse and /messages endpoints for older clients.
19
+ * @deprecated SSE transport is deprecated in favor of Streamable HTTP.
20
+ */
21
+ legacySse?: LegacySseOptions;
22
+ }
23
+ export interface HttpServerOptions {
24
+ port: number;
25
+ host: string;
26
+ endpoint: string;
27
+ sessions?: HttpServerSessionOptions | undefined;
28
+ }
29
+ /**
30
+ * Serve an MCP server over HTTP.
31
+ *
32
+ * @param serverFactory - Factory function that creates McpServer instances.
33
+ * In stateless mode, called once. In stateful mode, called per session.
34
+ * @param options - Server configuration options.
35
+ * If `sessions` is provided, runs in stateful mode with per-session servers.
36
+ * If `sessions` is undefined, runs in stateless mode with a single server.
37
+ * @returns A handle to control the server lifecycle.
38
+ */
39
+ export declare function serveHttp(serverFactory: () => McpServer, options?: Partial<HttpServerOptions>): Promise<ServerHandle>;
40
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,mDAAmD;IACnD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,wBAAwB;IACvC,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC;IAClC;;;;OAIG;IACH,SAAS,CAAC,EAAE,gBAAgB,CAAC;CAC9B;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;CACjD;AAqDD;;;;;;;;;GASG;AACH,wBAAsB,SAAS,CAC7B,aAAa,EAAE,MAAM,SAAS,EAC9B,OAAO,GAAE,OAAO,CAAC,iBAAiB,CAAM,GACvC,OAAO,CAAC,YAAY,CAAC,CAWvB"}
package/dist/http.js ADDED
@@ -0,0 +1,237 @@
1
+ import { serve } from "@hono/node-server";
2
+ import { RESPONSE_ALREADY_SENT } from "@hono/node-server/utils/response";
3
+ import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
4
+ import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
5
+ import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
6
+ import { Hono } from "hono";
7
+ import { cors } from "hono/cors";
8
+ import { v4 as uuidv4 } from "uuid";
9
+ import { InMemoryEventStore } from "./event-store.js";
10
+ const defaultOptions = Object.freeze({
11
+ port: 8080,
12
+ host: "127.0.0.1",
13
+ endpoint: "/mcp",
14
+ sessions: undefined,
15
+ });
16
+ /**
17
+ * Helper to create a closeable handle from a node server.
18
+ */
19
+ function createHandle(server) {
20
+ return {
21
+ close: () => new Promise((resolve, reject) => {
22
+ server.close((err) => {
23
+ if (err)
24
+ reject(err);
25
+ else
26
+ resolve();
27
+ });
28
+ }),
29
+ };
30
+ }
31
+ /**
32
+ * Serve an MCP server over HTTP.
33
+ *
34
+ * @param serverFactory - Factory function that creates McpServer instances.
35
+ * In stateless mode, called once. In stateful mode, called per session.
36
+ * @param options - Server configuration options.
37
+ * If `sessions` is provided, runs in stateful mode with per-session servers.
38
+ * If `sessions` is undefined, runs in stateless mode with a single server.
39
+ * @returns A handle to control the server lifecycle.
40
+ */
41
+ export async function serveHttp(serverFactory, options = {}) {
42
+ const mergedOptions = {
43
+ ...defaultOptions,
44
+ ...options,
45
+ };
46
+ if (mergedOptions.sessions) {
47
+ return serveHttpStateful(serverFactory, mergedOptions);
48
+ }
49
+ else {
50
+ return serveHttpStateless(serverFactory, mergedOptions);
51
+ }
52
+ }
53
+ /**
54
+ * Stateless mode: single server instance, single transport, no session tracking.
55
+ */
56
+ async function serveHttpStateless(serverFactory, options) {
57
+ // Call factory ONCE to get the single server instance
58
+ const server = serverFactory();
59
+ // Create the transport (no session ID generator = stateless)
60
+ const transport = new WebStandardStreamableHTTPServerTransport({
61
+ sessionIdGenerator: undefined,
62
+ });
63
+ // Create the Hono app
64
+ const app = new Hono();
65
+ addCors(app);
66
+ // MCP endpoint
67
+ app.all(options.endpoint, (c) => transport.handleRequest(c.req.raw));
68
+ await server.connect(transport);
69
+ const httpServer = serve({
70
+ fetch: app.fetch,
71
+ port: options.port,
72
+ hostname: options.host,
73
+ });
74
+ return createHandle(httpServer);
75
+ }
76
+ /**
77
+ * Stateful mode: per-session servers, transports, and event stores.
78
+ */
79
+ function serveHttpStateful(serverFactory, options) {
80
+ const sessions = new Map();
81
+ const sessionIdGenerator = options.sessions?.sessionIdGenerator ?? uuidv4;
82
+ // Legacy SSE options
83
+ const legacySse = options.sessions?.legacySse;
84
+ const sseEndpoint = legacySse?.sseEndpoint ?? "/sse";
85
+ const messagesEndpoint = legacySse?.messagesEndpoint ?? "/messages";
86
+ const app = new Hono();
87
+ addCors(app);
88
+ // Main MCP endpoint (Streamable HTTP)
89
+ app.all(options.endpoint, async (c) => {
90
+ const sessionId = c.req.header("mcp-session-id");
91
+ // Clone the request so we can read the body without consuming it
92
+ const rawRequest = c.req.raw;
93
+ const bodyText = await rawRequest.text();
94
+ let body = null;
95
+ try {
96
+ body = bodyText ? JSON.parse(bodyText) : null;
97
+ }
98
+ catch {
99
+ // Invalid JSON - body stays null
100
+ }
101
+ // Helper to recreate request with body (since we consumed it)
102
+ const recreateRequest = () => new Request(rawRequest.url, {
103
+ method: rawRequest.method,
104
+ headers: rawRequest.headers,
105
+ body: bodyText || undefined,
106
+ });
107
+ // New session (initialize request without session ID)
108
+ if (!sessionId && body && isInitializeRequest(body)) {
109
+ const eventStore = new InMemoryEventStore();
110
+ const transport = new WebStandardStreamableHTTPServerTransport({
111
+ sessionIdGenerator,
112
+ eventStore,
113
+ onsessioninitialized: (sid) => {
114
+ // Factory called per session!
115
+ const server = serverFactory();
116
+ const session = {
117
+ type: "streamable-http",
118
+ transport,
119
+ server,
120
+ eventStore,
121
+ };
122
+ sessions.set(sid, session);
123
+ server.connect(transport);
124
+ },
125
+ });
126
+ transport.onclose = () => {
127
+ if (transport.sessionId) {
128
+ sessions.delete(transport.sessionId);
129
+ }
130
+ };
131
+ return transport.handleRequest(recreateRequest());
132
+ }
133
+ // Existing session
134
+ if (sessionId) {
135
+ const session = sessions.get(sessionId);
136
+ if (!session) {
137
+ return c.text("Session not found", 404);
138
+ }
139
+ // Validate transport type matches endpoint
140
+ if (session.type !== "streamable-http") {
141
+ return c.json({
142
+ jsonrpc: "2.0",
143
+ error: {
144
+ code: -32000,
145
+ message: "Bad Request: Session exists but uses a different transport protocol",
146
+ },
147
+ id: null,
148
+ }, 400);
149
+ }
150
+ return session.transport.handleRequest(recreateRequest());
151
+ }
152
+ // Invalid request (no session ID, not an initialize request)
153
+ return c.text("Bad request - missing session ID", 400);
154
+ });
155
+ // Legacy SSE endpoints (only if enabled)
156
+ if (legacySse) {
157
+ // GET /sse - Establish SSE stream
158
+ app.get(sseEndpoint, async (c) => {
159
+ const { outgoing } = c.env;
160
+ // Create SSE transport with messages endpoint
161
+ const transport = new SSEServerTransport(messagesEndpoint, outgoing);
162
+ // Create and connect server
163
+ const server = serverFactory();
164
+ // Store session
165
+ const session = {
166
+ type: "sse",
167
+ transport,
168
+ server,
169
+ };
170
+ sessions.set(transport.sessionId, session);
171
+ // Cleanup on close
172
+ transport.onclose = () => {
173
+ sessions.delete(transport.sessionId);
174
+ };
175
+ // Connect and start
176
+ await server.connect(transport);
177
+ // Signal to Hono that we've handled the response directly
178
+ return RESPONSE_ALREADY_SENT;
179
+ });
180
+ // POST /messages - Handle messages for SSE sessions
181
+ app.post(messagesEndpoint, async (c) => {
182
+ const sessionId = c.req.query("sessionId");
183
+ if (!sessionId) {
184
+ return c.text("Missing sessionId query parameter", 400);
185
+ }
186
+ const session = sessions.get(sessionId);
187
+ if (!session) {
188
+ return c.text("Session not found", 404);
189
+ }
190
+ // Validate transport type matches endpoint
191
+ if (session.type !== "sse") {
192
+ return c.json({
193
+ jsonrpc: "2.0",
194
+ error: {
195
+ code: -32000,
196
+ message: "Bad Request: Session exists but uses a different transport protocol",
197
+ },
198
+ id: null,
199
+ }, 400);
200
+ }
201
+ const { incoming, outgoing } = c.env;
202
+ // Parse body for SSEServerTransport
203
+ const bodyText = await c.req.text();
204
+ let parsedBody = null;
205
+ try {
206
+ parsedBody = bodyText ? JSON.parse(bodyText) : null;
207
+ }
208
+ catch {
209
+ // Let handlePostMessage handle the error
210
+ }
211
+ await session.transport.handlePostMessage(incoming, outgoing, parsedBody);
212
+ return RESPONSE_ALREADY_SENT;
213
+ });
214
+ }
215
+ const httpServer = serve({
216
+ fetch: app.fetch,
217
+ port: options.port,
218
+ hostname: options.host,
219
+ });
220
+ return createHandle(httpServer);
221
+ }
222
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
223
+ function addCors(app) {
224
+ // Enable CORS for all origins
225
+ app.use("*", cors({
226
+ origin: "*",
227
+ allowMethods: ["GET", "POST", "DELETE", "OPTIONS"],
228
+ allowHeaders: [
229
+ "Content-Type",
230
+ "mcp-session-id",
231
+ "Last-Event-ID",
232
+ "mcp-protocol-version",
233
+ ],
234
+ exposeHeaders: ["mcp-session-id", "mcp-protocol-version"],
235
+ }));
236
+ }
237
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,29 +1,3 @@
1
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- export interface HttpServerSessionOptions {
3
- sessionIdGenerator?: () => string;
4
- }
5
- export interface HttpServerOptions {
6
- port: number;
7
- host: string;
8
- endpoint: string;
9
- sessions?: HttpServerSessionOptions | undefined;
10
- }
11
- /**
12
- * Handle returned by serveHttp for controlling the server lifecycle.
13
- */
14
- export interface HttpServerHandle {
15
- /** Close the HTTP server and stop accepting new connections. */
16
- close: () => Promise<void>;
17
- }
18
- /**
19
- * Serve an MCP server over HTTP.
20
- *
21
- * @param serverFactory - Factory function that creates McpServer instances.
22
- * In stateless mode, called once. In stateful mode, called per session.
23
- * @param options - Server configuration options.
24
- * If `sessions` is provided, runs in stateful mode with per-session servers.
25
- * If `sessions` is undefined, runs in stateless mode with a single server.
26
- * @returns A handle to control the server lifecycle.
27
- */
28
- export declare function serveHttp(serverFactory: () => McpServer, options?: Partial<HttpServerOptions>): Promise<HttpServerHandle>;
1
+ export * from "./http.js";
2
+ export * from "./stdio.js";
29
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQzE,MAAM,WAAW,wBAAwB;IACvC,kBAAkB,CAAC,EAAE,MAAM,MAAM,CAAC;CACnC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,wBAAwB,GAAG,SAAS,CAAC;CACjD;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,gEAAgE;IAChE,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAiCD;;;;;;;;;GASG;AACH,wBAAsB,SAAS,CAC7B,aAAa,EAAE,MAAM,SAAS,EAC9B,OAAO,GAAE,OAAO,CAAC,iBAAiB,CAAM,GACvC,OAAO,CAAC,gBAAgB,CAAC,CAW3B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
package/dist/index.js CHANGED
@@ -1,152 +1,6 @@
1
- import { serve } from "@hono/node-server";
2
- import { WebStandardStreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";
3
- import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
4
- import { Hono } from "hono";
5
- import { cors } from "hono/cors";
6
- import { v4 as uuidv4 } from "uuid";
7
- import { InMemoryEventStore } from "./event-store.js";
8
- const defaultOptions = Object.freeze({
9
- port: 8080,
10
- host: "127.0.0.1",
11
- endpoint: "/mcp",
12
- sessions: undefined,
13
- });
14
- /**
15
- * Helper to create a closeable handle from a node server.
16
- */
17
- function createHandle(server) {
18
- return {
19
- close: () => new Promise((resolve, reject) => {
20
- server.close((err) => {
21
- if (err)
22
- reject(err);
23
- else
24
- resolve();
25
- });
26
- }),
27
- };
28
- }
29
- /**
30
- * Serve an MCP server over HTTP.
31
- *
32
- * @param serverFactory - Factory function that creates McpServer instances.
33
- * In stateless mode, called once. In stateful mode, called per session.
34
- * @param options - Server configuration options.
35
- * If `sessions` is provided, runs in stateful mode with per-session servers.
36
- * If `sessions` is undefined, runs in stateless mode with a single server.
37
- * @returns A handle to control the server lifecycle.
38
- */
39
- export async function serveHttp(serverFactory, options = {}) {
40
- const mergedOptions = {
41
- ...defaultOptions,
42
- ...options,
43
- };
44
- if (mergedOptions.sessions) {
45
- return serveHttpStateful(serverFactory, mergedOptions);
46
- }
47
- else {
48
- return serveHttpStateless(serverFactory, mergedOptions);
49
- }
50
- }
51
- /**
52
- * Stateless mode: single server instance, single transport, no session tracking.
53
- */
54
- async function serveHttpStateless(serverFactory, options) {
55
- // Call factory ONCE to get the single server instance
56
- const server = serverFactory();
57
- // Create the transport (no session ID generator = stateless)
58
- const transport = new WebStandardStreamableHTTPServerTransport({
59
- sessionIdGenerator: undefined,
60
- });
61
- // Create the Hono app
62
- const app = new Hono();
63
- addCors(app);
64
- // MCP endpoint
65
- app.all(options.endpoint, (c) => transport.handleRequest(c.req.raw));
66
- await server.connect(transport);
67
- const httpServer = serve({
68
- fetch: app.fetch,
69
- port: options.port,
70
- hostname: options.host,
71
- });
72
- return createHandle(httpServer);
73
- }
74
- /**
75
- * Stateful mode: per-session servers, transports, and event stores.
76
- */
77
- function serveHttpStateful(serverFactory, options) {
78
- const sessions = new Map();
79
- const sessionIdGenerator = options.sessions?.sessionIdGenerator ?? uuidv4;
80
- const app = new Hono();
81
- addCors(app);
82
- app.all(options.endpoint, async (c) => {
83
- const sessionId = c.req.header("mcp-session-id");
84
- // Clone the request so we can read the body without consuming it
85
- const rawRequest = c.req.raw;
86
- const bodyText = await rawRequest.text();
87
- let body = null;
88
- try {
89
- body = bodyText ? JSON.parse(bodyText) : null;
90
- }
91
- catch {
92
- // Invalid JSON - body stays null
93
- }
94
- // Helper to recreate request with body (since we consumed it)
95
- const recreateRequest = () => new Request(rawRequest.url, {
96
- method: rawRequest.method,
97
- headers: rawRequest.headers,
98
- body: bodyText || undefined,
99
- });
100
- // New session (initialize request without session ID)
101
- if (!sessionId && body && isInitializeRequest(body)) {
102
- const eventStore = new InMemoryEventStore();
103
- const transport = new WebStandardStreamableHTTPServerTransport({
104
- sessionIdGenerator,
105
- eventStore,
106
- onsessioninitialized: (sid) => {
107
- // Factory called per session!
108
- const server = serverFactory();
109
- sessions.set(sid, { transport, server, eventStore });
110
- server.connect(transport);
111
- },
112
- });
113
- transport.onclose = () => {
114
- if (transport.sessionId) {
115
- sessions.delete(transport.sessionId);
116
- }
117
- };
118
- return transport.handleRequest(recreateRequest());
119
- }
120
- // Existing session
121
- if (sessionId) {
122
- const session = sessions.get(sessionId);
123
- if (!session) {
124
- return c.text("Session not found", 404);
125
- }
126
- return session.transport.handleRequest(recreateRequest());
127
- }
128
- // Invalid request (no session ID, not an initialize request)
129
- return c.text("Bad request - missing session ID", 400);
130
- });
131
- const httpServer = serve({
132
- fetch: app.fetch,
133
- port: options.port,
134
- hostname: options.host,
135
- });
136
- return createHandle(httpServer);
137
- }
138
- function addCors(app) {
139
- // Enable CORS for all origins
140
- app.use("*", cors({
141
- origin: "*",
142
- allowMethods: ["GET", "POST", "DELETE", "OPTIONS"],
143
- allowHeaders: [
144
- "Content-Type",
145
- "mcp-session-id",
146
- "Last-Event-ID",
147
- "mcp-protocol-version",
148
- ],
149
- exposeHeaders: ["mcp-session-id", "mcp-protocol-version"],
150
- }));
151
- }
1
+ // Re-export everything from both modules for convenience.
2
+ // Note: Importing from this entry point will load Hono dependencies.
3
+ // For stdio-only usage without Hono, import from "@karashiiro/mcp/stdio" instead.
4
+ export * from "./http.js";
5
+ export * from "./stdio.js";
152
6
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,qEAAqE;AACrE,kFAAkF;AAElF,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { ServerHandle } from "./types.js";
3
+ export type { ServerHandle } from "./types.js";
4
+ /**
5
+ * Serve an MCP server over stdio (stdin/stdout).
6
+ *
7
+ * @param serverFactory - Factory function that creates an McpServer instance.
8
+ * @returns A handle to control the server lifecycle.
9
+ */
10
+ export declare function serveStdio(serverFactory: () => McpServer): Promise<ServerHandle>;
11
+ //# sourceMappingURL=stdio.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C;;;;;GAKG;AACH,wBAAsB,UAAU,CAC9B,aAAa,EAAE,MAAM,SAAS,GAC7B,OAAO,CAAC,YAAY,CAAC,CA4BvB"}
package/dist/stdio.js ADDED
@@ -0,0 +1,31 @@
1
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
2
+ /**
3
+ * Serve an MCP server over stdio (stdin/stdout).
4
+ *
5
+ * @param serverFactory - Factory function that creates an McpServer instance.
6
+ * @returns A handle to control the server lifecycle.
7
+ */
8
+ export async function serveStdio(serverFactory) {
9
+ const server = serverFactory();
10
+ const transport = new StdioServerTransport();
11
+ // Set up the closed promise before connecting
12
+ let resolveClose;
13
+ const closedPromise = new Promise((resolve) => {
14
+ resolveClose = resolve;
15
+ });
16
+ transport.onclose = () => {
17
+ resolveClose();
18
+ };
19
+ // connect() automatically calls transport.start() for stdio
20
+ await server.connect(transport);
21
+ let closePromise;
22
+ return {
23
+ close: () => {
24
+ if (!closePromise) {
25
+ closePromise = transport.close().then(() => closedPromise);
26
+ }
27
+ return closePromise;
28
+ },
29
+ };
30
+ }
31
+ //# sourceMappingURL=stdio.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stdio.js","sourceRoot":"","sources":["../src/stdio.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAKjF;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,aAA8B,EACP;IACvB,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAE/B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAE7C,8CAA8C;IAC9C,IAAI,YAAwB,CAAC;IAC7B,MAAM,aAAa,GAAG,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,CAAC;QACnD,YAAY,GAAG,OAAO,CAAC;IAAA,CACxB,CAAC,CAAC;IAEH,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC;QACxB,YAAY,EAAE,CAAC;IAAA,CAChB,CAAC;IAEF,4DAA4D;IAC5D,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAEhC,IAAI,YAAuC,CAAC;IAE5C,OAAO;QACL,KAAK,EAAE,GAAG,EAAE,CAAC;YACX,IAAI,CAAC,YAAY,EAAE,CAAC;gBAClB,YAAY,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,aAAa,CAAC,CAAC;YAC7D,CAAC;YACD,OAAO,YAAY,CAAC;QAAA,CACrB;KACF,CAAC;AAAA,CACH"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Handle returned by serve functions for controlling the server lifecycle.
3
+ */
4
+ export interface ServerHandle {
5
+ /** Close the server and stop accepting new connections. */
6
+ close: () => Promise<void>;
7
+ }
8
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,2DAA2D;IAC3D,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "@karashiiro/mcp",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
7
+ "exports": {
8
+ ".": "./dist/index.js",
9
+ "./stdio": "./dist/stdio.js",
10
+ "./http": "./dist/http.js"
11
+ },
7
12
  "files": [
8
13
  "dist"
9
14
  ],
@@ -12,26 +17,42 @@
12
17
  "license": "UNLICENSED",
13
18
  "devDependencies": {
14
19
  "@eslint/js": "^9.39.2",
20
+ "@hono/node-server": "^1.19.8",
21
+ "@modelcontextprotocol/sdk": "^1.25.2",
15
22
  "@typescript/native-preview": "7.0.0-dev.20260113.1",
16
23
  "eslint": "^9.39.2",
24
+ "eventsource": "^4.1.0",
17
25
  "get-port": "^7.1.0",
18
26
  "globals": "^17.0.0",
27
+ "hono": "^4.11.4",
19
28
  "jiti": "^2.6.1",
20
29
  "prettier": "^3.7.4",
21
30
  "typescript-eslint": "^8.53.0",
22
- "vitest": "^4.0.17"
31
+ "vitest": "^4.0.17",
32
+ "zod": "^4.3.5"
23
33
  },
24
- "dependencies": {
34
+ "peerDependencies": {
25
35
  "@hono/node-server": "^1.19.8",
26
36
  "@modelcontextprotocol/sdk": "^1.25.2",
27
- "hono": "^4.11.4",
28
- "uuid": "^13.0.0",
29
- "zod": "^4.3.5"
37
+ "hono": "^4.11.4"
38
+ },
39
+ "peerDependenciesMeta": {
40
+ "@hono/node-server": {
41
+ "optional": true
42
+ },
43
+ "hono": {
44
+ "optional": true
45
+ }
46
+ },
47
+ "dependencies": {
48
+ "uuid": "^13.0.0"
30
49
  },
31
50
  "scripts": {
32
51
  "build": "tsgo -p tsconfig.dist.json",
33
- "test": "vitest",
52
+ "test": "vitest --run",
34
53
  "lint": "eslint . --ext .ts",
35
- "format": "prettier --write ."
54
+ "format": "prettier --write .",
55
+ "typecheck": "tsgo --noEmit",
56
+ "check": "pnpm typecheck && pnpm lint && pnpm test"
36
57
  }
37
58
  }