mcp-use
Version:
Opinionated MCP Framework for TypeScript (@modelcontextprotocol/sdk compatible) - Build MCP Agents and Clients + MCP Servers with support for MCP-UI.
1,473 lines (1,443 loc) • 92.9 kB
JavaScript
import {
logger
} from "./chunk-34R6SIER.js";
import {
__name
} from "./chunk-3GQAWCBQ.js";
// src/adapters/base.ts
var BaseAdapter = class {
static {
__name(this, "BaseAdapter");
}
/**
* List of tool names that should not be available.
*/
disallowedTools;
/**
* Internal cache that maps a connector instance to the list of tools
* generated for it.
*/
connectorToolMap = /* @__PURE__ */ new Map();
constructor(disallowedTools) {
this.disallowedTools = disallowedTools ?? [];
}
/**
* Create tools from an MCPClient instance.
*
* This is the recommended way to create tools from an MCPClient, as it handles
* session creation and connector extraction automatically.
*
* @param client The MCPClient to extract tools from.
* @param disallowedTools Optional list of tool names to exclude.
* @returns A promise that resolves with a list of converted tools.
*/
static async createTools(client, disallowedTools) {
const adapter = new this(disallowedTools);
if (!client.activeSessions || Object.keys(client.activeSessions).length === 0) {
logger.info("No active sessions found, creating new ones...");
await client.createAllSessions();
}
const sessions = client.getAllActiveSessions();
const connectors = Object.values(sessions).map(
(session) => session.connector
);
return adapter.createToolsFromConnectors(connectors);
}
/**
* Dynamically load tools for a specific connector.
*
* @param connector The connector to load tools for.
* @returns The list of tools that were loaded in the target framework's format.
*/
async loadToolsForConnector(connector) {
if (this.connectorToolMap.has(connector)) {
const cached = this.connectorToolMap.get(connector);
logger.debug(`Returning ${cached.length} existing tools for connector`);
return cached;
}
const connectorTools = [];
const success = await this.ensureConnectorInitialized(connector);
if (!success) {
return [];
}
for (const tool of connector.tools) {
const converted = this.convertTool(tool, connector);
if (converted) {
connectorTools.push(converted);
}
}
this.connectorToolMap.set(connector, connectorTools);
logger.debug(
`Loaded ${connectorTools.length} new tools for connector: ${connectorTools.map((t) => t?.name ?? String(t)).join(", ")}`
);
return connectorTools;
}
/**
* Create tools from MCP tools in all provided connectors.
*
* @param connectors List of MCP connectors to create tools from.
* @returns A promise that resolves with all converted tools.
*/
async createToolsFromConnectors(connectors) {
const tools = [];
for (const connector of connectors) {
const connectorTools = await this.loadToolsForConnector(connector);
tools.push(...connectorTools);
}
logger.debug(`Available tools: ${tools.length}`);
return tools;
}
/**
* Check if a connector is initialized and has tools.
*
* @param connector The connector to check.
* @returns True if the connector is initialized and has tools, false otherwise.
*/
checkConnectorInitialized(connector) {
return Boolean(connector.tools && connector.tools.length);
}
/**
* Ensure a connector is initialized.
*
* @param connector The connector to initialize.
* @returns True if initialization succeeded, false otherwise.
*/
async ensureConnectorInitialized(connector) {
if (!this.checkConnectorInitialized(connector)) {
logger.debug("Connector doesn't have tools, initializing it");
try {
await connector.initialize();
return true;
} catch (err) {
logger.error(`Error initializing connector: ${err}`);
return false;
}
}
return true;
}
};
// src/adapters/langchain_adapter.ts
import { JSONSchemaToZod } from "@dmitryrechkin/json-schema-to-zod";
import { DynamicStructuredTool } from "@langchain/core/tools";
import { z } from "zod";
function schemaToZod(schema) {
try {
return JSONSchemaToZod.convert(schema);
} catch (err) {
logger.warn(`Failed to convert JSON schema to Zod: ${err}`);
return z.any();
}
}
__name(schemaToZod, "schemaToZod");
var LangChainAdapter = class extends BaseAdapter {
static {
__name(this, "LangChainAdapter");
}
constructor(disallowedTools = []) {
super(disallowedTools);
}
/**
* Convert a single MCP tool specification into a LangChainJS structured tool.
*/
convertTool(mcpTool, connector) {
if (this.disallowedTools.includes(mcpTool.name)) {
return null;
}
const argsSchema = mcpTool.inputSchema ? schemaToZod(mcpTool.inputSchema) : z.object({}).optional();
const tool = new DynamicStructuredTool({
name: mcpTool.name ?? "NO NAME",
description: mcpTool.description ?? "",
// Blank is acceptable but discouraged.
schema: argsSchema,
func: /* @__PURE__ */ __name(async (input) => {
logger.debug(
`MCP tool "${mcpTool.name}" received input: ${JSON.stringify(input)}`
);
try {
const result = await connector.callTool(
mcpTool.name,
input
);
return JSON.stringify(result);
} catch (err) {
logger.error(`Error executing MCP tool: ${err.message}`);
return `Error executing MCP tool: ${String(err)}`;
}
}, "func")
});
return tool;
}
};
// src/managers/tools/acquire_active_mcp_server.ts
import { z as z2 } from "zod";
// src/managers/tools/base.ts
import { StructuredTool } from "@langchain/core/tools";
var MCPServerTool = class extends StructuredTool {
static {
__name(this, "MCPServerTool");
}
name = "mcp_server_tool";
description = "Base tool for MCP server operations.";
schema;
_manager;
constructor(manager) {
super();
this._manager = manager;
}
async _call(_arg, _runManager, _parentConfig) {
throw new Error("Method not implemented.");
}
get manager() {
return this._manager;
}
};
// src/managers/tools/acquire_active_mcp_server.ts
var PresentActiveServerSchema = z2.object({});
var AcquireActiveMCPServerTool = class extends MCPServerTool {
static {
__name(this, "AcquireActiveMCPServerTool");
}
name = "get_active_mcp_server";
description = "Get the currently active MCP (Model Context Protocol) server";
schema = PresentActiveServerSchema;
constructor(manager) {
super(manager);
}
async _call() {
if (!this.manager.activeServer) {
return `No MCP server is currently active. Use connect_to_mcp_server to connect to a server.`;
}
return `Currently active MCP server: ${this.manager.activeServer}`;
}
};
// src/managers/tools/add_server_from_config.ts
import { StructuredTool as StructuredTool2 } from "@langchain/core/tools";
import { z as z3 } from "zod";
var AddMCPServerFromConfigTool = class extends StructuredTool2 {
static {
__name(this, "AddMCPServerFromConfigTool");
}
name = "add_mcp_server_from_config";
description = "Adds a new MCP server to the client from a configuration object and connects to it, making its tools available.";
schema = z3.object({
serverName: z3.string().describe("The name for the new MCP server."),
serverConfig: z3.any().describe(
'The configuration object for the server. This should not include the top-level "mcpServers" key.'
)
});
manager;
constructor(manager) {
super();
this.manager = manager;
}
async _call({
serverName,
serverConfig
}) {
try {
this.manager.client.addServer(serverName, serverConfig);
let result = `Server '${serverName}' added to the client.`;
logger.debug(
`Connecting to new server '${serverName}' and discovering tools.`
);
const session = await this.manager.client.createSession(serverName);
const connector = session.connector;
const tools = await this.manager.adapter.createToolsFromConnectors([connector]);
this.manager.serverTools[serverName] = tools;
this.manager.initializedServers[serverName] = true;
this.manager.activeServer = serverName;
const numTools = tools.length;
result += ` Session created and connected. '${serverName}' is now the active server with ${numTools} tools available.`;
result += `
${tools.map((t) => t.name).join("\n")}`;
logger.info(result);
return result;
} catch (e) {
logger.error(
`Failed to add or connect to server '${serverName}': ${e.message}`
);
return `Failed to add or connect to server '${serverName}': ${e.message}`;
}
}
};
// src/managers/tools/connect_mcp_server.ts
import { z as z4 } from "zod";
var ConnectMCPServerSchema = z4.object({
serverName: z4.string().describe("The name of the MCP server.")
});
var ConnectMCPServerTool = class extends MCPServerTool {
static {
__name(this, "ConnectMCPServerTool");
}
name = "connect_to_mcp_server";
description = "Connect to a specific MCP (Model Context Protocol) server to use its tools. Use this tool to connect to a specific server and use its tools.";
schema = ConnectMCPServerSchema;
constructor(manager) {
super(manager);
}
async _call({ serverName }) {
const serverNames = this.manager.client.getServerNames();
if (!serverNames.includes(serverName)) {
const available = serverNames.length > 0 ? serverNames.join(", ") : "none";
return `Server '${serverName}' not found. Available servers: ${available}`;
}
if (this.manager.activeServer === serverName) {
return `Already connected to MCP server '${serverName}'`;
}
try {
let session = this.manager.client.getSession(serverName);
logger.debug(`Using existing session for server '${serverName}'`);
if (!session) {
logger.debug(`Creating new session for server '${serverName}'`);
session = await this.manager.client.createSession(serverName);
}
this.manager.activeServer = serverName;
if (this.manager.serverTools[serverName]) {
const connector = session.connector;
const tools = await this.manager.adapter.createToolsFromConnectors([connector]);
this.manager.serverTools[serverName] = tools;
this.manager.initializedServers[serverName] = true;
}
const serverTools = this.manager.serverTools[serverName] || [];
const numTools = serverTools.length;
return `Connected to MCP server '${serverName}'. ${numTools} tools are now available.`;
} catch (error) {
logger.error(
`Error connecting to server '${serverName}': ${String(error)}`
);
return `Failed to connect to server '${serverName}': ${String(error)}`;
}
}
};
// src/managers/tools/list_mcp_servers.ts
import { z as z5 } from "zod";
var EnumerateServersSchema = z5.object({});
var ListMCPServersTool = class extends MCPServerTool {
static {
__name(this, "ListMCPServersTool");
}
name = "list_mcp_servers";
description = `Lists all available MCP (Model Context Protocol) servers that can be connected to, along with the tools available on each server. Use this tool to discover servers and see what functionalities they offer.`;
schema = EnumerateServersSchema;
constructor(manager) {
super(manager);
}
async _call() {
const serverNames = this.manager.client.getServerNames();
if (serverNames.length === 0) {
return `No MCP servers are currently defined.`;
}
const outputLines = ["Available MCP servers:"];
for (const serverName of serverNames) {
const isActiveServer = serverName === this.manager.activeServer;
const activeFlag = isActiveServer ? " (ACTIVE)" : "";
outputLines.push(`- ${serverName}${activeFlag}`);
try {
const serverTools = this.manager.serverTools?.[serverName] ?? [];
const numberOfTools = Array.isArray(serverTools) ? serverTools.length : 0;
outputLines.push(`${numberOfTools} tools available for this server
`);
} catch (error) {
logger.error(
`Unexpected error listing tools for server '${serverName}': ${String(error)}`
);
}
}
return outputLines.join("\n");
}
};
// src/managers/tools/release_mcp_server_connection.ts
import { z as z6 } from "zod";
var ReleaseConnectionSchema = z6.object({});
var ReleaseMCPServerConnectionTool = class extends MCPServerTool {
static {
__name(this, "ReleaseMCPServerConnectionTool");
}
name = "disconnect_from_mcp_server";
description = "Disconnect from the currently active MCP (Model Context Protocol) server";
schema = ReleaseConnectionSchema;
constructor(manager) {
super(manager);
}
async _call() {
if (!this.manager.activeServer) {
return `No MCP server is currently active, so there's nothing to disconnect from.`;
}
const serverName = this.manager.activeServer;
this.manager.activeServer = null;
return `Successfully disconnected from MCP server '${serverName}'.`;
}
};
// src/managers/server_manager.ts
import { isEqual } from "lodash-es";
var ServerManager = class {
static {
__name(this, "ServerManager");
}
initializedServers = {};
serverTools = {};
client;
adapter;
activeServer = null;
overrideManagementTools;
constructor(client, adapter, managementTools) {
this.client = client;
this.adapter = adapter;
this.overrideManagementTools = managementTools;
}
setManagementTools(tools) {
this.overrideManagementTools = tools;
logger.info(
`Overriding default management tools with a new set of ${tools.length} tools.`
);
}
logState(context) {
const allServerNames = this.client.getServerNames();
const activeSessionNames = Object.keys(this.client.getAllActiveSessions());
if (allServerNames.length === 0) {
logger.info("Server Manager State: No servers configured.");
return;
}
const tableData = allServerNames.map((name) => ({
"Server Name": name,
Connected: activeSessionNames.includes(name) ? "\u2705" : "\u274C",
Initialized: this.initializedServers[name] ? "\u2705" : "\u274C",
"Tool Count": this.serverTools[name]?.length ?? 0,
Active: this.activeServer === name ? "\u2705" : "\u274C"
}));
logger.info(`Server Manager State: [${context}]`);
console.table(tableData);
}
initialize() {
const serverNames = this.client.getServerNames?.();
if (serverNames.length === 0) {
logger.warn("No MCP servers defined in client configuration");
}
}
async prefetchServerTools() {
const servers = this.client.getServerNames();
for (const serverName of servers) {
try {
let session = null;
session = this.client.getSession(serverName);
logger.debug(
`Using existing session for server '${serverName}' to prefetch tools.`
);
if (!session) {
session = await this.client.createSession(serverName).catch((createSessionError) => {
logger.warn(
`Could not create session for '${serverName}' during prefetch: ${createSessionError}`
);
return null;
});
logger.debug(
`Temporarily created session for '${serverName}' to prefetch tools.`
);
}
if (session) {
const connector = session.connector;
let tools = [];
try {
tools = await this.adapter.createToolsFromConnectors([connector]);
} catch (toolFetchError) {
logger.error(
`Failed to create tools from connector for server '${serverName}': ${toolFetchError}`
);
continue;
}
const cachedTools = this.serverTools[serverName];
const toolsChanged = !cachedTools || !isEqual(cachedTools, tools);
if (toolsChanged) {
this.serverTools[serverName] = tools;
this.initializedServers[serverName] = true;
logger.debug(
`Prefetched ${tools.length} tools for server '${serverName}'.`
);
} else {
logger.debug(
`Tools for server '${serverName}' unchanged, using cached version.`
);
}
}
} catch (outerError) {
logger.error(
`Error prefetching tools for server '${serverName}': ${outerError}`
);
}
}
}
get tools() {
if (logger.level === "debug") {
this.logState("Providing tools to agent");
}
const managementTools = this.overrideManagementTools ?? [
new AddMCPServerFromConfigTool(this),
new ListMCPServersTool(this),
new ConnectMCPServerTool(this),
new AcquireActiveMCPServerTool(this),
new ReleaseMCPServerConnectionTool(this)
];
if (this.activeServer && this.serverTools[this.activeServer]) {
const activeTools = this.serverTools[this.activeServer];
logger.debug(
`Adding ${activeTools.length} tools from active server '${this.activeServer}'`
);
return [...managementTools, ...activeTools];
}
return managementTools;
}
};
// src/observability/manager.ts
var ObservabilityManager = class {
static {
__name(this, "ObservabilityManager");
}
customCallbacks;
availableHandlers = [];
handlerNames = [];
initialized = false;
verbose;
observe;
agentId;
metadata;
metadataProvider;
tagsProvider;
constructor(config = {}) {
this.customCallbacks = config.customCallbacks;
this.verbose = config.verbose ?? false;
this.observe = config.observe ?? true;
this.agentId = config.agentId;
this.metadata = config.metadata;
this.metadataProvider = config.metadataProvider;
this.tagsProvider = config.tagsProvider;
}
/**
* Collect all available observability handlers from configured platforms.
*/
async collectAvailableHandlers() {
if (this.initialized) {
return;
}
try {
const { langfuseHandler: langfuseHandler2, langfuseInitPromise: langfuseInitPromise2 } = await import("./langfuse-C4HKZ3NL.js");
if (this.agentId || this.metadata || this.metadataProvider || this.tagsProvider) {
const { initializeLangfuse } = await import("./langfuse-C4HKZ3NL.js");
await initializeLangfuse(
this.agentId,
this.metadata,
this.metadataProvider,
this.tagsProvider
);
logger.debug(
`ObservabilityManager: Reinitialized Langfuse with agent ID: ${this.agentId}, metadata: ${JSON.stringify(this.metadata)}`
);
} else {
const initPromise = langfuseInitPromise2();
if (initPromise) {
await initPromise;
}
}
const handler = langfuseHandler2();
if (handler) {
this.availableHandlers.push(handler);
this.handlerNames.push("Langfuse");
logger.debug("ObservabilityManager: Langfuse handler available");
}
} catch {
logger.debug("ObservabilityManager: Langfuse module not available");
}
this.initialized = true;
}
/**
* Get the list of callbacks to use.
* @returns List of callbacks - either custom callbacks if provided, or all available observability handlers.
*/
async getCallbacks() {
if (!this.observe) {
logger.debug(
"ObservabilityManager: Observability disabled via observe=false"
);
return [];
}
if (this.customCallbacks) {
logger.debug(
`ObservabilityManager: Using ${this.customCallbacks.length} custom callbacks`
);
return this.customCallbacks;
}
await this.collectAvailableHandlers();
if (this.availableHandlers.length > 0) {
logger.debug(
`ObservabilityManager: Using ${this.availableHandlers.length} handlers`
);
} else {
logger.debug("ObservabilityManager: No callbacks configured");
}
return this.availableHandlers;
}
/**
* Get the names of available handlers.
* @returns List of handler names (e.g., ["Langfuse", "Laminar"])
*/
async getHandlerNames() {
if (!this.observe) {
return [];
}
if (this.customCallbacks) {
return this.customCallbacks.map((cb) => cb.constructor.name);
}
await this.collectAvailableHandlers();
return this.handlerNames;
}
/**
* Check if any callbacks are available.
* @returns True if callbacks are available, False otherwise.
*/
async hasCallbacks() {
if (!this.observe) {
return false;
}
const callbacks = await this.getCallbacks();
return callbacks.length > 0;
}
/**
* Get the current observability status including metadata and tags.
* @returns Object containing enabled status, callback count, handler names, metadata, and tags.
*/
async getStatus() {
const callbacks = await this.getCallbacks();
const handlerNames = await this.getHandlerNames();
const currentMetadata = this.metadataProvider ? this.metadataProvider() : this.metadata || {};
const currentTags = this.tagsProvider ? this.tagsProvider() : [];
return {
enabled: this.observe && callbacks.length > 0,
callbackCount: callbacks.length,
handlerNames,
metadata: currentMetadata,
tags: currentTags
};
}
/**
* Add a callback to the custom callbacks list.
* @param callback The callback to add.
*/
addCallback(callback) {
if (!this.customCallbacks) {
this.customCallbacks = [];
}
this.customCallbacks.push(callback);
logger.debug(
`ObservabilityManager: Added custom callback: ${callback.constructor.name}`
);
}
/**
* Clear all custom callbacks.
*/
clearCallbacks() {
this.customCallbacks = [];
logger.debug("ObservabilityManager: Cleared all custom callbacks");
}
/**
* Flush all pending traces to observability platforms.
* Important for serverless environments and short-lived processes.
*/
async flush() {
const callbacks = await this.getCallbacks();
for (const callback of callbacks) {
if ("flushAsync" in callback && typeof callback.flushAsync === "function") {
await callback.flushAsync();
}
}
logger.debug("ObservabilityManager: All traces flushed");
}
/**
* Shutdown all handlers gracefully (for serverless environments).
*/
async shutdown() {
await this.flush();
const callbacks = await this.getCallbacks();
for (const callback of callbacks) {
if ("shutdownAsync" in callback && typeof callback.shutdownAsync === "function") {
await callback.shutdownAsync();
} else if ("shutdown" in callback && typeof callback.shutdown === "function") {
await callback.shutdown();
}
}
logger.debug("ObservabilityManager: All handlers shutdown");
}
/**
* String representation of the ObservabilityManager.
*/
toString() {
const names = this.handlerNames;
if (names.length > 0) {
return `ObservabilityManager(handlers=${names.join(", ")})`;
}
return "ObservabilityManager(no handlers)";
}
};
// src/telemetry/telemetry.ts
import * as fs2 from "fs";
import * as os from "os";
import * as path2 from "path";
import { PostHog } from "posthog-node";
import { v4 as uuidv4 } from "uuid";
// 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
};
}
};
// src/telemetry/utils.ts
import * as fs from "fs";
import * as path from "path";
function getPackageVersion() {
try {
if (typeof __dirname === "undefined" || typeof fs === "undefined") {
return "unknown";
}
const packagePath = path.join(__dirname, "../../package.json");
const packageJson = JSON.parse(fs.readFileSync(packagePath, "utf-8"));
return packageJson.version || "unknown";
} catch {
return "unknown";
}
}
__name(getPackageVersion, "getPackageVersion");
function getModelProvider(llm) {
return llm._llm_type || llm.constructor.name.toLowerCase();
}
__name(getModelProvider, "getModelProvider");
function getModelName(llm) {
if ("_identifyingParams" in llm) {
const identifyingParams = llm._identifyingParams;
if (typeof identifyingParams === "object" && identifyingParams !== null) {
for (const key of [
"model",
"modelName",
"model_name",
"modelId",
"model_id",
"deploymentName",
"deployment_name"
]) {
if (key in identifyingParams) {
return String(identifyingParams[key]);
}
}
}
}
return llm.model || llm.modelName || llm.constructor.name;
}
__name(getModelName, "getModelName");
function extractModelInfo(llm) {
return [getModelProvider(llm), getModelName(llm)];
}
__name(extractModelInfo, "extractModelInfo");
// src/telemetry/telemetry.ts
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";
const hasNodeModules = typeof fs2 !== "undefined" && typeof os !== "undefined" && typeof fs2.existsSync === "function";
return hasNodeGlobals && hasNodeModules;
} catch {
return false;
}
}
__name(isNodeJSEnvironment, "isNodeJSEnvironment");
var ScarfEventLogger = class {
static {
__name(this, "ScarfEventLogger");
}
endpoint;
timeout;
constructor(endpoint, timeout = 3e3) {
this.endpoint = endpoint;
this.timeout = timeout;
}
async logEvent(properties) {
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
const response = await fetch(this.endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(properties),
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
} catch (error) {
logger.debug(`Failed to send Scarf event: ${error}`);
}
}
};
function getCacheHome() {
if (!isNodeJSEnvironment()) {
return "/tmp/mcp_use_cache";
}
const envVar = process.env.XDG_CACHE_HOME;
if (envVar && path2.isAbsolute(envVar)) {
return envVar;
}
const platform = process.platform;
const homeDir = os.homedir();
if (platform === "win32") {
const appdata = process.env.LOCALAPPDATA || process.env.APPDATA;
if (appdata) {
return appdata;
}
return path2.join(homeDir, "AppData", "Local");
} else if (platform === "darwin") {
return path2.join(homeDir, "Library", "Caches");
} else {
return path2.join(homeDir, ".cache");
}
}
__name(getCacheHome, "getCacheHome");
var Telemetry = class _Telemetry {
static {
__name(this, "Telemetry");
}
static instance = null;
USER_ID_PATH = path2.join(
getCacheHome(),
"mcp_use_3",
"telemetry_user_id"
);
VERSION_DOWNLOAD_PATH = path2.join(
getCacheHome(),
"mcp_use",
"download_version"
);
PROJECT_API_KEY = "phc_lyTtbYwvkdSbrcMQNPiKiiRWrrM1seyKIMjycSvItEI";
HOST = "https://eu.i.posthog.com";
SCARF_GATEWAY_URL = "https://mcpuse.gateway.scarf.sh/events-ts";
UNKNOWN_USER_ID = "UNKNOWN_USER_ID";
_currUserId = null;
_posthogClient = null;
_scarfClient = null;
_source = "typescript";
constructor() {
const isNodeJS = isNodeJSEnvironment();
const telemetryDisabled = typeof process !== "undefined" && process.env?.MCP_USE_ANONYMIZED_TELEMETRY?.toLowerCase() === "false" || false;
this._source = typeof process !== "undefined" && process.env?.MCP_USE_TELEMETRY_SOURCE || "typescript";
if (telemetryDisabled) {
this._posthogClient = null;
this._scarfClient = null;
logger.debug("Telemetry disabled via environment variable");
} else if (!isNodeJS) {
this._posthogClient = null;
this._scarfClient = null;
logger.debug(
"Telemetry disabled - non-Node.js environment detected (e.g., Cloudflare Workers)"
);
} else {
logger.info(
"Anonymized telemetry enabled. Set MCP_USE_ANONYMIZED_TELEMETRY=false to disable."
);
try {
this._posthogClient = new PostHog(this.PROJECT_API_KEY, {
host: this.HOST,
disableGeoip: false
});
} catch (e) {
logger.warn(`Failed to initialize PostHog telemetry: ${e}`);
this._posthogClient = null;
}
try {
this._scarfClient = new ScarfEventLogger(this.SCARF_GATEWAY_URL, 3e3);
} catch (e) {
logger.warn(`Failed to initialize Scarf telemetry: ${e}`);
this._scarfClient = null;
}
}
}
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;
logger.debug(`Telemetry source set to: ${source}`);
}
/**
* Get the current source identifier.
*/
getSource() {
return this._source;
}
get userId() {
if (this._currUserId) {
return this._currUserId;
}
if (!isNodeJSEnvironment()) {
this._currUserId = this.UNKNOWN_USER_ID;
return this._currUserId;
}
try {
const isFirstTime = !fs2.existsSync(this.USER_ID_PATH);
if (isFirstTime) {
logger.debug(`Creating user ID path: ${this.USER_ID_PATH}`);
fs2.mkdirSync(path2.dirname(this.USER_ID_PATH), { recursive: true });
const newUserId = uuidv4();
fs2.writeFileSync(this.USER_ID_PATH, newUserId);
this._currUserId = newUserId;
logger.debug(`User ID path created: ${this.USER_ID_PATH}`);
} else {
this._currUserId = fs2.readFileSync(this.USER_ID_PATH, "utf-8").trim();
}
this.trackPackageDownload({
triggered_by: "user_id_property"
}).catch((e) => logger.debug(`Failed to track package download: ${e}`));
} catch (e) {
logger.debug(`Failed to get/create user ID: ${e}`);
this._currUserId = this.UNKNOWN_USER_ID;
}
return this._currUserId;
}
async capture(event) {
if (!this._posthogClient && !this._scarfClient) {
return;
}
if (this._posthogClient) {
try {
const properties = { ...event.properties };
properties.mcp_use_version = getPackageVersion();
properties.language = "typescript";
properties.source = this._source;
this._posthogClient.capture({
distinctId: this.userId,
event: event.name,
properties
});
} catch (e) {
logger.debug(`Failed to track PostHog event ${event.name}: ${e}`);
}
}
if (this._scarfClient) {
try {
const properties = {};
properties.mcp_use_version = getPackageVersion();
properties.user_id = this.userId;
properties.event = event.name;
properties.language = "typescript";
properties.source = this._source;
await this._scarfClient.logEvent(properties);
} catch (e) {
logger.debug(`Failed to track Scarf event ${event.name}: ${e}`);
}
}
}
async trackPackageDownload(properties) {
if (!this._scarfClient) {
return;
}
if (!isNodeJSEnvironment()) {
return;
}
try {
const currentVersion = getPackageVersion();
let shouldTrack = false;
let firstDownload = false;
if (!fs2.existsSync(this.VERSION_DOWNLOAD_PATH)) {
shouldTrack = true;
firstDownload = true;
fs2.mkdirSync(path2.dirname(this.VERSION_DOWNLOAD_PATH), {
recursive: true
});
fs2.writeFileSync(this.VERSION_DOWNLOAD_PATH, currentVersion);
} else {
const savedVersion = fs2.readFileSync(this.VERSION_DOWNLOAD_PATH, "utf-8").trim();
if (currentVersion > savedVersion) {
shouldTrack = true;
firstDownload = false;
fs2.writeFileSync(this.VERSION_DOWNLOAD_PATH, currentVersion);
}
}
if (shouldTrack) {
logger.debug(
`Tracking package download event with properties: ${JSON.stringify(properties)}`
);
const eventProperties = { ...properties || {} };
eventProperties.mcp_use_version = currentVersion;
eventProperties.user_id = this.userId;
eventProperties.event = "package_download";
eventProperties.first_download = firstDownload;
eventProperties.language = "typescript";
eventProperties.source = this._source;
await this._scarfClient.logEvent(eventProperties);
}
} catch (e) {
logger.debug(`Failed to track Scarf package_download event: ${e}`);
}
}
async trackAgentExecution(data) {
const event = new MCPAgentExecutionEvent(data);
await this.capture(event);
}
flush() {
if (this._posthogClient) {
try {
this._posthogClient.flush();
logger.debug("PostHog client telemetry queue flushed");
} catch (e) {
logger.debug(`Failed to flush PostHog client: ${e}`);
}
}
if (this._scarfClient) {
logger.debug("Scarf telemetry events sent immediately (no flush needed)");
}
}
shutdown() {
if (this._posthogClient) {
try {
this._posthogClient.shutdown();
logger.debug("PostHog client shutdown successfully");
} catch (e) {
logger.debug(`Error shutting down PostHog client: ${e}`);
}
}
if (this._scarfClient) {
logger.debug("Scarf telemetry client shutdown (no action needed)");
}
}
};
// src/telemetry/index.ts
function setTelemetrySource(source) {
Telemetry.getInstance().setSource(source);
}
__name(setTelemetrySource, "setTelemetrySource");
// src/agents/remote.ts
import { zodToJsonSchema } from "zod-to-json-schema";
var API_CHATS_ENDPOINT = "/api/v1/chats";
var API_CHAT_EXECUTE_ENDPOINT = "/api/v1/chats/{chat_id}/execute";
var RemoteAgent = class {
static {
__name(this, "RemoteAgent");
}
agentId;
apiKey;
baseUrl;
chatId = null;
constructor(options) {
this.agentId = options.agentId;
this.baseUrl = options.baseUrl ?? "https://cloud.mcp-use.com";
const apiKey = options.apiKey ?? process.env.MCP_USE_API_KEY;
if (!apiKey) {
throw new Error(
"API key is required for remote execution. Please provide it as a parameter or set the MCP_USE_API_KEY environment variable. You can get an API key from https://cloud.mcp-use.com"
);
}
this.apiKey = apiKey;
}
pydanticToJsonSchema(schema) {
return zodToJsonSchema(schema);
}
parseStructuredResponse(responseData, outputSchema) {
let resultData;
if (typeof responseData === "object" && responseData !== null) {
if ("result" in responseData) {
const outerResult = responseData.result;
if (typeof outerResult === "object" && outerResult !== null && "result" in outerResult) {
resultData = outerResult.result;
} else {
resultData = outerResult;
}
} else {
resultData = responseData;
}
} else if (typeof responseData === "string") {
try {
resultData = JSON.parse(responseData);
} catch {
resultData = { content: responseData };
}
} else {
resultData = responseData;
}
try {
return outputSchema.parse(resultData);
} catch (e) {
logger.warn(`Failed to parse structured output: ${e}`);
const schemaShape = outputSchema._def?.shape();
if (schemaShape && "content" in schemaShape) {
return outputSchema.parse({ content: String(resultData) });
}
throw e;
}
}
async createChatSession() {
const chatPayload = {
title: `Remote Agent Session - ${this.agentId}`,
agent_id: this.agentId,
type: "agent_execution"
};
const headers = {
"Content-Type": "application/json",
"x-api-key": this.apiKey
};
const chatUrl = `${this.baseUrl}${API_CHATS_ENDPOINT}`;
logger.info(`\u{1F4DD} Creating chat session for agent ${this.agentId}`);
try {
const response = await fetch(chatUrl, {
method: "POST",
headers,
body: JSON.stringify(chatPayload)
});
if (!response.ok) {
const responseText = await response.text();
const statusCode = response.status;
if (statusCode === 404) {
throw new Error(
`Agent not found: Agent '${this.agentId}' does not exist or you don't have access to it. Please verify the agent ID and ensure it exists in your account.`
);
}
throw new Error(
`Failed to create chat session: ${statusCode} - ${responseText}`
);
}
const chatData = await response.json();
const chatId = chatData.id;
logger.info(`\u2705 Chat session created: ${chatId}`);
return chatId;
} catch (e) {
if (e instanceof Error) {
throw new TypeError(`Failed to create chat session: ${e.message}`);
}
throw new Error(`Failed to create chat session: ${String(e)}`);
}
}
async run(query, maxSteps, manageConnector, externalHistory, outputSchema) {
if (externalHistory !== void 0) {
logger.warn("External history is not yet supported for remote execution");
}
try {
logger.info(`\u{1F310} Executing query on remote agent ${this.agentId}`);
if (this.chatId === null) {
this.chatId = await this.createChatSession();
}
const chatId = this.chatId;
const executionPayload = {
query,
max_steps: maxSteps ?? 10
};
if (outputSchema) {
executionPayload.output_schema = this.pydanticToJsonSchema(outputSchema);
logger.info(`\u{1F527} Using structured output with schema`);
}
const headers = {
"Content-Type": "application/json",
"x-api-key": this.apiKey
};
const executionUrl = `${this.baseUrl}${API_CHAT_EXECUTE_ENDPOINT.replace("{chat_id}", chatId)}`;
logger.info(`\u{1F680} Executing agent in chat ${chatId}`);
const response = await fetch(executionUrl, {
method: "POST",
headers,
body: JSON.stringify(executionPayload),
signal: AbortSignal.timeout(3e5)
// 5 minute timeout
});
if (!response.ok) {
const responseText = await response.text();
const statusCode = response.status;
if (statusCode === 401) {
logger.error(`\u274C Authentication failed: ${responseText}`);
throw new Error(
"Authentication failed: Invalid or missing API key. Please check your API key and ensure the MCP_USE_API_KEY environment variable is set correctly."
);
} else if (statusCode === 403) {
logger.error(`\u274C Access forbidden: ${responseText}`);
throw new Error(
`Access denied: You don't have permission to execute agent '${this.agentId}'. Check if the agent exists and you have the necessary permissions.`
);
} else if (statusCode === 404) {
logger.error(`\u274C Agent not found: ${responseText}`);
throw new Error(
`Agent not found: Agent '${this.agentId}' does not exist or you don't have access to it. Please verify the agent ID and ensure it exists in your account.`
);
} else if (statusCode === 422) {
logger.error(`\u274C Validation error: ${responseText}`);
throw new Error(
`Request validation failed: ${responseText}. Please check your query parameters and output schema format.`
);
} else if (statusCode === 500) {
logger.error(`\u274C Server error: ${responseText}`);
throw new Error(
"Internal server error occurred during agent execution. Please try again later or contact support if the issue persists."
);
} else {
logger.error(
`\u274C Remote execution failed with status ${statusCode}: ${responseText}`
);
throw new Error(
`Remote agent execution failed: ${statusCode} - ${responseText}`
);
}
}
const result = await response.json();
logger.info(`\u{1F527} Response: ${JSON.stringify(result)}`);
logger.info("\u2705 Remote execution completed successfully");
if (typeof result === "object" && result !== null) {
if (result.status === "error" || result.error !== null) {
const errorMsg = result.error ?? String(result);
logger.error(`\u274C Remote agent execution failed: ${errorMsg}`);
throw new Error(`Remote agent execution failed: ${errorMsg}`);
}
if (String(result).includes("failed to initialize")) {
logger.error(`\u274C Agent initialization failed: ${result}`);
throw new Error(
`Agent initialization failed on remote server. This usually indicates:
\u2022 Invalid agent configuration (LLM model, system prompt)
\u2022 Missing or invalid MCP server configurations
\u2022 Network connectivity issues with MCP servers
\u2022 Missing environment variables or credentials
Raw error: ${result}`
);
}
}
if (outputSchema) {
return this.parseStructuredResponse(result, outputSchema);
}
if (typeof result === "object" && result !== null && "result" in result) {
return result.result;
} else if (typeof result === "string") {
return result;
} else {
return String(result);
}
} catch (e) {
if (e instanceof Error) {
if (e.name === "AbortError") {
logger.error(`\u274C Remote execution timed out: ${e}`);
throw new Error(
"Remote agent execution timed out. The server may be overloaded or the query is taking too long to process. Try again or use a simpler query."
);
}
logger.error(`\u274C Remote execution error: ${e}`);
throw new Error(`Remote agent execution failed: ${e.message}`);
}
logger.error(`\u274C Remote execution error: ${e}`);
throw new Error(`Remote agent execution failed: ${String(e)}`);
}
}
// eslint-disable-next-line require-yield
async *stream(query, maxSteps, manageConnector, externalHistory, outputSchema) {
const result = await this.run(
query,
maxSteps,
manageConnector,
externalHistory,
outputSchema
);
return result;
}
async close() {
logger.info("\u{1F50C} Remote agent client closed");
}
};
// src/agents/mcp_agent.ts
import {
createAgent,
modelCallLimitMiddleware,
SystemMessage as SystemMessage2,
AIMessage,
HumanMessage,
ToolMessage
} from "langchain";
import { zodToJsonSchema as zodToJsonSchema2 } from "zod-to-json-schema";
// src/agents/prompts/system_prompt_builder.ts
import { SystemMessage } from "langchain";
function generateToolDescriptions(tools, disallowedTools) {
const disallowedSet = new Set(disallowedTools ?? []);
const descriptions = [];
for (const tool of tools) {
if (disallowedSet.has(tool.name)) continue;
const escaped = tool.description.replace(/\{/g, "{{").replace(/\}/g, "}}");
descriptions.push(`- ${tool.name}: ${escaped}`);
}
return descriptions;
}
__name(generateToolDescriptions, "generateToolDescriptions");
function buildSystemPromptContent(template, toolDescriptionLines, additionalInstructions) {
const block = toolDescriptionLines.join("\n");
let content;
if (template.includes("{tool_descriptions}")) {
content = template.replace("{tool_descriptions}", block);
} else {
console.warn(
"`{tool_descriptions}` placeholder not found; appending at end."
);
content = `${template}
Available tools:
${block}`;
}
if (additionalInstructions) {
content += `
${additionalInstructions}`;
}
return content;
}
__name(buildSystemPromptContent, "buildSystemPromptContent");
function createSystemMessage(tools, systemPromptTemplate, serverManagerTemplate, useServerManager, disallowedTools, userProvidedPrompt, additionalInstructions) {
if (userProvidedPrompt) {
return new SystemMessage({ content: userProvidedPrompt });
}
const template = useServerManager ? serverManagerTemplate : systemPromptTemplate;
const toolLines = generateToolDescriptions(tools, disallowedTools);
const finalContent = buildSystemPromptContent(
template,
toolLines,
additionalInstructions
);
return new SystemMessage({ content: finalContent });
}
__name(createSystemMessage, "createSystemMessage");
// src/agents/prompts/templates.ts
var DEFAULT_SYSTEM_PROMPT_TEMPLATE = `You are a helpful AI assistant.
You have access to the following tools:
{tool_descriptions}
Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of the available tools
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can repeat N times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question`;
var SERVER_MANAGER_SYSTEM_PROMPT_TEMPLATE = `You are a helpful assistant designed to interact with MCP
(Model Context Protocol) servers. You can manage connections to different servers and use the tools
provided by the currently active server.
Important: The available tools change depending on which server is active.
If a request requires tools not listed below (e.g., file operations, web browsing,
image manipulation), you MUST first connect to the appropriate server using
'connect_to_mcp_server'.
Use 'list_mcp_servers' to find the relevant server if you are unsure.
Only after successfully connecting and seeing the new tools listed in
the response should you attempt to use those server-specific tools.
Before attempting a task that requires specific tools, you should
ensure you are connected to the correct server and aware of its
available tools. If unsure, use 'list_mcp_servers' to see options
or 'get_active_mcp_server' to check the current connection.
When you connect to a server using 'connect_to_mcp_server',
you will be informed about the new tools that become available.
You can then use these server-specific tools in subsequent steps.
Here are the tools *currently* available to you (this list includes server management tools and will
change when you connect to a server):
{tool_descriptions}
`;
// src/agents/mcp_agent.ts
var MCPAgent = class {
static {
__name(this, "MCPAgent");
}
llm;
client;
connectors;
maxSteps;
autoInitialize;
memoryEnabled;
disallowedTools;
additionalTools;
toolsUsedNames = [];
useServerManager;
verbose;
observe;
systemPrompt;
systemPromptTemplateOverride;
additionalInstructions;
_initialized = false;
conversationHistory = [];
_agentExecutor = null;
sessions = {};
systemMessage = null;
_tools = [];
adapter;
serverManager = null;
telemetry;
modelProvider;
modelName;
// Observability support
observabilityManager;
callbacks = [];
metadata = {};
tags = [];
// Remote agent support
isRemote = false;
remoteAgent = null;
constructor(options) {
if (options.agentId) {
this.isRemote = true;
this.remoteAgent = new RemoteAgent({
agentId: options.agentId,
apiKey: options.apiKey,
baseUrl: options.baseUrl
});
this.maxSteps = options.maxSteps ?? 5;
this.memoryEnabled = options.memoryEnabled ?? true;
this.autoInitialize = options.autoInitialize ?? false;
this.verbose = options.verbose ?? false;
this.observe = options.observe ?? tr