# io.Intelligence MCP HTTP

## Table of Contents

- [Introduction](#introduction)
- [Installation](#installation)
- [Core Concepts](#core-concepts)
  - [HTTP Transport](#http-transport)
  - [Session Management](#session-management)
  - [SSE vs JSON Response Modes](#sse-vs-json-response-modes)
  - [DNS Rebinding Protection](#dns-rebinding-protection)
- [API Reference](#api-reference)
  - [IoIntelMCPHttpFactory](#iointelmcphttpfactory)
  - [Configuration Types](#configuration-types)
- [Configuration](#configuration)
  - [License Key](#license-key)
  - [Server Options](#server-options)
  - [Transport Options](#transport-options)
  - [MCP Core Server Configuration](#mcp-core-server-configuration)
  - [Working Context Configuration](#working-context-configuration)
- [Integration Options](#integration-options)
  - [With io.Connect Desktop](#with-ioconnect-desktop)
  - [Standalone HTTP Server](#standalone-http-server)
- [Examples](#examples)
  - [Basic HTTP Server](#basic-http-server)
  - [Custom Port and CORS](#custom-port-and-cors)
  - [With DNS Rebinding Protection](#with-dns-rebinding-protection)
  - [Custom Server Configuration](#custom-server-configuration)
  - [Complete io.Connect Desktop Integration](#complete-ioconnect-desktop-integration)

---

## 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

```bash
npm install @interopio/mcp-http
```

### Requirements

- 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 (requires `mcp-session-id` header)
- **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 `Host` header values
- **Origin Validation**: Whitelist allowed `Origin` header values
- **Opt-in Security**: Must enable `enableDnsRebindingProtection` and configure allowed hosts/origins

---

## API Reference

### IoIntelMCPHttpFactory

```typescript
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 instance
- `config`: Configuration object (see [Configuration](#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

```typescript
interface Config {
  licenseKey: string;
  transportOptions?: HTTPTransportOptions;
  server?: ServerOptions;
  mcpCoreServer?: Omit<IoIntelMCPCore.McpServerConfig, "name" | "title">;
  mcpWorkingContext?: IoIntelMCPCore.WorkingContextConfig;
}
```

#### ServerOptions

```typescript
interface ServerOptions {
  port?: number;
  origin?: string | string[];
  exposedHeaders?: string[];
  allowedHeaders?: string[];
  configureServer?: (app: Application) => Promise<void>;
}
```

#### HTTPTransportOptions

```typescript
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**:

```typescript
const config = {
  licenseKey: "your-signed-jwt-token-here",
  // ...
};
```

### Server Options

#### port

```typescript
server: {
  port: 8080; // Default: 8080
}
```

Port number for the HTTP server (1-65535).

#### origin

```typescript
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

```typescript
server: {
  exposedHeaders: ["Mcp-Session-Id"]; // Default
}
```

HTTP headers exposed to clients via CORS.

#### allowedHeaders

```typescript
server: {
  allowedHeaders: ["Content-Type", "mcp-session-id", "mcp-protocol-version"]; // Default
}
```

HTTP headers allowed in requests via CORS.

#### configureServer

```typescript
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

```typescript
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

```typescript
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

```typescript
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

```typescript
transportOptions: {
  enableJsonResponse: true; // Default: false
}
```

Enable simple JSON response mode instead of SSE streaming.

#### eventStore

```typescript
transportOptions: {
  eventStore: customEventStore; // Implements EventStore interface
}
```

Optional event store for resumability support, allowing clients to reconnect and resume.

#### DNS Rebinding Protection

```typescript
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

```typescript
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](./mcp-core.md) for complete tool configuration options.

### Working Context Configuration

```typescript
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):**

```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):**

```javascript
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

```typescript
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/mcp
```

### Custom Port and CORS

```typescript
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

```typescript
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

```typescript
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

```typescript
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");
```
