@humain/terminal 0.1.1 → 0.2.2
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 +22 -0
- package/dist/bundle/chunks/{anthropic-messages-XULXUBIG.js → anthropic-messages-QFCEKGI3.js} +1 -1
- package/dist/bundle/chunks/{azure-openai-responses-JEG2XOYC.js → azure-openai-responses-G4ZMHV37.js} +1 -1
- package/dist/bundle/chunks/chunk-7T6XCLJF.js +22 -0
- package/dist/bundle/chunks/{chunk-LYAMSPR2.js → chunk-ADQYVZ6A.js} +483 -506
- package/dist/bundle/chunks/chunk-D6HHRSB5.js +103 -0
- package/dist/bundle/chunks/{chunk-JUPSJTFQ.js → chunk-K4JAZYQH.js} +1 -1
- package/dist/bundle/chunks/{chunk-HPPQHK3J.js → chunk-KKIB2TVR.js} +1 -1
- package/dist/bundle/chunks/chunk-LI2YVPWP.js +2 -0
- package/dist/bundle/chunks/chunk-NMPIM7MN.js +2 -0
- package/dist/bundle/chunks/{chunk-BZQ53VGE.js → chunk-XSR434CO.js} +1 -1
- package/dist/bundle/chunks/compat-CN7WN6DA.js +2 -0
- package/dist/bundle/chunks/dist-PRPIUY3U.js +2 -0
- package/dist/bundle/chunks/esm-E7UVEYTO.js +4 -0
- package/dist/bundle/chunks/{extract-TRW5FBY6.js → extract-CTIFQZDJ.js} +15 -14
- package/dist/bundle/chunks/{google-generative-ai-OX6VSCA6.js → google-generative-ai-RSUU4MWO.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-GW76GSS2.js → google-vertex-CKQPOITO.js} +1 -1
- package/dist/bundle/chunks/host-WP3MVKS2.js +2 -0
- package/dist/bundle/chunks/{node-KOIP55YZ.js → node-NF43OPII.js} +1 -1
- package/dist/bundle/chunks/{node-XY3CBY3C.js → node-UMFM7CDZ.js} +1 -1
- package/dist/bundle/chunks/{openai-codex-responses-NPLWP6ZC.js → openai-codex-responses-S34V5ZSD.js} +1 -1
- package/dist/bundle/chunks/{openai-completions-OT2GTJKC.js → openai-completions-T2IGVUEI.js} +1 -1
- package/dist/bundle/chunks/{openai-responses-5A6CR7GI.js → openai-responses-GYZODCT3.js} +1 -1
- package/dist/bundle/chunks/readability-LAGF34IB.js +3 -0
- package/dist/bundle/chunks/turndown.cjs-HRMZVRUL.js +2 -0
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/core/model-runtime.d.ts +21 -0
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +34 -4
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
- package/dist/core/tools/file-mutation-queue.js +21 -8
- package/dist/core/tools/file-mutation-queue.js.map +1 -1
- package/dist/core/tools/subagent-env.d.ts +20 -0
- package/dist/core/tools/subagent-env.d.ts.map +1 -0
- package/dist/core/tools/subagent-env.js +47 -0
- package/dist/core/tools/subagent-env.js.map +1 -0
- package/dist/core/tools/subagent-scheduler.d.ts +36 -0
- package/dist/core/tools/subagent-scheduler.d.ts.map +1 -0
- package/dist/core/tools/subagent-scheduler.js +213 -0
- package/dist/core/tools/subagent-scheduler.js.map +1 -0
- package/dist/core/tools/subagent.d.ts +83 -3
- package/dist/core/tools/subagent.d.ts.map +1 -1
- package/dist/core/tools/subagent.js +215 -76
- package/dist/core/tools/subagent.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/CHANGELOG.md +78 -0
- package/dist/humain/mcp-adapter/vendor/README.md +125 -19
- package/dist/humain/mcp-adapter/vendor/agent-plugin-loader.ts +69 -30
- package/dist/humain/mcp-adapter/vendor/agent-plugin-provenance.ts +36 -0
- package/dist/humain/mcp-adapter/vendor/claude-plugin-loader.ts +365 -0
- package/dist/humain/mcp-adapter/vendor/commands.ts +13 -15
- package/dist/humain/mcp-adapter/vendor/config.ts +198 -30
- package/dist/humain/mcp-adapter/vendor/consent-manager.ts +40 -9
- package/dist/humain/mcp-adapter/vendor/direct-tool-surface.ts +250 -0
- package/dist/humain/mcp-adapter/vendor/direct-tools.ts +9 -228
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-loader.js +74 -32
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-loader.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-provenance.d.ts +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-provenance.js +31 -0
- package/dist/humain/mcp-adapter/vendor/dist/agent-plugin-provenance.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/claude-plugin-loader.d.ts +9 -0
- package/dist/humain/mcp-adapter/vendor/dist/claude-plugin-loader.js +362 -0
- package/dist/humain/mcp-adapter/vendor/dist/claude-plugin-loader.js.map +1 -0
- package/dist/humain/mcp-adapter/vendor/dist/config.d.ts +3 -1
- package/dist/humain/mcp-adapter/vendor/dist/config.js +189 -27
- package/dist/humain/mcp-adapter/vendor/dist/config.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/dist/metadata-cache.js +7 -16
- package/dist/humain/mcp-adapter/vendor/dist/metadata-cache.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/dist/package-mcp-loader.js +5 -17
- package/dist/humain/mcp-adapter/vendor/dist/package-mcp-loader.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/dist/types.d.ts +30 -4
- package/dist/humain/mcp-adapter/vendor/dist/types.js +26 -0
- package/dist/humain/mcp-adapter/vendor/dist/types.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/dist/utils.d.ts +6 -0
- package/dist/humain/mcp-adapter/vendor/dist/utils.js +65 -6
- package/dist/humain/mcp-adapter/vendor/dist/utils.js.map +1 -1
- package/dist/humain/mcp-adapter/vendor/host-html-template.ts +20 -19
- package/dist/humain/mcp-adapter/vendor/http-ca.ts +84 -0
- package/dist/humain/mcp-adapter/vendor/index.bundle.mjs +37102 -15103
- package/dist/humain/mcp-adapter/vendor/index.ts +828 -164
- package/dist/humain/mcp-adapter/vendor/init.ts +48 -10
- package/dist/humain/mcp-adapter/vendor/lazy-loader.ts +7 -0
- package/dist/humain/mcp-adapter/vendor/mcp-auth-fetch.ts +113 -0
- package/dist/humain/mcp-adapter/vendor/mcp-auth-flow.ts +256 -77
- package/dist/humain/mcp-adapter/vendor/mcp-auth.ts +316 -54
- package/dist/humain/mcp-adapter/vendor/mcp-code.ts +45 -18
- package/dist/humain/mcp-adapter/vendor/mcp-install.ts +60 -0
- package/dist/humain/mcp-adapter/vendor/mcp-oauth-provider.ts +70 -6
- package/dist/humain/mcp-adapter/vendor/mcp-output-guard.ts +53 -42
- package/dist/humain/mcp-adapter/vendor/mcp-panel-theme.ts +105 -0
- package/dist/humain/mcp-adapter/vendor/mcp-panel.ts +366 -331
- package/dist/humain/mcp-adapter/vendor/mcp-references.ts +9 -14
- package/dist/humain/mcp-adapter/vendor/mcp-script-worker.mjs +3 -1
- package/dist/humain/mcp-adapter/vendor/mcp-setup-panel.ts +383 -341
- package/dist/humain/mcp-adapter/vendor/mcp-status.ts +5 -0
- package/dist/humain/mcp-adapter/vendor/metadata-cache.ts +7 -16
- package/dist/humain/mcp-adapter/vendor/namespace-tools.ts +61 -3
- package/dist/humain/mcp-adapter/vendor/oauth.ts +6 -2
- package/dist/humain/mcp-adapter/vendor/package-mcp-loader.ts +5 -17
- package/dist/humain/mcp-adapter/vendor/package.json +13 -3
- package/dist/humain/mcp-adapter/vendor/prompts.ts +35 -3
- package/dist/humain/mcp-adapter/vendor/proxy-modes.ts +108 -7
- package/dist/humain/mcp-adapter/vendor/runtime-owner.ts +16 -1
- package/dist/humain/mcp-adapter/vendor/sampling-handler.ts +9 -32
- package/dist/humain/mcp-adapter/vendor/sandbox-proxy-template.ts +20 -93
- package/dist/humain/mcp-adapter/vendor/server-manager.ts +227 -40
- package/dist/humain/mcp-adapter/vendor/session-approvals.ts +187 -0
- package/dist/humain/mcp-adapter/vendor/skills/mcp-scripting/SKILL.md +9 -1
- package/dist/humain/mcp-adapter/vendor/state.ts +10 -1
- package/dist/humain/mcp-adapter/vendor/tool-approval.ts +10 -22
- package/dist/humain/mcp-adapter/vendor/tool-metadata.ts +14 -0
- package/dist/humain/mcp-adapter/vendor/types.ts +57 -4
- package/dist/humain/mcp-adapter/vendor/ui-server.ts +36 -28
- package/dist/humain/mcp-adapter/vendor/utils.ts +64 -6
- package/dist/humain/web-access/vendor/abortable.d.ts +3 -0
- package/dist/humain/web-access/vendor/abortable.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/abortable.js +22 -0
- package/dist/humain/web-access/vendor/abortable.js.map +1 -0
- package/dist/humain/web-access/vendor/crawl4ai.d.ts +9 -0
- package/dist/humain/web-access/vendor/crawl4ai.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/crawl4ai.js +187 -0
- package/dist/humain/web-access/vendor/crawl4ai.js.map +1 -0
- package/dist/humain/web-access/vendor/credential-source.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/credential-source.js +1 -0
- package/dist/humain/web-access/vendor/credential-source.js.map +1 -1
- package/dist/humain/web-access/vendor/curator-page.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/curator-page.js +20 -2
- package/dist/humain/web-access/vendor/curator-page.js.map +1 -1
- package/dist/humain/web-access/vendor/curator-run.d.ts +11 -0
- package/dist/humain/web-access/vendor/curator-run.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/curator-run.js +38 -0
- package/dist/humain/web-access/vendor/curator-run.js.map +1 -0
- package/dist/humain/web-access/vendor/curator-server.d.ts +1 -0
- package/dist/humain/web-access/vendor/curator-server.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/curator-server.js +2 -0
- package/dist/humain/web-access/vendor/curator-server.js.map +1 -1
- package/dist/humain/web-access/vendor/duckduckgo.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/duckduckgo.js +1 -1
- package/dist/humain/web-access/vendor/duckduckgo.js.map +1 -1
- package/dist/humain/web-access/vendor/extract.d.ts +1 -1
- package/dist/humain/web-access/vendor/extract.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/extract.js +58 -11
- package/dist/humain/web-access/vendor/extract.js.map +1 -1
- package/dist/humain/web-access/vendor/fetch-params.js +1 -1
- package/dist/humain/web-access/vendor/fetch-params.js.map +1 -1
- package/dist/humain/web-access/vendor/gemini-search.d.ts +2 -2
- package/dist/humain/web-access/vendor/gemini-search.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/gemini-search.js +12 -5
- package/dist/humain/web-access/vendor/gemini-search.js.map +1 -1
- package/dist/humain/web-access/vendor/index.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/index.js +23 -19
- package/dist/humain/web-access/vendor/index.js.map +1 -1
- package/dist/humain/web-access/vendor/openai-search.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/openai-search.js +40 -14
- package/dist/humain/web-access/vendor/openai-search.js.map +1 -1
- package/dist/humain/web-access/vendor/page-query.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/page-query.js +6 -2
- package/dist/humain/web-access/vendor/page-query.js.map +1 -1
- package/dist/humain/web-access/vendor/query-rewrite.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/query-rewrite.js +6 -2
- package/dist/humain/web-access/vendor/query-rewrite.js.map +1 -1
- package/dist/humain/web-access/vendor/serpapi.d.ts +4 -0
- package/dist/humain/web-access/vendor/serpapi.d.ts.map +1 -0
- package/dist/humain/web-access/vendor/serpapi.js +215 -0
- package/dist/humain/web-access/vendor/serpapi.js.map +1 -0
- package/dist/humain/web-access/vendor/ssrf-protection.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/ssrf-protection.js +5 -1
- package/dist/humain/web-access/vendor/ssrf-protection.js.map +1 -1
- package/dist/humain/web-access/vendor/storage.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/storage.js +9 -0
- package/dist/humain/web-access/vendor/storage.js.map +1 -1
- package/dist/humain/web-access/vendor/summary-review.d.ts +1 -1
- package/dist/humain/web-access/vendor/summary-review.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/summary-review.js +35 -24
- package/dist/humain/web-access/vendor/summary-review.js.map +1 -1
- package/dist/humain/web-access/vendor/utils.d.ts.map +1 -1
- package/dist/humain/web-access/vendor/utils.js +5 -3
- package/dist/humain/web-access/vendor/utils.js.map +1 -1
- package/dist/modes/json-event.d.ts +8 -0
- package/dist/modes/json-event.d.ts.map +1 -1
- package/dist/modes/json-event.js +17 -0
- package/dist/modes/json-event.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +3 -2
- package/dist/modes/print-mode.js.map +1 -1
- package/docs/environment-variables.md +9 -0
- package/docs/json.md +16 -0
- package/npm-shrinkwrap.json +6 -6
- package/package.json +2 -2
- package/src/humain/mcp-adapter/UPSTREAM.md +56 -7
- package/src/humain/mcp-adapter/upstream.json +6 -4
- package/src/humain/mcp-adapter/vendor/CHANGELOG.md +78 -0
- package/src/humain/web-access/UPSTREAM.md +18 -8
- package/src/humain/web-access/upstream.json +6 -5
- package/dist/bundle/chunks/chunk-2LC3S3VV.js +0 -105
|
@@ -2,7 +2,7 @@ import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-a
|
|
|
2
2
|
import type { McpExtensionState } from "./state.ts";
|
|
3
3
|
import { formatToolName, isServerDisabled, resolveToolPrefix, type McpAdapterOptions, type PromptMetadata, type ToolMetadata, type ToolSelectorCandidateIndex } from "./types.ts";
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
5
|
-
import { cloneMcpConfig, loadMcpConfig } from "./config.ts";
|
|
5
|
+
import { cloneMcpConfig, loadMcpConfig, resolveConfiguredClaudePluginMcp } from "./config.ts";
|
|
6
6
|
import { ConsentManager } from "./consent-manager.ts";
|
|
7
7
|
import { McpLifecycleManager } from "./lifecycle.ts";
|
|
8
8
|
import {
|
|
@@ -38,6 +38,10 @@ import {
|
|
|
38
38
|
} from "./runtime-owner.ts";
|
|
39
39
|
import { publishMcpStatusSnapshot } from "./mcp-status.ts";
|
|
40
40
|
import { FAILURE_BACKOFF_MS, getFailureAgeSeconds } from "./failure-backoff.ts";
|
|
41
|
+
import {
|
|
42
|
+
createSessionApprovalWriter,
|
|
43
|
+
restoreSessionApprovalState,
|
|
44
|
+
} from "./session-approvals.ts";
|
|
41
45
|
export { getFailureAgeSeconds, getFailureMessage, isServerInActiveFailureBackoff } from "./failure-backoff.ts";
|
|
42
46
|
|
|
43
47
|
const MAX_FAILURE_MESSAGE_CHARS = 8 * 1024;
|
|
@@ -117,12 +121,27 @@ export async function initializeMcp(
|
|
|
117
121
|
const rawUi = hasUI ? ctx.ui : undefined;
|
|
118
122
|
const modelRegistry = ctx.modelRegistry;
|
|
119
123
|
const initialSignal = ctx.signal;
|
|
124
|
+
let sessionManager: ExtensionContext["sessionManager"] | undefined;
|
|
125
|
+
try {
|
|
126
|
+
sessionManager = ctx.sessionManager;
|
|
127
|
+
} catch {
|
|
128
|
+
// Synthetic/load-time contexts may not expose a session manager.
|
|
129
|
+
}
|
|
130
|
+
let sessionBranch: readonly unknown[] = [];
|
|
131
|
+
if (sessionManager) {
|
|
132
|
+
try {
|
|
133
|
+
sessionBranch = sessionManager.getBranch();
|
|
134
|
+
} catch (error) {
|
|
135
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
136
|
+
logger.debug(`MCP: could not read the active session branch for approval restore: ${detail}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
120
139
|
const ui = rawUi ? createOwnedUi(rawUi, owner) : undefined;
|
|
121
140
|
const runtimeSignal = combineAbortSignals(owner.signal, initialSignal);
|
|
122
141
|
const config = options.config !== undefined
|
|
123
|
-
? cloneMcpConfig(options.config)
|
|
142
|
+
? resolveConfiguredClaudePluginMcp(cloneMcpConfig(options.config), cwd)
|
|
124
143
|
: loadMcpConfig(configPath, cwd);
|
|
125
|
-
const authStorageOptions = getAuthStorageOptions(config.settings?.oauthDir, cwd);
|
|
144
|
+
const authStorageOptions = getAuthStorageOptions(config.settings?.oauthDir, cwd, config.settings?.oauthCredentialStore);
|
|
126
145
|
|
|
127
146
|
const ownsOAuthRuntime = options.oauthRuntime === undefined;
|
|
128
147
|
const oauthRuntime = options.oauthRuntime ?? createOAuthRuntime(owner.signal);
|
|
@@ -153,6 +172,7 @@ export async function initializeMcp(
|
|
|
153
172
|
}
|
|
154
173
|
const lifecycle = new McpLifecycleManager(manager, (serverName) => hasPendingAuth(serverName, undefined, oauthRuntime));
|
|
155
174
|
const toolMetadata = new Map<string, ToolMetadata[]>();
|
|
175
|
+
const directToolCounts = new Map<string, number>();
|
|
156
176
|
const resourceCounts = new Map<string, number>();
|
|
157
177
|
const promptMetadata = new Map<string, PromptMetadata[]>();
|
|
158
178
|
const promptMetadataLive = new Set<string>();
|
|
@@ -161,12 +181,23 @@ export async function initializeMcp(
|
|
|
161
181
|
const failureMessages = new Map<string, string>();
|
|
162
182
|
const approvedToolCalls = new Map<string, true>();
|
|
163
183
|
const uiResourceHandler = new UiResourceHandler(manager, config);
|
|
164
|
-
|
|
184
|
+
let appendEntry: ((customType: string, data?: unknown) => void) | undefined;
|
|
185
|
+
try {
|
|
186
|
+
const candidate = pi.appendEntry;
|
|
187
|
+
appendEntry = typeof candidate === "function" ? candidate.bind(pi) : undefined;
|
|
188
|
+
} catch {
|
|
189
|
+
// Load-time or synthetic APIs may not expose appendEntry yet.
|
|
190
|
+
}
|
|
191
|
+
const persistSessionApproval = sessionManager && appendEntry
|
|
192
|
+
? createSessionApprovalWriter(appendEntry, () => owner.isActive())
|
|
193
|
+
: undefined;
|
|
194
|
+
const consentManager = new ConsentManager("once-per-server", persistSessionApproval);
|
|
165
195
|
const state: McpExtensionState = {
|
|
166
196
|
owner,
|
|
167
197
|
manager,
|
|
168
198
|
lifecycle,
|
|
169
199
|
toolMetadata,
|
|
200
|
+
directToolCounts,
|
|
170
201
|
resourceCounts,
|
|
171
202
|
promptMetadata,
|
|
172
203
|
promptMetadataLive,
|
|
@@ -178,6 +209,8 @@ export async function initializeMcp(
|
|
|
178
209
|
failureTracker,
|
|
179
210
|
failureMessages,
|
|
180
211
|
approvedToolCalls,
|
|
212
|
+
...(persistSessionApproval !== undefined ? { persistSessionApproval } : {}),
|
|
213
|
+
...(sessionManager !== undefined ? { sessionManager } : {}),
|
|
181
214
|
approvalEvents: pi.events,
|
|
182
215
|
uiResourceHandler,
|
|
183
216
|
consentManager,
|
|
@@ -207,11 +240,12 @@ export async function initializeMcp(
|
|
|
207
240
|
},
|
|
208
241
|
...(options.statusEvents !== undefined ? { statusEvents: options.statusEvents } : {}),
|
|
209
242
|
};
|
|
243
|
+
if (sessionManager) restoreSessionApprovalState(state, sessionBranch);
|
|
210
244
|
if (ownsOAuthRuntime) owner.addCleanup(() => shutdownOAuth(oauthRuntime));
|
|
211
245
|
manager.setMetadataListChangedListener?.((serverName, reason) => {
|
|
212
246
|
if (!owner.isActive()) return;
|
|
213
247
|
updateServerMetadata(state, serverName);
|
|
214
|
-
updateMetadataCache(state, serverName
|
|
248
|
+
updateMetadataCache(state, serverName);
|
|
215
249
|
notifyToolMetadataUpdated(state, serverName, reason);
|
|
216
250
|
updateStatusBar(state);
|
|
217
251
|
});
|
|
@@ -500,7 +534,12 @@ export function markKeepAliveAfterConnect(state: McpExtensionState, serverName:
|
|
|
500
534
|
|
|
501
535
|
export function updateServerMetadata(state: McpExtensionState, serverName: string): void {
|
|
502
536
|
const connection = state.manager.getConnection(serverName);
|
|
503
|
-
if (!connection || connection.status !== "connected")
|
|
537
|
+
if (!connection || connection.status !== "connected") {
|
|
538
|
+
state.toolMetadata.delete(serverName);
|
|
539
|
+
state.resourceCounts?.delete(serverName);
|
|
540
|
+
state.directToolCounts?.delete(serverName);
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
504
543
|
|
|
505
544
|
const definition = state.config.mcpServers[serverName];
|
|
506
545
|
if (!definition) return;
|
|
@@ -532,8 +571,8 @@ export function updateServerMetadata(state: McpExtensionState, serverName: strin
|
|
|
532
571
|
export function updateMetadataCache(
|
|
533
572
|
state: McpExtensionState,
|
|
534
573
|
serverName: string,
|
|
535
|
-
options: { preserveEmptyResources?: boolean } = {},
|
|
536
574
|
): void {
|
|
575
|
+
if (state.provisionalInstalls?.has(serverName)) return;
|
|
537
576
|
const connection = state.manager.getConnection(serverName);
|
|
538
577
|
if (!connection || connection.status !== "connected") return;
|
|
539
578
|
|
|
@@ -552,10 +591,9 @@ export function updateMetadataCache(
|
|
|
552
591
|
|
|
553
592
|
if (
|
|
554
593
|
definition.exposeResources !== false &&
|
|
555
|
-
|
|
594
|
+
connection.resourceDiscoveryFailed === true &&
|
|
556
595
|
existingEntry?.resources?.length &&
|
|
557
|
-
existingEntry
|
|
558
|
-
options.preserveEmptyResources !== false
|
|
596
|
+
isServerCacheValid(existingEntry, definition)
|
|
559
597
|
) {
|
|
560
598
|
resources = existingEntry.resources;
|
|
561
599
|
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { FetchLike } from "@modelcontextprotocol/client"
|
|
2
|
+
import { combineAbortSignals } from "./runtime-owner.ts"
|
|
3
|
+
import { interpolateEnvRecord, resolveCommandSecretsRecord } from "./utils.ts"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Resolve only at a connection/authentication boundary, never during config discovery.
|
|
7
|
+
* TypeError is fatal to the native SDK's fresh and cached discovery paths; ordinary
|
|
8
|
+
* errors can be swallowed and allow authentication to continue without credentials.
|
|
9
|
+
*/
|
|
10
|
+
type OAuthHeaderOptions = { commands?: boolean; literal?: boolean }
|
|
11
|
+
|
|
12
|
+
export function resolveOAuthHeaders(values: Record<string, string> | undefined, options: OAuthHeaderOptions = {}): Headers {
|
|
13
|
+
const { commands = true, literal = false } = options
|
|
14
|
+
if (literal) return new Headers(values)
|
|
15
|
+
const selected = Object.fromEntries(Object.entries(values ?? {}).filter(([, value]) =>
|
|
16
|
+
commands || !value.startsWith("!") || value.startsWith("!!")))
|
|
17
|
+
for (const value of Object.values(selected)) {
|
|
18
|
+
if (value.startsWith("!") && !value.startsWith("!!")) continue
|
|
19
|
+
for (const match of value.matchAll(/\$\{(\w+)\}|\$env:(\w+)|\{env:(\w+)\}/g)) {
|
|
20
|
+
const name = (match[1] ?? match[2] ?? match[3])!
|
|
21
|
+
if (!process.env[name]) throw new TypeError("Missing environment credential in OAuth HTTP headers")
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
try {
|
|
25
|
+
const resolved = commands
|
|
26
|
+
? resolveCommandSecretsRecord(selected, () => "OAuth HTTP header")
|
|
27
|
+
: interpolateEnvRecord(selected)
|
|
28
|
+
if (Object.values(resolved ?? {}).some(value => !value.trim())) {
|
|
29
|
+
throw new Error("empty header")
|
|
30
|
+
}
|
|
31
|
+
return new Headers(resolved)
|
|
32
|
+
} catch {
|
|
33
|
+
// Header constructors and command errors can otherwise include secret values.
|
|
34
|
+
throw new TypeError("Failed to resolve OAuth HTTP headers")
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const DEFAULT_OAUTH_REQUEST_TIMEOUT_MS = 30_000
|
|
39
|
+
function resolveOAuthRequestTimeoutMs(): number {
|
|
40
|
+
const parsed = Number(process.env.PI_MCP_OAUTH_REQUEST_TIMEOUT_MS)
|
|
41
|
+
return Number.isSafeInteger(parsed) && parsed > 0 && parsed <= 2_147_483_647
|
|
42
|
+
? parsed : DEFAULT_OAUTH_REQUEST_TIMEOUT_MS
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export type OAuthFetch = FetchLike & { throwIfHeaderResolutionFailed(): void }
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Configured service headers belong only to the configured MCP origin, not to
|
|
49
|
+
* discovered issuers. SDK request headers win (notably Authorization and MIME
|
|
50
|
+
* types). Credential-bearing redirects fail closed, including same-origin ones.
|
|
51
|
+
*/
|
|
52
|
+
export function createOAuthFetch(
|
|
53
|
+
serverUrl: string,
|
|
54
|
+
getHeaders: () => Headers = () => new Headers(),
|
|
55
|
+
signal?: AbortSignal,
|
|
56
|
+
options: { timeout?: boolean; delegate?: FetchLike } = {},
|
|
57
|
+
): OAuthFetch {
|
|
58
|
+
const origin = new URL(serverUrl).origin
|
|
59
|
+
let headerResolutionError: TypeError | undefined
|
|
60
|
+
const throwIfHeaderResolutionFailed = () => {
|
|
61
|
+
if (headerResolutionError) throw headerResolutionError
|
|
62
|
+
}
|
|
63
|
+
const fetchFn: FetchLike = async (input, init) => {
|
|
64
|
+
const request = input instanceof Request ? input : undefined
|
|
65
|
+
const url = new URL(request ? request.url : String(input))
|
|
66
|
+
const combined = combineAbortSignals(signal, init?.signal ?? request?.signal,
|
|
67
|
+
options.timeout === false ? undefined : AbortSignal.timeout(resolveOAuthRequestTimeoutMs()))
|
|
68
|
+
combined?.throwIfAborted()
|
|
69
|
+
throwIfHeaderResolutionFailed()
|
|
70
|
+
let serviceHeaders: Headers
|
|
71
|
+
try {
|
|
72
|
+
serviceHeaders = url.origin === origin ? getHeaders() : new Headers()
|
|
73
|
+
} catch {
|
|
74
|
+
headerResolutionError = new TypeError("Failed to resolve OAuth HTTP headers")
|
|
75
|
+
throw headerResolutionError
|
|
76
|
+
}
|
|
77
|
+
const headers = new Headers(serviceHeaders)
|
|
78
|
+
new Headers(init?.headers ?? request?.headers).forEach((value, key) => headers.set(key, value))
|
|
79
|
+
const protectedRequest = [...serviceHeaders].length > 0
|
|
80
|
+
try {
|
|
81
|
+
return await (options.delegate ?? globalThis.fetch)(input, {
|
|
82
|
+
...init,
|
|
83
|
+
headers,
|
|
84
|
+
...(combined ? { signal: combined } : {}),
|
|
85
|
+
...(protectedRequest ? { redirect: "error" as const } : {}),
|
|
86
|
+
})
|
|
87
|
+
} catch (error) {
|
|
88
|
+
combined?.throwIfAborted()
|
|
89
|
+
// Fetch failures also include DNS, TLS, and connection errors. Do not
|
|
90
|
+
// misdiagnose them as redirects or expose a potentially secret-bearing cause.
|
|
91
|
+
if (protectedRequest) throw new TypeError("OAuth HTTP request failed")
|
|
92
|
+
throw error
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return Object.assign(fetchFn, { throwIfHeaderResolutionFailed })
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Cache success or failure only in the owning auth leg/connection, never in storage. */
|
|
99
|
+
export function oauthHeaderResolver(values: Record<string, string> | undefined, options: Pick<OAuthHeaderOptions, "literal"> = {}): () => Headers {
|
|
100
|
+
const snapshot = values ? { ...values } : undefined
|
|
101
|
+
let result: { headers: Headers } | { error: unknown } | undefined
|
|
102
|
+
return () => {
|
|
103
|
+
if (!result) {
|
|
104
|
+
try {
|
|
105
|
+
result = { headers: resolveOAuthHeaders(snapshot, options) }
|
|
106
|
+
} catch (error) {
|
|
107
|
+
result = { error }
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if ("error" in result) throw result.error
|
|
111
|
+
return result.headers
|
|
112
|
+
}
|
|
113
|
+
}
|