fix(config): add stdio to McpServerSchema transport union (#95102) · openclaw/openclaw@a964132
lzyyzznl
·
2026-06-22
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -253,6 +253,66 @@ describe("config schema", () => {
|
253 | 253 | } |
254 | 254 | }); |
255 | 255 | |
| 256 | +it("accepts stdio transport for command-bearing MCP servers", () => { |
| 257 | +const result = OpenClawSchema.safeParse({ |
| 258 | +mcp: { |
| 259 | +servers: { |
| 260 | +myTool: { |
| 261 | +command: "npx", |
| 262 | +args: ["-y", "@modelcontextprotocol/server-filesystem"], |
| 263 | +transport: "stdio", |
| 264 | +}, |
| 265 | +}, |
| 266 | +}, |
| 267 | +}); |
| 268 | +expect(result.success).toBe(true); |
| 269 | +}); |
| 270 | + |
| 271 | +it("rejects unsupported transport values for MCP servers", () => { |
| 272 | +for (const transport of ["tcp", "websocket", "grpc", ""]) { |
| 273 | +expect(() => |
| 274 | +OpenClawSchema.parse({ |
| 275 | +mcp: { |
| 276 | +servers: { |
| 277 | +bad: { |
| 278 | +url: "https://mcp.example.com/mcp", |
| 279 | + transport, |
| 280 | +}, |
| 281 | +}, |
| 282 | +}, |
| 283 | +}), |
| 284 | +).toThrow(); |
| 285 | +} |
| 286 | +}); |
| 287 | + |
| 288 | +it("rejects stdio transport for URL-only MCP servers (command required)", () => { |
| 289 | +const result = OpenClawSchema.safeParse({ |
| 290 | +mcp: { |
| 291 | +servers: { |
| 292 | +bad: { |
| 293 | +url: "https://mcp.example.com/mcp", |
| 294 | +transport: "stdio", |
| 295 | +}, |
| 296 | +}, |
| 297 | +}, |
| 298 | +}); |
| 299 | +expect(result.success).toBe(false); |
| 300 | +}); |
| 301 | + |
| 302 | +it("rejects stdio transport with whitespace-only command", () => { |
| 303 | +const result = OpenClawSchema.safeParse({ |
| 304 | +mcp: { |
| 305 | +servers: { |
| 306 | +bad: { |
| 307 | +command: " ", |
| 308 | +transport: "stdio", |
| 309 | +}, |
| 310 | +}, |
| 311 | +}, |
| 312 | +}); |
| 313 | +expect(result.success).toBe(false); |
| 314 | +}); |
| 315 | + |
256 | 316 | it("merges plugin ui hints", () => { |
257 | 317 | const res = buildConfigSchema(pluginUiHintInput); |
258 | 318 | |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -36,8 +36,8 @@ export type McpServerConfig = {
|
36 | 36 | workingDirectory?: string; |
37 | 37 | /** HTTP transport: URL of the remote MCP server (http or https). */ |
38 | 38 | url?: string; |
39 | | -/** HTTP transport type for remote MCP servers. */ |
40 | | -transport?: "sse" | "streamable-http"; |
| 39 | +/** Transport type — "stdio" for command-bearing servers, "sse" or "streamable-http" for remote URLs. */ |
| 40 | +transport?: "stdio" | "sse" | "streamable-http"; |
41 | 41 | /** HTTP transport: extra HTTP headers sent with every request. */ |
42 | 42 | headers?: Record<string, string | number | boolean>; |
43 | 43 | /** Optional connection timeout in milliseconds. */ |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -392,7 +392,9 @@ const McpServerSchema = z
|
392 | 392 | cwd: z.string().optional(), |
393 | 393 | workingDirectory: z.string().optional(), |
394 | 394 | url: HttpUrlSchema.optional(), |
395 | | -transport: z.union([z.literal("sse"), z.literal("streamable-http")]).optional(), |
| 395 | +transport: z |
| 396 | +.union([z.literal("stdio"), z.literal("sse"), z.literal("streamable-http")]) |
| 397 | +.optional(), |
396 | 398 | headers: z |
397 | 399 | .record( |
398 | 400 | z.string(), |
@@ -445,6 +447,19 @@ const McpServerSchema = z
|
445 | 447 | .strict() |
446 | 448 | .optional(), |
447 | 449 | }) |
| 450 | +.superRefine((data, ctx) => { |
| 451 | +// transport "stdio" requires a non-empty command — URL-only servers must use "sse" or "streamable-http" |
| 452 | +if ( |
| 453 | +data.transport === "stdio" && |
| 454 | +(typeof data.command !== "string" || data.command.trim().length === 0) |
| 455 | +) { |
| 456 | +ctx.addIssue({ |
| 457 | +code: z.ZodIssueCode.custom, |
| 458 | +message: '"stdio" transport requires a non-empty command', |
| 459 | +path: ["transport"], |
| 460 | +}); |
| 461 | +} |
| 462 | +}) |
448 | 463 | .catchall(z.unknown()); |
449 | 464 | |
450 | 465 | const McpConfigSchema = z |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。