mcp-use
Version:
A utility library for integrating Model Context Protocol (MCP) with LangChain, Zod, and related tools. Provides helpers for schema conversion, event streaming, and SDK usage.
125 lines (124 loc) • 4.8 kB
JavaScript
import { logger } from '../logging.js';
/**
* Abstract base class for converting MCP tools to other framework formats.
*
* This class defines the common interface that all adapter implementations
* should follow to ensure consistency across different frameworks.
*/
export class 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 = 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) {
// Create the adapter
const adapter = new this(disallowedTools);
// Ensure we have active sessions
if (!client.activeSessions || Object.keys(client.activeSessions).length === 0) {
logger.info('No active sessions found, creating new ones...');
await client.createAllSessions();
}
// Get all active sessions
const sessions = client.getAllActiveSessions();
// Extract connectors from sessions
const connectors = Object.values(sessions).map(session => session.connector);
// Create tools from connectors
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) {
// Return cached tools if we already processed this 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 = [];
// Make sure the connector is initialized and has tools
const success = await this.ensureConnectorInitialized(connector);
if (!success) {
return [];
}
// Convert and collect tools
for (const tool of connector.tools) {
const converted = this.convertTool(tool, connector);
if (converted) {
connectorTools.push(converted);
}
}
// Cache the tools for this connector
this.connectorToolMap.set(connector, connectorTools);
// Log for debugging purposes
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;
}
}