* #3707 added sse and streamable stransport support for mcp servers * #3707 yarn lint changes * bump MCP SDK to latest * option chain transport * small refactor --------- Co-authored-by: Aleksey Kapustyanenko <kapustyanenko@mercurydevelopment.com> Co-authored-by: Timothy Carambat <rambat1010@gmail.com>
This commit is contained in:
parent
480be2a6f0
commit
e93964b67b
@ -32,7 +32,7 @@
|
||||
"@langchain/textsplitters": "0.0.0",
|
||||
"@mintplex-labs/bree": "^9.2.5",
|
||||
"@mintplex-labs/express-ws": "^5.0.7",
|
||||
"@modelcontextprotocol/sdk": "^1.8.0",
|
||||
"@modelcontextprotocol/sdk": "^1.11.0",
|
||||
"@pinecone-database/pinecone": "^2.0.1",
|
||||
"@prisma/client": "5.3.1",
|
||||
"@qdrant/js-client-rest": "^1.9.0",
|
||||
|
||||
@ -5,6 +5,16 @@ const { Client } = require("@modelcontextprotocol/sdk/client/index.js");
|
||||
const {
|
||||
StdioClientTransport,
|
||||
} = require("@modelcontextprotocol/sdk/client/stdio.js");
|
||||
const {
|
||||
SSEClientTransport,
|
||||
} = require("@modelcontextprotocol/sdk/client/sse.js");
|
||||
const {
|
||||
StreamableHTTPClientTransport,
|
||||
} = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
||||
|
||||
/**
|
||||
* @typedef {'stdio' | 'http' | 'sse'} MCPServerTypes
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class MCPHypervisor
|
||||
@ -236,6 +246,81 @@ class MCPHypervisor {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the server type from the server definition
|
||||
* @param {Object} server - The server definition
|
||||
* @returns {MCPServerTypes | null} - The server type
|
||||
*/
|
||||
#parseServerType(server) {
|
||||
if (server.hasOwnProperty("command")) return "stdio";
|
||||
if (server.hasOwnProperty("url")) return "http";
|
||||
return "sse";
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the server definition by type
|
||||
* - Will throw an error if the server definition is invalid
|
||||
* @param {Object} server - The server definition
|
||||
* @param {MCPServerTypes} type - The server type
|
||||
* @returns {void}
|
||||
*/
|
||||
#validateServerDefinitionByType(server, type) {
|
||||
if (type === "stdio") {
|
||||
if (server.hasOwnProperty("args") && !Array.isArray(server.args))
|
||||
throw new Error("MCP server args must be an array");
|
||||
}
|
||||
|
||||
if (type === "http") {
|
||||
if (!["sse", "streamable"].includes(server?.type))
|
||||
throw new Error("MCP server type must have sse or streamable value.");
|
||||
}
|
||||
|
||||
if (type === "sse") return;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the server transport by type and server definition
|
||||
* @param {Object} server - The server definition
|
||||
* @param {MCPServerTypes} type - The server type
|
||||
* @returns {StdioClientTransport | StreamableHTTPClientTransport | SSEClientTransport} - The server transport
|
||||
*/
|
||||
#setupServerTransport(server, type) {
|
||||
// if not stdio then it is http or sse
|
||||
if (type !== "stdio") return this.createHttpTransport(server);
|
||||
|
||||
return new StdioClientTransport({
|
||||
command: server.command,
|
||||
args: server?.args ?? [],
|
||||
...this.#buildMCPServerENV(server),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create MCP client transport for http MCP server.
|
||||
* @param {Object} server - The server definition
|
||||
* @returns {StreamableHTTPClientTransport | SSEClientTransport} - The server transport
|
||||
*/
|
||||
createHttpTransport(server) {
|
||||
const url = new URL(server.url);
|
||||
|
||||
// If the server block has a type property then use that to determine the transport type
|
||||
switch (server.type) {
|
||||
case "streamable":
|
||||
return new StreamableHTTPClientTransport(url, {
|
||||
requestInit: {
|
||||
headers: server.headers,
|
||||
},
|
||||
});
|
||||
default:
|
||||
return new SSEClientTransport(url, {
|
||||
requestInit: {
|
||||
headers: server.headers,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private Start a single MCP server by its server definition from the JSON file
|
||||
* @param {string} name - The name of the MCP server to start
|
||||
@ -245,17 +330,13 @@ class MCPHypervisor {
|
||||
async #startMCPServer({ name, server }) {
|
||||
if (!name) throw new Error("MCP server name is required");
|
||||
if (!server) throw new Error("MCP server definition is required");
|
||||
if (!server.command) throw new Error("MCP server command is required");
|
||||
if (server.hasOwnProperty("args") && !Array.isArray(server.args))
|
||||
throw new Error("MCP server args must be an array");
|
||||
const serverType = this.#parseServerType(server);
|
||||
if (!serverType) throw new Error("MCP server command or url is required");
|
||||
|
||||
this.#validateServerDefinitionByType(server, serverType);
|
||||
this.log(`Attempting to start MCP server: ${name}`);
|
||||
const mcp = new Client({ name: name, version: "1.0.0" });
|
||||
const transport = new StdioClientTransport({
|
||||
command: server.command,
|
||||
args: server?.args ?? [],
|
||||
...this.#buildMCPServerENV(server),
|
||||
});
|
||||
const transport = this.#setupServerTransport(server, serverType);
|
||||
|
||||
// Add connection event listeners
|
||||
transport.onclose = () => this.log(`${name} - Transport closed`);
|
||||
|
||||
@ -142,7 +142,7 @@ class MCPCompatibilityLayer extends MCPHypervisor {
|
||||
tools,
|
||||
error: null,
|
||||
process: {
|
||||
pid: mcp.transport._process.pid,
|
||||
pid: mcp.transport?.process?.pid || null,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@ -1599,10 +1599,10 @@
|
||||
dependencies:
|
||||
ws "^7.5.10"
|
||||
|
||||
"@modelcontextprotocol/sdk@^1.8.0":
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.8.0.tgz#55cdd65054ec24e53800250c70e07429d669db67"
|
||||
integrity sha512-e06W7SwrontJDHwCawNO5SGxG+nU9AAx+jpHHZqGl/WrDBdWOpvirC+s58VpJTB5QemI4jTRcjWT4Pt3Q1NPQQ==
|
||||
"@modelcontextprotocol/sdk@^1.11.0":
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.11.0.tgz#9f1762efe6f3365f0bf3b019cc9bd1629d19bc50"
|
||||
integrity sha512-k/1pb70eD638anoi0e8wUGAlbMJXyvdV4p62Ko+EZ7eBe1xMx8Uhak1R5DgfoofsK5IBBnRwsYGTaLZl+6/+RQ==
|
||||
dependencies:
|
||||
content-type "^1.0.5"
|
||||
cors "^2.8.5"
|
||||
@ -1610,7 +1610,7 @@
|
||||
eventsource "^3.0.2"
|
||||
express "^5.0.1"
|
||||
express-rate-limit "^7.5.0"
|
||||
pkce-challenge "^4.1.0"
|
||||
pkce-challenge "^5.0.0"
|
||||
raw-body "^3.0.0"
|
||||
zod "^3.23.8"
|
||||
zod-to-json-schema "^3.24.1"
|
||||
@ -6615,10 +6615,10 @@ pirates@^3.0.2:
|
||||
dependencies:
|
||||
node-modules-regexp "^1.0.0"
|
||||
|
||||
pkce-challenge@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/pkce-challenge/-/pkce-challenge-4.1.0.tgz#95027d7750c3c0f21676a345b48f481786f9acdb"
|
||||
integrity sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ==
|
||||
pkce-challenge@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pkce-challenge/-/pkce-challenge-5.0.0.tgz#c3a405cb49e272094a38e890a2b51da0228c4d97"
|
||||
integrity sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==
|
||||
|
||||
platform@^1.3.6:
|
||||
version "1.3.6"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user