UNPKG

mcp-use

Version:

Opinionated MCP Framework for TypeScript (@modelcontextprotocol/sdk compatible) - Build MCP Agents, Clients and Servers with support for ChatGPT Apps, Code Mode, OAuth, Notifications, Sampling, Observability and more.

1,421 lines (1,414 loc) 393 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/logging.ts async function getNodeModules() { if (typeof process !== "undefined" && process.platform) { try { const fs2 = await import("fs"); const path2 = await import("path"); return { fs: fs2.default, path: path2.default }; } catch { return { fs: null, path: null }; } } return { fs: null, path: null }; } function loadWinstonSync() { if (typeof require !== "undefined") { try { winston = require("winston"); } catch { } } } async function getWinston() { if (!winston) { winston = await import("winston"); } return winston; } function isNodeJSEnvironment() { try { if (typeof navigator !== "undefined" && navigator.userAgent?.includes("Cloudflare-Workers")) { return false; } if (typeof globalThis.EdgeRuntime !== "undefined" || typeof globalThis.Deno !== "undefined") { return false; } const hasNodeGlobals = typeof process !== "undefined" && typeof process.platform !== "undefined" && typeof __dirname !== "undefined"; return hasNodeGlobals; } catch { return false; } } function resolveLevel(env) { const envValue = typeof process !== "undefined" && process.env ? env : void 0; switch (envValue?.trim()) { case "2": return "debug"; case "1": return "info"; default: return "info"; } } var winston, DEFAULT_LOGGER_NAME, SimpleConsoleLogger, Logger, logger; var init_logging = __esm({ "src/logging.ts"() { "use strict"; __name(getNodeModules, "getNodeModules"); winston = null; __name(loadWinstonSync, "loadWinstonSync"); __name(getWinston, "getWinston"); DEFAULT_LOGGER_NAME = "mcp-use"; __name(isNodeJSEnvironment, "isNodeJSEnvironment"); SimpleConsoleLogger = class { static { __name(this, "SimpleConsoleLogger"); } _level; name; constructor(name = DEFAULT_LOGGER_NAME, level = "info") { this.name = name; this._level = level; } shouldLog(level) { const levels = [ "error", "warn", "info", "http", "verbose", "debug", "silly" ]; const currentIndex = levels.indexOf(this._level); const messageIndex = levels.indexOf(level); return messageIndex <= currentIndex; } formatMessage(level, message) { const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false }); return `${timestamp} [${this.name}] ${level}: ${message}`; } error(message) { if (this.shouldLog("error")) { console.error(this.formatMessage("error", message)); } } warn(message) { if (this.shouldLog("warn")) { console.warn(this.formatMessage("warn", message)); } } info(message) { if (this.shouldLog("info")) { console.info(this.formatMessage("info", message)); } } debug(message) { if (this.shouldLog("debug")) { console.debug(this.formatMessage("debug", message)); } } http(message) { if (this.shouldLog("http")) { console.log(this.formatMessage("http", message)); } } verbose(message) { if (this.shouldLog("verbose")) { console.log(this.formatMessage("verbose", message)); } } silly(message) { if (this.shouldLog("silly")) { console.log(this.formatMessage("silly", message)); } } // Make it compatible with Winston interface get level() { return this._level; } set level(newLevel) { this._level = newLevel; } }; __name(resolveLevel, "resolveLevel"); Logger = class { static { __name(this, "Logger"); } static instances = {}; static simpleInstances = {}; static currentFormat = "minimal"; static get(name = DEFAULT_LOGGER_NAME) { if (!isNodeJSEnvironment()) { if (!this.simpleInstances[name]) { const debugEnv = typeof process !== "undefined" && process.env?.DEBUG || void 0; this.simpleInstances[name] = new SimpleConsoleLogger( name, resolveLevel(debugEnv) ); } return this.simpleInstances[name]; } if (!this.instances[name]) { if (!winston) { throw new Error("Winston not loaded - call Logger.configure() first"); } const { createLogger, format } = winston; const { combine, timestamp, label, colorize, splat } = format; this.instances[name] = createLogger({ level: resolveLevel(process.env.DEBUG), format: combine( colorize(), splat(), label({ label: name }), timestamp({ format: "HH:mm:ss" }), this.getFormatter() ), transports: [new winston.transports.Console()] }); } return this.instances[name]; } static getFormatter() { if (!winston) { throw new Error("Winston not loaded"); } const { format } = winston; const { printf } = format; const minimalFormatter = printf(({ level, message, label, timestamp }) => { return `${timestamp} [${label}] ${level}: ${message}`; }); const detailedFormatter = printf(({ level, message, label, timestamp }) => { return `${timestamp} [${label}] ${level.toUpperCase()}: ${message}`; }); const emojiFormatter = printf(({ level, message, label, timestamp }) => { return `${timestamp} [${label}] ${level.toUpperCase()}: ${message}`; }); switch (this.currentFormat) { case "minimal": return minimalFormatter; case "detailed": return detailedFormatter; case "emoji": return emojiFormatter; default: return minimalFormatter; } } static async configure(options = {}) { const { level, console: console2 = true, file, format = "minimal" } = options; const debugEnv = typeof process !== "undefined" && process.env?.DEBUG || void 0; const resolvedLevel = level ?? resolveLevel(debugEnv); this.currentFormat = format; if (!isNodeJSEnvironment()) { Object.values(this.simpleInstances).forEach((logger2) => { logger2.level = resolvedLevel; }); return; } await getWinston(); if (!winston) { throw new Error("Failed to load winston"); } const root = this.get(); root.level = resolvedLevel; const winstonRoot = root; winstonRoot.clear(); if (console2) { winstonRoot.add(new winston.transports.Console()); } if (file) { const { fs: nodeFs, path: nodePath } = await getNodeModules(); if (nodeFs && nodePath) { const dir = nodePath.dirname(nodePath.resolve(file)); if (!nodeFs.existsSync(dir)) { nodeFs.mkdirSync(dir, { recursive: true }); } winstonRoot.add(new winston.transports.File({ filename: file })); } } const { format: winstonFormat } = winston; const { combine, timestamp, label, colorize, splat } = winstonFormat; Object.values(this.instances).forEach((logger2) => { if (logger2 && "format" in logger2) { logger2.level = resolvedLevel; logger2.format = combine( colorize(), splat(), label({ label: DEFAULT_LOGGER_NAME }), timestamp({ format: "HH:mm:ss" }), this.getFormatter() ); } }); } static setDebug(enabled) { let level; if (enabled === 2 || enabled === true) level = "debug"; else if (enabled === 1) level = "info"; else level = "info"; Object.values(this.simpleInstances).forEach((logger2) => { logger2.level = level; }); Object.values(this.instances).forEach((logger2) => { if (logger2) { logger2.level = level; } }); if (typeof process !== "undefined" && process.env) { process.env.DEBUG = enabled ? enabled === true ? "2" : String(enabled) : "0"; } } static setFormat(format) { this.currentFormat = format; this.configure({ format }); } }; if (isNodeJSEnvironment()) { loadWinstonSync(); if (winston) { Logger.configure(); } } logger = Logger.get(); } }); // src/observability/langfuse.ts var langfuse_exports = {}; __export(langfuse_exports, { initializeLangfuse: () => initializeLangfuse, langfuseClient: () => langfuseClient, langfuseHandler: () => langfuseHandler, langfuseInitPromise: () => langfuseInitPromise }); async function initializeLangfuse(agentId, metadata, metadataProvider, tagsProvider) { try { const langfuseModule = await import("langfuse-langchain").catch(() => null); if (!langfuseModule) { logger.debug( "Langfuse package not installed - tracing disabled. Install with: npm install @langfuse/langchain" ); return; } const { CallbackHandler } = langfuseModule; class LoggingCallbackHandler extends CallbackHandler { static { __name(this, "LoggingCallbackHandler"); } agentId; metadata; metadataProvider; tagsProvider; verbose; constructor(config2, agentId2, metadata2, metadataProvider2, tagsProvider2) { super(config2); this.agentId = agentId2; this.metadata = metadata2; this.metadataProvider = metadataProvider2; this.tagsProvider = tagsProvider2; this.verbose = config2?.verbose ?? false; } // Override to add custom metadata to traces async handleChainStart(chain, inputs, runId, parentRunId, tags, metadata2, name, kwargs) { logger.debug("Langfuse: Chain start intercepted"); const customTags = this.getCustomTags(); const metadataToAdd = this.getMetadata(); const enhancedTags = [...tags || [], ...customTags]; const enhancedMetadata = { ...metadata2 || {}, ...metadataToAdd }; if (this.verbose) { logger.debug( `Langfuse: Chain start with custom tags: ${JSON.stringify(enhancedTags)}` ); logger.debug( `Langfuse: Chain start with metadata: ${JSON.stringify(enhancedMetadata)}` ); } return super.handleChainStart( chain, inputs, runId, parentRunId, enhancedTags, enhancedMetadata, name, kwargs ); } // Get custom tags based on environment and agent configuration getCustomTags() { const tags = []; const env = this.getEnvironmentTag(); if (env) { tags.push(`env:${env}`); } if (this.agentId) { tags.push(`agent_id:${this.agentId}`); } if (this.tagsProvider) { const providerTags = this.tagsProvider(); if (providerTags && providerTags.length > 0) { tags.push(...providerTags); } } return tags; } // Get metadata getMetadata() { const metadata2 = {}; const env = this.getEnvironmentTag(); if (env) { metadata2.env = env; } if (this.agentId) { metadata2.agent_id = this.agentId; } if (this.metadata) { Object.assign(metadata2, this.metadata); } if (this.metadataProvider) { const dynamicMetadata = this.metadataProvider(); if (dynamicMetadata) { Object.assign(metadata2, dynamicMetadata); } } return metadata2; } // Determine environment tag based on MCP_USE_AGENT_ENV getEnvironmentTag() { const agentEnv = process.env.MCP_USE_AGENT_ENV; if (!agentEnv) { return "unknown"; } const envLower = agentEnv.toLowerCase(); if (envLower === "local" || envLower === "development") { return "local"; } else if (envLower === "production" || envLower === "prod") { return "production"; } else if (envLower === "staging" || envLower === "stage") { return "staging"; } else if (envLower === "hosted" || envLower === "cloud") { return "hosted"; } return envLower.replace(/[^a-z0-9_-]/g, "_"); } async handleLLMStart(...args) { logger.debug("Langfuse: LLM start intercepted"); if (this.verbose) { logger.debug(`Langfuse: LLM start args: ${JSON.stringify(args)}`); } return super.handleLLMStart(...args); } async handleToolStart(...args) { logger.debug("Langfuse: Tool start intercepted"); if (this.verbose) { logger.debug(`Langfuse: Tool start args: ${JSON.stringify(args)}`); } return super.handleToolStart(...args); } async handleRetrieverStart(...args) { logger.debug("Langfuse: Retriever start intercepted"); if (this.verbose) { logger.debug( `Langfuse: Retriever start args: ${JSON.stringify(args)}` ); } return super.handleRetrieverStart(...args); } async handleAgentAction(...args) { logger.debug("Langfuse: Agent action intercepted"); if (this.verbose) { logger.debug(`Langfuse: Agent action args: ${JSON.stringify(args)}`); } return super.handleAgentAction(...args); } async handleAgentEnd(...args) { logger.debug("Langfuse: Agent end intercepted"); if (this.verbose) { logger.debug(`Langfuse: Agent end args: ${JSON.stringify(args)}`); } return super.handleAgentEnd(...args); } } const initialMetadata = metadata || (metadataProvider ? metadataProvider() : {}); const initialTags = tagsProvider ? tagsProvider() : []; const config = { publicKey: process.env.LANGFUSE_PUBLIC_KEY, secretKey: process.env.LANGFUSE_SECRET_KEY, baseUrl: process.env.LANGFUSE_HOST || process.env.LANGFUSE_BASEURL || "https://cloud.langfuse.com", flushAt: Number.parseInt(process.env.LANGFUSE_FLUSH_AT || "15"), flushInterval: Number.parseInt( process.env.LANGFUSE_FLUSH_INTERVAL || "10000" ), release: process.env.LANGFUSE_RELEASE, requestTimeout: Number.parseInt( process.env.LANGFUSE_REQUEST_TIMEOUT || "10000" ), enabled: process.env.LANGFUSE_ENABLED !== "false", // Set trace name - can be customized via metadata.trace_name or defaults to 'mcp-use-agent' traceName: initialMetadata.trace_name || process.env.LANGFUSE_TRACE_NAME || "mcp-use-agent", // Pass sessionId, userId, and tags to the handler sessionId: initialMetadata.session_id || void 0, userId: initialMetadata.user_id || void 0, tags: initialTags.length > 0 ? initialTags : void 0, metadata: initialMetadata || void 0 }; logger.debug( "Langfuse handler config:", JSON.stringify( { traceName: config.traceName, sessionId: config.sessionId, userId: config.userId, tags: config.tags }, null, 2 ) ); langfuseState.handler = new LoggingCallbackHandler( config, agentId, metadata, metadataProvider, tagsProvider ); logger.debug( "Langfuse observability initialized successfully with logging enabled" ); try { const langfuseCore = await import("langfuse").catch(() => null); if (langfuseCore) { const { Langfuse } = langfuseCore; langfuseState.client = new Langfuse({ publicKey: process.env.LANGFUSE_PUBLIC_KEY, secretKey: process.env.LANGFUSE_SECRET_KEY, baseUrl: process.env.LANGFUSE_HOST || "https://cloud.langfuse.com" }); logger.debug("Langfuse client initialized"); } } catch (error) { logger.debug(`Langfuse client initialization failed: ${error}`); } } catch (error) { logger.debug(`Langfuse initialization error: ${error}`); } } var langfuseDisabled, langfuseState, langfuseHandler, langfuseClient, langfuseInitPromise; var init_langfuse = __esm({ "src/observability/langfuse.ts"() { "use strict"; init_logging(); langfuseDisabled = process.env.MCP_USE_LANGFUSE?.toLowerCase() === "false"; langfuseState = { handler: null, client: null, initPromise: null }; __name(initializeLangfuse, "initializeLangfuse"); if (langfuseDisabled) { logger.debug( "Langfuse tracing disabled via MCP_USE_LANGFUSE environment variable" ); } else if (!process.env.LANGFUSE_PUBLIC_KEY || !process.env.LANGFUSE_SECRET_KEY) { logger.debug( "Langfuse API keys not found - tracing disabled. Set LANGFUSE_PUBLIC_KEY and LANGFUSE_SECRET_KEY to enable" ); } else { langfuseState.initPromise = initializeLangfuse(); } langfuseHandler = /* @__PURE__ */ __name(() => langfuseState.handler, "langfuseHandler"); langfuseClient = /* @__PURE__ */ __name(() => langfuseState.client, "langfuseClient"); langfuseInitPromise = /* @__PURE__ */ __name(() => langfuseState.initPromise, "langfuseInitPromise"); } }); // src/agents/display.ts var display_exports = {}; __export(display_exports, { extractCodeFromToolInput: () => extractCodeFromToolInput, extractToolMessageContent: () => extractToolMessageContent, formatSearchToolsAsTree: () => formatSearchToolsAsTree, handleToolEnd: () => handleToolEnd, handleToolStart: () => handleToolStart, parseExecuteCodeResult: () => parseExecuteCodeResult, prettyStreamEvents: () => prettyStreamEvents, printBox: () => printBox, renderContent: () => renderContent, unwrapToolInput: () => unwrapToolInput }); function highlightCode(content, language) { if (!highlight) { return content; } try { return highlight(content, { language: language ?? "javascript", ignoreIllegals: true }); } catch { return content; } } function stripAnsi(str) { if (stripVTControlCharacters) { return stripVTControlCharacters(str); } return str.replace(/\x1b\[[0-9;]*m/g, ""); } function wrapAnsiLine(line, maxWidth) { const stripped = stripAnsi(line); if (stripped.length <= maxWidth) return [line]; const result = []; let visibleCount = 0; let current = ""; let i = 0; while (i < line.length) { const char = line[i]; if (char === "\x1B") { let sequence = char; i++; while (i < line.length) { const nextChar = line[i]; sequence += nextChar; i++; if (nextChar === "m") break; } current += sequence; continue; } current += char; visibleCount++; i++; if (visibleCount >= maxWidth) { result.push(current); current = ""; visibleCount = 0; } } if (current) result.push(current); return result; } function printBox(content, title, language, bgColor = false) { const width = TERMINAL_WIDTH; let displayContent = content; if (language) { try { displayContent = highlightCode(content, language); } catch { } } const lines = displayContent.split("\n").flatMap((line) => wrapAnsiLine(line, width - 4)); console.log(chalkHelper.gray("\u250C" + "\u2500".repeat(width - 2) + "\u2510")); if (title) { const stripped = stripAnsi(title); const lineText = `${title} `; const padding = Math.max(0, width - 4 - stripped.length - 2); console.log( chalkHelper.gray("\u2502 ") + chalkHelper.bold.white(lineText) + " ".repeat(padding) + chalkHelper.gray(" \u2502") ); console.log(chalkHelper.gray("\u251C" + "\u2500".repeat(width - 2) + "\u2524")); } lines.forEach((line) => { const stripped = stripAnsi(line); const padding = Math.max(0, width - 4 - stripped.length); const finalLine = bgColor ? chalkHelper.bgGray(line + " ".repeat(padding)) : line + " ".repeat(padding); console.log(chalkHelper.gray("\u2502 ") + finalLine + chalkHelper.gray(" \u2502")); }); console.log(chalkHelper.gray("\u2514" + "\u2500".repeat(width - 2) + "\u2518")); } function extractCodeFromToolInput(input) { if (typeof input === "object" && input !== null && "code" in input) { const inputObj = input; return typeof inputObj.code === "string" ? inputObj.code : null; } return null; } function isExecuteCodeResult(obj) { if (typeof obj !== "object" || obj === null) return false; const result = obj; return "result" in result && "logs" in result && Array.isArray(result.logs) && "execution_time" in result && typeof result.execution_time === "number" && "error" in result && (typeof result.error === "string" || result.error === null); } function parseExecuteCodeResult(output) { try { if (typeof output === "string") { const parsed = JSON.parse(output); if (isExecuteCodeResult(parsed)) { return parsed; } } if (isExecuteCodeResult(output)) { return output; } } catch (e) { } return null; } function renderContent(content) { if (content === null || content === void 0) { return "null"; } if (typeof content === "object") { return JSON.stringify(content, null, 2); } return String(content); } function unwrapToolInput(input) { if (typeof input === "object" && input !== null && "input" in input) { const inputObj = input; if (typeof inputObj.input === "string") { try { return JSON.parse(inputObj.input); } catch (e) { return inputObj.input; } } } return input; } function handleToolStart(event) { const toolName = event.name || "unknown"; let input = event.data?.input || {}; input = unwrapToolInput(input); const code = extractCodeFromToolInput(input); if (code) { printBox(code, `${toolName} - input`, "javascript", false); const otherParams = { ...input }; delete otherParams.code; if (Object.keys(otherParams).length > 0) { printBox(renderContent(otherParams), "Other Parameters", "json", false); } } else { printBox(renderContent(input), `${toolName} - input`, "json", false); } } function extractToolMessageContent(output) { try { if (typeof output === "object" && output !== null && "name" in output && "content" in output) { const outputObj = output; const toolName = (typeof outputObj.name === "string" ? outputObj.name : null) || "unknown"; const lcKwargs = outputObj.lc_kwargs; const status = lcKwargs?.status || outputObj.status || "unknown"; let content = outputObj.content; if (typeof content === "string") { try { content = JSON.parse(content); } catch (e) { } } return { toolName, status, content }; } } catch (e) { } return null; } function formatSearchToolsAsTree(tools, meta, query) { const metaLines = []; if (meta) { if (meta.total_tools !== void 0) { metaLines.push(`Total tools: ${meta.total_tools}`); } if (meta.namespaces && meta.namespaces.length > 0) { metaLines.push(`Namespaces: ${meta.namespaces.join(", ")}`); } if (meta.result_count !== void 0) { metaLines.push(`Results: ${meta.result_count}`); } } if (!Array.isArray(tools) || tools.length === 0) { const noResultsMsg = query ? `No tools found for query "${query}"` : "(no tools found)"; if (metaLines.length > 0) { return `${metaLines.join("\n")} ${noResultsMsg}`; } return noResultsMsg; } const toolsByServer = {}; for (const tool of tools) { const server = tool.server || "unknown"; if (!toolsByServer[server]) { toolsByServer[server] = []; } toolsByServer[server].push(tool); } const lines = []; if (meta) { if (meta.total_tools !== void 0) { lines.push(`Total tools: ${meta.total_tools}`); } if (meta.namespaces && meta.namespaces.length > 0) { lines.push(`Namespaces: ${meta.namespaces.join(", ")}`); } if (meta.result_count !== void 0) { lines.push(`Results: ${meta.result_count}`); } if (lines.length > 0) { lines.push(""); } } const servers = Object.keys(toolsByServer).sort(); for (let i = 0; i < servers.length; i++) { const server = servers[i]; const serverTools = toolsByServer[server]; const isLastServer = i === servers.length - 1; const serverPrefix = isLastServer ? "\u2514\u2500" : "\u251C\u2500"; lines.push( `${serverPrefix} ${chalkHelper.cyan(server)} (${serverTools.length} tools)` ); for (let j = 0; j < serverTools.length; j++) { const tool = serverTools[j]; const isLastTool = j === serverTools.length - 1; const indent = isLastServer ? " " : "\u2502 "; const toolPrefix = isLastTool ? "\u2514\u2500" : "\u251C\u2500"; const toolLine = `${indent}${toolPrefix} ${tool.name}`; lines.push(toolLine); if (tool.description) { const descAlign = isLastTool ? " " : "\u2502 "; const descriptionIndent = `${indent}${descAlign}`; const indentLength = stripAnsi(descriptionIndent).length; const availableWidth = Math.max(40, TERMINAL_WIDTH - indentLength - 4); const words = tool.description.split(/(\s+)/); const wrappedLines = []; let currentLine = ""; for (const word of words) { const testLine = currentLine + word; if (stripAnsi(testLine).length <= availableWidth) { currentLine = testLine; } else { if (currentLine) { wrappedLines.push(currentLine.trimEnd()); } currentLine = word.trimStart(); } } if (currentLine) { wrappedLines.push(currentLine.trimEnd()); } for (const descLine of wrappedLines) { lines.push(`${descriptionIndent}${chalkHelper.dim(descLine)}`); } } } } return lines.join("\n"); } function handleToolEnd(event) { const output = event.data?.output; const toolMessage = extractToolMessageContent(output); if (toolMessage) { const { toolName, status, content } = toolMessage; if (toolName === "execute_code") { let actualContent = content; if (typeof content === "object" && content !== null && "content" in content) { const innerContent = content.content; if (Array.isArray(innerContent) && innerContent.length > 0) { if (innerContent[0].type === "text" && innerContent[0].text) { actualContent = innerContent[0].text; } } } const execResult2 = parseExecuteCodeResult(actualContent); if (execResult2) { const timeMs = execResult2.execution_time ? Math.round(execResult2.execution_time * 1e3) : 0; const timeStr = `${timeMs}ms`; const isError2 = execResult2.error !== null && execResult2.error !== void 0 && execResult2.error !== ""; const statusText = isError2 ? chalkHelper.red("error") : chalkHelper.green("success"); const title2 = `${toolName} - ${statusText} - ${timeStr}`; if (execResult2.result !== null && execResult2.result !== void 0) { const resultStr = renderContent(execResult2.result); const language3 = typeof execResult2.result === "object" ? "json" : void 0; printBox(resultStr, title2, language3, false); } else { printBox("(no result)", title2, void 0, false); } if (execResult2.logs && execResult2.logs.length > 0) { printBox(execResult2.logs.join("\n"), `Logs`, void 0, false); } if (execResult2.error) { printBox( execResult2.error, chalkHelper.red("Error"), void 0, false ); } return; } } if (toolName === "search_tools") { const toolInput = event.data?.input; const query = toolInput?.query; let actualContent = content; if (typeof content === "object" && content !== null && !Array.isArray(content) && "content" in content) { const innerContent = content.content; if (Array.isArray(innerContent) && innerContent.length > 0) { if (innerContent[0].type === "text" && innerContent[0].text) { try { actualContent = JSON.parse(innerContent[0].text); } catch (e) { actualContent = innerContent[0].text; } } } } if (typeof actualContent === "object" && actualContent !== null && !Array.isArray(actualContent) && "results" in actualContent && Array.isArray(actualContent.results)) { const results = actualContent.results; const contentWithMeta = actualContent; const meta = contentWithMeta.meta; const treeStr = formatSearchToolsAsTree(results, meta, query); const statusText = status === "success" ? chalk.green("Success") : chalk.red("Error"); const title2 = `${statusText}: ${toolName} - Result`; printBox(treeStr, title2, void 0, false); return; } if (Array.isArray(actualContent)) { const treeStr = formatSearchToolsAsTree( actualContent, void 0, query ); const statusText = status === "success" ? chalk.green("Success") : chalk.red("Error"); const title2 = `${statusText}: ${toolName} - Result`; printBox(treeStr, title2, void 0, false); return; } } const contentObj = typeof content === "object" && content !== null ? content : null; const isError = contentObj && "isError" in contentObj && contentObj.isError === true || status === "error"; let displayContent = content; if (typeof content === "object" && content !== null && "content" in content) { displayContent = content.content; if (Array.isArray(displayContent) && displayContent.length > 0) { if (displayContent[0].type === "text" && displayContent[0].text) { displayContent = displayContent[0].text; } } } const contentStr = renderContent(displayContent); const language2 = typeof displayContent === "object" ? "json" : void 0; const statusLabel = status === "success" ? chalkHelper.green("Success") : isError ? chalkHelper.red("Error") : "Result"; const title = `${statusLabel}: ${toolName} - Result`; printBox(contentStr, title, language2, false); return; } const execResult = parseExecuteCodeResult(output); if (execResult) { const timeMs = execResult.execution_time ? Math.round(execResult.execution_time * 1e3) : 0; const timeStr = `${timeMs}ms`; if (execResult.result !== null && execResult.result !== void 0) { const resultStr = renderContent(execResult.result); const language2 = typeof execResult.result === "object" ? "json" : void 0; printBox(resultStr, `Result - ${timeStr}`, language2, false); } if (execResult.logs && execResult.logs.length > 0) { printBox(execResult.logs.join("\n"), `Logs`, void 0, false); } if (execResult.error) { printBox(execResult.error, chalkHelper.red("Error"), void 0, false); } return; } const outputStr = renderContent(output); const language = typeof output === "object" ? "json" : void 0; printBox(outputStr, "Result", language, false); } async function* prettyStreamEvents(streamEventsGenerator) { let finalResponse = ""; let isFirstTextChunk = true; let hasStreamedText = false; for await (const event of streamEventsGenerator) { if (event.event === "on_tool_start") { if (hasStreamedText) { process.stdout.write("\n"); hasStreamedText = false; isFirstTextChunk = true; } handleToolStart(event); } else if (event.event === "on_tool_end") { handleToolEnd(event); } else if (event.event === "on_chat_model_stream") { if (event.data?.chunk?.text) { const text = event.data.chunk.text; if (typeof text === "string" && text.length > 0) { if (isFirstTextChunk) { process.stdout.write("\n\u{1F916} "); isFirstTextChunk = false; } process.stdout.write(text); finalResponse += text; hasStreamedText = true; } } } yield; } return finalResponse; } var chalk, highlight, stripVTControlCharacters, displayPackagesWarned, isNode, TERMINAL_WIDTH, chalkHelper; var init_display = __esm({ "src/agents/display.ts"() { "use strict"; chalk = null; highlight = null; stripVTControlCharacters = null; displayPackagesWarned = false; isNode = typeof process !== "undefined" && process.versions?.node; (async () => { if (isNode) { try { const utilModule = await import("util"); stripVTControlCharacters = utilModule.stripVTControlCharacters; } catch { } } try { const chalkModule = await import("chalk"); chalk = chalkModule.default; } catch { } try { const cliHighlightModule = await import("cli-highlight"); highlight = cliHighlightModule.highlight; } catch { } if (isNode && (!chalk || !highlight)) { if (!displayPackagesWarned) { displayPackagesWarned = true; console.warn( "\n\u2728 For enhanced console output with colors and syntax highlighting, install:\n\n npm install chalk cli-highlight\n # or\n pnpm add chalk cli-highlight\n" ); } } })(); TERMINAL_WIDTH = process.stdout.columns || 120; chalkHelper = { gray: /* @__PURE__ */ __name((str) => chalk?.gray(str) ?? str, "gray"), bold: { white: /* @__PURE__ */ __name((str) => chalk?.bold?.white(str) ?? str, "white") }, bgGray: /* @__PURE__ */ __name((str) => chalk?.bgGray(str) ?? str, "bgGray"), cyan: /* @__PURE__ */ __name((str) => chalk?.cyan(str) ?? str, "cyan"), dim: /* @__PURE__ */ __name((str) => chalk?.dim(str) ?? str, "dim"), red: /* @__PURE__ */ __name((str) => chalk?.red(str) ?? str, "red"), green: /* @__PURE__ */ __name((str) => chalk?.green(str) ?? str, "green") }; __name(highlightCode, "highlightCode"); __name(stripAnsi, "stripAnsi"); __name(wrapAnsiLine, "wrapAnsiLine"); __name(printBox, "printBox"); __name(extractCodeFromToolInput, "extractCodeFromToolInput"); __name(isExecuteCodeResult, "isExecuteCodeResult"); __name(parseExecuteCodeResult, "parseExecuteCodeResult"); __name(renderContent, "renderContent"); __name(unwrapToolInput, "unwrapToolInput"); __name(handleToolStart, "handleToolStart"); __name(extractToolMessageContent, "extractToolMessageContent"); __name(formatSearchToolsAsTree, "formatSearchToolsAsTree"); __name(handleToolEnd, "handleToolEnd"); __name(prettyStreamEvents, "prettyStreamEvents"); } }); // index.ts var index_exports = {}; __export(index_exports, { AcquireActiveMCPServerTool: () => AcquireActiveMCPServerTool, AddMCPServerFromConfigTool: () => AddMCPServerFromConfigTool, BaseAdapter: () => BaseAdapter, BaseCodeExecutor: () => BaseCodeExecutor, BaseConnector: () => BaseConnector, BrowserOAuthClientProvider: () => BrowserOAuthClientProvider, BrowserTelemetry: () => Tel, ConnectMCPServerTool: () => ConnectMCPServerTool, E2BCodeExecutor: () => E2BCodeExecutor, ElicitationDeclinedError: () => ElicitationDeclinedError, ElicitationTimeoutError: () => ElicitationTimeoutError, ElicitationValidationError: () => ElicitationValidationError, ErrorBoundary: () => ErrorBoundary, HttpConnector: () => HttpConnector, Image: () => Image, LINEAR_OAUTH_CONFIG: () => LINEAR_OAUTH_CONFIG, ListMCPServersTool: () => ListMCPServersTool, Logger: () => Logger, MCPAgent: () => MCPAgent, MCPClient: () => MCPClient, MCPSession: () => MCPSession, McpUseProvider: () => McpUseProvider, OAuthHelper: () => OAuthHelper, ObservabilityManager: () => ObservabilityManager, PROMPTS: () => PROMPTS, ReleaseMCPServerConnectionTool: () => ReleaseMCPServerConnectionTool, RemoteAgent: () => RemoteAgent, ServerManager: () => ServerManager, StdioConnector: () => StdioConnector, Tel: () => Tel, Telemetry: () => Telemetry, ThemeProvider: () => ThemeProvider, VERSION: () => VERSION, VMCodeExecutor: () => VMCodeExecutor, WidgetControls: () => WidgetControls, createLLMFromString: () => createLLMFromString, createOAuthMCPConfig: () => createOAuthMCPConfig, createReadableStreamFromGenerator: () => createReadableStreamFromGenerator, getPackageVersion: () => getPackageVersion, getSupportedProviders: () => getSupportedProviders, isVMAvailable: () => isVMAvailable, isValidLLMString: () => isValidLLMString, loadConfigFile: () => loadConfigFile, logger: () => logger, onMcpAuthorization: () => onMcpAuthorization, parseLLMString: () => parseLLMString, setBrowserTelemetrySource: () => setTelemetrySource, setTelemetrySource: () => setTelemetrySource, streamEventsToAISDK: () => streamEventsToAISDK, streamEventsToAISDKWithTools: () => streamEventsToAISDKWithTools, useMcp: () => useMcp, useWidget: () => useWidget, useWidgetProps: () => useWidgetProps, useWidgetState: () => useWidgetState, useWidgetTheme: () => useWidgetTheme }); module.exports = __toCommonJS(index_exports); // src/agents/mcp_agent.ts var import_langchain2 = require("langchain"); var import_zod9 = require("zod"); // src/utils/json-schema-to-zod/JSONSchemaToZod.ts var import_zod = require("zod"); var JSONSchemaToZod = class { static { __name(this, "JSONSchemaToZod"); } /** * Converts a JSON schema to a Zod schema. * * @param {JSONSchema} schema - The JSON schema. * @returns {ZodSchema} - The Zod schema. */ static convert(schema) { return this.parseSchema(schema); } /** * Checks if data matches a condition schema. * * @param {JSONValue} data - The data to check. * @param {JSONSchema} condition - The condition schema. * @returns {boolean} - Whether the data matches the condition. */ static matchesCondition(data, condition) { if (!condition.properties) { return true; } if (typeof data !== "object" || data === null || Array.isArray(data)) { return false; } const objectData = data; for (const [key, propCondition] of Object.entries(condition.properties)) { if (!(key in objectData)) { if ("const" in propCondition) { return false; } continue; } const value = objectData[key]; if ("const" in propCondition && value !== propCondition["const"]) { return false; } if ("minimum" in propCondition && typeof value === "number" && value < propCondition["minimum"]) { return false; } if ("maximum" in propCondition && typeof value === "number" && value > propCondition["maximum"]) { return false; } } return true; } /** * Validates data against a conditional schema and adds issues to context if validation fails. * * @param {JSONValue} data - The data to validate. * @param {JSONSchema} schema - The conditional schema. * @param {z.RefinementCtx} ctx - The Zod refinement context. */ static validateConditionalSchema(data, schema, ctx) { this.validateRequiredProperties(data, schema, ctx); this.validatePropertyPatterns(data, schema, ctx); this.validateNestedConditions(data, schema, ctx); } /** * Validates that all required properties are present in the data. * * @param {JSONValue} data - The data to validate. * @param {JSONSchema} schema - The schema containing required properties. * @param {z.RefinementCtx} ctx - The Zod refinement context. */ static validateRequiredProperties(data, schema, ctx) { if (!schema.required) { return; } if (typeof data !== "object" || data === null) { for (const requiredProp of schema.required) { ctx.addIssue({ code: import_zod.z.ZodIssueCode.custom, message: `Required property '${requiredProp}' is missing`, path: [requiredProp] }); } return; } for (const requiredProp of schema.required) { if (!(requiredProp in data)) { ctx.addIssue({ code: import_zod.z.ZodIssueCode.custom, message: `Required property '${requiredProp}' is missing`, path: [requiredProp] }); } } } /** * Validates property patterns for string properties. * * @param {JSONValue} data - The data to validate. * @param {JSONSchema} schema - The schema containing property patterns. * @param {z.RefinementCtx} ctx - The Zod refinement context. */ static validatePropertyPatterns(data, schema, ctx) { if (!schema.properties) { return; } if (typeof data !== "object" || data === null) { return; } if (Array.isArray(data)) { return; } const objectData = data; for (const [key, propSchema] of Object.entries(schema.properties)) { if (!(key in objectData)) { continue; } const value = objectData[key]; if (propSchema["pattern"] && typeof value === "string") { const regex = new RegExp(propSchema["pattern"]); if (!regex.test(value)) { ctx.addIssue({ code: import_zod.z.ZodIssueCode.custom, message: `String '${value}' does not match pattern '${propSchema["pattern"]}'`, path: [key] }); } } } } /** * Validates nested if-then-else conditions. * * @param {JSONValue} data - The data to validate. * @param {JSONSchema} schema - The schema containing if-then-else conditions. * @param {z.RefinementCtx} ctx - The Zod refinement context. */ static validateNestedConditions(data, schema, ctx) { if (!schema["if"] || !schema["then"]) { return; } const matchesIf = this.matchesCondition(data, schema["if"]); if (matchesIf) { this.validateConditionalSchema(data, schema["then"], ctx); } else if (schema["else"]) { this.validateConditionalSchema(data, schema["else"], ctx); } } /** * Parses a JSON schema and returns the corresponding Zod schema. * This is the main entry point for schema conversion. * * @param {JSONSchema} schema - The JSON schema. * @returns {ZodTypeAny} - The ZodTypeAny schema. */ static parseSchema(schema) { if (Array.isArray(schema.type)) { return this.handleTypeArray(schema); } if (schema.oneOf || schema.anyOf || schema.allOf) { return this.parseCombinator(schema); } if (schema["if"] && schema["then"]) { return this.parseObject(schema); } if (schema.properties && (!schema.type || schema.type === "object")) { return this.parseObject(schema); } return this.handleSingleType(schema); } /** * Handles schemas with an array of types. * * @param {JSONSchema} schema - The JSON schema with type array. * @returns {ZodTypeAny} - The ZodTypeAny schema. */ static handleTypeArray(schema) { if (!Array.isArray(schema.type)) { throw new Error("Expected schema.type to be an array"); } if (schema.type.includes("null")) { return this.handleNullableType(schema); } return this.createUnionFromTypes(schema.type, schema); } /** * Handles nullable types by creating a nullable schema. * * @param {JSONSchema} schema - The JSON schema with nullable type. * @returns {ZodTypeAny} - The nullable Zod schema. */ static handleNullableType(schema) { if (!Array.isArray(schema.type)) { throw new Error("Expected schema.type to be an array"); } const nonNullSchema = { ...schema }; nonNullSchema.type = schema.type.filter((t) => t !== "null"); if (nonNullSchema.type.length === 1) { const singleTypeSchema = this.handleSingleType({ ...schema, type: nonNullSchema.type[0] }); return singleTypeSchema.nullable(); } const unionSchema = this.parseSchema(nonNullSchema); return unionSchema.nullable(); } /** * Creates a union type from an array of types. * * @param {string[]} types - Array of type strings. * @param {JSONSchema} baseSchema - The base schema to apply to each type. * @returns {ZodTypeAny} - The union Zod schema. */ static createUnionFromTypes(types, baseSchema) { const schemas = types.map((type) => { const singleTypeSchema = { ...baseSchema, type }; return this.parseSchema(singleTypeSchema); }); return import_zod.z.union(schemas); } /** * Handles schemas with a single type. * * @param {JSONSchema} schema - The JSON schema with single type. * @returns {ZodTypeAny} - The ZodTypeAny schema. */ static handleSingleType(schema) { if (schema.type === void 0) { if (schema.oneOf || schema.anyOf || schema.allOf) { return this.parseCombinator(schema); } if (schema.properties) { return this.parseObject(schema); } return import_zod.z.any(); } switch (schema.type) { case "string": return this.parseString(schema); case "number": case "integer": return this.parseNumberSchema(schema); case "boolean": return import_zod.z.boolean(); case "array": return this.parseArray(schema); case "object": return this.parseObject(schema); default: throw new Error("Unsupported schema type"); } } /** * Parses a number schema. * * @param {JSONSchema} schema - The JSON schema for a number. * @returns {ZodTypeAny} - The ZodTypeAny schema. */ static parseNumberSchema(schema) { const numberSchema = import_zod.z.number(); let result = numberSchema; result = this.applyNumberBounds(numberSchema, schema); result = this.applyNumberMultipleOf(numberSchema, schema); result = this.applyNumberEnum(numberSchema, schema); result = this.applyIntegerConstraint(numberSchema, schema); return result; } /** * Applies bounds validation to a number schema. * * @param {z.ZodNumber} numberSchema - The base number schema. * @param {JSONSchema} schema - The JSON schema with bounds. * @returns {z.ZodNumber} - The updated schema with bounds validation. */ static applyNumberBounds(numberSchema, schema) { let result = numberSchema; if (schema["minimum"] !== void 0) { result = schema["exclusiveMinimum"] ? result.gt(schema["minimum"]) : result.gte(schema["minimum"]); } if (schema["maximum"] !== void 0) { result = schema["exclusiveMaximum"] ? result.lt(schema["maximum"]) : result.lte(schema["maximum"]); } return result; } /** * Applies multipleOf validation to a number schema. * * @param {z.ZodNumber} numberSchema - The base number schema. * @param {JSONSchema} schema - The JSON schema with multipleOf. * @returns {z.ZodNumber} - The updated schema with multipleOf validation. */ static applyNumberMultipleOf(numberSchema, schema) { if (schema["multipleOf"] === void 0) { return numberSchema; } return numberSchema.refine((val) => val % schema["multipleOf"] === 0, { message: `Number must be a multiple of ${schema["multipleOf"]}` }); } /** * Applies enum validation to a number schema. * * @param {z.ZodNumber} numberSchema - The base number schema. * @param {JSONSchema} schema - The JSON schema with enum. * @returns {z.ZodNumber} - The updated schema with enum validation. */ static applyNumberEnum(numberSchema, schema) { if (!schema.enum) { return numberSchema; } const numberEnums = schema.e