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,622 lines (1,608 loc) 113 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 __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/client.ts var client_exports = {}; __export(client_exports, { BaseCodeExecutor: () => BaseCodeExecutor, E2BCodeExecutor: () => E2BCodeExecutor, MCPClient: () => MCPClient, MCPSession: () => MCPSession, VMCodeExecutor: () => VMCodeExecutor, isVMAvailable: () => isVMAvailable }); module.exports = __toCommonJS(client_exports); var import_node_fs2 = __toESM(require("fs"), 1); var import_node_path = __toESM(require("path"), 1); // src/logging.ts var DEFAULT_LOGGER_NAME = "mcp-use"; 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"; } } __name(resolveLevel, "resolveLevel"); function formatArgs(args) { if (args.length === 0) return ""; return args.map((arg) => { if (typeof arg === "string") return arg; try { return JSON.stringify(arg); } catch { return String(arg); } }).join(" "); } __name(formatArgs, "formatArgs"); var SimpleConsoleLogger = class { static { __name(this, "SimpleConsoleLogger"); } _level; name; format; constructor(name = DEFAULT_LOGGER_NAME, level = "info", format = "minimal") { this.name = name; this._level = level; this.format = format; } 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, args) { const timestamp = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false }); const extraArgs = formatArgs(args); const fullMessage = extraArgs ? `${message} ${extraArgs}` : message; switch (this.format) { case "detailed": return `${timestamp} [${this.name}] ${level.toUpperCase()}: ${fullMessage}`; case "emoji": { const emojiMap = { error: "\u274C", warn: "\u26A0\uFE0F", info: "\u2139\uFE0F", http: "\u{1F310}", verbose: "\u{1F4DD}", debug: "\u{1F50D}", silly: "\u{1F92A}" }; return `${timestamp} [${this.name}] ${emojiMap[level] || ""} ${level.toUpperCase()}: ${fullMessage}`; } case "minimal": default: return `${timestamp} [${this.name}] ${level}: ${fullMessage}`; } } error(message, ...args) { if (this.shouldLog("error")) { console.error(this.formatMessage("error", message, args)); } } warn(message, ...args) { if (this.shouldLog("warn")) { console.warn(this.formatMessage("warn", message, args)); } } info(message, ...args) { if (this.shouldLog("info")) { console.info(this.formatMessage("info", message, args)); } } debug(message, ...args) { if (this.shouldLog("debug")) { console.debug(this.formatMessage("debug", message, args)); } } http(message, ...args) { if (this.shouldLog("http")) { console.log(this.formatMessage("http", message, args)); } } verbose(message, ...args) { if (this.shouldLog("verbose")) { console.log(this.formatMessage("verbose", message, args)); } } silly(message, ...args) { if (this.shouldLog("silly")) { console.log(this.formatMessage("silly", message, args)); } } get level() { return this._level; } set level(newLevel) { this._level = newLevel; } setFormat(format) { this.format = format; } }; var Logger = class { static { __name(this, "Logger"); } static instances = {}; static currentFormat = "minimal"; static get(name = DEFAULT_LOGGER_NAME) { if (!this.instances[name]) { const debugEnv = typeof process !== "undefined" && process.env?.DEBUG || void 0; this.instances[name] = new SimpleConsoleLogger( name, resolveLevel(debugEnv), this.currentFormat ); } return this.instances[name]; } static configure(options = {}) { const { level, format = "minimal" } = options; const debugEnv = typeof process !== "undefined" && process.env?.DEBUG || void 0; const resolvedLevel = level ?? resolveLevel(debugEnv); this.currentFormat = format; Object.values(this.instances).forEach((logger2) => { logger2.level = resolvedLevel; logger2.setFormat(format); }); } static setDebug(enabled) { let level; if (enabled === 2 || enabled === true) level = "debug"; else if (enabled === 1) level = "info"; else level = "info"; Object.values(this.instances).forEach((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 }); } }; var logger = Logger.get(); // src/session.ts var MCPSession = class { static { __name(this, "MCPSession"); } connector; autoConnect; constructor(connector, autoConnect = true) { this.connector = connector; this.autoConnect = autoConnect; } async connect() { await this.connector.connect(); } async disconnect() { await this.connector.disconnect(); } async initialize() { if (!this.isConnected && this.autoConnect) { await this.connect(); } await this.connector.initialize(); } get isConnected() { return this.connector && this.connector.isClientConnected; } /** * Register an event handler for session events * * @param event - The event type to listen for * @param handler - The handler function to call when the event occurs * * @example * ```typescript * session.on("notification", async (notification) => { * console.log(`Received: ${notification.method}`, notification.params); * * if (notification.method === "notifications/tools/list_changed") { * // Refresh tools list * } * }); * ``` */ on(event, handler) { if (event === "notification") { this.connector.onNotification(handler); } } /** * Set roots and notify the server. * Roots represent directories or files that the client has access to. * * @param roots - Array of Root objects with `uri` (must start with "file://") and optional `name` * * @example * ```typescript * await session.setRoots([ * { uri: "file:///home/user/project", name: "My Project" }, * { uri: "file:///home/user/data" } * ]); * ``` */ async setRoots(roots) { return this.connector.setRoots(roots); } /** * Get the current roots. */ getRoots() { return this.connector.getRoots(); } /** * Get the cached list of tools from the server. * * @returns Array of available tools * * @example * ```typescript * const tools = session.tools; * console.log(`Available tools: ${tools.map(t => t.name).join(", ")}`); * ``` */ get tools() { return this.connector.tools; } /** * List all available tools from the MCP server. * This method fetches fresh tools from the server, unlike the `tools` getter which returns cached tools. * * @param options - Optional request options * @returns Array of available tools * * @example * ```typescript * const tools = await session.listTools(); * console.log(`Available tools: ${tools.map(t => t.name).join(", ")}`); * ``` */ async listTools(options) { return this.connector.listTools(options); } /** * Get the server capabilities advertised during initialization. * * @returns Server capabilities object */ get serverCapabilities() { return this.connector.serverCapabilities; } /** * Get the server information (name and version). * * @returns Server info object or null if not available */ get serverInfo() { return this.connector.serverInfo; } /** * Call a tool on the server. * * @param name - Name of the tool to call * @param args - Arguments to pass to the tool (defaults to empty object) * @param options - Optional request options (timeout, progress handlers, etc.) * @returns Result from the tool execution * * @example * ```typescript * const result = await session.callTool("add", { a: 5, b: 3 }); * console.log(`Result: ${result.content[0].text}`); * ``` */ async callTool(name, args = {}, options) { return this.connector.callTool(name, args, options); } /** * List resources from the server with optional pagination. * * @param cursor - Optional cursor for pagination * @param options - Request options * @returns Resource list with optional nextCursor for pagination * * @example * ```typescript * const result = await session.listResources(); * console.log(`Found ${result.resources.length} resources`); * ``` */ async listResources(cursor, options) { return this.connector.listResources(cursor, options); } /** * List all resources from the server, automatically handling pagination. * * @param options - Request options * @returns Complete list of all resources * * @example * ```typescript * const result = await session.listAllResources(); * console.log(`Total resources: ${result.resources.length}`); * ``` */ async listAllResources(options) { return this.connector.listAllResources(options); } /** * List resource templates from the server. * * @param options - Request options * @returns List of available resource templates * * @example * ```typescript * const result = await session.listResourceTemplates(); * console.log(`Available templates: ${result.resourceTemplates.length}`); * ``` */ async listResourceTemplates(options) { return this.connector.listResourceTemplates(options); } /** * Read a resource by URI. * * @param uri - URI of the resource to read * @param options - Request options * @returns Resource content * * @example * ```typescript * const resource = await session.readResource("file:///path/to/file.txt"); * console.log(resource.contents); * ``` */ async readResource(uri, options) { return this.connector.readResource(uri, options); } /** * Subscribe to resource updates. * * @param uri - URI of the resource to subscribe to * @param options - Request options * * @example * ```typescript * await session.subscribeToResource("file:///path/to/file.txt"); * // Now you'll receive notifications when this resource changes * ``` */ async subscribeToResource(uri, options) { return this.connector.subscribeToResource(uri, options); } /** * Unsubscribe from resource updates. * * @param uri - URI of the resource to unsubscribe from * @param options - Request options * * @example * ```typescript * await session.unsubscribeFromResource("file:///path/to/file.txt"); * ``` */ async unsubscribeFromResource(uri, options) { return this.connector.unsubscribeFromResource(uri, options); } /** * List available prompts from the server. * * @returns List of available prompts * * @example * ```typescript * const result = await session.listPrompts(); * console.log(`Available prompts: ${result.prompts.length}`); * ``` */ async listPrompts() { return this.connector.listPrompts(); } /** * Get a specific prompt with arguments. * * @param name - Name of the prompt to get * @param args - Arguments for the prompt * @returns Prompt result * * @example * ```typescript * const prompt = await session.getPrompt("greeting", { name: "Alice" }); * console.log(prompt.messages); * ``` */ async getPrompt(name, args) { return this.connector.getPrompt(name, args); } /** * Send a raw request through the client. * * @param method - MCP method name * @param params - Request parameters * @param options - Request options * @returns Response from the server * * @example * ```typescript * const result = await session.request("custom/method", { key: "value" }); * ``` */ async request(method, params = null, options) { return this.connector.request(method, params, options); } }; // 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, description: this.data.description ?? null, base_url: this.data.baseUrl ?? null, tool_names: this.data.toolNames ?? null, resource_names: this.data.resourceNames ?? null, prompt_names: this.data.promptNames ?? null, tools: this.data.tools ?? null, resources: this.data.resources ?? null, prompts: this.data.prompts ?? null, templates: this.data.templates ?? null, capabilities: this.data.capabilities ? JSON.stringify(this.data.capabilities) : null, apps_sdk_resources: this.data.appsSdkResources ? JSON.stringify(this.data.appsSdkResources) : null, apps_sdk_resources_number: this.data.appsSdkResourcesNumber ?? 0, mcp_ui_resources: this.data.mcpUiResources ? JSON.stringify(this.data.mcpUiResources) : null, mcp_ui_resources_number: this.data.mcpUiResourcesNumber ?? 0, mcp_apps_resources: this.data.mcpAppsResources ? JSON.stringify(this.data.mcpAppsResources) : null, mcp_apps_resources_number: this.data.mcpAppsResourcesNumber ?? 0 }; } }; var ServerInitializeEvent = class extends BaseTelemetryEvent { constructor(data) { super(); this.data = data; } static { __name(this, "ServerInitializeEvent"); } get name() { return "server_initialize_call"; } get properties() { return { protocol_version: this.data.protocolVersion, client_info: JSON.stringify(this.data.clientInfo), client_capabilities: JSON.stringify(this.data.clientCapabilities), session_id: this.data.sessionId ?? null }; } }; var ServerToolCallEvent = class extends BaseTelemetryEvent { constructor(data) { super(); this.data = data; } static { __name(this, "ServerToolCallEvent"); } get name() { return "server_tool_call"; } get properties() { return { tool_name: this.data.toolName, length_input_argument: this.data.lengthInputArgument, success: this.data.success, error_type: this.data.errorType ?? null, execution_time_ms: this.data.executionTimeMs ?? null }; } }; var ServerResourceCallEvent = class extends BaseTelemetryEvent { constructor(data) { super(); this.data = data; } static { __name(this, "ServerResourceCallEvent"); } get name() { return "server_resource_call"; } get properties() { return { name: this.data.name, description: this.data.description, contents: this.data.contents, success: this.data.success, error_type: this.data.errorType ?? null }; } }; var ServerPromptCallEvent = class extends BaseTelemetryEvent { constructor(data) { super(); this.data = data; } static { __name(this, "ServerPromptCallEvent"); } get name() { return "server_prompt_call"; } get properties() { return { name: this.data.name, description: this.data.description, success: this.data.success, error_type: this.data.errorType ?? null }; } }; var ServerContextEvent = class extends BaseTelemetryEvent { constructor(data) { super(); this.data = data; } static { __name(this, "ServerContextEvent"); } get name() { return `server_context_${this.data.contextType}`; } get properties() { return { context_type: this.data.contextType, notification_type: this.data.notificationType ?? null }; } }; var MCPClientInitEvent = class extends BaseTelemetryEvent { constructor(data) { super(); this.data = data; } static { __name(this, "MCPClientInitEvent"); } get name() { return "mcpclient_init"; } get properties() { return { code_mode: this.data.codeMode, sandbox: this.data.sandbox, all_callbacks: this.data.allCallbacks, verify: this.data.verify, servers: this.data.servers, num_servers: this.data.numServers, is_browser: this.data.isBrowser }; } }; var ConnectorInitEvent = class extends BaseTelemetryEvent { constructor(data) { super(); this.data = data; } static { __name(this, "ConnectorInitEvent"); } get name() { return "connector_init"; } get properties() { return { connector_type: this.data.connectorType, server_command: this.data.serverCommand ?? null, server_args: this.data.serverArgs ?? null, server_url: this.data.serverUrl ?? null, public_identifier: this.data.publicIdentifier ?? null }; } }; var ClientAddServerEvent = class extends BaseTelemetryEvent { constructor(data) { super(); this.data = data; } static { __name(this, "ClientAddServerEvent"); } get name() { return "client_add_server"; } get properties() { const { serverName, serverConfig } = this.data; const url = serverConfig.url; return { server_name: serverName, server_url_domain: url ? this._extractHostname(url) : null, transport: serverConfig.transport ?? null, has_auth: !!(serverConfig.authToken || serverConfig.authProvider) }; } _extractHostname(url) { try { return new URL(url).hostname; } catch { return null; } } }; var ClientRemoveServerEvent = class extends BaseTelemetryEvent { constructor(data) { super(); this.data = data; } static { __name(this, "ClientRemoveServerEvent"); } get name() { return "client_remove_server"; } get properties() { return { server_name: this.data.serverName }; } }; // src/version.ts var VERSION = "1.12.4"; function getPackageVersion() { return VERSION; } __name(getPackageVersion, "getPackageVersion"); // src/telemetry/telemetry-browser.ts function generateUUID() { if (typeof globalThis !== "undefined" && globalThis.crypto && typeof globalThis.crypto.randomUUID === "function") { return globalThis.crypto.randomUUID(); } if (typeof globalThis !== "undefined" && globalThis.crypto && typeof globalThis.crypto.getRandomValues === "function") { const array = new Uint8Array(16); globalThis.crypto.getRandomValues(array); const hex = Array.from(array, (v) => v.toString(16).padStart(2, "0")).join( "" ); return `${hex.substring(0, 8)}-${hex.substring(8, 12)}-${hex.substring(12, 16)}-${hex.substring(16, 20)}-${hex.substring(20)}`; } return `${Date.now()}-${Math.random().toString(36).substring(2, 15)}-${Math.random().toString(36).substring(2, 15)}`; } __name(generateUUID, "generateUUID"); function secureRandomString() { if (typeof window !== "undefined" && window.crypto && typeof window.crypto.getRandomValues === "function") { const array = new Uint8Array(8); window.crypto.getRandomValues(array); return Array.from(array, (v) => v.toString(16).padStart(2, "0")).join(""); } if (typeof globalThis !== "undefined" && globalThis.crypto && typeof globalThis.crypto.getRandomValues === "function") { const array = new Uint8Array(8); globalThis.crypto.getRandomValues(array); return Array.from(array, (v) => v.toString(16).padStart(2, "0")).join(""); } return Math.random().toString(36).substring(2, 15); } __name(secureRandomString, "secureRandomString"); var USER_ID_STORAGE_KEY = "mcp_use_user_id"; function detectRuntimeEnvironment() { try { if (typeof window !== "undefined" && typeof document !== "undefined") { return "browser"; } return "unknown"; } catch { return "unknown"; } } __name(detectRuntimeEnvironment, "detectRuntimeEnvironment"); function getStorageCapability(env) { if (env === "browser") { try { if (typeof localStorage !== "undefined") { localStorage.setItem("__mcp_use_test__", "1"); localStorage.removeItem("__mcp_use_test__"); return "localStorage"; } } catch { } } return "session-only"; } __name(getStorageCapability, "getStorageCapability"); var cachedEnvironment = null; function getRuntimeEnvironment() { if (cachedEnvironment === null) { cachedEnvironment = detectRuntimeEnvironment(); } return cachedEnvironment; } __name(getRuntimeEnvironment, "getRuntimeEnvironment"); var Telemetry = class _Telemetry { static { __name(this, "Telemetry"); } static instance = null; PROJECT_API_KEY = "phc_lyTtbYwvkdSbrcMQNPiKiiRWrrM1seyKIMjycSvItEI"; HOST = "https://eu.i.posthog.com"; UNKNOWN_USER_ID = "UNKNOWN_USER_ID"; _currUserId = null; _posthogBrowserClient = null; _posthogLoading = null; _runtimeEnvironment; _storageCapability; _source; constructor() { this._runtimeEnvironment = getRuntimeEnvironment(); this._storageCapability = getStorageCapability(this._runtimeEnvironment); this._source = this._getSourceFromLocalStorage() || this._runtimeEnvironment; const telemetryDisabled = this._checkTelemetryDisabled(); const canSupportTelemetry = this._runtimeEnvironment !== "unknown"; if (telemetryDisabled) { this._posthogBrowserClient = null; logger.debug("Telemetry disabled via localStorage"); } else if (!canSupportTelemetry) { this._posthogBrowserClient = null; logger.debug( `Telemetry disabled - unknown environment: ${this._runtimeEnvironment}` ); } else { logger.info( "Anonymized telemetry enabled. Set MCP_USE_ANONYMIZED_TELEMETRY=false in localStorage to disable." ); this._posthogLoading = this._initPostHogBrowser(); } } _getSourceFromLocalStorage() { try { if (typeof localStorage !== "undefined") { return localStorage.getItem("MCP_USE_TELEMETRY_SOURCE"); } } catch { } return null; } _checkTelemetryDisabled() { if (typeof localStorage !== "undefined" && localStorage.getItem("MCP_USE_ANONYMIZED_TELEMETRY") === "false") { return true; } return false; } async _initPostHogBrowser() { try { const posthogModule = await import("posthog-js"); const posthogModuleTyped = posthogModule; const posthog = posthogModuleTyped.default || posthogModuleTyped.posthog; if (!posthog || typeof posthog.init !== "function") { throw new Error("posthog-js module did not export expected interface"); } posthog.init(this.PROJECT_API_KEY, { api_host: this.HOST, persistence: "localStorage", autocapture: false, // We only want explicit captures capture_pageview: false, // We don't want automatic pageview tracking disable_session_recording: true, // No session recording loaded: /* @__PURE__ */ __name(() => { logger.debug("PostHog browser client initialized"); }, "loaded") }); this._posthogBrowserClient = posthog; } catch (e) { logger.warn(`Failed to initialize PostHog browser telemetry: ${e}`); this._posthogBrowserClient = null; } } /** * Get the detected runtime environment */ get runtimeEnvironment() { return this._runtimeEnvironment; } /** * Get the storage capability for this environment */ get storageCapability() { return this._storageCapability; } static getInstance() { if (!_Telemetry.instance) { _Telemetry.instance = new _Telemetry(); } return _Telemetry.instance; } /** * Set the source identifier for telemetry events. * This allows tracking usage from different applications. * @param source - The source identifier (e.g., "my-app", "cli", "vs-code-extension") */ setSource(source) { this._source = source; try { if (typeof localStorage !== "undefined") { localStorage.setItem("MCP_USE_TELEMETRY_SOURCE", source); } } catch { } logger.debug(`Telemetry source set to: ${source}`); } /** * Get the current source identifier. */ getSource() { return this._source; } /** * Check if telemetry is enabled. */ get isEnabled() { return this._posthogBrowserClient !== null; } get userId() { if (this._currUserId) { return this._currUserId; } try { switch (this._storageCapability) { case "localStorage": this._currUserId = this._getUserIdFromLocalStorage(); break; case "session-only": default: try { this._currUserId = `session-${generateUUID()}`; } catch (uuidError) { this._currUserId = `session-${Date.now()}-${secureRandomString()}`; } break; } } catch (e) { this._currUserId = this.UNKNOWN_USER_ID; } return this._currUserId; } /** * Get or create user ID from localStorage (Browser) */ _getUserIdFromLocalStorage() { try { if (typeof localStorage === "undefined") { throw new Error("localStorage is not available"); } try { localStorage.setItem("__mcp_use_test__", "1"); localStorage.removeItem("__mcp_use_test__"); } catch (testError) { throw new Error(`localStorage is not writable: ${testError}`); } let userId = localStorage.getItem(USER_ID_STORAGE_KEY); if (!userId) { try { userId = generateUUID(); } catch (uuidError) { userId = `${Date.now()}-${secureRandomString()}`; } localStorage.setItem(USER_ID_STORAGE_KEY, userId); } return userId; } catch (e) { logger.debug(`Failed to access localStorage for user ID: ${e}`); let sessionId; try { sessionId = `session-${generateUUID()}`; } catch (uuidError) { sessionId = `session-${Date.now()}-${secureRandomString()}`; } return sessionId; } } async capture(event) { if (this._posthogLoading) { await this._posthogLoading; } if (!this._posthogBrowserClient) { return; } const currentUserId = this.userId; const properties = { ...event.properties }; properties.mcp_use_version = getPackageVersion(); properties.language = "typescript"; properties.source = this._source; properties.runtime = this._runtimeEnvironment; if (this._posthogBrowserClient) { try { this._posthogBrowserClient.capture(event.name, { ...properties, distinct_id: currentUserId }); } catch (e) { logger.debug( `Failed to track PostHog Browser event ${event.name}: ${e}` ); } } } // ============================================================================ // Agent Events // ============================================================================ async trackAgentExecution(data) { if (!this.isEnabled) return; const event = new MCPAgentExecutionEvent(data); await this.capture(event); } // ============================================================================ // Server Events // ============================================================================ /** * Track server run event directly from an MCPServer instance. */ async trackServerRunFromServer(server, transport) { if (!this.isEnabled) return; const data = createServerRunEventData(server, transport); const event = new ServerRunEvent(data); await this.capture(event); } async trackServerInitialize(data) { if (!this.isEnabled) return; const event = new ServerInitializeEvent(data); await this.capture(event); } async trackServerToolCall(data) { if (!this.isEnabled) return; const event = new ServerToolCallEvent(data); await this.capture(event); } async trackServerResourceCall(data) { if (!this.isEnabled) return; const event = new ServerResourceCallEvent(data); await this.capture(event); } async trackServerPromptCall(data) { if (!this.isEnabled) return; const event = new ServerPromptCallEvent(data); await this.capture(event); } async trackServerContext(data) { if (!this.isEnabled) return; const event = new ServerContextEvent(data); await this.capture(event); } // ============================================================================ // Client Events // ============================================================================ async trackMCPClientInit(data) { if (!this.isEnabled) return; const event = new MCPClientInitEvent(data); await this.capture(event); } async trackConnectorInit(data) { if (!this.isEnabled) return; const event = new ConnectorInitEvent(data); await this.capture(event); } async trackClientAddServer(serverName, serverConfig) { if (!this.isEnabled) return; const event = new ClientAddServerEvent({ serverName, serverConfig }); await this.capture(event); } async trackClientRemoveServer(serverName) { if (!this.isEnabled) return; const event = new ClientRemoveServerEvent({ serverName }); await this.capture(event); } // ============================================================================ // React Hook / Browser specific events // ============================================================================ async trackUseMcpConnection(data) { if (!this.isEnabled) return; await this.capture({ name: "usemcp_connection", properties: { url_domain: new URL(data.url).hostname, // Only domain for privacy transport_type: data.transportType, success: data.success, error_type: data.errorType ?? null, connection_time_ms: data.connectionTimeMs ?? null, has_oauth: data.hasOAuth, has_sampling: data.hasSampling, has_elicitation: data.hasElicitation } }); } async trackUseMcpToolCall(data) { if (!this.isEnabled) return; await this.capture({ name: "usemcp_tool_call", properties: { tool_name: data.toolName, success: data.success, error_type: data.errorType ?? null, execution_time_ms: data.executionTimeMs ?? null } }); } async trackUseMcpResourceRead(data) { if (!this.isEnabled) return; await this.capture({ name: "usemcp_resource_read", properties: { resource_uri_scheme: data.resourceUri.split(":")[0], // Only scheme for privacy success: data.success, error_type: data.errorType ?? null } }); } // ============================================================================ // Browser-specific Methods // ============================================================================ /** * Identify the current user (useful for linking sessions) * Browser only */ identify(userId, properties) { if (this._posthogBrowserClient) { try { this._posthogBrowserClient.identify(userId, properties); } catch (e) { logger.debug(`Failed to identify user: ${e}`); } } } /** * Reset the user identity (useful for logout) * Browser only */ reset() { if (this._posthogBrowserClient) { try { this._posthogBrowserClient.reset(); } catch (e) { logger.debug(`Failed to reset user: ${e}`); } } this._currUserId = null; } // ============================================================================ // Node.js-specific Methods (no-ops in browser) // ============================================================================ /** * Flush the telemetry queue (Node.js only - no-op in browser) */ flush() { } /** * Shutdown the telemetry client (Node.js only - no-op in browser) */ shutdown() { } /** * Track package download event (Node.js only - no-op in browser) */ async trackPackageDownload(properties) { } }; var Tel = Telemetry; // src/client/base.ts var BaseMCPClient = class { static { __name(this, "BaseMCPClient"); } config = {}; sessions = {}; activeSessions = []; constructor(config) { if (config) { this.config = config; } } static fromDict(_cfg) { throw new Error("fromDict must be implemented by concrete class"); } addServer(name, serverConfig) { this.config.mcpServers = this.config.mcpServers || {}; this.config.mcpServers[name] = serverConfig; Tel.getInstance().trackClientAddServer(name, serverConfig); } removeServer(name) { if (this.config.mcpServers?.[name]) { delete this.config.mcpServers[name]; this.activeSessions = this.activeSessions.filter((n) => n !== name); Tel.getInstance().trackClientRemoveServer(name); } } getServerNames() { return Object.keys(this.config.mcpServers ?? {}); } getServerConfig(name) { return this.config.mcpServers?.[name]; } getConfig() { return this.config ?? {}; } async createSession(serverName, autoInitialize = true) { const servers = this.config.mcpServers ?? {}; if (Object.keys(servers).length === 0) { logger.warn("No MCP servers defined in config"); } if (!servers[serverName]) { throw new Error(`Server '${serverName}' not found in config`); } const connector = this.createConnectorFromConfig(servers[serverName]); const session = new MCPSession(connector); if (autoInitialize) { await session.initialize(); } this.sessions[serverName] = session; if (!this.activeSessions.includes(serverName)) { this.activeSessions.push(serverName); } return session; } async createAllSessions(autoInitialize = true) { const servers = this.config.mcpServers ?? {}; if (Object.keys(servers).length === 0) { logger.warn("No MCP servers defined in config"); } for (const name of Object.keys(servers)) { await this.createSession(name, autoInitialize); } return this.sessions; } getSession(serverName) { const session = this.sessions[serverName]; if (!session) { return null; } return session; } requireSession(serverName) { const session = this.sessions[serverName]; if (!session) { throw new Error( `Session '${serverName}' not found. Available sessions: ${this.activeSessions.join(", ") || "none"}` ); } return session; } getAllActiveSessions() { return Object.fromEntries( this.activeSessions.map((n) => [n, this.sessions[n]]) ); } async closeSession(serverName) { const session = this.sessions[serverName]; if (!session) { logger.warn( `No session exists for server ${serverName}, nothing to close` ); return; } try { logger.debug(`Closing session for server ${serverName}`); await session.disconnect(); } catch (e) { logger.error(`Error closing session for server '${serverName}': ${e}`); } finally { delete this.sessions[serverName]; this.activeSessions = this.activeSessions.filter((n) => n !== serverName); } } async closeAllSessions() { const serverNames = Object.keys(this.sessions); const errors = []; for (const serverName of serverNames) { try { logger.debug(`Closing session for server ${serverName}`); await this.closeSession(serverName); } catch (e) { const errorMsg = `Failed to close session for server '${serverName}': ${e}`; logger.error(errorMsg); errors.push(errorMsg); } } if (errors.length) { logger.error( `Encountered ${errors.length} errors while closing sessions` ); } else { logger.debug("All sessions closed successfully"); } } }; // src/client/executors/base.ts var BaseCodeExecutor = class { static { __name(this, "BaseCodeExecutor"); } client; _connecting = false; constructor(client) { this.client = client; } /** * Ensure all configured MCP servers are connected before execution. * Prevents race conditions with a connection lock. */ async ensureServersConnected() { const configuredServers = this.client.getServerNames(); const activeSessions = Object.keys(this.client.getAllActiveSessions()); const missingServers = configuredServers.filter( (s) => !activeSessions.includes(s) ); if (missingServers.length > 0 && !this._connecting) { this._connecting = true; try { logger.debug( `Connecting to configured servers for code execution: ${missingServers.join(", ")}` ); await this.client.createAllSessions(); } finally { this._connecting = false; } } else if (missingServers.length > 0 && this._connecting) { logger.debug("Waiting for ongoing server connection..."); const startWait = Date.now(); while (this._connecting && Date.now() - startWait < 5e3) { await new Promise((resolve) => setTimeout(resolve, 100)); } } } /** * Get tool namespace information from all active MCP sessions. * Filters out the internal code_mode server. */ getToolNamespaces() { const namespaces = []; const activeSessions = this.client.getAllActiveSessions(); for (const [serverName, session] of Object.entries(activeSessions)) { if (serverName === "code_mode") continue; try { const connector = session.connector; let tools; try { tools = connector.tools; } catch (e) { logger.warn(`Tools not available for server ${serverName}: ${e}`); continue; } if (!tools || tools.length === 0) continue; namespaces.push({ serverName, tools, session }); } catch (e) { logger.warn(`Failed to load tools for server ${serverName}: ${e}`); } } return namespaces; } /** * Create a search function for discovering available MCP tools. * Used by code execution environments to find tools at runtime. */ createSearchToolsFunction() { return async (query = "", detailLevel = "full") => { const allTools = []; const allNamespaces = /* @__PURE__ */ new Set(); const queryLower = query.toLowerCase(); const activeSessions = this.client.getAllActiveSessions(); for (const [serverName, session] of Object.entries(activeSessions)) { if (serverName === "code_mode") continue; try { const tools = session.connector.tools; if (tools && tools.length > 0) { allNamespaces.add(serverName); } for (const tool of tools) { if (detailLevel === "names") { allTools.push({ name: tool.name, server: serverName }); } else if (detailLevel === "descriptions") { allTools.push({ name: tool.name, server: serverName, description: tool.description }); } else { allTools.push({ name: tool.name, server: serverName, description: tool.description, input_schema: tool.inputSchema }); } } } catch (e) { logger.warn(`Failed to search tools in server ${serverName}: ${e}`); } } let filteredTools = allTools; if (query) { filteredTools = allTools.filter((tool) => { const nameMatch = tool.name.toLowerCase().includes(queryLower); const descMatch = tool.description?.toLowerCase().includes(queryLower); const serverMatch = tool.server.toLowerCase().includes(queryLower); return nameMatch || descMatch || serverMatch; }); } return { meta: { total_tools: allTools.length, namespaces: Array.from(allNamespaces).sort(), result_count: filteredTools.length }, results: filteredTools }; }; } }; // src/client/executors/e2b.ts var E2BCodeExecutor = class extends BaseCodeExecutor { static { __name(this, "E2BCodeExecutor"); } e2bApiKey; codeExecSandbox = null; SandboxClass = null; timeoutMs; constructor(client, options) { super(client); this.e2bApiKey = options.apiKey; this.timeoutMs = options.timeoutMs ?? 3e5; } /** * Lazy load E2B Sandbox class. * This allows the library to work without E2B installed. */ async ensureSandboxClass() { if (this.SandboxClass) return; try { const e2b = await import("@e2b/code-interpreter"); this.SandboxClass = e2b.Sandbox; } catch (error) { throw new Error( "@e2b/code-interpreter is not installed. The E2B code executor requires this optional dependency. Install it with: yarn add @e2b/code-interpreter" ); } } /** * Get or create a dedicated sandbox for code execution. */ async getOrCreateCodeExecSandbox() { if (this.codeExecSandbox) return this.codeExecSandbox; await this.ensureSandboxClass(); logger.debug("Starting E2B sandbox for code execution..."); this.codeExecSandbox = await this.SandboxClass.create("base", { apiKey: this.e2bApiKey, timeoutMs: this.timeoutMs }); return this.codeExecSandbox; } /** * Generate the shim code that exposes tools to the sandbox environment. * Creates a bridge that intercepts tool calls and sends them back to host. */ generateShim(tools) { let shim = ` // MCP Bridge Shim global.__callMcpTool = async (server, tool, args) => { const id = Math.random().toString(36).substring(7); console.log(JSON.stringify({ type: '__MCP_TOOL_CALL__', id, server, tool, args })); const resultPath = \`/tmp/mcp_result_\${id}.json\`; const fs = require('fs'); // Poll for result file let attempts = 0; while (attempts < 300) { // 30 seconds timeout if (fs.existsSync(resultPath)) { const content = fs.readFileSync(resultPath, 'utf8'); const result = JSON.parse(content); fs.unlinkSync(resultPath); // Clean up if (result.error) { throw new Error(result.error); } return result.data; } await new Promise(resolve => setTimeout(resolve, 100)); attempts++; } throw new Error('Tool execution timed out'); }; // Global search_tools helper global.search_tools = async (query, detailLevel = 'full') => { const allTools = ${JSON.stringify( Object.entries(tools).flatMap( ([server, serverTools]) => serverTools.map((tool) => ({ name: tool.name, description: tool.description, server, input_schema: tool.inputSchema })) ) )}; const filtered = allTools.filter(tool => { if (!query) return true; const q = query.toLowerCase(); return tool.name.