@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/mcps-cli.js
CHANGED
|
@@ -1,41 +1,12 @@
|
|
|
1
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
|
-
*/ import { serve } from "@hono/node-server";
|
|
11
|
-
import { Command } from "commander";
|
|
12
2
|
import consola from "consola";
|
|
13
|
-
import {
|
|
3
|
+
import { createProgram } from "./cli.js";
|
|
14
4
|
const log = consola.withTag("mcps");
|
|
15
|
-
const program =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
port,
|
|
21
|
-
discoveryConfig: options.discoveryConfig
|
|
22
|
-
});
|
|
23
|
-
log.info(`Starting MCPS server on port ${port}`);
|
|
24
|
-
serve({
|
|
25
|
-
fetch: app.fetch,
|
|
26
|
-
port,
|
|
27
|
-
hostname: "0.0.0.0"
|
|
28
|
-
});
|
|
29
|
-
log.success(`MCPS server running at http://localhost:${port}`);
|
|
30
|
-
});
|
|
31
|
-
// Handle graceful shutdown
|
|
32
|
-
process.on("SIGINT", () => {
|
|
33
|
-
log.info("Shutting down...");
|
|
34
|
-
process.exit(130);
|
|
35
|
-
});
|
|
36
|
-
process.on("SIGTERM", () => {
|
|
37
|
-
log.info("Shutting down...");
|
|
38
|
-
process.exit(143);
|
|
5
|
+
const program = createProgram({
|
|
6
|
+
setup: async (ctx) => {
|
|
7
|
+
const { setupAudit } = await import("./audit/server/plugin.js");
|
|
8
|
+
setupAudit(ctx);
|
|
9
|
+
}
|
|
39
10
|
});
|
|
40
11
|
program.parseAsync(process.argv).catch((error) => {
|
|
41
12
|
log.error(error.message);
|
package/lib/mcps-cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcps-cli.ts"],"sourcesContent":["#!/usr/bin/env node\
|
|
1
|
+
{"version":3,"sources":["../src/mcps-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport consola from 'consola';\nimport { createProgram } from './cli';\n\nconst log = consola.withTag('mcps');\n\nconst program = createProgram({\n\tsetup: async (ctx) => {\n\t\tconst { setupAudit } = await import('./audit/server/plugin.js');\n\t\tsetupAudit(ctx);\n\t},\n});\n\nprogram.parseAsync(process.argv).catch((error) => {\n\tlog.error(error.message);\n\tprocess.exit(1);\n});\n"],"names":["consola","createProgram","log","withTag","program","setup","ctx","setupAudit","parseAsync","process","argv","catch","error","message","exit"],"mappings":";AACA,OAAOA,aAAa,UAAU;AAC9B,SAASC,aAAa,QAAQ,QAAQ;AAEtC,MAAMC,MAAMF,QAAQG,OAAO,CAAC;AAE5B,MAAMC,UAAUH,cAAc;IAC7BI,OAAO,OAAOC;QACb,MAAM,EAAEC,UAAU,EAAE,GAAG,MAAM,MAAM,CAAC;QACpCA,WAAWD;IACZ;AACD;AAEAF,QAAQI,UAAU,CAACC,QAAQC,IAAI,EAAEC,KAAK,CAAC,CAACC;IACvCV,IAAIU,KAAK,CAACA,MAAMC,OAAO;IACvBJ,QAAQK,IAAI,CAAC;AACd"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { FeishuMcpServerDef } from "@wener/ai/mcp/feishu";
|
|
2
|
+
import { HeaderNames } from "../../server/schema.js";
|
|
3
|
+
import { defineMcpServerHandler, registerMcpServerHandler } from "../McpServerHandlerDef.js";
|
|
4
|
+
export const FeishuMcpServerHandlerDef = defineMcpServerHandler(FeishuMcpServerDef, {
|
|
5
|
+
headerMappings: [
|
|
6
|
+
{
|
|
7
|
+
header: HeaderNames.FEISHU_APP_ID,
|
|
8
|
+
property: "appId",
|
|
9
|
+
required: true
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
header: HeaderNames.FEISHU_APP_SECRET,
|
|
13
|
+
property: "appSecret",
|
|
14
|
+
required: true
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
header: HeaderNames.FEISHU_DOMAIN,
|
|
18
|
+
property: "domain"
|
|
19
|
+
}
|
|
20
|
+
],
|
|
21
|
+
resolveConfig(config, headers) {
|
|
22
|
+
const appId = config.appId || headers?.get(HeaderNames.FEISHU_APP_ID) || config.headers?.[HeaderNames.FEISHU_APP_ID];
|
|
23
|
+
const appSecret = config.appSecret || headers?.get(HeaderNames.FEISHU_APP_SECRET) || config.headers?.[HeaderNames.FEISHU_APP_SECRET];
|
|
24
|
+
if (!appId || !appSecret)
|
|
25
|
+
return null;
|
|
26
|
+
const domain = config.domain || headers?.get(HeaderNames.FEISHU_DOMAIN) || config.headers?.[HeaderNames.FEISHU_DOMAIN] || "feishu";
|
|
27
|
+
return {
|
|
28
|
+
appId,
|
|
29
|
+
appSecret,
|
|
30
|
+
domain
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
registerMcpServerHandler(FeishuMcpServerHandlerDef);
|
|
35
|
+
//# sourceMappingURL=def.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/providers/feishu/def.ts"],"sourcesContent":["import { FeishuMcpServerDef, type CreateFeishuMcpServerOptions } from '@wener/ai/mcp/feishu';\nimport { HeaderNames, type FeishuConfig } from '../../server/schema';\nimport { defineMcpServerHandler, registerMcpServerHandler } from '../McpServerHandlerDef';\n\nexport const FeishuMcpServerHandlerDef = defineMcpServerHandler<CreateFeishuMcpServerOptions, FeishuConfig>(\n\tFeishuMcpServerDef,\n\t{\n\t\theaderMappings: [\n\t\t\t{ header: HeaderNames.FEISHU_APP_ID, property: 'appId', required: true },\n\t\t\t{ header: HeaderNames.FEISHU_APP_SECRET, property: 'appSecret', required: true },\n\t\t\t{ header: HeaderNames.FEISHU_DOMAIN, property: 'domain' },\n\t\t],\n\n\t\tresolveConfig(config, headers) {\n\t\t\tconst appId =\n\t\t\t\tconfig.appId ||\n\t\t\t\theaders?.get(HeaderNames.FEISHU_APP_ID) ||\n\t\t\t\tconfig.headers?.[HeaderNames.FEISHU_APP_ID];\n\t\t\tconst appSecret =\n\t\t\t\tconfig.appSecret ||\n\t\t\t\theaders?.get(HeaderNames.FEISHU_APP_SECRET) ||\n\t\t\t\tconfig.headers?.[HeaderNames.FEISHU_APP_SECRET];\n\n\t\t\tif (!appId || !appSecret) return null;\n\n\t\t\tconst domain =\n\t\t\t\tconfig.domain ||\n\t\t\t\theaders?.get(HeaderNames.FEISHU_DOMAIN) ||\n\t\t\t\tconfig.headers?.[HeaderNames.FEISHU_DOMAIN] ||\n\t\t\t\t'feishu';\n\n\t\t\treturn { appId, appSecret, domain };\n\t\t},\n\t},\n);\n\nregisterMcpServerHandler(FeishuMcpServerHandlerDef);\n"],"names":["FeishuMcpServerDef","HeaderNames","defineMcpServerHandler","registerMcpServerHandler","FeishuMcpServerHandlerDef","headerMappings","header","FEISHU_APP_ID","property","required","FEISHU_APP_SECRET","FEISHU_DOMAIN","resolveConfig","config","headers","appId","get","appSecret","domain"],"mappings":"AAAA,SAASA,kBAAkB,QAA2C,uBAAuB;AAC7F,SAASC,WAAW,QAA2B,sBAAsB;AACrE,SAASC,sBAAsB,EAAEC,wBAAwB,QAAQ,yBAAyB;AAE1F,OAAO,MAAMC,4BAA4BF,uBACxCF,oBACA;IACCK,gBAAgB;QACf;YAAEC,QAAQL,YAAYM,aAAa;YAAEC,UAAU;YAASC,UAAU;QAAK;QACvE;YAAEH,QAAQL,YAAYS,iBAAiB;YAAEF,UAAU;YAAaC,UAAU;QAAK;QAC/E;YAAEH,QAAQL,YAAYU,aAAa;YAAEH,UAAU;QAAS;KACxD;IAEDI,eAAcC,MAAM,EAAEC,OAAO;QAC5B,MAAMC,QACLF,OAAOE,KAAK,IACZD,SAASE,IAAIf,YAAYM,aAAa,KACtCM,OAAOC,OAAO,EAAE,CAACb,YAAYM,aAAa,CAAC;QAC5C,MAAMU,YACLJ,OAAOI,SAAS,IAChBH,SAASE,IAAIf,YAAYS,iBAAiB,KAC1CG,OAAOC,OAAO,EAAE,CAACb,YAAYS,iBAAiB,CAAC;QAEhD,IAAI,CAACK,SAAS,CAACE,WAAW,OAAO;QAEjC,MAAMC,SACLL,OAAOK,MAAM,IACbJ,SAASE,IAAIf,YAAYU,aAAa,KACtCE,OAAOC,OAAO,EAAE,CAACb,YAAYU,aAAa,CAAC,IAC3C;QAED,OAAO;YAAEI;YAAOE;YAAWC;QAAO;IACnC;AACD,GACC;AAEFf,yBAAyBC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/providers/findMcpServerDef.ts"],"sourcesContent":["import { getAllMcpServerHandlerDefs, type McpServerHandlerDef } from './McpServerHandlerDef';\n// Import all server definitions to ensure they are registered\nimport './prometheus/def';\nimport './tencent-cls/def';\nimport './sql/def';\nimport './relay/def';\n\n/**\n * Find MCP server definitions matching a predicate\n */\nexport function findMcpServerDef(predicate?: (def: McpServerHandlerDef) => boolean): McpServerHandlerDef[] {\n\tconst all = getAllMcpServerHandlerDefs();\n\tif (!predicate) {\n\t\treturn all;\n\t}\n\treturn all.filter(predicate);\n}\n\n/**\n * Resolve a single MCP server definition by name\n */\nexport function resolveMcpServerDef(name: string): McpServerHandlerDef | undefined {\n\treturn findMcpServerDef((v) => v.name === name)[0];\n}\n\n/**\n * Get total count of registered MCP server types\n */\nexport function getMcpServerDefCount(): number {\n\treturn getAllMcpServerHandlerDefs().length;\n}\n"],"names":["getAllMcpServerHandlerDefs","findMcpServerDef","predicate","all","filter","resolveMcpServerDef","name","v","getMcpServerDefCount","length"],"mappings":"AAAA,SAASA,0BAA0B,QAAkC,wBAAwB;AAC7F,8DAA8D;AAC9D,OAAO,mBAAmB;AAC1B,OAAO,oBAAoB;AAC3B,OAAO,YAAY;AACnB,OAAO,cAAc;
|
|
1
|
+
{"version":3,"sources":["../../src/providers/findMcpServerDef.ts"],"sourcesContent":["import { getAllMcpServerHandlerDefs, type McpServerHandlerDef } from './McpServerHandlerDef';\n// Import all server definitions to ensure they are registered\nimport './prometheus/def';\nimport './tencent-cls/def';\nimport './sql/def';\nimport './relay/def';\nimport './feishu/def';\n\n/**\n * Find MCP server definitions matching a predicate\n */\nexport function findMcpServerDef(predicate?: (def: McpServerHandlerDef) => boolean): McpServerHandlerDef[] {\n\tconst all = getAllMcpServerHandlerDefs();\n\tif (!predicate) {\n\t\treturn all;\n\t}\n\treturn all.filter(predicate);\n}\n\n/**\n * Resolve a single MCP server definition by name\n */\nexport function resolveMcpServerDef(name: string): McpServerHandlerDef | undefined {\n\treturn findMcpServerDef((v) => v.name === name)[0];\n}\n\n/**\n * Get total count of registered MCP server types\n */\nexport function getMcpServerDefCount(): number {\n\treturn getAllMcpServerHandlerDefs().length;\n}\n"],"names":["getAllMcpServerHandlerDefs","findMcpServerDef","predicate","all","filter","resolveMcpServerDef","name","v","getMcpServerDefCount","length"],"mappings":"AAAA,SAASA,0BAA0B,QAAkC,wBAAwB;AAC7F,8DAA8D;AAC9D,OAAO,mBAAmB;AAC1B,OAAO,oBAAoB;AAC3B,OAAO,YAAY;AACnB,OAAO,cAAc;AACrB,OAAO,eAAe;AAEtB;;CAEC,GACD,OAAO,SAASC,iBAAiBC,SAAiD;IACjF,MAAMC,MAAMH;IACZ,IAAI,CAACE,WAAW;QACf,OAAOC;IACR;IACA,OAAOA,IAAIC,MAAM,CAACF;AACnB;AAEA;;CAEC,GACD,OAAO,SAASG,oBAAoBC,IAAY;IAC/C,OAAOL,iBAAiB,CAACM,IAAMA,EAAED,IAAI,KAAKA,KAAK,CAAC,EAAE;AACnD;AAEA;;CAEC,GACD,OAAO,SAASE;IACf,OAAOR,6BAA6BS,MAAM;AAC3C"}
|
package/lib/scripts/bundle.js
CHANGED
|
@@ -40,9 +40,15 @@ const commonOptions = {
|
|
|
40
40
|
// External native modules
|
|
41
41
|
external: [
|
|
42
42
|
'better-sqlite3',
|
|
43
|
+
'bun:sqlite',
|
|
44
|
+
'kysely-bun-sqlite',
|
|
43
45
|
'oracledb',
|
|
44
46
|
'mariadb/callback',
|
|
45
|
-
'mysql'
|
|
47
|
+
'mysql',
|
|
48
|
+
'@nestjs/websockets',
|
|
49
|
+
'@nestjs/microservices',
|
|
50
|
+
'@nestjs/platform-express',
|
|
51
|
+
'@larksuiteoapi/node-sdk'
|
|
46
52
|
]
|
|
47
53
|
};
|
|
48
54
|
// Ensure dist directory exists
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/scripts/bundle.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from 'node:fs';\nimport * as esbuild from 'esbuild';\n\nconst pkg = JSON.parse(fs.readFileSync('package.json', 'utf-8'));\n\nconst banner = `// Bundled with esbuild\n// ${pkg.name}@${pkg.version}\n\nvar require,__filename,__dirname;\n{\n const {createRequire} = await import('node:module');\n require ||= createRequire(import.meta.url);\n}\n{\n const {fileURLToPath} = await import('node:url');\n const {dirname} = await import('node:path');\n __filename ||= fileURLToPath(import.meta.url);\n __dirname ||= dirname(__filename)\n};\n`;\n\nconst commonOptions: esbuild.BuildOptions = {\n\tbundle: true,\n\tlogLevel: 'info',\n\tbanner: { js: banner },\n\tdefine: {\n\t\tNODE_ENV: JSON.stringify('production'),\n\t\t__DEV__: JSON.stringify(false),\n\t\t'process.env.NODE_ENV': JSON.stringify('production'),\n\t},\n\tkeepNames: true,\n\ttreeShaking: true,\n\tminifySyntax: true,\n\tformat: 'esm',\n\tplatform: 'node',\n\tcharset: 'utf8',\n\ttarget: 'node18',\n\tsourcemap: false,\n\tlegalComments: 'none',\n\t// External native modules\n\texternal: ['better-sqlite3'
|
|
1
|
+
{"version":3,"sources":["../../src/scripts/bundle.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from 'node:fs';\nimport * as esbuild from 'esbuild';\n\nconst pkg = JSON.parse(fs.readFileSync('package.json', 'utf-8'));\n\nconst banner = `// Bundled with esbuild\n// ${pkg.name}@${pkg.version}\n\nvar require,__filename,__dirname;\n{\n const {createRequire} = await import('node:module');\n require ||= createRequire(import.meta.url);\n}\n{\n const {fileURLToPath} = await import('node:url');\n const {dirname} = await import('node:path');\n __filename ||= fileURLToPath(import.meta.url);\n __dirname ||= dirname(__filename)\n};\n`;\n\nconst commonOptions: esbuild.BuildOptions = {\n\tbundle: true,\n\tlogLevel: 'info',\n\tbanner: { js: banner },\n\tdefine: {\n\t\tNODE_ENV: JSON.stringify('production'),\n\t\t__DEV__: JSON.stringify(false),\n\t\t'process.env.NODE_ENV': JSON.stringify('production'),\n\t},\n\tkeepNames: true,\n\ttreeShaking: true,\n\tminifySyntax: true,\n\tformat: 'esm',\n\tplatform: 'node',\n\tcharset: 'utf8',\n\ttarget: 'node18',\n\tsourcemap: false,\n\tlegalComments: 'none',\n\t// External native modules\n\texternal: [\n\t\t'better-sqlite3',\n\t\t'bun:sqlite',\n\t\t'kysely-bun-sqlite',\n\t\t'oracledb',\n\t\t'mariadb/callback',\n\t\t'mysql',\n\t\t'@nestjs/websockets',\n\t\t'@nestjs/microservices',\n\t\t'@nestjs/platform-express',\n\t\t'@larksuiteoapi/node-sdk',\n\t],\n};\n\n// Ensure dist directory exists\nfs.mkdirSync('dist', { recursive: true });\n\nconsole.log('Building MCPS...');\n\n// Build library entry (index.ts)\nconst libResult = await esbuild.build({\n\t...commonOptions,\n\tentryPoints: ['src/index.ts'],\n\toutfile: 'dist/index.mjs',\n});\n\n// Build CLI entry (mcps-cli.ts)\nconst cliResult = await esbuild.build({\n\t...commonOptions,\n\tentryPoints: ['src/mcps-cli.ts'],\n\toutfile: 'dist/mcps-cli.mjs',\n});\n\nif (libResult.errors.length === 0 && cliResult.errors.length === 0) {\n\t// Process CLI output - add shebang\n\tconst cliOutfile = 'dist/mcps-cli.mjs';\n\tlet content = fs.readFileSync(cliOutfile, 'utf-8');\n\tcontent = content.replace(/^#!.*\\n/gm, '');\n\tfs.writeFileSync(cliOutfile, `#!/usr/bin/env node\\n${content}`);\n\tfs.chmodSync(cliOutfile, 0o755);\n\n\tconst libStats = fs.statSync('dist/index.mjs');\n\tconst cliStats = fs.statSync(cliOutfile);\n\n\tconsole.log(`✅ Build successful!`);\n\tconsole.log(`📦 Library: dist/index.mjs (${(libStats.size / 1024).toFixed(1)}KB)`);\n\tconsole.log(`📦 CLI: ${cliOutfile} (${(cliStats.size / 1024).toFixed(1)}KB)`);\n\tconsole.log(`🚀 Ready for npm publish and npx usage`);\n} else {\n\tconsole.error('❌ Build failed:', [...libResult.errors, ...cliResult.errors]);\n\tprocess.exit(1);\n}\n"],"names":["fs","esbuild","pkg","JSON","parse","readFileSync","banner","name","version","commonOptions","bundle","logLevel","js","define","NODE_ENV","stringify","__DEV__","keepNames","treeShaking","minifySyntax","format","platform","charset","target","sourcemap","legalComments","external","mkdirSync","recursive","console","log","libResult","build","entryPoints","outfile","cliResult","errors","length","cliOutfile","content","replace","writeFileSync","chmodSync","libStats","statSync","cliStats","size","toFixed","error","process","exit"],"mappings":";AACA,OAAOA,QAAQ,UAAU;AACzB,YAAYC,aAAa,UAAU;AAEnC,MAAMC,MAAMC,KAAKC,KAAK,CAACJ,GAAGK,YAAY,CAAC,gBAAgB;AAEvD,MAAMC,SAAS,CAAC;GACb,EAAEJ,IAAIK,IAAI,CAAC,CAAC,EAAEL,IAAIM,OAAO,CAAC;;;;;;;;;;;;;AAa7B,CAAC;AAED,MAAMC,gBAAsC;IAC3CC,QAAQ;IACRC,UAAU;IACVL,QAAQ;QAAEM,IAAIN;IAAO;IACrBO,QAAQ;QACPC,UAAUX,KAAKY,SAAS,CAAC;QACzBC,SAASb,KAAKY,SAAS,CAAC;QACxB,wBAAwBZ,KAAKY,SAAS,CAAC;IACxC;IACAE,WAAW;IACXC,aAAa;IACbC,cAAc;IACdC,QAAQ;IACRC,UAAU;IACVC,SAAS;IACTC,QAAQ;IACRC,WAAW;IACXC,eAAe;IACf,0BAA0B;IAC1BC,UAAU;QACT;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;QACA;KACA;AACF;AAEA,+BAA+B;AAC/B1B,GAAG2B,SAAS,CAAC,QAAQ;IAAEC,WAAW;AAAK;AAEvCC,QAAQC,GAAG,CAAC;AAEZ,iCAAiC;AACjC,MAAMC,YAAY,MAAM9B,QAAQ+B,KAAK,CAAC;IACrC,GAAGvB,aAAa;IAChBwB,aAAa;QAAC;KAAe;IAC7BC,SAAS;AACV;AAEA,gCAAgC;AAChC,MAAMC,YAAY,MAAMlC,QAAQ+B,KAAK,CAAC;IACrC,GAAGvB,aAAa;IAChBwB,aAAa;QAAC;KAAkB;IAChCC,SAAS;AACV;AAEA,IAAIH,UAAUK,MAAM,CAACC,MAAM,KAAK,KAAKF,UAAUC,MAAM,CAACC,MAAM,KAAK,GAAG;IACnE,mCAAmC;IACnC,MAAMC,aAAa;IACnB,IAAIC,UAAUvC,GAAGK,YAAY,CAACiC,YAAY;IAC1CC,UAAUA,QAAQC,OAAO,CAAC,aAAa;IACvCxC,GAAGyC,aAAa,CAACH,YAAY,CAAC,qBAAqB,EAAEC,SAAS;IAC9DvC,GAAG0C,SAAS,CAACJ,YAAY;IAEzB,MAAMK,WAAW3C,GAAG4C,QAAQ,CAAC;IAC7B,MAAMC,WAAW7C,GAAG4C,QAAQ,CAACN;IAE7BT,QAAQC,GAAG,CAAC,CAAC,mBAAmB,CAAC;IACjCD,QAAQC,GAAG,CAAC,CAAC,4BAA4B,EAAE,AAACa,CAAAA,SAASG,IAAI,GAAG,IAAG,EAAGC,OAAO,CAAC,GAAG,GAAG,CAAC;IACjFlB,QAAQC,GAAG,CAAC,CAAC,QAAQ,EAAEQ,WAAW,EAAE,EAAE,AAACO,CAAAA,SAASC,IAAI,GAAG,IAAG,EAAGC,OAAO,CAAC,GAAG,GAAG,CAAC;IAC5ElB,QAAQC,GAAG,CAAC,CAAC,sCAAsC,CAAC;AACrD,OAAO;IACND,QAAQmB,KAAK,CAAC,mBAAmB;WAAIjB,UAAUK,MAAM;WAAKD,UAAUC,MAAM;KAAC;IAC3Ea,QAAQC,IAAI,CAAC;AACd"}
|
package/lib/server/api-routes.js
CHANGED
|
@@ -5,19 +5,18 @@ import { RPCHandler } from "@orpc/server/fetch";
|
|
|
5
5
|
import { CORSPlugin } from "@orpc/server/plugins";
|
|
6
6
|
import { ZodToJsonSchemaConverter } from "@orpc/zod/zod4";
|
|
7
7
|
import { html } from "hono/html";
|
|
8
|
-
import { AuditRouter } from "./audit.js";
|
|
9
8
|
import { createMcpsRouter } from "./mcps-router.js";
|
|
10
9
|
/**
|
|
11
|
-
* Register oRPC API routes for
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
* Register oRPC API routes for MCPS.
|
|
11
|
+
* Audit router is not included by default - use setupAudit() plugin to add it.
|
|
12
|
+
*/ export function registerApiRoutes({ app, config, apiRouters, statsProvider }) {
|
|
14
13
|
const McpsRouter = createMcpsRouter({
|
|
15
|
-
config
|
|
14
|
+
config,
|
|
15
|
+
statsProvider
|
|
16
16
|
});
|
|
17
|
-
// Combined router for all APIs
|
|
18
17
|
const combinedRouter = {
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
mcps: McpsRouter,
|
|
19
|
+
...apiRouters
|
|
21
20
|
};
|
|
22
21
|
const handleByRpc = new RPCHandler(combinedRouter);
|
|
23
22
|
const handleByOpenAPI = new OpenAPIHandler(combinedRouter, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/server/api-routes.ts"],"sourcesContent":["import { SmartCoercionPlugin } from '@orpc/json-schema';\nimport { OpenAPIGenerator } from '@orpc/openapi';\nimport { OpenAPIHandler } from '@orpc/openapi/fetch';\nimport { RPCHandler } from '@orpc/server/fetch';\nimport { CORSPlugin } from '@orpc/server/plugins';\nimport { ZodToJsonSchemaConverter } from '@orpc/zod/zod4';\nimport type { Hono } from 'hono';\nimport { html } from 'hono/html';\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/server/api-routes.ts"],"sourcesContent":["import { SmartCoercionPlugin } from '@orpc/json-schema';\nimport { OpenAPIGenerator } from '@orpc/openapi';\nimport { OpenAPIHandler } from '@orpc/openapi/fetch';\nimport { RPCHandler } from '@orpc/server/fetch';\nimport { CORSPlugin } from '@orpc/server/plugins';\nimport { ZodToJsonSchemaConverter } from '@orpc/zod/zod4';\nimport type { Hono } from 'hono';\nimport { html } from 'hono/html';\nimport { createMcpsRouter } from './mcps-router';\nimport type { McpsConfig } from './schema';\nimport type { StatsProvider } from './server';\n\nexport interface RegisterApiRoutesOptions {\n\tapp: Hono;\n\tconfig: McpsConfig;\n\t/** Additional oRPC routers registered by plugins (e.g. audit) */\n\tapiRouters?: Record<string, any>;\n\t/** Optional stats provider from audit plugin */\n\tstatsProvider?: StatsProvider;\n}\n\n/**\n * Register oRPC API routes for MCPS.\n * Audit router is not included by default - use setupAudit() plugin to add it.\n */\nexport function registerApiRoutes({ app, config, apiRouters, statsProvider }: RegisterApiRoutesOptions) {\n\tconst McpsRouter = createMcpsRouter({ config, statsProvider });\n\n\tconst combinedRouter: Record<string, any> = {\n\t\tmcps: McpsRouter,\n\t\t...apiRouters,\n\t};\n\n\tconst handleByRpc = new RPCHandler(combinedRouter);\n\tconst handleByOpenAPI = new OpenAPIHandler(combinedRouter, {\n\t\tplugins: [\n\t\t\tnew SmartCoercionPlugin({\n\t\t\t\tschemaConverters: [new ZodToJsonSchemaConverter()],\n\t\t\t}),\n\t\t\tnew CORSPlugin({\n\t\t\t\texposeHeaders: ['Content-Disposition'],\n\t\t\t}),\n\t\t],\n\t});\n\n\tapp.use('/api/rpc/*', async (c, next) => {\n\t\tconst { matched, response } = await handleByRpc.handle(c.req.raw, {\n\t\t\tprefix: '/api/rpc',\n\t\t\tcontext: {},\n\t\t});\n\t\tif (matched) {\n\t\t\treturn c.newResponse(response.body, response);\n\t\t}\n\t\treturn next();\n\t});\n\n\tapp.use('/api/*', async (c, next) => {\n\t\tconst { matched, response } = await handleByOpenAPI.handle(c.req.raw, {\n\t\t\tprefix: '/api',\n\t\t\tcontext: {},\n\t\t});\n\t\tif (matched) {\n\t\t\treturn c.newResponse(response.body, response);\n\t\t}\n\t\treturn next();\n\t});\n\n\t// OpenAPI spec\n\tconst openAPIGenerator = new OpenAPIGenerator({\n\t\tschemaConverters: [new ZodToJsonSchemaConverter()],\n\t});\n\tlet specCache: unknown;\n\n\tapp.get('/api/spec.json', async (c) => {\n\t\tif (!specCache) {\n\t\t\tspecCache = await openAPIGenerator.generate(combinedRouter, {\n\t\t\t\tinfo: { title: 'MCPS API', version: '1.0.0' },\n\t\t\t\tservers: [{ url: '/api' }],\n\t\t\t});\n\t\t}\n\t\treturn c.json(specCache);\n\t});\n\n\t// Swagger UI\n\tapp.get('/api/docs', (c) => {\n\t\treturn c.html(\n\t\t\thtml`<!doctype html>\n\t\t\t\t<html lang=\"en\">\n\t\t\t\t\t<head>\n\t\t\t\t\t\t<title>MCPS API</title>\n\t\t\t\t\t\t<meta charset=\"utf-8\" />\n\t\t\t\t\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n\t\t\t\t\t</head>\n\t\t\t\t\t<body>\n\t\t\t\t\t\t<script id=\"api-reference\" data-url=\"/api/spec.json\"></script>\n\t\t\t\t\t\t<script src=\"https://cdn.jsdelivr.net/npm/@scalar/api-reference\"></script>\n\t\t\t\t\t</body>\n\t\t\t\t</html>`,\n\t\t);\n\t});\n}\n"],"names":["SmartCoercionPlugin","OpenAPIGenerator","OpenAPIHandler","RPCHandler","CORSPlugin","ZodToJsonSchemaConverter","html","createMcpsRouter","registerApiRoutes","app","config","apiRouters","statsProvider","McpsRouter","combinedRouter","mcps","handleByRpc","handleByOpenAPI","plugins","schemaConverters","exposeHeaders","use","c","next","matched","response","handle","req","raw","prefix","context","newResponse","body","openAPIGenerator","specCache","get","generate","info","title","version","servers","url","json"],"mappings":"AAAA,SAASA,mBAAmB,QAAQ,oBAAoB;AACxD,SAASC,gBAAgB,QAAQ,gBAAgB;AACjD,SAASC,cAAc,QAAQ,sBAAsB;AACrD,SAASC,UAAU,QAAQ,qBAAqB;AAChD,SAASC,UAAU,QAAQ,uBAAuB;AAClD,SAASC,wBAAwB,QAAQ,iBAAiB;AAE1D,SAASC,IAAI,QAAQ,YAAY;AACjC,SAASC,gBAAgB,QAAQ,gBAAgB;AAajD;;;CAGC,GACD,OAAO,SAASC,kBAAkB,EAAEC,GAAG,EAAEC,MAAM,EAAEC,UAAU,EAAEC,aAAa,EAA4B;IACrG,MAAMC,aAAaN,iBAAiB;QAAEG;QAAQE;IAAc;IAE5D,MAAME,iBAAsC;QAC3CC,MAAMF;QACN,GAAGF,UAAU;IACd;IAEA,MAAMK,cAAc,IAAIb,WAAWW;IACnC,MAAMG,kBAAkB,IAAIf,eAAeY,gBAAgB;QAC1DI,SAAS;YACR,IAAIlB,oBAAoB;gBACvBmB,kBAAkB;oBAAC,IAAId;iBAA2B;YACnD;YACA,IAAID,WAAW;gBACdgB,eAAe;oBAAC;iBAAsB;YACvC;SACA;IACF;IAEAX,IAAIY,GAAG,CAAC,cAAc,OAAOC,GAAGC;QAC/B,MAAM,EAAEC,OAAO,EAAEC,QAAQ,EAAE,GAAG,MAAMT,YAAYU,MAAM,CAACJ,EAAEK,GAAG,CAACC,GAAG,EAAE;YACjEC,QAAQ;YACRC,SAAS,CAAC;QACX;QACA,IAAIN,SAAS;YACZ,OAAOF,EAAES,WAAW,CAACN,SAASO,IAAI,EAAEP;QACrC;QACA,OAAOF;IACR;IAEAd,IAAIY,GAAG,CAAC,UAAU,OAAOC,GAAGC;QAC3B,MAAM,EAAEC,OAAO,EAAEC,QAAQ,EAAE,GAAG,MAAMR,gBAAgBS,MAAM,CAACJ,EAAEK,GAAG,CAACC,GAAG,EAAE;YACrEC,QAAQ;YACRC,SAAS,CAAC;QACX;QACA,IAAIN,SAAS;YACZ,OAAOF,EAAES,WAAW,CAACN,SAASO,IAAI,EAAEP;QACrC;QACA,OAAOF;IACR;IAEA,eAAe;IACf,MAAMU,mBAAmB,IAAIhC,iBAAiB;QAC7CkB,kBAAkB;YAAC,IAAId;SAA2B;IACnD;IACA,IAAI6B;IAEJzB,IAAI0B,GAAG,CAAC,kBAAkB,OAAOb;QAChC,IAAI,CAACY,WAAW;YACfA,YAAY,MAAMD,iBAAiBG,QAAQ,CAACtB,gBAAgB;gBAC3DuB,MAAM;oBAAEC,OAAO;oBAAYC,SAAS;gBAAQ;gBAC5CC,SAAS;oBAAC;wBAAEC,KAAK;oBAAO;iBAAE;YAC3B;QACD;QACA,OAAOnB,EAAEoB,IAAI,CAACR;IACf;IAEA,aAAa;IACbzB,IAAI0B,GAAG,CAAC,aAAa,CAACb;QACrB,OAAOA,EAAEhB,IAAI,CACZA,IAAI,CAAC;;;;;;;;;;;WAWG,CAAC;IAEX;AACD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/server/events.ts"],"sourcesContent":["import Emittery from 'emittery';\n\nexport const McpsEventType = {\n\tRequest: 'Mcps:Request',\n} as const;\n\nexport type McpsRequestEvent = {\n\ttimestamp: string;\n\tmethod: string;\n\tpath: string;\n\tserverName?: string;\n\tserverType?: string;\n\tstatus?: number;\n\tdurationMs?: number;\n\terror?: string;\n\trequestHeaders?: Record<string, string>;\n};\n\nexport type McpsEventData = {\n\t[McpsEventType.Request]: McpsRequestEvent;\n};\n\nexport type McpsEmitter = Emittery<McpsEventData>;\n\nexport function createMcpsEmitter(): McpsEmitter {\n\treturn new Emittery<McpsEventData>({\n\t\tdebug: { name: 'McpsEmitter' },\n\t});\n}\n"],"names":["Emittery","McpsEventType","Request","createMcpsEmitter","debug","name"],"mappings":"AAAA,OAAOA,cAAc,WAAW;AAEhC,OAAO,MAAMC,gBAAgB;IAC5BC,SAAS;AACV,EAAW;AAoBX,OAAO,SAASC;IACf,OAAO,IAAIH,SAAwB;QAClCI,OAAO;YAAEC,MAAM;QAAc;IAC9B;AACD"}
|
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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"}
|