mindweave 2.4.2 → 2.4.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/App.js +213 -104
- package/dist/cli/App.js.map +1 -1
- package/dist/cli/attachments.js +14 -1
- package/dist/cli/attachments.js.map +1 -1
- package/dist/cli/blockSpacing.js +22 -1
- package/dist/cli/blockSpacing.js.map +1 -1
- package/dist/cli/components/ApprovalBox.js +16 -4
- package/dist/cli/components/ApprovalBox.js.map +1 -1
- package/dist/cli/components/BlockView.js +1 -1
- package/dist/cli/components/BlockView.js.map +1 -1
- package/dist/cli/components/KeyManager.js +3 -42
- package/dist/cli/components/KeyManager.js.map +1 -1
- package/dist/cli/components/McpMinitabs.js +689 -0
- package/dist/cli/components/McpMinitabs.js.map +1 -0
- package/dist/cli/components/ToolLine.js +12 -3
- package/dist/cli/components/ToolLine.js.map +1 -1
- package/dist/cli/components/minitabs.js +71 -0
- package/dist/cli/components/minitabs.js.map +1 -0
- package/dist/cli/framebuffer/writer.js +20 -3
- package/dist/cli/framebuffer/writer.js.map +1 -1
- package/dist/cli/toolDisplay.js +4 -1
- package/dist/cli/toolDisplay.js.map +1 -1
- package/dist/cli/transcript.js +1 -0
- package/dist/cli/transcript.js.map +1 -1
- package/dist/dynamo/engine.js +15 -0
- package/dist/dynamo/engine.js.map +1 -1
- package/dist/dynamo/prompt.js +1 -0
- package/dist/dynamo/prompt.js.map +1 -1
- package/dist/mcp/config.js +57 -3
- package/dist/mcp/config.js.map +1 -1
- package/dist/mcp/configWrite.js +40 -2
- package/dist/mcp/configWrite.js.map +1 -1
- package/dist/mcp/connection.js +51 -1
- package/dist/mcp/connection.js.map +1 -1
- package/dist/mcp/manager.js +65 -0
- package/dist/mcp/manager.js.map +1 -1
- package/dist/mcp/oauth/callback.js +171 -0
- package/dist/mcp/oauth/callback.js.map +1 -0
- package/dist/mcp/oauth/flow.js +398 -0
- package/dist/mcp/oauth/flow.js.map +1 -0
- package/dist/mcp/oauth/index.js +243 -0
- package/dist/mcp/oauth/index.js.map +1 -0
- package/dist/mcp/oauth/metadata.js +192 -0
- package/dist/mcp/oauth/metadata.js.map +1 -0
- package/dist/mcp/oauth/pkce.js +56 -0
- package/dist/mcp/oauth/pkce.js.map +1 -0
- package/dist/mcp/oauth/tokenStore.js +103 -0
- package/dist/mcp/oauth/tokenStore.js.map +1 -0
- package/dist/mcp/transport/http.js +33 -5
- package/dist/mcp/transport/http.js.map +1 -1
- package/dist/tools/askUser.js +26 -3
- package/dist/tools/askUser.js.map +1 -1
- package/dist/tools/backgroundShells.js +112 -7
- package/dist/tools/backgroundShells.js.map +1 -1
- package/dist/tools/mcpAdd.js +7 -0
- package/dist/tools/mcpAdd.js.map +1 -1
- package/dist/tools/shellTools.js +8 -1
- package/dist/tools/shellTools.js.map +1 -1
- package/package.json +74 -74
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/mcp/oauth/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* metadata.ts — finding out WHO can issue a token for a server, from the server itself.
|
|
3
|
+
*
|
|
4
|
+
* A remote MCP server that wants authorization answers an unauthenticated call with 401
|
|
5
|
+
* and a `WWW-Authenticate` header, and that header is the whole entry point: it names the
|
|
6
|
+
* URL of the server's Protected Resource Metadata (RFC 9728), which in turn names the
|
|
7
|
+
* authorization servers that can issue tokens for it, and each of those publishes its own
|
|
8
|
+
* metadata (RFC 8414) saying where to send someone to approve access and where to redeem
|
|
9
|
+
* the code afterwards. Three documents, fetched in that order, and none of them is
|
|
10
|
+
* configured by hand: the point of the chain is that adding a server is a URL and nothing
|
|
11
|
+
* else.
|
|
12
|
+
*
|
|
13
|
+
* Everything here is PURE — parsing and URL construction only. The fetching lives in
|
|
14
|
+
* `flow.ts`, so the part with all the branching is the part a test can drive directly
|
|
15
|
+
* with a string, and the part doing network I/O stays small enough to read in one go.
|
|
16
|
+
*
|
|
17
|
+
* THE FALLBACKS ARE NOT OPTIONAL. RFC 9728 arrived long after the servers that are
|
|
18
|
+
* deployed today, and a large share of them either omit the header, omit the metadata
|
|
19
|
+
* document, or publish it at the pre-RFC location. Every lookup here therefore produces a
|
|
20
|
+
* LIST of candidate URLs in descending order of correctness, and the caller tries them in
|
|
21
|
+
* turn. The alternative is refusing to connect to most of the ecosystem on a technicality.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Parse a `WWW-Authenticate` header (pure).
|
|
25
|
+
*
|
|
26
|
+
* The grammar is `Scheme param=value, param="value"` and the values that matter here are
|
|
27
|
+
* routinely quoted and routinely contain `=` and `,` of their own (a metadata URL has a
|
|
28
|
+
* query string), so this walks the string rather than splitting it. A header we cannot
|
|
29
|
+
* make sense of yields an empty challenge rather than throwing: it costs us the shortcut,
|
|
30
|
+
* not the connection, because every field is a shortcut past a fallback.
|
|
31
|
+
*/
|
|
32
|
+
export function parseWwwAuthenticate(header) {
|
|
33
|
+
if (!header)
|
|
34
|
+
return {};
|
|
35
|
+
const challenge = {};
|
|
36
|
+
// Skip the scheme token ("Bearer"), then read `key=value` pairs. A quoted value runs to
|
|
37
|
+
// its closing quote and may hold anything; a bare value runs to the next comma.
|
|
38
|
+
const params = /([A-Za-z_-]+)\s*=\s*(?:"((?:[^"\\]|\\.)*)"|([^,\s]*))/g;
|
|
39
|
+
for (const match of header.matchAll(params)) {
|
|
40
|
+
const key = match[1].toLowerCase();
|
|
41
|
+
const value = (match[2] ?? match[3] ?? "").replace(/\\(.)/g, "$1");
|
|
42
|
+
if (!value)
|
|
43
|
+
continue;
|
|
44
|
+
if (key === "resource_metadata")
|
|
45
|
+
challenge.resourceMetadata = value;
|
|
46
|
+
else if (key === "scope")
|
|
47
|
+
challenge.scope = value;
|
|
48
|
+
else if (key === "error")
|
|
49
|
+
challenge.error = value;
|
|
50
|
+
}
|
|
51
|
+
return challenge;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Where a server's Protected Resource Metadata might live, best first (pure).
|
|
55
|
+
*
|
|
56
|
+
* RFC 9728 inserts the well-known segment BEFORE the resource's own path
|
|
57
|
+
* (`/.well-known/oauth-protected-resource/mcp`), which is the opposite of the OpenID
|
|
58
|
+
* convention and the single most common thing to get wrong, so the path-aware form leads
|
|
59
|
+
* and the root form follows for servers that publish one document for the whole host.
|
|
60
|
+
*/
|
|
61
|
+
export function protectedResourceUrls(serverUrl) {
|
|
62
|
+
const url = safeUrl(serverUrl);
|
|
63
|
+
if (!url)
|
|
64
|
+
return [];
|
|
65
|
+
const path = trimSlashes(url.pathname);
|
|
66
|
+
const out = [];
|
|
67
|
+
if (path)
|
|
68
|
+
out.push(`${url.origin}/.well-known/oauth-protected-resource/${path}`);
|
|
69
|
+
out.push(`${url.origin}/.well-known/oauth-protected-resource`);
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Where an authorization server's metadata might live, best first (pure).
|
|
74
|
+
*
|
|
75
|
+
* Four shapes, because two specifications disagree about where the segment goes and both
|
|
76
|
+
* are deployed: RFC 8414 puts `.well-known` before the issuer's path, OpenID Connect
|
|
77
|
+
* Discovery appends it. An issuer with no path collapses to two.
|
|
78
|
+
*/
|
|
79
|
+
export function authServerUrls(issuer) {
|
|
80
|
+
const url = safeUrl(issuer);
|
|
81
|
+
if (!url)
|
|
82
|
+
return [];
|
|
83
|
+
const path = trimSlashes(url.pathname);
|
|
84
|
+
const out = [];
|
|
85
|
+
if (path) {
|
|
86
|
+
out.push(`${url.origin}/.well-known/oauth-authorization-server/${path}`);
|
|
87
|
+
out.push(`${url.origin}/${path}/.well-known/oauth-authorization-server`);
|
|
88
|
+
out.push(`${url.origin}/.well-known/openid-configuration/${path}`);
|
|
89
|
+
out.push(`${url.origin}/${path}/.well-known/openid-configuration`);
|
|
90
|
+
return out;
|
|
91
|
+
}
|
|
92
|
+
out.push(`${url.origin}/.well-known/oauth-authorization-server`);
|
|
93
|
+
out.push(`${url.origin}/.well-known/openid-configuration`);
|
|
94
|
+
return out;
|
|
95
|
+
}
|
|
96
|
+
/** Read RFC 9728 metadata, or null if it is not that (pure). */
|
|
97
|
+
export function readResourceMetadata(json) {
|
|
98
|
+
const o = asObject(json);
|
|
99
|
+
if (!o)
|
|
100
|
+
return null;
|
|
101
|
+
const servers = stringArray(o.authorization_servers);
|
|
102
|
+
if (servers.length === 0)
|
|
103
|
+
return null;
|
|
104
|
+
const out = { authorizationServers: servers };
|
|
105
|
+
const resource = asString(o.resource);
|
|
106
|
+
if (resource)
|
|
107
|
+
out.resource = resource;
|
|
108
|
+
const scopes = stringArray(o.scopes_supported);
|
|
109
|
+
if (scopes.length > 0)
|
|
110
|
+
out.scopesSupported = scopes;
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
/** Read RFC 8414 / OIDC discovery metadata, or null if the required endpoints are absent
|
|
114
|
+
* (pure). Both endpoints are load bearing, so a document missing either is not usable
|
|
115
|
+
* even though it parsed. */
|
|
116
|
+
export function readAuthServerMetadata(json) {
|
|
117
|
+
const o = asObject(json);
|
|
118
|
+
if (!o)
|
|
119
|
+
return null;
|
|
120
|
+
const authorizationEndpoint = asString(o.authorization_endpoint);
|
|
121
|
+
const tokenEndpoint = asString(o.token_endpoint);
|
|
122
|
+
if (!authorizationEndpoint || !tokenEndpoint)
|
|
123
|
+
return null;
|
|
124
|
+
const out = {
|
|
125
|
+
issuer: asString(o.issuer) ?? "",
|
|
126
|
+
authorizationEndpoint,
|
|
127
|
+
tokenEndpoint,
|
|
128
|
+
};
|
|
129
|
+
const registration = asString(o.registration_endpoint);
|
|
130
|
+
if (registration)
|
|
131
|
+
out.registrationEndpoint = registration;
|
|
132
|
+
const revocation = asString(o.revocation_endpoint);
|
|
133
|
+
if (revocation)
|
|
134
|
+
out.revocationEndpoint = revocation;
|
|
135
|
+
const scopes = stringArray(o.scopes_supported);
|
|
136
|
+
if (scopes.length > 0)
|
|
137
|
+
out.scopesSupported = scopes;
|
|
138
|
+
const methods = stringArray(o.code_challenge_methods_supported);
|
|
139
|
+
if (methods.length > 0)
|
|
140
|
+
out.codeChallengeMethodsSupported = methods;
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Does this authorization server support the only PKCE method we will use (pure)?
|
|
145
|
+
*
|
|
146
|
+
* A server that ADVERTISES its methods and does not list S256 is refused rather than
|
|
147
|
+
* downgraded. `plain` sends the verifier itself as the challenge, which protects against
|
|
148
|
+
* nothing, and quietly falling back to it would turn a loud incompatibility into a silent
|
|
149
|
+
* loss of the protection PKCE exists for. A server that advertises nothing is assumed to
|
|
150
|
+
* support S256, which is what the OAuth 2.1 draft requires of it anyway.
|
|
151
|
+
*/
|
|
152
|
+
export function supportsS256(meta) {
|
|
153
|
+
return meta.codeChallengeMethodsSupported === undefined || meta.codeChallengeMethodsSupported.includes("S256");
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* The scope string to ask for, or undefined to let the server decide (pure).
|
|
157
|
+
*
|
|
158
|
+
* The 401's own `scope` wins: it is the server saying what the call that just failed
|
|
159
|
+
* needed, which is more precise than anything advertised. Otherwise everything the
|
|
160
|
+
* resource says it supports, and failing that nothing at all — an empty `scope` parameter
|
|
161
|
+
* is meaningfully different from an absent one at several providers, so it is omitted
|
|
162
|
+
* rather than sent blank.
|
|
163
|
+
*/
|
|
164
|
+
export function scopeToRequest(challenge, resource) {
|
|
165
|
+
if (challenge.scope?.trim())
|
|
166
|
+
return challenge.scope.trim();
|
|
167
|
+
if (resource?.scopesSupported && resource.scopesSupported.length > 0)
|
|
168
|
+
return resource.scopesSupported.join(" ");
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
function safeUrl(raw) {
|
|
172
|
+
try {
|
|
173
|
+
const url = new URL(raw);
|
|
174
|
+
return url.protocol === "https:" || url.protocol === "http:" ? url : null;
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
function trimSlashes(path) {
|
|
181
|
+
return path.replace(/^\/+|\/+$/g, "");
|
|
182
|
+
}
|
|
183
|
+
function asObject(value) {
|
|
184
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
185
|
+
}
|
|
186
|
+
function asString(value) {
|
|
187
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
188
|
+
}
|
|
189
|
+
function stringArray(value) {
|
|
190
|
+
return Array.isArray(value) ? value.filter((v) => typeof v === "string" && v.trim().length > 0) : [];
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../../src/mcp/oauth/metadata.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* pkce.ts — the proof that the code being redeemed is being redeemed by whoever asked.
|
|
3
|
+
*
|
|
4
|
+
* A CLI cannot keep a client secret: anything shipped in the binary or written to a
|
|
5
|
+
* config file is readable by anything else on the machine, so OAuth for native apps
|
|
6
|
+
* treats us as a PUBLIC client and closes the resulting hole with PKCE instead. We invent
|
|
7
|
+
* a random `verifier`, send only its SHA-256 (the `challenge`) when we send the user off
|
|
8
|
+
* to approve, and send the verifier itself when we redeem the code. Anything that
|
|
9
|
+
* intercepts the redirect gets a code it cannot spend, because it never saw the verifier.
|
|
10
|
+
*
|
|
11
|
+
* `state` is the other half and guards the other direction: it proves a callback arriving
|
|
12
|
+
* on our loopback port belongs to the flow WE started, rather than to something else on
|
|
13
|
+
* the machine firing a request at the port we just opened.
|
|
14
|
+
*
|
|
15
|
+
* All of it is one small pure-ish module on node:crypto so the encodings — which are the
|
|
16
|
+
* part that silently breaks, since base64url is not base64 and a single `+` will fail an
|
|
17
|
+
* exchange with a message that names none of this — live in exactly one place.
|
|
18
|
+
*/
|
|
19
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
20
|
+
/** RFC 7636 puts the verifier between 43 and 128 characters; 32 random bytes encode to
|
|
21
|
+
* 43, which is the shortest legal value and therefore the one with nothing to spare in
|
|
22
|
+
* it. Entropy is the point, not length, and 256 bits is not the weak link. */
|
|
23
|
+
const VERIFIER_BYTES = 32;
|
|
24
|
+
/** base64url: base64 with the two URL-hostile characters swapped and the padding dropped.
|
|
25
|
+
* Everything here goes into a query string or a form body, so the plain alphabet would
|
|
26
|
+
* need escaping at every call site and would be forgotten at one of them. */
|
|
27
|
+
function base64Url(buffer) {
|
|
28
|
+
return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
29
|
+
}
|
|
30
|
+
/** A fresh verifier and its challenge. One per authorization attempt, never reused: a
|
|
31
|
+
* verifier that outlives its code is a secret with no expiry. */
|
|
32
|
+
export function createPkce() {
|
|
33
|
+
const verifier = base64Url(randomBytes(VERIFIER_BYTES));
|
|
34
|
+
const challenge = base64Url(createHash("sha256").update(verifier).digest());
|
|
35
|
+
return { verifier, challenge, method: "S256" };
|
|
36
|
+
}
|
|
37
|
+
/** An opaque value tying a callback to the request that caused it. */
|
|
38
|
+
export function randomState() {
|
|
39
|
+
return base64Url(randomBytes(VERIFIER_BYTES));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Compare two `state` values without leaking where they first differ (pure).
|
|
43
|
+
*
|
|
44
|
+
* `===` on strings short-circuits at the first mismatched character, and the callback URL
|
|
45
|
+
* is attacker-supplied, so the comparison time is a signal about our secret. The amount
|
|
46
|
+
* of signal is small and the fix is three lines, which is the wrong trade to skip.
|
|
47
|
+
*/
|
|
48
|
+
export function stateMatches(expected, received) {
|
|
49
|
+
if (typeof received !== "string" || received.length !== expected.length)
|
|
50
|
+
return false;
|
|
51
|
+
let diff = 0;
|
|
52
|
+
for (let i = 0; i < expected.length; i++)
|
|
53
|
+
diff |= expected.charCodeAt(i) ^ received.charCodeAt(i);
|
|
54
|
+
return diff === 0;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=pkce.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../../src/mcp/oauth/pkce.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEtD;;+EAE+E;AAC/E,MAAM,cAAc,GAAG,EAAE,CAAC;AAW1B;;8EAE8E;AAC9E,SAAS,SAAS,CAAC,MAAc;IAC/B,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAC9F,CAAC;AAED;kEACkE;AAClE,MAAM,UAAU,UAAU;IACxB,MAAM,QAAQ,GAAG,SAAS,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC;IACxD,MAAM,SAAS,GAAG,SAAS,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5E,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AACjD,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,WAAW;IACzB,OAAO,SAAS,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC,CAAC;AAChD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,QAAmC;IAChF,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACtF,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,IAAI,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAClG,OAAO,IAAI,KAAK,CAAC,CAAC;AACpB,CAAC"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tokenStore.ts — where a server's tokens live between runs.
|
|
3
|
+
*
|
|
4
|
+
* NOT the `.env` file the API keys use, and that is deliberate. A provider key is typed
|
|
5
|
+
* once by a person and belongs in a file a person can open; an OAuth token is issued by a
|
|
6
|
+
* machine, expires in an hour, is replaced silently by a refresh, and is meaningless to
|
|
7
|
+
* read. Putting the two in one file would mean a rewrite of the user's own config every
|
|
8
|
+
* time a token rotated, with their comments and ordering at risk each time.
|
|
9
|
+
*
|
|
10
|
+
* So: one JSON file of our own under the state directory, written whole, `0600`.
|
|
11
|
+
*
|
|
12
|
+
* KEYED BY NAME **AND** CONFIG, via `serverKey`. Keying by name alone would hand the
|
|
13
|
+
* token issued for one URL to whatever is configured under that name later — rename a
|
|
14
|
+
* server, point it at a different host, and the old credential follows it. Names are
|
|
15
|
+
* chosen by the user and reused freely; the URL is what the token was actually minted
|
|
16
|
+
* for, so both go into the key and changing either is a different server.
|
|
17
|
+
*/
|
|
18
|
+
import { promises as fs } from "node:fs";
|
|
19
|
+
import { createHash } from "node:crypto";
|
|
20
|
+
import { dirname, join } from "node:path";
|
|
21
|
+
import { stateRoot } from "../../memory/store.js";
|
|
22
|
+
/** Read on every call rather than cached at import, matching `stateRoot` itself, so a
|
|
23
|
+
* test can point this somewhere disposable before anything touches it. */
|
|
24
|
+
export function authFilePath() {
|
|
25
|
+
return join(stateRoot(), "mcp-auth.json");
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The identity a credential is filed under (pure).
|
|
29
|
+
*
|
|
30
|
+
* A short hash of the URL rather than the URL itself: this string ends up as a JSON key
|
|
31
|
+
* in a file people will open when something is wrong, and a full URL with its query
|
|
32
|
+
* string makes that file unreadable. The name is kept in front of it so the entry is
|
|
33
|
+
* still recognisable at a glance.
|
|
34
|
+
*/
|
|
35
|
+
export function serverKey(name, config) {
|
|
36
|
+
// The HEADERS are part of the identity too, not just the URL. A configured header is
|
|
37
|
+
// frequently the thing that selects an account or a tenant at the other end, so a token
|
|
38
|
+
// minted while one was set has no business being sent after it changed — that is a
|
|
39
|
+
// credential for a context that no longer exists.
|
|
40
|
+
const identity = config.type === "http"
|
|
41
|
+
? JSON.stringify({ type: "http", url: config.url, headers: config.headers ?? {} })
|
|
42
|
+
: JSON.stringify({ type: "stdio", command: config.command, args: config.args });
|
|
43
|
+
const digest = createHash("sha256").update(identity).digest("hex").slice(0, 16);
|
|
44
|
+
return `${name}:${digest}`;
|
|
45
|
+
}
|
|
46
|
+
async function readFile() {
|
|
47
|
+
try {
|
|
48
|
+
const raw = await fs.readFile(authFilePath(), "utf8");
|
|
49
|
+
const parsed = JSON.parse(raw);
|
|
50
|
+
const servers = typeof parsed === "object" && parsed !== null ? parsed.servers : undefined;
|
|
51
|
+
return { servers: typeof servers === "object" && servers !== null ? servers : {} };
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
// Missing is the normal case on a first run, and unreadable is not worth failing a
|
|
55
|
+
// connection over: both mean "no credential", and the flow that follows will mint one.
|
|
56
|
+
return { servers: {} };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Replace the whole file, owner-readable only.
|
|
61
|
+
*
|
|
62
|
+
* Written to a temporary name and renamed, because a token file truncated by a crash
|
|
63
|
+
* mid-write is not a token file with one bad entry — it is a file that fails to parse and
|
|
64
|
+
* silently signs the user out of every server at once. The mode is set on the temporary
|
|
65
|
+
* file BEFORE the rename, so there is no window in which the real path exists readable.
|
|
66
|
+
*/
|
|
67
|
+
async function writeFile(file) {
|
|
68
|
+
const target = authFilePath();
|
|
69
|
+
await fs.mkdir(dirname(target), { recursive: true });
|
|
70
|
+
const temp = `${target}.${process.pid}.tmp`;
|
|
71
|
+
await fs.writeFile(temp, `${JSON.stringify(file, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
|
|
72
|
+
await fs.rename(temp, target);
|
|
73
|
+
}
|
|
74
|
+
export async function readAuth(key) {
|
|
75
|
+
return (await readFile()).servers[key];
|
|
76
|
+
}
|
|
77
|
+
export async function writeAuth(key, auth) {
|
|
78
|
+
// Re-read immediately before writing rather than holding the file in memory: two
|
|
79
|
+
// servers can finish a refresh at the same moment, and the loser of a last-write-wins
|
|
80
|
+
// race would otherwise drop the winner's brand new token.
|
|
81
|
+
const file = await readFile();
|
|
82
|
+
file.servers[key] = auth;
|
|
83
|
+
await writeFile(file);
|
|
84
|
+
}
|
|
85
|
+
export async function clearAuth(key) {
|
|
86
|
+
const file = await readFile();
|
|
87
|
+
if (!(key in file.servers))
|
|
88
|
+
return;
|
|
89
|
+
delete file.servers[key];
|
|
90
|
+
await writeFile(file);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Is this token worth sending (pure)?
|
|
94
|
+
*
|
|
95
|
+
* A minute of headroom, because the token has to survive the round trip it is about to be
|
|
96
|
+
* spent on, and a clock that is thirty seconds fast would otherwise send something the
|
|
97
|
+
* server has already retired and turn a refresh into a 401.
|
|
98
|
+
*/
|
|
99
|
+
const EXPIRY_SKEW_MS = 60_000;
|
|
100
|
+
export function isExpired(auth, now = Date.now()) {
|
|
101
|
+
return auth.expiresAt !== undefined && auth.expiresAt - EXPIRY_SKEW_MS <= now;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=tokenStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokenStore.js","sourceRoot":"","sources":["../../../src/mcp/oauth/tokenStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -133,6 +133,28 @@ export class HttpTransport {
|
|
|
133
133
|
this.resolveClosed = resolve;
|
|
134
134
|
});
|
|
135
135
|
}
|
|
136
|
+
/** The configured headers with any live credential merged over them. Resolved per
|
|
137
|
+
* request; a failure to produce one is not fatal, because a request WITHOUT a token is
|
|
138
|
+
* exactly how a server gets the chance to tell us it wants one. */
|
|
139
|
+
async liveHeaders() {
|
|
140
|
+
const base = this.options.headers ?? {};
|
|
141
|
+
if (!this.options.authHeaders)
|
|
142
|
+
return base;
|
|
143
|
+
try {
|
|
144
|
+
return { ...base, ...(await this.options.authHeaders()) };
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return base;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/** Remember what a rejection said about how to authorize, before the response is gone. */
|
|
151
|
+
noteChallenge(response) {
|
|
152
|
+
if (response.status !== 401 && response.status !== 403)
|
|
153
|
+
return;
|
|
154
|
+
const header = response.headers.get("www-authenticate");
|
|
155
|
+
if (header)
|
|
156
|
+
this.options.onAuthChallenge?.(header);
|
|
157
|
+
}
|
|
136
158
|
async request(method, params, mirrored) {
|
|
137
159
|
if (this.disposed)
|
|
138
160
|
throw new RpcError(-32603, "mcp transport is closed");
|
|
@@ -143,6 +165,7 @@ export class HttpTransport {
|
|
|
143
165
|
timer.unref?.();
|
|
144
166
|
let response;
|
|
145
167
|
try {
|
|
168
|
+
const configured = await this.liveHeaders();
|
|
146
169
|
response = await this.fetchImpl(this.options.url, {
|
|
147
170
|
method: "POST",
|
|
148
171
|
signal: controller.signal,
|
|
@@ -151,7 +174,7 @@ export class HttpTransport {
|
|
|
151
174
|
// The client says it takes either shape; the SERVER picks. A single result
|
|
152
175
|
// comes back as JSON, a long-running call upgrades to a stream.
|
|
153
176
|
accept: "application/json, text/event-stream",
|
|
154
|
-
...
|
|
177
|
+
...configured,
|
|
155
178
|
// Mirrored last, so configuration cannot overwrite them. These are not
|
|
156
179
|
// settings — they are a restatement of the body, checked against it by the
|
|
157
180
|
// server, and a configured header that disagreed would earn a -32020 on every
|
|
@@ -172,6 +195,7 @@ export class HttpTransport {
|
|
|
172
195
|
if (!response.ok) {
|
|
173
196
|
// 401/403 are the auth signal the connection layer turns into `needs-auth`
|
|
174
197
|
// rather than `failed`, so the code has to survive as more than a message.
|
|
198
|
+
this.noteChallenge(response);
|
|
175
199
|
throw new RpcError(httpErrorCode(response.status), `mcp http ${response.status} ${response.statusText || ""}`.trim());
|
|
176
200
|
}
|
|
177
201
|
const contentType = response.headers.get("content-type") ?? "";
|
|
@@ -196,16 +220,18 @@ export class HttpTransport {
|
|
|
196
220
|
notify(method, params) {
|
|
197
221
|
if (this.disposed)
|
|
198
222
|
return;
|
|
199
|
-
void this.
|
|
223
|
+
void this.liveHeaders()
|
|
224
|
+
.then((configured) => this.fetchImpl(this.options.url, {
|
|
200
225
|
method: "POST",
|
|
201
226
|
headers: {
|
|
202
227
|
"content-type": "application/json",
|
|
203
228
|
accept: "application/json, text/event-stream",
|
|
204
229
|
...metadataHeaders(method, params),
|
|
205
|
-
...
|
|
230
|
+
...configured,
|
|
206
231
|
},
|
|
207
232
|
body: JSON.stringify({ jsonrpc: "2.0", method, ...(params ? { params } : {}) }),
|
|
208
|
-
})
|
|
233
|
+
}))
|
|
234
|
+
.catch(() => {
|
|
209
235
|
/* nothing awaits a notification */
|
|
210
236
|
});
|
|
211
237
|
}
|
|
@@ -228,6 +254,7 @@ export class HttpTransport {
|
|
|
228
254
|
throw new RpcError(-32603, "mcp transport is closed");
|
|
229
255
|
const controller = new AbortController();
|
|
230
256
|
this.streams.add(controller);
|
|
257
|
+
const streamHeaders = await this.liveHeaders();
|
|
231
258
|
const response = await this.fetchImpl(this.options.url, {
|
|
232
259
|
method: "POST",
|
|
233
260
|
signal: controller.signal,
|
|
@@ -235,7 +262,7 @@ export class HttpTransport {
|
|
|
235
262
|
"content-type": "application/json",
|
|
236
263
|
accept: "text/event-stream",
|
|
237
264
|
...metadataHeaders(method, params),
|
|
238
|
-
...
|
|
265
|
+
...streamHeaders,
|
|
239
266
|
},
|
|
240
267
|
// No id: nothing resolves this, and a stream is not a request/response pair.
|
|
241
268
|
body: JSON.stringify({ jsonrpc: "2.0", id: this.nextId++, method, ...(params ? { params } : {}) }),
|
|
@@ -245,6 +272,7 @@ export class HttpTransport {
|
|
|
245
272
|
});
|
|
246
273
|
if (!response.ok) {
|
|
247
274
|
this.streams.delete(controller);
|
|
275
|
+
this.noteChallenge(response);
|
|
248
276
|
throw new RpcError(httpErrorCode(response.status), `mcp http ${response.status} on ${method}`);
|
|
249
277
|
}
|
|
250
278
|
const body = response.body;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/mcp/transport/http.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,0BAA0B,EAAE,QAAQ,EAAqC,MAAM,YAAY,CAAC;AAErG,OAAO,EAAE,iBAAiB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/mcp/transport/http.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/askUser.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { APPROVAL_DISMISSED } from "./approval.js";
|
|
1
|
+
import { APPROVAL_DISMISSED, readFreeText } from "./approval.js";
|
|
2
2
|
import { failQuietly } from "./results.js";
|
|
3
3
|
const askUserDef = {
|
|
4
4
|
name: "ask_user",
|
|
@@ -13,7 +13,14 @@ const askUserDef = {
|
|
|
13
13
|
description: "Ask the user a focused question when the task is genuinely ambiguous and you " +
|
|
14
14
|
"cannot proceed well without their input: which of two real approaches they want, " +
|
|
15
15
|
"a missing requirement, an unclear denial. Give 2-4 concrete options — only the " +
|
|
16
|
-
"first 4 are shown — and their choice comes back to you
|
|
16
|
+
"first 4 are shown — and their choice comes back to you. The user can also TYPE " +
|
|
17
|
+
"their own answer instead of picking one (offered automatically), so write real, " +
|
|
18
|
+
"distinct options rather than trying to pre-cover every case.\n" +
|
|
19
|
+
"When the options carry a trade-off, end each with a short parenthetical that names " +
|
|
20
|
+
"it — \"(recommended)\", \"(simplest)\", \"(fastest)\", \"(most complete, most work)\" — " +
|
|
21
|
+
"so the user can decide without reverse-engineering the difference. Make each option " +
|
|
22
|
+
"self-contained: it is read on its own line, so it should say what it means without " +
|
|
23
|
+
"leaning on the others.\n" +
|
|
17
24
|
"Use it sparingly. Anything you can settle with a sensible default, or find out by " +
|
|
18
25
|
"reading the project, is not a question; asking about it spends the user's " +
|
|
19
26
|
"attention on work they delegated. Prefer acting when the answer is obvious, and " +
|
|
@@ -58,7 +65,14 @@ const askUserDef = {
|
|
|
58
65
|
summary: "ask_user unavailable — proceed with a default",
|
|
59
66
|
};
|
|
60
67
|
}
|
|
61
|
-
|
|
68
|
+
// Always offer a typed answer as one more row: the options are the model's best guesses
|
|
69
|
+
// at what the user wants, and forcing a choice among only those is the exact failure this
|
|
70
|
+
// tool exists to avoid — the user picks the nearest wrong one because there is no way to
|
|
71
|
+
// say the real thing. The row is theirs to write a full answer or a note in.
|
|
72
|
+
const choice = await ctx.requestApproval(question, options.slice(0, 4), undefined, undefined, {
|
|
73
|
+
label: "Write my own answer",
|
|
74
|
+
placeholder: "type your answer",
|
|
75
|
+
});
|
|
62
76
|
// Dismissing the question is not an answer, and must never be reported as one.
|
|
63
77
|
// It used to resolve as the second option, so "Postgres or SQLite?" dismissed came
|
|
64
78
|
// back as "The user chose: SQLite" — a decision attributed to someone who declined
|
|
@@ -84,6 +98,15 @@ const askUserDef = {
|
|
|
84
98
|
summary: `asked: ${clip(question)} → cancelled`,
|
|
85
99
|
};
|
|
86
100
|
}
|
|
101
|
+
// A typed answer is not one of the options — it is the user saying the options missed,
|
|
102
|
+
// so it must be carried back as their own words, not squeezed into "chose".
|
|
103
|
+
const typed = readFreeText(choice);
|
|
104
|
+
if (typed !== null) {
|
|
105
|
+
return {
|
|
106
|
+
output: `The user did not pick an option and wrote their own answer instead: ${typed}`,
|
|
107
|
+
summary: `asked: ${clip(question)} → wrote an answer`,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
87
110
|
return {
|
|
88
111
|
output: `The user chose: ${choice}`,
|
|
89
112
|
summary: `asked: ${clip(question)} → ${clip(choice)}`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"askUser.js","sourceRoot":"","sources":["../../src/tools/askUser.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"askUser.js","sourceRoot":"","sources":["../../src/tools/askUser.ts"],"names":[],"mappings":"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"}
|