@openai/agents-core
Version:
The OpenAI Agents SDK is a lightweight yet powerful framework for building multi-agent workflows.
201 lines (200 loc) • 7.78 kB
JavaScript
import { BaseMCPServerStdio, BaseMCPServerStreamableHttp, invalidateServerToolsCache, } from "../../mcp.js";
import logger from "../../logger.js";
function failedToImport(error) {
logger.error(`
Failed to load the MCP SDK. Please install the /sdk package.
npm install /sdk
`.trim());
throw error;
}
export class NodeMCPServerStdio extends BaseMCPServerStdio {
session = null;
_cacheDirty = true;
_toolsList = [];
serverInitializeResult = null;
clientSessionTimeoutSeconds;
params;
_name;
transport = null;
constructor(params) {
super(params);
this.clientSessionTimeoutSeconds = params.clientSessionTimeoutSeconds ?? 5;
if ('fullCommand' in params) {
const elements = params.fullCommand.split(' ');
const command = elements.shift();
if (!command) {
throw new Error('Invalid fullCommand: ' + params.fullCommand);
}
this.params = {
...params,
command: command,
args: elements,
encoding: params.encoding || 'utf-8',
encodingErrorHandler: params.encodingErrorHandler || 'strict',
};
}
else {
this.params = params;
}
this._name = params.name || `stdio: ${this.params.command}`;
}
async connect() {
try {
const { StdioClientTransport } = await import('@modelcontextprotocol/sdk/client/stdio.js').catch(failedToImport);
const { Client } = await import('@modelcontextprotocol/sdk/client/index.js').catch(failedToImport);
this.transport = new StdioClientTransport({
command: this.params.command,
args: this.params.args,
env: this.params.env,
cwd: this.params.cwd,
});
this.session = new Client({
name: this._name,
version: '1.0.0', // You may want to make this configurable
});
await this.session.connect(this.transport);
this.serverInitializeResult = {
serverInfo: { name: this._name, version: '1.0.0' },
};
}
catch (e) {
this.logger.error('Error initializing MCP server:', e);
await this.close();
throw e;
}
this.debugLog(() => `Connected to MCP server: ${this._name}`);
}
async invalidateToolsCache() {
await invalidateServerToolsCache(this.name);
this._cacheDirty = true;
}
async listTools() {
const { ListToolsResultSchema } = await import('@modelcontextprotocol/sdk/types.js').catch(failedToImport);
if (!this.session) {
throw new Error('Server not initialized. Make sure you call connect() first.');
}
if (this.cacheToolsList && !this._cacheDirty && this._toolsList) {
return this._toolsList;
}
this._cacheDirty = false;
const response = await this.session.listTools();
this.debugLog(() => `Listed tools: ${JSON.stringify(response)}`);
this._toolsList = ListToolsResultSchema.parse(response).tools;
return this._toolsList;
}
async callTool(toolName, args) {
const { CallToolResultSchema } = await import('@modelcontextprotocol/sdk/types.js').catch(failedToImport);
if (!this.session) {
throw new Error('Server not initialized. Make sure you call connect() first.');
}
const response = await this.session.callTool({
name: toolName,
arguments: args ?? {},
});
const parsed = CallToolResultSchema.parse(response);
const result = parsed.content;
this.debugLog(() => `Called tool ${toolName} (args: ${JSON.stringify(args)}, result: ${JSON.stringify(result)})`);
return result;
}
get name() {
return this._name;
}
async close() {
if (this.transport) {
await this.transport.close();
this.transport = null;
}
if (this.session) {
await this.session.close();
this.session = null;
}
}
}
export class NodeMCPServerStreamableHttp extends BaseMCPServerStreamableHttp {
session = null;
_cacheDirty = true;
_toolsList = [];
serverInitializeResult = null;
clientSessionTimeoutSeconds;
params;
_name;
transport = null;
constructor(params) {
super(params);
this.clientSessionTimeoutSeconds = params.clientSessionTimeoutSeconds ?? 5;
this.params = params;
this._name = params.name || `streamable-http: ${this.params.url}`;
}
async connect() {
try {
const { StreamableHTTPClientTransport } = await import('@modelcontextprotocol/sdk/client/streamableHttp.js').catch(failedToImport);
const { Client } = await import('@modelcontextprotocol/sdk/client/index.js').catch(failedToImport);
this.transport = new StreamableHTTPClientTransport(new URL(this.params.url), {
authProvider: this.params.authProvider,
requestInit: this.params.requestInit,
reconnectionOptions: this.params.reconnectionOptions,
sessionId: this.params.sessionId,
});
this.session = new Client({
name: this._name,
version: '1.0.0', // You may want to make this configurable
});
await this.session.connect(this.transport);
this.serverInitializeResult = {
serverInfo: { name: this._name, version: '1.0.0' },
};
}
catch (e) {
this.logger.error('Error initializing MCP server:', e);
await this.close();
throw e;
}
this.debugLog(() => `Connected to MCP server: ${this._name}`);
}
async invalidateToolsCache() {
await invalidateServerToolsCache(this.name);
this._cacheDirty = true;
}
async listTools() {
const { ListToolsResultSchema } = await import('@modelcontextprotocol/sdk/types.js').catch(failedToImport);
if (!this.session) {
throw new Error('Server not initialized. Make sure you call connect() first.');
}
if (this.cacheToolsList && !this._cacheDirty && this._toolsList) {
return this._toolsList;
}
this._cacheDirty = false;
const response = await this.session.listTools();
this.debugLog(() => `Listed tools: ${JSON.stringify(response)}`);
this._toolsList = ListToolsResultSchema.parse(response).tools;
return this._toolsList;
}
async callTool(toolName, args) {
const { CallToolResultSchema } = await import('@modelcontextprotocol/sdk/types.js').catch(failedToImport);
if (!this.session) {
throw new Error('Server not initialized. Make sure you call connect() first.');
}
const response = await this.session.callTool({
name: toolName,
arguments: args ?? {},
});
const parsed = CallToolResultSchema.parse(response);
const result = parsed.content;
this.debugLog(() => `Called tool ${toolName} (args: ${JSON.stringify(args)}, result: ${JSON.stringify(result)})`);
return result;
}
get name() {
return this._name;
}
async close() {
if (this.transport) {
await this.transport.close();
this.transport = null;
}
if (this.session) {
await this.session.close();
this.session = null;
}
}
}
//# sourceMappingURL=node.js.map