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.
144 lines (143 loc) • 5.04 kB
JavaScript
import { logger } from '../logging.js';
/**
* Base class for MCP connectors.
*/
export class BaseConnector {
client = null;
connectionManager = null;
toolsCache = null;
connected = false;
opts;
constructor(opts = {}) {
this.opts = opts;
}
/** Disconnect and release resources. */
async disconnect() {
if (!this.connected) {
logger.debug('Not connected to MCP implementation');
return;
}
logger.debug('Disconnecting from MCP implementation');
await this.cleanupResources();
this.connected = false;
logger.debug('Disconnected from MCP implementation');
}
/** Check if the client is connected */
get isClientConnected() {
return this.client != null;
}
/**
* Initialise the MCP session **after** `connect()` has succeeded.
*
* In the SDK, `Client.connect(transport)` automatically performs the
* protocol‑level `initialize` handshake, so we only need to cache the list of
* tools and expose some server info.
*/
async initialize(defaultRequestOptions = this.opts.defaultRequestOptions ?? {}) {
if (!this.client) {
throw new Error('MCP client is not connected');
}
logger.debug('Caching server capabilities & tools');
// Cache server capabilities for callers who need them.
const capabilities = this.client.getServerCapabilities();
// Fetch and cache tools
const listToolsRes = await this.client.listTools(undefined, defaultRequestOptions);
this.toolsCache = (listToolsRes.tools ?? []);
logger.debug(`Fetched ${this.toolsCache.length} tools from server`);
return capabilities;
}
/** Lazily expose the cached tools list. */
get tools() {
if (!this.toolsCache) {
throw new Error('MCP client is not initialized; call initialize() first');
}
return this.toolsCache;
}
/** Call a tool on the server. */
async callTool(name, args, options) {
if (!this.client) {
throw new Error('MCP client is not connected');
}
logger.debug(`Calling tool '${name}' with args`, args);
const res = await this.client.callTool({ name, arguments: args }, undefined, options);
logger.debug(`Tool '${name}' returned`, res);
return res;
}
/** List resources from the server. */
async listResources(options) {
if (!this.client) {
throw new Error('MCP client is not connected');
}
logger.debug('Listing resources');
return await this.client.listResources(undefined, options);
}
/** Read a resource by URI. */
async readResource(uri, options) {
if (!this.client) {
throw new Error('MCP client is not connected');
}
logger.debug(`Reading resource ${uri}`);
const res = await this.client.readResource({ uri }, options);
return { content: res.content, mimeType: res.mimeType };
}
async listPrompts() {
if (!this.client) {
throw new Error('MCP client is not connected');
}
logger.debug('Listing prompt');
return await this.client.listPrompts();
}
async getPrompt(name, args) {
if (!this.client) {
throw new Error('MCP client is not connected');
}
logger.debug(`Getting prompt ${name}`);
return await this.client.getPrompt({ name, arguments: args });
}
/** Send a raw request through the client. */
async request(method, params = null, options) {
if (!this.client) {
throw new Error('MCP client is not connected');
}
logger.debug(`Sending raw request '${method}' with params`, params);
return await this.client.request({ method, params: params ?? {} }, undefined, options);
}
/**
* Helper to tear down the client & connection manager safely.
*/
async cleanupResources() {
const issues = [];
if (this.client) {
try {
if (typeof this.client.close === 'function') {
await this.client.close();
}
}
catch (e) {
const msg = `Error closing client: ${e}`;
logger.warn(msg);
issues.push(msg);
}
finally {
this.client = null;
}
}
if (this.connectionManager) {
try {
await this.connectionManager.stop();
}
catch (e) {
const msg = `Error stopping connection manager: ${e}`;
logger.warn(msg);
issues.push(msg);
}
finally {
this.connectionManager = null;
}
}
this.toolsCache = null;
if (issues.length) {
logger.warn(`Resource cleanup finished with ${issues.length} issue(s)`);
}
}
}