@interopio/mcp-http 0.1.0-beta.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 ADDED
@@ -0,0 +1,613 @@
1
+ # io.Intelligence MCP HTTP
2
+
3
+ ## Table of Contents
4
+
5
+ - [Introduction](#introduction)
6
+ - [Installation](#installation)
7
+ - [Core Concepts](#core-concepts)
8
+ - [HTTP Transport](#http-transport)
9
+ - [Session Management](#session-management)
10
+ - [SSE vs JSON Response Modes](#sse-vs-json-response-modes)
11
+ - [DNS Rebinding Protection](#dns-rebinding-protection)
12
+ - [API Reference](#api-reference)
13
+ - [IoIntelMCPHttpFactory](#iointelmcphttpfactory)
14
+ - [Configuration Types](#configuration-types)
15
+ - [Configuration](#configuration)
16
+ - [License Key](#license-key)
17
+ - [Server Options](#server-options)
18
+ - [Transport Options](#transport-options)
19
+ - [MCP Core Server Configuration](#mcp-core-server-configuration)
20
+ - [Working Context Configuration](#working-context-configuration)
21
+ - [Integration Options](#integration-options)
22
+ - [With io.Connect Desktop](#with-ioconnect-desktop)
23
+ - [Standalone HTTP Server](#standalone-http-server)
24
+ - [Examples](#examples)
25
+ - [Basic HTTP Server](#basic-http-server)
26
+ - [Custom Port and CORS](#custom-port-and-cors)
27
+ - [With Session Management](#with-session-management)
28
+ - [With DNS Rebinding Protection](#with-dns-rebinding-protection)
29
+ - [Custom Server Configuration](#custom-server-configuration)
30
+ - [Complete io.Connect Desktop Integration](#complete-ioconnect-desktop-integration)
31
+
32
+ ---
33
+
34
+ ## Introduction
35
+
36
+ `@interopio/mcp-http` is a TypeScript library that provides HTTP transport implementation for Model Context Protocol (MCP) servers in the io.Intelligence ecosystem. It enables MCP functionality from `@interopio/mcp-core` to be delivered over HTTP, making it ideal for integration with io.Connect Desktop and other HTTP-based clients.
37
+
38
+ ### Key Features
39
+
40
+ - **Express-based HTTP Server**: Built-in HTTP server with automatic middleware configuration
41
+ - **Session Management**: Support for multiple concurrent MCP sessions with unique session IDs
42
+ - **Server-Sent Events (SSE)**: Streaming responses for real-time communication
43
+ - **JSON Response Mode**: Optional simple request/response mode without streaming
44
+ - **Resumability**: Event store support for reconnection and message resumption
45
+ - **DNS Rebinding Protection**: Security features to prevent DNS rebinding attacks
46
+ - **Flexible CORS**: Configurable origin, headers, and exposed headers
47
+ - **Custom Middleware**: Hook for adding custom Express middleware
48
+ - **Multi-Instance Support**: Manage multiple MCP instances per session
49
+
50
+ ### Target Audience
51
+
52
+ Developers building HTTP-based MCP servers for io.Connect Desktop or other HTTP clients who need to expose MCP tools and functionality over HTTP.
53
+
54
+ ---
55
+
56
+ ## Installation
57
+
58
+ ```bash
59
+ npm install @interopio/mcp-http
60
+ ```
61
+
62
+ ### Requirements
63
+
64
+ - Node.js 16 or higher
65
+ - TypeScript 4.5 or higher
66
+ - Valid io.Intelligence license key
67
+ - io.Connect Desktop or io.Connect Browser instance
68
+
69
+ ---
70
+
71
+ ## Core Concepts
72
+
73
+ ### HTTP Transport
74
+
75
+ The package uses the HTTP transport implementation from `@modelcontextprotocol/sdk`, exposing three primary endpoints:
76
+
77
+ - **GET `/mcp`**: Retrieve messages for an existing session (requires `mcp-session-id` header)
78
+ - **POST `/mcp`**: Send messages or initialize a new session
79
+ - **DELETE `/mcp`**: Close a session and clean up resources
80
+
81
+ All endpoints require a `mcp-session-id` header except for the initial initialization POST request.
82
+
83
+ ### Session Management
84
+
85
+ Each MCP client connection is represented by a session with a unique session ID. Sessions are:
86
+
87
+ - **Generated**: Automatically using `randomUUID()` or via custom `sessionIdGenerator`
88
+ - **Tracked**: Stored internally and mapped to transport instances
89
+ - **Lifecycle-managed**: Created on initialization, closed on DELETE request
90
+ - **Multi-instance**: Each session can manage multiple MCP server instances
91
+
92
+ ### SSE vs JSON Response Modes
93
+
94
+ The library supports two response modes:
95
+
96
+ **Server-Sent Events (SSE) - Default**
97
+
98
+ - Streams responses in real-time
99
+ - Maintains persistent connection
100
+ - Better for long-running operations
101
+ - Preferred for most use cases
102
+
103
+ **JSON Response Mode**
104
+
105
+ - Simple request/response pattern
106
+ - No persistent connection
107
+ - Useful for testing or simple scenarios
108
+ - Enabled via `enableJsonResponse: true`
109
+
110
+ ### DNS Rebinding Protection
111
+
112
+ Security features to prevent DNS rebinding attacks:
113
+
114
+ - **Host Validation**: Whitelist allowed `Host` header values
115
+ - **Origin Validation**: Whitelist allowed `Origin` header values
116
+ - **Opt-in Security**: Must enable `enableDnsRebindingProtection` and configure allowed hosts/origins
117
+
118
+ ---
119
+
120
+ ## API Reference
121
+
122
+ ### IoIntelMCPHttpFactory
123
+
124
+ ```typescript
125
+ IoIntelMCPHttpFactory(
126
+ io: IOConnectDesktop.API,
127
+ config: IoIntelMCPHttp.Config
128
+ ): Promise<void>
129
+ ```
130
+
131
+ Factory function that initializes an HTTP-based MCP server.
132
+
133
+ **Parameters:**
134
+
135
+ - `io`: Initialized io.Connect Desktop API instance
136
+ - `config`: Configuration object (see [Configuration](#configuration))
137
+
138
+ **Returns:** Promise that resolves when server is started
139
+
140
+ **Throws:** Error if configuration is invalid or license key is invalid/expired
141
+
142
+ ### Configuration Types
143
+
144
+ #### IoIntelMCPHttp.Config
145
+
146
+ ```typescript
147
+ interface Config {
148
+ licenseKey: string;
149
+ transportOptions?: HTTPTransportOptions;
150
+ server?: ServerOptions;
151
+ mcpCoreServer?: Omit<IoIntelMCPCore.McpServerConfig, "name" | "title">;
152
+ mcpWorkingContext?: IoIntelMCPCore.WorkingContextConfig;
153
+ }
154
+ ```
155
+
156
+ #### ServerOptions
157
+
158
+ ```typescript
159
+ interface ServerOptions {
160
+ port?: number;
161
+ origin?: string | string[];
162
+ exposedHeaders?: string[];
163
+ allowedHeaders?: string[];
164
+ configureServer?: (app: Application) => Promise<void>;
165
+ }
166
+ ```
167
+
168
+ #### HTTPTransportOptions
169
+
170
+ ```typescript
171
+ interface HTTPTransportOptions {
172
+ sessionIdGenerator?: (() => string) | undefined;
173
+ onsessioninitialized?: (sessionId: string) => void | Promise<void>;
174
+ onsessionclosed?: (sessionId: string) => void | Promise<void>;
175
+ enableJsonResponse?: boolean;
176
+ eventStore?: EventStore;
177
+ allowedHosts?: string[];
178
+ allowedOrigins?: string[];
179
+ enableDnsRebindingProtection?: boolean;
180
+ }
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Configuration
186
+
187
+ ### License Key
188
+
189
+ A valid io.Intelligence license key is **required**:
190
+
191
+ ```typescript
192
+ const config = {
193
+ licenseKey: "your-signed-jwt-token-here",
194
+ // ...
195
+ };
196
+ ```
197
+
198
+ ### Server Options
199
+
200
+ #### port
201
+
202
+ ```typescript
203
+ server: {
204
+ port: 8080; // Default: 8080
205
+ }
206
+ ```
207
+
208
+ Port number for the HTTP server (1-65535).
209
+
210
+ #### origin
211
+
212
+ ```typescript
213
+ server: {
214
+ origin: "*"; // Default: "*"
215
+ // or
216
+ origin: ["https://example.com", "https://app.example.com"];
217
+ }
218
+ ```
219
+
220
+ CORS origin configuration. Can be a single string or array of allowed origins.
221
+
222
+ #### exposedHeaders
223
+
224
+ ```typescript
225
+ server: {
226
+ exposedHeaders: ["Mcp-Session-Id"]; // Default
227
+ }
228
+ ```
229
+
230
+ HTTP headers exposed to clients via CORS.
231
+
232
+ #### allowedHeaders
233
+
234
+ ```typescript
235
+ server: {
236
+ allowedHeaders: ["Content-Type", "mcp-session-id", "mcp-protocol-version"]; // Default
237
+ }
238
+ ```
239
+
240
+ HTTP headers allowed in requests via CORS.
241
+
242
+ #### configureServer
243
+
244
+ ```typescript
245
+ server: {
246
+ configureServer: async (app) => {
247
+ app.use(express.static("public"));
248
+ app.use(customMiddleware());
249
+ };
250
+ }
251
+ ```
252
+
253
+ Optional callback to apply custom Express middleware before routes are registered.
254
+
255
+ ### Transport Options
256
+
257
+ #### sessionIdGenerator
258
+
259
+ ```typescript
260
+ transportOptions: {
261
+ sessionIdGenerator: () => {
262
+ return customSecureUUID();
263
+ };
264
+ }
265
+ ```
266
+
267
+ Custom function to generate session IDs. Should return globally unique and cryptographically secure strings. Return `undefined` to disable session management.
268
+
269
+ #### onsessioninitialized
270
+
271
+ ```typescript
272
+ transportOptions: {
273
+ onsessioninitialized: async (sessionId) => {
274
+ console.log(`Session ${sessionId} initialized`);
275
+ await registerSession(sessionId);
276
+ };
277
+ }
278
+ ```
279
+
280
+ Callback invoked when a new session is initialized. Useful for tracking or logging.
281
+
282
+ #### onsessionclosed
283
+
284
+ ```typescript
285
+ transportOptions: {
286
+ onsessionclosed: async (sessionId) => {
287
+ console.log(`Session ${sessionId} closed`);
288
+ await cleanupSession(sessionId);
289
+ };
290
+ }
291
+ ```
292
+
293
+ Callback invoked when a session is closed via DELETE request. Useful for cleanup.
294
+
295
+ #### enableJsonResponse
296
+
297
+ ```typescript
298
+ transportOptions: {
299
+ enableJsonResponse: true; // Default: false
300
+ }
301
+ ```
302
+
303
+ Enable simple JSON response mode instead of SSE streaming.
304
+
305
+ #### eventStore
306
+
307
+ ```typescript
308
+ transportOptions: {
309
+ eventStore: customEventStore; // Implements EventStore interface
310
+ }
311
+ ```
312
+
313
+ Optional event store for resumability support, allowing clients to reconnect and resume.
314
+
315
+ #### DNS Rebinding Protection
316
+
317
+ ```typescript
318
+ transportOptions: {
319
+ enableDnsRebindingProtection: true,
320
+ allowedHosts: ["localhost:8080", "127.0.0.1:8080"],
321
+ allowedOrigins: ["http://localhost:3000"]
322
+ }
323
+ ```
324
+
325
+ Enable DNS rebinding protection with whitelisted hosts and origins.
326
+
327
+ ### MCP Core Server Configuration
328
+
329
+ ```typescript
330
+ mcpCoreServer: {
331
+ tools: {
332
+ system: {
333
+ searchApps: { enabled: true },
334
+ startApps: { enabled: true }
335
+ },
336
+ static: {
337
+ methods: [
338
+ // Static method tool definitions
339
+ ]
340
+ },
341
+ dynamic: {
342
+ methods: { enabled: true }
343
+ }
344
+ }
345
+ }
346
+ ```
347
+
348
+ Configure MCP tools as defined in `@interopio/mcp-core`. See the [MCP Core documentation](./mcp-core.md) for complete tool configuration options.
349
+
350
+ ### Working Context Configuration
351
+
352
+ ```typescript
353
+ mcpWorkingContext: {
354
+ factory: IoIntelWorkingContextFactory,
355
+ config: {
356
+ // Working context configuration
357
+ }
358
+ }
359
+ ```
360
+
361
+ Optional working context integration. See `@interopio/intel-working-context` documentation for configuration details.
362
+
363
+ ---
364
+
365
+ ## Integration Options
366
+
367
+ ### With io.Connect Desktop
368
+
369
+ The preferred integration method for io.Connect Desktop is defining the HTTP server as a service application:
370
+
371
+ **Application Definition (JSON):**
372
+
373
+ ```json
374
+ [
375
+ {
376
+ "name": "intel-mcp-server",
377
+ "type": "node",
378
+ "details": {
379
+ "path": "%IO_CD_USER_DATA_DIR%/mcp/index.cjs",
380
+ "showConsole": true,
381
+ "passGlueToken": true,
382
+ "logging": true
383
+ },
384
+ "allowLogging": true
385
+ }
386
+ ]
387
+ ```
388
+
389
+ **Server Implementation (index.cjs):**
390
+
391
+ ```javascript
392
+ const IoIntelMCPHttpFactory = require("@interopio/mcp-http");
393
+ const IODesktop = require("@interopio/desktop");
394
+
395
+ const start = async () => {
396
+ const desktop = await IODesktop();
397
+
398
+ await IoIntelMCPHttpFactory(desktop, {
399
+ licenseKey: process.env.IO_LICENSE_KEY,
400
+ server: {
401
+ port: 8989,
402
+ },
403
+ });
404
+ };
405
+
406
+ start();
407
+ ```
408
+
409
+ ---
410
+
411
+ ## Examples
412
+
413
+ ### Basic HTTP Server
414
+
415
+ ```typescript
416
+ import IoIntelMCPHttpFactory from "@interopio/mcp-http";
417
+ import IODesktop from "@interopio/desktop";
418
+
419
+ const desktop = await IODesktop();
420
+
421
+ await IoIntelMCPHttpFactory(desktop, {
422
+ licenseKey: process.env.IO_LICENSE_KEY!,
423
+ });
424
+
425
+ // Server starts on default port 8080
426
+ // Endpoints available at:
427
+ // GET http://localhost:8080/mcp
428
+ // POST http://localhost:8080/mcp
429
+ // DELETE http://localhost:8080/mcp
430
+ ```
431
+
432
+ ### Custom Port and CORS
433
+
434
+ ```typescript
435
+ await IoIntelMCPHttpFactory(desktop, {
436
+ licenseKey: process.env.IO_LICENSE_KEY!,
437
+ server: {
438
+ port: 9000,
439
+ origin: ["https://app.example.com", "https://admin.example.com"],
440
+ exposedHeaders: ["Mcp-Session-Id", "X-Custom-Header"],
441
+ allowedHeaders: [
442
+ "Content-Type",
443
+ "mcp-session-id",
444
+ "mcp-protocol-version",
445
+ "Authorization",
446
+ ],
447
+ },
448
+ });
449
+ ```
450
+
451
+ ### With Session Management
452
+
453
+ ```typescript
454
+ import { randomUUID } from "crypto";
455
+
456
+ const sessionRegistry = new Map();
457
+
458
+ await IoIntelMCPHttpFactory(desktop, {
459
+ licenseKey: process.env.IO_LICENSE_KEY!,
460
+ transportOptions: {
461
+ sessionIdGenerator: () => {
462
+ return `session-${randomUUID()}`;
463
+ },
464
+ onsessioninitialized: async (sessionId) => {
465
+ sessionRegistry.set(sessionId, {
466
+ createdAt: new Date(),
467
+ messageCount: 0,
468
+ });
469
+ console.log(`Session ${sessionId} registered`);
470
+ },
471
+ onsessionclosed: async (sessionId) => {
472
+ const session = sessionRegistry.get(sessionId);
473
+ console.log(
474
+ `Session ${sessionId} closed after ${session.messageCount} messages`,
475
+ );
476
+ sessionRegistry.delete(sessionId);
477
+ },
478
+ },
479
+ });
480
+ ```
481
+
482
+ ### With DNS Rebinding Protection
483
+
484
+ ```typescript
485
+ await IoIntelMCPHttpFactory(desktop, {
486
+ licenseKey: process.env.IO_LICENSE_KEY!,
487
+ server: {
488
+ port: 8080,
489
+ },
490
+ transportOptions: {
491
+ enableDnsRebindingProtection: true,
492
+ allowedHosts: ["localhost:8080", "127.0.0.1:8080", "mcp-server.local:8080"],
493
+ allowedOrigins: ["http://localhost:3000", "https://app.example.com"],
494
+ },
495
+ });
496
+ ```
497
+
498
+ ### Custom Server Configuration
499
+
500
+ ```typescript
501
+ import express from "express";
502
+ import helmet from "helmet";
503
+ import rateLimit from "express-rate-limit";
504
+
505
+ await IoIntelMCPHttpFactory(desktop, {
506
+ licenseKey: process.env.IO_LICENSE_KEY!,
507
+ server: {
508
+ port: 8080,
509
+ configureServer: async (app) => {
510
+ // Add security middleware
511
+ app.use(helmet());
512
+
513
+ // Add rate limiting
514
+ const limiter = rateLimit({
515
+ windowMs: 15 * 60 * 1000,
516
+ max: 100,
517
+ });
518
+ app.use(limiter);
519
+
520
+ // Serve static files
521
+ app.use(express.static("public"));
522
+
523
+ // Custom health check endpoint
524
+ app.get("/health", (req, res) => {
525
+ res.json({ status: "healthy" });
526
+ });
527
+ },
528
+ },
529
+ });
530
+ ```
531
+
532
+ ### Complete io.Connect Desktop Integration
533
+
534
+ ```typescript
535
+ import IoIntelMCPHttpFactory from "@interopio/mcp-http";
536
+ import IODesktop from "@interopio/desktop";
537
+ import IOWorkspaces from "@interopio/workspaces-api";
538
+ import { IoIntelWorkingContextFactory } from "@interopio/intel-working-context";
539
+
540
+ const desktop = await IODesktop({
541
+ logger: "info",
542
+ libraries: [IOWorkspaces],
543
+ });
544
+
545
+ await IoIntelMCPHttpFactory(desktop, {
546
+ licenseKey: process.env.IO_LICENSE_KEY!,
547
+ server: {
548
+ port: 8989,
549
+ origin: "*",
550
+ },
551
+ transportOptions: {
552
+ sessionIdGenerator: () => `mcp-${Date.now()}-${Math.random()}`,
553
+ onsessioninitialized: (sessionId) => {
554
+ console.log(`MCP session ${sessionId} initialized`);
555
+ },
556
+ },
557
+ mcpCoreServer: {
558
+ tools: {
559
+ system: {
560
+ searchApps: { enabled: true },
561
+ searchWorkspaces: { enabled: true },
562
+ startApps: { enabled: true },
563
+ startWorkspaces: { enabled: true },
564
+ },
565
+ static: {
566
+ methods: [
567
+ {
568
+ availability: "constant",
569
+ name: "get-portfolio",
570
+ config: {
571
+ description: "Retrieves client portfolio data",
572
+ inputSchema: {
573
+ type: "object",
574
+ properties: {
575
+ clientId: { type: "string" },
576
+ },
577
+ required: ["clientId"],
578
+ },
579
+ outputSchema: {
580
+ type: "object",
581
+ properties: {
582
+ portfolio: { type: "object" },
583
+ },
584
+ required: ["portfolio"],
585
+ },
586
+ },
587
+ interop: {
588
+ methodName: "portfolio.get",
589
+ responseTimeoutMs: 5000,
590
+ },
591
+ },
592
+ ],
593
+ },
594
+ dynamic: {
595
+ methods: {
596
+ enabled: true,
597
+ guard: (method) => method.name.startsWith("mcp_"),
598
+ },
599
+ },
600
+ },
601
+ },
602
+ mcpWorkingContext: {
603
+ factory: IoIntelWorkingContextFactory,
604
+ config: {
605
+ trackers: {
606
+ fdc3: { enabled: true },
607
+ },
608
+ },
609
+ },
610
+ });
611
+
612
+ console.log("MCP HTTP server started successfully");
613
+ ```