UNPKG

@openai/agents-core

Version:

The OpenAI Agents SDK is a lightweight yet powerful framework for building multi-agent workflows.

866 lines • 35.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.defaultMCPToolCacheKey = exports.MCPServerSSE = exports.MCPServerStreamableHttp = exports.MCPServerStdio = exports.invalidateServerToolsCache = exports.attachCallToolResultMetadata = exports.MCPTool = exports.DEFAULT_STREAMABLE_HTTP_MCP_CLIENT_LOGGER_NAME = exports.DEFAULT_STDIO_MCP_CLIENT_LOGGER_NAME = exports.DEFAULT_SSE_MCP_CLIENT_LOGGER_NAME = exports.BaseMCPServerStreamableHttp = exports.BaseMCPServerStdio = exports.BaseMCPServerSSE = void 0; exports.getAllMcpTools = getAllMcpTools; exports.mcpToFunctionTool = mcpToFunctionTool; const tool_1 = require("./tool.js"); const errors_1 = require("./errors.js"); const toolIdentity_1 = require("./toolIdentity.js"); const _shims_1 = require("@openai/agents-core/_shims"); const tracing_1 = require("./tracing/index.js"); const logger_1 = require("./logger.js"); const mcpLogging_1 = require("./mcpLogging.js"); const customData_1 = require("./utils/customData.js"); const mcpShared_1 = require("./mcpShared.js"); const mcpToolCache_1 = require("./mcpToolCache.js"); const agentToolRunConfig_1 = require("./agentToolRunConfig.js"); const strictToolSchema_1 = require("./utils/strictToolSchema.js"); const tools_1 = require("./utils/tools.js"); var mcpShared_2 = require("./mcpShared.js"); Object.defineProperty(exports, "BaseMCPServerSSE", { enumerable: true, get: function () { return mcpShared_2.BaseMCPServerSSE; } }); Object.defineProperty(exports, "BaseMCPServerStdio", { enumerable: true, get: function () { return mcpShared_2.BaseMCPServerStdio; } }); Object.defineProperty(exports, "BaseMCPServerStreamableHttp", { enumerable: true, get: function () { return mcpShared_2.BaseMCPServerStreamableHttp; } }); Object.defineProperty(exports, "DEFAULT_SSE_MCP_CLIENT_LOGGER_NAME", { enumerable: true, get: function () { return mcpShared_2.DEFAULT_SSE_MCP_CLIENT_LOGGER_NAME; } }); Object.defineProperty(exports, "DEFAULT_STDIO_MCP_CLIENT_LOGGER_NAME", { enumerable: true, get: function () { return mcpShared_2.DEFAULT_STDIO_MCP_CLIENT_LOGGER_NAME; } }); Object.defineProperty(exports, "DEFAULT_STREAMABLE_HTTP_MCP_CLIENT_LOGGER_NAME", { enumerable: true, get: function () { return mcpShared_2.DEFAULT_STREAMABLE_HTTP_MCP_CLIENT_LOGGER_NAME; } }); Object.defineProperty(exports, "MCPTool", { enumerable: true, get: function () { return mcpShared_2.MCPTool; } }); Object.defineProperty(exports, "attachCallToolResultMetadata", { enumerable: true, get: function () { return mcpShared_2.attachCallToolResultMetadata; } }); var mcpToolCache_2 = require("./mcpToolCache.js"); Object.defineProperty(exports, "invalidateServerToolsCache", { enumerable: true, get: function () { return mcpToolCache_2.invalidateServerToolsCache; } }); const MCP_FUNCTION_TOOL_NAME_MAX_LENGTH = 64; const MCP_FUNCTION_TOOL_HASH_LENGTH = 8; function snapshotMcpTools(tools) { return structuredClone(tools); } class MCPToolsLifecycleGuard { generation = 0; activeOperations = 0; startLifecycleBranch(operation) { try { return operation?.() ?? Promise.resolve(); } catch (error) { return Promise.reject(error); } } beginLifecycleOperation() { this.activeOperations += 1; this.generation += 1; } endLifecycleOperation() { this.activeOperations -= 1; } async runLifecycleOperation(invalidate, operation) { this.beginLifecycleOperation(); try { const [invalidationResult, operationResult] = await Promise.allSettled([ this.startLifecycleBranch(invalidate), this.startLifecycleBranch(operation), ]); if (invalidationResult.status === 'rejected') { throw invalidationResult.reason; } if (operationResult.status === 'rejected') { throw operationResult.reason; } } finally { this.endLifecycleOperation(); } } invalidate() { this.generation += 1; } beginListing() { if (this.activeOperations > 0) { throw new Error('Cannot list MCP tools while a server lifecycle operation is in progress.'); } return this.generation; } assertListingIsCurrent(listingGeneration) { if (this.activeOperations > 0 || listingGeneration !== this.generation) { throw new Error('MCP tool listing became stale before it completed.'); } } } /** * Public interface of an MCP server that provides tools. * You can use this class to pass MCP server settings to your agent. */ class MCPServerStdio extends mcpShared_1.BaseMCPServerStdio { underlying; toolsLifecycle = new MCPToolsLifecycleGuard(); constructor(options) { super(options); this.underlying = new _shims_1.MCPServerStdio(options); } get name() { return this.underlying.name; } async invalidateToolsCaches() { this._cachedTools = undefined; await this.underlying.invalidateToolsCache(); } connect() { return this.toolsLifecycle.runLifecycleOperation(() => this.invalidateToolsCaches(), () => this.underlying.connect()); } close() { return this.toolsLifecycle.runLifecycleOperation(() => this.invalidateToolsCaches(), () => this.underlying.close()); } async listTools() { const listingGeneration = this.toolsLifecycle.beginListing(); if (this.cacheToolsList && this._cachedTools) { return snapshotMcpTools(this._cachedTools); } const tools = await this.underlying.listTools(); this.toolsLifecycle.assertListingIsCurrent(listingGeneration); if (this.cacheToolsList) { this._cachedTools = snapshotMcpTools(tools); return snapshotMcpTools(this._cachedTools); } return snapshotMcpTools(tools); } async callTool(toolName, args, meta, options) { return (await this.callToolResult(toolName, args, meta, options)).content; } callToolResult(toolName, args, meta, options) { return this.underlying.callToolResult(toolName, args, meta, options); } listResources(params) { return this.underlying.listResources(params); } listResourceTemplates(params) { return this.underlying.listResourceTemplates(params); } readResource(uri) { return this.underlying.readResource(uri); } invalidateToolsCache() { return this.toolsLifecycle.runLifecycleOperation(() => this.invalidateToolsCaches()); } } exports.MCPServerStdio = MCPServerStdio; class MCPServerStreamableHttp extends mcpShared_1.BaseMCPServerStreamableHttp { underlying; _cachedToolsSessionId = undefined; toolsLifecycle = new MCPToolsLifecycleGuard(); constructor(options) { super(options); this.underlying = new _shims_1.MCPServerStreamableHttp(options); } clearLocalToolsCache() { this._cachedTools = undefined; this._cachedToolsSessionId = undefined; } async invalidateToolsCaches() { this.clearLocalToolsCache(); await this.underlying.invalidateToolsCache(); } get name() { return this.underlying.name; } get sessionId() { return this.underlying.sessionId; } connect() { return this.toolsLifecycle.runLifecycleOperation(() => this.invalidateToolsCaches(), () => this.underlying.connect()); } close() { return this.toolsLifecycle.runLifecycleOperation(() => this.invalidateToolsCaches(), () => this.underlying.close()); } async listTools() { const listingGeneration = this.toolsLifecycle.beginListing(); const sessionId = this.sessionId; if (sessionId === undefined) { this.toolsLifecycle.invalidate(); await this.invalidateToolsCaches(); const tools = await this.underlying.listTools(); return snapshotMcpTools(tools); } if (this.cacheToolsList && this._cachedTools && this._cachedToolsSessionId === sessionId) { return snapshotMcpTools(this._cachedTools); } const tools = await this.underlying.listTools(); this.toolsLifecycle.assertListingIsCurrent(listingGeneration); if (this.cacheToolsList) { this._cachedTools = snapshotMcpTools(tools); this._cachedToolsSessionId = sessionId; return snapshotMcpTools(this._cachedTools); } return snapshotMcpTools(tools); } async callTool(toolName, args, meta, options) { return (await this.callToolResult(toolName, args, meta, options)).content; } async callToolResult(toolName, args, meta, options) { const previousSessionId = this.sessionId; try { return await this.underlying.callToolResult(toolName, args, meta, options); } finally { if (previousSessionId !== this.sessionId) { this.toolsLifecycle.invalidate(); await this.invalidateToolsCaches(); } } } listResources(params) { return this.underlying.listResources(params); } listResourceTemplates(params) { return this.underlying.listResourceTemplates(params); } readResource(uri) { return this.underlying.readResource(uri); } invalidateToolsCache() { return this.toolsLifecycle.runLifecycleOperation(() => this.invalidateToolsCaches()); } } exports.MCPServerStreamableHttp = MCPServerStreamableHttp; class MCPServerSSE extends mcpShared_1.BaseMCPServerSSE { underlying; toolsLifecycle = new MCPToolsLifecycleGuard(); constructor(options) { super(options); this.underlying = new _shims_1.MCPServerSSE(options); } get name() { return this.underlying.name; } async invalidateToolsCaches() { this._cachedTools = undefined; await this.underlying.invalidateToolsCache(); } connect() { return this.toolsLifecycle.runLifecycleOperation(() => this.invalidateToolsCaches(), () => this.underlying.connect()); } close() { return this.toolsLifecycle.runLifecycleOperation(() => this.invalidateToolsCaches(), () => this.underlying.close()); } async listTools() { const listingGeneration = this.toolsLifecycle.beginListing(); if (this.cacheToolsList && this._cachedTools) { return snapshotMcpTools(this._cachedTools); } const tools = await this.underlying.listTools(); this.toolsLifecycle.assertListingIsCurrent(listingGeneration); if (this.cacheToolsList) { this._cachedTools = snapshotMcpTools(tools); return snapshotMcpTools(this._cachedTools); } return snapshotMcpTools(tools); } async callTool(toolName, args, meta, options) { return (await this.callToolResult(toolName, args, meta, options)).content; } callToolResult(toolName, args, meta, options) { return this.underlying.callToolResult(toolName, args, meta, options); } listResources(params) { return this.underlying.listResources(params); } listResourceTemplates(params) { return this.underlying.listResourceTemplates(params); } readResource(uri) { return this.underlying.readResource(uri); } invalidateToolsCache() { return this.toolsLifecycle.runLifecycleOperation(() => this.invalidateToolsCaches()); } } exports.MCPServerSSE = MCPServerSSE; /** * Default cache key generator for MCP tools. * Uses server name, or server+agent if using callable filter. */ const defaultMCPToolCacheKey = ({ server, agent, }) => { if (server.toolFilter && typeof server.toolFilter === 'function' && agent) { return `${server.name}:${agent.name}`; } return server.name; }; exports.defaultMCPToolCacheKey = defaultMCPToolCacheKey; function logMcpToolFilterDebug(buildMessage) { if (!logger_1.logger.dontLogToolData) { logger_1.logger.debug(buildMessage()); } } /** * Fetches and filters raw MCP tools from a single MCP server. */ async function getMcpToolsFromServer({ server, runContext, agent, generateMCPToolCacheKey, tracingParent, }) { const cacheKey = (generateMCPToolCacheKey || exports.defaultMCPToolCacheKey)({ server, agent, runContext, }); const serverName = server.name; // Use cache key generator injected from the outside, or the default if absent. const cachedMcpTools = server.cacheToolsList ? mcpToolCache_1.cachedMcpTools[cacheKey] : undefined; const cacheListing = (0, mcpToolCache_1.beginServerToolsCacheListing)(serverName); const listToolsForServer = async (span) => { const fetchedMcpTools = snapshotMcpTools(cachedMcpTools ?? (await server.listTools())); let mcpTools = fetchedMcpTools; if (server.toolFilter) { const filteredTools = []; for (const tool of fetchedMcpTools) { const filter = server.toolFilter; if (filter) { if (typeof filter === 'function') { if (!runContext || !agent) { filteredTools.push(tool); continue; } const context = { runContext, agent, serverName: server.name }; const [detachedTool] = snapshotMcpTools([tool]); const filtered = await filter(context, detachedTool); if (!filtered) { logMcpToolFilterDebug(() => `MCP Tool (server: ${(0, mcpLogging_1.getMcpServerExternalName)(server.name)}, tool: ${tool.name}) is blocked by the callable filter.`); continue; } } else { const allowedToolNames = filter.allowedToolNames ?? []; const blockedToolNames = filter.blockedToolNames ?? []; if (allowedToolNames.length > 0 || blockedToolNames.length > 0) { const allowed = allowedToolNames.length > 0 ? allowedToolNames.includes(tool.name) : true; const blocked = blockedToolNames.length > 0 ? blockedToolNames.includes(tool.name) : false; if (!allowed || blocked) { if (blocked) { logMcpToolFilterDebug(() => `MCP Tool (server: ${(0, mcpLogging_1.getMcpServerExternalName)(server.name)}, tool: ${tool.name}) is blocked by the static filter.`); } else if (!allowed) { logMcpToolFilterDebug(() => `MCP Tool (server: ${(0, mcpLogging_1.getMcpServerExternalName)(server.name)}, tool: ${tool.name}) is not allowed by the static filter.`); } continue; } } } } filteredTools.push(tool); } mcpTools = filteredTools; } if (span) { span.spanData.result = mcpTools.map((t) => t.name); } // Cache discovery only; filter decisions belong to the current lookup. if (!cachedMcpTools && server.cacheToolsList && cacheListing.isCurrent()) { mcpToolCache_1.cachedMcpTools[cacheKey] = snapshotMcpTools(fetchedMcpTools); if (!mcpToolCache_1.cachedMcpToolKeysByServer[serverName]) { mcpToolCache_1.cachedMcpToolKeysByServer[serverName] = new Set(); } mcpToolCache_1.cachedMcpToolKeysByServer[serverName].add(cacheKey); } return snapshotMcpTools(mcpTools); }; try { if (cachedMcpTools || (!tracingParent && !(0, tracing_1.getCurrentTrace)())) { return await listToolsForServer(); } return await (0, tracing_1.withMCPListToolsSpan)(listToolsForServer, { data: { server: (0, mcpLogging_1.getMcpServerExternalName)(server.name) }, }, tracingParent); } finally { cacheListing.release(); } } function convertMcpToolsToFunctionTools({ mcpTools, server, convertSchemasToStrict, toolNameOverrides, serverIndex = null, errorFunction, }) { return mcpTools.map((mcpTool, index) => { const converted = mcpToFunctionTool(mcpTool, server, convertSchemasToStrict, { toolNameOverride: toolNameOverrides?.[index], errorFunction, }); return (0, toolIdentity_1.bindMcpTool)(converted, { ...(0, toolIdentity_1.getMcpToolBinding)(converted), serverIndex, }); }); } /** * Fetches all function tools from a single MCP server. */ async function getFunctionToolsFromServer({ server, serverIndex, convertSchemasToStrict, runContext, agent, generateMCPToolCacheKey, errorFunction, tracingParent, }) { const mcpTools = await getMcpToolsFromServer({ server, runContext, agent, generateMCPToolCacheKey, tracingParent, }); return convertMcpToolsToFunctionTools({ mcpTools, serverIndex, server, convertSchemasToStrict, errorFunction, }); } /** * Returns all MCP tools from the provided servers, using the function tool conversion. * If runContext and agent are provided, callable tool filters will be applied. */ async function getAllMcpTools(mcpServersOrOpts, runContext, agent, convertSchemasToStrict = false) { const opts = Array.isArray(mcpServersOrOpts) ? { mcpServers: mcpServersOrOpts, runContext, agent, convertSchemasToStrict, } : mcpServersOrOpts; const { mcpServers, convertSchemasToStrict: convertSchemasToStrictFromOpts = false, runContext: runContextFromOpts, agent: agentFromOpts, generateMCPToolCacheKey, errorFunction, includeServerInToolNames = false, reservedToolNames, tracingParent, } = opts; const allTools = []; const toolNames = new Set(); if (includeServerInToolNames) { const serverToolBatches = await Promise.all(mcpServers.map(async (server, serverIndex) => ({ server, serverIndex, mcpTools: await getMcpToolsFromServer({ server, runContext: runContextFromOpts, agent: agentFromOpts, generateMCPToolCacheKey, tracingParent, }), }))); const toolNameOverrides = buildPrefixedToolNameOverrides(serverToolBatches, new Set(reservedToolNames ?? [])); for (const { server, serverIndex, mcpTools } of serverToolBatches) { const serverTools = convertMcpToolsToFunctionTools({ mcpTools, server, serverIndex, convertSchemasToStrict: convertSchemasToStrictFromOpts, errorFunction, toolNameOverrides: mcpTools.map((_, toolIndex) => toolNameOverrides.get(getToolNameOverrideKey(serverIndex, toolIndex))), }); const duplicateToolNames = findDuplicateToolNames(serverTools.map((t) => t.name), toolNames); if (duplicateToolNames.length > 0) { throw new errors_1.UserError(`Duplicate tool names found across MCP servers: ${duplicateToolNames.join(', ')}`); } for (const t of serverTools) { toolNames.add(t.name); allTools.push(t); } } return allTools; } for (const [serverIndex, server] of mcpServers.entries()) { const serverTools = await getFunctionToolsFromServer({ server, serverIndex, convertSchemasToStrict: convertSchemasToStrictFromOpts, runContext: runContextFromOpts, agent: agentFromOpts, generateMCPToolCacheKey, errorFunction, tracingParent, }); const duplicateToolNames = findDuplicateToolNames(serverTools.map((t) => t.name), toolNames); if (duplicateToolNames.length > 0) { throw new errors_1.UserError(`Duplicate tool names found across MCP servers: ${duplicateToolNames.join(', ')}`); } for (const t of serverTools) { toolNames.add(t.name); allTools.push(t); } } return allTools; } /** * Returns the names that repeat within `names` or were already seen in * `previousNames`. */ function findDuplicateToolNames(names, previousNames) { const seen = new Set(previousNames); const duplicates = new Set(); for (const name of names) { if (seen.has(name)) { duplicates.add(name); } seen.add(name); } return [...duplicates].sort(); } function getToolNameOverrideKey(serverIndex, toolIndex) { return `${serverIndex}:${toolIndex}`; } function getSafeToolNamePart(value, fallback) { const safe = Array.from(value) .map((char) => { const code = char.charCodeAt(0); return code <= 127 && /[A-Za-z0-9_-]/.test(char) ? char : '_'; }) .join('') .replace(/^[_-]+|[_-]+$/g, ''); return safe || fallback; } function getUtf8Bytes(value) { const encoded = encodeURIComponent(value); const bytes = []; for (let index = 0; index < encoded.length; index += 1) { if (encoded[index] === '%') { bytes.push(Number.parseInt(encoded.slice(index + 1, index + 3), 16)); index += 2; } else { bytes.push(encoded.charCodeAt(index)); } } return bytes; } function rotateLeft(value, bits) { return ((value << bits) | (value >>> (32 - bits))) >>> 0; } function getSha1Hex(value) { const bytes = getUtf8Bytes(value); const bitLength = bytes.length * 8; bytes.push(0x80); while (bytes.length % 64 !== 56) { bytes.push(0); } for (let shift = 56; shift >= 0; shift -= 8) { bytes.push(Math.floor(bitLength / 2 ** shift) & 0xff); } let h0 = 0x67452301; let h1 = 0xefcdab89; let h2 = 0x98badcfe; let h3 = 0x10325476; let h4 = 0xc3d2e1f0; for (let offset = 0; offset < bytes.length; offset += 64) { const words = new Array(80).fill(0); for (let index = 0; index < 16; index += 1) { const byteOffset = offset + index * 4; words[index] = ((bytes[byteOffset] ?? 0) << 24) | ((bytes[byteOffset + 1] ?? 0) << 16) | ((bytes[byteOffset + 2] ?? 0) << 8) | (bytes[byteOffset + 3] ?? 0); } for (let index = 16; index < 80; index += 1) { words[index] = rotateLeft(words[index - 3] ^ words[index - 8] ^ words[index - 14] ^ words[index - 16], 1); } let a = h0; let b = h1; let c = h2; let d = h3; let e = h4; for (let index = 0; index < 80; index += 1) { let f; let k; if (index < 20) { f = (b & c) | (~b & d); k = 0x5a827999; } else if (index < 40) { f = b ^ c ^ d; k = 0x6ed9eba1; } else if (index < 60) { f = (b & c) | (b & d) | (c & d); k = 0x8f1bbcdc; } else { f = b ^ c ^ d; k = 0xca62c1d6; } const temp = (rotateLeft(a, 5) + f + e + k + (words[index] ?? 0)) >>> 0; e = d; d = c; c = rotateLeft(b, 30); b = a; a = temp; } h0 = (h0 + a) >>> 0; h1 = (h1 + b) >>> 0; h2 = (h2 + c) >>> 0; h3 = (h3 + d) >>> 0; h4 = (h4 + e) >>> 0; } return [h0, h1, h2, h3, h4] .map((word) => word.toString(16).padStart(8, '0')) .join(''); } function shortenToolName(baseName, seed, forceHash = false) { if (!forceHash && baseName.length <= MCP_FUNCTION_TOOL_NAME_MAX_LENGTH) { return baseName; } const hashSuffix = getSha1Hex(seed).slice(0, MCP_FUNCTION_TOOL_HASH_LENGTH); const suffix = `_${hashSuffix}`; const stemLength = MCP_FUNCTION_TOOL_NAME_MAX_LENGTH - suffix.length; const stem = baseName.slice(0, stemLength).replace(/[_-]+$/g, '') || 'mcp'; return `${stem}${suffix}`; } function buildPrefixedToolBaseName(serverName, toolName) { const serverPart = getSafeToolNamePart(serverName, 'server'); const toolPart = getSafeToolNamePart(toolName, 'tool'); return `mcp_${serverPart}__${toolPart}`; } function buildPrefixedToolNameOverrides(serverToolBatches, reservedNames) { const baseNameCounts = new Map(); for (const { server, mcpTools } of serverToolBatches) { const serverName = (0, mcpLogging_1.getMcpServerExternalName)(server.name); for (const mcpTool of mcpTools) { const baseName = buildPrefixedToolBaseName(serverName, mcpTool.name); const publicName = (0, tools_1.toFunctionToolName)(baseName); baseNameCounts.set(publicName, (baseNameCounts.get(publicName) ?? 0) + 1); } } const candidates = []; const rawServerNamesBySeed = new Map(); for (const { server, serverIndex, mcpTools } of serverToolBatches) { const serverName = (0, mcpLogging_1.getMcpServerExternalName)(server.name); mcpTools.forEach((mcpTool, toolIndex) => { const baseName = buildPrefixedToolBaseName(serverName, mcpTool.name); const seed = `${serverName}\0${mcpTool.name}`; const previousRawServerName = rawServerNamesBySeed.get(seed); if (previousRawServerName !== undefined && previousRawServerName !== server.name) { throw new errors_1.UserError(`MCP server names are indistinguishable after URL redaction for tool '${mcpTool.name}': '${serverName}'. Configure unique safe server names when includeServerInToolNames is enabled.`); } rawServerNamesBySeed.set(seed, server.name); const functionToolName = (0, tools_1.toFunctionToolName)(baseName); const forceHash = (baseNameCounts.get(functionToolName) ?? 0) > 1 || reservedNames.has(functionToolName); candidates.push({ batchKey: getToolNameOverrideKey(serverIndex, toolIndex), baseName, seed, initialName: shortenToolName(baseName, seed, forceHash), serverIndex, toolIndex, }); }); } const usedNames = new Set(reservedNames); const overrides = new Map(); for (const candidate of candidates.sort((left, right) => { return (left.initialName.localeCompare(right.initialName) || left.seed.localeCompare(right.seed) || left.serverIndex - right.serverIndex || left.toolIndex - right.toolIndex); })) { let publicName = candidate.initialName; let collisionIndex = 1; while (usedNames.has((0, tools_1.toFunctionToolName)(publicName))) { publicName = shortenToolName(candidate.baseName, `${candidate.seed}\0${collisionIndex}`, true); collisionIndex += 1; } usedNames.add((0, tools_1.toFunctionToolName)(publicName)); overrides.set(candidate.batchKey, publicName); } return overrides; } async function resolveMcpToolMeta(server, runContext, toolName, args) { const resolver = server.toolMetaResolver; if (!resolver) { return undefined; } const context = { runContext, serverName: server.name, toolName, arguments: args, }; const resolved = await resolver(context); if (resolved == null) { return undefined; } if (typeof resolved !== 'object' || Array.isArray(resolved)) { throw new TypeError('MCP tool meta resolver must return an object or null.'); } return resolved; } function mcpToFunctionTool(mcpTool, server, convertSchemasToStrict, options = {}) { const rawToolName = mcpTool.name; const toolName = options.toolNameOverride ?? rawToolName; const binding = { serverName: (0, mcpLogging_1.getMcpServerExternalName)(server.name), toolName: rawToolName, serverIndex: null, }; const annotations = mcpTool.annotations === undefined ? undefined : structuredClone(mcpTool.annotations); function finishConversion(converted) { if (annotations !== undefined) { Object.defineProperty(converted, 'mcpAnnotations', { get: () => structuredClone(annotations), }); } return (0, toolIdentity_1.bindMcpTool)(converted, binding); } const inputGuardrails = server.toolInputGuardrails ? [...server.toolInputGuardrails] : undefined; const outputGuardrails = server.toolOutputGuardrails ? [...server.toolOutputGuardrails] : undefined; const customDataByCall = new WeakMap(); const serverErrorFunction = server.errorFunction; const mcpErrorFunction = serverErrorFunction !== undefined ? serverErrorFunction : options.errorFunction; const errorFunction = typeof mcpErrorFunction === 'function' ? (context, error) => mcpErrorFunction({ context, error }) : mcpErrorFunction; async function invoke(input, runContext, details) { let args = {}; if (typeof input === 'string' && input) { args = JSON.parse(input); } else if (typeof input === 'object' && input != null) { args = input; } const currentSpan = (0, agentToolRunConfig_1.getToolCallParentSpanFromDetails)(details) ?? (0, tracing_1.getCurrentSpan)(); if (currentSpan) { currentSpan.spanData['mcp_data'] = { server: (0, mcpLogging_1.getMcpServerExternalName)(server.name), }; } const meta = runContext ? await resolveMcpToolMeta(server, runContext, rawToolName, args) : undefined; const callOptions = details?.signal ? { signal: details.signal } : undefined; const useFullResult = (server.useStructuredContent === true || server.customDataExtractor !== undefined) && server.callToolResult !== undefined; let result; if (useFullResult) { result = callOptions ? await server.callToolResult(rawToolName, args, meta, callOptions) : meta === undefined ? await server.callToolResult(rawToolName, args) : await server.callToolResult(rawToolName, args, meta); } else { result = { content: callOptions ? await server.callTool(rawToolName, args, meta, callOptions) : meta === undefined ? await server.callTool(rawToolName, args) : await server.callTool(rawToolName, args, meta), }; } const content = result.content; const resultMeta = result._meta ?? content._meta; const structuredContent = result.structuredContent ?? content.structuredContent; const isError = result.isError ?? content.isError; const toolOutput = server.useStructuredContent === true && isError !== true && structuredContent !== undefined ? JSON.stringify(structuredContent) : content.length === 1 ? content[0] : content; if (runContext && details?.toolCall?.callId && server.customDataExtractor) { let byCall = customDataByCall.get(runContext); if (!byCall) { byCall = new Map(); customDataByCall.set(runContext, byCall); } byCall.set(details.toolCall.callId, { runContext, serverName: server.name, toolName: rawToolName, toolDisplayName: toolName, arguments: cloneMcpCustomDataContextValue(args), resultMeta: cloneMcpCustomDataContextValue(resultMeta), structuredContent: cloneMcpCustomDataContextValue(structuredContent), isError, toolOutput: cloneMcpCustomDataContextValue(toolOutput), }); } return toolOutput; } async function extractCustomData(context) { const mcpContext = getMcpCustomDataContext(customDataByCall, context.runContext, context.toolCall.callId); return mcpContext ? (0, customData_1.maybeExtractToolOutputCustomData)(server.customDataExtractor, { ...mcpContext, toolOutput: context.output, }) : undefined; } const inputSchema = mcpTool.inputSchema ?? {}; const inputSchemaIsEmpty = Object.keys(inputSchema).length === 0; const schema = { ...inputSchema, type: inputSchema.type ?? 'object', properties: inputSchema.properties ?? {}, required: inputSchema.required ?? [], }; const strictSchema = (inputSchemaIsEmpty ? { ...schema, additionalProperties: false } : schema); let preserveSchemaOnFallback = false; if (convertSchemasToStrict || schema.additionalProperties === true) { try { (0, strictToolSchema_1.assertOpenAIStrictToolSchemaPreservesOpenObjects)(strictSchema); return finishConversion((0, tool_1.tool)({ name: toolName, description: mcpTool.description || '', parameters: strictSchema, strict: true, execute: invoke, errorFunction, inputGuardrails, outputGuardrails, customDataExtractor: extractCustomData, })); } catch (e) { if (convertSchemasToStrict && (0, strictToolSchema_1.isJsonSchemaDepthError)(e)) { throw e; } preserveSchemaOnFallback = true; (0, logger_1.logToolActionWarning)(logger_1.logger, 'Error converting MCP schema to strict mode:', e); } } const nonStrictSchema = { ...schema, additionalProperties: preserveSchemaOnFallback && 'additionalProperties' in schema ? schema.additionalProperties : true, }; return finishConversion((0, tool_1.tool)({ name: toolName, description: mcpTool.description || '', parameters: nonStrictSchema, strict: false, execute: invoke, errorFunction, inputGuardrails, outputGuardrails, customDataExtractor: extractCustomData, })); } function getMcpCustomDataContext(contexts, runContext, callId) { const byCall = contexts.get(runContext); const context = byCall?.get(callId); byCall?.delete(callId); return context; } function cloneMcpCustomDataContextValue(value) { try { return structuredClone(value); } catch { return value; } } //# sourceMappingURL=mcp.js.map