@fitchmultz/pi-mcp-adapter 6.0.0 → 7.0.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/CHANGELOG.md +26 -0
- package/README.md +12 -8
- package/dist/app-bridge.bundle.js +14 -14
- package/dist/config.js +41 -16
- package/dist/gateway-arguments.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/lifecycle.d.ts +2 -2
- package/dist/lifecycle.js +2 -2
- package/dist/mcp-auth-flow.js +2 -2
- package/dist/mcp-auth.d.ts +1 -1
- package/dist/mcp-auth.js +3 -3
- package/dist/mcp-code.d.ts +6 -6
- package/dist/mcp-code.js +11 -10
- package/dist/mcp-oauth-provider.d.ts +5 -5
- package/dist/mcp-oauth-provider.js +5 -5
- package/dist/mcp-output-guard.d.ts +1 -1
- package/dist/mcp-panel.d.ts +2 -2
- package/dist/mcp-panel.js +2 -2
- package/dist/mcp-setup-panel.d.ts +5 -4
- package/dist/mcp-setup-panel.js +15 -7
- package/dist/mcp-trace.d.ts +1 -1
- package/dist/mcp-trace.js +1 -1
- package/dist/npx-resolver.js +8 -4
- package/dist/proxy-modes.d.ts +2 -2
- package/dist/proxy-modes.js +9 -9
- package/dist/sampling-handler.js +1 -0
- package/dist/search-ranking.js +6 -2
- package/dist/server-manager.d.ts +2 -2
- package/dist/server-manager.js +44 -27
- package/dist/session-recovery.d.ts +7 -4
- package/dist/session-recovery.js +76 -10
- package/dist/tool-metadata.d.ts +43 -43
- package/dist/tool-result-renderer.d.ts +3 -3
- package/dist/tool-result-renderer.js +3 -3
- package/dist/ui-resource-handler.d.ts +2 -2
- package/dist/ui-resource-handler.js +2 -2
- package/dist/ui-server.js +4 -3
- package/dist/ui-stream-types.d.ts +8 -8
- package/dist/unix-socket-transport.d.ts +1 -1
- package/dist/unix-socket-transport.js +1 -1
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +14 -0
- package/package.json +34 -98
- package/abort.ts +0 -34
- package/agent-dir.ts +0 -24
- package/app-bridge.bundle.js +0 -109
- package/banner.png +0 -0
- package/checkpoint.ts +0 -55
- package/commands.ts +0 -622
- package/config.ts +0 -1204
- package/consent-manager.ts +0 -25
- package/direct-tools.ts +0 -75
- package/elicitation-handler.ts +0 -349
- package/error-signal.ts +0 -21
- package/gateway-arguments.ts +0 -73
- package/glimpse-ui.ts +0 -80
- package/host-html-template.ts +0 -456
- package/index.ts +0 -767
- package/init.ts +0 -613
- package/legacy-migration.ts +0 -47
- package/lifecycle.ts +0 -165
- package/logger.ts +0 -127
- package/mcp-auth-flow.ts +0 -975
- package/mcp-auth.ts +0 -793
- package/mcp-callback-server.ts +0 -450
- package/mcp-code.ts +0 -412
- package/mcp-keyring-helper.cjs +0 -89
- package/mcp-oauth-provider.ts +0 -774
- package/mcp-output-guard.ts +0 -530
- package/mcp-panel.ts +0 -907
- package/mcp-script-worker.mjs +0 -131
- package/mcp-setup-panel.ts +0 -666
- package/mcp-status.ts +0 -110
- package/mcp-trace.ts +0 -295
- package/metadata-cache.ts +0 -271
- package/npx-resolver.ts +0 -488
- package/onboarding-state.ts +0 -58
- package/panel-keys.ts +0 -37
- package/prompts.ts +0 -337
- package/proxy-modes.ts +0 -1109
- package/resource-tools.ts +0 -52
- package/runtime-owner.ts +0 -123
- package/sampling-handler.ts +0 -276
- package/scripts/build-app-bridge.mjs +0 -15
- package/scripts/build.mjs +0 -132
- package/scripts/prepare.mjs +0 -103
- package/search-ranking.ts +0 -132
- package/server-manager.ts +0 -1320
- package/session-recovery.ts +0 -316
- package/state.ts +0 -64
- package/tool-approval.ts +0 -78
- package/tool-loader.ts +0 -153
- package/tool-metadata.ts +0 -240
- package/tool-registrar.ts +0 -74
- package/tool-result-renderer.ts +0 -294
- package/tsconfig.build.json +0 -13
- package/tsconfig.json +0 -16
- package/types.ts +0 -785
- package/ui-resource-handler.ts +0 -249
- package/ui-server.ts +0 -808
- package/ui-session.ts +0 -568
- package/ui-stream-types.ts +0 -89
- package/ui-tool-visibility.ts +0 -25
- package/unix-socket-transport.ts +0 -85
- package/utils.ts +0 -307
package/dist/proxy-modes.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_REQUEST_TIMEOUT_MSEC, UrlElicitationRequiredError } from "@modelcontextprotocol/client";
|
|
2
2
|
import { getServerPrefix, isServerDisabled, isNonInteractiveOAuth, parseUiPromptHandoff, resolveToolPrefix } from "./types.js";
|
|
3
|
-
import { lazyConnect, markKeepAliveAfterConnect, notifyToolMetadataUpdated, updateMetadataCache, getFailureAgeSeconds, updateStatusBar, clearFailure, recordFailure } from "./init.js";
|
|
3
|
+
import { lazyConnect, markKeepAliveAfterConnect, notifyToolMetadataUpdated, updateServerMetadata, updateMetadataCache, getFailureAgeSeconds, updateStatusBar, clearFailure, recordFailure } from "./init.js";
|
|
4
4
|
import { abortable, throwIfAborted } from "./abort.js";
|
|
5
5
|
import { combineAbortSignals, isAbortError } from "./runtime-owner.js";
|
|
6
6
|
import { buildToolMetadata, catalogCoverage, findToolByName, formatSchema, toToolDescriptor } from "./tool-metadata.js";
|
|
@@ -10,7 +10,7 @@ import { guardMcpOutput, guardedMcpDetails, retainMcpResult, resolveMcpOutputGua
|
|
|
10
10
|
import { maybeStartUiSession, summarizeUiSessionResult } from "./ui-session.js";
|
|
11
11
|
import { formatAuthRequiredMessage, formatMcpStatus, resolveServerUrl, truncateAtWord } from "./utils.js";
|
|
12
12
|
import { authenticate, completeAuthFromInput, startAuth, supportsOAuth } from "./mcp-auth-flow.js";
|
|
13
|
-
import { isToolTransportFailure, SessionRecoveryAuthRequiredError, withSessionRecovery } from "./session-recovery.js";
|
|
13
|
+
import { isInterruptedToolCall, isToolTransportFailure, trackToolCallOutcome, SessionRecoveryAuthRequiredError, withSessionRecovery } from "./session-recovery.js";
|
|
14
14
|
import { paginate, rankSuggestions, rankToolMatches } from "./search-ranking.js";
|
|
15
15
|
import { ensureToolCallApproved, isToolCallApprovalRequired } from "./tool-approval.js";
|
|
16
16
|
const INSTRUCTIONS_PREVIEW_LENGTH = 300;
|
|
@@ -387,9 +387,9 @@ export function executeDescribe(state, toolName, serverFilter) {
|
|
|
387
387
|
details: { mode: "describe", tool: toolMeta, server: serverName },
|
|
388
388
|
};
|
|
389
389
|
}
|
|
390
|
-
export function executeSearch(state, query, server, includeSchemas, limit = 12, offset = 0) {
|
|
390
|
+
export function executeSearch(state, query, server, includeSchemas, limit = 12, offset = 0, caller = "mcp") {
|
|
391
391
|
const showSchemas = includeSchemas !== false;
|
|
392
|
-
const searchCall = (nextOffset) =>
|
|
392
|
+
const searchCall = (nextOffset) => `${caller}({ ${caller === "mcp" ? 'action: "search", ' : ""}query: ${JSON.stringify(query)}${server ? `, server: ${JSON.stringify(server)}` : ""}${caller === "mcp" && !showSchemas ? ", includeSchemas: false" : ""}, limit: ${limit}, offset: ${nextOffset} })`;
|
|
393
393
|
if (server && isServerDisabled(state.config.mcpServers[server]))
|
|
394
394
|
return disabledResult("search", server);
|
|
395
395
|
let matches;
|
|
@@ -670,7 +670,7 @@ export async function runToolCall(state, serverName, target, args, options) {
|
|
|
670
670
|
state.manager.touch(serverName);
|
|
671
671
|
state.manager.incrementInFlight(serverName);
|
|
672
672
|
uiSession = !target.resourceUri && target.uiResourceUri
|
|
673
|
-
? await maybeStartUiSession(state, {
|
|
673
|
+
? await abortable(maybeStartUiSession(state, {
|
|
674
674
|
serverName,
|
|
675
675
|
toolName: target.originalName,
|
|
676
676
|
toolArgs: args ?? {},
|
|
@@ -678,7 +678,7 @@ export async function runToolCall(state, serverName, target, args, options) {
|
|
|
678
678
|
...(target.uiStreamMode !== undefined ? { streamMode: target.uiStreamMode } : {}),
|
|
679
679
|
...(signal ? { signal } : {}),
|
|
680
680
|
onNeedsAuth: recoverAuthConnection,
|
|
681
|
-
})
|
|
681
|
+
}), callerSignal)
|
|
682
682
|
: null;
|
|
683
683
|
// UI preparation can replace the connection; use its current annotations.
|
|
684
684
|
const liveTools = state.manager.getConnection(serverName)?.tools;
|
|
@@ -720,7 +720,7 @@ export async function runToolCall(state, serverName, target, args, options) {
|
|
|
720
720
|
};
|
|
721
721
|
const result = target.resourceUri
|
|
722
722
|
? await dispatch(() => withSessionRecovery(recovery, serverName, conn => abortable(conn.client.readResource({ uri: target.resourceUri }, requestOptions), ownedSignal)))
|
|
723
|
-
: await dispatch(() => withSessionRecovery({ ...recovery, retryOnTransportFailure: annotations?.readOnlyHint === true || annotations?.idempotentHint === true }, serverName, conn => abortable(conn.client.callTool({ name: target.originalName, arguments: args ?? {}, _meta: uiSession?.requestMeta }, requestOptions), ownedSignal)));
|
|
723
|
+
: await dispatch(() => trackToolCallOutcome(() => withSessionRecovery({ ...recovery, retryOnTransportFailure: annotations?.readOnlyHint === true || annotations?.idempotentHint === true }, serverName, conn => abortable(conn.client.callTool({ name: target.originalName, arguments: args ?? {}, _meta: uiSession?.requestMeta }, requestOptions), ownedSignal)), ownedSignal));
|
|
724
724
|
if (!target.resourceUri)
|
|
725
725
|
uiSession?.sendToolResult(result);
|
|
726
726
|
const record = result;
|
|
@@ -762,8 +762,8 @@ export async function runToolCall(state, serverName, target, args, options) {
|
|
|
762
762
|
details: { ...detailsBase, ...retained, error: isAbortError(error, callerSignal) ? "aborted" : "call_capture_failed", message, recovery: context },
|
|
763
763
|
};
|
|
764
764
|
}
|
|
765
|
-
if (isToolTransportFailure(error)) {
|
|
766
|
-
const message = `The outcome of MCP tool "${target.originalName}" on "${serverName}" is unknown after
|
|
765
|
+
if (isToolTransportFailure(error) || isInterruptedToolCall(error)) {
|
|
766
|
+
const message = `The outcome of MCP tool "${target.originalName}" on "${serverName}" is unknown after the call was interrupted. Read back the original operation using its saved arguments and provider identity before continuing. Do not blindly repeat the call or rerun its script.`;
|
|
767
767
|
uiSession?.sendToolCancelled(message);
|
|
768
768
|
return {
|
|
769
769
|
content: [{ type: "text", text: message }],
|
package/dist/sampling-handler.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { truncateAtWord } from "./utils.js";
|
|
2
2
|
import { throwIfAborted } from "./abort.js";
|
|
3
|
+
import {} from "@modelcontextprotocol/client";
|
|
3
4
|
export function registerSamplingHandler(client, options, own = run => run()) {
|
|
4
5
|
// Own the handler's real promise, not the SDK caller's cancellable response facade.
|
|
5
6
|
client.setRequestHandler("sampling/createMessage", request => own(() => handleSamplingRequest(options, request)));
|
package/dist/search-ranking.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import MiniSearch from "minisearch";
|
|
1
|
+
import MiniSearch, {} from "minisearch";
|
|
2
2
|
import { getServerPrefix, isServerDisabled, isToolAllowed, resolveToolPrefix } from "./types.js";
|
|
3
3
|
export const MAX_PAGE_SIZE = 100;
|
|
4
4
|
export const MAX_TOOL_NAME_LENGTH = 512;
|
|
@@ -69,7 +69,11 @@ function searchCatalog(state, query, server, options) {
|
|
|
69
69
|
.sort((a, b) => b.score - a.score || a.tool.name.localeCompare(b.tool.name));
|
|
70
70
|
}
|
|
71
71
|
export function rankToolMatches(state, query, server) {
|
|
72
|
-
|
|
72
|
+
const matches = searchCatalog(state, query, server);
|
|
73
|
+
const identity = query.trim();
|
|
74
|
+
const exact = ({ tool }) => tool.name === identity || (Boolean(server) && tool.originalName === identity);
|
|
75
|
+
// Stable partition retains MiniSearch order and scores within both groups.
|
|
76
|
+
return [...matches.filter(exact), ...matches.filter(match => !exact(match))];
|
|
73
77
|
}
|
|
74
78
|
export function paginate(items, offset, limit) {
|
|
75
79
|
const safeOffset = Number.isFinite(offset) ? Math.max(0, Math.trunc(offset)) : 0;
|
package/dist/server-manager.d.ts
CHANGED
|
@@ -24,7 +24,6 @@ export interface ServerConnection {
|
|
|
24
24
|
type UiStreamListener = (serverName: string, notification: ServerStreamResultPatchNotification["params"]) => void;
|
|
25
25
|
type MetadataListChangedListener = (serverName: string, reason: string) => void;
|
|
26
26
|
export declare class McpServerManager {
|
|
27
|
-
private readonly defaultCwd?;
|
|
28
27
|
private ownedClients;
|
|
29
28
|
private connections;
|
|
30
29
|
private connectPromises;
|
|
@@ -56,7 +55,8 @@ export declare class McpServerManager {
|
|
|
56
55
|
* Preserve existing property setters (including tracing) rather than replacing their behavior. */
|
|
57
56
|
private fenceTransport;
|
|
58
57
|
/** Default cwd for stdio servers without an explicit config `cwd`. */
|
|
59
|
-
|
|
58
|
+
private readonly defaultCwd;
|
|
59
|
+
constructor(defaultCwd?: string);
|
|
60
60
|
setSamplingConfig(config: ServerSamplingConfig | undefined): void;
|
|
61
61
|
setMetadataListChangedListener(listener: MetadataListChangedListener | undefined): void;
|
|
62
62
|
setElicitationConfig(config: ServerElicitationConfig | undefined): void;
|
package/dist/server-manager.js
CHANGED
|
@@ -2,7 +2,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
2
2
|
import { Client, StreamableHTTPClientTransport, SSEClientTransport, SdkHttpError, auth, extractWWWAuthenticateParams, UnauthorizedError, } from "@modelcontextprotocol/client";
|
|
3
3
|
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
|
|
4
4
|
import { UnixSocketClientTransport } from "./unix-socket-transport.js";
|
|
5
|
-
import {
|
|
5
|
+
import { trackToolTransport, trackToolTransportFailure } from "./session-recovery.js";
|
|
6
6
|
import { isServerDisabled, isNonInteractiveOAuth, validateServerProtocolConfig, serverStreamResultPatchNotificationSchema, } from "./types.js";
|
|
7
7
|
import { resolveNpxBinary } from "./npx-resolver.js";
|
|
8
8
|
import { logger } from "./logger.js";
|
|
@@ -11,10 +11,10 @@ import { extractOAuthConfig, supportsOAuth, isOAuthChallenge, recordOAuthChallen
|
|
|
11
11
|
import { getAuthBaseDir } from "./mcp-auth.js";
|
|
12
12
|
import { registerSamplingHandler } from "./sampling-handler.js";
|
|
13
13
|
import { handleUrlElicitation, registerElicitationHandler, } from "./elicitation-handler.js";
|
|
14
|
-
import { normalizeRequestTimeoutMs, resolveBearerToken, resolveCommandSecret, resolveCommandSecretsRecord, resolveConfigPath, resolveServerUrl, } from "./utils.js";
|
|
14
|
+
import { ADAPTER_VERSION, normalizeRequestTimeoutMs, resolveBearerToken, resolveCommandSecret, resolveCommandSecretsRecord, resolveConfigPath, resolveServerUrl, } from "./utils.js";
|
|
15
15
|
import { abortable, throwIfAborted } from "./abort.js";
|
|
16
16
|
import { combineAbortSignals } from "./runtime-owner.js";
|
|
17
|
-
import { createMcpTraceWriter, isMcpTraceEnabled, traceTransportKind, wrapTransportWithMcpTrace, } from "./mcp-trace.js";
|
|
17
|
+
import { createMcpTraceWriter, isMcpTraceEnabled, McpTraceWriter, traceTransportKind, wrapTransportWithMcpTrace, } from "./mcp-trace.js";
|
|
18
18
|
const MAX_CAPTURED_STDERR_BYTES = 8 * 1024;
|
|
19
19
|
const MAX_CAPTURED_STDERR_LINES = 3;
|
|
20
20
|
const abortCleanupPromises = new WeakMap();
|
|
@@ -161,7 +161,6 @@ function appendStderrTail(tail, chunk) {
|
|
|
161
161
|
: combined;
|
|
162
162
|
}
|
|
163
163
|
export class McpServerManager {
|
|
164
|
-
defaultCwd;
|
|
165
164
|
// Includes native clients whose public connect/close facade ended before their send/auth tail.
|
|
166
165
|
// Their operation promises remain in the same clientOperations authority until settlement.
|
|
167
166
|
ownedClients = new Set();
|
|
@@ -267,6 +266,7 @@ export class McpServerManager {
|
|
|
267
266
|
}
|
|
268
267
|
}
|
|
269
268
|
/** Default cwd for stdio servers without an explicit config `cwd`. */
|
|
269
|
+
defaultCwd;
|
|
270
270
|
constructor(defaultCwd) {
|
|
271
271
|
this.defaultCwd = defaultCwd;
|
|
272
272
|
}
|
|
@@ -329,9 +329,30 @@ export class McpServerManager {
|
|
|
329
329
|
throwIfAborted(ownedSignal);
|
|
330
330
|
if (this.stopped)
|
|
331
331
|
throw new Error("MCP server manager is closed");
|
|
332
|
+
const wait = (promise, attempt) => {
|
|
333
|
+
attempt.waiters++;
|
|
334
|
+
return abortable(promise, ownedSignal).finally(() => {
|
|
335
|
+
if (--attempt.waiters === 0 && ownedSignal?.aborted)
|
|
336
|
+
attempt.controller.abort(ownedSignal.reason);
|
|
337
|
+
});
|
|
338
|
+
};
|
|
332
339
|
// Dedupe concurrent connection attempts.
|
|
333
|
-
|
|
334
|
-
|
|
340
|
+
const pending = this.connectPromises.get(name);
|
|
341
|
+
if (pending) {
|
|
342
|
+
const attempt = this.connectAttempts.get(name);
|
|
343
|
+
if (attempt.controller.signal.aborted) {
|
|
344
|
+
// Finish the canceled attempt's cleanup before starting a fresh one.
|
|
345
|
+
try {
|
|
346
|
+
await abortable(pending, ownedSignal);
|
|
347
|
+
}
|
|
348
|
+
catch (error) {
|
|
349
|
+
throwIfAborted(ownedSignal);
|
|
350
|
+
if (this.containsCleanupFailure(error))
|
|
351
|
+
throw error;
|
|
352
|
+
}
|
|
353
|
+
return this.connect(name, definition, signal);
|
|
354
|
+
}
|
|
355
|
+
return wait(pending, attempt);
|
|
335
356
|
}
|
|
336
357
|
const existing = this.connections.get(name);
|
|
337
358
|
if (existing?.status === "connected") {
|
|
@@ -339,10 +360,10 @@ export class McpServerManager {
|
|
|
339
360
|
return existing;
|
|
340
361
|
}
|
|
341
362
|
const generation = this.closeGenerations.get(name) ?? 0;
|
|
342
|
-
const
|
|
343
|
-
const attemptSignal = combineAbortSignals(
|
|
344
|
-
const promise = this.createConnection(name, definition, attemptSignal, ownedSignal).then(async (connection) => {
|
|
345
|
-
if (
|
|
363
|
+
const attempt = { controller: new AbortController(), waiters: 0 };
|
|
364
|
+
const attemptSignal = combineAbortSignals(this.runtimeSignal, attempt.controller.signal);
|
|
365
|
+
const promise = this.createConnection(name, definition, attemptSignal, ownedSignal ? attemptSignal : undefined).then(async (connection) => {
|
|
366
|
+
if (connection.status === "closed" || attempt.controller.signal.aborted || (this.closeGenerations.get(name) ?? 0) !== generation) {
|
|
346
367
|
await this.disposeConnection(connection);
|
|
347
368
|
throwIfAborted(attemptSignal);
|
|
348
369
|
throw new Error(`MCP connection for ${name} was closed while connecting`);
|
|
@@ -350,18 +371,15 @@ export class McpServerManager {
|
|
|
350
371
|
connection.inFlight = this.connections.get(name)?.inFlight ?? 0;
|
|
351
372
|
this.connections.set(name, connection);
|
|
352
373
|
return connection;
|
|
353
|
-
})
|
|
354
|
-
this.connectPromises.set(name, promise);
|
|
355
|
-
this.connectAttempts.set(name, attemptController);
|
|
356
|
-
try {
|
|
357
|
-
return await promise;
|
|
358
|
-
}
|
|
359
|
-
finally {
|
|
374
|
+
}).finally(() => {
|
|
360
375
|
if (this.connectPromises.get(name) === promise)
|
|
361
376
|
this.connectPromises.delete(name);
|
|
362
|
-
if (this.connectAttempts.get(name) ===
|
|
377
|
+
if (this.connectAttempts.get(name) === attempt)
|
|
363
378
|
this.connectAttempts.delete(name);
|
|
364
|
-
}
|
|
379
|
+
});
|
|
380
|
+
this.connectPromises.set(name, promise);
|
|
381
|
+
this.connectAttempts.set(name, attempt);
|
|
382
|
+
return wait(promise, attempt);
|
|
365
383
|
}
|
|
366
384
|
/**
|
|
367
385
|
* Reconnect a server whose connection was proven stale (e.g. by a 404
|
|
@@ -493,6 +511,8 @@ export class McpServerManager {
|
|
|
493
511
|
else {
|
|
494
512
|
transport = new UnixSocketClientTransport(resolveConfigPath(definition.socket));
|
|
495
513
|
}
|
|
514
|
+
if (!definition.url)
|
|
515
|
+
trackToolTransport(transport);
|
|
496
516
|
if (traceObserver) {
|
|
497
517
|
const traceTransportKindValue = traceTransportKind(definition, transport);
|
|
498
518
|
transport = wrapTransportWithMcpTrace(transport, name, traceTransportKindValue, traceObserver);
|
|
@@ -536,11 +556,9 @@ export class McpServerManager {
|
|
|
536
556
|
status: "connected",
|
|
537
557
|
oauthProvider,
|
|
538
558
|
};
|
|
539
|
-
//
|
|
540
|
-
// client's late close must never change its replacement's status.
|
|
559
|
+
// Track closure during discovery too; this only changes this client's connection.
|
|
541
560
|
client.onclose = () => {
|
|
542
|
-
|
|
543
|
-
connection.status = "closed";
|
|
561
|
+
connection.status = "closed";
|
|
544
562
|
};
|
|
545
563
|
const discoveryOptions = this.buildRequestOptions(definition, signal);
|
|
546
564
|
const catalogs = [
|
|
@@ -671,7 +689,7 @@ export class McpServerManager {
|
|
|
671
689
|
createClient(serverName, definition) {
|
|
672
690
|
const capabilities = this.buildClientCapabilities(definition);
|
|
673
691
|
let client;
|
|
674
|
-
client = new ManagedClient({ name: `pi-mcp-${serverName}`, version:
|
|
692
|
+
client = new ManagedClient({ name: `pi-mcp-${serverName}`, version: ADAPTER_VERSION }, {
|
|
675
693
|
versionNegotiation: { mode: definition.protocolVersion ?? (definition.url ? "auto" : "legacy") },
|
|
676
694
|
listMaxPages: 0,
|
|
677
695
|
...(Object.keys(capabilities).length > 0 ? { capabilities } : {}),
|
|
@@ -936,8 +954,7 @@ export class McpServerManager {
|
|
|
936
954
|
onAuthChallenge?.(error);
|
|
937
955
|
};
|
|
938
956
|
}
|
|
939
|
-
|
|
940
|
-
trackToolHttpFailures(transport);
|
|
957
|
+
trackToolTransport(transport, true);
|
|
941
958
|
return { transport, oauthProvider: authProvider !== undefined };
|
|
942
959
|
}
|
|
943
960
|
async fetchAllTools(client, requestOptions) {
|
|
@@ -1021,7 +1038,7 @@ export class McpServerManager {
|
|
|
1021
1038
|
async close(name) {
|
|
1022
1039
|
this.beforeActivity();
|
|
1023
1040
|
this.closeGenerations.set(name, (this.closeGenerations.get(name) ?? 0) + 1);
|
|
1024
|
-
this.connectAttempts.get(name)?.abort(new Error(`MCP connection ${name} was closed`));
|
|
1041
|
+
this.connectAttempts.get(name)?.controller.abort(new Error(`MCP connection ${name} was closed`));
|
|
1025
1042
|
const pendingClose = this.closePromises.get(name);
|
|
1026
1043
|
if (pendingClose)
|
|
1027
1044
|
return pendingClose;
|
|
@@ -2,15 +2,18 @@ import { type FetchLike, type Transport } from "@modelcontextprotocol/client";
|
|
|
2
2
|
import { type McpConfig } from "./types.ts";
|
|
3
3
|
import type { McpServerManager, ServerConnection } from "./server-manager.ts";
|
|
4
4
|
export declare function isToolTransportFailure(error: unknown): boolean;
|
|
5
|
-
|
|
5
|
+
export declare function isInterruptedToolCall(error: unknown): boolean;
|
|
6
|
+
/** Interrupted outcome reporting is separate from the transport retry policy. */
|
|
7
|
+
export declare function trackToolCallOutcome<T>(fn: () => Promise<T>, signal?: AbortSignal): Promise<T>;
|
|
8
|
+
/** Retain fetch/body-error origin without parsing or buffering the response. */
|
|
6
9
|
export declare const trackToolTransportFailure: FetchLike;
|
|
7
10
|
/** Observe only the originating tool send, not OAuth or catalog requests. */
|
|
8
|
-
export declare function
|
|
11
|
+
export declare function trackToolTransport(transport: Transport, http?: boolean): void;
|
|
9
12
|
export declare function isTerminatedSession(err: unknown, hadSessionId: boolean): boolean;
|
|
10
13
|
export declare class SessionRecoveryAuthRequiredError extends Error {
|
|
11
14
|
readonly serverName: string;
|
|
12
|
-
readonly authMessage
|
|
13
|
-
constructor(serverName: string, authMessage?: string
|
|
15
|
+
readonly authMessage: string | undefined;
|
|
16
|
+
constructor(serverName: string, authMessage?: string);
|
|
14
17
|
}
|
|
15
18
|
export interface AuthChallengeContext {
|
|
16
19
|
connection: ServerConnection;
|
package/dist/session-recovery.js
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
// - treat generic -32000/ConnectionClosed errors as session expiry
|
|
22
22
|
// - treat AbortError/cancellation as a session failure
|
|
23
23
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
24
|
-
import { SdkHttpError, SdkErrorCode, ProtocolError, InsufficientScopeError, UnauthorizedError } from "@modelcontextprotocol/client";
|
|
24
|
+
import { SdkError, SdkHttpError, SdkErrorCode, ProtocolError, InsufficientScopeError, UnauthorizedError } from "@modelcontextprotocol/client";
|
|
25
25
|
import { logger } from "./logger.js";
|
|
26
26
|
import { abortable, throwIfAborted } from "./abort.js";
|
|
27
27
|
import { isServerDisabled, isNonInteractiveOAuth } from "./types.js";
|
|
@@ -30,18 +30,62 @@ const toolTransportFailures = new WeakSet();
|
|
|
30
30
|
export function isToolTransportFailure(error) {
|
|
31
31
|
return error instanceof Error && toolTransportFailures.has(error);
|
|
32
32
|
}
|
|
33
|
+
const interruptedToolCalls = new WeakSet();
|
|
34
|
+
export function isInterruptedToolCall(error) {
|
|
35
|
+
return error instanceof Error && interruptedToolCalls.has(error);
|
|
36
|
+
}
|
|
37
|
+
const toolCallOutcome = new AsyncLocalStorage();
|
|
38
|
+
/** Interrupted outcome reporting is separate from the transport retry policy. */
|
|
39
|
+
export async function trackToolCallOutcome(fn, signal) {
|
|
40
|
+
const outcome = { pending: false, cleanup: new Set() };
|
|
41
|
+
return toolCallOutcome.run(outcome, async () => {
|
|
42
|
+
try {
|
|
43
|
+
return await fn();
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
if (outcome.pending && error instanceof Error
|
|
47
|
+
&& (signal?.aborted || (error instanceof SdkError
|
|
48
|
+
&& (error.code === SdkErrorCode.RequestTimeout || error.code === SdkErrorCode.ConnectionClosed)))) {
|
|
49
|
+
// Abort reasons can be shared by calls that never reached dispatch.
|
|
50
|
+
const interrupted = new Error(error.message, { cause: error });
|
|
51
|
+
interruptedToolCalls.add(interrupted);
|
|
52
|
+
throw interrupted;
|
|
53
|
+
}
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
for (const cleanup of outcome.cleanup)
|
|
58
|
+
cleanup();
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
33
62
|
const toolSend = new AsyncLocalStorage();
|
|
34
|
-
/** Retain fetch/body-error origin without parsing or buffering the
|
|
63
|
+
/** Retain fetch/body-error origin without parsing or buffering the response. */
|
|
35
64
|
export const trackToolTransportFailure = async (input, init) => {
|
|
36
65
|
const pending = toolSend.getStore();
|
|
37
66
|
if (pending)
|
|
38
67
|
pending.bodyFailure = undefined;
|
|
68
|
+
let toolPost = false;
|
|
69
|
+
if (pending && init?.method === "POST" && typeof init.body === "string") {
|
|
70
|
+
try {
|
|
71
|
+
const request = JSON.parse(init.body);
|
|
72
|
+
toolPost = request.method === "tools/call" && request.id === pending.id;
|
|
73
|
+
}
|
|
74
|
+
catch { }
|
|
75
|
+
}
|
|
76
|
+
if (toolPost && pending?.outcome)
|
|
77
|
+
pending.outcome.pending = true;
|
|
39
78
|
try {
|
|
40
79
|
const response = await fetch(input, init);
|
|
41
|
-
if (
|
|
42
|
-
|
|
80
|
+
if (toolPost && !response.ok && response.status < 500 && pending?.outcome)
|
|
81
|
+
pending.outcome.pending = false;
|
|
82
|
+
const mediaType = response.headers.get("content-type")?.split(";", 1)[0]?.trim().toLowerCase();
|
|
83
|
+
const observeBody = response.ok
|
|
84
|
+
? mediaType === "text/event-stream" || (toolPost && mediaType === "application/json")
|
|
85
|
+
: toolPost && response.status >= 500;
|
|
86
|
+
if (!pending || !response.body || !observeBody)
|
|
43
87
|
return response;
|
|
44
|
-
pending.streaming =
|
|
88
|
+
pending.streaming = response.ok && mediaType === "text/event-stream";
|
|
45
89
|
// The native end hook has no error argument. Only a failed body read proves loss.
|
|
46
90
|
const reader = response.body.getReader();
|
|
47
91
|
return new Response(new ReadableStream({
|
|
@@ -59,8 +103,11 @@ export const trackToolTransportFailure = async (input, init) => {
|
|
|
59
103
|
// Native intentional closure suppresses onRequestStreamEnd.
|
|
60
104
|
if (init?.signal?.aborted)
|
|
61
105
|
pending.finishSend();
|
|
62
|
-
else if (error instanceof Error)
|
|
106
|
+
else if (error instanceof Error) {
|
|
63
107
|
pending.bodyFailure = error;
|
|
108
|
+
if (!pending.streaming)
|
|
109
|
+
interruptedToolCalls.add(error);
|
|
110
|
+
}
|
|
64
111
|
controller.error(error);
|
|
65
112
|
reader.releaseLock();
|
|
66
113
|
}
|
|
@@ -77,12 +124,16 @@ export const trackToolTransportFailure = async (input, init) => {
|
|
|
77
124
|
}
|
|
78
125
|
};
|
|
79
126
|
/** Observe only the originating tool send, not OAuth or catalog requests. */
|
|
80
|
-
export function
|
|
127
|
+
export function trackToolTransport(transport, http = false) {
|
|
128
|
+
const requests = new Map();
|
|
81
129
|
const onmessage = transport.onmessage;
|
|
82
130
|
transport.onmessage = (message, extra) => {
|
|
83
|
-
const pending = toolSend.getStore();
|
|
131
|
+
const pending = ("id" in message && message.id !== undefined ? requests.get(message.id) : undefined) ?? toolSend.getStore();
|
|
84
132
|
if (pending && "id" in message && message.id === pending.id && ("result" in message || "error" in message)) {
|
|
85
133
|
pending.responseReceived = true;
|
|
134
|
+
if (pending.outcome)
|
|
135
|
+
pending.outcome.pending = false;
|
|
136
|
+
requests.delete(pending.id);
|
|
86
137
|
pending.finishSend();
|
|
87
138
|
}
|
|
88
139
|
onmessage?.(message, extra);
|
|
@@ -98,15 +149,24 @@ export function trackToolHttpFailures(transport) {
|
|
|
98
149
|
const send = transport.send.bind(transport);
|
|
99
150
|
transport.send = async (message, options) => {
|
|
100
151
|
try {
|
|
101
|
-
if (!("method" in message && message.method === "tools/call" && "id" in message
|
|
152
|
+
if (!("method" in message && message.method === "tools/call" && "id" in message)) {
|
|
102
153
|
return await toolSend.run(undefined, () => send(message, options));
|
|
103
154
|
}
|
|
104
155
|
const pending = {
|
|
105
|
-
id: message.id, streaming: false, responseReceived: false,
|
|
156
|
+
id: message.id, outcome: toolCallOutcome.getStore(), streaming: false, responseReceived: false,
|
|
106
157
|
bodyFailure: undefined, otherFailure: undefined,
|
|
107
158
|
finishSend: () => { },
|
|
108
159
|
};
|
|
160
|
+
if (pending.outcome) {
|
|
161
|
+
requests.set(message.id, pending);
|
|
162
|
+
pending.outcome.cleanup.add(() => requests.delete(message.id));
|
|
163
|
+
if (!http)
|
|
164
|
+
pending.outcome.pending = true;
|
|
165
|
+
}
|
|
109
166
|
try {
|
|
167
|
+
if (!options?.requestSignal) {
|
|
168
|
+
return await toolSend.run(pending, () => send(message, options));
|
|
169
|
+
}
|
|
110
170
|
await abortable(new Promise((resolve, reject) => {
|
|
111
171
|
pending.finishSend = resolve;
|
|
112
172
|
void toolSend.run(pending, () => send(message, {
|
|
@@ -126,6 +186,12 @@ export function trackToolHttpFailures(transport) {
|
|
|
126
186
|
resolve(); }, reject);
|
|
127
187
|
}), options.requestSignal);
|
|
128
188
|
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
// Local send failures are distinct from a sent request waiting for its reply.
|
|
191
|
+
if (!http && pending.outcome)
|
|
192
|
+
pending.outcome.pending = false;
|
|
193
|
+
throw error;
|
|
194
|
+
}
|
|
129
195
|
finally {
|
|
130
196
|
pending.finishSend = () => { };
|
|
131
197
|
}
|
package/dist/tool-metadata.d.ts
CHANGED
|
@@ -6,10 +6,20 @@ export declare function buildToolMetadata(tools: McpTool[], resources: McpResour
|
|
|
6
6
|
};
|
|
7
7
|
export declare function totalToolCount(state: McpExtensionState): number;
|
|
8
8
|
export declare function toToolDescriptor(server: string, tool: ToolMetadata): {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
outputSchema?: {
|
|
10
|
+
[x: string]: unknown;
|
|
11
|
+
$schema?: string | undefined;
|
|
12
|
+
} | undefined;
|
|
13
|
+
annotations?: {
|
|
14
|
+
title?: string | undefined;
|
|
15
|
+
readOnlyHint?: boolean | undefined;
|
|
16
|
+
destructiveHint?: boolean | undefined;
|
|
17
|
+
idempotentHint?: boolean | undefined;
|
|
18
|
+
openWorldHint?: boolean | undefined;
|
|
19
|
+
} | undefined;
|
|
20
|
+
execution?: {
|
|
21
|
+
taskSupport?: "forbidden" | "optional" | "required" | undefined;
|
|
22
|
+
} | undefined;
|
|
13
23
|
_meta?: {
|
|
14
24
|
[x: string]: unknown;
|
|
15
25
|
} | undefined;
|
|
@@ -17,55 +27,45 @@ export declare function toToolDescriptor(server: string, tool: ToolMetadata): {
|
|
|
17
27
|
src: string;
|
|
18
28
|
mimeType?: string | undefined;
|
|
19
29
|
sizes?: string[] | undefined;
|
|
20
|
-
theme?: "
|
|
30
|
+
theme?: "dark" | "light" | undefined;
|
|
21
31
|
}[] | undefined;
|
|
22
32
|
title?: string | undefined;
|
|
23
33
|
inputSchema?: {
|
|
24
34
|
[x: string]: unknown;
|
|
25
35
|
type: "object";
|
|
26
36
|
properties?: {
|
|
27
|
-
[x: string]: string | number | boolean | {
|
|
28
|
-
[x: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
29
|
-
} | (string | number | boolean | {
|
|
30
|
-
[x: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
31
|
-
} | (string | number | boolean | {
|
|
32
|
-
[x: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
33
|
-
} | (string | number | boolean | {
|
|
34
|
-
[x: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
35
|
-
} | (string | number | boolean | {
|
|
36
|
-
[x: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
37
|
-
} | (string | number | boolean | {
|
|
38
|
-
[x: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
39
|
-
} | (string | number | boolean | {
|
|
40
|
-
[x: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null)[] | null;
|
|
41
|
-
} | (string | number | boolean | {
|
|
42
|
-
[x: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null)[] | null;
|
|
43
|
-
} | (string | number | boolean | {
|
|
44
|
-
[x: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null)[] | null;
|
|
45
|
-
} | (string | number | boolean | {
|
|
46
|
-
[x: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null)[] | null;
|
|
47
|
-
} | (string | number | boolean | {
|
|
48
|
-
[x: string]: string | number | boolean | /*elided*/ any | (string | number | boolean | /*elided*/ any | /*elided*/ any | null)[] | null;
|
|
49
|
-
} | (string | number | boolean | {
|
|
37
|
+
[x: string]: string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | (string | number | boolean | /*elided*/ any | {
|
|
50
38
|
[x: string]: string | number | boolean | /*elided*/ any | /*elided*/ any | null;
|
|
51
|
-
} |
|
|
39
|
+
} | null)[] | {
|
|
40
|
+
[x: string]: string | number | boolean | any | any | null;
|
|
41
|
+
} | null)[] | {
|
|
42
|
+
[x: string]: string | number | boolean | any | any | null;
|
|
43
|
+
} | null)[] | {
|
|
44
|
+
[x: string]: string | number | boolean | any | any | null;
|
|
45
|
+
} | null)[] | {
|
|
46
|
+
[x: string]: string | number | boolean | any | any | null;
|
|
47
|
+
} | null)[] | {
|
|
48
|
+
[x: string]: string | number | boolean | any | any | null;
|
|
49
|
+
} | null)[] | {
|
|
50
|
+
[x: string]: string | number | boolean | any | any | null;
|
|
51
|
+
} | null)[] | {
|
|
52
|
+
[x: string]: string | number | boolean | any | any | null;
|
|
53
|
+
} | null)[] | {
|
|
54
|
+
[x: string]: string | number | boolean | any | any | null;
|
|
55
|
+
} | null)[] | {
|
|
56
|
+
[x: string]: string | number | boolean | any | any | null;
|
|
57
|
+
} | null)[] | {
|
|
58
|
+
[x: string]: string | number | boolean | any | any | null;
|
|
59
|
+
} | null)[] | {
|
|
60
|
+
[x: string]: string | number | boolean | any | any | null;
|
|
61
|
+
} | null;
|
|
52
62
|
} | undefined;
|
|
53
63
|
required?: string[] | undefined;
|
|
54
64
|
};
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
annotations?: {
|
|
60
|
-
title?: string | undefined;
|
|
61
|
-
readOnlyHint?: boolean | undefined;
|
|
62
|
-
destructiveHint?: boolean | undefined;
|
|
63
|
-
idempotentHint?: boolean | undefined;
|
|
64
|
-
openWorldHint?: boolean | undefined;
|
|
65
|
-
} | undefined;
|
|
66
|
-
execution?: {
|
|
67
|
-
taskSupport?: "optional" | "required" | "forbidden" | undefined;
|
|
68
|
-
} | undefined;
|
|
65
|
+
description: string;
|
|
66
|
+
server: string;
|
|
67
|
+
path: string;
|
|
68
|
+
name: string;
|
|
69
69
|
};
|
|
70
70
|
export declare function catalogCoverage(state: McpExtensionState, server?: string): {
|
|
71
71
|
complete: boolean;
|
|
@@ -25,15 +25,15 @@ export interface McpToolResultDisplay {
|
|
|
25
25
|
truncated: boolean;
|
|
26
26
|
}
|
|
27
27
|
declare class CollapsibleText implements Component {
|
|
28
|
+
private readonly fullText;
|
|
29
|
+
private readonly footerText;
|
|
30
|
+
private collapsedText;
|
|
28
31
|
private readonly text;
|
|
29
32
|
private readonly expanded;
|
|
30
33
|
private readonly maxCollapsedLines;
|
|
31
34
|
private readonly ellipsis;
|
|
32
35
|
private readonly expandHint;
|
|
33
36
|
private readonly preTruncated;
|
|
34
|
-
private readonly fullText;
|
|
35
|
-
private readonly footerText;
|
|
36
|
-
private collapsedText;
|
|
37
37
|
constructor(text: string, expanded: boolean, maxCollapsedLines: number, ellipsis: string, expandHint: string, preTruncated?: boolean);
|
|
38
38
|
render(width: number): string[];
|
|
39
39
|
invalidate(): void;
|
|
@@ -9,15 +9,15 @@ const DEFAULT_MAX_COLLAPSED_LINES = 3;
|
|
|
9
9
|
const DEFAULT_MAX_COLLAPSED_CHARS = 8000;
|
|
10
10
|
const COLLAPSED_RENDER_CHAR_SLACK = 8;
|
|
11
11
|
class CollapsibleText {
|
|
12
|
+
fullText;
|
|
13
|
+
footerText;
|
|
14
|
+
collapsedText = null;
|
|
12
15
|
text;
|
|
13
16
|
expanded;
|
|
14
17
|
maxCollapsedLines;
|
|
15
18
|
ellipsis;
|
|
16
19
|
expandHint;
|
|
17
20
|
preTruncated;
|
|
18
|
-
fullText;
|
|
19
|
-
footerText;
|
|
20
|
-
collapsedText = null;
|
|
21
21
|
constructor(text, expanded, maxCollapsedLines, ellipsis, expandHint, preTruncated = false) {
|
|
22
22
|
this.text = text;
|
|
23
23
|
this.expanded = expanded;
|
|
@@ -7,10 +7,10 @@ interface ReadUiResourceOptions {
|
|
|
7
7
|
onNeedsAuth?: SessionRecoveryDeps["onNeedsAuth"];
|
|
8
8
|
}
|
|
9
9
|
export declare class UiResourceHandler {
|
|
10
|
+
private log;
|
|
10
11
|
private manager;
|
|
11
12
|
private config;
|
|
12
|
-
|
|
13
|
-
constructor(manager: McpServerManager, config?: McpConfig | undefined);
|
|
13
|
+
constructor(manager: McpServerManager, config?: McpConfig);
|
|
14
14
|
readUiResource(serverName: string, uri: string, options?: ReadUiResourceOptions): Promise<UiResourceContent>;
|
|
15
15
|
private getListResourceMeta;
|
|
16
16
|
}
|
|
@@ -4,10 +4,10 @@ import { logger } from "./logger.js";
|
|
|
4
4
|
import { SessionRecoveryAuthRequiredError, withSessionRecovery } from "./session-recovery.js";
|
|
5
5
|
import { isServerDisabled } from "./types.js";
|
|
6
6
|
export class UiResourceHandler {
|
|
7
|
+
log = logger.child({ component: "UiResourceHandler" });
|
|
7
8
|
manager;
|
|
8
9
|
config;
|
|
9
|
-
|
|
10
|
-
constructor(manager, config = undefined) {
|
|
10
|
+
constructor(manager, config) {
|
|
11
11
|
this.manager = manager;
|
|
12
12
|
this.config = config;
|
|
13
13
|
}
|