@interopio/mcp-http
v1.2.1
Published
Node.js Express server with TypeScript and Rollup bundling
Downloads
427
Readme
io.Intelligence MCP HTTP
Table of Contents
Introduction
@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.
Important: Unlike @interopio/mcp-web, this package provides server-side functionality only and does not include client-side capabilities. This is by design: @interopio/mcp-http implements the HTTP transport definition from the MCP Standard itself, ensuring compatibility with any standard-compliant MCP HTTP client as described in the Model Context Protocol specification.
Key Features
- Express-based HTTP Server: Built-in HTTP server with automatic middleware configuration
- Session Management: Support for multiple concurrent MCP sessions with unique session IDs
- Server-Sent Events (SSE): Streaming responses for real-time communication
- JSON Response Mode: Optional simple request/response mode without streaming
- Resumability: Event store support for reconnection and message resumption
- DNS Rebinding Protection: Security features to prevent DNS rebinding attacks
- Flexible CORS: Configurable origin, headers, and exposed headers
- Custom Middleware: Hook for adding custom Express middleware
- Multi-Instance Support: Manage multiple MCP instances per session
Target Audience
Developers building HTTP-based MCP servers for io.Connect Desktop or other HTTP clients who need to expose MCP tools and functionality over HTTP.
Installation
npm install @interopio/mcp-httpRequirements
- Node.js 16 or higher
- TypeScript 4.5 or higher
- Valid io.Intelligence license key
- io.Connect Desktop or io.Connect Browser instance
Core Concepts
HTTP Transport
The package uses the HTTP transport implementation from @modelcontextprotocol/sdk, exposing three primary endpoints:
- GET
/mcp: Retrieve messages for an existing session (requiresmcp-session-idheader) - POST
/mcp: Send messages or initialize a new session - DELETE
/mcp: Close a session and clean up resources
All endpoints require a mcp-session-id header except for the initial initialization POST request.
Session Management
Session management is configured and working out of the box with secure defaults. Each MCP client connection is represented by a session with a unique session ID. Sessions are:
- Generated: Automatically using cryptographically secure
randomUUID() - Tracked: Stored internally and mapped to transport instances
- Lifecycle-managed: Created on initialization, closed on DELETE request
- Multi-instance: Each session can manage multiple MCP server instances
The default configuration works without manual setup, though you can customize session behavior for advanced use cases such as logging or tracking.
SSE vs JSON Response Modes
The library supports two response modes:
Server-Sent Events (SSE) - Default
- Streams responses in real-time
- Maintains persistent connection
- Better for long-running operations
- Preferred for most use cases
JSON Response Mode
- Simple request/response pattern
- No persistent connection
- Useful for testing or simple scenarios
- Enabled via
enableJsonResponse: true
DNS Rebinding Protection
Security features to prevent DNS rebinding attacks:
- Host Validation: Whitelist allowed
Hostheader values - Origin Validation: Whitelist allowed
Originheader values - Opt-in Security: Must enable
enableDnsRebindingProtectionand configure allowed hosts/origins
API Reference
IoIntelMCPHttpFactory
IoIntelMCPHttpFactory(
io: IOConnectDesktop.API,
config: IoIntelMCPHttp.Config
): Promise<void>Factory function that initializes an HTTP-based MCP server.
Parameters:
io: Initialized io.Connect Desktop API instanceconfig: Configuration object (see Configuration)
Returns: Promise that resolves when server is started
Throws: Error if configuration is invalid or license key is invalid/expired
Configuration Types
IoIntelMCPHttp.Config
interface Config {
licenseKey: string;
transportOptions?: HTTPTransportOptions;
server?: ServerOptions;
mcpCoreServer?: Omit<IoIntelMCPCore.McpServerConfig, "name" | "title">;
mcpWorkingContext?: IoIntelMCPCore.WorkingContextConfig;
}ServerOptions
interface ServerOptions {
port?: number;
origin?: string | string[];
exposedHeaders?: string[];
allowedHeaders?: string[];
configureServer?: (app: Application) => Promise<void>;
}HTTPTransportOptions
interface HTTPTransportOptions {
sessionIdGenerator?: (() => string) | undefined;
onsessioninitialized?: (sessionId: string) => void | Promise<void>;
onsessionclosed?: (sessionId: string) => void | Promise<void>;
enableJsonResponse?: boolean;
eventStore?: EventStore;
allowedHosts?: string[];
allowedOrigins?: string[];
enableDnsRebindingProtection?: boolean;
}Configuration
License Key
A valid io.Intelligence license key is required:
const config = {
licenseKey: "your-signed-jwt-token-here",
// ...
};Server Options
port
server: {
port: 8080; // Default: 8080
}Port number for the HTTP server (1-65535).
origin
server: {
origin: "*"; // Default: "*"
// or
origin: ["https://example.com", "https://app.example.com"];
}CORS origin configuration. Can be a single string or array of allowed origins.
exposedHeaders
server: {
exposedHeaders: ["Mcp-Session-Id"]; // Default
}HTTP headers exposed to clients via CORS.
allowedHeaders
server: {
allowedHeaders: ["Content-Type", "mcp-session-id", "mcp-protocol-version"]; // Default
}HTTP headers allowed in requests via CORS.
configureServer
server: {
configureServer: async (app) => {
app.use(express.static("public"));
app.use(customMiddleware());
};
}Optional callback to apply custom Express middleware before routes are registered.
Transport Options
sessionIdGenerator
transportOptions: {
sessionIdGenerator: () => {
return customSecureUUID();
};
}Custom function to generate session IDs. Should return globally unique and cryptographically secure strings. Return undefined to disable session management.
onsessioninitialized
transportOptions: {
onsessioninitialized: async (sessionId) => {
console.log(`Session ${sessionId} initialized`);
await registerSession(sessionId);
};
}Callback invoked when a new session is initialized. Useful for tracking or logging.
onsessionclosed
transportOptions: {
onsessionclosed: async (sessionId) => {
console.log(`Session ${sessionId} closed`);
await cleanupSession(sessionId);
};
}Callback invoked when a session is closed via DELETE request. Useful for cleanup.
enableJsonResponse
transportOptions: {
enableJsonResponse: true; // Default: false
}Enable simple JSON response mode instead of SSE streaming.
eventStore
transportOptions: {
eventStore: customEventStore; // Implements EventStore interface
}Optional event store for resumability support, allowing clients to reconnect and resume.
DNS Rebinding Protection
transportOptions: {
enableDnsRebindingProtection: true,
allowedHosts: ["localhost:8080", "127.0.0.1:8080"],
allowedOrigins: ["http://localhost:3000"]
}Enable DNS rebinding protection with whitelisted hosts and origins.
MCP Core Server Configuration
mcpCoreServer: {
tools: {
system: {
searchApps: { enabled: true },
startApps: { enabled: true }
},
static: {
methods: [
// Static method tool definitions
]
},
dynamic: {
methods: { enabled: true }
}
}
}Configure MCP tools as defined in @interopio/mcp-core. See the MCP Core documentation for complete tool configuration options.
Working Context Configuration
mcpWorkingContext: {
factory: IoIntelWorkingContextFactory,
config: {
// Working context configuration
}
}Optional working context integration. See @interopio/working-context documentation for configuration details.
Integration Options
With io.Connect Desktop
The preferred integration method for io.Connect Desktop is defining the HTTP server as a service application:
Application Definition (JSON):
[
{
"name": "intel-mcp-server",
"type": "node",
"details": {
"path": "%IO_CD_USER_DATA_DIR%/mcp/index.cjs",
"showConsole": true,
"passGlueToken": true,
"logging": true
},
"allowLogging": true
}
]Server Implementation (index.cjs):
const IoIntelMCPHttpFactory = require("@interopio/mcp-http");
const IODesktop = require("@interopio/desktop");
const start = async () => {
const desktop = await IODesktop();
await IoIntelMCPHttpFactory(desktop, {
licenseKey: process.env.IO_LICENSE_KEY,
server: {
port: 8989,
},
});
};
start();Examples
Basic HTTP Server
import IoIntelMCPHttpFactory from "@interopio/mcp-http";
import IODesktop from "@interopio/desktop";
const desktop = await IODesktop();
await IoIntelMCPHttpFactory(desktop, {
licenseKey: process.env.IO_LICENSE_KEY!,
});
// Server starts on default port 8080
// Endpoints available at:
// GET http://localhost:8080/mcp
// POST http://localhost:8080/mcp
// DELETE http://localhost:8080/mcpCustom Port and CORS
await IoIntelMCPHttpFactory(desktop, {
licenseKey: process.env.IO_LICENSE_KEY!,
server: {
port: 9000,
origin: ["https://app.example.com", "https://admin.example.com"],
exposedHeaders: ["Mcp-Session-Id", "X-Custom-Header"],
allowedHeaders: [
"Content-Type",
"mcp-session-id",
"mcp-protocol-version",
"Authorization",
],
},
});With DNS Rebinding Protection
await IoIntelMCPHttpFactory(desktop, {
licenseKey: process.env.IO_LICENSE_KEY!,
server: {
port: 8080,
},
transportOptions: {
enableDnsRebindingProtection: true,
allowedHosts: ["localhost:8080", "127.0.0.1:8080", "mcp-server.local:8080"],
allowedOrigins: ["http://localhost:3000", "https://app.example.com"],
},
});Custom Server Configuration
import express from "express";
import helmet from "helmet";
import rateLimit from "express-rate-limit";
await IoIntelMCPHttpFactory(desktop, {
licenseKey: process.env.IO_LICENSE_KEY!,
server: {
port: 8080,
configureServer: async (app) => {
// Add security middleware
app.use(helmet());
// Add rate limiting
const limiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 100,
});
app.use(limiter);
// Serve static files
app.use(express.static("public"));
// Custom health check endpoint
app.get("/health", (req, res) => {
res.json({ status: "healthy" });
});
},
},
});Complete io.Connect Desktop Integration
import IoIntelMCPHttpFactory from "@interopio/mcp-http";
import IODesktop from "@interopio/desktop";
import IOWorkspaces from "@interopio/workspaces-api";
import { IoIntelWorkingContextFactory } from "@interopio/working-context";
const desktop = await IODesktop({
logger: "info",
libraries: [IOWorkspaces],
});
await IoIntelMCPHttpFactory(desktop, {
licenseKey: process.env.IO_LICENSE_KEY!,
server: {
port: 8989,
origin: "*",
},
transportOptions: {
sessionIdGenerator: () => `mcp-${Date.now()}-${Math.random()}`,
onsessioninitialized: (sessionId) => {
console.log(`MCP session ${sessionId} initialized`);
},
},
mcpCoreServer: {
tools: {
system: {
searchApps: { enabled: true },
searchWorkspaces: { enabled: true },
startApps: { enabled: true },
startWorkspaces: { enabled: true },
},
static: {
methods: [
{
availability: "constant",
name: "get-portfolio",
config: {
description: "Retrieves client portfolio data",
inputSchema: {
type: "object",
properties: {
clientId: { type: "string" },
},
required: ["clientId"],
},
outputSchema: {
type: "object",
properties: {
portfolio: { type: "object" },
},
required: ["portfolio"],
},
},
interop: {
methodName: "portfolio.get",
responseTimeoutMs: 5000,
},
},
],
},
dynamic: {
methods: {
enabled: true,
guard: (method) => method.name.startsWith("mcp_"),
},
},
},
},
mcpWorkingContext: {
factory: IoIntelWorkingContextFactory,
config: {
trackers: {
fdc3: { enabled: true },
},
},
},
});
console.log("MCP HTTP server started successfully");