mirror of
https://github.com/cline/cline.git
synced 2025-06-03 03:59:07 +00:00
feat: support streameable http transport (#3413)
* feat: support Stremeable Http transport * feat: add http to rpc method
This commit is contained in:
parent
0870c65fa5
commit
8356e058c1
5
.changeset/rare-flowers-switch.md
Normal file
5
.changeset/rare-flowers-switch.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"claude-dev": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Support Streameable Http Transport for MCPs
|
@ -134,14 +134,6 @@ const baseConfig = {
|
|||||||
aliasResolverPlugin,
|
aliasResolverPlugin,
|
||||||
/* add to the end of plugins array */
|
/* add to the end of plugins array */
|
||||||
esbuildProblemMatcherPlugin,
|
esbuildProblemMatcherPlugin,
|
||||||
{
|
|
||||||
name: "alias-plugin",
|
|
||||||
setup(build) {
|
|
||||||
build.onResolve({ filter: /^pkce-challenge$/ }, (args) => {
|
|
||||||
return { path: require.resolve("pkce-challenge/dist/index.browser.js") }
|
|
||||||
})
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
format: "cjs",
|
format: "cjs",
|
||||||
sourcesContent: false,
|
sourcesContent: false,
|
||||||
|
34
package-lock.json
generated
34
package-lock.json
generated
@ -19,7 +19,7 @@
|
|||||||
"@grpc/grpc-js": "^1.9.15",
|
"@grpc/grpc-js": "^1.9.15",
|
||||||
"@grpc/reflection": "^1.0.4",
|
"@grpc/reflection": "^1.0.4",
|
||||||
"@mistralai/mistralai": "^1.5.0",
|
"@mistralai/mistralai": "^1.5.0",
|
||||||
"@modelcontextprotocol/sdk": "^1.7.0",
|
"@modelcontextprotocol/sdk": "^1.11.1",
|
||||||
"@opentelemetry/api": "^1.4.1",
|
"@opentelemetry/api": "^1.4.1",
|
||||||
"@opentelemetry/exporter-trace-otlp-http": "^0.39.1",
|
"@opentelemetry/exporter-trace-otlp-http": "^0.39.1",
|
||||||
"@opentelemetry/resources": "^1.30.1",
|
"@opentelemetry/resources": "^1.30.1",
|
||||||
@ -7600,17 +7600,17 @@
|
|||||||
"license": "BSD-2-Clause"
|
"license": "BSD-2-Clause"
|
||||||
},
|
},
|
||||||
"node_modules/@modelcontextprotocol/sdk": {
|
"node_modules/@modelcontextprotocol/sdk": {
|
||||||
"version": "1.7.0",
|
"version": "1.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.11.1.tgz",
|
||||||
"integrity": "sha512-IYPe/FLpvF3IZrd/f5p5ffmWhMc3aEMuM2wGJASDqC2Ge7qatVCdbfPx3n/5xFeb19xN0j/911M2AaFuircsWA==",
|
"integrity": "sha512-9LfmxKTb1v+vUS1/emSk1f5ePmTLkb9Le9AxOB5T0XM59EUumwcS45z05h7aiZx3GI0Bl7mjb3FMEglYj+acuQ==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"content-type": "^1.0.5",
|
"content-type": "^1.0.5",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
|
"cross-spawn": "^7.0.3",
|
||||||
"eventsource": "^3.0.2",
|
"eventsource": "^3.0.2",
|
||||||
"express": "^5.0.1",
|
"express": "^5.0.1",
|
||||||
"express-rate-limit": "^7.5.0",
|
"express-rate-limit": "^7.5.0",
|
||||||
"pkce-challenge": "^4.1.0",
|
"pkce-challenge": "^5.0.0",
|
||||||
"raw-body": "^3.0.0",
|
"raw-body": "^3.0.0",
|
||||||
"zod": "^3.23.8",
|
"zod": "^3.23.8",
|
||||||
"zod-to-json-schema": "^3.24.1"
|
"zod-to-json-schema": "^3.24.1"
|
||||||
@ -21465,10 +21465,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pkce-challenge": {
|
"node_modules/pkce-challenge": {
|
||||||
"version": "4.1.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz",
|
||||||
"integrity": "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ==",
|
"integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==",
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=16.20.0"
|
"node": ">=16.20.0"
|
||||||
}
|
}
|
||||||
@ -31509,16 +31508,17 @@
|
|||||||
"integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw=="
|
"integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw=="
|
||||||
},
|
},
|
||||||
"@modelcontextprotocol/sdk": {
|
"@modelcontextprotocol/sdk": {
|
||||||
"version": "1.7.0",
|
"version": "1.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.11.1.tgz",
|
||||||
"integrity": "sha512-IYPe/FLpvF3IZrd/f5p5ffmWhMc3aEMuM2wGJASDqC2Ge7qatVCdbfPx3n/5xFeb19xN0j/911M2AaFuircsWA==",
|
"integrity": "sha512-9LfmxKTb1v+vUS1/emSk1f5ePmTLkb9Le9AxOB5T0XM59EUumwcS45z05h7aiZx3GI0Bl7mjb3FMEglYj+acuQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"content-type": "^1.0.5",
|
"content-type": "^1.0.5",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
|
"cross-spawn": "^7.0.3",
|
||||||
"eventsource": "^3.0.2",
|
"eventsource": "^3.0.2",
|
||||||
"express": "^5.0.1",
|
"express": "^5.0.1",
|
||||||
"express-rate-limit": "^7.5.0",
|
"express-rate-limit": "^7.5.0",
|
||||||
"pkce-challenge": "^4.1.0",
|
"pkce-challenge": "^5.0.0",
|
||||||
"raw-body": "^3.0.0",
|
"raw-body": "^3.0.0",
|
||||||
"zod": "^3.23.8",
|
"zod": "^3.23.8",
|
||||||
"zod-to-json-schema": "^3.24.1"
|
"zod-to-json-schema": "^3.24.1"
|
||||||
@ -41248,9 +41248,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"pkce-challenge": {
|
"pkce-challenge": {
|
||||||
"version": "4.1.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/pkce-challenge/-/pkce-challenge-5.0.0.tgz",
|
||||||
"integrity": "sha512-ZBmhE1C9LcPoH9XZSdwiPtbPHZROwAnMy+kIFQVrnMCxY4Cudlz3gBOpzilgc0jOgRaiT3sIWfpMomW2ar2orQ=="
|
"integrity": "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ=="
|
||||||
},
|
},
|
||||||
"pony-cause": {
|
"pony-cause": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
|
@ -341,7 +341,7 @@
|
|||||||
"@grpc/grpc-js": "^1.9.15",
|
"@grpc/grpc-js": "^1.9.15",
|
||||||
"@grpc/reflection": "^1.0.4",
|
"@grpc/reflection": "^1.0.4",
|
||||||
"@mistralai/mistralai": "^1.5.0",
|
"@mistralai/mistralai": "^1.5.0",
|
||||||
"@modelcontextprotocol/sdk": "^1.7.0",
|
"@modelcontextprotocol/sdk": "^1.11.1",
|
||||||
"@opentelemetry/api": "^1.4.1",
|
"@opentelemetry/api": "^1.4.1",
|
||||||
"@opentelemetry/exporter-trace-otlp-http": "^0.39.1",
|
"@opentelemetry/exporter-trace-otlp-http": "^0.39.1",
|
||||||
"@opentelemetry/resources": "^1.30.1",
|
"@opentelemetry/resources": "^1.30.1",
|
||||||
|
@ -30,6 +30,7 @@ import { arePathsEqual } from "@utils/path"
|
|||||||
import { secondsToMs } from "@utils/time"
|
import { secondsToMs } from "@utils/time"
|
||||||
import { GlobalFileNames } from "@core/storage/disk"
|
import { GlobalFileNames } from "@core/storage/disk"
|
||||||
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"
|
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"
|
||||||
|
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
|
||||||
import { ExtensionMessage } from "@shared/ExtensionMessage"
|
import { ExtensionMessage } from "@shared/ExtensionMessage"
|
||||||
|
|
||||||
// Default timeout for internal MCP data requests in milliseconds; is not the same as the user facing timeout stored as DEFAULT_MCP_TIMEOUT_SECONDS
|
// Default timeout for internal MCP data requests in milliseconds; is not the same as the user facing timeout stored as DEFAULT_MCP_TIMEOUT_SECONDS
|
||||||
@ -38,10 +39,10 @@ const DEFAULT_REQUEST_TIMEOUT_MS = 5000
|
|||||||
export type McpConnection = {
|
export type McpConnection = {
|
||||||
server: McpServer
|
server: McpServer
|
||||||
client: Client
|
client: Client
|
||||||
transport: StdioClientTransport | SSEClientTransport
|
transport: StdioClientTransport | SSEClientTransport | StreamableHTTPClientTransport
|
||||||
}
|
}
|
||||||
|
|
||||||
export type McpTransportType = "stdio" | "sse"
|
export type McpTransportType = "stdio" | "sse" | "http"
|
||||||
|
|
||||||
export type McpServerConfig = z.infer<typeof ServerConfigSchema>
|
export type McpServerConfig = z.infer<typeof ServerConfigSchema>
|
||||||
|
|
||||||
@ -54,22 +55,23 @@ const BaseConfigSchema = z.object({
|
|||||||
})
|
})
|
||||||
|
|
||||||
const SseConfigSchema = BaseConfigSchema.extend({
|
const SseConfigSchema = BaseConfigSchema.extend({
|
||||||
|
transportType: z.literal("sse"),
|
||||||
url: z.string().url(),
|
url: z.string().url(),
|
||||||
}).transform((config) => ({
|
})
|
||||||
...config,
|
|
||||||
transportType: "sse" as const,
|
|
||||||
}))
|
|
||||||
|
|
||||||
const StdioConfigSchema = BaseConfigSchema.extend({
|
const StdioConfigSchema = BaseConfigSchema.extend({
|
||||||
|
transportType: z.literal("stdio"),
|
||||||
command: z.string(),
|
command: z.string(),
|
||||||
args: z.array(z.string()).optional(),
|
args: z.array(z.string()).optional(),
|
||||||
env: z.record(z.string()).optional(),
|
env: z.record(z.string()).optional(),
|
||||||
}).transform((config) => ({
|
})
|
||||||
...config,
|
|
||||||
transportType: "stdio" as const,
|
|
||||||
}))
|
|
||||||
|
|
||||||
const ServerConfigSchema = z.union([StdioConfigSchema, SseConfigSchema])
|
const StreamableHTTPConfigSchema = BaseConfigSchema.extend({
|
||||||
|
transportType: z.literal("http"),
|
||||||
|
url: z.string().url(),
|
||||||
|
})
|
||||||
|
|
||||||
|
const ServerConfigSchema = z.discriminatedUnion("transportType", [StdioConfigSchema, SseConfigSchema, StreamableHTTPConfigSchema])
|
||||||
|
|
||||||
const McpSettingsSchema = z.object({
|
const McpSettingsSchema = z.object({
|
||||||
mcpServers: z.record(ServerConfigSchema),
|
mcpServers: z.record(ServerConfigSchema),
|
||||||
@ -183,7 +185,7 @@ export class McpHub {
|
|||||||
|
|
||||||
private async connectToServerRPC(
|
private async connectToServerRPC(
|
||||||
name: string,
|
name: string,
|
||||||
config: z.infer<typeof StdioConfigSchema> | z.infer<typeof SseConfigSchema>,
|
config: z.infer<typeof StdioConfigSchema> | z.infer<typeof SseConfigSchema> | z.infer<typeof StreamableHTTPConfigSchema>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// Remove existing connection if it exists (should never happen, the connection should be deleted beforehand)
|
// Remove existing connection if it exists (should never happen, the connection should be deleted beforehand)
|
||||||
this.connections = this.connections.filter((conn) => conn.server.name !== name)
|
this.connections = this.connections.filter((conn) => conn.server.name !== name)
|
||||||
@ -200,10 +202,12 @@ export class McpHub {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
let transport: StdioClientTransport | SSEClientTransport
|
let transport: StdioClientTransport | SSEClientTransport | StreamableHTTPClientTransport
|
||||||
|
|
||||||
if (config.transportType === "sse") {
|
if (config.transportType === "sse") {
|
||||||
transport = new SSEClientTransport(new URL(config.url), {})
|
transport = new SSEClientTransport(new URL(config.url), {})
|
||||||
|
} else if (config.transportType === "http") {
|
||||||
|
transport = new StreamableHTTPClientTransport(new URL(config.url), {})
|
||||||
} else {
|
} else {
|
||||||
transport = new StdioClientTransport({
|
transport = new StdioClientTransport({
|
||||||
command: config.command,
|
command: config.command,
|
||||||
@ -297,7 +301,7 @@ export class McpHub {
|
|||||||
|
|
||||||
private async connectToServer(
|
private async connectToServer(
|
||||||
name: string,
|
name: string,
|
||||||
config: z.infer<typeof StdioConfigSchema> | z.infer<typeof SseConfigSchema>,
|
config: z.infer<typeof StdioConfigSchema> | z.infer<typeof SseConfigSchema> | z.infer<typeof StreamableHTTPConfigSchema>,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
// Remove existing connection if it exists (should never happen, the connection should be deleted beforehand)
|
// Remove existing connection if it exists (should never happen, the connection should be deleted beforehand)
|
||||||
this.connections = this.connections.filter((conn) => conn.server.name !== name)
|
this.connections = this.connections.filter((conn) => conn.server.name !== name)
|
||||||
@ -314,10 +318,12 @@ export class McpHub {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
let transport: StdioClientTransport | SSEClientTransport
|
let transport: StdioClientTransport | SSEClientTransport | StreamableHTTPClientTransport
|
||||||
|
|
||||||
if (config.transportType === "sse") {
|
if (config.transportType === "sse") {
|
||||||
transport = new SSEClientTransport(new URL(config.url), {})
|
transport = new SSEClientTransport(new URL(config.url), {})
|
||||||
|
} else if (config.transportType === "http") {
|
||||||
|
transport = new StreamableHTTPClientTransport(new URL(config.url), {})
|
||||||
} else {
|
} else {
|
||||||
transport = new StdioClientTransport({
|
transport = new StdioClientTransport({
|
||||||
command: config.command,
|
command: config.command,
|
||||||
|
Loading…
Reference in New Issue
Block a user