@wener/mcps 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +144 -0
  2. package/dist/index.mjs +213076 -1
  3. package/dist/mcps-cli.mjs +102547 -59344
  4. package/lib/chat/handler.js +2 -2
  5. package/lib/chat/handler.js.map +1 -1
  6. package/lib/cli-start.js +36 -0
  7. package/lib/cli-start.js.map +1 -0
  8. package/lib/cli.js +19 -0
  9. package/lib/cli.js.map +1 -0
  10. package/lib/dev.server.js +7 -1
  11. package/lib/dev.server.js.map +1 -1
  12. package/lib/index.js +21 -3
  13. package/lib/index.js.map +1 -1
  14. package/lib/mcps-cli.js +6 -35
  15. package/lib/mcps-cli.js.map +1 -1
  16. package/lib/providers/feishu/def.js +35 -0
  17. package/lib/providers/feishu/def.js.map +1 -0
  18. package/lib/providers/findMcpServerDef.js +1 -0
  19. package/lib/providers/findMcpServerDef.js.map +1 -1
  20. package/lib/scripts/bundle.js +7 -1
  21. package/lib/scripts/bundle.js.map +1 -1
  22. package/lib/server/api-routes.js +7 -8
  23. package/lib/server/api-routes.js.map +1 -1
  24. package/lib/server/audit-db.js +64 -0
  25. package/lib/server/audit-db.js.map +1 -0
  26. package/lib/server/{audit.js → audit-plugin.js} +72 -126
  27. package/lib/server/audit-plugin.js.map +1 -0
  28. package/lib/server/events.js +13 -0
  29. package/lib/server/events.js.map +1 -0
  30. package/lib/server/mcp-routes.js +31 -60
  31. package/lib/server/mcp-routes.js.map +1 -1
  32. package/lib/server/mcps-router.js +19 -24
  33. package/lib/server/mcps-router.js.map +1 -1
  34. package/lib/server/schema.js +22 -2
  35. package/lib/server/schema.js.map +1 -1
  36. package/lib/server/server.js +142 -87
  37. package/lib/server/server.js.map +1 -1
  38. package/package.json +33 -6
  39. package/src/chat/handler.ts +2 -2
  40. package/src/cli-start.ts +43 -0
  41. package/src/cli.ts +45 -0
  42. package/src/dev.server.ts +8 -1
  43. package/src/index.ts +47 -1
  44. package/src/mcps-cli.ts +6 -48
  45. package/src/providers/feishu/def.ts +37 -0
  46. package/src/providers/findMcpServerDef.ts +1 -0
  47. package/src/scripts/bundle.ts +12 -1
  48. package/src/server/api-routes.ts +11 -8
  49. package/src/server/audit-db.ts +65 -0
  50. package/src/server/{audit.ts → audit-plugin.ts} +69 -142
  51. package/src/server/events.ts +29 -0
  52. package/src/server/mcp-routes.ts +30 -58
  53. package/src/server/mcps-router.ts +21 -29
  54. package/src/server/schema.ts +23 -2
  55. package/src/server/server.ts +149 -81
  56. package/lib/server/audit.js.map +0 -1
  57. package/lib/server/db.js +0 -97
  58. package/lib/server/db.js.map +0 -1
  59. package/src/server/db.ts +0 -115
@@ -5,18 +5,19 @@ import { findMcpServerDef } from "../providers/findMcpServerDef.js";
5
5
  import { createMcpLoggingHandler } from "./mcp-handler.js";
6
6
  const log = consola.withTag("mcps");
7
7
  /**
8
- * Register MCP routes for both pre-configured and dynamic endpoints
9
- */ export function registerMcpRoutes({ app, config, serverCache }) {
8
+ * Register MCP routes for both pre-configured and dynamic endpoints.
9
+ *
10
+ * McpServer only supports one transport connection at a time, so we create
11
+ * a fresh server instance per request instead of caching stateful servers.
12
+ */ export function registerMcpRoutes({ app, config, serverCache: _serverCache }) {
10
13
  const serverDefs = findMcpServerDef();
11
14
  // Register pre-configured servers from config
12
- // These are named endpoints like /mcp/my-sql that use config from file
13
15
  for (const [name, serverConfig] of Object.entries(config.servers)) {
14
16
  const def = getMcpServerHandlerDef(serverConfig.type);
15
17
  if (!def) {
16
18
  log.warn(`Unknown server type for ${name}: ${serverConfig.type}`);
17
19
  continue;
18
20
  }
19
- // Resolve config using def (config comes from file, not headers)
20
21
  const options = def.resolveConfig(serverConfig);
21
22
  if (!options) {
22
23
  log.warn(`Failed to resolve config for ${name}`);
@@ -27,86 +28,56 @@ const log = consola.withTag("mcps");
27
28
  log.warn(`Invalid config for ${name}: ${validation.error}`);
28
29
  continue;
29
30
  }
30
- // Create and cache the server instance at startup
31
- const cacheKey = `config::${name}`;
32
- const item = def.create(options);
33
- if (!item) {
34
- log.warn(`Failed to create server: ${name}`);
35
- continue;
36
- }
37
- serverCache.set(cacheKey, item);
38
31
  const path = `/mcp/${name}`;
39
32
  log.info(`Registered MCP server: ${path} (${serverConfig.type})`);
40
33
  app.all(path, async (c) => {
41
- const serverItem = serverCache.get(cacheKey);
42
- if (!serverItem) {
43
- return c.text("Server not found", 404);
44
- }
45
- // Create a new transport for each request to avoid "Transport already started" error
46
- const transport = new StreamableHTTPTransport();
47
- try {
48
- await serverItem.server.connect(transport);
49
- const handleRequest = createMcpLoggingHandler(transport, name);
50
- return await handleRequest(c);
51
- }
52
- catch (e) {
53
- log.error(`[${name}] Request error:`, e);
54
- return c.text(`Internal server error: ${e instanceof Error ? e.message : "Unknown error"}`, 500);
55
- }
34
+ return handleMcpRequest(c, def, options, name);
56
35
  });
57
36
  }
58
- // Register dynamic endpoints for all server types
59
- // These endpoints accept config via HTTP headers
37
+ // Register dynamic endpoints for all server types (header-based config)
60
38
  for (const def of serverDefs) {
61
39
  const path = `/mcp/${def.name}`;
62
40
  log.debug(`Registering dynamic endpoint: ${path}`);
63
41
  app.all(path, async (c) => {
64
- // Use def.resolveConfig to parse config from headers
65
42
  const options = def.resolveConfig({
66
43
  type: def.name
67
44
  }, c.req.raw.headers);
68
45
  if (!options) {
69
- // Build error message from headerMappings
70
46
  const requiredHeaders = def.headerMappings?.filter((m) => m.required).map((m) => m.header).join(", ") || "required headers";
71
47
  return c.text(`Missing ${requiredHeaders}`, 400);
72
48
  }
73
- // Validate options
74
49
  const validation = def.validateOptions(options);
75
50
  if (!validation.valid) {
76
51
  return c.text(validation.error || `Invalid configuration for ${def.name}`, 400);
77
52
  }
78
- // Get or create cached server instance
79
- const key = def.getCacheKey(options);
80
- let item = serverCache.get(key);
81
- if (!item) {
82
- log.info(`Creating new ${def.title} server: ${key}`);
83
- try {
84
- const newItem = def.create(options);
85
- if (!newItem)
86
- return c.text(`Failed to create ${def.name} server`, 500);
87
- item = newItem;
88
- serverCache.set(key, item);
89
- }
90
- catch (e) {
91
- log.error(`Failed to create ${def.name} server:`, e);
92
- return c.text(`Failed to create ${def.name} server`, 500);
93
- }
94
- }
95
- // Create a new transport for each request
96
- const transport = new StreamableHTTPTransport();
97
- try {
98
- await item.server.connect(transport);
99
- const handleRequest = createMcpLoggingHandler(transport, def.name);
100
- return await handleRequest(c);
101
- }
102
- catch (e) {
103
- log.error(`[${def.name}] Request error:`, e);
104
- return c.text(`Internal server error: ${e instanceof Error ? e.message : "Unknown error"}`, 500);
105
- }
53
+ return handleMcpRequest(c, def, options, def.name);
106
54
  });
107
55
  }
108
56
  return {
109
57
  serverDefs
110
58
  };
111
59
  }
60
+ async function handleMcpRequest(c, def, options, name) {
61
+ let item;
62
+ try {
63
+ item = def.create(options);
64
+ if (!item)
65
+ return c.text(`Failed to create ${name} server`, 500);
66
+ }
67
+ catch (e) {
68
+ log.error(`Failed to create ${name} server:`, e);
69
+ return c.text(`Failed to create ${name} server`, 500);
70
+ }
71
+ const transport = new StreamableHTTPTransport();
72
+ try {
73
+ await item.server.connect(transport);
74
+ const handleRequest = createMcpLoggingHandler(transport, name);
75
+ return await handleRequest(c);
76
+ }
77
+ catch (e) {
78
+ log.error(`[${name}] Request error:`, e);
79
+ item.close?.().catch(() => { });
80
+ return c.text(`Internal server error: ${e instanceof Error ? e.message : "Unknown error"}`, 500);
81
+ }
82
+ }
112
83
  //# sourceMappingURL=mcp-routes.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/mcp-routes.ts"],"sourcesContent":["import { StreamableHTTPTransport } from '@hono/mcp';\nimport consola from 'consola';\nimport type { Hono } from 'hono';\nimport type { LRUCache } from 'lru-cache';\nimport type { McpServerInstance } from '@wener/ai/mcp';\nimport { getMcpServerHandlerDef, type McpServerHandlerDef } from '../providers/McpServerHandlerDef';\nimport { findMcpServerDef } from '../providers/findMcpServerDef';\nimport { createMcpLoggingHandler } from './mcp-handler';\nimport type { McpsConfig, ServerConfig } from './schema';\n\nconst log = consola.withTag('mcps');\n\nexport interface RegisterMcpRoutesOptions {\n\tapp: Hono;\n\tconfig: McpsConfig;\n\tserverCache: LRUCache<string, McpServerInstance>;\n}\n\n/**\n * Register MCP routes for both pre-configured and dynamic endpoints\n */\nexport function registerMcpRoutes({ app, config, serverCache }: RegisterMcpRoutesOptions) {\n\tconst serverDefs = findMcpServerDef();\n\n\t// Register pre-configured servers from config\n\t// These are named endpoints like /mcp/my-sql that use config from file\n\tfor (const [name, serverConfig] of Object.entries(config.servers)) {\n\t\tconst def = getMcpServerHandlerDef(serverConfig.type);\n\t\tif (!def) {\n\t\t\tlog.warn(`Unknown server type for ${name}: ${serverConfig.type}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Resolve config using def (config comes from file, not headers)\n\t\tconst options = def.resolveConfig(serverConfig);\n\t\tif (!options) {\n\t\t\tlog.warn(`Failed to resolve config for ${name}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst validation = def.validateOptions(options);\n\t\tif (!validation.valid) {\n\t\t\tlog.warn(`Invalid config for ${name}: ${validation.error}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Create and cache the server instance at startup\n\t\tconst cacheKey = `config::${name}`;\n\t\tconst item = def.create(options);\n\t\tif (!item) {\n\t\t\tlog.warn(`Failed to create server: ${name}`);\n\t\t\tcontinue;\n\t\t}\n\t\tserverCache.set(cacheKey, item);\n\n\t\tconst path = `/mcp/${name}`;\n\t\tlog.info(`Registered MCP server: ${path} (${serverConfig.type})`);\n\n\t\tapp.all(path, async (c) => {\n\t\t\tconst serverItem = serverCache.get(cacheKey);\n\t\t\tif (!serverItem) {\n\t\t\t\treturn c.text('Server not found', 404);\n\t\t\t}\n\t\t\t// Create a new transport for each request to avoid \"Transport already started\" error\n\t\t\tconst transport = new StreamableHTTPTransport();\n\t\t\ttry {\n\t\t\t\tawait serverItem.server.connect(transport);\n\t\t\t\tconst handleRequest = createMcpLoggingHandler(transport, name);\n\t\t\t\treturn await handleRequest(c);\n\t\t\t} catch (e) {\n\t\t\t\tlog.error(`[${name}] Request error:`, e);\n\t\t\t\treturn c.text(`Internal server error: ${e instanceof Error ? e.message : 'Unknown error'}`, 500);\n\t\t\t}\n\t\t});\n\t}\n\n\t// Register dynamic endpoints for all server types\n\t// These endpoints accept config via HTTP headers\n\tfor (const def of serverDefs) {\n\t\tconst path = `/mcp/${def.name}`;\n\t\tlog.debug(`Registering dynamic endpoint: ${path}`);\n\n\t\tapp.all(path, async (c) => {\n\t\t\t// Use def.resolveConfig to parse config from headers\n\t\t\tconst options = def.resolveConfig({ type: def.name } as any, c.req.raw.headers);\n\n\t\t\tif (!options) {\n\t\t\t\t// Build error message from headerMappings\n\t\t\t\tconst requiredHeaders =\n\t\t\t\t\tdef.headerMappings\n\t\t\t\t\t\t?.filter((m) => m.required)\n\t\t\t\t\t\t.map((m) => m.header)\n\t\t\t\t\t\t.join(', ') || 'required headers';\n\t\t\t\treturn c.text(`Missing ${requiredHeaders}`, 400);\n\t\t\t}\n\n\t\t\t// Validate options\n\t\t\tconst validation = def.validateOptions(options);\n\t\t\tif (!validation.valid) {\n\t\t\t\treturn c.text(validation.error || `Invalid configuration for ${def.name}`, 400);\n\t\t\t}\n\n\t\t\t// Get or create cached server instance\n\t\t\tconst key = def.getCacheKey(options);\n\t\t\tlet item = serverCache.get(key);\n\t\t\tif (!item) {\n\t\t\t\tlog.info(`Creating new ${def.title} server: ${key}`);\n\t\t\t\ttry {\n\t\t\t\t\tconst newItem = def.create(options);\n\t\t\t\t\tif (!newItem) return c.text(`Failed to create ${def.name} server`, 500);\n\t\t\t\t\titem = newItem;\n\t\t\t\t\tserverCache.set(key, item);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tlog.error(`Failed to create ${def.name} server:`, e);\n\t\t\t\t\treturn c.text(`Failed to create ${def.name} server`, 500);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Create a new transport for each request\n\t\t\tconst transport = new StreamableHTTPTransport();\n\t\t\ttry {\n\t\t\t\tawait item.server.connect(transport);\n\t\t\t\tconst handleRequest = createMcpLoggingHandler(transport, def.name);\n\t\t\t\treturn await handleRequest(c);\n\t\t\t} catch (e) {\n\t\t\t\tlog.error(`[${def.name}] Request error:`, e);\n\t\t\t\treturn c.text(`Internal server error: ${e instanceof Error ? e.message : 'Unknown error'}`, 500);\n\t\t\t}\n\t\t});\n\t}\n\n\treturn { serverDefs };\n}\n"],"names":["StreamableHTTPTransport","consola","getMcpServerHandlerDef","findMcpServerDef","createMcpLoggingHandler","log","withTag","registerMcpRoutes","app","config","serverCache","serverDefs","name","serverConfig","Object","entries","servers","def","type","warn","options","resolveConfig","validation","validateOptions","valid","error","cacheKey","item","create","set","path","info","all","c","serverItem","get","text","transport","server","connect","handleRequest","e","Error","message","debug","req","raw","headers","requiredHeaders","headerMappings","filter","m","required","map","header","join","key","getCacheKey","title","newItem"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/server/mcp-routes.ts"],"sourcesContent":["import { StreamableHTTPTransport } from '@hono/mcp';\nimport consola from 'consola';\nimport type { Hono } from 'hono';\nimport type { LRUCache } from 'lru-cache';\nimport type { McpServerInstance } from '@wener/ai/mcp';\nimport { getMcpServerHandlerDef, type McpServerHandlerDef } from '../providers/McpServerHandlerDef';\nimport { findMcpServerDef } from '../providers/findMcpServerDef';\nimport { createMcpLoggingHandler } from './mcp-handler';\nimport type { McpsConfig, ServerConfig } from './schema';\n\nconst log = consola.withTag('mcps');\n\nexport interface RegisterMcpRoutesOptions {\n\tapp: Hono;\n\tconfig: McpsConfig;\n\tserverCache: LRUCache<string, McpServerInstance>;\n}\n\n/**\n * Register MCP routes for both pre-configured and dynamic endpoints.\n *\n * McpServer only supports one transport connection at a time, so we create\n * a fresh server instance per request instead of caching stateful servers.\n */\nexport function registerMcpRoutes({ app, config, serverCache: _serverCache }: RegisterMcpRoutesOptions) {\n\tconst serverDefs = findMcpServerDef();\n\n\t// Register pre-configured servers from config\n\tfor (const [name, serverConfig] of Object.entries(config.servers)) {\n\t\tconst def = getMcpServerHandlerDef(serverConfig.type);\n\t\tif (!def) {\n\t\t\tlog.warn(`Unknown server type for ${name}: ${serverConfig.type}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst options = def.resolveConfig(serverConfig);\n\t\tif (!options) {\n\t\t\tlog.warn(`Failed to resolve config for ${name}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst validation = def.validateOptions(options);\n\t\tif (!validation.valid) {\n\t\t\tlog.warn(`Invalid config for ${name}: ${validation.error}`);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst path = `/mcp/${name}`;\n\t\tlog.info(`Registered MCP server: ${path} (${serverConfig.type})`);\n\n\t\tapp.all(path, async (c) => {\n\t\t\treturn handleMcpRequest(c, def, options, name);\n\t\t});\n\t}\n\n\t// Register dynamic endpoints for all server types (header-based config)\n\tfor (const def of serverDefs) {\n\t\tconst path = `/mcp/${def.name}`;\n\t\tlog.debug(`Registering dynamic endpoint: ${path}`);\n\n\t\tapp.all(path, async (c) => {\n\t\t\tconst options = def.resolveConfig({ type: def.name } as any, c.req.raw.headers);\n\n\t\t\tif (!options) {\n\t\t\t\tconst requiredHeaders =\n\t\t\t\t\tdef.headerMappings\n\t\t\t\t\t\t?.filter((m) => m.required)\n\t\t\t\t\t\t.map((m) => m.header)\n\t\t\t\t\t\t.join(', ') || 'required headers';\n\t\t\t\treturn c.text(`Missing ${requiredHeaders}`, 400);\n\t\t\t}\n\n\t\t\tconst validation = def.validateOptions(options);\n\t\t\tif (!validation.valid) {\n\t\t\t\treturn c.text(validation.error || `Invalid configuration for ${def.name}`, 400);\n\t\t\t}\n\n\t\t\treturn handleMcpRequest(c, def, options, def.name);\n\t\t});\n\t}\n\n\treturn { serverDefs };\n}\n\nasync function handleMcpRequest(c: any, def: McpServerHandlerDef, options: any, name: string) {\n\tlet item: McpServerInstance | undefined;\n\ttry {\n\t\titem = def.create(options);\n\t\tif (!item) return c.text(`Failed to create ${name} server`, 500);\n\t} catch (e) {\n\t\tlog.error(`Failed to create ${name} server:`, e);\n\t\treturn c.text(`Failed to create ${name} server`, 500);\n\t}\n\n\tconst transport = new StreamableHTTPTransport();\n\ttry {\n\t\tawait item.server.connect(transport);\n\t\tconst handleRequest = createMcpLoggingHandler(transport, name);\n\t\treturn await handleRequest(c);\n\t} catch (e) {\n\t\tlog.error(`[${name}] Request error:`, e);\n\t\titem.close?.().catch(() => {});\n\t\treturn c.text(`Internal server error: ${e instanceof Error ? e.message : 'Unknown error'}`, 500);\n\t}\n}\n"],"names":["StreamableHTTPTransport","consola","getMcpServerHandlerDef","findMcpServerDef","createMcpLoggingHandler","log","withTag","registerMcpRoutes","app","config","serverCache","_serverCache","serverDefs","name","serverConfig","Object","entries","servers","def","type","warn","options","resolveConfig","validation","validateOptions","valid","error","path","info","all","c","handleMcpRequest","debug","req","raw","headers","requiredHeaders","headerMappings","filter","m","required","map","header","join","text","item","create","e","transport","server","connect","handleRequest","close","catch","Error","message"],"mappings":"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"}
@@ -1,14 +1,10 @@
1
1
  import { implement } from "@orpc/server";
2
2
  import { McpsContract } from "../contracts/index.js";
3
3
  import { findMcpServerDef } from "../providers/findMcpServerDef.js";
4
- import { getAuditStats, queryAuditEvents } from "./audit.js";
5
- // Simple glob pattern matching
6
4
  function matchGlob(pattern, text) {
7
- const regexPattern = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&") // Escape regex special chars except * and ?
8
- .replace(/\*/g, ".*").replace(/\?/g, ".");
5
+ const regexPattern = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*").replace(/\?/g, ".");
9
6
  return new RegExp(`^${regexPattern}$`, "i").test(text);
10
7
  }
11
- // Build server types from registry
12
8
  function getServerTypes() {
13
9
  return findMcpServerDef().map((def) => ({
14
10
  type: def.name,
@@ -16,7 +12,6 @@ function getServerTypes() {
16
12
  dynamicEndpoint: `/mcp/${def.name}`
17
13
  }));
18
14
  }
19
- // Build endpoints from server types
20
15
  function getEndpoints() {
21
16
  const mcpEndpoints = findMcpServerDef().map((def) => `/mcp/${def.name}`);
22
17
  const chatEndpoints = [
@@ -32,17 +27,20 @@ function getEndpoints() {
32
27
  ...chatEndpoints
33
28
  ];
34
29
  }
35
- /**
36
- * Create MCPS Router with config context
37
- */ export function createMcpsRouter(ctx) {
38
- const { config } = ctx;
39
- // Build server info list
30
+ const emptyStats = {
31
+ totalRequests: 0,
32
+ totalErrors: 0,
33
+ avgDurationMs: 0,
34
+ byServer: [],
35
+ byMethod: []
36
+ };
37
+ export function createMcpsRouter(ctx) {
38
+ const { config, statsProvider } = ctx;
40
39
  const servers = Object.entries(config.servers).map(([name, serverConfig]) => ({
41
40
  name,
42
41
  type: serverConfig.type,
43
42
  disabled: serverConfig.disabled
44
43
  }));
45
- // Build model info list
46
44
  const models = (config.models ?? []).map((model) => ({
47
45
  name: model.name,
48
46
  adapter: model.adapter,
@@ -63,9 +61,14 @@ function getEndpoints() {
63
61
  };
64
62
  }),
65
63
  stats: implement(McpsContract.stats).handler(async ({ input }) => {
66
- const auditStats = getAuditStats(input);
67
- // Build endpoint stats from audit events
68
- const { events } = queryAuditEvents({
64
+ if (!statsProvider) {
65
+ return {
66
+ ...emptyStats,
67
+ byEndpoint: []
68
+ };
69
+ }
70
+ const auditStats = statsProvider.getStats(input);
71
+ const { events } = statsProvider.queryEvents({
69
72
  limit: 10000
70
73
  });
71
74
  const endpointCounts = new Map();
@@ -76,7 +79,7 @@ function getEndpoints() {
76
79
  const byEndpoint = Array.from(endpointCounts.entries()).map(([endpoint, count]) => ({
77
80
  endpoint,
78
81
  count
79
- })).sort((a, b) => b.count - a.count).slice(0, 20); // Top 20 endpoints
82
+ })).sort((a, b) => b.count - a.count).slice(0, 20);
80
83
  return {
81
84
  ...auditStats,
82
85
  byEndpoint
@@ -93,15 +96,7 @@ function getEndpoints() {
93
96
  };
94
97
  }),
95
98
  tools: implement(McpsContract.tools).handler(async ({ input }) => {
96
- // TODO: This is a placeholder that returns empty tools list.
97
- // Full implementation would require connecting to each MCP server
98
- // and calling tools/list. Consider caching tool lists and
99
- // refreshing periodically or on demand.
100
99
  const tools = [];
101
- // For now, return an empty list.
102
- // When MCP servers support persistent connections or when we
103
- // implement a tool registry, this will be populated.
104
- // Apply filters if provided
105
100
  let filteredTools = tools;
106
101
  if (input.server) {
107
102
  filteredTools = filteredTools.filter((t) => t.serverName === input.server);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/mcps-router.ts"],"sourcesContent":["import { implement } from '@orpc/server';\nimport { McpsContract, type ModelInfo, type ServerInfo, type ServerTypeInfo, type ToolInfo } from '../contracts';\nimport { findMcpServerDef } from '../providers/findMcpServerDef';\nimport { getAuditStats, queryAuditEvents } from './audit';\nimport type { McpsConfig } from './schema';\n\n// Simple glob pattern matching\nfunction matchGlob(pattern: string, text: string): boolean {\n\tconst regexPattern = pattern\n\t\t.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&') // Escape regex special chars except * and ?\n\t\t.replace(/\\*/g, '.*')\n\t\t.replace(/\\?/g, '.');\n\treturn new RegExp(`^${regexPattern}$`, 'i').test(text);\n}\n\n// Build server types from registry\nfunction getServerTypes(): ServerTypeInfo[] {\n\treturn findMcpServerDef().map((def) => ({\n\t\ttype: def.name,\n\t\tdescription: def.description,\n\t\tdynamicEndpoint: `/mcp/${def.name}`,\n\t}));\n}\n\n// Build endpoints from server types\nfunction getEndpoints(): string[] {\n\tconst mcpEndpoints = findMcpServerDef().map((def) => `/mcp/${def.name}`);\n\tconst chatEndpoints = [\n\t\t'/v1/chat/completions',\n\t\t'/v1/messages',\n\t\t'/v1/models',\n\t\t'/v1/responses',\n\t\t'/v1/models/:model:generateContent',\n\t\t'/v1/models/:model:streamGenerateContent',\n\t];\n\treturn [...mcpEndpoints, ...chatEndpoints];\n}\n\nexport interface McpsRouterContext {\n\tconfig: McpsConfig;\n}\n\n/**\n * Create MCPS Router with config context\n */\nexport function createMcpsRouter(ctx: McpsRouterContext) {\n\tconst { config } = ctx;\n\n\t// Build server info list\n\tconst servers: ServerInfo[] = Object.entries(config.servers).map(([name, serverConfig]) => ({\n\t\tname,\n\t\ttype: serverConfig.type,\n\t\tdisabled: serverConfig.disabled,\n\t}));\n\n\t// Build model info list\n\tconst models: ModelInfo[] = (config.models ?? []).map((model) => ({\n\t\tname: model.name,\n\t\tadapter: model.adapter,\n\t\tbaseUrl: model.baseUrl,\n\t\tcontextWindow: model.contextWindow,\n\t\tmaxInputTokens: model.maxInputTokens,\n\t\tmaxOutputTokens: model.maxOutputTokens,\n\t}));\n\n\treturn implement(McpsContract).router({\n\t\toverview: implement(McpsContract.overview).handler(async () => {\n\t\t\treturn {\n\t\t\t\tname: '@wener/mcps',\n\t\t\t\tversion: '0.1.0',\n\t\t\t\tservers,\n\t\t\t\tserverTypes: getServerTypes(),\n\t\t\t\tmodels,\n\t\t\t\tendpoints: getEndpoints(),\n\t\t\t};\n\t\t}),\n\n\t\tstats: implement(McpsContract.stats).handler(async ({ input }) => {\n\t\t\tconst auditStats = getAuditStats(input);\n\n\t\t\t// Build endpoint stats from audit events\n\t\t\tconst { events } = queryAuditEvents({ limit: 10000 });\n\t\t\tconst endpointCounts = new Map<string, number>();\n\t\t\tfor (const event of events) {\n\t\t\t\tconst endpoint = event.path || 'unknown';\n\t\t\t\tendpointCounts.set(endpoint, (endpointCounts.get(endpoint) || 0) + 1);\n\t\t\t}\n\t\t\tconst byEndpoint = Array.from(endpointCounts.entries())\n\t\t\t\t.map(([endpoint, count]) => ({ endpoint, count }))\n\t\t\t\t.sort((a, b) => b.count - a.count)\n\t\t\t\t.slice(0, 20); // Top 20 endpoints\n\n\t\t\treturn {\n\t\t\t\t...auditStats,\n\t\t\t\tbyEndpoint,\n\t\t\t};\n\t\t}),\n\n\t\tservers: implement(McpsContract.servers).handler(async () => {\n\t\t\treturn { servers };\n\t\t}),\n\n\t\tmodels: implement(McpsContract.models).handler(async () => {\n\t\t\treturn { models };\n\t\t}),\n\n\t\ttools: implement(McpsContract.tools).handler(async ({ input }) => {\n\t\t\t// TODO: This is a placeholder that returns empty tools list.\n\t\t\t// Full implementation would require connecting to each MCP server\n\t\t\t// and calling tools/list. Consider caching tool lists and\n\t\t\t// refreshing periodically or on demand.\n\t\t\tconst tools: ToolInfo[] = [];\n\n\t\t\t// For now, return an empty list.\n\t\t\t// When MCP servers support persistent connections or when we\n\t\t\t// implement a tool registry, this will be populated.\n\n\t\t\t// Apply filters if provided\n\t\t\tlet filteredTools = tools;\n\n\t\t\tif (input.server) {\n\t\t\t\tfilteredTools = filteredTools.filter((t) => t.serverName === input.server);\n\t\t\t}\n\n\t\t\tif (input.filter) {\n\t\t\t\tconst patterns = input.filter.split(',').map((p) => p.trim());\n\t\t\t\tfilteredTools = filteredTools.filter((t) => patterns.some((pattern) => matchGlob(pattern, t.name)));\n\t\t\t}\n\n\t\t\treturn { tools: filteredTools };\n\t\t}),\n\t});\n}\n"],"names":["implement","McpsContract","findMcpServerDef","getAuditStats","queryAuditEvents","matchGlob","pattern","text","regexPattern","replace","RegExp","test","getServerTypes","map","def","type","name","description","dynamicEndpoint","getEndpoints","mcpEndpoints","chatEndpoints","createMcpsRouter","ctx","config","servers","Object","entries","serverConfig","disabled","models","model","adapter","baseUrl","contextWindow","maxInputTokens","maxOutputTokens","router","overview","handler","version","serverTypes","endpoints","stats","input","auditStats","events","limit","endpointCounts","Map","event","endpoint","path","set","get","byEndpoint","Array","from","count","sort","a","b","slice","tools","filteredTools","server","filter","t","serverName","patterns","split","p","trim","some"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/server/mcps-router.ts"],"sourcesContent":["import { implement } from '@orpc/server';\nimport { McpsContract, type ModelInfo, type ServerInfo, type ServerTypeInfo, type ToolInfo } from '../contracts';\nimport { findMcpServerDef } from '../providers/findMcpServerDef';\nimport type { McpsConfig } from './schema';\nimport type { StatsProvider } from './server';\n\nfunction matchGlob(pattern: string, text: string): boolean {\n\tconst regexPattern = pattern\n\t\t.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&')\n\t\t.replace(/\\*/g, '.*')\n\t\t.replace(/\\?/g, '.');\n\treturn new RegExp(`^${regexPattern}$`, 'i').test(text);\n}\n\nfunction getServerTypes(): ServerTypeInfo[] {\n\treturn findMcpServerDef().map((def) => ({\n\t\ttype: def.name,\n\t\tdescription: def.description,\n\t\tdynamicEndpoint: `/mcp/${def.name}`,\n\t}));\n}\n\nfunction getEndpoints(): string[] {\n\tconst mcpEndpoints = findMcpServerDef().map((def) => `/mcp/${def.name}`);\n\tconst chatEndpoints = [\n\t\t'/v1/chat/completions',\n\t\t'/v1/messages',\n\t\t'/v1/models',\n\t\t'/v1/responses',\n\t\t'/v1/models/:model:generateContent',\n\t\t'/v1/models/:model:streamGenerateContent',\n\t];\n\treturn [...mcpEndpoints, ...chatEndpoints];\n}\n\nexport interface McpsRouterContext {\n\tconfig: McpsConfig;\n\t/** Optional stats provider (e.g. from audit plugin) */\n\tstatsProvider?: StatsProvider;\n}\n\nconst emptyStats = {\n\ttotalRequests: 0,\n\ttotalErrors: 0,\n\tavgDurationMs: 0,\n\tbyServer: [] as Array<{ name: string; count: number }>,\n\tbyMethod: [] as Array<{ method: string; count: number }>,\n};\n\nexport function createMcpsRouter(ctx: McpsRouterContext) {\n\tconst { config, statsProvider } = ctx;\n\n\tconst servers: ServerInfo[] = Object.entries(config.servers).map(([name, serverConfig]) => ({\n\t\tname,\n\t\ttype: serverConfig.type,\n\t\tdisabled: serverConfig.disabled,\n\t}));\n\n\tconst models: ModelInfo[] = (config.models ?? []).map((model) => ({\n\t\tname: model.name,\n\t\tadapter: model.adapter,\n\t\tbaseUrl: model.baseUrl,\n\t\tcontextWindow: model.contextWindow,\n\t\tmaxInputTokens: model.maxInputTokens,\n\t\tmaxOutputTokens: model.maxOutputTokens,\n\t}));\n\n\treturn implement(McpsContract).router({\n\t\toverview: implement(McpsContract.overview).handler(async () => {\n\t\t\treturn {\n\t\t\t\tname: '@wener/mcps',\n\t\t\t\tversion: '0.1.0',\n\t\t\t\tservers,\n\t\t\t\tserverTypes: getServerTypes(),\n\t\t\t\tmodels,\n\t\t\t\tendpoints: getEndpoints(),\n\t\t\t};\n\t\t}),\n\n\t\tstats: implement(McpsContract.stats).handler(async ({ input }) => {\n\t\t\tif (!statsProvider) {\n\t\t\t\treturn { ...emptyStats, byEndpoint: [] };\n\t\t\t}\n\n\t\t\tconst auditStats = statsProvider.getStats(input);\n\t\t\tconst { events } = statsProvider.queryEvents({ limit: 10000 });\n\n\t\t\tconst endpointCounts = new Map<string, number>();\n\t\t\tfor (const event of events) {\n\t\t\t\tconst endpoint = event.path || 'unknown';\n\t\t\t\tendpointCounts.set(endpoint, (endpointCounts.get(endpoint) || 0) + 1);\n\t\t\t}\n\t\t\tconst byEndpoint = Array.from(endpointCounts.entries())\n\t\t\t\t.map(([endpoint, count]) => ({ endpoint, count }))\n\t\t\t\t.sort((a, b) => b.count - a.count)\n\t\t\t\t.slice(0, 20);\n\n\t\t\treturn { ...auditStats, byEndpoint };\n\t\t}),\n\n\t\tservers: implement(McpsContract.servers).handler(async () => {\n\t\t\treturn { servers };\n\t\t}),\n\n\t\tmodels: implement(McpsContract.models).handler(async () => {\n\t\t\treturn { models };\n\t\t}),\n\n\t\ttools: implement(McpsContract.tools).handler(async ({ input }) => {\n\t\t\tconst tools: ToolInfo[] = [];\n\t\t\tlet filteredTools = tools;\n\n\t\t\tif (input.server) {\n\t\t\t\tfilteredTools = filteredTools.filter((t) => t.serverName === input.server);\n\t\t\t}\n\n\t\t\tif (input.filter) {\n\t\t\t\tconst patterns = input.filter.split(',').map((p) => p.trim());\n\t\t\t\tfilteredTools = filteredTools.filter((t) => patterns.some((pattern) => matchGlob(pattern, t.name)));\n\t\t\t}\n\n\t\t\treturn { tools: filteredTools };\n\t\t}),\n\t});\n}\n"],"names":["implement","McpsContract","findMcpServerDef","matchGlob","pattern","text","regexPattern","replace","RegExp","test","getServerTypes","map","def","type","name","description","dynamicEndpoint","getEndpoints","mcpEndpoints","chatEndpoints","emptyStats","totalRequests","totalErrors","avgDurationMs","byServer","byMethod","createMcpsRouter","ctx","config","statsProvider","servers","Object","entries","serverConfig","disabled","models","model","adapter","baseUrl","contextWindow","maxInputTokens","maxOutputTokens","router","overview","handler","version","serverTypes","endpoints","stats","input","byEndpoint","auditStats","getStats","events","queryEvents","limit","endpointCounts","Map","event","endpoint","path","set","get","Array","from","count","sort","a","b","slice","tools","filteredTools","server","filter","t","serverName","patterns","split","p","trim","some"],"mappings":"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"}
@@ -13,6 +13,9 @@ export const HeaderNames = {
13
13
  MCP_URL: 'X-MCP-URL',
14
14
  MCP_TYPE: 'X-MCP-TYPE',
15
15
  MCP_COMMAND: 'X-MCP-COMMAND',
16
+ FEISHU_APP_ID: 'X-FEISHU-APP-ID',
17
+ FEISHU_APP_SECRET: 'X-FEISHU-APP-SECRET',
18
+ FEISHU_DOMAIN: 'X-FEISHU-DOMAIN',
16
19
  // Tool filtering headers
17
20
  MCP_READONLY: 'X-MCP-Readonly',
18
21
  MCP_INCLUDE: 'X-MCP-Include',
@@ -44,6 +47,13 @@ export const PrometheusConfigSchema = BaseServerConfigSchema.extend({
44
47
  type: z.literal('prometheus'),
45
48
  url: z.string().optional().describe('Prometheus server URL')
46
49
  });
50
+ // Feishu/Lark config
51
+ export const FeishuConfigSchema = BaseServerConfigSchema.extend({
52
+ type: z.literal('feishu'),
53
+ appId: z.string().optional().describe('Feishu App ID'),
54
+ appSecret: z.string().optional().describe('Feishu App Secret'),
55
+ domain: z.string().optional().describe('feishu (China) or lark (International)')
56
+ });
47
57
  // Relay config for proxying to other MCP servers
48
58
  export const RelayConfigSchema = BaseServerConfigSchema.extend({
49
59
  type: z.literal('relay'),
@@ -55,13 +65,23 @@ export const RelayConfigSchema = BaseServerConfigSchema.extend({
55
65
  command: z.string().optional().describe('Command to run (stdio transport)'),
56
66
  args: z.array(z.string()).optional().describe('Command arguments')
57
67
  });
58
- // Union of all server configs
59
- export const ServerConfigSchema = z.discriminatedUnion('type', [
68
+ // Known server config schemas
69
+ const KnownServerConfigSchema = z.discriminatedUnion('type', [
60
70
  TencentClsConfigSchema,
61
71
  SqlConfigSchema,
62
72
  PrometheusConfigSchema,
73
+ FeishuConfigSchema,
63
74
  RelayConfigSchema
64
75
  ]);
76
+ // Catch-all for custom/extension server types (e.g. platform-admin, fusionops-admin)
77
+ const GenericServerConfigSchema = BaseServerConfigSchema.extend({
78
+ type: z.string()
79
+ }).passthrough();
80
+ // Union of known types with generic fallback for extensibility
81
+ export const ServerConfigSchema = z.union([
82
+ KnownServerConfigSchema,
83
+ GenericServerConfigSchema
84
+ ]);
65
85
  /**
66
86
  * Resolve config from headers - merge headers into config properties
67
87
  * @deprecated Use McpServerDef.resolveConfig instead. This function is kept for backward compatibility.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/schema.ts"],"sourcesContent":["import { z } from 'zod';\n\n// Header name constants for config parsing\nexport const HeaderNames = {\n\tCLS_SECRET_ID: 'X-CLS-SECRET-ID',\n\tCLS_SECRET_KEY: 'X-CLS-SECRET-KEY',\n\tCLS_REGION: 'X-CLS-REGION',\n\tCLS_ENDPOINT: 'X-CLS-ENDPOINT',\n\tDB_URL: 'X-DB-URL',\n\tDB_READ_URL: 'X-DB-READ-URL',\n\tDB_WRITE_URL: 'X-DB-WRITE-URL',\n\tSERVICE_URL: 'X-SERVICE-URL',\n\tTOKEN: 'X-TOKEN',\n\tMCP_URL: 'X-MCP-URL',\n\tMCP_TYPE: 'X-MCP-TYPE',\n\tMCP_COMMAND: 'X-MCP-COMMAND',\n\t// Tool filtering headers\n\tMCP_READONLY: 'X-MCP-Readonly',\n\tMCP_INCLUDE: 'X-MCP-Include',\n\tMCP_EXCLUDE: 'X-MCP-Exclude',\n} as const;\n\n// Base server config with common fields\nexport const BaseServerConfigSchema = z.object({\n\tdisabled: z.boolean().optional(),\n\t// Headers can be used as alternative to direct config properties\n\theaders: z.record(z.string(), z.string()).optional(),\n});\n\n// Tencent CLS config - supports both direct config and headers\nexport const TencentClsConfigSchema = BaseServerConfigSchema.extend({\n\ttype: z.literal('tencent-cls'),\n\tclientId: z.string().optional().describe('Tencent Cloud Secret ID'),\n\tclientSecret: z.string().optional().describe('Tencent Cloud Secret Key'),\n\tregion: z.string().optional().describe('CLS region'),\n\tendpoint: z.string().optional().describe('CLS endpoint'),\n});\nexport type TencentClsConfig = z.infer<typeof TencentClsConfigSchema>;\n\n// SQL config with read/write separation\nexport const SqlConfigSchema = BaseServerConfigSchema.extend({\n\ttype: z.literal('sql'),\n\tdbUrl: z.string().optional().describe('Database URL (for both read and write)'),\n\tdbReadUrl: z.string().optional().describe('Database URL for read operations'),\n\tdbWriteUrl: z.string().optional().describe('Database URL for write operations'),\n});\nexport type SqlConfig = z.infer<typeof SqlConfigSchema>;\n\n// Prometheus config\nexport const PrometheusConfigSchema = BaseServerConfigSchema.extend({\n\ttype: z.literal('prometheus'),\n\turl: z.string().optional().describe('Prometheus server URL'),\n});\nexport type PrometheusConfig = z.infer<typeof PrometheusConfigSchema>;\n\n// Relay config for proxying to other MCP servers\nexport const RelayConfigSchema = BaseServerConfigSchema.extend({\n\ttype: z.literal('relay'),\n\turl: z.string().optional().describe('Target MCP server URL'),\n\ttransport: z.enum(['http', 'sse']).optional().describe('MCP transport type'),\n\tcommand: z.string().optional().describe('Command to run (stdio transport)'),\n\targs: z.array(z.string()).optional().describe('Command arguments'),\n});\nexport type RelayConfig = z.infer<typeof RelayConfigSchema>;\n\n// Union of all server configs\nexport const ServerConfigSchema = z.discriminatedUnion('type', [\n\tTencentClsConfigSchema,\n\tSqlConfigSchema,\n\tPrometheusConfigSchema,\n\tRelayConfigSchema,\n]);\nexport type ServerConfig = z.infer<typeof ServerConfigSchema>;\n\n/**\n * Resolve config from headers - merge headers into config properties\n * @deprecated Use McpServerDef.resolveConfig instead. This function is kept for backward compatibility.\n */\nexport function resolveServerConfig<T extends ServerConfig>(config: T): T {\n\t// This function is now a pass-through - actual resolution is done in McpServerDef.resolveConfig\n\t// Keeping it for backward compatibility with any external code that might use it\n\treturn config;\n}\n\n// ============================================================================\n// Chat/LLM Gateway Configuration\n// ============================================================================\n\n/**\n * Adapter types for protocol conversion\n */\nexport const AdapterType = z.enum(['openai', 'anthropic', 'gemini']);\nexport type AdapterType = z.infer<typeof AdapterType>;\n\n/**\n * Adapter endpoint configuration for chat models\n */\nexport const AdapterEndpointConfigSchema = z.object({\n\tbaseUrl: z.string().optional(),\n\theaders: z.record(z.string(), z.string()).optional(),\n\tprocessors: z.array(z.string()).optional(),\n});\nexport type AdapterEndpointConfig = z.infer<typeof AdapterEndpointConfigSchema>;\n\n/**\n * Model configuration for chat gateway\n */\nexport const ModelConfigSchema = z.object({\n\t/** Model name or pattern (supports wildcards like \"gpt-*\") */\n\tname: z.string(),\n\t/** Base URL for the API */\n\tbaseUrl: z.string().optional(),\n\t/** API key (uses Authorization: Bearer header) */\n\tapiKey: z.string().optional(),\n\t/** Additional headers */\n\theaders: z.record(z.string(), z.string()).optional(),\n\t/** Default adapter to use for protocol conversion */\n\tadapter: AdapterType.optional(),\n\t/** Adapter-specific endpoint configurations */\n\tadapters: z\n\t\t.object({\n\t\t\topenai: AdapterEndpointConfigSchema.optional(),\n\t\t\tanthropic: AdapterEndpointConfigSchema.optional(),\n\t\t\tgemini: AdapterEndpointConfigSchema.optional(),\n\t\t})\n\t\t.optional(),\n\t/** Processor chain */\n\tprocessors: z.array(z.string()).optional(),\n\t/** Context window size (max total tokens) */\n\tcontextWindow: z.number().optional(),\n\t/** Max input tokens */\n\tmaxInputTokens: z.number().optional(),\n\t/** Max output tokens */\n\tmaxOutputTokens: z.number().optional(),\n\t/** Whether to fetch models from upstream on /v1/models */\n\tfetchUpstreamModels: z.boolean().optional(),\n});\nexport type ModelConfig = z.infer<typeof ModelConfigSchema>;\n\n/**\n * Database configuration for audit storage\n */\nexport const DbConfigSchema = z.object({\n\t/** Path to SQLite database file (default: .mcps.db) */\n\tpath: z.string().optional(),\n});\nexport type DbConfig = z.infer<typeof DbConfigSchema>;\n\n/**\n * Audit configuration\n */\nexport const AuditConfigSchema = z.object({\n\t/** Enable audit logging (default: true) */\n\tenabled: z.boolean().optional(),\n\t/** Database configuration for audit storage (overrides root db config) */\n\tdb: DbConfigSchema.optional(),\n});\nexport type AuditConfig = z.infer<typeof AuditConfigSchema>;\n\n// Main config file schema\nexport const McpsConfigSchema = z.object({\n\tservers: z.record(z.string(), ServerConfigSchema).default({}),\n\t/** Model configurations for chat gateway (array format) */\n\tmodels: z.array(ModelConfigSchema).optional(),\n\t/** Whether to expose server config discovery endpoints (default: false) */\n\tdiscoveryConfig: z.boolean().optional(),\n\t/** Database configuration (shared, used as fallback for audit.db) */\n\tdb: DbConfigSchema.optional(),\n\t/** Audit configuration */\n\taudit: AuditConfigSchema.optional(),\n});\nexport type McpsConfig = z.infer<typeof McpsConfigSchema>;\n\n// Legacy ChatConfig type alias for backwards compatibility\nexport type ChatConfig = { models?: ModelConfig[] };\n"],"names":["z","HeaderNames","CLS_SECRET_ID","CLS_SECRET_KEY","CLS_REGION","CLS_ENDPOINT","DB_URL","DB_READ_URL","DB_WRITE_URL","SERVICE_URL","TOKEN","MCP_URL","MCP_TYPE","MCP_COMMAND","MCP_READONLY","MCP_INCLUDE","MCP_EXCLUDE","BaseServerConfigSchema","object","disabled","boolean","optional","headers","record","string","TencentClsConfigSchema","extend","type","literal","clientId","describe","clientSecret","region","endpoint","SqlConfigSchema","dbUrl","dbReadUrl","dbWriteUrl","PrometheusConfigSchema","url","RelayConfigSchema","transport","enum","command","args","array","ServerConfigSchema","discriminatedUnion","resolveServerConfig","config","AdapterType","AdapterEndpointConfigSchema","baseUrl","processors","ModelConfigSchema","name","apiKey","adapter","adapters","openai","anthropic","gemini","contextWindow","number","maxInputTokens","maxOutputTokens","fetchUpstreamModels","DbConfigSchema","path","AuditConfigSchema","enabled","db","McpsConfigSchema","servers","default","models","discoveryConfig","audit"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/server/schema.ts"],"sourcesContent":["import { z } from 'zod';\n\n// Header name constants for config parsing\nexport const HeaderNames = {\n\tCLS_SECRET_ID: 'X-CLS-SECRET-ID',\n\tCLS_SECRET_KEY: 'X-CLS-SECRET-KEY',\n\tCLS_REGION: 'X-CLS-REGION',\n\tCLS_ENDPOINT: 'X-CLS-ENDPOINT',\n\tDB_URL: 'X-DB-URL',\n\tDB_READ_URL: 'X-DB-READ-URL',\n\tDB_WRITE_URL: 'X-DB-WRITE-URL',\n\tSERVICE_URL: 'X-SERVICE-URL',\n\tTOKEN: 'X-TOKEN',\n\tMCP_URL: 'X-MCP-URL',\n\tMCP_TYPE: 'X-MCP-TYPE',\n\tMCP_COMMAND: 'X-MCP-COMMAND',\n\tFEISHU_APP_ID: 'X-FEISHU-APP-ID',\n\tFEISHU_APP_SECRET: 'X-FEISHU-APP-SECRET',\n\tFEISHU_DOMAIN: 'X-FEISHU-DOMAIN',\n\t// Tool filtering headers\n\tMCP_READONLY: 'X-MCP-Readonly',\n\tMCP_INCLUDE: 'X-MCP-Include',\n\tMCP_EXCLUDE: 'X-MCP-Exclude',\n} as const;\n\n// Base server config with common fields\nexport const BaseServerConfigSchema = z.object({\n\tdisabled: z.boolean().optional(),\n\t// Headers can be used as alternative to direct config properties\n\theaders: z.record(z.string(), z.string()).optional(),\n});\n\n// Tencent CLS config - supports both direct config and headers\nexport const TencentClsConfigSchema = BaseServerConfigSchema.extend({\n\ttype: z.literal('tencent-cls'),\n\tclientId: z.string().optional().describe('Tencent Cloud Secret ID'),\n\tclientSecret: z.string().optional().describe('Tencent Cloud Secret Key'),\n\tregion: z.string().optional().describe('CLS region'),\n\tendpoint: z.string().optional().describe('CLS endpoint'),\n});\nexport type TencentClsConfig = z.infer<typeof TencentClsConfigSchema>;\n\n// SQL config with read/write separation\nexport const SqlConfigSchema = BaseServerConfigSchema.extend({\n\ttype: z.literal('sql'),\n\tdbUrl: z.string().optional().describe('Database URL (for both read and write)'),\n\tdbReadUrl: z.string().optional().describe('Database URL for read operations'),\n\tdbWriteUrl: z.string().optional().describe('Database URL for write operations'),\n});\nexport type SqlConfig = z.infer<typeof SqlConfigSchema>;\n\n// Prometheus config\nexport const PrometheusConfigSchema = BaseServerConfigSchema.extend({\n\ttype: z.literal('prometheus'),\n\turl: z.string().optional().describe('Prometheus server URL'),\n});\nexport type PrometheusConfig = z.infer<typeof PrometheusConfigSchema>;\n\n// Feishu/Lark config\nexport const FeishuConfigSchema = BaseServerConfigSchema.extend({\n\ttype: z.literal('feishu'),\n\tappId: z.string().optional().describe('Feishu App ID'),\n\tappSecret: z.string().optional().describe('Feishu App Secret'),\n\tdomain: z.string().optional().describe('feishu (China) or lark (International)'),\n});\nexport type FeishuConfig = z.infer<typeof FeishuConfigSchema>;\n\n// Relay config for proxying to other MCP servers\nexport const RelayConfigSchema = BaseServerConfigSchema.extend({\n\ttype: z.literal('relay'),\n\turl: z.string().optional().describe('Target MCP server URL'),\n\ttransport: z.enum(['http', 'sse']).optional().describe('MCP transport type'),\n\tcommand: z.string().optional().describe('Command to run (stdio transport)'),\n\targs: z.array(z.string()).optional().describe('Command arguments'),\n});\nexport type RelayConfig = z.infer<typeof RelayConfigSchema>;\n\n// Known server config schemas\nconst KnownServerConfigSchema = z.discriminatedUnion('type', [\n\tTencentClsConfigSchema,\n\tSqlConfigSchema,\n\tPrometheusConfigSchema,\n\tFeishuConfigSchema,\n\tRelayConfigSchema,\n]);\n\n// Catch-all for custom/extension server types (e.g. platform-admin, fusionops-admin)\nconst GenericServerConfigSchema = BaseServerConfigSchema.extend({\n\ttype: z.string(),\n}).passthrough();\n\n// Union of known types with generic fallback for extensibility\nexport const ServerConfigSchema = z.union([KnownServerConfigSchema, GenericServerConfigSchema]);\nexport type ServerConfig = z.infer<typeof ServerConfigSchema>;\n\n/**\n * Resolve config from headers - merge headers into config properties\n * @deprecated Use McpServerDef.resolveConfig instead. This function is kept for backward compatibility.\n */\nexport function resolveServerConfig<T extends ServerConfig>(config: T): T {\n\t// This function is now a pass-through - actual resolution is done in McpServerDef.resolveConfig\n\t// Keeping it for backward compatibility with any external code that might use it\n\treturn config;\n}\n\n// ============================================================================\n// Chat/LLM Gateway Configuration\n// ============================================================================\n\n/**\n * Adapter types for protocol conversion\n */\nexport const AdapterType = z.enum(['openai', 'anthropic', 'gemini']);\nexport type AdapterType = z.infer<typeof AdapterType>;\n\n/**\n * Adapter endpoint configuration for chat models\n */\nexport const AdapterEndpointConfigSchema = z.object({\n\tbaseUrl: z.string().optional(),\n\theaders: z.record(z.string(), z.string()).optional(),\n\tprocessors: z.array(z.string()).optional(),\n});\nexport type AdapterEndpointConfig = z.infer<typeof AdapterEndpointConfigSchema>;\n\n/**\n * Model configuration for chat gateway\n */\nexport const ModelConfigSchema = z.object({\n\t/** Model name or pattern (supports wildcards like \"gpt-*\") */\n\tname: z.string(),\n\t/** Base URL for the API */\n\tbaseUrl: z.string().optional(),\n\t/** API key (uses Authorization: Bearer header) */\n\tapiKey: z.string().optional(),\n\t/** Additional headers */\n\theaders: z.record(z.string(), z.string()).optional(),\n\t/** Default adapter to use for protocol conversion */\n\tadapter: AdapterType.optional(),\n\t/** Adapter-specific endpoint configurations */\n\tadapters: z\n\t\t.object({\n\t\t\topenai: AdapterEndpointConfigSchema.optional(),\n\t\t\tanthropic: AdapterEndpointConfigSchema.optional(),\n\t\t\tgemini: AdapterEndpointConfigSchema.optional(),\n\t\t})\n\t\t.optional(),\n\t/** Processor chain */\n\tprocessors: z.array(z.string()).optional(),\n\t/** Context window size (max total tokens) */\n\tcontextWindow: z.number().optional(),\n\t/** Max input tokens */\n\tmaxInputTokens: z.number().optional(),\n\t/** Max output tokens */\n\tmaxOutputTokens: z.number().optional(),\n\t/** Whether to fetch models from upstream on /v1/models */\n\tfetchUpstreamModels: z.boolean().optional(),\n});\nexport type ModelConfig = z.infer<typeof ModelConfigSchema>;\n\n/**\n * Database configuration for audit storage\n */\nexport const DbConfigSchema = z.object({\n\t/** Path to SQLite database file (default: .mcps.db) */\n\tpath: z.string().optional(),\n});\nexport type DbConfig = z.infer<typeof DbConfigSchema>;\n\n/**\n * Audit configuration\n */\nexport const AuditConfigSchema = z.object({\n\t/** Enable audit logging (default: true) */\n\tenabled: z.boolean().optional(),\n\t/** Database configuration for audit storage (overrides root db config) */\n\tdb: DbConfigSchema.optional(),\n});\nexport type AuditConfig = z.infer<typeof AuditConfigSchema>;\n\n// Main config file schema\nexport const McpsConfigSchema = z.object({\n\tservers: z.record(z.string(), ServerConfigSchema).default({}),\n\t/** Model configurations for chat gateway (array format) */\n\tmodels: z.array(ModelConfigSchema).optional(),\n\t/** Whether to expose server config discovery endpoints (default: false) */\n\tdiscoveryConfig: z.boolean().optional(),\n\t/** Database configuration (shared, used as fallback for audit.db) */\n\tdb: DbConfigSchema.optional(),\n\t/** Audit configuration */\n\taudit: AuditConfigSchema.optional(),\n});\nexport type McpsConfig = z.infer<typeof McpsConfigSchema>;\n\n// Legacy ChatConfig type alias for backwards compatibility\nexport type ChatConfig = { models?: ModelConfig[] };\n"],"names":["z","HeaderNames","CLS_SECRET_ID","CLS_SECRET_KEY","CLS_REGION","CLS_ENDPOINT","DB_URL","DB_READ_URL","DB_WRITE_URL","SERVICE_URL","TOKEN","MCP_URL","MCP_TYPE","MCP_COMMAND","FEISHU_APP_ID","FEISHU_APP_SECRET","FEISHU_DOMAIN","MCP_READONLY","MCP_INCLUDE","MCP_EXCLUDE","BaseServerConfigSchema","object","disabled","boolean","optional","headers","record","string","TencentClsConfigSchema","extend","type","literal","clientId","describe","clientSecret","region","endpoint","SqlConfigSchema","dbUrl","dbReadUrl","dbWriteUrl","PrometheusConfigSchema","url","FeishuConfigSchema","appId","appSecret","domain","RelayConfigSchema","transport","enum","command","args","array","KnownServerConfigSchema","discriminatedUnion","GenericServerConfigSchema","passthrough","ServerConfigSchema","union","resolveServerConfig","config","AdapterType","AdapterEndpointConfigSchema","baseUrl","processors","ModelConfigSchema","name","apiKey","adapter","adapters","openai","anthropic","gemini","contextWindow","number","maxInputTokens","maxOutputTokens","fetchUpstreamModels","DbConfigSchema","path","AuditConfigSchema","enabled","db","McpsConfigSchema","servers","default","models","discoveryConfig","audit"],"mappings":"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"}