@interopio/mcp-core
v1.2.1
Published
io.Intelligence MCP Core Library
Downloads
597
Readme
io.Intelligence MCP Core
Table of Contents
Introduction
@interopio/mcp-core is a TypeScript library that provides foundational functionality for building Model Context Protocol (MCP) servers within the io.Intelligence ecosystem. It enables seamless interoperability between applications and Large Language Models (LLMs) by providing interfaces and functions to create, register, and manage MCP tools.
Key Features
- MCP Server Creation: Initialize and manage MCP server instances compliant with the MCP specification
- System Tools: Pre-built tools for searching and starting applications and workspaces
- Static Tools: Define tools in configuration that are automatically managed
- Dynamic Tools: Register and unregister tools at runtime based on application state
- Working Context Integration: Optional integration with
@interopio/working-contextfor enhanced context management - Client Capability Detection: Automatically adjusts available tools based on client capabilities
- Multi-Transport Support: Works with STDIO, HTTP, and web-based transports
Target Audience
Developers building MCP servers for io.Connect Desktop or io.Connect Browser platforms who need to expose application functionality to LLMs.
Installation
npm install @interopio/mcp-coreRequirements
- 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
MCP Server
An MCP server acts as a bridge between LLMs and io.Connect applications. The core library creates standard McpServer instances that can be connected to any MCP-compliant transport. Each server instance exposes tools that LLMs can invoke to interact with applications.
Tools
Tools are functions that LLMs can call to perform actions. The library supports three types:
- System Tools: Built-in tools for searching/starting applications and workspaces
- Static Tools: Defined in configuration, automatically registered/unregistered based on interop availability
- Dynamic Tools: Registered at runtime using
io.interop.registerwith MCP-specific flags
Client Capabilities
MCP clients declare capabilities such as sampling (for search operations) and elicitation (for user confirmations). The library adjusts available tools based on these capabilities:
- Search tools require
samplingcapability - Start tools require
elicitationcapability - Working context tools are available unless client declares
experimental.workingContext
Working Context Integration
Optional integration with @interopio/working-context enables the io_connect_get_working_context tool, allowing LLMs to retrieve the user's current business context (selected clients, portfolios, instruments, etc.).
API Reference
IoIntelMCPCoreFactory
IoIntelMCPCoreFactory(
io: IOConnectBrowser.API | IOConnectDesktop.API,
config: IoIntelMCPCore.Config
): Promise<IoIntelMCPCore.API>Factory function that initializes the MCP Core and returns an API for managing MCP instances.
Parameters:
io: Initialized io.Connect API instance (Browser or Desktop)config: Configuration object (see Configuration)
Returns: Promise resolving to the MCP Core API
Throws: Error if license key is invalid or expired (for trial licenses)
API Methods
createMCPInstance
createMCPInstance(
clientCapabilities: IoIntelMCPCore.ClientCapabilities
): IoIntelMCPCore.MCPCoreCreates a new MCP server instance configured with tools appropriate for the client's capabilities.
Parameters:
clientCapabilities: Object declaring what the client supports
Returns: Object with id (string) and instance (McpServer)
removeMCPInstance
removeMCPInstance(id: string): voidRemoves an MCP instance and cleans up associated resources.
Parameters:
id: Unique identifier of the instance to remove
Configuration Types
IoIntelMCPCore.Config
interface Config {
licenseKey: string;
transport: McpTransportConfig;
server: McpServerConfig;
context?: WorkingContextConfig;
}McpTransportConfig
interface McpTransportConfig {
type: "stdio" | "http" | "web";
}McpServerConfig
interface McpServerConfig {
name: string;
title?: string;
tools?: {
dynamic?: DynamicToolsConfig;
static?: StaticToolsConfig;
system?: SystemToolConfig;
};
}ClientCapabilities
interface ClientCapabilities {
sampling?: object;
elicitation?: object;
experimental?: {
workingContext?: boolean;
};
[key: string]: unknown;
}Configuration
License Key
A valid io.Intelligence license key is required to use this package. The license is a signed JWT token provided by the io.Intelligence team.
const config = {
licenseKey: "your-signed-jwt-token-here",
// ...
};License Types:
- Trial: Must not be expired or initialization will fail
- Paid: Will log warning if expired but continue operation
Transport Configuration
Specifies the transport type for logging adjustment:
transport: {
type: "stdio"; // Options: "stdio", "http", "web"
}Important: STDIO transport disables console logging to avoid interfering with MCP protocol messages.
Server Configuration
Basic Configuration
server: {
name: "my-mcp-server",
title: "My MCP Server"
}Tools Configuration
server: {
name: "my-server",
tools: {
system: {
searchApps: { enabled: true },
searchWorkspaces: { enabled: true },
startApps: { enabled: true },
startWorkspaces: { enabled: true }
},
static: {
methods: [],
intents: []
},
dynamic: {
methods: { enabled: true }
}
}
}Working Context Configuration
context: {
factory: IoIntelWorkingContextFactory,
config: {
// Working context configuration
}
}When provided, automatically registers the io_connect_get_working_context tool.
Application and Workspace Definition Requirements
For the system searching tools (io_connect_search_applications and io_connect_search_workspaces) to work effectively, application and workspace definitions in io.Connect must contain specific properties that enable the LLM to understand and explain their purpose.
Application Definition Requirements
Required Properties:
caption: A clear, descriptive explanation of what the application does. Without this property, the searching system tools cannot explain the application's functionality to the LLM, and the application will be filtered out from search results.
Optional Properties:
customProperties.interop: Provides detailed information about the application's interoperability features. This property follows theApplicationInteropInfointerface and can include:methods: Array of interop methods the application exposescontext: Context data requirements and sourcesintents: Intents the application can handle
Example Application Definition:
{
"name": "proposal",
"type": "window",
"caption": "Manages and displays client proposals with detailed financial information",
"details": {
"url": "http://localhost:4100?intent=my_custom_intent"
},
"customProperties": {
"includeInWorkspaces": true,
"interop": {
"methods": [
{
"name": "get-proposal-data",
"description": "Get proposal data from the proposal app",
"inputSchema": {
"type": "object",
"properties": {
"proposalId": {
"type": "string",
"description": "The ID of the proposal to retrieve"
}
},
"required": ["proposalId"]
},
"outputSchema": {
"type": "object",
"properties": {
"proposalId": {
"type": "string",
"description": "The ID of the proposal"
},
"clientName": {
"type": "string",
"description": "The name of the client"
},
"amount": {
"type": "number",
"description": "The amount of the proposal"
},
"status": {
"type": "string",
"description": "The status of the proposal"
}
},
"required": ["proposalId", "clientName", "amount", "status"]
}
}
],
"context": {
"sources": [
"initial-instance",
"global",
"channel",
"window",
"workspace"
],
"description": "The app uses the context data to identify the proposal to display.",
"schema": {
"type": "object",
"properties": {
"proposalId": {
"type": "string",
"description": "The ID of the proposal"
},
"clientName": {
"type": "string",
"description": "The name of the client"
}
},
"required": ["proposalId", "clientName"]
}
},
"intents": [
{
"name": "my_custom_intent",
"description": "Handles requests to view proposal details.",
"contextTypes": ["fdc3.proposal"],
"inputSchema": {
"type": "object",
"properties": {
"proposalId": {
"type": "string",
"description": "The ID of the proposal"
},
"clientName": {
"type": "string",
"description": "The name of the client"
}
},
"required": ["proposalId", "clientName"]
},
"outputSchema": {
"type": "object",
"properties": {
"status": {
"type": "string",
"description": "The status of the intent handling"
}
},
"required": ["status"]
},
"resultType": "fdc3.intentResult",
"customConfig": {},
"displayName": "View Proposal Details"
}
]
}
},
"intents": [
{
"name": "my_custom_intent"
}
]
}Workspace Definition Requirements
Required Properties:
metadata.description: A clear explanation of what the workspace layout contains and its purpose. Without this property, the searching system tools cannot explain the workspace's functionality to the LLM, and the workspace will be excluded from search results.
Optional Properties:
metadata.contextSchema: Defines the shape of the context object that the workspace uses. This JSON Schema describes the expected structure and properties of the workspace's context data.
Example Workspace Definition:
{
"name": "All Demos",
"type": "Workspace",
"metadata": {
"description": "A workspace layout containing all demo applications for comprehensive product demonstration.",
"contextSchema": {
"type": "object",
"properties": {
"clientId": {
"type": "string",
"description": "The client identifier to load across all applications"
},
"portfolioId": {
"type": "string",
"description": "The portfolio identifier to display"
}
},
"required": ["clientId"]
}
},
"components": []
}Impact on System Tools
Applications and workspaces that don't meet the required property specifications will be automatically filtered out during the search process:
- Applications without
description: Cannot be analyzed by the LLM and will not appear in search results - Applications with only global/channel context sources: Filtered out as they lack specific interop capabilities
- Workspaces without
metadata.description: Cannot be explained to the LLM and will be excluded from workspace searches
Providing optional properties like customProperties.interop for applications and metadata.contextSchema for workspaces enhances the LLM's ability to make informed decisions about which applications or workspaces best satisfy user intent.
Integration Options
Standalone Usage
Use directly with any MCP transport:
import { IoIntelMCPCoreFactory } from "@interopio/mcp-core";
import IOConnectBrowser from "@interopio/browser";
const io = await IOConnectBrowser();
const mcpApi = await IoIntelMCPCoreFactory(io, {
licenseKey: "your-license-key",
transport: { type: "web" },
server: { name: "my-server" },
});
const { instance } = mcpApi.createMCPInstance({
sampling: {},
elicitation: {},
});
// Connect instance to your transportWith @interopio/mcp-stdio
Provides standard input/output transport for console-based communication:
import { IoIntelMCPStdioFactory } from "@interopio/mcp-stdio";
const server = await IoIntelMCPStdioFactory(io, {
licenseKey: "your-license-key",
server: { name: "my-server" },
});With @interopio/mcp-http
Provides HTTP transport, preferred for io.Connect Desktop integration:
import { IoIntelMCPHttpFactory } from "@interopio/mcp-http";
const server = await IoIntelMCPHttpFactory(io, {
licenseKey: "your-license-key",
server: { name: "my-server" },
http: {
port: 3000,
},
});With @interopio/mcp-web
Provides web-based transport built on io.Connect Browser, preferred when frontend must be its own server:
import { IoIntelMCPWebFactory } from "@interopio/mcp-web";
const server = await IoIntelMCPWebFactory(io, {
licenseKey: "your-license-key",
server: { name: "my-server" },
});Tools
System Tools
Five built-in system tools are available:
io_connect_search_applications
Discovers applications that can satisfy user intent and returns their interaction schemas.
Input:
{
userIntent: string; // Description of what user wants to accomplish
}Output:
{
canSatisfyUserIntent: boolean,
summary: string,
nextSteps: string,
willSatisfyUserIntentBy: {
workspace?: { apps: ApplicationInfo[] },
apps?: ApplicationInfo[]
}
}Requires: Client sampling capability
Configuration:
system: {
searchApps: {
enabled: true,
overrides: {
name: "custom_search_apps",
description: "Custom description"
},
guard: (app) => app.name !== "internal-app"
}
}io_connect_search_workspaces
Discovers saved workspaces that satisfy user intent.
Input:
{
userIntent: string;
}Output:
{
canSatisfyUserIntent: boolean,
summary: string,
nextSteps: string,
willSatisfyUserIntentBy: {
workspace?: {
name: string,
description: string,
contextSchema: object
}
}
}Requires: Client sampling capability, io.Connect Workspaces API available
Configuration:
system: {
searchWorkspaces: {
enabled: true,
overrides: {
name: "custom_search_workspaces"
},
guard: (ws) => !ws.name.startsWith("_internal")
}
}io_connect_start_applications
Launches applications with populated context data.
Input:
{
apps: Array<{
name: string;
initialInstanceContext?: object;
startOptions?: {
channelName?: string;
height?: number;
width?: number;
top?: number;
left?: number;
};
interop?: {
method?: { name: string; params?: object };
windowContext?: object;
intent?: {
name: string;
intentContextType?: string;
intentContextData?: object;
};
};
}>;
}Output:
{
apps: Array<{
name: string;
status: "success" | "error";
responseData?: any;
errorMessage?: string;
}>;
}Requires: Client elicitation capability
Configuration:
system: {
startApps: {
enabled: true,
overrides: {
description: "Custom start description"
}
}
}io_connect_start_workspace
Creates new workspace or restores existing workspace with context.
Input:
{
workspace:
| { name: string, context?: object } // Restore
| { apps: Array<...>, workspaceContext?: object } // Create
}Output:
{
result: {
id: string,
status: "success" | "error",
errorMessage?: string,
methodInvocationResults?: Array<{
app: string,
invocationResult: any
}>
}
}Requires: Client elicitation capability, io.Connect Workspaces API available
io_connect_get_working_context
Retrieves current working context from io.Connect.
Input: None
Output:
{
workingContext: Record<
string,
{
description?: string;
value: any;
}
>;
}Requires: Working context configured, client does not declare experimental.workingContext
Static Tools
Static tools are defined in configuration and automatically managed by MCP Core.
Static Method Tools
static: {
methods: [
{
availability: "constant", // or "variable"
name: "my-tool-hello",
config: {
description: "Greets a person",
inputSchema: {
type: "object",
properties: {
name: { type: "string", description: "Person's name" },
},
required: ["name"],
},
outputSchema: {
type: "object",
properties: {
greeting: { type: "string" },
},
required: ["greeting"],
},
},
interop: {
methodName: "my_custom_method",
responseTimeoutMs: 5000,
allowedApplications: ["app1", "app2"],
},
},
];
}Availability:
constant: Registered at startup, never changesvariable: Registered/unregistered automatically based on interop availability
Interop Application:
await io.interop.register(
{
name: "my_custom_method",
},
(args) => {
return { greeting: `Hello, ${args.name}` };
},
);Static Intent Tools
static: {
intents: [
{
availability: "variable",
name: "my-intent-tool",
config: {
description: "Handles custom intent",
inputSchema: {
type: "object",
properties: {
type: { type: "string" },
data: { type: "object" },
},
required: ["type"],
},
outputSchema: {
/* ... */
},
},
interop: {
intentName: "my_custom_intent",
resolutionStrategy: "mcp", // or "io_connect"
allowedApplications: ["handler-app"],
},
},
];
}Resolution Strategies:
mcp: Prefers app handlers over instance handlersio_connect: Uses io.Connect's default resolution
Interop Application:
await io.intents.register({ intent: "my_custom_intent" }, (ctx) => {
return { result: `Processed ${ctx.data.type}` };
});Dynamic Tools
Dynamic tools are registered at runtime and managed entirely by the application.
Registration
await io.interop.register(
{
name: "awesome-method",
description: "An awesome MCP tool", // Required
flags: {
ioIntelMCPTool: {
name: "io_jpm_greeting_tool",
inputSchema: JSON.stringify({
$schema: "https://json-schema.org/draft-07/schema",
type: "object",
properties: {
name: { type: "string", description: "Person's name" },
},
required: ["name"],
}),
outputSchema: JSON.stringify({
type: "object",
properties: {
greeting: { type: "string" },
},
required: ["greeting"],
}),
},
},
},
(args) => {
return { greeting: `Hello, ${args.name}` };
},
);Configuration Options
interface InteropMethodToolConfig {
name: string;
inputSchema: string; // JSON Schema as string
outputSchema: string; // JSON Schema as string
title?: string;
annotations?: {
title?: string;
readOnlyHint?: boolean;
destructiveHint?: boolean;
idempotentHint?: boolean;
openWorldHint?: boolean;
};
_meta?: Record<string, unknown>;
responseTimeoutMs?: number;
}Guard Function
Filter which methods become MCP tools:
dynamic: {
methods: {
enabled: true,
guard: (method, server) => {
return method.name.startsWith("mcp_") &&
server.applicationName === "allowed-app";
}
}
}Examples
Basic Server Setup
import { IoIntelMCPCoreFactory } from "@interopio/mcp-core";
import IOConnectBrowser from "@interopio/browser";
const io = await IOConnectBrowser();
const mcpApi = await IoIntelMCPCoreFactory(io, {
licenseKey: process.env.IO_LICENSE_KEY!,
transport: { type: "web" },
server: {
name: "basic-server",
title: "Basic MCP Server",
},
});
const { instance } = mcpApi.createMCPInstance({
sampling: {},
elicitation: {},
});
console.log("MCP server ready");With Working Context
import { IoIntelMCPCoreFactory } from "@interopio/mcp-core";
import { IoIntelWorkingContextFactory } from "@interopio/working-context";
import IOConnectBrowser from "@interopio/browser";
const io = await IOConnectBrowser();
const mcpApi = await IoIntelMCPCoreFactory(io, {
licenseKey: process.env.IO_LICENSE_KEY!,
transport: { type: "web" },
server: { name: "context-server" },
context: {
factory: IoIntelWorkingContextFactory,
config: {
trackers: {
fdc3: { enabled: true },
},
},
},
});
const { instance } = mcpApi.createMCPInstance({
sampling: {},
elicitation: {},
});
// io_connect_get_working_context tool is now availableCustom Static Tools
const mcpApi = await IoIntelMCPCoreFactory(io, {
licenseKey: process.env.IO_LICENSE_KEY!,
transport: { type: "http" },
server: {
name: "static-tools-server",
tools: {
static: {
methods: [
{
availability: "constant",
name: "get-client-portfolio",
config: {
description: "Retrieves portfolio for a client",
inputSchema: {
type: "object",
properties: {
clientId: {
type: "string",
description: "Client identifier",
},
},
required: ["clientId"],
},
outputSchema: {
type: "object",
properties: {
portfolio: {
type: "object",
description: "Client portfolio data",
},
},
required: ["portfolio"],
},
},
interop: {
methodName: "portfolio.get",
responseTimeoutMs: 3000,
allowedApplications: ["portfolio-service"],
},
},
],
},
},
},
});
// Register the backend method
await io.interop.register(
{
name: "portfolio.get",
},
async ({ clientId }) => {
const portfolio = await fetchPortfolio(clientId);
return { portfolio };
},
);Dynamic Tool Registration
const mcpApi = await IoIntelMCPCoreFactory(io, {
licenseKey: process.env.IO_LICENSE_KEY!,
transport: { type: "stdio" },
server: {
name: "dynamic-tools-server",
tools: {
dynamic: {
methods: {
enabled: true,
guard: (method) => method.name.startsWith("ai_"),
},
},
},
},
});
// Register dynamic tool
await io.interop.register(
{
name: "ai_calculate_risk",
description: "Calculates risk score for a portfolio",
flags: {
ioIntelMCPTool: {
name: "calculate_risk",
inputSchema: JSON.stringify({
type: "object",
properties: {
portfolioId: { type: "string" },
},
required: ["portfolioId"],
}),
outputSchema: JSON.stringify({
type: "object",
properties: {
riskScore: { type: "number" },
},
required: ["riskScore"],
}),
},
},
},
async ({ portfolioId }) => {
const riskScore = await calculateRisk(portfolioId);
return { riskScore };
},
);
// Tool is automatically available to MCP clients