diff --git a/packages/data-provider/specs/mcp.spec.ts b/packages/data-provider/specs/mcp.spec.ts index 573769c4fa..985bccf697 100644 --- a/packages/data-provider/specs/mcp.spec.ts +++ b/packages/data-provider/specs/mcp.spec.ts @@ -1,6 +1,42 @@ -import { SSEOptionsSchema, MCPServerUserInputSchema } from '../src/mcp'; +import { MCPOptionsSchema, SSEOptionsSchema, MCPServerUserInputSchema } from '../src/mcp'; + +describe('MCPOptionsSchema', () => { + describe('title validation', () => { + it('should accept hyphenated MCP server titles in config', () => { + const result = MCPOptionsSchema.safeParse({ + type: 'sse', + url: 'https://example.com/mcp', + title: 'My-Test Server', + }); + + expect(result.success).toBe(true); + }); + + it('should still reject unsupported title characters', () => { + const result = MCPOptionsSchema.safeParse({ + type: 'sse', + url: 'https://example.com/mcp', + title: 'My_Test Server', + }); + + expect(result.success).toBe(false); + }); + }); +}); describe('MCPServerUserInputSchema', () => { + describe('title validation', () => { + it('should accept hyphenated MCP server titles in user input', () => { + const result = MCPServerUserInputSchema.safeParse({ + type: 'sse', + url: 'https://example.com/mcp', + title: 'My-Test Server', + }); + + expect(result.success).toBe(true); + }); + }); + describe('env variable exfiltration prevention', () => { it('should confirm admin schema resolves env vars (attack vector baseline)', () => { process.env.FAKE_SECRET = 'leaked-secret-value'; diff --git a/packages/data-provider/src/mcp.ts b/packages/data-provider/src/mcp.ts index b22a599b9b..150dcfb8a1 100644 --- a/packages/data-provider/src/mcp.ts +++ b/packages/data-provider/src/mcp.ts @@ -3,10 +3,10 @@ import { TokenExchangeMethodEnum } from './types/agents'; import { extractEnvVariable } from './utils'; const BaseOptionsSchema = z.object({ - /** Display name for the MCP server - only letters, numbers, and spaces allowed */ + /** Display name for the MCP server - only letters, numbers, spaces, and hyphens allowed */ title: z .string() - .regex(/^[a-zA-Z0-9 ]+$/, 'Title can only contain letters, numbers, and spaces') + .regex(/^[a-zA-Z0-9 -]+$/, 'Title can only contain letters, numbers, spaces, and hyphens') .optional(), /** Description of the MCP server */ description: z.string().optional(),