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.32 kB
JavaScript
import fs from 'node:fs';
import path from 'node:path';
import { createConnectorFromConfig, loadConfigFile } from './config.js';
import { logger } from './logging.js';
import { MCPSession } from './session.js';
export class MCPClient {
config = {};
sessions = {};
activeSessions = [];
constructor(config) {
if (config) {
if (typeof config === 'string') {
this.config = loadConfigFile(config);
}
else {
this.config = config;
}
}
}
static fromDict(cfg) {
return new MCPClient(cfg);
}
static fromConfigFile(path) {
return new MCPClient(loadConfigFile(path));
}
addServer(name, serverConfig) {
this.config.mcpServers = this.config.mcpServers || {};
this.config.mcpServers[name] = serverConfig;
}
removeServer(name) {
if (this.config.mcpServers?.[name]) {
delete this.config.mcpServers[name];
this.activeSessions = this.activeSessions.filter(n => n !== name);
}
}
getServerNames() {
return Object.keys(this.config.mcpServers ?? {});
}
saveConfig(filepath) {
const dir = path.dirname(filepath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(filepath, JSON.stringify(this.config, null, 2), 'utf-8');
}
async createSession(serverName, autoInitialize = true) {
const servers = this.config.mcpServers ?? {};
if (Object.keys(servers).length === 0) {
throw new Error('No MCP servers defined in config');
}
if (!servers[serverName]) {
throw new Error(`Server '${serverName}' not found in config`);
}
const connector = 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) {
throw new Error('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) {
throw new Error(`No session exists for server '${serverName}'`);
}
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');
}
}
}