@mcpc-tech/unplugin-dev-inspector-mcp 0.0.38 → 0.0.40
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 +134 -10
- package/client/dist/inspector.iife.js +10 -6
- package/dist/config-updater.cjs +114 -29
- package/dist/config-updater.js +114 -29
- package/dist/index.cjs +35 -5
- package/dist/index.d.cts +15 -0
- package/dist/index.d.ts +19 -4
- package/dist/index.js +35 -5
- package/package.json +8 -2
package/dist/config-updater.cjs
CHANGED
|
@@ -37,6 +37,7 @@ let url = require("url");
|
|
|
37
37
|
let ai = require("ai");
|
|
38
38
|
let _agentclientprotocol_sdk = require("@agentclientprotocol/sdk");
|
|
39
39
|
let node_child_process = require("node:child_process");
|
|
40
|
+
let module$1 = require("module");
|
|
40
41
|
let fs_promises = require("fs/promises");
|
|
41
42
|
|
|
42
43
|
//#region ../../node_modules/.pnpm/@mcpc-tech+cmcp@0.0.15/node_modules/@mcpc-tech/cmcp/index.mjs
|
|
@@ -34870,7 +34871,7 @@ var require_snapshot_utils = /* @__PURE__ */ require_chunk.__commonJSMin(((expor
|
|
|
34870
34871
|
//#region ../../node_modules/.pnpm/undici@7.16.0/node_modules/undici/lib/mock/snapshot-recorder.js
|
|
34871
34872
|
var require_snapshot_recorder = /* @__PURE__ */ require_chunk.__commonJSMin(((exports, module) => {
|
|
34872
34873
|
const { writeFile: writeFile$1, readFile: readFile$1, mkdir: mkdir$1 } = require("node:fs/promises");
|
|
34873
|
-
const { dirname: dirname$
|
|
34874
|
+
const { dirname: dirname$2, resolve } = require("node:path");
|
|
34874
34875
|
const { setTimeout: setTimeout$1, clearTimeout: clearTimeout$1 } = require("node:timers");
|
|
34875
34876
|
const { InvalidArgumentError, UndiciError } = require_errors$1();
|
|
34876
34877
|
const { hashId, isUrlExcludedFactory, normalizeHeaders, createHeaderFilters } = require_snapshot_utils();
|
|
@@ -35149,7 +35150,7 @@ var require_snapshot_recorder = /* @__PURE__ */ require_chunk.__commonJSMin(((ex
|
|
|
35149
35150
|
const path$3 = filePath || this.#snapshotPath;
|
|
35150
35151
|
if (!path$3) throw new InvalidArgumentError("Snapshot path is required");
|
|
35151
35152
|
const resolvedPath = resolve(path$3);
|
|
35152
|
-
await mkdir$1(dirname$
|
|
35153
|
+
await mkdir$1(dirname$2(resolvedPath), { recursive: true });
|
|
35153
35154
|
const data$1 = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
|
|
35154
35155
|
hash,
|
|
35155
35156
|
snapshot
|
|
@@ -83446,6 +83447,19 @@ async function getOrCreateMcpClient(defKey, def) {
|
|
|
83446
83447
|
mcpClientConnecting.delete(defKey);
|
|
83447
83448
|
}
|
|
83448
83449
|
}
|
|
83450
|
+
async function releaseMcpClient(defKey) {
|
|
83451
|
+
const entry = mcpClientPool.get(defKey);
|
|
83452
|
+
if (!entry) return;
|
|
83453
|
+
entry.refCount -= 1;
|
|
83454
|
+
if (entry.refCount <= 0) {
|
|
83455
|
+
mcpClientPool.delete(defKey);
|
|
83456
|
+
try {
|
|
83457
|
+
await entry.client.close();
|
|
83458
|
+
} catch (err) {
|
|
83459
|
+
console.error("Error closing MCP client:", err);
|
|
83460
|
+
}
|
|
83461
|
+
}
|
|
83462
|
+
}
|
|
83449
83463
|
var cleanupAllPooledClients = async () => {
|
|
83450
83464
|
const entries = Array.from(mcpClientPool.entries());
|
|
83451
83465
|
mcpClientPool.clear();
|
|
@@ -83503,7 +83517,12 @@ async function composeMcpDepTools(mcpConfig, filterIn) {
|
|
|
83503
83517
|
console.error(`Error creating MCP client for ${name}:`, error);
|
|
83504
83518
|
}
|
|
83505
83519
|
}
|
|
83506
|
-
const cleanupClients = async () => {
|
|
83520
|
+
const cleanupClients = async () => {
|
|
83521
|
+
await Promise.all(acquiredKeys.map((k) => releaseMcpClient(k)));
|
|
83522
|
+
acquiredKeys.length = 0;
|
|
83523
|
+
Object.keys(allTools).forEach((key) => delete allTools[key]);
|
|
83524
|
+
Object.keys(allClients).forEach((key) => delete allClients[key]);
|
|
83525
|
+
};
|
|
83507
83526
|
return {
|
|
83508
83527
|
tools: allTools,
|
|
83509
83528
|
clients: allClients,
|
|
@@ -86305,6 +86324,17 @@ var ComposableMCPServer = class extends _modelcontextprotocol_sdk_server_index_j
|
|
|
86305
86324
|
server: this,
|
|
86306
86325
|
toolNames: Object.keys(allTools)
|
|
86307
86326
|
});
|
|
86327
|
+
this.onclose = async () => {
|
|
86328
|
+
await cleanupClients();
|
|
86329
|
+
await this.disposePlugins();
|
|
86330
|
+
await this.logger.info(`[${name}] Event: closed - cleaned up dependent clients and plugins`);
|
|
86331
|
+
};
|
|
86332
|
+
this.onerror = async (error) => {
|
|
86333
|
+
await this.logger.error(`[${name}] Event: error - ${error?.stack ?? String(error)}`);
|
|
86334
|
+
await cleanupClients();
|
|
86335
|
+
await this.disposePlugins();
|
|
86336
|
+
await this.logger.info(`[${name}] Action: cleaned up dependent clients and plugins`);
|
|
86337
|
+
};
|
|
86308
86338
|
const toolNameToDetailList = Object.entries(allTools);
|
|
86309
86339
|
const publicToolNames = this.getPublicToolNames();
|
|
86310
86340
|
const hiddenToolNames = this.getHiddenToolNames();
|
|
@@ -86896,14 +86926,20 @@ var ConnectionManager = class {
|
|
|
86896
86926
|
//#endregion
|
|
86897
86927
|
//#region src/utils/cors.ts
|
|
86898
86928
|
/**
|
|
86899
|
-
* Set CORS headers and handle preflight requests
|
|
86900
|
-
*
|
|
86929
|
+
* Set CORS headers and handle preflight requests.
|
|
86930
|
+
*
|
|
86931
|
+
* Uses the browser's requested headers (Access-Control-Request-Headers) when present
|
|
86932
|
+
* to avoid mismatches that can break CORS preflight (e.g. 'user-agent').
|
|
86933
|
+
*
|
|
86934
|
+
* Returns true if request was handled (preflight), false otherwise.
|
|
86901
86935
|
*/
|
|
86902
|
-
function handleCors(
|
|
86936
|
+
function handleCors(req, res) {
|
|
86903
86937
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
86904
86938
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
86905
|
-
|
|
86906
|
-
|
|
86939
|
+
const requested = req.headers["access-control-request-headers"];
|
|
86940
|
+
const requestedValue = Array.isArray(requested) ? requested.join(", ") : requested;
|
|
86941
|
+
res.setHeader("Access-Control-Allow-Headers", requestedValue ?? "Content-Type, mcp-session-id, mcp-protocol-version");
|
|
86942
|
+
if (req.method === "OPTIONS") {
|
|
86907
86943
|
res.statusCode = 204;
|
|
86908
86944
|
res.end();
|
|
86909
86945
|
return true;
|
|
@@ -86929,7 +86965,7 @@ async function setupMcpMiddleware(middlewares, serverContext) {
|
|
|
86929
86965
|
middlewares.use(async (req, res, next$1) => {
|
|
86930
86966
|
const url$1 = req.url || "";
|
|
86931
86967
|
if (url$1.startsWith("/__mcp__")) {
|
|
86932
|
-
if (handleCors(
|
|
86968
|
+
if (handleCors(req, res)) return;
|
|
86933
86969
|
}
|
|
86934
86970
|
if (url$1.startsWith("/__mcp__") && !url$1.startsWith("/__mcp__/sse") && !url$1.startsWith("/__mcp__/messages")) {
|
|
86935
86971
|
if (req.method === "POST") await handleStreamableHttpPost(req, res, serverContext, connectionManager);
|
|
@@ -87166,7 +87202,7 @@ function setupInspectorMiddleware(middlewares, config) {
|
|
|
87166
87202
|
let filesChecked = false;
|
|
87167
87203
|
middlewares.use((req, res, next$1) => {
|
|
87168
87204
|
if (req.url?.startsWith("/__inspector__")) {
|
|
87169
|
-
if (handleCors(
|
|
87205
|
+
if (handleCors(req, res)) return;
|
|
87170
87206
|
}
|
|
87171
87207
|
if (!filesChecked) {
|
|
87172
87208
|
cachedScript = getInspectorScript();
|
|
@@ -87209,7 +87245,7 @@ function setupInspectorMiddleware(middlewares, config) {
|
|
|
87209
87245
|
}
|
|
87210
87246
|
|
|
87211
87247
|
//#endregion
|
|
87212
|
-
//#region ../../node_modules/.pnpm/@mcpc-tech+acp-ai-provider@0.1.
|
|
87248
|
+
//#region ../../node_modules/.pnpm/@mcpc-tech+acp-ai-provider@0.1.43/node_modules/@mcpc-tech/acp-ai-provider/index.mjs
|
|
87213
87249
|
(0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
|
|
87214
87250
|
function formatToolError(toolResult) {
|
|
87215
87251
|
if (!toolResult || toolResult.length === 0) return "Unknown tool error";
|
|
@@ -87652,7 +87688,6 @@ var ACPLanguageModel = class {
|
|
|
87652
87688
|
*/
|
|
87653
87689
|
parseToolCall(update$1) {
|
|
87654
87690
|
if (update$1.sessionUpdate !== "tool_call") throw new Error("Invalid update type for parseToolCall");
|
|
87655
|
-
console.log("Parsing tool call update:", JSON.stringify(update$1, null, 2));
|
|
87656
87691
|
return {
|
|
87657
87692
|
toolCallId: update$1.toolCallId,
|
|
87658
87693
|
toolName: update$1.title || update$1.toolCallId,
|
|
@@ -87954,11 +87989,6 @@ var ACPLanguageModel = class {
|
|
|
87954
87989
|
this.currentThinkingId = null;
|
|
87955
87990
|
}
|
|
87956
87991
|
const { toolCallId, toolName, toolInput } = this.parseToolCall(update$1);
|
|
87957
|
-
console.log(`Parsing tool call: ${JSON.stringify({
|
|
87958
|
-
toolCallId,
|
|
87959
|
-
toolName,
|
|
87960
|
-
toolInput
|
|
87961
|
-
}, null, 2)}`);
|
|
87962
87992
|
const existingToolCall = this.toolCallsMap.get(toolCallId);
|
|
87963
87993
|
const hasInput = toolInput && typeof toolInput === "object" && Object.keys(toolInput).length > 0;
|
|
87964
87994
|
if (!existingToolCall) {
|
|
@@ -87985,13 +88015,14 @@ var ACPLanguageModel = class {
|
|
|
87985
88015
|
});
|
|
87986
88016
|
} else if (!existingToolCall.inputAvailable && hasInput) {
|
|
87987
88017
|
existingToolCall.inputAvailable = true;
|
|
88018
|
+
if (update$1.title && existingToolCall.name !== update$1.title && update$1.title !== toolCallId) existingToolCall.name = update$1.title;
|
|
87988
88019
|
controller.enqueue({
|
|
87989
88020
|
type: "tool-call",
|
|
87990
88021
|
toolCallId,
|
|
87991
88022
|
toolName: ACP_PROVIDER_AGENT_DYNAMIC_TOOL_NAME2,
|
|
87992
88023
|
input: JSON.stringify({
|
|
87993
88024
|
toolCallId,
|
|
87994
|
-
toolName,
|
|
88025
|
+
toolName: existingToolCall.name,
|
|
87995
88026
|
args: toolInput
|
|
87996
88027
|
})
|
|
87997
88028
|
});
|
|
@@ -88018,13 +88049,14 @@ var ACPLanguageModel = class {
|
|
|
88018
88049
|
}
|
|
88019
88050
|
if (!toolInfo.inputAvailable) {
|
|
88020
88051
|
toolInfo.inputAvailable = true;
|
|
88052
|
+
if (update$1.title && toolInfo.name !== update$1.title && update$1.title !== toolCallId) toolInfo.name = update$1.title;
|
|
88021
88053
|
controller.enqueue({
|
|
88022
88054
|
type: "tool-call",
|
|
88023
88055
|
toolCallId,
|
|
88024
88056
|
toolName: ACP_PROVIDER_AGENT_DYNAMIC_TOOL_NAME2,
|
|
88025
88057
|
input: JSON.stringify({
|
|
88026
88058
|
toolCallId,
|
|
88027
|
-
toolName,
|
|
88059
|
+
toolName: toolInfo.name,
|
|
88028
88060
|
args: {}
|
|
88029
88061
|
})
|
|
88030
88062
|
});
|
|
@@ -88050,13 +88082,14 @@ var ACPLanguageModel = class {
|
|
|
88050
88082
|
});
|
|
88051
88083
|
} else if (!toolInfo.inputAvailable) {
|
|
88052
88084
|
toolInfo.inputAvailable = true;
|
|
88085
|
+
if (update$1.title && toolInfo.name !== update$1.title && update$1.title !== toolCallId) toolInfo.name = update$1.title;
|
|
88053
88086
|
controller.enqueue({
|
|
88054
88087
|
type: "tool-call",
|
|
88055
88088
|
toolCallId,
|
|
88056
88089
|
toolName: ACP_PROVIDER_AGENT_DYNAMIC_TOOL_NAME2,
|
|
88057
88090
|
input: JSON.stringify({
|
|
88058
88091
|
toolCallId,
|
|
88059
|
-
toolName,
|
|
88092
|
+
toolName: toolInfo.name,
|
|
88060
88093
|
args: {}
|
|
88061
88094
|
})
|
|
88062
88095
|
});
|
|
@@ -88083,7 +88116,6 @@ var ACPLanguageModel = class {
|
|
|
88083
88116
|
try {
|
|
88084
88117
|
await this.ensureConnected();
|
|
88085
88118
|
const promptContent = convertAiSdkMessagesToAcp(options, this.isFreshSession);
|
|
88086
|
-
console.log(`###########`, promptContent);
|
|
88087
88119
|
this.isFreshSession = false;
|
|
88088
88120
|
let accumulatedText = "";
|
|
88089
88121
|
const toolCalls = [];
|
|
@@ -88290,6 +88322,36 @@ function createACPProvider(config) {
|
|
|
88290
88322
|
return new ACPProvider(config);
|
|
88291
88323
|
}
|
|
88292
88324
|
|
|
88325
|
+
//#endregion
|
|
88326
|
+
//#region src/utils/npm-package.ts
|
|
88327
|
+
/**
|
|
88328
|
+
* Resolve npm package bin entry point
|
|
88329
|
+
* Returns the absolute path to the bin file, or null if resolution fails
|
|
88330
|
+
*/
|
|
88331
|
+
function resolveNpmPackageBin(packageName) {
|
|
88332
|
+
try {
|
|
88333
|
+
const packageJsonPath = (0, module$1.createRequire)(require("url").pathToFileURL(__filename).href).resolve(`${packageName}/package.json`);
|
|
88334
|
+
const packageJson = JSON.parse((0, fs.readFileSync)(packageJsonPath, "utf-8"));
|
|
88335
|
+
let binPath;
|
|
88336
|
+
if (typeof packageJson.bin === "string") binPath = packageJson.bin;
|
|
88337
|
+
else if (typeof packageJson.bin === "object") {
|
|
88338
|
+
const binEntries = Object.entries(packageJson.bin);
|
|
88339
|
+
const matchingEntry = binEntries.find(([name]) => name === packageJson.name.split("/").pop());
|
|
88340
|
+
binPath = matchingEntry ? matchingEntry[1] : binEntries[0]?.[1];
|
|
88341
|
+
}
|
|
88342
|
+
if (!binPath) {
|
|
88343
|
+
console.warn(`[dev-inspector] [acp] No bin entry found in ${packageName}/package.json`);
|
|
88344
|
+
return null;
|
|
88345
|
+
}
|
|
88346
|
+
const binFullPath = (0, path.join)((0, path.dirname)(packageJsonPath), binPath);
|
|
88347
|
+
console.log(`[dev-inspector] [acp] Resolved ${packageName} bin to: ${binFullPath}`);
|
|
88348
|
+
return binFullPath;
|
|
88349
|
+
} catch (error) {
|
|
88350
|
+
console.warn(`[dev-inspector] [acp] Failed to resolve npm package ${packageName}:`, error);
|
|
88351
|
+
return null;
|
|
88352
|
+
}
|
|
88353
|
+
}
|
|
88354
|
+
|
|
88293
88355
|
//#endregion
|
|
88294
88356
|
//#region src/middleware/acp-middleware.ts
|
|
88295
88357
|
/**
|
|
@@ -88358,10 +88420,13 @@ async function loadMcpToolsV5(transport) {
|
|
|
88358
88420
|
inputSchema: (0, ai.jsonSchema)(toolInfo.inputSchema),
|
|
88359
88421
|
execute: async (args) => {
|
|
88360
88422
|
console.log(`[dev-inspector] [acp] Executing MCP tool: ${toolName}`);
|
|
88361
|
-
|
|
88423
|
+
const result = await callMcpMethodViaTransport(transport, "tools/call", {
|
|
88362
88424
|
name: toolName,
|
|
88363
88425
|
arguments: args
|
|
88364
88426
|
});
|
|
88427
|
+
const parsedResult = _modelcontextprotocol_sdk_types_js.CallToolResultSchema.safeParse(result);
|
|
88428
|
+
if (!parsedResult.success) return result;
|
|
88429
|
+
return parsedResult.data?.content?.map((item) => item?.text).join("\n");
|
|
88365
88430
|
}
|
|
88366
88431
|
});
|
|
88367
88432
|
}
|
|
@@ -88405,7 +88470,7 @@ function setupAcpMiddleware(middlewares, serverContext, acpOptions) {
|
|
|
88405
88470
|
* Returns: { sessionId }
|
|
88406
88471
|
*/
|
|
88407
88472
|
middlewares.use("/api/acp/init-session", async (req, res) => {
|
|
88408
|
-
if (handleCors(
|
|
88473
|
+
if (handleCors(req, res)) return;
|
|
88409
88474
|
if (req.method !== "POST") {
|
|
88410
88475
|
res.statusCode = 405;
|
|
88411
88476
|
res.end("Method Not Allowed");
|
|
@@ -88451,9 +88516,19 @@ function setupAcpMiddleware(middlewares, serverContext, acpOptions) {
|
|
|
88451
88516
|
return;
|
|
88452
88517
|
}
|
|
88453
88518
|
console.log(`[dev-inspector] [acp] Creating new global provider for ${agent.name}`);
|
|
88519
|
+
let command = agent.command;
|
|
88520
|
+
let args = agent.args;
|
|
88521
|
+
if (agent.npmPackage) {
|
|
88522
|
+
const binPath = resolveNpmPackageBin(agent.npmPackage);
|
|
88523
|
+
if (binPath) {
|
|
88524
|
+
command = binPath;
|
|
88525
|
+
args = agent.npmArgs || [];
|
|
88526
|
+
console.log(`[dev-inspector] [acp] Using resolved npm package: ${agent.npmPackage}`);
|
|
88527
|
+
} else console.log(`[dev-inspector] [acp] Failed to resolve npm package, falling back to: ${agent.command}`);
|
|
88528
|
+
}
|
|
88454
88529
|
provider = createACPProvider({
|
|
88455
|
-
command
|
|
88456
|
-
args
|
|
88530
|
+
command,
|
|
88531
|
+
args,
|
|
88457
88532
|
env: {
|
|
88458
88533
|
...process.env,
|
|
88459
88534
|
...envVars
|
|
@@ -88522,7 +88597,7 @@ function setupAcpMiddleware(middlewares, serverContext, acpOptions) {
|
|
|
88522
88597
|
* Body: { sessionId }
|
|
88523
88598
|
*/
|
|
88524
88599
|
middlewares.use("/api/acp/cleanup-session", async (req, res) => {
|
|
88525
|
-
if (handleCors(
|
|
88600
|
+
if (handleCors(req, res)) return;
|
|
88526
88601
|
if (req.method !== "POST") {
|
|
88527
88602
|
res.statusCode = 405;
|
|
88528
88603
|
res.end("Method Not Allowed");
|
|
@@ -88565,7 +88640,7 @@ function setupAcpMiddleware(middlewares, serverContext, acpOptions) {
|
|
|
88565
88640
|
* Body: { messages, agent, envVars, sessionId? }
|
|
88566
88641
|
*/
|
|
88567
88642
|
middlewares.use("/api/acp/chat", async (req, res) => {
|
|
88568
|
-
if (handleCors(
|
|
88643
|
+
if (handleCors(req, res)) return;
|
|
88569
88644
|
if (req.method !== "POST") {
|
|
88570
88645
|
res.statusCode = 405;
|
|
88571
88646
|
res.end("Method Not Allowed");
|
|
@@ -88588,9 +88663,19 @@ function setupAcpMiddleware(middlewares, serverContext, acpOptions) {
|
|
|
88588
88663
|
shouldCleanupProvider = false;
|
|
88589
88664
|
} else {
|
|
88590
88665
|
console.log(`[dev-inspector] [acp] Creating new provider (no session found or provided)`);
|
|
88666
|
+
let command = agent.command;
|
|
88667
|
+
let args = agent.args;
|
|
88668
|
+
if (agent.npmPackage) {
|
|
88669
|
+
const binPath = resolveNpmPackageBin(agent.npmPackage);
|
|
88670
|
+
if (binPath) {
|
|
88671
|
+
command = binPath;
|
|
88672
|
+
args = agent.npmArgs || [];
|
|
88673
|
+
console.log(`[dev-inspector] [acp] Using resolved npm package: ${agent.npmPackage}`);
|
|
88674
|
+
}
|
|
88675
|
+
}
|
|
88591
88676
|
provider = createACPProvider({
|
|
88592
|
-
command
|
|
88593
|
-
args
|
|
88677
|
+
command,
|
|
88678
|
+
args,
|
|
88594
88679
|
env: {
|
|
88595
88680
|
...process.env,
|
|
88596
88681
|
...envVars
|
package/dist/config-updater.js
CHANGED
|
@@ -2,7 +2,7 @@ import { createRequire } from "node:module";
|
|
|
2
2
|
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
3
3
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
4
4
|
import { randomUUID } from "crypto";
|
|
5
|
-
import { CallToolRequestSchema, CompleteRequestSchema, ErrorCode, GetPromptRequestSchema, JSONRPCMessageSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, McpError, PingRequestSchema, ReadResourceRequestSchema, SetLevelRequestSchema, SubscribeRequestSchema, UnsubscribeRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { CallToolRequestSchema, CallToolResultSchema, CompleteRequestSchema, ErrorCode, GetPromptRequestSchema, JSONRPCMessageSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, McpError, PingRequestSchema, ReadResourceRequestSchema, SetLevelRequestSchema, SubscribeRequestSchema, UnsubscribeRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
6
6
|
import z$1, { z } from "zod";
|
|
7
7
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
8
8
|
import { Readable, Writable } from "node:stream";
|
|
@@ -18,7 +18,7 @@ import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
|
|
18
18
|
import process$1, { cwd } from "node:process";
|
|
19
19
|
import { homedir } from "os";
|
|
20
20
|
import { execSync } from "child_process";
|
|
21
|
-
import fs, { existsSync } from "fs";
|
|
21
|
+
import fs, { existsSync, readFileSync } from "fs";
|
|
22
22
|
import * as http from "http";
|
|
23
23
|
import * as https from "https";
|
|
24
24
|
import * as zlib from "zlib";
|
|
@@ -28,6 +28,7 @@ import { fileURLToPath as fileURLToPath$1 } from "url";
|
|
|
28
28
|
import { asSchema, convertToModelMessages, jsonSchema, streamText, tool } from "ai";
|
|
29
29
|
import { ClientSideConnection, PROTOCOL_VERSION, ndJsonStream, planEntrySchema } from "@agentclientprotocol/sdk";
|
|
30
30
|
import { spawn } from "node:child_process";
|
|
31
|
+
import { createRequire as createRequire$1 } from "module";
|
|
31
32
|
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
32
33
|
|
|
33
34
|
//#region rolldown:runtime
|
|
@@ -83481,6 +83482,19 @@ async function getOrCreateMcpClient(defKey, def) {
|
|
|
83481
83482
|
mcpClientConnecting.delete(defKey);
|
|
83482
83483
|
}
|
|
83483
83484
|
}
|
|
83485
|
+
async function releaseMcpClient(defKey) {
|
|
83486
|
+
const entry = mcpClientPool.get(defKey);
|
|
83487
|
+
if (!entry) return;
|
|
83488
|
+
entry.refCount -= 1;
|
|
83489
|
+
if (entry.refCount <= 0) {
|
|
83490
|
+
mcpClientPool.delete(defKey);
|
|
83491
|
+
try {
|
|
83492
|
+
await entry.client.close();
|
|
83493
|
+
} catch (err) {
|
|
83494
|
+
console.error("Error closing MCP client:", err);
|
|
83495
|
+
}
|
|
83496
|
+
}
|
|
83497
|
+
}
|
|
83484
83498
|
var cleanupAllPooledClients = async () => {
|
|
83485
83499
|
const entries = Array.from(mcpClientPool.entries());
|
|
83486
83500
|
mcpClientPool.clear();
|
|
@@ -83538,7 +83552,12 @@ async function composeMcpDepTools(mcpConfig, filterIn) {
|
|
|
83538
83552
|
console.error(`Error creating MCP client for ${name}:`, error);
|
|
83539
83553
|
}
|
|
83540
83554
|
}
|
|
83541
|
-
const cleanupClients = async () => {
|
|
83555
|
+
const cleanupClients = async () => {
|
|
83556
|
+
await Promise.all(acquiredKeys.map((k) => releaseMcpClient(k)));
|
|
83557
|
+
acquiredKeys.length = 0;
|
|
83558
|
+
Object.keys(allTools).forEach((key) => delete allTools[key]);
|
|
83559
|
+
Object.keys(allClients).forEach((key) => delete allClients[key]);
|
|
83560
|
+
};
|
|
83542
83561
|
return {
|
|
83543
83562
|
tools: allTools,
|
|
83544
83563
|
clients: allClients,
|
|
@@ -86340,6 +86359,17 @@ var ComposableMCPServer = class extends Server {
|
|
|
86340
86359
|
server: this,
|
|
86341
86360
|
toolNames: Object.keys(allTools)
|
|
86342
86361
|
});
|
|
86362
|
+
this.onclose = async () => {
|
|
86363
|
+
await cleanupClients();
|
|
86364
|
+
await this.disposePlugins();
|
|
86365
|
+
await this.logger.info(`[${name}] Event: closed - cleaned up dependent clients and plugins`);
|
|
86366
|
+
};
|
|
86367
|
+
this.onerror = async (error) => {
|
|
86368
|
+
await this.logger.error(`[${name}] Event: error - ${error?.stack ?? String(error)}`);
|
|
86369
|
+
await cleanupClients();
|
|
86370
|
+
await this.disposePlugins();
|
|
86371
|
+
await this.logger.info(`[${name}] Action: cleaned up dependent clients and plugins`);
|
|
86372
|
+
};
|
|
86343
86373
|
const toolNameToDetailList = Object.entries(allTools);
|
|
86344
86374
|
const publicToolNames = this.getPublicToolNames();
|
|
86345
86375
|
const hiddenToolNames = this.getHiddenToolNames();
|
|
@@ -86931,14 +86961,20 @@ var ConnectionManager = class {
|
|
|
86931
86961
|
//#endregion
|
|
86932
86962
|
//#region src/utils/cors.ts
|
|
86933
86963
|
/**
|
|
86934
|
-
* Set CORS headers and handle preflight requests
|
|
86935
|
-
*
|
|
86964
|
+
* Set CORS headers and handle preflight requests.
|
|
86965
|
+
*
|
|
86966
|
+
* Uses the browser's requested headers (Access-Control-Request-Headers) when present
|
|
86967
|
+
* to avoid mismatches that can break CORS preflight (e.g. 'user-agent').
|
|
86968
|
+
*
|
|
86969
|
+
* Returns true if request was handled (preflight), false otherwise.
|
|
86936
86970
|
*/
|
|
86937
|
-
function handleCors(
|
|
86971
|
+
function handleCors(req, res) {
|
|
86938
86972
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
86939
86973
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
|
|
86940
|
-
|
|
86941
|
-
|
|
86974
|
+
const requested = req.headers["access-control-request-headers"];
|
|
86975
|
+
const requestedValue = Array.isArray(requested) ? requested.join(", ") : requested;
|
|
86976
|
+
res.setHeader("Access-Control-Allow-Headers", requestedValue ?? "Content-Type, mcp-session-id, mcp-protocol-version");
|
|
86977
|
+
if (req.method === "OPTIONS") {
|
|
86942
86978
|
res.statusCode = 204;
|
|
86943
86979
|
res.end();
|
|
86944
86980
|
return true;
|
|
@@ -86964,7 +87000,7 @@ async function setupMcpMiddleware(middlewares, serverContext) {
|
|
|
86964
87000
|
middlewares.use(async (req, res, next$1) => {
|
|
86965
87001
|
const url = req.url || "";
|
|
86966
87002
|
if (url.startsWith("/__mcp__")) {
|
|
86967
|
-
if (handleCors(
|
|
87003
|
+
if (handleCors(req, res)) return;
|
|
86968
87004
|
}
|
|
86969
87005
|
if (url.startsWith("/__mcp__") && !url.startsWith("/__mcp__/sse") && !url.startsWith("/__mcp__/messages")) {
|
|
86970
87006
|
if (req.method === "POST") await handleStreamableHttpPost(req, res, serverContext, connectionManager);
|
|
@@ -87201,7 +87237,7 @@ function setupInspectorMiddleware(middlewares, config) {
|
|
|
87201
87237
|
let filesChecked = false;
|
|
87202
87238
|
middlewares.use((req, res, next$1) => {
|
|
87203
87239
|
if (req.url?.startsWith("/__inspector__")) {
|
|
87204
|
-
if (handleCors(
|
|
87240
|
+
if (handleCors(req, res)) return;
|
|
87205
87241
|
}
|
|
87206
87242
|
if (!filesChecked) {
|
|
87207
87243
|
cachedScript = getInspectorScript();
|
|
@@ -87244,7 +87280,7 @@ function setupInspectorMiddleware(middlewares, config) {
|
|
|
87244
87280
|
}
|
|
87245
87281
|
|
|
87246
87282
|
//#endregion
|
|
87247
|
-
//#region ../../node_modules/.pnpm/@mcpc-tech+acp-ai-provider@0.1.
|
|
87283
|
+
//#region ../../node_modules/.pnpm/@mcpc-tech+acp-ai-provider@0.1.43/node_modules/@mcpc-tech/acp-ai-provider/index.mjs
|
|
87248
87284
|
createRequire(import.meta.url);
|
|
87249
87285
|
function formatToolError(toolResult) {
|
|
87250
87286
|
if (!toolResult || toolResult.length === 0) return "Unknown tool error";
|
|
@@ -87687,7 +87723,6 @@ var ACPLanguageModel = class {
|
|
|
87687
87723
|
*/
|
|
87688
87724
|
parseToolCall(update$1) {
|
|
87689
87725
|
if (update$1.sessionUpdate !== "tool_call") throw new Error("Invalid update type for parseToolCall");
|
|
87690
|
-
console.log("Parsing tool call update:", JSON.stringify(update$1, null, 2));
|
|
87691
87726
|
return {
|
|
87692
87727
|
toolCallId: update$1.toolCallId,
|
|
87693
87728
|
toolName: update$1.title || update$1.toolCallId,
|
|
@@ -87989,11 +88024,6 @@ var ACPLanguageModel = class {
|
|
|
87989
88024
|
this.currentThinkingId = null;
|
|
87990
88025
|
}
|
|
87991
88026
|
const { toolCallId, toolName, toolInput } = this.parseToolCall(update$1);
|
|
87992
|
-
console.log(`Parsing tool call: ${JSON.stringify({
|
|
87993
|
-
toolCallId,
|
|
87994
|
-
toolName,
|
|
87995
|
-
toolInput
|
|
87996
|
-
}, null, 2)}`);
|
|
87997
88027
|
const existingToolCall = this.toolCallsMap.get(toolCallId);
|
|
87998
88028
|
const hasInput = toolInput && typeof toolInput === "object" && Object.keys(toolInput).length > 0;
|
|
87999
88029
|
if (!existingToolCall) {
|
|
@@ -88020,13 +88050,14 @@ var ACPLanguageModel = class {
|
|
|
88020
88050
|
});
|
|
88021
88051
|
} else if (!existingToolCall.inputAvailable && hasInput) {
|
|
88022
88052
|
existingToolCall.inputAvailable = true;
|
|
88053
|
+
if (update$1.title && existingToolCall.name !== update$1.title && update$1.title !== toolCallId) existingToolCall.name = update$1.title;
|
|
88023
88054
|
controller.enqueue({
|
|
88024
88055
|
type: "tool-call",
|
|
88025
88056
|
toolCallId,
|
|
88026
88057
|
toolName: ACP_PROVIDER_AGENT_DYNAMIC_TOOL_NAME2,
|
|
88027
88058
|
input: JSON.stringify({
|
|
88028
88059
|
toolCallId,
|
|
88029
|
-
toolName,
|
|
88060
|
+
toolName: existingToolCall.name,
|
|
88030
88061
|
args: toolInput
|
|
88031
88062
|
})
|
|
88032
88063
|
});
|
|
@@ -88053,13 +88084,14 @@ var ACPLanguageModel = class {
|
|
|
88053
88084
|
}
|
|
88054
88085
|
if (!toolInfo.inputAvailable) {
|
|
88055
88086
|
toolInfo.inputAvailable = true;
|
|
88087
|
+
if (update$1.title && toolInfo.name !== update$1.title && update$1.title !== toolCallId) toolInfo.name = update$1.title;
|
|
88056
88088
|
controller.enqueue({
|
|
88057
88089
|
type: "tool-call",
|
|
88058
88090
|
toolCallId,
|
|
88059
88091
|
toolName: ACP_PROVIDER_AGENT_DYNAMIC_TOOL_NAME2,
|
|
88060
88092
|
input: JSON.stringify({
|
|
88061
88093
|
toolCallId,
|
|
88062
|
-
toolName,
|
|
88094
|
+
toolName: toolInfo.name,
|
|
88063
88095
|
args: {}
|
|
88064
88096
|
})
|
|
88065
88097
|
});
|
|
@@ -88085,13 +88117,14 @@ var ACPLanguageModel = class {
|
|
|
88085
88117
|
});
|
|
88086
88118
|
} else if (!toolInfo.inputAvailable) {
|
|
88087
88119
|
toolInfo.inputAvailable = true;
|
|
88120
|
+
if (update$1.title && toolInfo.name !== update$1.title && update$1.title !== toolCallId) toolInfo.name = update$1.title;
|
|
88088
88121
|
controller.enqueue({
|
|
88089
88122
|
type: "tool-call",
|
|
88090
88123
|
toolCallId,
|
|
88091
88124
|
toolName: ACP_PROVIDER_AGENT_DYNAMIC_TOOL_NAME2,
|
|
88092
88125
|
input: JSON.stringify({
|
|
88093
88126
|
toolCallId,
|
|
88094
|
-
toolName,
|
|
88127
|
+
toolName: toolInfo.name,
|
|
88095
88128
|
args: {}
|
|
88096
88129
|
})
|
|
88097
88130
|
});
|
|
@@ -88118,7 +88151,6 @@ var ACPLanguageModel = class {
|
|
|
88118
88151
|
try {
|
|
88119
88152
|
await this.ensureConnected();
|
|
88120
88153
|
const promptContent = convertAiSdkMessagesToAcp(options, this.isFreshSession);
|
|
88121
|
-
console.log(`###########`, promptContent);
|
|
88122
88154
|
this.isFreshSession = false;
|
|
88123
88155
|
let accumulatedText = "";
|
|
88124
88156
|
const toolCalls = [];
|
|
@@ -88325,6 +88357,36 @@ function createACPProvider(config) {
|
|
|
88325
88357
|
return new ACPProvider(config);
|
|
88326
88358
|
}
|
|
88327
88359
|
|
|
88360
|
+
//#endregion
|
|
88361
|
+
//#region src/utils/npm-package.ts
|
|
88362
|
+
/**
|
|
88363
|
+
* Resolve npm package bin entry point
|
|
88364
|
+
* Returns the absolute path to the bin file, or null if resolution fails
|
|
88365
|
+
*/
|
|
88366
|
+
function resolveNpmPackageBin(packageName) {
|
|
88367
|
+
try {
|
|
88368
|
+
const packageJsonPath = createRequire$1(import.meta.url).resolve(`${packageName}/package.json`);
|
|
88369
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
88370
|
+
let binPath;
|
|
88371
|
+
if (typeof packageJson.bin === "string") binPath = packageJson.bin;
|
|
88372
|
+
else if (typeof packageJson.bin === "object") {
|
|
88373
|
+
const binEntries = Object.entries(packageJson.bin);
|
|
88374
|
+
const matchingEntry = binEntries.find(([name]) => name === packageJson.name.split("/").pop());
|
|
88375
|
+
binPath = matchingEntry ? matchingEntry[1] : binEntries[0]?.[1];
|
|
88376
|
+
}
|
|
88377
|
+
if (!binPath) {
|
|
88378
|
+
console.warn(`[dev-inspector] [acp] No bin entry found in ${packageName}/package.json`);
|
|
88379
|
+
return null;
|
|
88380
|
+
}
|
|
88381
|
+
const binFullPath = join(dirname(packageJsonPath), binPath);
|
|
88382
|
+
console.log(`[dev-inspector] [acp] Resolved ${packageName} bin to: ${binFullPath}`);
|
|
88383
|
+
return binFullPath;
|
|
88384
|
+
} catch (error) {
|
|
88385
|
+
console.warn(`[dev-inspector] [acp] Failed to resolve npm package ${packageName}:`, error);
|
|
88386
|
+
return null;
|
|
88387
|
+
}
|
|
88388
|
+
}
|
|
88389
|
+
|
|
88328
88390
|
//#endregion
|
|
88329
88391
|
//#region src/middleware/acp-middleware.ts
|
|
88330
88392
|
/**
|
|
@@ -88393,10 +88455,13 @@ async function loadMcpToolsV5(transport) {
|
|
|
88393
88455
|
inputSchema: jsonSchema(toolInfo.inputSchema),
|
|
88394
88456
|
execute: async (args) => {
|
|
88395
88457
|
console.log(`[dev-inspector] [acp] Executing MCP tool: ${toolName}`);
|
|
88396
|
-
|
|
88458
|
+
const result = await callMcpMethodViaTransport(transport, "tools/call", {
|
|
88397
88459
|
name: toolName,
|
|
88398
88460
|
arguments: args
|
|
88399
88461
|
});
|
|
88462
|
+
const parsedResult = CallToolResultSchema.safeParse(result);
|
|
88463
|
+
if (!parsedResult.success) return result;
|
|
88464
|
+
return parsedResult.data?.content?.map((item) => item?.text).join("\n");
|
|
88400
88465
|
}
|
|
88401
88466
|
});
|
|
88402
88467
|
}
|
|
@@ -88440,7 +88505,7 @@ function setupAcpMiddleware(middlewares, serverContext, acpOptions) {
|
|
|
88440
88505
|
* Returns: { sessionId }
|
|
88441
88506
|
*/
|
|
88442
88507
|
middlewares.use("/api/acp/init-session", async (req, res) => {
|
|
88443
|
-
if (handleCors(
|
|
88508
|
+
if (handleCors(req, res)) return;
|
|
88444
88509
|
if (req.method !== "POST") {
|
|
88445
88510
|
res.statusCode = 405;
|
|
88446
88511
|
res.end("Method Not Allowed");
|
|
@@ -88486,9 +88551,19 @@ function setupAcpMiddleware(middlewares, serverContext, acpOptions) {
|
|
|
88486
88551
|
return;
|
|
88487
88552
|
}
|
|
88488
88553
|
console.log(`[dev-inspector] [acp] Creating new global provider for ${agent.name}`);
|
|
88554
|
+
let command = agent.command;
|
|
88555
|
+
let args = agent.args;
|
|
88556
|
+
if (agent.npmPackage) {
|
|
88557
|
+
const binPath = resolveNpmPackageBin(agent.npmPackage);
|
|
88558
|
+
if (binPath) {
|
|
88559
|
+
command = binPath;
|
|
88560
|
+
args = agent.npmArgs || [];
|
|
88561
|
+
console.log(`[dev-inspector] [acp] Using resolved npm package: ${agent.npmPackage}`);
|
|
88562
|
+
} else console.log(`[dev-inspector] [acp] Failed to resolve npm package, falling back to: ${agent.command}`);
|
|
88563
|
+
}
|
|
88489
88564
|
provider = createACPProvider({
|
|
88490
|
-
command
|
|
88491
|
-
args
|
|
88565
|
+
command,
|
|
88566
|
+
args,
|
|
88492
88567
|
env: {
|
|
88493
88568
|
...process.env,
|
|
88494
88569
|
...envVars
|
|
@@ -88557,7 +88632,7 @@ function setupAcpMiddleware(middlewares, serverContext, acpOptions) {
|
|
|
88557
88632
|
* Body: { sessionId }
|
|
88558
88633
|
*/
|
|
88559
88634
|
middlewares.use("/api/acp/cleanup-session", async (req, res) => {
|
|
88560
|
-
if (handleCors(
|
|
88635
|
+
if (handleCors(req, res)) return;
|
|
88561
88636
|
if (req.method !== "POST") {
|
|
88562
88637
|
res.statusCode = 405;
|
|
88563
88638
|
res.end("Method Not Allowed");
|
|
@@ -88600,7 +88675,7 @@ function setupAcpMiddleware(middlewares, serverContext, acpOptions) {
|
|
|
88600
88675
|
* Body: { messages, agent, envVars, sessionId? }
|
|
88601
88676
|
*/
|
|
88602
88677
|
middlewares.use("/api/acp/chat", async (req, res) => {
|
|
88603
|
-
if (handleCors(
|
|
88678
|
+
if (handleCors(req, res)) return;
|
|
88604
88679
|
if (req.method !== "POST") {
|
|
88605
88680
|
res.statusCode = 405;
|
|
88606
88681
|
res.end("Method Not Allowed");
|
|
@@ -88623,9 +88698,19 @@ function setupAcpMiddleware(middlewares, serverContext, acpOptions) {
|
|
|
88623
88698
|
shouldCleanupProvider = false;
|
|
88624
88699
|
} else {
|
|
88625
88700
|
console.log(`[dev-inspector] [acp] Creating new provider (no session found or provided)`);
|
|
88701
|
+
let command = agent.command;
|
|
88702
|
+
let args = agent.args;
|
|
88703
|
+
if (agent.npmPackage) {
|
|
88704
|
+
const binPath = resolveNpmPackageBin(agent.npmPackage);
|
|
88705
|
+
if (binPath) {
|
|
88706
|
+
command = binPath;
|
|
88707
|
+
args = agent.npmArgs || [];
|
|
88708
|
+
console.log(`[dev-inspector] [acp] Using resolved npm package: ${agent.npmPackage}`);
|
|
88709
|
+
}
|
|
88710
|
+
}
|
|
88626
88711
|
provider = createACPProvider({
|
|
88627
|
-
command
|
|
88628
|
-
args
|
|
88712
|
+
command,
|
|
88713
|
+
args,
|
|
88629
88714
|
env: {
|
|
88630
88715
|
...process.env,
|
|
88631
88716
|
...envVars
|