| import { z } from 'zod'; |
| import { TokenExchangeMethodEnum } from './types/agents'; |
| import { extractEnvVariable } from './utils'; |
|
|
| const BaseOptionsSchema = z.object({ |
| |
| |
| |
| |
| |
| |
| startup: z.boolean().optional(), |
| iconPath: z.string().optional(), |
| timeout: z.number().optional(), |
| initTimeout: z.number().optional(), |
| |
| chatMenu: z.boolean().optional(), |
| |
| |
| |
| |
| |
| |
| serverInstructions: z.union([z.boolean(), z.string()]).optional(), |
| |
| |
| |
| |
| requiresOAuth: z.boolean().optional(), |
| |
| |
| |
| |
| |
| oauth: z |
| .object({ |
| |
| authorization_url: z.string().url().optional(), |
| |
| token_url: z.string().url().optional(), |
| |
| client_id: z.string().optional(), |
| |
| client_secret: z.string().optional(), |
| |
| scope: z.string().optional(), |
| |
| redirect_uri: z.string().url().optional(), |
| |
| token_exchange_method: z.nativeEnum(TokenExchangeMethodEnum).optional(), |
| |
| grant_types_supported: z.array(z.string()).optional(), |
| |
| token_endpoint_auth_methods_supported: z.array(z.string()).optional(), |
| |
| response_types_supported: z.array(z.string()).optional(), |
| |
| code_challenge_methods_supported: z.array(z.string()).optional(), |
| |
| skip_code_challenge_check: z.boolean().optional(), |
| |
| revocation_endpoint: z.string().url().optional(), |
| |
| revocation_endpoint_auth_methods_supported: z.array(z.string()).optional(), |
| }) |
| .optional(), |
| |
| oauth_headers: z.record(z.string(), z.string()).optional(), |
| customUserVars: z |
| .record( |
| z.string(), |
| z.object({ |
| title: z.string(), |
| description: z.string(), |
| }), |
| ) |
| .optional(), |
| }); |
|
|
| export const StdioOptionsSchema = BaseOptionsSchema.extend({ |
| type: z.literal('stdio').optional(), |
| |
| |
| |
| command: z.string(), |
| |
| |
| |
| args: z.array(z.string()), |
| |
| |
| |
| |
| |
| |
| env: z |
| .record(z.string(), z.string()) |
| .optional() |
| .transform((env) => { |
| if (!env) { |
| return env; |
| } |
|
|
| const processedEnv: Record<string, string> = {}; |
| for (const [key, value] of Object.entries(env)) { |
| processedEnv[key] = extractEnvVariable(value); |
| } |
| return processedEnv; |
| }), |
| |
| |
| |
| |
| |
| |
| |
| stderr: z.any().optional(), |
| }); |
|
|
| export const WebSocketOptionsSchema = BaseOptionsSchema.extend({ |
| type: z.literal('websocket').optional(), |
| url: z |
| .string() |
| .transform((val: string) => extractEnvVariable(val)) |
| .pipe(z.string().url()) |
| .refine( |
| (val: string) => { |
| const protocol = new URL(val).protocol; |
| return protocol === 'ws:' || protocol === 'wss:'; |
| }, |
| { |
| message: 'WebSocket URL must start with ws:// or wss://', |
| }, |
| ), |
| }); |
|
|
| export const SSEOptionsSchema = BaseOptionsSchema.extend({ |
| type: z.literal('sse').optional(), |
| headers: z.record(z.string(), z.string()).optional(), |
| url: z |
| .string() |
| .transform((val: string) => extractEnvVariable(val)) |
| .pipe(z.string().url()) |
| .refine( |
| (val: string) => { |
| const protocol = new URL(val).protocol; |
| return protocol !== 'ws:' && protocol !== 'wss:'; |
| }, |
| { |
| message: 'SSE URL must not start with ws:// or wss://', |
| }, |
| ), |
| }); |
|
|
| export const StreamableHTTPOptionsSchema = BaseOptionsSchema.extend({ |
| type: z.union([z.literal('streamable-http'), z.literal('http')]), |
| headers: z.record(z.string(), z.string()).optional(), |
| url: z |
| .string() |
| .transform((val: string) => extractEnvVariable(val)) |
| .pipe(z.string().url()) |
| .refine( |
| (val: string) => { |
| const protocol = new URL(val).protocol; |
| return protocol !== 'ws:' && protocol !== 'wss:'; |
| }, |
| { |
| message: 'Streamable HTTP URL must not start with ws:// or wss://', |
| }, |
| ), |
| }); |
|
|
| export const MCPOptionsSchema = z.union([ |
| StdioOptionsSchema, |
| WebSocketOptionsSchema, |
| SSEOptionsSchema, |
| StreamableHTTPOptionsSchema, |
| ]); |
|
|
| export const MCPServersSchema = z.record(z.string(), MCPOptionsSchema); |
|
|
| export type MCPOptions = z.infer<typeof MCPOptionsSchema>; |
|
|