apcore-mcp 0.4.0 → 0.5.0
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/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +9 -0
- package/dist/cli.js.map +1 -1
- package/dist/explorer/handler.d.ts +55 -0
- package/dist/explorer/handler.d.ts.map +1 -0
- package/dist/explorer/handler.js +175 -0
- package/dist/explorer/handler.js.map +1 -0
- package/dist/explorer/html.d.ts +9 -0
- package/dist/explorer/html.d.ts.map +1 -0
- package/dist/explorer/html.js +238 -0
- package/dist/explorer/html.js.map +1 -0
- package/dist/explorer/index.d.ts +6 -0
- package/dist/explorer/index.d.ts.map +1 -0
- package/dist/explorer/index.js +5 -0
- package/dist/explorer/index.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -1
- package/dist/index.js.map +1 -1
- package/dist/server/transport.d.ts +18 -1
- package/dist/server/transport.d.ts.map +1 -1
- package/dist/server/transport.js +41 -1
- package/dist/server/transport.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG;AAoCH,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAkH1C"}
|
package/dist/cli.js
CHANGED
|
@@ -28,6 +28,9 @@ Options:
|
|
|
28
28
|
--name <string> MCP server name (default: apcore-mcp, max 255 chars)
|
|
29
29
|
--version <string> MCP server version (default: package version)
|
|
30
30
|
--log-level <level> Logging level: DEBUG, INFO, WARNING, ERROR (default: INFO)
|
|
31
|
+
--explorer Enable the browser-based Tool Explorer UI (HTTP only)
|
|
32
|
+
--explorer-prefix <path> URL prefix for the explorer UI (default: /explorer)
|
|
33
|
+
--allow-execute Allow tool execution from the explorer UI
|
|
31
34
|
--help Show this help message
|
|
32
35
|
`);
|
|
33
36
|
}
|
|
@@ -47,6 +50,9 @@ export async function main() {
|
|
|
47
50
|
name: { type: "string", default: "apcore-mcp" },
|
|
48
51
|
version: { type: "string" },
|
|
49
52
|
"log-level": { type: "string", default: "INFO" },
|
|
53
|
+
explorer: { type: "boolean", default: false },
|
|
54
|
+
"explorer-prefix": { type: "string", default: "/explorer" },
|
|
55
|
+
"allow-execute": { type: "boolean", default: false },
|
|
50
56
|
help: { type: "boolean", default: false },
|
|
51
57
|
},
|
|
52
58
|
strict: true,
|
|
@@ -123,6 +129,9 @@ export async function main() {
|
|
|
123
129
|
name,
|
|
124
130
|
version: values.version ?? undefined,
|
|
125
131
|
logLevel: logLevel,
|
|
132
|
+
explorer: values.explorer,
|
|
133
|
+
explorerPrefix: values["explorer-prefix"],
|
|
134
|
+
allowExecute: values["allow-execute"],
|
|
126
135
|
});
|
|
127
136
|
}
|
|
128
137
|
catch (error) {
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5C,SAAS,UAAU;IACjB,OAAO,CAAC,GAAG,CAAC;cACA,OAAO
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5C,SAAS,UAAU;IACjB,OAAO,CAAC,GAAG,CAAC;cACA,OAAO;;;;;;;;;;;;;;;;;;;CAmBpB,CAAC,CAAC;AACH,CAAC;AAED,SAAS,IAAI,CAAC,OAAe,EAAE,WAAmB,CAAC;IACjD,OAAO,CAAC,KAAK,CAAC,UAAU,OAAO,EAAE,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,IAAI;IACxB,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,MAAM,GAAG,SAAS,CAAC;YACjB,OAAO,EAAE;gBACP,gBAAgB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACpC,SAAS,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE;gBAC/C,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE;gBAC9C,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE;gBACzC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE;gBAC/C,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC3B,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE;gBAChD,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;gBAC7C,iBAAiB,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,WAAW,EAAE;gBAC3D,eAAe,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;gBACpD,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;aAC1C;YACD,MAAM,EAAE,IAAI;SACb,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,UAAU,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC;IAE1B,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAChB,UAAU,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,4BAA4B;IAC5B,MAAM,aAAa,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAAC;IAC/C,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,IAAI,CAAC,+BAA+B,CAAC,CAAC;IACxC,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC3C,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,IAAI,CAAC,qBAAqB,aAAa,mBAAmB,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QACzC,IAAI,CAAC,qBAAqB,aAAa,uBAAuB,CAAC,CAAC;IAClE,CAAC;IAED,qBAAqB;IACrB,MAAM,SAAS,GAAG,MAAM,CAAC,SAAmB,CAAC;IAC7C,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,iBAAiB,EAAE,KAAK,CAAC,CAAC;IAC5D,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACzC,IAAI,CACF,+BAA+B,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,SAAS,IAAI,CACjF,CAAC;IACJ,CAAC;IAED,gBAAgB;IAChB,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,IAAc,EAAE,EAAE,CAAC,CAAC;IACjD,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QAC5C,IAAI,CAAC,yCAAyC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC;IACjE,CAAC;IAED,uBAAuB;IACvB,MAAM,IAAI,GAAG,MAAM,CAAC,IAAc,CAAC;IACnC,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC,8CAA8C,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;IACrE,CAAC;IAED,sDAAsD;IACtD,8DAA8D;IAC9D,IAAI,QAAqF,CAAC;IAC1F,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QACzC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,CACF,8EAA8E,CAC/E,CAAC;IACJ,CAAC;IAED,uCAAuC;IACvC,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,EAAE,aAAa,EAAE,WAAW,EAAE,CAAC,CAAC;IAC9D,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,CAAC;IAE7C,IAAI,UAAU,KAAK,CAAC,EAAE,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,sCAAsC,aAAa,IAAI,CAAC,CAAC;IACxE,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,IAAI,CAAC,cAAc,UAAU,kBAAkB,aAAa,IAAI,CAAC,CAAC;IAC5E,CAAC;IAED,qBAAqB;IACrB,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CAAuB,CAAC;IAC3D,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IAC7D,IAAI,QAAQ,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;QACnD,IAAI,CACF,+BAA+B,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,QAAQ,IAAI,CAC/E,CAAC;IACJ,CAAC;IAED,wBAAwB;IACxB,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,QAAiB,EAAE;YAC7B,SAAS,EAAE,SAAgD;YAC3D,IAAI,EAAE,MAAM,CAAC,IAAc;YAC3B,IAAI;YACJ,IAAI;YACJ,OAAO,EAAE,MAAM,CAAC,OAAO,IAAI,SAAS;YACpC,QAAQ,EAAE,QAA8D;YACxE,QAAQ,EAAE,MAAM,CAAC,QAAmB;YACpC,cAAc,EAAE,MAAM,CAAC,iBAAiB,CAAW;YACnD,YAAY,EAAE,MAAM,CAAC,eAAe,CAAY;SACjD,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;QAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;IACrB,OAAO,CAAC,KAAK,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;IAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExplorerHandler - HTTP route handler for the MCP Tool Explorer.
|
|
3
|
+
*
|
|
4
|
+
* Provides a browser-based UI for inspecting and testing MCP tools.
|
|
5
|
+
* Handles explorer-prefixed HTTP routes within the existing HTTP server.
|
|
6
|
+
*
|
|
7
|
+
* Routes:
|
|
8
|
+
* - GET {prefix}/ → HTML explorer page
|
|
9
|
+
* - GET {prefix}/tools → JSON array of tool summaries
|
|
10
|
+
* - GET {prefix}/tools/{name} → JSON tool detail
|
|
11
|
+
* - POST {prefix}/tools/{name}/call → Execute tool (403 if disabled)
|
|
12
|
+
*/
|
|
13
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
14
|
+
import type { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
15
|
+
import type { ExecutionRouter } from "../server/router.js";
|
|
16
|
+
/** Options for creating an ExplorerHandler. */
|
|
17
|
+
export interface ExplorerHandlerOptions {
|
|
18
|
+
/** Whether to allow tool execution from the explorer UI. Default: false */
|
|
19
|
+
allowExecute?: boolean;
|
|
20
|
+
/** URL prefix for the explorer. Default: "/explorer" */
|
|
21
|
+
prefix?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare class ExplorerHandler {
|
|
24
|
+
private readonly _toolsByName;
|
|
25
|
+
private readonly _tools;
|
|
26
|
+
private readonly _router;
|
|
27
|
+
private readonly _allowExecute;
|
|
28
|
+
private readonly _prefix;
|
|
29
|
+
constructor(tools: Tool[], router: ExecutionRouter, options?: ExplorerHandlerOptions);
|
|
30
|
+
/** The URL prefix this handler is mounted at. */
|
|
31
|
+
get prefix(): string;
|
|
32
|
+
/**
|
|
33
|
+
* Attempt to handle an HTTP request.
|
|
34
|
+
*
|
|
35
|
+
* @returns true if the request was handled, false if it should be passed through
|
|
36
|
+
*/
|
|
37
|
+
handleRequest(req: IncomingMessage, res: ServerResponse, url: URL): Promise<boolean>;
|
|
38
|
+
/**
|
|
39
|
+
* Build a summary dict for a tool (used in the list endpoint).
|
|
40
|
+
*/
|
|
41
|
+
private _toolSummary;
|
|
42
|
+
/**
|
|
43
|
+
* Build a full detail dict for a tool (used in the detail endpoint).
|
|
44
|
+
*/
|
|
45
|
+
private _toolDetail;
|
|
46
|
+
/**
|
|
47
|
+
* Handle GET {prefix}/tools/{name} - return tool detail or 404.
|
|
48
|
+
*/
|
|
49
|
+
private _handleToolDetail;
|
|
50
|
+
/**
|
|
51
|
+
* Handle POST {prefix}/tools/{name}/call - execute tool or return 403/404.
|
|
52
|
+
*/
|
|
53
|
+
private _handleCallTool;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/explorer/handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAC/D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAI3D,+CAA+C;AAC/C,MAAM,WAAW,sBAAsB;IACrC,2EAA2E;IAC3E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,wDAAwD;IACxD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAKD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAkB;IAC1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAG/B,KAAK,EAAE,IAAI,EAAE,EACb,MAAM,EAAE,eAAe,EACvB,OAAO,CAAC,EAAE,sBAAsB;IASlC,iDAAiD;IACjD,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED;;;;OAIG;IACG,aAAa,CACjB,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,GAAG,EAAE,GAAG,GACP,OAAO,CAAC,OAAO,CAAC;IA6CnB;;OAEG;IACH,OAAO,CAAC,YAAY;IAWpB;;OAEG;IACH,OAAO,CAAC,WAAW;IAYnB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAWzB;;OAEG;YACW,eAAe;CAqE9B"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExplorerHandler - HTTP route handler for the MCP Tool Explorer.
|
|
3
|
+
*
|
|
4
|
+
* Provides a browser-based UI for inspecting and testing MCP tools.
|
|
5
|
+
* Handles explorer-prefixed HTTP routes within the existing HTTP server.
|
|
6
|
+
*
|
|
7
|
+
* Routes:
|
|
8
|
+
* - GET {prefix}/ → HTML explorer page
|
|
9
|
+
* - GET {prefix}/tools → JSON array of tool summaries
|
|
10
|
+
* - GET {prefix}/tools/{name} → JSON tool detail
|
|
11
|
+
* - POST {prefix}/tools/{name}/call → Execute tool (403 if disabled)
|
|
12
|
+
*/
|
|
13
|
+
import { readBody } from "../server/transport.js";
|
|
14
|
+
import { EXPLORER_HTML } from "./html.js";
|
|
15
|
+
/** Maximum request body size for explorer call endpoint (1MB). */
|
|
16
|
+
const EXPLORER_MAX_BODY_BYTES = 1024 * 1024;
|
|
17
|
+
export class ExplorerHandler {
|
|
18
|
+
_toolsByName;
|
|
19
|
+
_tools;
|
|
20
|
+
_router;
|
|
21
|
+
_allowExecute;
|
|
22
|
+
_prefix;
|
|
23
|
+
constructor(tools, router, options) {
|
|
24
|
+
this._tools = tools;
|
|
25
|
+
this._router = router;
|
|
26
|
+
this._allowExecute = options?.allowExecute ?? false;
|
|
27
|
+
this._prefix = options?.prefix ?? "/explorer";
|
|
28
|
+
this._toolsByName = new Map(tools.map((t) => [t.name, t]));
|
|
29
|
+
}
|
|
30
|
+
/** The URL prefix this handler is mounted at. */
|
|
31
|
+
get prefix() {
|
|
32
|
+
return this._prefix;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Attempt to handle an HTTP request.
|
|
36
|
+
*
|
|
37
|
+
* @returns true if the request was handled, false if it should be passed through
|
|
38
|
+
*/
|
|
39
|
+
async handleRequest(req, res, url) {
|
|
40
|
+
const pathname = url.pathname;
|
|
41
|
+
// Normalize: strip trailing slash for matching (except root)
|
|
42
|
+
const prefixSlash = this._prefix + "/";
|
|
43
|
+
// GET {prefix}/ → HTML page
|
|
44
|
+
if (req.method === "GET" &&
|
|
45
|
+
(pathname === this._prefix || pathname === prefixSlash)) {
|
|
46
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
47
|
+
res.end(EXPLORER_HTML);
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
// GET {prefix}/tools → list all tools
|
|
51
|
+
if (req.method === "GET" && pathname === this._prefix + "/tools") {
|
|
52
|
+
const summaries = this._tools.map((t) => this._toolSummary(t));
|
|
53
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
54
|
+
res.end(JSON.stringify(summaries));
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
// POST {prefix}/tools/{name}/call → execute tool
|
|
58
|
+
if (req.method === "POST" && pathname.startsWith(this._prefix + "/tools/") && pathname.endsWith("/call")) {
|
|
59
|
+
const toolName = decodeURIComponent(pathname.slice((this._prefix + "/tools/").length, -"/call".length));
|
|
60
|
+
await this._handleCallTool(req, res, toolName);
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
// GET {prefix}/tools/{name} → tool detail
|
|
64
|
+
if (req.method === "GET" && pathname.startsWith(this._prefix + "/tools/")) {
|
|
65
|
+
const toolName = decodeURIComponent(pathname.slice((this._prefix + "/tools/").length));
|
|
66
|
+
this._handleToolDetail(res, toolName);
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Build a summary dict for a tool (used in the list endpoint).
|
|
73
|
+
*/
|
|
74
|
+
_toolSummary(tool) {
|
|
75
|
+
const result = {
|
|
76
|
+
name: tool.name,
|
|
77
|
+
description: tool.description ?? "",
|
|
78
|
+
};
|
|
79
|
+
if (tool.annotations) {
|
|
80
|
+
result.annotations = tool.annotations;
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Build a full detail dict for a tool (used in the detail endpoint).
|
|
86
|
+
*/
|
|
87
|
+
_toolDetail(tool) {
|
|
88
|
+
const result = {
|
|
89
|
+
name: tool.name,
|
|
90
|
+
description: tool.description ?? "",
|
|
91
|
+
inputSchema: tool.inputSchema,
|
|
92
|
+
};
|
|
93
|
+
if (tool.annotations) {
|
|
94
|
+
result.annotations = tool.annotations;
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Handle GET {prefix}/tools/{name} - return tool detail or 404.
|
|
100
|
+
*/
|
|
101
|
+
_handleToolDetail(res, toolName) {
|
|
102
|
+
const tool = this._toolsByName.get(toolName);
|
|
103
|
+
if (!tool) {
|
|
104
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
105
|
+
res.end(JSON.stringify({ error: `Tool not found: ${toolName}` }));
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
109
|
+
res.end(JSON.stringify(this._toolDetail(tool)));
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Handle POST {prefix}/tools/{name}/call - execute tool or return 403/404.
|
|
113
|
+
*/
|
|
114
|
+
async _handleCallTool(req, res, toolName) {
|
|
115
|
+
if (!this._allowExecute) {
|
|
116
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
117
|
+
res.end(JSON.stringify({
|
|
118
|
+
error: "Tool execution is disabled. Launch with --allow-execute to enable.",
|
|
119
|
+
}));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const tool = this._toolsByName.get(toolName);
|
|
123
|
+
if (!tool) {
|
|
124
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
125
|
+
res.end(JSON.stringify({ error: `Tool not found: ${toolName}` }));
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
let body = {};
|
|
129
|
+
try {
|
|
130
|
+
const raw = await readBody(req, EXPLORER_MAX_BODY_BYTES);
|
|
131
|
+
if (raw) {
|
|
132
|
+
body = JSON.parse(raw);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// Use empty body if parsing fails
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const [content, isError] = await this._router.handleCall(toolName, body);
|
|
140
|
+
// Extract text from content list
|
|
141
|
+
const texts = content
|
|
142
|
+
.filter((item) => item.type === "text")
|
|
143
|
+
.map((item) => item.text);
|
|
144
|
+
// Try to parse as JSON for a cleaner response
|
|
145
|
+
let result;
|
|
146
|
+
if (texts.length === 1) {
|
|
147
|
+
try {
|
|
148
|
+
result = JSON.parse(texts[0]);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
result = texts[0];
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
result = texts;
|
|
156
|
+
}
|
|
157
|
+
if (isError) {
|
|
158
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
159
|
+
res.end(JSON.stringify({ error: result }));
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
163
|
+
res.end(JSON.stringify({ result }));
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
console.error(`Explorer call_tool error for ${toolName}:`, err);
|
|
168
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
169
|
+
res.end(JSON.stringify({
|
|
170
|
+
error: err instanceof Error ? err.message : String(err),
|
|
171
|
+
}));
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/explorer/handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-contained HTML page for the MCP Tool Explorer.
|
|
3
|
+
*
|
|
4
|
+
* Single-page application with no external dependencies.
|
|
5
|
+
* Displays registered MCP tools, their schemas, annotations,
|
|
6
|
+
* and optionally allows executing tools from the browser.
|
|
7
|
+
*/
|
|
8
|
+
export declare const EXPLORER_HTML = "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n<title>MCP Tool Explorer</title>\n<style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, monospace;\n background: #f5f5f5; color: #333; padding: 24px; }\n h1 { font-size: 1.4rem; margin-bottom: 16px; }\n .tool-list { list-style: none; }\n .tool-item { background: #fff; border: 1px solid #ddd; border-radius: 6px;\n padding: 12px 16px; margin-bottom: 8px; cursor: pointer; }\n .tool-item:hover { border-color: #888; }\n .tool-name { font-weight: 600; }\n .tool-desc { color: #666; font-size: 0.9rem; margin-top: 4px; }\n .hint { display: inline-block; background: #e8e8e8; padding: 2px 8px;\n border-radius: 3px; font-size: 0.75rem; margin-right: 4px; }\n .hint-readonly { background: #d4edda; color: #155724; }\n .hint-destructive { background: #f8d7da; color: #721c24; }\n .hint-idempotent { background: #cce5ff; color: #004085; }\n .detail { background: #fff; border: 1px solid #ddd; border-radius: 6px;\n padding: 16px; margin-top: 16px; display: none; }\n .detail.active { display: block; }\n .detail h2 { font-size: 1.1rem; margin-bottom: 12px; }\n .schema-label { font-weight: 600; margin-top: 12px; display: block; }\n pre { background: #282c34; color: #abb2bf; padding: 12px; border-radius: 4px;\n overflow-x: auto; font-size: 0.85rem; margin-top: 4px; }\n #loading { color: #888; }\n .try-it { margin-top: 16px; border-top: 1px solid #eee; padding-top: 16px; }\n .try-it h3 { font-size: 0.95rem; margin-bottom: 8px; }\n .input-editor { width: 100%; min-height: 120px; font-family: monospace;\n font-size: 0.85rem; padding: 10px; border: 1px solid #ddd;\n border-radius: 4px; resize: vertical; background: #fafafa; }\n .execute-btn { margin-top: 8px; padding: 8px 20px; background: #4CAF50; color: #fff;\n border: none; border-radius: 4px; cursor: pointer; font-size: 0.9rem;\n font-weight: 600; }\n .execute-btn:hover { background: #45a049; }\n .execute-btn:disabled { background: #ccc; cursor: not-allowed; }\n .result-area { margin-top: 12px; }\n .result-area pre { background: #1a2332; }\n .result-error { color: #f93e3e; }\n .result-success { color: #49cc90; }\n .exec-disabled { color: #888; font-size: 0.85rem; font-style: italic; margin-top: 16px; }\n</style>\n</head>\n<body>\n<h1>MCP Tool Explorer</h1>\n<div id=\"loading\">Loading tools...</div>\n<ul class=\"tool-list\" id=\"tools\"></ul>\n<div class=\"detail\" id=\"detail\"></div>\n<script>\n(function() {\n var base = window.location.pathname.replace(/\\/$/, '');\n var toolsEl = document.getElementById('tools');\n var detailEl = document.getElementById('detail');\n var loadingEl = document.getElementById('loading');\n var executeEnabled = null;\n\n function esc(s) {\n var d = document.createElement('div');\n d.appendChild(document.createTextNode(s));\n return d.innerHTML;\n }\n\n function defaultFromSchema(schema) {\n if (!schema || !schema.properties) return {};\n var result = {};\n var props = schema.properties;\n for (var key in props) {\n if (!props.hasOwnProperty(key)) continue;\n var t = props[key].type;\n if (props[key]['default'] !== undefined) {\n result[key] = props[key]['default'];\n } else if (t === 'string') {\n result[key] = '';\n } else if (t === 'number' || t === 'integer') {\n result[key] = 0;\n } else if (t === 'boolean') {\n result[key] = false;\n } else if (t === 'array') {\n result[key] = [];\n } else if (t === 'object') {\n result[key] = {};\n } else {\n result[key] = null;\n }\n }\n return result;\n }\n\n function hintsHtml(annotations) {\n if (!annotations) return '';\n var parts = [];\n if (annotations.readOnlyHint) parts.push('<span class=\"hint hint-readonly\">readOnly</span>');\n if (annotations.destructiveHint) parts.push('<span class=\"hint hint-destructive\">destructive</span>');\n if (annotations.idempotentHint) parts.push('<span class=\"hint hint-idempotent\">idempotent</span>');\n if (annotations.openWorldHint === false) parts.push('<span class=\"hint\">closedWorld</span>');\n return parts.join('');\n }\n\n fetch(base + '/tools')\n .then(function(r) { return r.json(); })\n .then(function(tools) {\n loadingEl.style.display = 'none';\n tools.forEach(function(t) {\n var li = document.createElement('li');\n li.className = 'tool-item';\n li.innerHTML =\n '<span class=\"tool-name\">' + esc(t.name) + '</span> ' +\n hintsHtml(t.annotations) +\n '<div class=\"tool-desc\">' + esc(t.description || '') + '</div>';\n li.onclick = function() { loadDetail(t.name); };\n toolsEl.appendChild(li);\n });\n fetch(base + '/tools/__probe__/call', {\n method: 'POST',\n headers: {'Content-Type': 'application/json'},\n body: '{}'\n }).then(function(r) {\n executeEnabled = r.status !== 403;\n }).catch(function() {});\n })\n .catch(function(e) { loadingEl.textContent = 'Error: ' + e; });\n\n function loadDetail(name) {\n fetch(base + '/tools/' + encodeURIComponent(name))\n .then(function(r) { return r.json(); })\n .then(function(d) {\n detailEl.className = 'detail active';\n var html =\n '<h2>' + esc(d.name) + '</h2>' +\n '<p>' + esc(d.description || '') + '</p>' +\n '<span class=\"schema-label\">Input Schema</span>' +\n '<pre>' + esc(JSON.stringify(d.inputSchema, null, 2)) + '</pre>';\n\n if (d.annotations) {\n html += '<span class=\"schema-label\">Annotations</span>' +\n '<pre>' + esc(JSON.stringify(d.annotations, null, 2)) + '</pre>';\n }\n\n html += '<div class=\"try-it\" id=\"try-it-section\">' +\n '<h3>Try it</h3>' +\n '<textarea class=\"input-editor\" id=\"input-editor\">' +\n esc(JSON.stringify(defaultFromSchema(d.inputSchema), null, 2)) +\n '</textarea>' +\n '<button class=\"execute-btn\" id=\"execute-btn\">Execute</button>' +\n '<div class=\"result-area\" id=\"result-area\"></div>' +\n '</div>';\n\n detailEl.innerHTML = html;\n\n document.getElementById('execute-btn').onclick = function() {\n execTool(d.name);\n };\n\n if (executeEnabled === false) {\n var section = document.getElementById('try-it-section');\n if (section) section.innerHTML =\n '<p class=\"exec-disabled\">' +\n 'Tool execution is disabled. ' +\n 'Launch with --allow-execute to enable.</p>';\n }\n })\n .catch(function(e) {\n detailEl.className = 'detail active';\n detailEl.innerHTML = '<p class=\"result-error\">Failed to load tool details: ' + esc(e.message) + '</p>';\n });\n }\n\n function execTool(name) {\n var btn = document.getElementById('execute-btn');\n var editor = document.getElementById('input-editor');\n var resultArea = document.getElementById('result-area');\n\n var inputText = editor.value.trim();\n var inputs;\n try {\n inputs = inputText ? JSON.parse(inputText) : {};\n } catch (e) {\n resultArea.innerHTML = '<p class=\"result-error\">Invalid JSON: ' + esc(e.message) + '</p>';\n return;\n }\n\n btn.disabled = true;\n btn.textContent = 'Executing...';\n resultArea.innerHTML = '';\n\n fetch(base + '/tools/' + encodeURIComponent(name) + '/call', {\n method: 'POST',\n headers: {'Content-Type': 'application/json'},\n body: JSON.stringify(inputs)\n })\n .then(function(r) {\n if (r.status === 403) {\n executeEnabled = false;\n var section = document.getElementById('try-it-section');\n if (section) section.innerHTML =\n '<p class=\"exec-disabled\">' +\n 'Tool execution is disabled. ' +\n 'Launch with --allow-execute to enable.</p>';\n return null;\n }\n return r.json().then(function(data) { return {status: r.status, data: data}; });\n })\n .then(function(result) {\n if (!result) return;\n btn.disabled = false;\n btn.textContent = 'Execute';\n if (result.status >= 400) {\n resultArea.innerHTML = '<span class=\"schema-label result-error\">Error (' + result.status + ')</span>' +\n '<pre>' + esc(JSON.stringify(result.data, null, 2)) + '</pre>';\n } else {\n resultArea.innerHTML = '<span class=\"schema-label result-success\">Result</span>' +\n '<pre>' + esc(JSON.stringify(result.data, null, 2)) + '</pre>';\n }\n })\n .catch(function(e) {\n btn.disabled = false;\n btn.textContent = 'Execute';\n resultArea.innerHTML = '<p class=\"result-error\">Request failed: ' + esc(e.message) + '</p>';\n });\n }\n})();\n</script>\n</body>\n</html>\n";
|
|
9
|
+
//# sourceMappingURL=html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/explorer/html.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,eAAO,MAAM,aAAa,i/RAqOzB,CAAC"}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Self-contained HTML page for the MCP Tool Explorer.
|
|
3
|
+
*
|
|
4
|
+
* Single-page application with no external dependencies.
|
|
5
|
+
* Displays registered MCP tools, their schemas, annotations,
|
|
6
|
+
* and optionally allows executing tools from the browser.
|
|
7
|
+
*/
|
|
8
|
+
export const EXPLORER_HTML = `\
|
|
9
|
+
<!DOCTYPE html>
|
|
10
|
+
<html lang="en">
|
|
11
|
+
<head>
|
|
12
|
+
<meta charset="utf-8">
|
|
13
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
14
|
+
<title>MCP Tool Explorer</title>
|
|
15
|
+
<style>
|
|
16
|
+
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|
17
|
+
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, monospace;
|
|
18
|
+
background: #f5f5f5; color: #333; padding: 24px; }
|
|
19
|
+
h1 { font-size: 1.4rem; margin-bottom: 16px; }
|
|
20
|
+
.tool-list { list-style: none; }
|
|
21
|
+
.tool-item { background: #fff; border: 1px solid #ddd; border-radius: 6px;
|
|
22
|
+
padding: 12px 16px; margin-bottom: 8px; cursor: pointer; }
|
|
23
|
+
.tool-item:hover { border-color: #888; }
|
|
24
|
+
.tool-name { font-weight: 600; }
|
|
25
|
+
.tool-desc { color: #666; font-size: 0.9rem; margin-top: 4px; }
|
|
26
|
+
.hint { display: inline-block; background: #e8e8e8; padding: 2px 8px;
|
|
27
|
+
border-radius: 3px; font-size: 0.75rem; margin-right: 4px; }
|
|
28
|
+
.hint-readonly { background: #d4edda; color: #155724; }
|
|
29
|
+
.hint-destructive { background: #f8d7da; color: #721c24; }
|
|
30
|
+
.hint-idempotent { background: #cce5ff; color: #004085; }
|
|
31
|
+
.detail { background: #fff; border: 1px solid #ddd; border-radius: 6px;
|
|
32
|
+
padding: 16px; margin-top: 16px; display: none; }
|
|
33
|
+
.detail.active { display: block; }
|
|
34
|
+
.detail h2 { font-size: 1.1rem; margin-bottom: 12px; }
|
|
35
|
+
.schema-label { font-weight: 600; margin-top: 12px; display: block; }
|
|
36
|
+
pre { background: #282c34; color: #abb2bf; padding: 12px; border-radius: 4px;
|
|
37
|
+
overflow-x: auto; font-size: 0.85rem; margin-top: 4px; }
|
|
38
|
+
#loading { color: #888; }
|
|
39
|
+
.try-it { margin-top: 16px; border-top: 1px solid #eee; padding-top: 16px; }
|
|
40
|
+
.try-it h3 { font-size: 0.95rem; margin-bottom: 8px; }
|
|
41
|
+
.input-editor { width: 100%; min-height: 120px; font-family: monospace;
|
|
42
|
+
font-size: 0.85rem; padding: 10px; border: 1px solid #ddd;
|
|
43
|
+
border-radius: 4px; resize: vertical; background: #fafafa; }
|
|
44
|
+
.execute-btn { margin-top: 8px; padding: 8px 20px; background: #4CAF50; color: #fff;
|
|
45
|
+
border: none; border-radius: 4px; cursor: pointer; font-size: 0.9rem;
|
|
46
|
+
font-weight: 600; }
|
|
47
|
+
.execute-btn:hover { background: #45a049; }
|
|
48
|
+
.execute-btn:disabled { background: #ccc; cursor: not-allowed; }
|
|
49
|
+
.result-area { margin-top: 12px; }
|
|
50
|
+
.result-area pre { background: #1a2332; }
|
|
51
|
+
.result-error { color: #f93e3e; }
|
|
52
|
+
.result-success { color: #49cc90; }
|
|
53
|
+
.exec-disabled { color: #888; font-size: 0.85rem; font-style: italic; margin-top: 16px; }
|
|
54
|
+
</style>
|
|
55
|
+
</head>
|
|
56
|
+
<body>
|
|
57
|
+
<h1>MCP Tool Explorer</h1>
|
|
58
|
+
<div id="loading">Loading tools...</div>
|
|
59
|
+
<ul class="tool-list" id="tools"></ul>
|
|
60
|
+
<div class="detail" id="detail"></div>
|
|
61
|
+
<script>
|
|
62
|
+
(function() {
|
|
63
|
+
var base = window.location.pathname.replace(/\\/$/, '');
|
|
64
|
+
var toolsEl = document.getElementById('tools');
|
|
65
|
+
var detailEl = document.getElementById('detail');
|
|
66
|
+
var loadingEl = document.getElementById('loading');
|
|
67
|
+
var executeEnabled = null;
|
|
68
|
+
|
|
69
|
+
function esc(s) {
|
|
70
|
+
var d = document.createElement('div');
|
|
71
|
+
d.appendChild(document.createTextNode(s));
|
|
72
|
+
return d.innerHTML;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function defaultFromSchema(schema) {
|
|
76
|
+
if (!schema || !schema.properties) return {};
|
|
77
|
+
var result = {};
|
|
78
|
+
var props = schema.properties;
|
|
79
|
+
for (var key in props) {
|
|
80
|
+
if (!props.hasOwnProperty(key)) continue;
|
|
81
|
+
var t = props[key].type;
|
|
82
|
+
if (props[key]['default'] !== undefined) {
|
|
83
|
+
result[key] = props[key]['default'];
|
|
84
|
+
} else if (t === 'string') {
|
|
85
|
+
result[key] = '';
|
|
86
|
+
} else if (t === 'number' || t === 'integer') {
|
|
87
|
+
result[key] = 0;
|
|
88
|
+
} else if (t === 'boolean') {
|
|
89
|
+
result[key] = false;
|
|
90
|
+
} else if (t === 'array') {
|
|
91
|
+
result[key] = [];
|
|
92
|
+
} else if (t === 'object') {
|
|
93
|
+
result[key] = {};
|
|
94
|
+
} else {
|
|
95
|
+
result[key] = null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function hintsHtml(annotations) {
|
|
102
|
+
if (!annotations) return '';
|
|
103
|
+
var parts = [];
|
|
104
|
+
if (annotations.readOnlyHint) parts.push('<span class="hint hint-readonly">readOnly</span>');
|
|
105
|
+
if (annotations.destructiveHint) parts.push('<span class="hint hint-destructive">destructive</span>');
|
|
106
|
+
if (annotations.idempotentHint) parts.push('<span class="hint hint-idempotent">idempotent</span>');
|
|
107
|
+
if (annotations.openWorldHint === false) parts.push('<span class="hint">closedWorld</span>');
|
|
108
|
+
return parts.join('');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
fetch(base + '/tools')
|
|
112
|
+
.then(function(r) { return r.json(); })
|
|
113
|
+
.then(function(tools) {
|
|
114
|
+
loadingEl.style.display = 'none';
|
|
115
|
+
tools.forEach(function(t) {
|
|
116
|
+
var li = document.createElement('li');
|
|
117
|
+
li.className = 'tool-item';
|
|
118
|
+
li.innerHTML =
|
|
119
|
+
'<span class="tool-name">' + esc(t.name) + '</span> ' +
|
|
120
|
+
hintsHtml(t.annotations) +
|
|
121
|
+
'<div class="tool-desc">' + esc(t.description || '') + '</div>';
|
|
122
|
+
li.onclick = function() { loadDetail(t.name); };
|
|
123
|
+
toolsEl.appendChild(li);
|
|
124
|
+
});
|
|
125
|
+
fetch(base + '/tools/__probe__/call', {
|
|
126
|
+
method: 'POST',
|
|
127
|
+
headers: {'Content-Type': 'application/json'},
|
|
128
|
+
body: '{}'
|
|
129
|
+
}).then(function(r) {
|
|
130
|
+
executeEnabled = r.status !== 403;
|
|
131
|
+
}).catch(function() {});
|
|
132
|
+
})
|
|
133
|
+
.catch(function(e) { loadingEl.textContent = 'Error: ' + e; });
|
|
134
|
+
|
|
135
|
+
function loadDetail(name) {
|
|
136
|
+
fetch(base + '/tools/' + encodeURIComponent(name))
|
|
137
|
+
.then(function(r) { return r.json(); })
|
|
138
|
+
.then(function(d) {
|
|
139
|
+
detailEl.className = 'detail active';
|
|
140
|
+
var html =
|
|
141
|
+
'<h2>' + esc(d.name) + '</h2>' +
|
|
142
|
+
'<p>' + esc(d.description || '') + '</p>' +
|
|
143
|
+
'<span class="schema-label">Input Schema</span>' +
|
|
144
|
+
'<pre>' + esc(JSON.stringify(d.inputSchema, null, 2)) + '</pre>';
|
|
145
|
+
|
|
146
|
+
if (d.annotations) {
|
|
147
|
+
html += '<span class="schema-label">Annotations</span>' +
|
|
148
|
+
'<pre>' + esc(JSON.stringify(d.annotations, null, 2)) + '</pre>';
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
html += '<div class="try-it" id="try-it-section">' +
|
|
152
|
+
'<h3>Try it</h3>' +
|
|
153
|
+
'<textarea class="input-editor" id="input-editor">' +
|
|
154
|
+
esc(JSON.stringify(defaultFromSchema(d.inputSchema), null, 2)) +
|
|
155
|
+
'</textarea>' +
|
|
156
|
+
'<button class="execute-btn" id="execute-btn">Execute</button>' +
|
|
157
|
+
'<div class="result-area" id="result-area"></div>' +
|
|
158
|
+
'</div>';
|
|
159
|
+
|
|
160
|
+
detailEl.innerHTML = html;
|
|
161
|
+
|
|
162
|
+
document.getElementById('execute-btn').onclick = function() {
|
|
163
|
+
execTool(d.name);
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
if (executeEnabled === false) {
|
|
167
|
+
var section = document.getElementById('try-it-section');
|
|
168
|
+
if (section) section.innerHTML =
|
|
169
|
+
'<p class="exec-disabled">' +
|
|
170
|
+
'Tool execution is disabled. ' +
|
|
171
|
+
'Launch with --allow-execute to enable.</p>';
|
|
172
|
+
}
|
|
173
|
+
})
|
|
174
|
+
.catch(function(e) {
|
|
175
|
+
detailEl.className = 'detail active';
|
|
176
|
+
detailEl.innerHTML = '<p class="result-error">Failed to load tool details: ' + esc(e.message) + '</p>';
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function execTool(name) {
|
|
181
|
+
var btn = document.getElementById('execute-btn');
|
|
182
|
+
var editor = document.getElementById('input-editor');
|
|
183
|
+
var resultArea = document.getElementById('result-area');
|
|
184
|
+
|
|
185
|
+
var inputText = editor.value.trim();
|
|
186
|
+
var inputs;
|
|
187
|
+
try {
|
|
188
|
+
inputs = inputText ? JSON.parse(inputText) : {};
|
|
189
|
+
} catch (e) {
|
|
190
|
+
resultArea.innerHTML = '<p class="result-error">Invalid JSON: ' + esc(e.message) + '</p>';
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
btn.disabled = true;
|
|
195
|
+
btn.textContent = 'Executing...';
|
|
196
|
+
resultArea.innerHTML = '';
|
|
197
|
+
|
|
198
|
+
fetch(base + '/tools/' + encodeURIComponent(name) + '/call', {
|
|
199
|
+
method: 'POST',
|
|
200
|
+
headers: {'Content-Type': 'application/json'},
|
|
201
|
+
body: JSON.stringify(inputs)
|
|
202
|
+
})
|
|
203
|
+
.then(function(r) {
|
|
204
|
+
if (r.status === 403) {
|
|
205
|
+
executeEnabled = false;
|
|
206
|
+
var section = document.getElementById('try-it-section');
|
|
207
|
+
if (section) section.innerHTML =
|
|
208
|
+
'<p class="exec-disabled">' +
|
|
209
|
+
'Tool execution is disabled. ' +
|
|
210
|
+
'Launch with --allow-execute to enable.</p>';
|
|
211
|
+
return null;
|
|
212
|
+
}
|
|
213
|
+
return r.json().then(function(data) { return {status: r.status, data: data}; });
|
|
214
|
+
})
|
|
215
|
+
.then(function(result) {
|
|
216
|
+
if (!result) return;
|
|
217
|
+
btn.disabled = false;
|
|
218
|
+
btn.textContent = 'Execute';
|
|
219
|
+
if (result.status >= 400) {
|
|
220
|
+
resultArea.innerHTML = '<span class="schema-label result-error">Error (' + result.status + ')</span>' +
|
|
221
|
+
'<pre>' + esc(JSON.stringify(result.data, null, 2)) + '</pre>';
|
|
222
|
+
} else {
|
|
223
|
+
resultArea.innerHTML = '<span class="schema-label result-success">Result</span>' +
|
|
224
|
+
'<pre>' + esc(JSON.stringify(result.data, null, 2)) + '</pre>';
|
|
225
|
+
}
|
|
226
|
+
})
|
|
227
|
+
.catch(function(e) {
|
|
228
|
+
btn.disabled = false;
|
|
229
|
+
btn.textContent = 'Execute';
|
|
230
|
+
resultArea.innerHTML = '<p class="result-error">Request failed: ' + esc(e.message) + '</p>';
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
})();
|
|
234
|
+
</script>
|
|
235
|
+
</body>
|
|
236
|
+
</html>
|
|
237
|
+
`;
|
|
238
|
+
//# sourceMappingURL=html.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"html.js","sourceRoot":"","sources":["../../src/explorer/html.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqO5B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/explorer/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,YAAY,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/explorer/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ export type { CallResult, HandleCallExtra, ExecutionRouterOptions } from "./serv
|
|
|
22
22
|
export { RegistryListener } from "./server/listener.js";
|
|
23
23
|
export { TransportManager } from "./server/transport.js";
|
|
24
24
|
export type { MetricsExporter } from "./server/transport.js";
|
|
25
|
+
export { ExplorerHandler } from "./explorer/index.js";
|
|
26
|
+
export type { ExplorerHandlerOptions } from "./explorer/index.js";
|
|
25
27
|
export { AnnotationMapper } from "./adapters/annotations.js";
|
|
26
28
|
export { SchemaConverter } from "./adapters/schema.js";
|
|
27
29
|
export { ErrorMapper } from "./adapters/errors.js";
|
|
@@ -74,6 +76,12 @@ export interface ServeOptions {
|
|
|
74
76
|
onShutdown?: () => void | Promise<void>;
|
|
75
77
|
/** Optional MetricsCollector for Prometheus /metrics endpoint. */
|
|
76
78
|
metricsCollector?: MetricsExporter;
|
|
79
|
+
/** Enable the browser-based Tool Explorer UI (HTTP transports only). Default: false */
|
|
80
|
+
explorer?: boolean;
|
|
81
|
+
/** URL prefix for the explorer. Default: "/explorer" */
|
|
82
|
+
explorerPrefix?: string;
|
|
83
|
+
/** Allow tool execution from the explorer UI. Default: false */
|
|
84
|
+
allowExecute?: boolean;
|
|
77
85
|
}
|
|
78
86
|
/**
|
|
79
87
|
* Launch an MCP Server that exposes all apcore modules as tools.
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAIrE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -10,6 +10,7 @@ import { OpenAIConverter } from "./converters/openai.js";
|
|
|
10
10
|
import { MCPServerFactory } from "./server/factory.js";
|
|
11
11
|
import { ExecutionRouter } from "./server/router.js";
|
|
12
12
|
import { TransportManager } from "./server/transport.js";
|
|
13
|
+
import { ExplorerHandler } from "./explorer/handler.js";
|
|
13
14
|
const require = createRequire(import.meta.url);
|
|
14
15
|
const pkg = require("../package.json");
|
|
15
16
|
export const VERSION = pkg.version;
|
|
@@ -22,6 +23,7 @@ export { MCPServerFactory } from "./server/factory.js";
|
|
|
22
23
|
export { ExecutionRouter } from "./server/router.js";
|
|
23
24
|
export { RegistryListener } from "./server/listener.js";
|
|
24
25
|
export { TransportManager } from "./server/transport.js";
|
|
26
|
+
export { ExplorerHandler } from "./explorer/index.js";
|
|
25
27
|
export { AnnotationMapper } from "./adapters/annotations.js";
|
|
26
28
|
export { SchemaConverter } from "./adapters/schema.js";
|
|
27
29
|
export { ErrorMapper } from "./adapters/errors.js";
|
|
@@ -76,7 +78,7 @@ export function resolveExecutor(registryOrExecutor) {
|
|
|
76
78
|
* @param options - Server configuration options.
|
|
77
79
|
*/
|
|
78
80
|
export async function serve(registryOrExecutor, options = {}) {
|
|
79
|
-
const { transport = "stdio", host = "127.0.0.1", port = 8000, name = "apcore-mcp", version = VERSION, validateInputs, tags, prefix, logLevel, onStartup, onShutdown, metricsCollector, } = options;
|
|
81
|
+
const { transport = "stdio", host = "127.0.0.1", port = 8000, name = "apcore-mcp", version = VERSION, validateInputs, tags, prefix, logLevel, onStartup, onShutdown, metricsCollector, explorer = false, explorerPrefix = "/explorer", allowExecute = false, } = options;
|
|
80
82
|
// Input validation (matching Python's checks)
|
|
81
83
|
if (!name || name.length === 0) {
|
|
82
84
|
throw new Error("name must not be empty");
|
|
@@ -94,6 +96,9 @@ export async function serve(registryOrExecutor, options = {}) {
|
|
|
94
96
|
if (prefix !== undefined && prefix !== null && prefix.length === 0) {
|
|
95
97
|
throw new Error("prefix must not be empty if provided");
|
|
96
98
|
}
|
|
99
|
+
if (explorer && !explorerPrefix.startsWith("/")) {
|
|
100
|
+
throw new Error("explorerPrefix must start with '/'");
|
|
101
|
+
}
|
|
97
102
|
// Save original console methods before suppression
|
|
98
103
|
const origDebug = console.debug;
|
|
99
104
|
const origInfo = console.info;
|
|
@@ -130,6 +135,16 @@ export async function serve(registryOrExecutor, options = {}) {
|
|
|
130
135
|
if (metricsCollector) {
|
|
131
136
|
transportManager.setMetricsCollector(metricsCollector);
|
|
132
137
|
}
|
|
138
|
+
// Mount explorer for HTTP transports only
|
|
139
|
+
const transportLower = transport.toLowerCase();
|
|
140
|
+
if (explorer && (transportLower === "streamable-http" || transportLower === "sse")) {
|
|
141
|
+
const explorerHandler = new ExplorerHandler(tools, router, {
|
|
142
|
+
allowExecute,
|
|
143
|
+
prefix: explorerPrefix,
|
|
144
|
+
});
|
|
145
|
+
transportManager.setExplorerHandler(explorerHandler);
|
|
146
|
+
origInfo(`Tool Explorer enabled at ${explorerPrefix}`);
|
|
147
|
+
}
|
|
133
148
|
try {
|
|
134
149
|
if (transport === "stdio") {
|
|
135
150
|
await transportManager.runStdio(server);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* - streamableHttp: Streamable HTTP with SSE support
|
|
7
7
|
* - sse: Legacy Server-Sent Events transport
|
|
8
8
|
*/
|
|
9
|
-
import { type Server as HttpServer } from "node:http";
|
|
9
|
+
import { type IncomingMessage, type Server as HttpServer } from "node:http";
|
|
10
10
|
import type { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
11
|
+
import type { ExplorerHandler } from "../explorer/handler.js";
|
|
11
12
|
/** Options for HTTP-based transports. */
|
|
12
13
|
export interface HttpTransportOptions {
|
|
13
14
|
host: string;
|
|
@@ -18,6 +19,14 @@ export interface HttpTransportOptions {
|
|
|
18
19
|
export interface MetricsExporter {
|
|
19
20
|
exportPrometheus(): string;
|
|
20
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Read the full request body as a string.
|
|
24
|
+
*
|
|
25
|
+
* Enforces a maximum byte size to prevent memory exhaustion.
|
|
26
|
+
* @param req - The incoming HTTP request
|
|
27
|
+
* @param maxBytes - Maximum allowed body size in bytes (default: MAX_BODY_BYTES)
|
|
28
|
+
*/
|
|
29
|
+
export declare function readBody(req: IncomingMessage, maxBytes?: number): Promise<string>;
|
|
21
30
|
export declare class TransportManager {
|
|
22
31
|
/** The underlying HTTP server, if an HTTP-based transport is active. */
|
|
23
32
|
httpServer?: HttpServer;
|
|
@@ -27,6 +36,8 @@ export declare class TransportManager {
|
|
|
27
36
|
private _moduleCount;
|
|
28
37
|
/** Optional metrics collector for Prometheus /metrics endpoint. */
|
|
29
38
|
private _metricsCollector?;
|
|
39
|
+
/** Optional explorer handler for Tool Explorer UI. */
|
|
40
|
+
private _explorerHandler?;
|
|
30
41
|
/**
|
|
31
42
|
* Set the number of registered modules/tools.
|
|
32
43
|
*
|
|
@@ -39,6 +50,12 @@ export declare class TransportManager {
|
|
|
39
50
|
* @param collector - A MetricsExporter instance (e.g. MetricsCollector from apcore)
|
|
40
51
|
*/
|
|
41
52
|
setMetricsCollector(collector: MetricsExporter): void;
|
|
53
|
+
/**
|
|
54
|
+
* Set the explorer handler for Tool Explorer UI routes.
|
|
55
|
+
*
|
|
56
|
+
* @param handler - An ExplorerHandler instance
|
|
57
|
+
*/
|
|
58
|
+
setExplorerHandler(handler: ExplorerHandler): void;
|
|
42
59
|
/**
|
|
43
60
|
* Build the health check response payload.
|
|
44
61
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/server/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"transport.d.ts","sourceRoot":"","sources":["../../src/server/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAgB,KAAK,eAAe,EAAE,KAAK,MAAM,IAAI,UAAU,EAAuB,MAAM,WAAW,CAAC;AAC/G,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAIxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,yCAAyC;AACzC,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,oFAAoF;AACpF,MAAM,WAAW,eAAe;IAC9B,gBAAgB,IAAI,MAAM,CAAC;CAC5B;AAiBD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,eAAe,EAAE,QAAQ,GAAE,MAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwBjG;AAED,qBAAa,gBAAgB;IAC3B,wEAAwE;IACxE,UAAU,CAAC,EAAE,UAAU,CAAC;IAExB,iFAAiF;IACjF,OAAO,CAAC,UAAU,CAAsB;IAExC,0CAA0C;IAC1C,OAAO,CAAC,YAAY,CAAa;IAEjC,mEAAmE;IACnE,OAAO,CAAC,iBAAiB,CAAC,CAAkB;IAE5C,sDAAsD;IACtD,OAAO,CAAC,gBAAgB,CAAC,CAAkB;IAE3C;;;;OAIG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAInC;;;;OAIG;IACH,mBAAmB,CAAC,SAAS,EAAE,eAAe,GAAG,IAAI;IAIrD;;;;OAIG;IACH,kBAAkB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IAIlD;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAQ5B;;;;;;;OAOG;IACH,OAAO,CAAC,mBAAmB;IAyB3B;;;;;;;OAOG;IACG,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7C;;;;;;;;OAQG;IACG,iBAAiB,CACrB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC;IAwEhB;;;;;;;;;OASG;IACG,MAAM,CACV,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,oBAAoB,GAC5B,OAAO,CAAC,IAAI,CAAC;IAwFhB;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B;;;;;;OAMG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;CAcpD"}
|
package/dist/server/transport.js
CHANGED
|
@@ -31,7 +31,7 @@ const MAX_BODY_BYTES = (() => {
|
|
|
31
31
|
* @param req - The incoming HTTP request
|
|
32
32
|
* @param maxBytes - Maximum allowed body size in bytes (default: MAX_BODY_BYTES)
|
|
33
33
|
*/
|
|
34
|
-
function readBody(req, maxBytes = MAX_BODY_BYTES) {
|
|
34
|
+
export function readBody(req, maxBytes = MAX_BODY_BYTES) {
|
|
35
35
|
return new Promise((resolve, reject) => {
|
|
36
36
|
let data = "";
|
|
37
37
|
let bytes = 0;
|
|
@@ -68,6 +68,8 @@ export class TransportManager {
|
|
|
68
68
|
_moduleCount = 0;
|
|
69
69
|
/** Optional metrics collector for Prometheus /metrics endpoint. */
|
|
70
70
|
_metricsCollector;
|
|
71
|
+
/** Optional explorer handler for Tool Explorer UI. */
|
|
72
|
+
_explorerHandler;
|
|
71
73
|
/**
|
|
72
74
|
* Set the number of registered modules/tools.
|
|
73
75
|
*
|
|
@@ -84,6 +86,14 @@ export class TransportManager {
|
|
|
84
86
|
setMetricsCollector(collector) {
|
|
85
87
|
this._metricsCollector = collector;
|
|
86
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Set the explorer handler for Tool Explorer UI routes.
|
|
91
|
+
*
|
|
92
|
+
* @param handler - An ExplorerHandler instance
|
|
93
|
+
*/
|
|
94
|
+
setExplorerHandler(handler) {
|
|
95
|
+
this._explorerHandler = handler;
|
|
96
|
+
}
|
|
87
97
|
/**
|
|
88
98
|
* Build the health check response payload.
|
|
89
99
|
*
|
|
@@ -157,10 +167,25 @@ export class TransportManager {
|
|
|
157
167
|
sessionIdGenerator: () => crypto.randomUUID(),
|
|
158
168
|
});
|
|
159
169
|
await server.connect(transport);
|
|
170
|
+
const explorerHandler = this._explorerHandler;
|
|
160
171
|
const httpServer = createServer(async (req, res) => {
|
|
161
172
|
const url = new URL(req.url ?? "/", `http://${options.host}:${options.port}`);
|
|
162
173
|
if (this._handleBuiltinRoute(req, res, url))
|
|
163
174
|
return;
|
|
175
|
+
// Check explorer routes before MCP transport
|
|
176
|
+
if (explorerHandler) {
|
|
177
|
+
try {
|
|
178
|
+
const handled = await explorerHandler.handleRequest(req, res, url);
|
|
179
|
+
if (handled)
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
catch (err) {
|
|
183
|
+
if (!res.headersSent) {
|
|
184
|
+
res.writeHead(500).end("Internal Server Error");
|
|
185
|
+
}
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
164
189
|
if (url.pathname !== endpoint) {
|
|
165
190
|
res.writeHead(404).end("Not Found");
|
|
166
191
|
return;
|
|
@@ -215,10 +240,25 @@ export class TransportManager {
|
|
|
215
240
|
const endpoint = options.endpoint ?? "/sse";
|
|
216
241
|
const messagesEndpoint = "/messages";
|
|
217
242
|
const transports = new Map();
|
|
243
|
+
const explorerHandler = this._explorerHandler;
|
|
218
244
|
const httpServer = createServer(async (req, res) => {
|
|
219
245
|
const url = new URL(req.url ?? "/", `http://${options.host}:${options.port}`);
|
|
220
246
|
if (this._handleBuiltinRoute(req, res, url))
|
|
221
247
|
return;
|
|
248
|
+
// Check explorer routes before SSE transport
|
|
249
|
+
if (explorerHandler) {
|
|
250
|
+
try {
|
|
251
|
+
const handled = await explorerHandler.handleRequest(req, res, url);
|
|
252
|
+
if (handled)
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
catch (err) {
|
|
256
|
+
if (!res.headersSent) {
|
|
257
|
+
res.writeHead(500).end("Internal Server Error");
|
|
258
|
+
}
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
222
262
|
if (url.pathname === endpoint && req.method === "GET") {
|
|
223
263
|
// Establish SSE connection
|
|
224
264
|
const transport = new SSEServerTransport(messagesEndpoint, res);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/server/transport.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAwE,MAAM,WAAW,CAAC;AAE/G,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/server/transport.ts"],"names":[],"mappings":"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"}
|