@wener/mcps 1.0.2 → 1.0.5
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 +102632 -59429
- package/lib/audit/AuditContract.js.map +1 -0
- package/lib/{chat/audit.js → audit/chat.js} +1 -1
- package/lib/audit/chat.js.map +1 -0
- package/lib/audit/entities/ChatRequestEntity.js.map +1 -0
- package/lib/audit/entities/McpRequestEntity.js.map +1 -0
- package/lib/audit/entities/RequestLogEntity.js.map +1 -0
- package/lib/audit/entities/ResponseEntity.js.map +1 -0
- package/lib/audit/entities/index.js +6 -0
- package/lib/audit/entities/index.js.map +1 -0
- package/lib/audit/server/db.js +64 -0
- package/lib/audit/server/db.js.map +1 -0
- package/lib/audit/server/index.js +2 -0
- package/lib/audit/server/index.js.map +1 -0
- package/lib/{server/audit.js → audit/server/plugin.js} +73 -127
- package/lib/audit/server/plugin.js.map +1 -0
- package/lib/audit/types.js.map +1 -0
- package/lib/chat/handler.js +5 -5
- package/lib/chat/handler.js.map +1 -1
- package/lib/chat/index.js +1 -1
- package/lib/chat/index.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/contracts/index.js +1 -1
- package/lib/contracts/index.js.map +1 -1
- package/lib/dev.server.js +7 -1
- package/lib/dev.server.js.map +1 -1
- package/lib/entities/index.js +2 -10
- package/lib/entities/index.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/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 +145 -85
- package/src/{chat/audit.ts → audit/chat.ts} +3 -3
- package/src/audit/entities/index.ts +6 -0
- package/src/audit/server/db.ts +65 -0
- package/src/audit/server/index.ts +8 -0
- package/src/{server/audit.ts → audit/server/plugin.ts} +71 -144
- package/src/chat/handler.ts +5 -5
- package/src/chat/index.ts +1 -1
- package/src/cli-start.ts +43 -0
- package/src/cli.ts +45 -0
- package/src/contracts/index.ts +1 -1
- package/src/dev.server.ts +8 -1
- package/src/entities/index.ts +2 -12
- 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/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/LICENSE +0 -21
- package/lib/chat/audit.js.map +0 -1
- package/lib/contracts/AuditContract.js.map +0 -1
- package/lib/entities/ChatRequestEntity.js.map +0 -1
- package/lib/entities/McpRequestEntity.js.map +0 -1
- package/lib/entities/RequestLogEntity.js.map +0 -1
- package/lib/entities/ResponseEntity.js.map +0 -1
- package/lib/entities/types.js.map +0 -1
- 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/{contracts → audit}/AuditContract.js +0 -0
- /package/lib/{entities → audit/entities}/ChatRequestEntity.js +0 -0
- /package/lib/{entities → audit/entities}/McpRequestEntity.js +0 -0
- /package/lib/{entities → audit/entities}/RequestLogEntity.js +0 -0
- /package/lib/{entities → audit/entities}/ResponseEntity.js +0 -0
- /package/lib/{entities → audit}/types.js +0 -0
- /package/src/{contracts → audit}/AuditContract.ts +0 -0
- /package/src/{entities → audit/entities}/ChatRequestEntity.ts +0 -0
- /package/src/{entities → audit/entities}/McpRequestEntity.ts +0 -0
- /package/src/{entities → audit/entities}/RequestLogEntity.ts +0 -0
- /package/src/{entities → audit/entities}/ResponseEntity.ts +0 -0
- /package/src/{entities → audit}/types.ts +0 -0
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":"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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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"}
|
package/lib/server/server.js
CHANGED
|
@@ -5,38 +5,32 @@ import { LRUCache } from "lru-cache";
|
|
|
5
5
|
import { isDevelopment } from "std-env";
|
|
6
6
|
import { findMcpServerDef } from "../providers/findMcpServerDef.js";
|
|
7
7
|
import { registerApiRoutes } from "./api-routes.js";
|
|
8
|
-
import { auditMiddleware, configureAudit } from "./audit.js";
|
|
9
8
|
import { registerChatRoutes } from "./chat-routes.js";
|
|
10
9
|
import { loadConfig, loadEnvFiles, substituteEnvVars } from "./config.js";
|
|
10
|
+
import { createMcpsEmitter, McpsEventType } from "./events.js";
|
|
11
11
|
import { registerMcpRoutes } from "./mcp-routes.js";
|
|
12
12
|
const log = consola.withTag("mcps");
|
|
13
13
|
export function createServer(options = {}) {
|
|
14
|
-
const { cwd = process.cwd(), discoveryConfig: discoveryConfigOption } = options;
|
|
14
|
+
const { cwd = process.cwd(), discoveryConfig: discoveryConfigOption, setup } = options;
|
|
15
15
|
const app = new Hono();
|
|
16
|
+
const emitter = createMcpsEmitter();
|
|
17
|
+
const apiRouters = {};
|
|
16
18
|
// Request logging
|
|
17
19
|
app.use(logger((v) => {
|
|
18
20
|
log.debug(v);
|
|
19
21
|
}));
|
|
20
|
-
//
|
|
21
|
-
app.use(
|
|
22
|
+
// Request event middleware - emits events for subscribers (audit, monitoring, etc.)
|
|
23
|
+
app.use(requestEventMiddleware(emitter));
|
|
22
24
|
// Load .env files first
|
|
23
25
|
loadEnvFiles(cwd);
|
|
24
26
|
// Load config (with env var substitution)
|
|
25
27
|
const config = substituteEnvVars(loadConfig(cwd));
|
|
26
|
-
// discoveryConfig: CLI option overrides config file, defaults to false
|
|
27
28
|
const discoveryConfig = discoveryConfigOption ?? config.discoveryConfig ?? false;
|
|
28
29
|
// Log available server types from registry
|
|
29
30
|
const serverDefs = findMcpServerDef();
|
|
30
31
|
log.info(`Available server types: ${serverDefs.map((d) => d.name).join(", ")}`);
|
|
31
32
|
log.info(`Loaded ${Object.keys(config.servers).length} servers from config (discoveryConfig: ${discoveryConfig})`);
|
|
32
|
-
//
|
|
33
|
-
// DB will only be initialized when the first audit event needs persistence
|
|
34
|
-
configureAudit(config.audit, config.db);
|
|
35
|
-
const auditEnabled = config.audit?.enabled !== false;
|
|
36
|
-
const auditDbPath = config.audit?.db?.path ?? config.db?.path ?? ".mcps.db";
|
|
37
|
-
log.info(`Audit configured: enabled=${auditEnabled}, db=${auditDbPath} (lazy init)`);
|
|
38
|
-
// Unified cache for all MCP servers (both pre-configured and dynamic)
|
|
39
|
-
// Keyed by cache key from def.getCacheKey() or `config::${name}` for pre-configured
|
|
33
|
+
// Unified cache for all MCP servers
|
|
40
34
|
const serverCache = new LRUCache({
|
|
41
35
|
max: 100,
|
|
42
36
|
dispose: (value, key) => {
|
|
@@ -44,76 +38,81 @@ export function createServer(options = {}) {
|
|
|
44
38
|
value.close?.().catch((e) => log.error("Failed to close server", e));
|
|
45
39
|
}
|
|
46
40
|
});
|
|
47
|
-
|
|
48
|
-
// Register MCP routes (pre-configured and dynamic endpoints)
|
|
49
|
-
// =========================================================================
|
|
50
|
-
registerMcpRoutes({
|
|
41
|
+
const ctx = {
|
|
51
42
|
app,
|
|
52
43
|
config,
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}));
|
|
68
|
-
app.get("/", (c) => {
|
|
69
|
-
return c.json({
|
|
70
|
-
message: "hello"
|
|
44
|
+
emitter,
|
|
45
|
+
serverCache,
|
|
46
|
+
apiRouters
|
|
47
|
+
};
|
|
48
|
+
const finalize = async () => {
|
|
49
|
+
// Allow plugins to set up before routes are registered
|
|
50
|
+
await setup?.(ctx);
|
|
51
|
+
// =========================================================================
|
|
52
|
+
// Register MCP routes (pre-configured and dynamic endpoints)
|
|
53
|
+
// =========================================================================
|
|
54
|
+
registerMcpRoutes({
|
|
55
|
+
app,
|
|
56
|
+
config,
|
|
57
|
+
serverCache
|
|
71
58
|
});
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
59
|
+
// =========================================================================
|
|
60
|
+
// Register Chat/LLM Gateway routes
|
|
61
|
+
// =========================================================================
|
|
62
|
+
registerChatRoutes({
|
|
63
|
+
app,
|
|
64
|
+
config
|
|
65
|
+
});
|
|
66
|
+
// =========================================================================
|
|
67
|
+
// Health and info endpoints
|
|
68
|
+
// =========================================================================
|
|
69
|
+
app.get("/health", (c) => c.json({
|
|
70
|
+
status: "ok"
|
|
71
|
+
}));
|
|
72
|
+
app.get("/", (c) => c.json({
|
|
73
|
+
message: "hello"
|
|
74
|
+
}));
|
|
75
|
+
if (isDevelopment || discoveryConfig) {
|
|
76
|
+
app.get("/info", (c) => {
|
|
77
|
+
const routes = app.routes.map((r) => ({
|
|
78
|
+
method: r.method,
|
|
79
|
+
path: r.path
|
|
80
|
+
})).filter((r) => r.method !== "ALL" || r.path.startsWith("/mcp/")).sort((a, b) => a.path.localeCompare(b.path) || a.method.localeCompare(b.method));
|
|
81
|
+
const mcpRoutes = routes.filter((r) => r.path.startsWith("/mcp/")).map((r) => r.path);
|
|
82
|
+
const apiRoutes = routes.filter((r) => r.path.startsWith("/api/")).map((r) => `${r.method} ${r.path}`);
|
|
83
|
+
const chatRoutes = routes.filter((r) => r.path.startsWith("/v1/")).map((r) => `${r.method} ${r.path}`);
|
|
84
|
+
const uniqueMcpPaths = [
|
|
85
|
+
...new Set(mcpRoutes)
|
|
86
|
+
];
|
|
87
|
+
return c.json({
|
|
88
|
+
name: "@wener/mcps",
|
|
89
|
+
version: "0.1.0",
|
|
90
|
+
servers: Object.keys(config.servers),
|
|
91
|
+
serverTypes: findMcpServerDef().map((d) => d.name),
|
|
92
|
+
models: config.models ? config.models.map((m) => m.name) : [],
|
|
93
|
+
endpoints: {
|
|
94
|
+
mcp: uniqueMcpPaths,
|
|
95
|
+
api: [
|
|
96
|
+
...new Set(apiRoutes)
|
|
97
|
+
],
|
|
98
|
+
chat: [
|
|
99
|
+
...new Set(chatRoutes)
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
});
|
|
104
103
|
});
|
|
104
|
+
}
|
|
105
|
+
// =========================================================================
|
|
106
|
+
// Register oRPC API routes (with any plugin-provided routers)
|
|
107
|
+
// =========================================================================
|
|
108
|
+
registerApiRoutes({
|
|
109
|
+
app,
|
|
110
|
+
config,
|
|
111
|
+
apiRouters,
|
|
112
|
+
statsProvider: ctx.statsProvider
|
|
105
113
|
});
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Register oRPC API routes
|
|
109
|
-
// =========================================================================
|
|
110
|
-
registerApiRoutes({
|
|
111
|
-
app,
|
|
112
|
-
config
|
|
113
|
-
});
|
|
114
|
-
/**
|
|
115
|
-
* Print available endpoints grouped by category
|
|
116
|
-
*/ const printEndpoints = () => {
|
|
114
|
+
};
|
|
115
|
+
const printEndpoints = () => {
|
|
117
116
|
const routes = app.routes;
|
|
118
117
|
const mcpPaths = new Set();
|
|
119
118
|
const apiPaths = new Set();
|
|
@@ -135,32 +134,88 @@ export function createServer(options = {}) {
|
|
|
135
134
|
}
|
|
136
135
|
}
|
|
137
136
|
log.info("Available endpoints:");
|
|
138
|
-
if (mcpPaths.size > 0)
|
|
137
|
+
if (mcpPaths.size > 0)
|
|
139
138
|
log.info(` MCP: ${[
|
|
140
139
|
...mcpPaths
|
|
141
140
|
].sort().join(", ")}`);
|
|
142
|
-
|
|
143
|
-
if (chatPaths.size > 0) {
|
|
141
|
+
if (chatPaths.size > 0)
|
|
144
142
|
log.info(` Chat: ${[
|
|
145
143
|
...chatPaths
|
|
146
144
|
].sort().join(", ")}`);
|
|
147
|
-
|
|
148
|
-
if (apiPaths.size > 0) {
|
|
145
|
+
if (apiPaths.size > 0)
|
|
149
146
|
log.info(` API: ${[
|
|
150
147
|
...apiPaths
|
|
151
148
|
].sort().join(", ")}`);
|
|
152
|
-
|
|
153
|
-
if (otherPaths.size > 0) {
|
|
149
|
+
if (otherPaths.size > 0)
|
|
154
150
|
log.info(` Other: ${[
|
|
155
151
|
...otherPaths
|
|
156
152
|
].sort().join(", ")}`);
|
|
157
|
-
}
|
|
158
153
|
};
|
|
159
154
|
return {
|
|
160
155
|
app,
|
|
161
156
|
config,
|
|
157
|
+
emitter,
|
|
162
158
|
serverCache,
|
|
163
|
-
printEndpoints
|
|
159
|
+
printEndpoints,
|
|
160
|
+
finalize
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function headersToRecord(headers) {
|
|
164
|
+
const record = {};
|
|
165
|
+
headers.forEach((value, key) => {
|
|
166
|
+
record[key] = value;
|
|
167
|
+
});
|
|
168
|
+
return record;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Middleware that emits request events via the emitter.
|
|
172
|
+
* Subscribers (like audit plugin) can listen and handle these events.
|
|
173
|
+
*/ function requestEventMiddleware(emitter) {
|
|
174
|
+
return async (c, next) => {
|
|
175
|
+
const startTime = Date.now();
|
|
176
|
+
const path = c.req.path;
|
|
177
|
+
let serverName;
|
|
178
|
+
let serverType;
|
|
179
|
+
const mcpMatch = path.match(/^\/mcp\/([^/]+)/);
|
|
180
|
+
if (mcpMatch) {
|
|
181
|
+
serverName = mcpMatch[1];
|
|
182
|
+
if ([
|
|
183
|
+
"tencent-cls",
|
|
184
|
+
"sql",
|
|
185
|
+
"prometheus",
|
|
186
|
+
"relay"
|
|
187
|
+
].includes(serverName)) {
|
|
188
|
+
serverType = serverName;
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
serverType = "custom";
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (path.startsWith("/v1/")) {
|
|
195
|
+
serverType = "chat";
|
|
196
|
+
}
|
|
197
|
+
let error;
|
|
198
|
+
try {
|
|
199
|
+
await next();
|
|
200
|
+
}
|
|
201
|
+
catch (e) {
|
|
202
|
+
error = e instanceof Error ? e.message : String(e);
|
|
203
|
+
throw e;
|
|
204
|
+
}
|
|
205
|
+
finally {
|
|
206
|
+
const durationMs = Date.now() - startTime;
|
|
207
|
+
emitter.emit(McpsEventType.Request, {
|
|
208
|
+
timestamp: new Date().toISOString(),
|
|
209
|
+
method: c.req.method,
|
|
210
|
+
path,
|
|
211
|
+
serverName,
|
|
212
|
+
serverType,
|
|
213
|
+
status: c.res.status,
|
|
214
|
+
durationMs,
|
|
215
|
+
error,
|
|
216
|
+
requestHeaders: headersToRecord(c.req.raw.headers)
|
|
217
|
+
});
|
|
218
|
+
}
|
|
164
219
|
};
|
|
165
220
|
}
|
|
166
221
|
//# sourceMappingURL=server.js.map
|
package/lib/server/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/server.ts"],"sourcesContent":["import consola from 'consola';\nimport { Hono } from 'hono';\nimport { logger } from 'hono/logger';\nimport { LRUCache } from 'lru-cache';\nimport { isDevelopment } from 'std-env';\nimport type { McpServerInstance } from '@wener/ai/mcp';\nimport { findMcpServerDef } from '../providers/findMcpServerDef';\nimport { registerApiRoutes } from './api-routes';\nimport { auditMiddleware, configureAudit } from './audit';\nimport { registerChatRoutes } from './chat-routes';\nimport { loadConfig, loadEnvFiles, substituteEnvVars } from './config';\nimport { registerMcpRoutes } from './mcp-routes';\n\nconst log = consola.withTag('mcps');\n\nexport interface CreateServerOptions {\n\tcwd?: string;\n\tport?: number;\n\t/** Enable server config discovery endpoints (default: false) */\n\tdiscoveryConfig?: boolean;\n}\n\nexport function createServer(options: CreateServerOptions = {}) {\n\tconst { cwd = process.cwd(), discoveryConfig: discoveryConfigOption } = options;\n\n\tconst app = new Hono();\n\n\t// Request logging\n\tapp.use(\n\t\tlogger((v) => {\n\t\t\tlog.debug(v);\n\t\t}),\n\t);\n\n\t// Audit middleware\n\tapp.use(auditMiddleware());\n\n\t// Load .env files first\n\tloadEnvFiles(cwd);\n\n\t// Load config (with env var substitution)\n\tconst config = substituteEnvVars(loadConfig(cwd));\n\t// discoveryConfig: CLI option overrides config file, defaults to false\n\tconst discoveryConfig = discoveryConfigOption ?? config.discoveryConfig ?? false;\n\n\t// Log available server types from registry\n\tconst serverDefs = findMcpServerDef();\n\tlog.info(`Available server types: ${serverDefs.map((d) => d.name).join(', ')}`);\n\tlog.info(`Loaded ${Object.keys(config.servers).length} servers from config (discoveryConfig: ${discoveryConfig})`);\n\n\t// Configure audit with lazy DB initialization\n\t// DB will only be initialized when the first audit event needs persistence\n\tconfigureAudit(config.audit, config.db);\n\tconst auditEnabled = config.audit?.enabled !== false;\n\tconst auditDbPath = config.audit?.db?.path ?? config.db?.path ?? '.mcps.db';\n\tlog.info(`Audit configured: enabled=${auditEnabled}, db=${auditDbPath} (lazy init)`);\n\n\t// Unified cache for all MCP servers (both pre-configured and dynamic)\n\t// Keyed by cache key from def.getCacheKey() or `config::${name}` for pre-configured\n\tconst serverCache = new LRUCache<string, McpServerInstance>({\n\t\tmax: 100,\n\t\tdispose: (value, key) => {\n\t\t\tlog.info(`Closing expired MCP server: ${key}`);\n\t\t\tvalue.close?.().catch((e: unknown) => log.error('Failed to close server', e));\n\t\t},\n\t});\n\n\t// =========================================================================\n\t// Register MCP routes (pre-configured and dynamic endpoints)\n\t// =========================================================================\n\tregisterMcpRoutes({ app, config, serverCache });\n\n\t// =========================================================================\n\t// Register Chat/LLM Gateway routes\n\t// =========================================================================\n\tregisterChatRoutes({ app, config });\n\n\t// =========================================================================\n\t// Health and info endpoints\n\t// =========================================================================\n\tapp.get('/health', (c) => c.json({ status: 'ok' }));\n\n\tapp.get('/', (c) => {\n\t\treturn c.json({ message: 'hello' });\n\t});\n\n\t// Server info - only available in dev mode or when discoveryConfig is enabled\n\tif (isDevelopment || discoveryConfig) {\n\t\tapp.get('/info', (c) => {\n\t\t\t// Dynamically get routes from Hono app\n\t\t\tconst routes = app.routes\n\t\t\t\t.map((r) => ({ method: r.method, path: r.path }))\n\t\t\t\t.filter((r) => r.method !== 'ALL' || r.path.startsWith('/mcp/'))\n\t\t\t\t.sort((a, b) => a.path.localeCompare(b.path) || a.method.localeCompare(b.method));\n\n\t\t\t// Group routes by category\n\t\t\tconst mcpRoutes = routes.filter((r) => r.path.startsWith('/mcp/')).map((r) => r.path);\n\t\t\tconst apiRoutes = routes.filter((r) => r.path.startsWith('/api/')).map((r) => `${r.method} ${r.path}`);\n\t\t\tconst chatRoutes = routes.filter((r) => r.path.startsWith('/v1/')).map((r) => `${r.method} ${r.path}`);\n\n\t\t\t// Get unique MCP paths\n\t\t\tconst uniqueMcpPaths = [...new Set(mcpRoutes)];\n\n\t\t\treturn c.json({\n\t\t\t\tname: '@wener/mcps',\n\t\t\t\tversion: '0.1.0',\n\t\t\t\tservers: Object.keys(config.servers),\n\t\t\t\tserverTypes: findMcpServerDef().map((d) => d.name),\n\t\t\t\tmodels: config.models ? config.models.map((m) => m.name) : [],\n\t\t\t\tendpoints: {\n\t\t\t\t\tmcp: uniqueMcpPaths,\n\t\t\t\t\tapi: [...new Set(apiRoutes)],\n\t\t\t\t\tchat: [...new Set(chatRoutes)],\n\t\t\t\t},\n\t\t\t});\n\t\t});\n\t}\n\n\t// =========================================================================\n\t// Register oRPC API routes\n\t// =========================================================================\n\tregisterApiRoutes({ app, config });\n\n\t/**\n\t * Print available endpoints grouped by category\n\t */\n\tconst printEndpoints = () => {\n\t\tconst routes = app.routes;\n\t\tconst mcpPaths = new Set<string>();\n\t\tconst apiPaths = new Set<string>();\n\t\tconst chatPaths = new Set<string>();\n\t\tconst otherPaths = new Set<string>();\n\n\t\tfor (const route of routes) {\n\t\t\tconst path = route.path;\n\t\t\tif (path.startsWith('/mcp/')) {\n\t\t\t\tmcpPaths.add(path);\n\t\t\t} else if (path.startsWith('/api/')) {\n\t\t\t\tapiPaths.add(`${route.method} ${path}`);\n\t\t\t} else if (path.startsWith('/v1/')) {\n\t\t\t\tchatPaths.add(`${route.method} ${path}`);\n\t\t\t} else if (route.method !== 'ALL') {\n\t\t\t\totherPaths.add(`${route.method} ${path}`);\n\t\t\t}\n\t\t}\n\n\t\tlog.info('Available endpoints:');\n\t\tif (mcpPaths.size > 0) {\n\t\t\tlog.info(` MCP: ${[...mcpPaths].sort().join(', ')}`);\n\t\t}\n\t\tif (chatPaths.size > 0) {\n\t\t\tlog.info(` Chat: ${[...chatPaths].sort().join(', ')}`);\n\t\t}\n\t\tif (apiPaths.size > 0) {\n\t\t\tlog.info(` API: ${[...apiPaths].sort().join(', ')}`);\n\t\t}\n\t\tif (otherPaths.size > 0) {\n\t\t\tlog.info(` Other: ${[...otherPaths].sort().join(', ')}`);\n\t\t}\n\t};\n\n\treturn { app, config, serverCache, printEndpoints };\n}\n"],"names":["consola","Hono","logger","LRUCache","isDevelopment","findMcpServerDef","registerApiRoutes","auditMiddleware","configureAudit","registerChatRoutes","loadConfig","loadEnvFiles","substituteEnvVars","registerMcpRoutes","log","withTag","createServer","options","cwd","process","discoveryConfig","discoveryConfigOption","app","use","v","debug","config","serverDefs","info","map","d","name","join","Object","keys","servers","length","audit","db","auditEnabled","enabled","auditDbPath","path","serverCache","max","dispose","value","key","close","catch","e","error","get","c","json","status","message","routes","r","method","filter","startsWith","sort","a","b","localeCompare","mcpRoutes","apiRoutes","chatRoutes","uniqueMcpPaths","Set","version","serverTypes","models","m","endpoints","mcp","api","chat","printEndpoints","mcpPaths","apiPaths","chatPaths","otherPaths","route","add","size"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/server/server.ts"],"sourcesContent":["import consola from 'consola';\nimport type { Context, Next } from 'hono';\nimport { Hono } from 'hono';\nimport { logger } from 'hono/logger';\nimport { LRUCache } from 'lru-cache';\nimport { isDevelopment } from 'std-env';\nimport type { McpServerInstance } from '@wener/ai/mcp';\nimport { findMcpServerDef } from '../providers/findMcpServerDef';\nimport { registerApiRoutes } from './api-routes';\nimport { registerChatRoutes } from './chat-routes';\nimport { loadConfig, loadEnvFiles, substituteEnvVars } from './config';\nimport { createMcpsEmitter, McpsEventType, type McpsEmitter } from './events';\nimport { registerMcpRoutes } from './mcp-routes';\n\nconst log = consola.withTag('mcps');\n\nexport interface McpsServerContext {\n\tapp: Hono;\n\tconfig: import('./schema').McpsConfig;\n\temitter: McpsEmitter;\n\tserverCache: LRUCache<string, McpServerInstance>;\n\t/** Plugins can register additional oRPC routers here */\n\tapiRouters: Record<string, any>;\n\t/** Plugins can register stats providers here */\n\tstatsProvider?: StatsProvider;\n}\n\nexport interface StatsProvider {\n\tgetStats(options: { from?: string | null; to?: string | null }): {\n\t\ttotalRequests: number;\n\t\ttotalErrors: number;\n\t\tavgDurationMs: number;\n\t\tbyServer: Array<{ name: string; count: number }>;\n\t\tbyMethod: Array<{ method: string; count: number }>;\n\t};\n\tqueryEvents(options: { limit?: number }): { events: Array<{ path: string }>; total: number };\n}\n\nexport interface CreateServerOptions {\n\tcwd?: string;\n\tport?: number;\n\t/** Enable server config discovery endpoints (default: false) */\n\tdiscoveryConfig?: boolean;\n\t/**\n\t * Called after core server is created but before routes are registered.\n\t * Use this to set up optional plugins like audit via the emitter.\n\t */\n\tsetup?: (ctx: McpsServerContext) => void | Promise<void>;\n}\n\nexport function createServer(options: CreateServerOptions = {}) {\n\tconst { cwd = process.cwd(), discoveryConfig: discoveryConfigOption, setup } = options;\n\n\tconst app = new Hono();\n\tconst emitter = createMcpsEmitter();\n\tconst apiRouters: Record<string, any> = {};\n\n\t// Request logging\n\tapp.use(\n\t\tlogger((v) => {\n\t\t\tlog.debug(v);\n\t\t}),\n\t);\n\n\t// Request event middleware - emits events for subscribers (audit, monitoring, etc.)\n\tapp.use(requestEventMiddleware(emitter));\n\n\t// Load .env files first\n\tloadEnvFiles(cwd);\n\n\t// Load config (with env var substitution)\n\tconst config = substituteEnvVars(loadConfig(cwd));\n\tconst discoveryConfig = discoveryConfigOption ?? config.discoveryConfig ?? false;\n\n\t// Log available server types from registry\n\tconst serverDefs = findMcpServerDef();\n\tlog.info(`Available server types: ${serverDefs.map((d) => d.name).join(', ')}`);\n\tlog.info(`Loaded ${Object.keys(config.servers).length} servers from config (discoveryConfig: ${discoveryConfig})`);\n\n\t// Unified cache for all MCP servers\n\tconst serverCache = new LRUCache<string, McpServerInstance>({\n\t\tmax: 100,\n\t\tdispose: (value, key) => {\n\t\t\tlog.info(`Closing expired MCP server: ${key}`);\n\t\t\tvalue.close?.().catch((e: unknown) => log.error('Failed to close server', e));\n\t\t},\n\t});\n\n\tconst ctx: McpsServerContext = { app, config, emitter, serverCache, apiRouters };\n\n\tconst finalize = async () => {\n\t\t// Allow plugins to set up before routes are registered\n\t\tawait setup?.(ctx);\n\n\t\t// =========================================================================\n\t\t// Register MCP routes (pre-configured and dynamic endpoints)\n\t\t// =========================================================================\n\t\tregisterMcpRoutes({ app, config, serverCache });\n\n\t\t// =========================================================================\n\t\t// Register Chat/LLM Gateway routes\n\t\t// =========================================================================\n\t\tregisterChatRoutes({ app, config });\n\n\t\t// =========================================================================\n\t\t// Health and info endpoints\n\t\t// =========================================================================\n\t\tapp.get('/health', (c) => c.json({ status: 'ok' }));\n\t\tapp.get('/', (c) => c.json({ message: 'hello' }));\n\n\t\tif (isDevelopment || discoveryConfig) {\n\t\t\tapp.get('/info', (c) => {\n\t\t\t\tconst routes = app.routes\n\t\t\t\t\t.map((r) => ({ method: r.method, path: r.path }))\n\t\t\t\t\t.filter((r) => r.method !== 'ALL' || r.path.startsWith('/mcp/'))\n\t\t\t\t\t.sort((a, b) => a.path.localeCompare(b.path) || a.method.localeCompare(b.method));\n\n\t\t\t\tconst mcpRoutes = routes.filter((r) => r.path.startsWith('/mcp/')).map((r) => r.path);\n\t\t\t\tconst apiRoutes = routes.filter((r) => r.path.startsWith('/api/')).map((r) => `${r.method} ${r.path}`);\n\t\t\t\tconst chatRoutes = routes.filter((r) => r.path.startsWith('/v1/')).map((r) => `${r.method} ${r.path}`);\n\t\t\t\tconst uniqueMcpPaths = [...new Set(mcpRoutes)];\n\n\t\t\t\treturn c.json({\n\t\t\t\t\tname: '@wener/mcps',\n\t\t\t\t\tversion: '0.1.0',\n\t\t\t\t\tservers: Object.keys(config.servers),\n\t\t\t\t\tserverTypes: findMcpServerDef().map((d) => d.name),\n\t\t\t\t\tmodels: config.models ? config.models.map((m) => m.name) : [],\n\t\t\t\t\tendpoints: {\n\t\t\t\t\t\tmcp: uniqueMcpPaths,\n\t\t\t\t\t\tapi: [...new Set(apiRoutes)],\n\t\t\t\t\t\tchat: [...new Set(chatRoutes)],\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t});\n\t\t}\n\n\t\t// =========================================================================\n\t\t// Register oRPC API routes (with any plugin-provided routers)\n\t\t// =========================================================================\n\t\tregisterApiRoutes({ app, config, apiRouters, statsProvider: ctx.statsProvider });\n\t};\n\n\tconst printEndpoints = () => {\n\t\tconst routes = app.routes;\n\t\tconst mcpPaths = new Set<string>();\n\t\tconst apiPaths = new Set<string>();\n\t\tconst chatPaths = new Set<string>();\n\t\tconst otherPaths = new Set<string>();\n\n\t\tfor (const route of routes) {\n\t\t\tconst path = route.path;\n\t\t\tif (path.startsWith('/mcp/')) {\n\t\t\t\tmcpPaths.add(path);\n\t\t\t} else if (path.startsWith('/api/')) {\n\t\t\t\tapiPaths.add(`${route.method} ${path}`);\n\t\t\t} else if (path.startsWith('/v1/')) {\n\t\t\t\tchatPaths.add(`${route.method} ${path}`);\n\t\t\t} else if (route.method !== 'ALL') {\n\t\t\t\totherPaths.add(`${route.method} ${path}`);\n\t\t\t}\n\t\t}\n\n\t\tlog.info('Available endpoints:');\n\t\tif (mcpPaths.size > 0) log.info(` MCP: ${[...mcpPaths].sort().join(', ')}`);\n\t\tif (chatPaths.size > 0) log.info(` Chat: ${[...chatPaths].sort().join(', ')}`);\n\t\tif (apiPaths.size > 0) log.info(` API: ${[...apiPaths].sort().join(', ')}`);\n\t\tif (otherPaths.size > 0) log.info(` Other: ${[...otherPaths].sort().join(', ')}`);\n\t};\n\n\treturn { app, config, emitter, serverCache, printEndpoints, finalize };\n}\n\nfunction headersToRecord(headers: Headers): Record<string, string> {\n\tconst record: Record<string, string> = {};\n\theaders.forEach((value, key) => {\n\t\trecord[key] = value;\n\t});\n\treturn record;\n}\n\n/**\n * Middleware that emits request events via the emitter.\n * Subscribers (like audit plugin) can listen and handle these events.\n */\nfunction requestEventMiddleware(emitter: McpsEmitter) {\n\treturn async (c: Context, next: Next) => {\n\t\tconst startTime = Date.now();\n\t\tconst path = c.req.path;\n\n\t\tlet serverName: string | undefined;\n\t\tlet serverType: string | undefined;\n\n\t\tconst mcpMatch = path.match(/^\\/mcp\\/([^/]+)/);\n\t\tif (mcpMatch) {\n\t\t\tserverName = mcpMatch[1];\n\t\t\tif (['tencent-cls', 'sql', 'prometheus', 'relay'].includes(serverName)) {\n\t\t\t\tserverType = serverName;\n\t\t\t} else {\n\t\t\t\tserverType = 'custom';\n\t\t\t}\n\t\t}\n\n\t\tif (path.startsWith('/v1/')) {\n\t\t\tserverType = 'chat';\n\t\t}\n\n\t\tlet error: string | undefined;\n\n\t\ttry {\n\t\t\tawait next();\n\t\t} catch (e) {\n\t\t\terror = e instanceof Error ? e.message : String(e);\n\t\t\tthrow e;\n\t\t} finally {\n\t\t\tconst durationMs = Date.now() - startTime;\n\n\t\t\temitter.emit(McpsEventType.Request, {\n\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\tmethod: c.req.method,\n\t\t\t\tpath,\n\t\t\t\tserverName,\n\t\t\t\tserverType,\n\t\t\t\tstatus: c.res.status,\n\t\t\t\tdurationMs,\n\t\t\t\terror,\n\t\t\t\trequestHeaders: headersToRecord(c.req.raw.headers),\n\t\t\t});\n\t\t}\n\t};\n}\n"],"names":["consola","Hono","logger","LRUCache","isDevelopment","findMcpServerDef","registerApiRoutes","registerChatRoutes","loadConfig","loadEnvFiles","substituteEnvVars","createMcpsEmitter","McpsEventType","registerMcpRoutes","log","withTag","createServer","options","cwd","process","discoveryConfig","discoveryConfigOption","setup","app","emitter","apiRouters","use","v","debug","requestEventMiddleware","config","serverDefs","info","map","d","name","join","Object","keys","servers","length","serverCache","max","dispose","value","key","close","catch","e","error","ctx","finalize","get","c","json","status","message","routes","r","method","path","filter","startsWith","sort","a","b","localeCompare","mcpRoutes","apiRoutes","chatRoutes","uniqueMcpPaths","Set","version","serverTypes","models","m","endpoints","mcp","api","chat","statsProvider","printEndpoints","mcpPaths","apiPaths","chatPaths","otherPaths","route","add","size","headersToRecord","headers","record","forEach","next","startTime","Date","now","req","serverName","serverType","mcpMatch","match","includes","Error","String","durationMs","emit","Request","timestamp","toISOString","res","requestHeaders","raw"],"mappings":"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"}
|