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
JavaScript
"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