Skip to main content
Version: 3.1

Integrating MCP-Server

The Model Context Protocol (MCP) is an open standard that lets LLMs discover and call tools exposed by external servers. Operaide ships a built-in MCP connection type, so you can wire any MCP server into your Reaktor without writing transport code yourself.


Overview

An MCP server publishes a set of tools — functions with names, descriptions, and JSON-Schema parameters. At runtime, your Reaktor connects to the server, fetches the tool catalog, and hands it to the LLM. The LLM then decides which tools to call based on the user's request.

TransportWhen to Use
SSEDefault choice. Works with most hosted MCP servers (Context7, Atlassian, etc.)
HTTPStreamable HTTP transport for servers that support it
note

The stdio transport is defined in the config schema but is not supported in the Operaide server environment. Use SSE or HTTP instead.

Administrators create MCP connections in the platform UI — see Connection Management for details.


Setting Up the MCP Connection

The @operaide/ai package already registers an MCP connection type. You do not need to call registerConnectionType yourself. Once the package is loaded, the connection type appears in the admin UI under Connections > + Add Connection > MCP Server.

Configuration Fields

FieldRequiredDescription
transportYes'sse' or 'http'
urlYesMCP server endpoint URL
apiKeyNoBearer token for authentication
headersNoAdditional HTTP headers (key-value pairs)

Example: Context7

Context7 is an MCP server that provides up-to-date library documentation. To connect:

  1. In the admin UI, create a new MCP Server connection.
  2. Set the transport to SSE.
  3. Enter the URL: https://mcp.context7.com/sse
  4. Optionally add an API key for higher rate limits (available at context7.com/dashboard).

Fetching Tools from an MCP Server

Create an AktorFunction that connects to the MCP server and returns its tools as a ToolSet. The pattern: accept a connection name, retrieve the typed config, build the transport, and call the MCP client.

import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
import { mcpConnectionType, type MCPConfig } from '@operaide/ai';
import { createAktorFunction } from '@operaide/aktor';
import { experimental_createMCPClient as createMCPClient, type ToolSet } from 'ai';

export const aktorGetMCPTools = createAktorFunction('aktorGetMCPTools', getMCPTools);

async function getMCPTools(input: { connectionName: string }): Promise<ToolSet> {
const config: MCPConfig = await mcpConnectionType.getConnection(input.connectionName);

if (!config.url) {
throw new Error('MCP requires a URL');
}

const headers: Record<string, string> = { ...config.headers };
if (config.apiKey) {
headers.Authorization = `Bearer ${config.apiKey}`;
}

let transport;
if (config.transport === 'http') {
transport = new StreamableHTTPClientTransport(new URL(config.url), {
requestInit: { headers },
});
} else if (config.transport === 'sse') {
transport = {
type: 'sse' as const,
url: config.url,
...(Object.keys(headers).length > 0 && { headers }),
};
} else {
throw new Error(`Unsupported transport type: ${config.transport}`);
}

const mcpClient = await createMCPClient({
transport,
name: 'operaide-mcp-client',
});

return mcpClient.tools();
}

The returned ToolSet can be passed directly to aktorAICall — the LLM will see each MCP tool as a callable function.


Using MCP Tools in a Chat Reaktor

App Settings

Register an app setting so operators can choose which MCP connection the app uses:

import { z } from 'zod';
import { registerAppSettings } from '@operaide/aktor';

registerAppSettings(
z.object({
mcpConnectionName: z
.string()
.min(1)
.default('context7')
.describe('MCP connection name to use for tool discovery'),
})
);

Chat Reaktor

Wire the MCP tools into a chat Reaktor. The LLM receives the tools and can call them as part of the conversation:

import type { LlmOptions } from '@operaide/ai';
import {
aktorAICall,
aktorAISettingProviderModel,
aktorPatchMessages,
registerChatReaktorDefinition,
} from '@operaide/ai';
import { aktorConst, aktorSetting, appSetting, createAktorComposition } from '@operaide/aktor';
import { z } from 'zod';
import { aktorGetMCPTools } from './aktors/mcp.tools';

const aktorMcpChatDemo = createAktorComposition('aktorMcpChatDemo', ({ messages }) => {
const mcpConnectionName = appSetting<string>('mcpConnectionName');

const systemPrompt = aktorSetting(
z.string().describe('[textarea]System Prompt'),
'You are an AI assistant with access to an MCP server. Tell the user what you can do according to your tools.',
'System Message'
);

const mcpTools = aktorGetMCPTools({
connectionName: mcpConnectionName,
});

return aktorAICall({
messages: aktorPatchMessages({
messages,
system: systemPrompt,
}),
providerModel: aktorAISettingProviderModel(),
tools: mcpTools,
llmOptions: aktorConst<LlmOptions>({
max_steps: 10,
}),
});
});

registerChatReaktorDefinition({
reaktorDefinitionId: 'mcp-chat-demo',
label: 'Chat with MCP server',
description: 'Chat Reaktor with access to tools from an MCP server.',
aktor: aktorMcpChatDemo,
});

When a user opens this chat, the Reaktor connects to the configured MCP server, fetches its tools, and lets the LLM use them during the conversation.

tip

Wrap the system prompt in aktorSetting so operators can tailor the assistant's behavior per deployment — no code change required.


Best Practices

  1. Use appSetting for the connection name so operators can switch MCP servers without redeploying code.

  2. Set max_steps on aktorAICall to limit how many tool-call rounds the LLM performs. Without a cap, a chatty tool loop can burn tokens.

  3. Tools are discovered at runtime. You do not hard-code tool definitions — the LLM learns what the MCP server offers each time it connects. This means you can update or replace the MCP server independently of your Reaktor code.

  4. Prefer SSE transport for hosted MCP servers. It is the most widely supported transport in the MCP ecosystem.