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
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 __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.