mcp-server-sdk 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/LICENSE +21 -0
- package/README.md +388 -0
- package/dist/index.d.ts +178 -0
- package/dist/index.js +253 -0
- package/package.json +46 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Human4AI
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# mcp-server-sdk
|
|
2
|
+
|
|
3
|
+
Enhanced Model Context Protocol (MCP) server SDK with session management, message routing, and distributed capabilities.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- ð **Single Instance, Multiple Sessions** - One server handles concurrent connections
|
|
8
|
+
- ð **Per-Request Transport** - Initialize transport for each request
|
|
9
|
+
- ð **Session Management** - Unique distributed session tracking with automatic timeouts
|
|
10
|
+
- ðĻ **Message Routing** - Route and store messages for resumability and replay
|
|
11
|
+
- ðū **Message Storage** - Built-in and custom storage implementations
|
|
12
|
+
- ð **Event System** - Listen to session and message events
|
|
13
|
+
- ðŊ **TypeScript Support** - Full type definitions
|
|
14
|
+
- ð **MCP Compatible** - Extends official `@modelcontextprotocol/sdk`
|
|
15
|
+
- ðŠķ **Minimal Dependencies**
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install mcp-server-sdk @modelcontextprotocol/sdk
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Architecture
|
|
24
|
+
|
|
25
|
+
The SDK supports a distributed architecture where:
|
|
26
|
+
|
|
27
|
+
1. **Single Server Instance** - Runs continuously and handles multiple sessions
|
|
28
|
+
2. **Per-Request Transports** - Each HTTP request can initialize its own transport
|
|
29
|
+
3. **Session-Based Routing** - Messages are routed by unique session IDs
|
|
30
|
+
4. **Message Storage** - All messages can be stored for resumability
|
|
31
|
+
5. **Event-Driven** - React to session lifecycle and message events
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
### Basic Usage
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { createMCPServer } from "mcp-server-sdk";
|
|
39
|
+
|
|
40
|
+
// Create server instance (singleton pattern recommended)
|
|
41
|
+
const server = createMCPServer({
|
|
42
|
+
name: "my-mcp-server",
|
|
43
|
+
version: "1.0.0",
|
|
44
|
+
title: "My MCP Server",
|
|
45
|
+
websiteUrl: "https://example.com"
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// Register tools
|
|
49
|
+
server.tool("hello", "Say hello", async () => {
|
|
50
|
+
return {
|
|
51
|
+
content: [{ type: "text", text: "Hello from MCP!" }]
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// Register resources
|
|
56
|
+
server.resource("config", "file:///config.json", async (uri) => {
|
|
57
|
+
return {
|
|
58
|
+
contents: [{
|
|
59
|
+
uri: uri.href,
|
|
60
|
+
text: JSON.stringify({ setting: "value" }),
|
|
61
|
+
mimeType: "application/json"
|
|
62
|
+
}]
|
|
63
|
+
};
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
console.log(`Server instance ID: ${server.getInstanceId()}`);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### HTTP/SSE Server Integration
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import express from "express";
|
|
73
|
+
import { createMCPServer } from "mcp-server-sdk";
|
|
74
|
+
import { DistributedStreamableHttpServerTransport } from "@human4.ai/distributed-streamable-http-server-transport";
|
|
75
|
+
|
|
76
|
+
const app = express();
|
|
77
|
+
const server = createMCPServer({
|
|
78
|
+
name: "distributed-mcp-server",
|
|
79
|
+
version: "1.0.0"
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Register your tools, resources, and prompts
|
|
83
|
+
server.tool("process-data", "Process data", async (args) => {
|
|
84
|
+
return {
|
|
85
|
+
content: [{ type: "text", text: `Processed: ${JSON.stringify(args)}` }]
|
|
86
|
+
};
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Handle incoming requests
|
|
90
|
+
app.use("/mcp", async (req, res) => {
|
|
91
|
+
try {
|
|
92
|
+
// Create per-request transport
|
|
93
|
+
const transport = new DistributedStreamableHttpServerTransport();
|
|
94
|
+
|
|
95
|
+
// Create or resume session
|
|
96
|
+
const sessionId = req.headers["x-session-id"] as string;
|
|
97
|
+
const session = await server.connectWithSession(transport, sessionId);
|
|
98
|
+
|
|
99
|
+
// Set session header for client
|
|
100
|
+
res.setHeader("X-Session-ID", session.sessionId);
|
|
101
|
+
|
|
102
|
+
// Handle the request
|
|
103
|
+
await transport.handleRequest(req, res);
|
|
104
|
+
|
|
105
|
+
// Update session activity
|
|
106
|
+
server.updateSessionActivity(session.sessionId);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
console.error("MCP request error:", error);
|
|
109
|
+
res.status(500).json({
|
|
110
|
+
jsonrpc: "2.0",
|
|
111
|
+
error: { code: -32603, message: "Internal server error" },
|
|
112
|
+
id: null
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
app.listen(3000, () => {
|
|
118
|
+
console.log("MCP server listening on port 3000");
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Session Management
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
const server = createMCPServer(
|
|
126
|
+
{ name: "my-server", version: "1.0.0" },
|
|
127
|
+
{
|
|
128
|
+
sessionTimeout: 30 * 60 * 1000, // 30 minutes
|
|
129
|
+
enableMessageRouting: true
|
|
130
|
+
}
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
// Listen to session events
|
|
134
|
+
server.on("session:created", (session) => {
|
|
135
|
+
console.log(`Session created: ${session.sessionId}`);
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
server.on("session:closed", (session) => {
|
|
139
|
+
console.log(`Session closed: ${session.sessionId}`);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Get active sessions
|
|
143
|
+
const sessions = server.getActiveSessions();
|
|
144
|
+
console.log(`Active sessions: ${sessions.length}`);
|
|
145
|
+
|
|
146
|
+
// Manually close a session
|
|
147
|
+
await server.closeSession("session-id");
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Message Storage and Replay
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { createMCPServer, InMemoryMessageStorage } from "mcp-server-sdk";
|
|
154
|
+
|
|
155
|
+
const server = createMCPServer(
|
|
156
|
+
{ name: "my-server", version: "1.0.0" },
|
|
157
|
+
{
|
|
158
|
+
messageStorage: new InMemoryMessageStorage(),
|
|
159
|
+
enableMessageRouting: true
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
// Listen to message events
|
|
164
|
+
server.on("message:stored", (message) => {
|
|
165
|
+
console.log(`Message stored: ${message.id}`);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// Retrieve session messages for replay
|
|
169
|
+
const messages = await server.getMessages("session-id", {
|
|
170
|
+
limit: 100,
|
|
171
|
+
offset: 0
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
console.log(`Retrieved ${messages.length} messages`);
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Custom Message Storage
|
|
178
|
+
|
|
179
|
+
Implement your own storage backend:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { MessageStorage, Message } from "mcp-server-sdk";
|
|
183
|
+
import { createClient } from "redis";
|
|
184
|
+
|
|
185
|
+
class RedisMessageStorage implements MessageStorage {
|
|
186
|
+
private client = createClient();
|
|
187
|
+
|
|
188
|
+
async store(message: Message): Promise<void> {
|
|
189
|
+
await this.client.connect();
|
|
190
|
+
const key = `messages:${message.sessionId}`;
|
|
191
|
+
await this.client.rPush(key, JSON.stringify(message));
|
|
192
|
+
await this.client.expire(key, 86400); // 24 hour TTL
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async retrieve(
|
|
196
|
+
sessionId: string,
|
|
197
|
+
options?: { limit?: number; offset?: number }
|
|
198
|
+
): Promise<Message[]> {
|
|
199
|
+
await this.client.connect();
|
|
200
|
+
const key = `messages:${sessionId}`;
|
|
201
|
+
const start = options?.offset || 0;
|
|
202
|
+
const end = start + (options?.limit || 100) - 1;
|
|
203
|
+
const data = await this.client.lRange(key, start, end);
|
|
204
|
+
return data.map((item) => JSON.parse(item));
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async delete(sessionId: string): Promise<void> {
|
|
208
|
+
await this.client.connect();
|
|
209
|
+
await this.client.del(`messages:${sessionId}`);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const server = createMCPServer(
|
|
214
|
+
{ name: "my-server", version: "1.0.0" },
|
|
215
|
+
{ messageStorage: new RedisMessageStorage() }
|
|
216
|
+
);
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## API Reference
|
|
220
|
+
|
|
221
|
+
### `createMCPServer(serverInfo, options)`
|
|
222
|
+
|
|
223
|
+
Creates a new MCP server instance with enhanced capabilities.
|
|
224
|
+
|
|
225
|
+
**Parameters:**
|
|
226
|
+
- `serverInfo: Implementation` - Server metadata
|
|
227
|
+
- `name: string` - Server name (required)
|
|
228
|
+
- `version: string` - Server version (required)
|
|
229
|
+
- `title?: string` - Display title
|
|
230
|
+
- `websiteUrl?: string` - Website URL
|
|
231
|
+
- `icons?: Array` - Server icons
|
|
232
|
+
- `options?: McpServerOptions` - Configuration options
|
|
233
|
+
- `instanceId?: string` - Unique server instance ID (auto-generated if omitted)
|
|
234
|
+
- `distributed?: boolean` - Enable distributed features (default: true)
|
|
235
|
+
- `messageStorage?: MessageStorage` - Message storage implementation
|
|
236
|
+
- `enableMessageRouting?: boolean` - Enable message routing (default: true)
|
|
237
|
+
- `sessionTimeout?: number` - Session timeout in ms (default: 1800000 / 30 min)
|
|
238
|
+
|
|
239
|
+
**Returns:** `MCPServer`
|
|
240
|
+
|
|
241
|
+
### `MCPServer`
|
|
242
|
+
|
|
243
|
+
Main server class extending `McpServer` from `@modelcontextprotocol/sdk`.
|
|
244
|
+
|
|
245
|
+
**Session Methods:**
|
|
246
|
+
- `createSession(metadata?: Record<string, unknown>): SessionInfo` - Create a new session
|
|
247
|
+
- `getSession(sessionId: string): SessionInfo | undefined` - Get session by ID
|
|
248
|
+
- `updateSessionActivity(sessionId: string): void` - Update session activity timestamp
|
|
249
|
+
- `closeSession(sessionId: string): Promise<void>` - Close a specific session
|
|
250
|
+
- `getActiveSessions(): SessionInfo[]` - Get all active sessions
|
|
251
|
+
|
|
252
|
+
**Message Methods:**
|
|
253
|
+
- `storeMessage(message: Omit<Message, "id" | "timestamp">): Promise<Message>` - Store a message
|
|
254
|
+
- `getMessages(sessionId: string, options?: { limit?: number; offset?: number }): Promise<Message[]>` - Retrieve messages
|
|
255
|
+
|
|
256
|
+
**Connection Methods:**
|
|
257
|
+
- `connect(transport: Transport): Promise<void>` - Connect to transport (standard MCP)
|
|
258
|
+
- `connectWithSession(transport: Transport, sessionId?: string): Promise<SessionInfo>` - Connect with session support
|
|
259
|
+
- `close(): Promise<void>` - Close all connections and sessions
|
|
260
|
+
|
|
261
|
+
**Instance Methods:**
|
|
262
|
+
- `getInstanceId(): string` - Get the unique instance identifier
|
|
263
|
+
- `isDistributed(): boolean` - Check if distributed mode is enabled
|
|
264
|
+
|
|
265
|
+
**Event Methods:**
|
|
266
|
+
- `on(event: string, listener: (...args: unknown[]) => void): this` - Listen to events
|
|
267
|
+
- `off(event: string, listener: (...args: unknown[]) => void): this` - Remove event listener
|
|
268
|
+
|
|
269
|
+
**Inherited Methods:**
|
|
270
|
+
All methods from `McpServer`:
|
|
271
|
+
- `tool()` - Register tools
|
|
272
|
+
- `resource()` - Register resources
|
|
273
|
+
- `prompt()` - Register prompts
|
|
274
|
+
- `sendLoggingMessage()` - Send log messages
|
|
275
|
+
- And more...
|
|
276
|
+
|
|
277
|
+
### Events
|
|
278
|
+
|
|
279
|
+
**Session Events:**
|
|
280
|
+
- `session:created` - Emitted when a session is created
|
|
281
|
+
- `session:closed` - Emitted when a session is closed
|
|
282
|
+
|
|
283
|
+
**Message Events:**
|
|
284
|
+
- `message:stored` - Emitted when a message is stored
|
|
285
|
+
|
|
286
|
+
### Types
|
|
287
|
+
|
|
288
|
+
```typescript
|
|
289
|
+
interface SessionInfo {
|
|
290
|
+
sessionId: string;
|
|
291
|
+
instanceId: string;
|
|
292
|
+
createdAt: Date;
|
|
293
|
+
lastActivity: Date;
|
|
294
|
+
metadata?: Record<string, unknown>;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
interface Message {
|
|
298
|
+
id: string;
|
|
299
|
+
sessionId: string;
|
|
300
|
+
timestamp: Date;
|
|
301
|
+
direction: "request" | "response" | "notification";
|
|
302
|
+
payload: unknown;
|
|
303
|
+
metadata?: Record<string, unknown>;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
interface MessageStorage {
|
|
307
|
+
store(message: Message): Promise<void>;
|
|
308
|
+
retrieve(sessionId: string, options?: { limit?: number; offset?: number }): Promise<Message[]>;
|
|
309
|
+
delete(sessionId: string): Promise<void>;
|
|
310
|
+
}
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
### Built-in Storage
|
|
314
|
+
|
|
315
|
+
**`InMemoryMessageStorage`**
|
|
316
|
+
|
|
317
|
+
In-memory implementation of `MessageStorage` interface. Suitable for development and testing.
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
import { InMemoryMessageStorage } from "mcp-server-sdk";
|
|
321
|
+
|
|
322
|
+
const storage = new InMemoryMessageStorage();
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## Use Cases
|
|
326
|
+
|
|
327
|
+
### 1. HTTP/SSE MCP Server
|
|
328
|
+
|
|
329
|
+
Single server instance handling multiple HTTP requests with SSE for streaming responses.
|
|
330
|
+
|
|
331
|
+
### 2. WebSocket MCP Server
|
|
332
|
+
|
|
333
|
+
Maintain sessions across WebSocket connections with message replay on reconnection.
|
|
334
|
+
|
|
335
|
+
### 3. Distributed MCP Cluster
|
|
336
|
+
|
|
337
|
+
Multiple server instances with shared session storage (e.g., Redis) for load balancing.
|
|
338
|
+
|
|
339
|
+
### 4. Development and Testing
|
|
340
|
+
|
|
341
|
+
In-memory storage for rapid development without external dependencies.
|
|
342
|
+
|
|
343
|
+
## TypeScript Support
|
|
344
|
+
|
|
345
|
+
Full TypeScript support with exported types:
|
|
346
|
+
|
|
347
|
+
```typescript
|
|
348
|
+
import type {
|
|
349
|
+
Implementation,
|
|
350
|
+
Transport,
|
|
351
|
+
ToolCallback,
|
|
352
|
+
RegisteredTool,
|
|
353
|
+
ResourceTemplate,
|
|
354
|
+
CallToolResult,
|
|
355
|
+
SessionInfo,
|
|
356
|
+
Message,
|
|
357
|
+
MessageStorage,
|
|
358
|
+
McpServerOptions,
|
|
359
|
+
} from "mcp-server-sdk";
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
## Backward Compatibility
|
|
363
|
+
|
|
364
|
+
Legacy exports are maintained for backward compatibility:
|
|
365
|
+
|
|
366
|
+
```typescript
|
|
367
|
+
import { DistributedMcpServer, createDistributedMcpServer } from "mcp-server-sdk";
|
|
368
|
+
// Aliases for MCPServer and createMCPServer
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## Requirements
|
|
372
|
+
|
|
373
|
+
- Node.js >= 18.0.0
|
|
374
|
+
- `@modelcontextprotocol/sdk` >= 1.0.0
|
|
375
|
+
|
|
376
|
+
## License
|
|
377
|
+
|
|
378
|
+
MIT
|
|
379
|
+
|
|
380
|
+
## Contributing
|
|
381
|
+
|
|
382
|
+
Contributions are welcome! This SDK is designed to be extended for specific distributed use cases.
|
|
383
|
+
|
|
384
|
+
## Related
|
|
385
|
+
|
|
386
|
+
- [Model Context Protocol](https://modelcontextprotocol.io/)
|
|
387
|
+
- [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/sdk)
|
|
388
|
+
- [Human4AI Platform](https://github.com/Human4AI/source-code)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
3
|
+
import { Implementation } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Session information for tracking distributed MCP connections
|
|
6
|
+
*/
|
|
7
|
+
export interface SessionInfo {
|
|
8
|
+
sessionId: string;
|
|
9
|
+
instanceId: string;
|
|
10
|
+
createdAt: Date;
|
|
11
|
+
lastActivity: Date;
|
|
12
|
+
metadata?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Message for routing and storage
|
|
16
|
+
*/
|
|
17
|
+
export interface Message {
|
|
18
|
+
id: string;
|
|
19
|
+
sessionId: string;
|
|
20
|
+
timestamp: Date;
|
|
21
|
+
direction: "request" | "response" | "notification";
|
|
22
|
+
payload: unknown;
|
|
23
|
+
metadata?: Record<string, unknown>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Message storage interface for resumability and replay
|
|
27
|
+
*/
|
|
28
|
+
export interface MessageStorage {
|
|
29
|
+
store(message: Message): Promise<void>;
|
|
30
|
+
retrieve(sessionId: string, options?: {
|
|
31
|
+
limit?: number;
|
|
32
|
+
offset?: number;
|
|
33
|
+
}): Promise<Message[]>;
|
|
34
|
+
delete(sessionId: string): Promise<void>;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* In-memory message storage implementation
|
|
38
|
+
*/
|
|
39
|
+
export declare class InMemoryMessageStorage implements MessageStorage {
|
|
40
|
+
private messages;
|
|
41
|
+
store(message: Message): Promise<void>;
|
|
42
|
+
retrieve(sessionId: string, options?: {
|
|
43
|
+
limit?: number;
|
|
44
|
+
offset?: number;
|
|
45
|
+
}): Promise<Message[]>;
|
|
46
|
+
delete(sessionId: string): Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
export interface McpServerOptions {
|
|
49
|
+
/**
|
|
50
|
+
* Unique identifier for this server instance
|
|
51
|
+
*/
|
|
52
|
+
instanceId?: string;
|
|
53
|
+
/**
|
|
54
|
+
* Enable distributed mode features
|
|
55
|
+
*/
|
|
56
|
+
distributed?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Message storage implementation for resumability
|
|
59
|
+
*/
|
|
60
|
+
messageStorage?: MessageStorage;
|
|
61
|
+
/**
|
|
62
|
+
* Enable message routing
|
|
63
|
+
*/
|
|
64
|
+
enableMessageRouting?: boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Session timeout in milliseconds (default: 30 minutes)
|
|
67
|
+
*/
|
|
68
|
+
sessionTimeout?: number;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* MCP Server SDK - Enhanced MCP server with session management and distributed capabilities
|
|
72
|
+
*
|
|
73
|
+
* Features:
|
|
74
|
+
* - Single instance server supporting multiple concurrent sessions
|
|
75
|
+
* - Per-request transport initialization
|
|
76
|
+
* - Unique distributed session tracking
|
|
77
|
+
* - Message routing and storage for resumability
|
|
78
|
+
* - Built-in session management with timeouts
|
|
79
|
+
*/
|
|
80
|
+
export declare class MCPServer extends McpServer {
|
|
81
|
+
private readonly instanceId;
|
|
82
|
+
private readonly distributed;
|
|
83
|
+
private readonly sessions;
|
|
84
|
+
private readonly messageStorage;
|
|
85
|
+
private readonly enableMessageRouting;
|
|
86
|
+
private readonly sessionTimeout;
|
|
87
|
+
private readonly eventEmitter;
|
|
88
|
+
constructor(serverInfo: Implementation, options?: McpServerOptions);
|
|
89
|
+
/**
|
|
90
|
+
* Get the instance ID for this server
|
|
91
|
+
*/
|
|
92
|
+
getInstanceId(): string;
|
|
93
|
+
/**
|
|
94
|
+
* Check if distributed mode is enabled
|
|
95
|
+
*/
|
|
96
|
+
isDistributed(): boolean;
|
|
97
|
+
/**
|
|
98
|
+
* Create a new session for a transport connection
|
|
99
|
+
*/
|
|
100
|
+
createSession(metadata?: Record<string, unknown>): SessionInfo;
|
|
101
|
+
/**
|
|
102
|
+
* Get session by ID
|
|
103
|
+
*/
|
|
104
|
+
getSession(sessionId: string): SessionInfo | undefined;
|
|
105
|
+
/**
|
|
106
|
+
* Update session activity timestamp
|
|
107
|
+
*/
|
|
108
|
+
updateSessionActivity(sessionId: string): void;
|
|
109
|
+
/**
|
|
110
|
+
* Close a specific session
|
|
111
|
+
*/
|
|
112
|
+
closeSession(sessionId: string): Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* Get all active sessions
|
|
115
|
+
*/
|
|
116
|
+
getActiveSessions(): SessionInfo[];
|
|
117
|
+
/**
|
|
118
|
+
* Store a message for resumability
|
|
119
|
+
*/
|
|
120
|
+
storeMessage(message: Omit<Message, "id" | "timestamp">): Promise<Message>;
|
|
121
|
+
/**
|
|
122
|
+
* Retrieve messages for a session
|
|
123
|
+
*/
|
|
124
|
+
getMessages(sessionId: string, options?: {
|
|
125
|
+
limit?: number;
|
|
126
|
+
offset?: number;
|
|
127
|
+
}): Promise<Message[]>;
|
|
128
|
+
/**
|
|
129
|
+
* Connect to a transport (standard MCP method)
|
|
130
|
+
*/
|
|
131
|
+
connect(transport: Transport): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Connect to a transport with session management
|
|
134
|
+
*/
|
|
135
|
+
connectWithSession(transport: Transport, sessionId?: string): Promise<SessionInfo>;
|
|
136
|
+
/**
|
|
137
|
+
* Close the connection with session cleanup
|
|
138
|
+
*/
|
|
139
|
+
close(): Promise<void>;
|
|
140
|
+
/**
|
|
141
|
+
* Listen to server events
|
|
142
|
+
*/
|
|
143
|
+
on(event: string, listener: (...args: unknown[]) => void): this;
|
|
144
|
+
/**
|
|
145
|
+
* Remove event listener
|
|
146
|
+
*/
|
|
147
|
+
off(event: string, listener: (...args: unknown[]) => void): this;
|
|
148
|
+
/**
|
|
149
|
+
* Generate a unique session ID
|
|
150
|
+
*/
|
|
151
|
+
private generateSessionId;
|
|
152
|
+
/**
|
|
153
|
+
* Generate a unique message ID
|
|
154
|
+
*/
|
|
155
|
+
private generateMessageId;
|
|
156
|
+
/**
|
|
157
|
+
* Generate a unique instance ID
|
|
158
|
+
*/
|
|
159
|
+
private generateInstanceId;
|
|
160
|
+
/**
|
|
161
|
+
* Start periodic session cleanup
|
|
162
|
+
*/
|
|
163
|
+
private startSessionCleanup;
|
|
164
|
+
/**
|
|
165
|
+
* Log distributed events
|
|
166
|
+
*/
|
|
167
|
+
private logDistributedEvent;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Create a new MCP server instance with enhanced capabilities
|
|
171
|
+
*/
|
|
172
|
+
export declare function createMCPServer(serverInfo: Implementation, options?: McpServerOptions): MCPServer;
|
|
173
|
+
export type { ToolCallback, RegisteredTool, RegisteredResource, RegisteredPrompt, ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
174
|
+
export type { Implementation, CallToolResult, ReadResourceResult, GetPromptResult } from "@modelcontextprotocol/sdk/types.js";
|
|
175
|
+
export type { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
176
|
+
export type { ServerOptions } from "@modelcontextprotocol/sdk/server/index.js";
|
|
177
|
+
export { MCPServer as DistributedMcpServer };
|
|
178
|
+
export { createMCPServer as createDistributedMcpServer };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DistributedMcpServer = exports.MCPServer = exports.InMemoryMessageStorage = void 0;
|
|
4
|
+
exports.createMCPServer = createMCPServer;
|
|
5
|
+
exports.createDistributedMcpServer = createMCPServer;
|
|
6
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
7
|
+
const events_1 = require("events");
|
|
8
|
+
/**
|
|
9
|
+
* In-memory message storage implementation
|
|
10
|
+
*/
|
|
11
|
+
class InMemoryMessageStorage {
|
|
12
|
+
constructor() {
|
|
13
|
+
this.messages = new Map();
|
|
14
|
+
}
|
|
15
|
+
async store(message) {
|
|
16
|
+
const messages = this.messages.get(message.sessionId) || [];
|
|
17
|
+
messages.push(message);
|
|
18
|
+
this.messages.set(message.sessionId, messages);
|
|
19
|
+
}
|
|
20
|
+
async retrieve(sessionId, options) {
|
|
21
|
+
const messages = this.messages.get(sessionId) || [];
|
|
22
|
+
const offset = options?.offset || 0;
|
|
23
|
+
const limit = options?.limit || messages.length;
|
|
24
|
+
return messages.slice(offset, offset + limit);
|
|
25
|
+
}
|
|
26
|
+
async delete(sessionId) {
|
|
27
|
+
this.messages.delete(sessionId);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.InMemoryMessageStorage = InMemoryMessageStorage;
|
|
31
|
+
/**
|
|
32
|
+
* MCP Server SDK - Enhanced MCP server with session management and distributed capabilities
|
|
33
|
+
*
|
|
34
|
+
* Features:
|
|
35
|
+
* - Single instance server supporting multiple concurrent sessions
|
|
36
|
+
* - Per-request transport initialization
|
|
37
|
+
* - Unique distributed session tracking
|
|
38
|
+
* - Message routing and storage for resumability
|
|
39
|
+
* - Built-in session management with timeouts
|
|
40
|
+
*/
|
|
41
|
+
class MCPServer extends mcp_js_1.McpServer {
|
|
42
|
+
constructor(serverInfo, options = {}) {
|
|
43
|
+
super(serverInfo);
|
|
44
|
+
this.sessions = new Map();
|
|
45
|
+
this.eventEmitter = new events_1.EventEmitter();
|
|
46
|
+
this.instanceId = options.instanceId || this.generateInstanceId();
|
|
47
|
+
this.distributed = options.distributed ?? true;
|
|
48
|
+
this.messageStorage = options.messageStorage || new InMemoryMessageStorage();
|
|
49
|
+
this.enableMessageRouting = options.enableMessageRouting ?? true;
|
|
50
|
+
this.sessionTimeout = options.sessionTimeout || 30 * 60 * 1000; // 30 minutes
|
|
51
|
+
// Start session cleanup interval
|
|
52
|
+
this.startSessionCleanup();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Get the instance ID for this server
|
|
56
|
+
*/
|
|
57
|
+
getInstanceId() {
|
|
58
|
+
return this.instanceId;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Check if distributed mode is enabled
|
|
62
|
+
*/
|
|
63
|
+
isDistributed() {
|
|
64
|
+
return this.distributed;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Create a new session for a transport connection
|
|
68
|
+
*/
|
|
69
|
+
createSession(metadata) {
|
|
70
|
+
const sessionId = this.generateSessionId();
|
|
71
|
+
const session = {
|
|
72
|
+
sessionId,
|
|
73
|
+
instanceId: this.instanceId,
|
|
74
|
+
createdAt: new Date(),
|
|
75
|
+
lastActivity: new Date(),
|
|
76
|
+
metadata,
|
|
77
|
+
};
|
|
78
|
+
this.sessions.set(sessionId, session);
|
|
79
|
+
this.eventEmitter.emit("session:created", session);
|
|
80
|
+
return session;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Get session by ID
|
|
84
|
+
*/
|
|
85
|
+
getSession(sessionId) {
|
|
86
|
+
return this.sessions.get(sessionId);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Update session activity timestamp
|
|
90
|
+
*/
|
|
91
|
+
updateSessionActivity(sessionId) {
|
|
92
|
+
const session = this.sessions.get(sessionId);
|
|
93
|
+
if (session) {
|
|
94
|
+
session.lastActivity = new Date();
|
|
95
|
+
this.sessions.set(sessionId, session);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Close a specific session
|
|
100
|
+
*/
|
|
101
|
+
async closeSession(sessionId) {
|
|
102
|
+
const session = this.sessions.get(sessionId);
|
|
103
|
+
if (session) {
|
|
104
|
+
this.sessions.delete(sessionId);
|
|
105
|
+
this.eventEmitter.emit("session:closed", session);
|
|
106
|
+
if (this.distributed) {
|
|
107
|
+
await this.logDistributedEvent("session:closed", {
|
|
108
|
+
sessionId,
|
|
109
|
+
instanceId: this.instanceId,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get all active sessions
|
|
116
|
+
*/
|
|
117
|
+
getActiveSessions() {
|
|
118
|
+
return Array.from(this.sessions.values());
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Store a message for resumability
|
|
122
|
+
*/
|
|
123
|
+
async storeMessage(message) {
|
|
124
|
+
const fullMessage = {
|
|
125
|
+
...message,
|
|
126
|
+
id: this.generateMessageId(),
|
|
127
|
+
timestamp: new Date(),
|
|
128
|
+
};
|
|
129
|
+
if (this.enableMessageRouting) {
|
|
130
|
+
await this.messageStorage.store(fullMessage);
|
|
131
|
+
this.eventEmitter.emit("message:stored", fullMessage);
|
|
132
|
+
}
|
|
133
|
+
return fullMessage;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Retrieve messages for a session
|
|
137
|
+
*/
|
|
138
|
+
async getMessages(sessionId, options) {
|
|
139
|
+
return this.messageStorage.retrieve(sessionId, options);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Connect to a transport (standard MCP method)
|
|
143
|
+
*/
|
|
144
|
+
async connect(transport) {
|
|
145
|
+
return super.connect(transport);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Connect to a transport with session management
|
|
149
|
+
*/
|
|
150
|
+
async connectWithSession(transport, sessionId) {
|
|
151
|
+
const session = sessionId
|
|
152
|
+
? this.getSession(sessionId) || this.createSession()
|
|
153
|
+
: this.createSession();
|
|
154
|
+
if (this.distributed) {
|
|
155
|
+
await this.logDistributedEvent("connect", {
|
|
156
|
+
sessionId: session.sessionId,
|
|
157
|
+
instanceId: this.instanceId,
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
await super.connect(transport);
|
|
161
|
+
return session;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Close the connection with session cleanup
|
|
165
|
+
*/
|
|
166
|
+
async close() {
|
|
167
|
+
// Close all sessions
|
|
168
|
+
const sessionIds = Array.from(this.sessions.keys());
|
|
169
|
+
for (const sessionId of sessionIds) {
|
|
170
|
+
await this.closeSession(sessionId);
|
|
171
|
+
}
|
|
172
|
+
if (this.distributed) {
|
|
173
|
+
await this.logDistributedEvent("close", { instanceId: this.instanceId });
|
|
174
|
+
}
|
|
175
|
+
return super.close();
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Listen to server events
|
|
179
|
+
*/
|
|
180
|
+
on(event, listener) {
|
|
181
|
+
this.eventEmitter.on(event, listener);
|
|
182
|
+
return this;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Remove event listener
|
|
186
|
+
*/
|
|
187
|
+
off(event, listener) {
|
|
188
|
+
this.eventEmitter.off(event, listener);
|
|
189
|
+
return this;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Generate a unique session ID
|
|
193
|
+
*/
|
|
194
|
+
generateSessionId() {
|
|
195
|
+
const timestamp = Date.now().toString(36);
|
|
196
|
+
const random = Math.random().toString(36).substring(2, 15);
|
|
197
|
+
return `session-${timestamp}-${random}`;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Generate a unique message ID
|
|
201
|
+
*/
|
|
202
|
+
generateMessageId() {
|
|
203
|
+
const timestamp = Date.now().toString(36);
|
|
204
|
+
const random = Math.random().toString(36).substring(2, 15);
|
|
205
|
+
return `msg-${timestamp}-${random}`;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Generate a unique instance ID
|
|
209
|
+
*/
|
|
210
|
+
generateInstanceId() {
|
|
211
|
+
const timestamp = Date.now().toString(36);
|
|
212
|
+
const random = Math.random().toString(36).substring(2, 9);
|
|
213
|
+
return `mcp-${timestamp}-${random}`;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Start periodic session cleanup
|
|
217
|
+
*/
|
|
218
|
+
startSessionCleanup() {
|
|
219
|
+
setInterval(() => {
|
|
220
|
+
const now = Date.now();
|
|
221
|
+
for (const [sessionId, session] of this.sessions.entries()) {
|
|
222
|
+
if (now - session.lastActivity.getTime() > this.sessionTimeout) {
|
|
223
|
+
this.closeSession(sessionId).catch((error) => {
|
|
224
|
+
console.error(`Error closing session ${sessionId}:`, error);
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}, 60000); // Check every minute
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Log distributed events
|
|
232
|
+
*/
|
|
233
|
+
async logDistributedEvent(event, data) {
|
|
234
|
+
if (this.isConnected()) {
|
|
235
|
+
await this.sendLoggingMessage({
|
|
236
|
+
level: "info",
|
|
237
|
+
data: {
|
|
238
|
+
event,
|
|
239
|
+
...data,
|
|
240
|
+
timestamp: new Date().toISOString(),
|
|
241
|
+
},
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
exports.MCPServer = MCPServer;
|
|
247
|
+
exports.DistributedMcpServer = MCPServer;
|
|
248
|
+
/**
|
|
249
|
+
* Create a new MCP server instance with enhanced capabilities
|
|
250
|
+
*/
|
|
251
|
+
function createMCPServer(serverInfo, options) {
|
|
252
|
+
return new MCPServer(serverInfo, options);
|
|
253
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "mcp-server-sdk",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Enhanced MCP server SDK with session management, message routing, and distributed capabilities",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"README.md",
|
|
10
|
+
"LICENSE"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"prepublishOnly": "npm run build",
|
|
15
|
+
"clean": "rm -rf dist"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"mcp",
|
|
19
|
+
"model-context-protocol",
|
|
20
|
+
"mcp-server",
|
|
21
|
+
"distributed",
|
|
22
|
+
"session-management",
|
|
23
|
+
"message-routing",
|
|
24
|
+
"server",
|
|
25
|
+
"sdk",
|
|
26
|
+
"ai"
|
|
27
|
+
],
|
|
28
|
+
"author": "Human4AI",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/Human4AI/source-code.git",
|
|
33
|
+
"directory": "tmp/distributed-mcp-server"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"@modelcontextprotocol/sdk": ">=1.0.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
40
|
+
"@types/node": "^20.0.0",
|
|
41
|
+
"typescript": "^5.0.0"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18.0.0"
|
|
45
|
+
}
|
|
46
|
+
}
|