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,433 lines (1,422 loc) • 300 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");
}
});
// src/browser.ts
var browser_exports = {};
__export(browser_exports, {
BaseAdapter: () => BaseAdapter,
BaseConnector: () => BaseConnector,
BrowserOAuthClientProvider: () => BrowserOAuthClientProvider,
BrowserTelemetry: () => Tel,
HttpConnector: () => HttpConnector,
Logger: () => Logger,
MCPAgent: () => MCPAgent,
MCPClient: () => BrowserMCPClient,
MCPSession: () => MCPSession,
ObservabilityManager: () => ObservabilityManager,
RemoteAgent: () => RemoteAgent,
Tel: () => Tel,
Telemetry: () => Telemetry,
VERSION: () => VERSION,
createLLMFromString: () => createLLMFromString,
createReadableStreamFromGenerator: () => createReadableStreamFromGenerator,
getPackageVersion: () => getPackageVersion,
getSupportedProviders: () => getSupportedProviders,
isValidLLMString: () => isValidLLMString,
logger: () => logger,
onMcpAuthorization: () => onMcpAuthorization,
parseLLMString: () => parseLLMString,
setBrowserTelemetrySource: () => setTelemetrySource,
setTelemetrySource: () => setTelemetrySource,
streamEventsToAISDK: () => streamEventsToAISDK,
streamEventsToAISDKWithTools: () => streamEventsToAISDKWithTools
});
module.exports = __toCommonJS(browser_exports);
// src/connectors/http.ts
var import_client = require("@mcp-use/modelcontextprotocol-sdk/client/index.js");
var import_streamableHttp = require("@mcp-use/modelcontextprotocol-sdk/client/streamableHttp.js");
init_logging();
// src/task_managers/sse.ts
var import_sse = require("@mcp-use/modelcontextprotocol-sdk/client/sse.js");
init_logging();
// src/task_managers/base.ts
init_logging();
var ConnectionManager = class {
static {
__name(this, "ConnectionManager");
}
_readyPromise;
_readyResolver;
_donePromise;
_doneResolver;
_exception = null;
_connection = null;
_task = null;
_abortController = null;
constructor() {
this.reset();
}
/**
* Start the connection manager and establish a connection.
*
* @returns The established connection.
* @throws If the connection cannot be established.
*/
async start() {
this.reset();
logger.debug(`Starting ${this.constructor.name}`);
this._task = this.connectionTask();
await this._readyPromise;
if (this._exception) {
throw this._exception;
}
if (this._connection === null) {
throw new Error("Connection was not established");
}
return this._connection;
}
/**
* Stop the connection manager and close the connection.
*/
async stop() {
if (this._task && this._abortController) {
logger.debug(`Cancelling ${this.constructor.name} task`);
this._abortController.abort();
try {
await this._task;
} catch (e) {
if (e instanceof Error && e.name === "AbortError") {
logger.debug(`${this.constructor.name} task aborted successfully`);
} else {
logger.warn(`Error stopping ${this.constructor.name} task: ${e}`);
}
}
}
await this._donePromise;
logger.debug(`${this.constructor.name} task completed`);
}
/**
* Reset all internal state.
*/
reset() {
this._readyPromise = new Promise((res) => this._readyResolver = res);
this._donePromise = new Promise((res) => this._doneResolver = res);
this._exception = null;
this._connection = null;
this._task = null;
this._abortController = new AbortController();
}
/**
* The background task responsible for establishing and maintaining the
* connection until it is cancelled.
*/
async connectionTask() {
logger.debug(`Running ${this.constructor.name} task`);
try {
this._connection = await this.establishConnection();
logger.debug(`${this.constructor.name} connected successfully`);
this._readyResolver();
await this.waitForAbort();
} catch (err) {
this._exception = err;
logger.error(`Error in ${this.constructor.name} task: ${err}`);
this._readyResolver();
} finally {
if (this._connection !== null) {
try {
await this.closeConnection(this._connection);
} catch (closeErr) {
logger.warn(
`Error closing connection in ${this.constructor.name}: ${closeErr}`
);
}
this._connection = null;
}
this._doneResolver();
}
}
/**
* Helper that returns a promise which resolves when the abort signal fires.
*/
async waitForAbort() {
return new Promise((_resolve, _reject) => {
if (!this._abortController) {
return;
}
const signal = this._abortController.signal;
if (signal.aborted) {
_resolve();
return;
}
const onAbort = /* @__PURE__ */ __name(() => {
signal.removeEventListener("abort", onAbort);
_resolve();
}, "onAbort");
signal.addEventListener("abort", onAbort);
});
}
};
// src/task_managers/sse.ts
var SseConnectionManager = class extends ConnectionManager {
static {
__name(this, "SseConnectionManager");
}
url;
opts;
_transport = null;
reinitializing = false;
/**
* Create an SSE connection manager.
*
* @param url The SSE endpoint URL.
* @param opts Optional transport options (auth, headers, etc.).
*/
constructor(url, opts) {
super();
this.url = typeof url === "string" ? new URL(url) : url;
this.opts = opts;
}
/**
* Spawn a new `SSEClientTransport` and wrap it with 404 handling.
* Per MCP spec, clients MUST re-initialize when receiving 404 for stale sessions.
*/
async establishConnection() {
const transport = new import_sse.SSEClientTransport(this.url, this.opts);
const originalSend = transport.send.bind(transport);
transport.send = async (message) => {
const sendMessage = /* @__PURE__ */ __name(async (msg) => {
if (Array.isArray(msg)) {
for (const singleMsg of msg) {
await originalSend(singleMsg);
}
} else {
await originalSend(msg);
}
}, "sendMessage");
try {
await sendMessage(message);
} catch (error) {
if (error?.code === 404 && transport.sessionId && !this.reinitializing) {
logger.warn(
`[SSE] Session not found (404), re-initializing per MCP spec...`
);
this.reinitializing = true;
try {
transport.sessionId = void 0;
await this.reinitialize(transport);
logger.info(`[SSE] Re-initialization successful, retrying request`);
await sendMessage(message);
} finally {
this.reinitializing = false;
}
} else {
throw error;
}
}
};
this._transport = transport;
logger.debug(`${this.constructor.name} connected successfully`);
return transport;
}
/**
* Re-initialize the transport with a new session
* This is called when the server returns 404 for a stale session
*/
async reinitialize(transport) {
logger.debug(`[SSE] Re-initialization triggered`);
}
/**
* Close the underlying transport and clean up resources.
*/
async closeConnection(_connection) {
if (this._transport) {
try {
await this._transport.close();
} catch (e) {
logger.warn(`Error closing SSE transport: ${e}`);
} finally {
this._transport = null;
}
}
}
};
// src/connectors/base.ts
var import_types = require("@mcp-use/modelcontextprotocol-sdk/types.js");
init_logging();
// src/telemetry/events.ts
var BaseTelemetryEvent = class {
static {
__name(this, "BaseTelemetryEvent");
}
};
var MCPAgentExecutionEvent = class extends BaseTelemetryEvent {
constructor(data) {
super();
this.data = data;
}
static {
__name(this, "MCPAgentExecutionEvent");
}
get name() {
return "mcp_agent_execution";
}
get properties() {
return {
// Core execution info
execution_method: this.data.executionMethod,
query: this.data.query,
query_length: this.data.query.length,
success: this.data.success,
// Agent configuration
model_provider: this.data.modelProvider,
model_name: this.data.modelName,
server_count: this.data.serverCount,
server_identifiers: this.data.serverIdentifiers,
total_tools_available: this.data.totalToolsAvailable,
tools_available_names: this.data.toolsAvailableNames,
max_steps_configured: this.data.maxStepsConfigured,
memory_enabled: this.data.memoryEnabled,
use_server_manager: this.data.useServerManager,
// Execution parameters (always include, even if null)
max_steps_used: this.data.maxStepsUsed,
manage_connector: this.data.manageConnector,
external_history_used: this.data.externalHistoryUsed,
// Execution results (always include, even if null)
steps_taken: this.data.stepsTaken ?? null,
tools_used_count: this.data.toolsUsedCount ?? null,
tools_used_names: this.data.toolsUsedNames ?? null,
response: this.data.response ?? null,
response_length: this.data.response ? this.data.response.length : null,
execution_time_ms: this.data.executionTimeMs ?? null,
error_type: this.data.errorType ?? null,
conversation_history_length: this.data.conversationHistoryLength ?? null
};
}
};
function createServerRunEventData(server, transport) {
const toolRegistrations = Array.from(server.registrations.tools.values());
const promptRegistrations = Array.from(server.registrations.prompts.values());
const resourceRegistrations = Array.from(
server.registrations.resources.values()
);
const templateRegistrations = Array.from(
server.registrations.resourceTemplates.values()
);
const allResources = resourceRegistrations.map((r) => ({
name: r.config.name,
title: r.config.title ?? null,
description: r.config.description ?? null,
uri: r.config.uri ?? null,
mime_type: r.config.mimeType ?? null
}));
const appsSdkResources = allResources.filter(
(r) => r.mime_type === "text/html+skybridge"
);
const mcpUiResources = allResources.filter(
(r) => r.mime_type === "text/uri-list" || r.mime_type === "text/html"
);
const mcpAppsResources = allResources.filter(
(r) => r.mime_type === "text/html+mcp"
);
return {
transport,
toolsNumber: server.registeredTools.length,
resourcesNumber: server.registeredResources.length,
promptsNumber: server.registeredPrompts.length,
auth: !!server.oauthProvider,
name: server.config.name,
description: server.config.description ?? null,
baseUrl: server.serverBaseUrl ?? null,
toolNames: server.registeredTools.length > 0 ? server.registeredTools : null,
resourceNames: server.registeredResources.length > 0 ? server.registeredResources : null,
promptNames: server.registeredPrompts.length > 0 ? server.registeredPrompts : null,
tools: toolRegistrations.length > 0 ? toolRegistrations.map((r) => ({
name: r.config.name,
title: r.config.title ?? null,
description: r.config.description ?? null,
input_schema: r.config.schema ? JSON.stringify(r.config.schema) : null,
output_schema: r.config.outputSchema ? JSON.stringify(r.config.outputSchema) : null
})) : null,
resources: allResources.length > 0 ? allResources : null,
prompts: promptRegistrations.length > 0 ? promptRegistrations.map((r) => ({
name: r.config.name,
title: r.config.title ?? null,
description: r.config.description ?? null,
args: r.config.args ? JSON.stringify(r.config.args) : null
})) : null,
templates: templateRegistrations.length > 0 ? templateRegistrations.map((r) => ({
name: r.config.name,
title: r.config.title ?? null,
description: r.config.description ?? null
})) : null,
capabilities: {
logging: true,
resources: { subscribe: true, listChanged: true }
},
appsSdkResources: appsSdkResources.length > 0 ? appsSdkResources : null,
appsSdkResourcesNumber: appsSdkResources.length,
mcpUiResources: mcpUiResources.length > 0 ? mcpUiResources : null,
mcpUiResourcesNumber: mcpUiResources.length,
mcpAppsResources: mcpAppsResources.length > 0 ? mcpAppsResources : null,
mcpAppsResourcesNumber: mcpAppsResources.length
};
}
__name(createServerRunEventData, "createServerRunEventData");
var ServerRunEvent = class extends BaseTelemetryEvent {
constructor(data) {
super();
this.data = data;
}
static {
__name(this, "ServerRunEvent");
}
get name() {
return "server_run";
}
get properties() {
return {
transport: this.data.transport,
tools_number: this.data.toolsNumber,
resources_number: this.data.resourcesNumber,
prompts_number: this.data.promptsNumber,
auth: this.data.auth,
name: this.data.name,
descript