@wener/mcps 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.mjs +15 -0
  3. package/dist/mcps-cli.mjs +174727 -0
  4. package/lib/chat/agent.js +187 -0
  5. package/lib/chat/agent.js.map +1 -0
  6. package/lib/chat/audit.js +238 -0
  7. package/lib/chat/audit.js.map +1 -0
  8. package/lib/chat/converters.js +467 -0
  9. package/lib/chat/converters.js.map +1 -0
  10. package/lib/chat/handler.js +1068 -0
  11. package/lib/chat/handler.js.map +1 -0
  12. package/lib/chat/index.js +12 -0
  13. package/lib/chat/index.js.map +1 -0
  14. package/lib/chat/types.js +35 -0
  15. package/lib/chat/types.js.map +1 -0
  16. package/lib/contracts/AuditContract.js +85 -0
  17. package/lib/contracts/AuditContract.js.map +1 -0
  18. package/lib/contracts/McpsContract.js +113 -0
  19. package/lib/contracts/McpsContract.js.map +1 -0
  20. package/lib/contracts/index.js +3 -0
  21. package/lib/contracts/index.js.map +1 -0
  22. package/lib/dev.server.js +7 -0
  23. package/lib/dev.server.js.map +1 -0
  24. package/lib/entities/ChatRequestEntity.js +318 -0
  25. package/lib/entities/ChatRequestEntity.js.map +1 -0
  26. package/lib/entities/McpRequestEntity.js +271 -0
  27. package/lib/entities/McpRequestEntity.js.map +1 -0
  28. package/lib/entities/RequestLogEntity.js +177 -0
  29. package/lib/entities/RequestLogEntity.js.map +1 -0
  30. package/lib/entities/ResponseEntity.js +150 -0
  31. package/lib/entities/ResponseEntity.js.map +1 -0
  32. package/lib/entities/index.js +11 -0
  33. package/lib/entities/index.js.map +1 -0
  34. package/lib/entities/types.js +11 -0
  35. package/lib/entities/types.js.map +1 -0
  36. package/lib/index.js +3 -0
  37. package/lib/index.js.map +1 -0
  38. package/lib/mcps-cli.js +44 -0
  39. package/lib/mcps-cli.js.map +1 -0
  40. package/lib/providers/McpServerHandlerDef.js +40 -0
  41. package/lib/providers/McpServerHandlerDef.js.map +1 -0
  42. package/lib/providers/findMcpServerDef.js +26 -0
  43. package/lib/providers/findMcpServerDef.js.map +1 -0
  44. package/lib/providers/prometheus/def.js +24 -0
  45. package/lib/providers/prometheus/def.js.map +1 -0
  46. package/lib/providers/prometheus/index.js +2 -0
  47. package/lib/providers/prometheus/index.js.map +1 -0
  48. package/lib/providers/relay/def.js +32 -0
  49. package/lib/providers/relay/def.js.map +1 -0
  50. package/lib/providers/relay/index.js +2 -0
  51. package/lib/providers/relay/index.js.map +1 -0
  52. package/lib/providers/sql/def.js +31 -0
  53. package/lib/providers/sql/def.js.map +1 -0
  54. package/lib/providers/sql/index.js +2 -0
  55. package/lib/providers/sql/index.js.map +1 -0
  56. package/lib/providers/tencent-cls/def.js +44 -0
  57. package/lib/providers/tencent-cls/def.js.map +1 -0
  58. package/lib/providers/tencent-cls/index.js +2 -0
  59. package/lib/providers/tencent-cls/index.js.map +1 -0
  60. package/lib/scripts/bundle.js +90 -0
  61. package/lib/scripts/bundle.js.map +1 -0
  62. package/lib/server/api-routes.js +96 -0
  63. package/lib/server/api-routes.js.map +1 -0
  64. package/lib/server/audit.js +274 -0
  65. package/lib/server/audit.js.map +1 -0
  66. package/lib/server/chat-routes.js +82 -0
  67. package/lib/server/chat-routes.js.map +1 -0
  68. package/lib/server/config.js +223 -0
  69. package/lib/server/config.js.map +1 -0
  70. package/lib/server/db.js +97 -0
  71. package/lib/server/db.js.map +1 -0
  72. package/lib/server/index.js +2 -0
  73. package/lib/server/index.js.map +1 -0
  74. package/lib/server/mcp-handler.js +167 -0
  75. package/lib/server/mcp-handler.js.map +1 -0
  76. package/lib/server/mcp-routes.js +112 -0
  77. package/lib/server/mcp-routes.js.map +1 -0
  78. package/lib/server/mcps-router.js +119 -0
  79. package/lib/server/mcps-router.js.map +1 -0
  80. package/lib/server/schema.js +129 -0
  81. package/lib/server/schema.js.map +1 -0
  82. package/lib/server/server.js +166 -0
  83. package/lib/server/server.js.map +1 -0
  84. package/lib/web/ChatPage.js +827 -0
  85. package/lib/web/ChatPage.js.map +1 -0
  86. package/lib/web/McpInspectorPage.js +214 -0
  87. package/lib/web/McpInspectorPage.js.map +1 -0
  88. package/lib/web/ServersPage.js +93 -0
  89. package/lib/web/ServersPage.js.map +1 -0
  90. package/lib/web/main.js +541 -0
  91. package/lib/web/main.js.map +1 -0
  92. package/package.json +83 -0
  93. package/src/chat/agent.ts +240 -0
  94. package/src/chat/audit.ts +377 -0
  95. package/src/chat/converters.test.ts +325 -0
  96. package/src/chat/converters.ts +459 -0
  97. package/src/chat/handler.test.ts +137 -0
  98. package/src/chat/handler.ts +1233 -0
  99. package/src/chat/index.ts +16 -0
  100. package/src/chat/types.ts +72 -0
  101. package/src/contracts/AuditContract.ts +93 -0
  102. package/src/contracts/McpsContract.ts +141 -0
  103. package/src/contracts/index.ts +18 -0
  104. package/src/dev.server.ts +7 -0
  105. package/src/entities/ChatRequestEntity.ts +157 -0
  106. package/src/entities/McpRequestEntity.ts +149 -0
  107. package/src/entities/RequestLogEntity.ts +78 -0
  108. package/src/entities/ResponseEntity.ts +75 -0
  109. package/src/entities/index.ts +12 -0
  110. package/src/entities/types.ts +188 -0
  111. package/src/index.ts +1 -0
  112. package/src/mcps-cli.ts +59 -0
  113. package/src/providers/McpServerHandlerDef.ts +105 -0
  114. package/src/providers/findMcpServerDef.ts +31 -0
  115. package/src/providers/prometheus/def.ts +21 -0
  116. package/src/providers/prometheus/index.ts +1 -0
  117. package/src/providers/relay/def.ts +31 -0
  118. package/src/providers/relay/index.ts +1 -0
  119. package/src/providers/relay/relay.test.ts +47 -0
  120. package/src/providers/sql/def.ts +33 -0
  121. package/src/providers/sql/index.ts +1 -0
  122. package/src/providers/tencent-cls/def.ts +38 -0
  123. package/src/providers/tencent-cls/index.ts +1 -0
  124. package/src/scripts/bundle.ts +82 -0
  125. package/src/server/api-routes.ts +98 -0
  126. package/src/server/audit.ts +310 -0
  127. package/src/server/chat-routes.ts +95 -0
  128. package/src/server/config.test.ts +162 -0
  129. package/src/server/config.ts +198 -0
  130. package/src/server/db.ts +115 -0
  131. package/src/server/index.ts +1 -0
  132. package/src/server/mcp-handler.ts +209 -0
  133. package/src/server/mcp-routes.ts +133 -0
  134. package/src/server/mcps-router.ts +133 -0
  135. package/src/server/schema.ts +175 -0
  136. package/src/server/server.ts +163 -0
  137. package/src/web/ChatPage.tsx +1005 -0
  138. package/src/web/McpInspectorPage.tsx +254 -0
  139. package/src/web/ServersPage.tsx +139 -0
  140. package/src/web/main.tsx +600 -0
  141. package/src/web/styles.css +15 -0
@@ -0,0 +1,78 @@
1
+ import { Entity, PrimaryKey, Property } from '@mikro-orm/decorators/es';
2
+
3
+ /**
4
+ * Generic HTTP Request Log Entity
5
+ * For general request auditing
6
+ */
7
+ @Entity({ tableName: 'request_log' })
8
+ export class RequestLogEntity {
9
+ @PrimaryKey({ type: 'integer' })
10
+ id!: number;
11
+
12
+ /** Unique request ID */
13
+ @Property({ type: 'string' })
14
+ requestId!: string;
15
+
16
+ /** Request timestamp */
17
+ @Property({ type: 'datetime' })
18
+ timestamp: Date = new Date();
19
+
20
+ /** HTTP method */
21
+ @Property({ type: 'string' })
22
+ method!: string;
23
+
24
+ /** Request path */
25
+ @Property({ type: 'string' })
26
+ path!: string;
27
+
28
+ /** Request type (chat, mcp, api, etc) */
29
+ @Property({ type: 'string', nullable: true })
30
+ requestType?: string;
31
+
32
+ /** Server name (for MCP) or model (for Chat) */
33
+ @Property({ type: 'string', nullable: true })
34
+ serverName?: string;
35
+
36
+ /** Server type */
37
+ @Property({ type: 'string', nullable: true })
38
+ serverType?: string;
39
+
40
+ /** HTTP status code */
41
+ @Property({ type: 'integer', nullable: true })
42
+ status?: number;
43
+
44
+ /** Request duration in ms */
45
+ @Property({ type: 'integer', nullable: true })
46
+ durationMs?: number;
47
+
48
+ /** Error message */
49
+ @Property({ type: 'text', nullable: true })
50
+ error?: string;
51
+
52
+ /** Client IP */
53
+ @Property({ type: 'string', nullable: true })
54
+ clientIp?: string;
55
+
56
+ /** User agent */
57
+ @Property({ type: 'string', nullable: true })
58
+ userAgent?: string;
59
+
60
+ /** Request headers (JSON) */
61
+ @Property({ type: 'json', nullable: true })
62
+ requestHeaders?: Record<string, string>;
63
+
64
+ /** Request body summary (JSON) */
65
+ @Property({ type: 'json', nullable: true })
66
+ requestBody?: Record<string, unknown>;
67
+
68
+ /** Response body summary (JSON) */
69
+ @Property({ type: 'json', nullable: true })
70
+ responseBody?: Record<string, unknown>;
71
+
72
+ /** Additional metadata (JSON) */
73
+ @Property({ type: 'json', nullable: true })
74
+ metadata?: Record<string, unknown>;
75
+
76
+ @Property({ type: 'datetime' })
77
+ createdAt: Date = new Date();
78
+ }
@@ -0,0 +1,75 @@
1
+ import { Entity, PrimaryKey, Property } from '@mikro-orm/decorators/es';
2
+
3
+ /**
4
+ * Response Entity for storing Responses API responses
5
+ * Enables previous_response_id support
6
+ */
7
+ @Entity({ tableName: 'response' })
8
+ export class ResponseEntity {
9
+ @PrimaryKey({ type: 'integer' })
10
+ id!: number;
11
+
12
+ /** Response ID (e.g., resp_xxx) */
13
+ @Property({ type: 'string', unique: true })
14
+ responseId!: string;
15
+
16
+ /** Model name */
17
+ @Property({ type: 'string' })
18
+ model!: string;
19
+
20
+ /** Response status */
21
+ @Property({ type: 'string' })
22
+ status!: string;
23
+
24
+ /** Input (request) - stored as JSON */
25
+ @Property({ type: 'json' })
26
+ input!: unknown;
27
+
28
+ /** Output items - stored as JSON */
29
+ @Property({ type: 'json' })
30
+ output!: unknown[];
31
+
32
+ /** Usage statistics */
33
+ @Property({ type: 'json', nullable: true })
34
+ usage?: {
35
+ prompt_tokens?: number;
36
+ completion_tokens?: number;
37
+ total_tokens?: number;
38
+ };
39
+
40
+ /** Instructions/system prompt */
41
+ @Property({ type: 'text', nullable: true })
42
+ instructions?: string;
43
+
44
+ /** Previous response ID for conversation chaining */
45
+ @Property({ type: 'string', nullable: true })
46
+ previousResponseId?: string;
47
+
48
+ /** Tools configuration */
49
+ @Property({ type: 'json', nullable: true })
50
+ tools?: unknown[];
51
+
52
+ /** Tool choice */
53
+ @Property({ type: 'json', nullable: true })
54
+ toolChoice?: unknown;
55
+
56
+ /** Metadata */
57
+ @Property({ type: 'json', nullable: true })
58
+ metadata?: Record<string, unknown>;
59
+
60
+ /** Error information */
61
+ @Property({ type: 'json', nullable: true })
62
+ error?: {
63
+ type?: string;
64
+ message?: string;
65
+ code?: string;
66
+ };
67
+
68
+ /** Created timestamp */
69
+ @Property({ type: 'datetime' })
70
+ createdAt: Date = new Date();
71
+
72
+ /** Request duration in ms */
73
+ @Property({ type: 'integer', nullable: true })
74
+ durationMs?: number;
75
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Entity type definitions
3
+ * These are pure TypeScript types without decorators
4
+ * Can be used with any ORM or database layer
5
+ */
6
+ export * from './types';
7
+
8
+ // MikroORM Entities
9
+ export { ChatRequestEntity, ChatProtocolType, RequestStatus } from './ChatRequestEntity';
10
+ export { McpRequestEntity, McpServerType, McpRequestType } from './McpRequestEntity';
11
+ export { RequestLogEntity } from './RequestLogEntity';
12
+ export { ResponseEntity } from './ResponseEntity';
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Entity Type Definitions
3
+ * These types can be used with MikroORM or other ORMs
4
+ * Avoids decorator issues in test environments
5
+ */
6
+
7
+ /**
8
+ * Base entity fields
9
+ */
10
+ export interface BaseEntity {
11
+ id: number;
12
+ createdAt: Date;
13
+ updatedAt: Date;
14
+ }
15
+
16
+ /**
17
+ * Request status
18
+ */
19
+ export type RequestStatus = 'pending' | 'success' | 'error' | 'timeout';
20
+
21
+ /**
22
+ * Chat protocol type
23
+ */
24
+ export type ChatProtocolType = 'openai' | 'anthropic' | 'gemini';
25
+
26
+ /**
27
+ * MCP server type
28
+ */
29
+ export type McpServerType = 'tencent-cls' | 'sql' | 'prometheus' | 'relay' | 'custom';
30
+
31
+ /**
32
+ * MCP request type
33
+ */
34
+ export type McpRequestType =
35
+ | 'initialize'
36
+ | 'tools/list'
37
+ | 'tools/call'
38
+ | 'resources/list'
39
+ | 'resources/read'
40
+ | 'prompts/list'
41
+ | 'prompts/get'
42
+ | 'completion/complete'
43
+ | 'logging/setLevel'
44
+ | 'ping'
45
+ | 'other';
46
+
47
+ /**
48
+ * Chat request entity for auditing and metering
49
+ */
50
+ export interface ChatRequest extends BaseEntity {
51
+ /** Unique request ID for tracing */
52
+ requestId: string;
53
+ /** Request timestamp */
54
+ requestedAt: Date;
55
+ /** Response timestamp */
56
+ completedAt?: Date;
57
+ /** Request status */
58
+ status: RequestStatus;
59
+ /** HTTP method */
60
+ method: string;
61
+ /** Request path/endpoint */
62
+ endpoint: string;
63
+ /** Input protocol (client-facing) */
64
+ inputProtocol: ChatProtocolType;
65
+ /** Output protocol (upstream provider) */
66
+ outputProtocol: ChatProtocolType;
67
+ /** Model name requested */
68
+ model: string;
69
+ /** Resolved model name */
70
+ resolvedModel?: string;
71
+ /** Provider name */
72
+ provider?: string;
73
+ /** Upstream base URL */
74
+ upstreamUrl?: string;
75
+ /** Whether request was streaming */
76
+ streaming: boolean;
77
+ /** Input token count */
78
+ inputTokens?: number;
79
+ /** Output token count */
80
+ outputTokens?: number;
81
+ /** Total token count */
82
+ totalTokens?: number;
83
+ /** Request duration in ms */
84
+ durationMs?: number;
85
+ /** Time to first token in ms */
86
+ ttftMs?: number;
87
+ /** HTTP status code */
88
+ httpStatus?: number;
89
+ /** Error message */
90
+ errorMessage?: string;
91
+ /** Error code */
92
+ errorCode?: string;
93
+ /** Client IP */
94
+ clientIp?: string;
95
+ /** User agent */
96
+ userAgent?: string;
97
+ /** User ID */
98
+ userId?: string;
99
+ /** Organization ID */
100
+ orgId?: string;
101
+ /** API key ID (not the actual key) */
102
+ apiKeyId?: string;
103
+ /** Request metadata */
104
+ requestMeta?: Record<string, unknown>;
105
+ /** Response metadata */
106
+ responseMeta?: Record<string, unknown>;
107
+ /** Cost in credits */
108
+ cost?: string;
109
+ /** Currency */
110
+ currency?: string;
111
+ }
112
+
113
+ /**
114
+ * MCP request entity for auditing
115
+ */
116
+ export interface McpRequest extends BaseEntity {
117
+ /** Unique request ID */
118
+ requestId: string;
119
+ /** MCP session ID */
120
+ sessionId?: string;
121
+ /** Request timestamp */
122
+ requestedAt: Date;
123
+ /** Response timestamp */
124
+ completedAt?: Date;
125
+ /** Request status */
126
+ status: RequestStatus;
127
+ /** HTTP method */
128
+ method: string;
129
+ /** Request path */
130
+ path: string;
131
+ /** MCP server name */
132
+ serverName: string;
133
+ /** MCP server type */
134
+ serverType: McpServerType;
135
+ /** MCP request type */
136
+ mcpMethod: McpRequestType;
137
+ /** Tool name (for tools/call) */
138
+ toolName?: string;
139
+ /** Resource URI (for resources/read) */
140
+ resourceUri?: string;
141
+ /** Prompt name (for prompts/get) */
142
+ promptName?: string;
143
+ /** Request duration in ms */
144
+ durationMs?: number;
145
+ /** HTTP status code */
146
+ httpStatus?: number;
147
+ /** Error message */
148
+ errorMessage?: string;
149
+ /** Error code */
150
+ errorCode?: string;
151
+ /** Client IP */
152
+ clientIp?: string;
153
+ /** User agent */
154
+ userAgent?: string;
155
+ /** User ID */
156
+ userId?: string;
157
+ /** Request headers */
158
+ requestHeaders?: Record<string, string>;
159
+ /** Request body */
160
+ requestBody?: Record<string, unknown>;
161
+ /** Response metadata */
162
+ responseMeta?: Record<string, unknown>;
163
+ }
164
+
165
+ /**
166
+ * Chat audit statistics
167
+ */
168
+ export interface ChatAuditStats {
169
+ totalRequests: number;
170
+ successfulRequests: number;
171
+ failedRequests: number;
172
+ totalInputTokens: number;
173
+ totalOutputTokens: number;
174
+ avgDurationMs: number;
175
+ byModel: { model: string; count: number; tokens: number }[];
176
+ byProvider: { provider: string; count: number; tokens: number }[];
177
+ }
178
+
179
+ /**
180
+ * MCP audit statistics
181
+ */
182
+ export interface McpAuditStats {
183
+ totalRequests: number;
184
+ totalErrors: number;
185
+ avgDurationMs: number;
186
+ byServer: { name: string; count: number }[];
187
+ byMethod: { method: string; count: number }[];
188
+ }
package/src/index.ts ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MCPS - MCP Proxy Server CLI
4
+ *
5
+ * A unified MCP server that supports:
6
+ * - Tencent CLS (Cloud Log Service)
7
+ * - SQL (MySQL, PostgreSQL, SQLite)
8
+ * - Prometheus
9
+ * - Relay (proxy to other MCP servers)
10
+ */
11
+ import { serve } from '@hono/node-server';
12
+ import { Command } from 'commander';
13
+ import consola from 'consola';
14
+ import { createServer } from './server/server';
15
+
16
+ const log = consola.withTag('mcps');
17
+
18
+ const program = new Command();
19
+
20
+ program
21
+ .name('mcps')
22
+ .description('MCP Proxy Server - Unified MCP service with relay, SQL, CLS, and Prometheus support')
23
+ .version('0.1.0')
24
+ .option('-p, --port <port>', 'Port to listen on', '8036')
25
+ .option('-c, --cwd <path>', 'Working directory for config files', process.cwd())
26
+ .option('--discovery-config', 'Enable server config discovery endpoints', false)
27
+ .action(async (options) => {
28
+ const port = Number.parseInt(options.port, 10);
29
+ const { app } = createServer({
30
+ cwd: options.cwd,
31
+ port,
32
+ discoveryConfig: options.discoveryConfig,
33
+ });
34
+
35
+ log.info(`Starting MCPS server on port ${port}`);
36
+
37
+ serve({
38
+ fetch: app.fetch,
39
+ port,
40
+ hostname: '0.0.0.0',
41
+ });
42
+
43
+ log.success(`MCPS server running at http://localhost:${port}`);
44
+ });
45
+
46
+ // Handle graceful shutdown
47
+ process.on('SIGINT', () => {
48
+ log.info('Shutting down...');
49
+ process.exit(130);
50
+ });
51
+ process.on('SIGTERM', () => {
52
+ log.info('Shutting down...');
53
+ process.exit(143);
54
+ });
55
+
56
+ program.parseAsync(process.argv).catch((error) => {
57
+ log.error(error.message);
58
+ process.exit(1);
59
+ });
@@ -0,0 +1,105 @@
1
+ import type { McpServerDef, McpServerInstance, ValidationResult } from '@wener/ai/mcp';
2
+
3
+ /**
4
+ * Header to config property mapping
5
+ */
6
+ export interface HeaderMapping {
7
+ /** Header name (e.g., 'X-CLS-SECRET-ID') */
8
+ header: string;
9
+ /** Config property name (e.g., 'clientId') */
10
+ property: string;
11
+ /** Whether this header/property is required */
12
+ required?: boolean;
13
+ /** Default value if not provided */
14
+ default?: string;
15
+ }
16
+
17
+ /**
18
+ * MCP Server Handler Definition - wraps a McpServerDef with HTTP header handling
19
+ */
20
+ export interface McpServerHandlerDef<TOptions = any, TConfig = any> {
21
+ /** Reference to the base MCP server definition */
22
+ base: McpServerDef<TOptions>;
23
+
24
+ /** Unique server type name */
25
+ name: string;
26
+ /** Display name */
27
+ title: string;
28
+ /** Server description */
29
+ description: string;
30
+ /** Server version */
31
+ version: string;
32
+ /** Tags for categorization */
33
+ tags: string[];
34
+ /** Additional metadata */
35
+ metadata: Record<string, any>;
36
+
37
+ /** Header mappings for dynamic endpoint */
38
+ headerMappings?: HeaderMapping[];
39
+
40
+ /** Resolve config from ServerConfig and optional Headers */
41
+ resolveConfig: (config: TConfig, headers?: Headers) => TOptions | null;
42
+
43
+ /** Validate resolved options */
44
+ validateOptions: (options: Partial<TOptions>) => ValidationResult;
45
+
46
+ /** Generate cache key for server instance caching */
47
+ getCacheKey: (options: TOptions) => string;
48
+
49
+ /** Factory function to create the server instance */
50
+ create: (options: TOptions) => McpServerInstance;
51
+ }
52
+
53
+ export interface DefineMcpServerHandlerOptions<TOptions = any, TConfig = any> {
54
+ /** Header mappings for dynamic endpoint */
55
+ headerMappings?: HeaderMapping[];
56
+
57
+ /** Resolve config from ServerConfig and optional Headers */
58
+ resolveConfig: (config: TConfig, headers?: Headers) => TOptions | null;
59
+ }
60
+
61
+ /**
62
+ * Define an MCP server handler by wrapping a base McpServerDef with HTTP header handling
63
+ */
64
+ export function defineMcpServerHandler<TOptions = any, TConfig = any>(
65
+ base: McpServerDef<TOptions>,
66
+ options: DefineMcpServerHandlerOptions<TOptions, TConfig>,
67
+ ): McpServerHandlerDef<TOptions, TConfig> {
68
+ return {
69
+ base,
70
+ name: base.name,
71
+ title: base.title,
72
+ description: base.description,
73
+ version: base.version,
74
+ tags: [...base.tags],
75
+ metadata: { ...base.metadata },
76
+ headerMappings: options.headerMappings,
77
+ resolveConfig: options.resolveConfig,
78
+ validateOptions: base.validateOptions,
79
+ getCacheKey: base.getCacheKey,
80
+ create: base.create,
81
+ };
82
+ }
83
+
84
+ const _all: McpServerHandlerDef[] = [];
85
+
86
+ /**
87
+ * Register an MCP server handler definition
88
+ */
89
+ export function registerMcpServerHandler(def: McpServerHandlerDef): void {
90
+ _all.push(def);
91
+ }
92
+
93
+ /**
94
+ * Get all registered MCP server handler definitions
95
+ */
96
+ export function getAllMcpServerHandlerDefs(): McpServerHandlerDef[] {
97
+ return _all;
98
+ }
99
+
100
+ /**
101
+ * Find MCP server handler definition by name
102
+ */
103
+ export function getMcpServerHandlerDef(name: string): McpServerHandlerDef | undefined {
104
+ return _all.find((def) => def.name === name);
105
+ }
@@ -0,0 +1,31 @@
1
+ import { getAllMcpServerHandlerDefs, type McpServerHandlerDef } from './McpServerHandlerDef';
2
+ // Import all server definitions to ensure they are registered
3
+ import './prometheus/def';
4
+ import './tencent-cls/def';
5
+ import './sql/def';
6
+ import './relay/def';
7
+
8
+ /**
9
+ * Find MCP server definitions matching a predicate
10
+ */
11
+ export function findMcpServerDef(predicate?: (def: McpServerHandlerDef) => boolean): McpServerHandlerDef[] {
12
+ const all = getAllMcpServerHandlerDefs();
13
+ if (!predicate) {
14
+ return all;
15
+ }
16
+ return all.filter(predicate);
17
+ }
18
+
19
+ /**
20
+ * Resolve a single MCP server definition by name
21
+ */
22
+ export function resolveMcpServerDef(name: string): McpServerHandlerDef | undefined {
23
+ return findMcpServerDef((v) => v.name === name)[0];
24
+ }
25
+
26
+ /**
27
+ * Get total count of registered MCP server types
28
+ */
29
+ export function getMcpServerDefCount(): number {
30
+ return getAllMcpServerHandlerDefs().length;
31
+ }
@@ -0,0 +1,21 @@
1
+ import { PrometheusMcpServerDef, type CreatePrometheusMcpServerOptions } from '@wener/ai/mcp/prometheus';
2
+ import { HeaderNames, type PrometheusConfig } from '../../server/schema';
3
+ import { defineMcpServerHandler, registerMcpServerHandler } from '../McpServerHandlerDef';
4
+
5
+ export const PrometheusMcpServerHandlerDef = defineMcpServerHandler<CreatePrometheusMcpServerOptions, PrometheusConfig>(
6
+ PrometheusMcpServerDef,
7
+ {
8
+ headerMappings: [{ header: HeaderNames.SERVICE_URL, property: 'url', required: true }],
9
+
10
+ resolveConfig(config, headers) {
11
+ const url = config.url || headers?.get(HeaderNames.SERVICE_URL) || config.headers?.[HeaderNames.SERVICE_URL];
12
+ if (!url) return null;
13
+ return { url };
14
+ },
15
+ },
16
+ );
17
+
18
+ registerMcpServerHandler(PrometheusMcpServerHandlerDef);
19
+
20
+ // backward compatibility
21
+ export { PrometheusMcpServerHandlerDef as PrometheusMcpServerDef };
@@ -0,0 +1 @@
1
+ export { PrometheusMcpServerDef, PrometheusMcpServerHandlerDef } from './def';
@@ -0,0 +1,31 @@
1
+ import { RelayMcpServerDef, type CreateRelayMcpServerOptions } from '@wener/ai/mcp/relay';
2
+ import { HeaderNames, type RelayConfig } from '../../server/schema';
3
+ import { defineMcpServerHandler, registerMcpServerHandler } from '../McpServerHandlerDef';
4
+
5
+ export const RelayMcpServerHandlerDef = defineMcpServerHandler<CreateRelayMcpServerOptions, RelayConfig>(
6
+ RelayMcpServerDef,
7
+ {
8
+ headerMappings: [
9
+ { header: HeaderNames.MCP_URL, property: 'url', required: true },
10
+ { header: HeaderNames.MCP_TYPE, property: 'transport', default: 'http' },
11
+ ],
12
+
13
+ resolveConfig(config, headers) {
14
+ const url = config.url || headers?.get(HeaderNames.MCP_URL) || config.headers?.[HeaderNames.MCP_URL];
15
+ const transport =
16
+ (config.transport as 'http' | 'sse') ||
17
+ (headers?.get(HeaderNames.MCP_TYPE) as 'http' | 'sse') ||
18
+ (config.headers?.[HeaderNames.MCP_TYPE] as 'http' | 'sse') ||
19
+ 'http';
20
+
21
+ if (!url) return null;
22
+
23
+ return { url, transport, headers: config.headers };
24
+ },
25
+ },
26
+ );
27
+
28
+ registerMcpServerHandler(RelayMcpServerHandlerDef);
29
+
30
+ // backward compatibility
31
+ export { RelayMcpServerHandlerDef as RelayMcpServerDef };
@@ -0,0 +1 @@
1
+ export { RelayMcpServerDef, RelayMcpServerHandlerDef } from './def';
@@ -0,0 +1,47 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { createRelayMcpServer } from '@wener/ai/mcp/relay';
3
+
4
+ describe('createRelayMcpServer', () => {
5
+ describe('deepwiki relay', () => {
6
+ it('should connect to deepwiki and list tools', async () => {
7
+ const { getClient, close } = createRelayMcpServer({
8
+ url: 'https://mcp.deepwiki.com/mcp',
9
+ transport: 'http',
10
+ name: 'deepwiki-relay',
11
+ });
12
+
13
+ try {
14
+ const client = await getClient();
15
+ expect(client).toBeDefined();
16
+
17
+ const tools = await client.listTools();
18
+ expect(tools.tools).toBeDefined();
19
+ expect(Array.isArray(tools.tools)).toBe(true);
20
+ console.log(
21
+ 'DeepWiki tools:',
22
+ tools.tools.map((t: { name: string }) => t.name),
23
+ );
24
+ } finally {
25
+ await close();
26
+ }
27
+ }, 30000);
28
+ });
29
+
30
+ describe('huggingface relay', () => {
31
+ it.skip('should connect to huggingface (requires login)', async () => {
32
+ // Note: huggingface requires login, so this test is skipped by default
33
+ const { getClient, close } = createRelayMcpServer({
34
+ url: 'https://huggingface.co/mcp',
35
+ transport: 'http',
36
+ name: 'hf-relay',
37
+ });
38
+
39
+ try {
40
+ const client = await getClient();
41
+ expect(client).toBeDefined();
42
+ } finally {
43
+ await close();
44
+ }
45
+ }, 30000);
46
+ });
47
+ });
@@ -0,0 +1,33 @@
1
+ import { SqlMcpServerDef, type CreateSqlMcpServerOptions } from '@wener/ai/mcp/sql';
2
+ import { HeaderNames, type SqlConfig } from '../../server/schema';
3
+ import { defineMcpServerHandler, registerMcpServerHandler } from '../McpServerHandlerDef';
4
+
5
+ export const SqlMcpServerHandlerDef = defineMcpServerHandler<CreateSqlMcpServerOptions, SqlConfig>(SqlMcpServerDef, {
6
+ headerMappings: [
7
+ { header: HeaderNames.DB_URL, property: 'url' },
8
+ { header: HeaderNames.DB_READ_URL, property: 'readUrl' },
9
+ { header: HeaderNames.DB_WRITE_URL, property: 'writeUrl' },
10
+ ],
11
+
12
+ resolveConfig(config, headers) {
13
+ const url =
14
+ config.dbUrl ||
15
+ config.dbReadUrl ||
16
+ config.dbWriteUrl ||
17
+ headers?.get(HeaderNames.DB_URL) ||
18
+ headers?.get(HeaderNames.DB_READ_URL) ||
19
+ headers?.get(HeaderNames.DB_WRITE_URL) ||
20
+ config.headers?.[HeaderNames.DB_URL] ||
21
+ config.headers?.[HeaderNames.DB_READ_URL] ||
22
+ config.headers?.[HeaderNames.DB_WRITE_URL];
23
+
24
+ if (!url) return null;
25
+
26
+ return { url };
27
+ },
28
+ });
29
+
30
+ registerMcpServerHandler(SqlMcpServerHandlerDef);
31
+
32
+ // backward compatibility
33
+ export { SqlMcpServerHandlerDef as SqlMcpServerDef };