Просмотр исходного кода

refactor(config): migrate mcp schemas to Effect Schema.Class (#23163)

Kit Langton 3 дней назад
Родитель
Сommit
11fa257549

+ 1 - 1
packages/opencode/src/config/config.ts

@@ -178,7 +178,7 @@ export const Info = z
       .record(
       .record(
         z.string(),
         z.string(),
         z.union([
         z.union([
-          ConfigMCP.Info,
+          ConfigMCP.Info.zod,
           z
           z
             .object({
             .object({
               enabled: z.boolean(),
               enabled: z.boolean(),

+ 56 - 62
packages/opencode/src/config/mcp.ts

@@ -1,68 +1,62 @@
-import z from "zod"
+import { Schema } from "effect"
+import { zod } from "@/util/effect-zod"
+import { withStatics } from "@/util/schema"
 
 
-export const Local = z
-  .object({
-    type: z.literal("local").describe("Type of MCP server connection"),
-    command: z.string().array().describe("Command and arguments to run the MCP server"),
-    environment: z
-      .record(z.string(), z.string())
-      .optional()
-      .describe("Environment variables to set when running the MCP server"),
-    enabled: z.boolean().optional().describe("Enable or disable the MCP server on startup"),
-    timeout: z
-      .number()
-      .int()
-      .positive()
-      .optional()
-      .describe("Timeout in ms for MCP server requests. Defaults to 5000 (5 seconds) if not specified."),
-  })
-  .strict()
-  .meta({
-    ref: "McpLocalConfig",
-  })
+export class Local extends Schema.Class<Local>("McpLocalConfig")({
+  type: Schema.Literal("local").annotate({ description: "Type of MCP server connection" }),
+  command: Schema.mutable(Schema.Array(Schema.String)).annotate({
+    description: "Command and arguments to run the MCP server",
+  }),
+  environment: Schema.optional(Schema.Record(Schema.String, Schema.String)).annotate({
+    description: "Environment variables to set when running the MCP server",
+  }),
+  enabled: Schema.optional(Schema.Boolean).annotate({
+    description: "Enable or disable the MCP server on startup",
+  }),
+  timeout: Schema.optional(Schema.Number).annotate({
+    description: "Timeout in ms for MCP server requests. Defaults to 5000 (5 seconds) if not specified.",
+  }),
+}) {
+  static readonly zod = zod(this)
+}
 
 
-export const OAuth = z
-  .object({
-    clientId: z
-      .string()
-      .optional()
-      .describe("OAuth client ID. If not provided, dynamic client registration (RFC 7591) will be attempted."),
-    clientSecret: z.string().optional().describe("OAuth client secret (if required by the authorization server)"),
-    scope: z.string().optional().describe("OAuth scopes to request during authorization"),
-    redirectUri: z
-      .string()
-      .optional()
-      .describe("OAuth redirect URI (default: http://127.0.0.1:19876/mcp/oauth/callback)."),
-  })
-  .strict()
-  .meta({
-    ref: "McpOAuthConfig",
-  })
-export type OAuth = z.infer<typeof OAuth>
+export class OAuth extends Schema.Class<OAuth>("McpOAuthConfig")({
+  clientId: Schema.optional(Schema.String).annotate({
+    description: "OAuth client ID. If not provided, dynamic client registration (RFC 7591) will be attempted.",
+  }),
+  clientSecret: Schema.optional(Schema.String).annotate({
+    description: "OAuth client secret (if required by the authorization server)",
+  }),
+  scope: Schema.optional(Schema.String).annotate({ description: "OAuth scopes to request during authorization" }),
+  redirectUri: Schema.optional(Schema.String).annotate({
+    description: "OAuth redirect URI (default: http://127.0.0.1:19876/mcp/oauth/callback).",
+  }),
+}) {
+  static readonly zod = zod(this)
+}
 
 
-export const Remote = z
-  .object({
-    type: z.literal("remote").describe("Type of MCP server connection"),
-    url: z.string().describe("URL of the remote MCP server"),
-    enabled: z.boolean().optional().describe("Enable or disable the MCP server on startup"),
-    headers: z.record(z.string(), z.string()).optional().describe("Headers to send with the request"),
-    oauth: z
-      .union([OAuth, z.literal(false)])
-      .optional()
-      .describe("OAuth authentication configuration for the MCP server. Set to false to disable OAuth auto-detection."),
-    timeout: z
-      .number()
-      .int()
-      .positive()
-      .optional()
-      .describe("Timeout in ms for MCP server requests. Defaults to 5000 (5 seconds) if not specified."),
-  })
-  .strict()
-  .meta({
-    ref: "McpRemoteConfig",
-  })
+export class Remote extends Schema.Class<Remote>("McpRemoteConfig")({
+  type: Schema.Literal("remote").annotate({ description: "Type of MCP server connection" }),
+  url: Schema.String.annotate({ description: "URL of the remote MCP server" }),
+  enabled: Schema.optional(Schema.Boolean).annotate({
+    description: "Enable or disable the MCP server on startup",
+  }),
+  headers: Schema.optional(Schema.Record(Schema.String, Schema.String)).annotate({
+    description: "Headers to send with the request",
+  }),
+  oauth: Schema.optional(Schema.Union([OAuth, Schema.Literal(false)])).annotate({
+    description: "OAuth authentication configuration for the MCP server. Set to false to disable OAuth auto-detection.",
+  }),
+  timeout: Schema.optional(Schema.Number).annotate({
+    description: "Timeout in ms for MCP server requests. Defaults to 5000 (5 seconds) if not specified.",
+  }),
+}) {
+  static readonly zod = zod(this)
+}
 
 
-export const Info = z.discriminatedUnion("type", [Local, Remote])
-export type Info = z.infer<typeof Info>
+export const Info = Schema.Union([Local, Remote])
+  .annotate({ discriminator: "type" })
+  .pipe(withStatics((s) => ({ zod: zod(s) })))
+export type Info = Schema.Schema.Type<typeof Info>
 
 
 export * as ConfigMCP from "./mcp"
 export * as ConfigMCP from "./mcp"

+ 1 - 1
packages/opencode/src/server/routes/instance/mcp.ts

@@ -54,7 +54,7 @@ export const McpRoutes = lazy(() =>
         "json",
         "json",
         z.object({
         z.object({
           name: z.string(),
           name: z.string(),
-          config: ConfigMCP.Info,
+          config: ConfigMCP.Info.zod,
         }),
         }),
       ),
       ),
       async (c) => {
       async (c) => {