@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.
- package/README.md +144 -0
- package/dist/index.mjs +213076 -1
- package/dist/mcps-cli.mjs +102547 -59344
- package/lib/chat/handler.js +2 -2
- package/lib/chat/handler.js.map +1 -1
- package/lib/cli-start.js +36 -0
- package/lib/cli-start.js.map +1 -0
- package/lib/cli.js +19 -0
- package/lib/cli.js.map +1 -0
- package/lib/dev.server.js +7 -1
- package/lib/dev.server.js.map +1 -1
- package/lib/index.js +21 -3
- package/lib/index.js.map +1 -1
- package/lib/mcps-cli.js +6 -35
- package/lib/mcps-cli.js.map +1 -1
- package/lib/providers/feishu/def.js +35 -0
- package/lib/providers/feishu/def.js.map +1 -0
- package/lib/providers/findMcpServerDef.js +1 -0
- package/lib/providers/findMcpServerDef.js.map +1 -1
- package/lib/scripts/bundle.js +7 -1
- package/lib/scripts/bundle.js.map +1 -1
- package/lib/server/api-routes.js +7 -8
- package/lib/server/api-routes.js.map +1 -1
- package/lib/server/audit-db.js +64 -0
- package/lib/server/audit-db.js.map +1 -0
- package/lib/server/{audit.js → audit-plugin.js} +72 -126
- package/lib/server/audit-plugin.js.map +1 -0
- package/lib/server/events.js +13 -0
- package/lib/server/events.js.map +1 -0
- package/lib/server/mcp-routes.js +31 -60
- package/lib/server/mcp-routes.js.map +1 -1
- package/lib/server/mcps-router.js +19 -24
- package/lib/server/mcps-router.js.map +1 -1
- package/lib/server/schema.js +22 -2
- package/lib/server/schema.js.map +1 -1
- package/lib/server/server.js +142 -87
- package/lib/server/server.js.map +1 -1
- package/package.json +33 -6
- package/src/chat/handler.ts +2 -2
- package/src/cli-start.ts +43 -0
- package/src/cli.ts +45 -0
- package/src/dev.server.ts +8 -1
- package/src/index.ts +47 -1
- package/src/mcps-cli.ts +6 -48
- package/src/providers/feishu/def.ts +37 -0
- package/src/providers/findMcpServerDef.ts +1 -0
- package/src/scripts/bundle.ts +12 -1
- package/src/server/api-routes.ts +11 -8
- package/src/server/audit-db.ts +65 -0
- package/src/server/{audit.ts → audit-plugin.ts} +69 -142
- package/src/server/events.ts +29 -0
- package/src/server/mcp-routes.ts +30 -58
- package/src/server/mcps-router.ts +21 -29
- package/src/server/schema.ts +23 -2
- package/src/server/server.ts +149 -81
- package/lib/server/audit.js.map +0 -1
- package/lib/server/db.js +0 -97
- package/lib/server/db.js.map +0 -1
- package/src/server/db.ts +0 -115
package/lib/server/mcp-routes.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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\
|
|
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, "\\$&")
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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);
|
|
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 {
|
|
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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"}
|
package/lib/server/schema.js
CHANGED
|
@@ -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
|
-
//
|
|
59
|
-
|
|
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.
|
package/lib/server/schema.js.map
CHANGED
|
@@ -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":"AAAA,SAASA,CAAC,QAAQ,MAAM;AAExB,2CAA2C;AAC3C,OAAO,MAAMC,cAAc;IAC1BC,eAAe;IACfC,gBAAgB;IAChBC,YAAY;IACZC,cAAc;IACdC,QAAQ;IACRC,aAAa;IACbC,cAAc;IACdC,aAAa;IACbC,OAAO;IACPC,SAAS;IACTC,UAAU;IACVC,aAAa;IACb,yBAAyB;IACzBC,cAAc;IACdC,aAAa;IACbC,aAAa;AACd,EAAW;AAEX,wCAAwC;AACxC,OAAO,MAAMC,yBAAyBjB,EAAEkB,MAAM,CAAC;IAC9CC,UAAUnB,EAAEoB,OAAO,GAAGC,QAAQ;IAC9B,iEAAiE;IACjEC,SAAStB,EAAEuB,MAAM,CAACvB,EAAEwB,MAAM,IAAIxB,EAAEwB,MAAM,IAAIH,QAAQ;AACnD,GAAG;AAEH,+DAA+D;AAC/D,OAAO,MAAMI,yBAAyBR,uBAAuBS,MAAM,CAAC;IACnEC,MAAM3B,EAAE4B,OAAO,CAAC;IAChBC,UAAU7B,EAAEwB,MAAM,GAAGH,QAAQ,GAAGS,QAAQ,CAAC;IACzCC,cAAc/B,EAAEwB,MAAM,GAAGH,QAAQ,GAAGS,QAAQ,CAAC;IAC7CE,QAAQhC,EAAEwB,MAAM,GAAGH,QAAQ,GAAGS,QAAQ,CAAC;IACvCG,UAAUjC,EAAEwB,MAAM,GAAGH,QAAQ,GAAGS,QAAQ,CAAC;AAC1C,GAAG;AAGH,wCAAwC;AACxC,OAAO,MAAMI,kBAAkBjB,uBAAuBS,MAAM,CAAC;IAC5DC,MAAM3B,EAAE4B,OAAO,CAAC;IAChBO,OAAOnC,EAAEwB,MAAM,GAAGH,QAAQ,GAAGS,QAAQ,CAAC;IACtCM,WAAWpC,EAAEwB,MAAM,GAAGH,QAAQ,GAAGS,QAAQ,CAAC;IAC1CO,YAAYrC,EAAEwB,MAAM,GAAGH,QAAQ,GAAGS,QAAQ,CAAC;AAC5C,GAAG;AAGH,oBAAoB;AACpB,OAAO,MAAMQ,yBAAyBrB,uBAAuBS,MAAM,CAAC;IACnEC,MAAM3B,EAAE4B,OAAO,CAAC;IAChBW,KAAKvC,EAAEwB,MAAM,GAAGH,QAAQ,GAAGS,QAAQ,CAAC;AACrC,GAAG;AAGH,iDAAiD;AACjD,OAAO,MAAMU,oBAAoBvB,uBAAuBS,MAAM,CAAC;IAC9DC,MAAM3B,EAAE4B,OAAO,CAAC;IAChBW,KAAKvC,EAAEwB,MAAM,GAAGH,QAAQ,GAAGS,QAAQ,CAAC;IACpCW,WAAWzC,EAAE0C,IAAI,CAAC;QAAC;QAAQ;KAAM,EAAErB,QAAQ,GAAGS,QAAQ,CAAC;IACvDa,SAAS3C,EAAEwB,MAAM,GAAGH,QAAQ,GAAGS,QAAQ,CAAC;IACxCc,MAAM5C,EAAE6C,KAAK,CAAC7C,EAAEwB,MAAM,IAAIH,QAAQ,GAAGS,QAAQ,CAAC;AAC/C,GAAG;AAGH,8BAA8B;AAC9B,OAAO,MAAMgB,qBAAqB9C,EAAE+C,kBAAkB,CAAC,QAAQ;IAC9DtB;IACAS;IACAI;IACAE;CACA,EAAE;AAGH;;;CAGC,GACD,OAAO,SAASQ,oBAA4CC,MAAS;IACpE,gGAAgG;IAChG,iFAAiF;IACjF,OAAOA;AACR;AAEA,+EAA+E;AAC/E,iCAAiC;AACjC,+EAA+E;AAE/E;;CAEC,GACD,OAAO,MAAMC,cAAclD,EAAE0C,IAAI,CAAC;IAAC;IAAU;IAAa;CAAS,EAAE;AAGrE;;CAEC,GACD,OAAO,MAAMS,8BAA8BnD,EAAEkB,MAAM,CAAC;IACnDkC,SAASpD,EAAEwB,MAAM,GAAGH,QAAQ;IAC5BC,SAAStB,EAAEuB,MAAM,CAACvB,EAAEwB,MAAM,IAAIxB,EAAEwB,MAAM,IAAIH,QAAQ;IAClDgC,YAAYrD,EAAE6C,KAAK,CAAC7C,EAAEwB,MAAM,IAAIH,QAAQ;AACzC,GAAG;AAGH;;CAEC,GACD,OAAO,MAAMiC,oBAAoBtD,EAAEkB,MAAM,CAAC;IACzC,4DAA4D,GAC5DqC,MAAMvD,EAAEwB,MAAM;IACd,yBAAyB,GACzB4B,SAASpD,EAAEwB,MAAM,GAAGH,QAAQ;IAC5B,gDAAgD,GAChDmC,QAAQxD,EAAEwB,MAAM,GAAGH,QAAQ;IAC3B,uBAAuB,GACvBC,SAAStB,EAAEuB,MAAM,CAACvB,EAAEwB,MAAM,IAAIxB,EAAEwB,MAAM,IAAIH,QAAQ;IAClD,mDAAmD,GACnDoC,SAASP,YAAY7B,QAAQ;IAC7B,6CAA6C,GAC7CqC,UAAU1D,EACRkB,MAAM,CAAC;QACPyC,QAAQR,4BAA4B9B,QAAQ;QAC5CuC,WAAWT,4BAA4B9B,QAAQ;QAC/CwC,QAAQV,4BAA4B9B,QAAQ;IAC7C,GACCA,QAAQ;IACV,oBAAoB,GACpBgC,YAAYrD,EAAE6C,KAAK,CAAC7C,EAAEwB,MAAM,IAAIH,QAAQ;IACxC,2CAA2C,GAC3CyC,eAAe9D,EAAE+D,MAAM,GAAG1C,QAAQ;IAClC,qBAAqB,GACrB2C,gBAAgBhE,EAAE+D,MAAM,GAAG1C,QAAQ;IACnC,sBAAsB,GACtB4C,iBAAiBjE,EAAE+D,MAAM,GAAG1C,QAAQ;IACpC,wDAAwD,GACxD6C,qBAAqBlE,EAAEoB,OAAO,GAAGC,QAAQ;AAC1C,GAAG;AAGH;;CAEC,GACD,OAAO,MAAM8C,iBAAiBnE,EAAEkB,MAAM,CAAC;IACtC,qDAAqD,GACrDkD,MAAMpE,EAAEwB,MAAM,GAAGH,QAAQ;AAC1B,GAAG;AAGH;;CAEC,GACD,OAAO,MAAMgD,oBAAoBrE,EAAEkB,MAAM,CAAC;IACzC,yCAAyC,GACzCoD,SAAStE,EAAEoB,OAAO,GAAGC,QAAQ;IAC7B,wEAAwE,GACxEkD,IAAIJ,eAAe9C,QAAQ;AAC5B,GAAG;AAGH,0BAA0B;AAC1B,OAAO,MAAMmD,mBAAmBxE,EAAEkB,MAAM,CAAC;IACxCuD,SAASzE,EAAEuB,MAAM,CAACvB,EAAEwB,MAAM,IAAIsB,oBAAoB4B,OAAO,CAAC,CAAC;IAC3D,yDAAyD,GACzDC,QAAQ3E,EAAE6C,KAAK,CAACS,mBAAmBjC,QAAQ;IAC3C,yEAAyE,GACzEuD,iBAAiB5E,EAAEoB,OAAO,GAAGC,QAAQ;IACrC,mEAAmE,GACnEkD,IAAIJ,eAAe9C,QAAQ;IAC3B,wBAAwB,GACxBwD,OAAOR,kBAAkBhD,QAAQ;AAClC,GAAG"}
|
|
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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"}
|