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

This commit is contained in:
Kit Langton
2026-04-17 16:25:49 -04:00
committed by GitHub
parent 6af8ab0df2
commit 11fa257549
3 changed files with 58 additions and 64 deletions

View File

@@ -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(),

View File

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

View File

@@ -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) => {