@axtary/mcp 0.0.1 → 0.2.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/LICENSE +202 -0
- package/README.md +57 -3
- package/dist/conformance.d.ts +150 -0
- package/dist/conformance.d.ts.map +1 -0
- package/dist/conformance.js +131 -0
- package/dist/conformance.js.map +1 -0
- package/dist/core.d.ts +95 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +311 -0
- package/dist/core.js.map +1 -0
- package/dist/http-client.d.ts +46 -0
- package/dist/http-client.d.ts.map +1 -0
- package/dist/http-client.js +280 -0
- package/dist/http-client.js.map +1 -0
- package/dist/index.d.ts +7 -86
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -295
- package/dist/index.js.map +1 -1
- package/dist/oauth.d.ts +168 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +449 -0
- package/dist/oauth.js.map +1 -0
- package/dist/pins.d.ts +179 -0
- package/dist/pins.d.ts.map +1 -0
- package/dist/pins.js +243 -0
- package/dist/pins.js.map +1 -0
- package/dist/server.d.ts +85 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +289 -0
- package/dist/server.js.map +1 -0
- package/dist/signing.d.ts +218 -0
- package/dist/signing.d.ts.map +1 -0
- package/dist/signing.js +429 -0
- package/dist/signing.js.map +1 -0
- package/package.json +6 -7
package/dist/oauth.js
ADDED
|
@@ -0,0 +1,449 @@
|
|
|
1
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
// Remote-MCP OAuth discovery and request building (provider-neutral).
|
|
4
|
+
//
|
|
5
|
+
// This module implements the protocol half of the MCP authorization spec
|
|
6
|
+
// (2025-06-18): given a remote MCP endpoint, discover its authorization server
|
|
7
|
+
// from RFC 9728 Protected Resource Metadata, then RFC 8414 Authorization Server
|
|
8
|
+
// Metadata; build OAuth 2.1 Authorization-Code + PKCE (RFC 7636) requests that
|
|
9
|
+
// carry the RFC 8707 `resource` parameter binding the token to this exact MCP
|
|
10
|
+
// server; optionally register a public client via RFC 7591 Dynamic Client
|
|
11
|
+
// Registration. It performs no browser/loopback I/O and stores no secrets — the
|
|
12
|
+
// CLI drives the loopback consent and persists the bearer in the local
|
|
13
|
+
// credential broker. Every function takes an injectable `fetch` so the whole
|
|
14
|
+
// flow is deterministically testable against a mock AS + RS.
|
|
15
|
+
//
|
|
16
|
+
// References (verified against primary docs 2026-06-23):
|
|
17
|
+
// - MCP Authorization, spec 2025-06-18
|
|
18
|
+
// - RFC 9728 OAuth 2.0 Protected Resource Metadata
|
|
19
|
+
// - RFC 8414 OAuth 2.0 Authorization Server Metadata
|
|
20
|
+
// - RFC 8707 Resource Indicators for OAuth 2.0
|
|
21
|
+
// - RFC 7636 PKCE
|
|
22
|
+
// - RFC 7591 OAuth 2.0 Dynamic Client Registration
|
|
23
|
+
export const PROTECTED_RESOURCE_WELL_KNOWN = "/.well-known/oauth-protected-resource";
|
|
24
|
+
export const AUTHORIZATION_SERVER_WELL_KNOWN = "/.well-known/oauth-authorization-server";
|
|
25
|
+
export const OPENID_CONFIGURATION_WELL_KNOWN = "/.well-known/openid-configuration";
|
|
26
|
+
/**
|
|
27
|
+
* The canonical resource identifier for an MCP server, per RFC 8707 §2 and the
|
|
28
|
+
* MCP spec's "Canonical Server URI" rules: lowercase scheme + host, no fragment,
|
|
29
|
+
* no trailing slash (unless the path is just "/"). This exact string is the
|
|
30
|
+
* `resource` parameter and must match the `resource` field of the Protected
|
|
31
|
+
* Resource Metadata document.
|
|
32
|
+
*/
|
|
33
|
+
export function canonicalResourceUri(rawUrl) {
|
|
34
|
+
let url;
|
|
35
|
+
try {
|
|
36
|
+
url = new URL(rawUrl);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
throw new Error("mcp_oauth_invalid_resource_url");
|
|
40
|
+
}
|
|
41
|
+
if (url.hash) {
|
|
42
|
+
throw new Error("mcp_oauth_resource_uri_has_fragment");
|
|
43
|
+
}
|
|
44
|
+
if (url.protocol !== "https:" && url.protocol !== "http:") {
|
|
45
|
+
throw new Error(`mcp_oauth_resource_uri_unsupported_scheme:${url.protocol}`);
|
|
46
|
+
}
|
|
47
|
+
const scheme = url.protocol.toLowerCase();
|
|
48
|
+
const host = url.host.toLowerCase();
|
|
49
|
+
let path = url.pathname;
|
|
50
|
+
if (path === "/") {
|
|
51
|
+
path = "";
|
|
52
|
+
}
|
|
53
|
+
else if (path.endsWith("/")) {
|
|
54
|
+
path = path.slice(0, -1);
|
|
55
|
+
}
|
|
56
|
+
// Query and fragment are intentionally dropped: the canonical identifier is
|
|
57
|
+
// scheme + authority + path only.
|
|
58
|
+
return `${scheme}//${host}${path}`;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Allow `https://` always; allow `http://` only for loopback hosts. The MCP
|
|
62
|
+
* authorization spec requires all authorization-server endpoints to be served
|
|
63
|
+
* over HTTPS — we never send a bearer, code, or verifier in cleartext to a
|
|
64
|
+
* remote host. Loopback stays permitted for local conformance servers.
|
|
65
|
+
*/
|
|
66
|
+
export function assertSafeOAuthEndpoint(rawUrl) {
|
|
67
|
+
let url;
|
|
68
|
+
try {
|
|
69
|
+
url = new URL(rawUrl);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
throw new Error("mcp_oauth_invalid_endpoint_url");
|
|
73
|
+
}
|
|
74
|
+
if (url.protocol === "https:") {
|
|
75
|
+
return url;
|
|
76
|
+
}
|
|
77
|
+
if (url.protocol === "http:") {
|
|
78
|
+
const host = url.hostname;
|
|
79
|
+
if (host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]") {
|
|
80
|
+
return url;
|
|
81
|
+
}
|
|
82
|
+
throw new Error("mcp_oauth_insecure_endpoint:http_allowed_only_for_localhost");
|
|
83
|
+
}
|
|
84
|
+
throw new Error(`mcp_oauth_unsupported_scheme:${url.protocol}`);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Parse an RFC 7235 `WWW-Authenticate` header far enough to recover the RFC 9728
|
|
88
|
+
* `resource_metadata` and (optionally) `scope` from a Bearer challenge. We only
|
|
89
|
+
* need quoted/unquoted token68-free `key=value` auth params, which is what real
|
|
90
|
+
* MCP resource servers emit.
|
|
91
|
+
*/
|
|
92
|
+
export function parseWwwAuthenticate(header) {
|
|
93
|
+
const trimmed = header.trim();
|
|
94
|
+
if (trimmed.length === 0) {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
const spaceIndex = trimmed.indexOf(" ");
|
|
98
|
+
const scheme = spaceIndex === -1 ? trimmed : trimmed.slice(0, spaceIndex);
|
|
99
|
+
const remainder = spaceIndex === -1 ? "" : trimmed.slice(spaceIndex + 1);
|
|
100
|
+
const params = {};
|
|
101
|
+
const paramPattern = /([a-zA-Z0-9_-]+)\s*=\s*(?:"([^"]*)"|([^\s,]+))/g;
|
|
102
|
+
let match;
|
|
103
|
+
while ((match = paramPattern.exec(remainder)) !== null) {
|
|
104
|
+
const key = match[1].toLowerCase();
|
|
105
|
+
const value = match[2] !== undefined ? match[2] : (match[3] ?? "");
|
|
106
|
+
params[key] = value;
|
|
107
|
+
}
|
|
108
|
+
return { scheme: scheme.toLowerCase(), params };
|
|
109
|
+
}
|
|
110
|
+
const ProtectedResourceMetadataSchema = z.object({
|
|
111
|
+
resource: z.string().min(1),
|
|
112
|
+
authorization_servers: z.array(z.string().min(1)).optional(),
|
|
113
|
+
scopes_supported: z.array(z.string()).optional(),
|
|
114
|
+
resource_name: z.string().optional(),
|
|
115
|
+
});
|
|
116
|
+
const AuthorizationServerMetadataSchema = z.object({
|
|
117
|
+
issuer: z.string().min(1),
|
|
118
|
+
authorization_endpoint: z.string().min(1),
|
|
119
|
+
token_endpoint: z.string().min(1),
|
|
120
|
+
registration_endpoint: z.string().min(1).optional(),
|
|
121
|
+
response_types_supported: z.array(z.string()).optional(),
|
|
122
|
+
grant_types_supported: z.array(z.string()).optional(),
|
|
123
|
+
code_challenge_methods_supported: z.array(z.string()).optional(),
|
|
124
|
+
scopes_supported: z.array(z.string()).optional(),
|
|
125
|
+
token_endpoint_auth_methods_supported: z.array(z.string()).optional(),
|
|
126
|
+
});
|
|
127
|
+
/**
|
|
128
|
+
* Build the RFC 9728 Protected Resource Metadata URL from an MCP server URL. The
|
|
129
|
+
* well-known segment is inserted between host and path (path-aware), matching
|
|
130
|
+
* RFC 9728 §3.1, so `https://h/mcp` → `https://h/.well-known/oauth-protected-resource/mcp`.
|
|
131
|
+
*/
|
|
132
|
+
export function protectedResourceMetadataUrl(mcpUrl) {
|
|
133
|
+
const url = new URL(mcpUrl);
|
|
134
|
+
const path = url.pathname === "/" ? "" : url.pathname.replace(/\/$/, "");
|
|
135
|
+
return `${url.protocol}//${url.host}${PROTECTED_RESOURCE_WELL_KNOWN}${path}`;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Candidate RFC 8414 Authorization Server Metadata URLs for an issuer, tried in
|
|
139
|
+
* order. RFC 8414 inserts the well-known segment between host and path; we also
|
|
140
|
+
* fall back to the OpenID Connect discovery document, which many real
|
|
141
|
+
* authorization servers (including ones fronting MCP) serve instead.
|
|
142
|
+
*/
|
|
143
|
+
export function authorizationServerMetadataUrls(issuer) {
|
|
144
|
+
const url = new URL(issuer);
|
|
145
|
+
const hasPath = url.pathname !== "/" && url.pathname !== "";
|
|
146
|
+
const path = hasPath ? url.pathname.replace(/\/$/, "") : "";
|
|
147
|
+
const base = `${url.protocol}//${url.host}`;
|
|
148
|
+
if (!hasPath) {
|
|
149
|
+
return [
|
|
150
|
+
`${base}${AUTHORIZATION_SERVER_WELL_KNOWN}`,
|
|
151
|
+
`${base}${OPENID_CONFIGURATION_WELL_KNOWN}`,
|
|
152
|
+
];
|
|
153
|
+
}
|
|
154
|
+
return [
|
|
155
|
+
`${base}${AUTHORIZATION_SERVER_WELL_KNOWN}${path}`,
|
|
156
|
+
`${base}${path}${AUTHORIZATION_SERVER_WELL_KNOWN}`,
|
|
157
|
+
`${base}${OPENID_CONFIGURATION_WELL_KNOWN}${path}`,
|
|
158
|
+
`${base}${path}${OPENID_CONFIGURATION_WELL_KNOWN}`,
|
|
159
|
+
];
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Discover Protected Resource Metadata for an MCP server. Prefers the
|
|
163
|
+
* `resource_metadata` URL advertised in a 401 `WWW-Authenticate` header (RFC
|
|
164
|
+
* 9728 §5.1); otherwise derives the well-known URL from the MCP endpoint. The
|
|
165
|
+
* returned `resource` must equal the canonical MCP URI or we fail closed rather
|
|
166
|
+
* than request a token for the wrong audience.
|
|
167
|
+
*/
|
|
168
|
+
export async function discoverProtectedResourceMetadata(input) {
|
|
169
|
+
const fetchImpl = input.fetch ?? globalThis.fetch;
|
|
170
|
+
if (!fetchImpl) {
|
|
171
|
+
throw new Error("mcp_oauth_fetch_required");
|
|
172
|
+
}
|
|
173
|
+
const advertised = input.wwwAuthenticate
|
|
174
|
+
? parseWwwAuthenticate(input.wwwAuthenticate)?.params.resource_metadata
|
|
175
|
+
: undefined;
|
|
176
|
+
const metadataUrl = advertised ?? protectedResourceMetadataUrl(input.mcpUrl);
|
|
177
|
+
assertSafeOAuthEndpoint(metadataUrl);
|
|
178
|
+
const response = await fetchJson(fetchImpl, metadataUrl, input.timeoutMs);
|
|
179
|
+
const parsed = ProtectedResourceMetadataSchema.safeParse(response);
|
|
180
|
+
if (!parsed.success) {
|
|
181
|
+
throw new Error("mcp_oauth_invalid_protected_resource_metadata");
|
|
182
|
+
}
|
|
183
|
+
const servers = parsed.data.authorization_servers ?? [];
|
|
184
|
+
if (servers.length === 0) {
|
|
185
|
+
throw new Error("mcp_oauth_no_authorization_servers");
|
|
186
|
+
}
|
|
187
|
+
for (const server of servers) {
|
|
188
|
+
assertSafeOAuthEndpoint(server);
|
|
189
|
+
}
|
|
190
|
+
const expectedResource = canonicalResourceUri(input.mcpUrl);
|
|
191
|
+
const advertisedResource = canonicalResourceUri(parsed.data.resource);
|
|
192
|
+
if (advertisedResource !== expectedResource) {
|
|
193
|
+
throw new Error(`mcp_oauth_resource_mismatch:${advertisedResource}!=${expectedResource}`);
|
|
194
|
+
}
|
|
195
|
+
return {
|
|
196
|
+
resource: advertisedResource,
|
|
197
|
+
authorizationServers: servers,
|
|
198
|
+
scopesSupported: parsed.data.scopes_supported ?? [],
|
|
199
|
+
resourceName: parsed.data.resource_name ?? null,
|
|
200
|
+
metadataUrl,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Discover RFC 8414 Authorization Server Metadata for an issuer, trying the
|
|
205
|
+
* path-aware well-known URLs and the OpenID fallback in order. The metadata's
|
|
206
|
+
* `issuer` must equal the requested issuer (RFC 8414 §3.3), and the
|
|
207
|
+
* authorization/token endpoints must be HTTPS (or loopback) or we fail closed.
|
|
208
|
+
*/
|
|
209
|
+
export async function discoverAuthorizationServerMetadata(input) {
|
|
210
|
+
const fetchImpl = input.fetch ?? globalThis.fetch;
|
|
211
|
+
if (!fetchImpl) {
|
|
212
|
+
throw new Error("mcp_oauth_fetch_required");
|
|
213
|
+
}
|
|
214
|
+
assertSafeOAuthEndpoint(input.issuer);
|
|
215
|
+
const candidates = authorizationServerMetadataUrls(input.issuer);
|
|
216
|
+
let lastError = null;
|
|
217
|
+
for (const candidate of candidates) {
|
|
218
|
+
let response;
|
|
219
|
+
try {
|
|
220
|
+
response = await fetchJson(fetchImpl, candidate, input.timeoutMs);
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
lastError = error;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
const parsed = AuthorizationServerMetadataSchema.safeParse(response);
|
|
227
|
+
if (!parsed.success) {
|
|
228
|
+
lastError = new Error("mcp_oauth_invalid_authorization_server_metadata");
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (normalizeIssuer(parsed.data.issuer) !== normalizeIssuer(input.issuer)) {
|
|
232
|
+
throw new Error(`mcp_oauth_issuer_mismatch:${parsed.data.issuer}!=${input.issuer}`);
|
|
233
|
+
}
|
|
234
|
+
assertSafeOAuthEndpoint(parsed.data.authorization_endpoint);
|
|
235
|
+
assertSafeOAuthEndpoint(parsed.data.token_endpoint);
|
|
236
|
+
if (parsed.data.registration_endpoint) {
|
|
237
|
+
assertSafeOAuthEndpoint(parsed.data.registration_endpoint);
|
|
238
|
+
}
|
|
239
|
+
return {
|
|
240
|
+
issuer: parsed.data.issuer,
|
|
241
|
+
authorizationEndpoint: parsed.data.authorization_endpoint,
|
|
242
|
+
tokenEndpoint: parsed.data.token_endpoint,
|
|
243
|
+
registrationEndpoint: parsed.data.registration_endpoint ?? null,
|
|
244
|
+
codeChallengeMethodsSupported: parsed.data.code_challenge_methods_supported ?? [],
|
|
245
|
+
scopesSupported: parsed.data.scopes_supported ?? [],
|
|
246
|
+
grantTypesSupported: parsed.data.grant_types_supported ?? [],
|
|
247
|
+
metadataUrl: candidate,
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
throw new Error(`mcp_oauth_authorization_server_metadata_unreachable:${lastError instanceof Error ? lastError.message : "unknown"}`);
|
|
251
|
+
}
|
|
252
|
+
/** Create an RFC 7636 PKCE verifier/challenge pair (S256). */
|
|
253
|
+
export function createPkcePair(randomVerifier) {
|
|
254
|
+
const verifier = (randomVerifier ?? (() => base64Url(randomBytes(32))))();
|
|
255
|
+
const challenge = base64Url(createHash("sha256").update(verifier).digest());
|
|
256
|
+
return { verifier, challenge, method: "S256" };
|
|
257
|
+
}
|
|
258
|
+
/** Create an anti-CSRF `state` value for the authorization request. */
|
|
259
|
+
export function createOAuthState(randomState) {
|
|
260
|
+
return (randomState ?? (() => base64Url(randomBytes(24))))();
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Build the OAuth 2.1 authorization-request URL. The RFC 8707 `resource`
|
|
264
|
+
* parameter is always included and set to the canonical MCP URI (MUST per the
|
|
265
|
+
* MCP spec, regardless of AS support), alongside PKCE `code_challenge` and the
|
|
266
|
+
* anti-CSRF `state`.
|
|
267
|
+
*/
|
|
268
|
+
export function buildAuthorizationUrl(input) {
|
|
269
|
+
const url = new URL(input.authorizationEndpoint);
|
|
270
|
+
url.searchParams.set("response_type", "code");
|
|
271
|
+
url.searchParams.set("client_id", input.clientId);
|
|
272
|
+
url.searchParams.set("redirect_uri", input.redirectUri);
|
|
273
|
+
url.searchParams.set("state", input.state);
|
|
274
|
+
url.searchParams.set("code_challenge", input.codeChallenge);
|
|
275
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
276
|
+
url.searchParams.set("resource", input.resource);
|
|
277
|
+
if (input.scopes.length > 0) {
|
|
278
|
+
url.searchParams.set("scope", input.scopes.join(" "));
|
|
279
|
+
}
|
|
280
|
+
for (const [key, value] of Object.entries(input.extraParams ?? {})) {
|
|
281
|
+
url.searchParams.set(key, value);
|
|
282
|
+
}
|
|
283
|
+
return url.toString();
|
|
284
|
+
}
|
|
285
|
+
const TokenResponseSchema = z.object({
|
|
286
|
+
access_token: z.string().min(1),
|
|
287
|
+
token_type: z.string().optional(),
|
|
288
|
+
refresh_token: z.string().min(1).optional(),
|
|
289
|
+
scope: z.string().optional(),
|
|
290
|
+
expires_in: z.number().optional(),
|
|
291
|
+
error: z.string().optional(),
|
|
292
|
+
error_description: z.string().optional(),
|
|
293
|
+
});
|
|
294
|
+
/**
|
|
295
|
+
* Exchange an authorization code for tokens at the token endpoint. Sends the
|
|
296
|
+
* RFC 7636 `code_verifier` and the RFC 8707 `resource` parameter so the issued
|
|
297
|
+
* token is audience-bound to this MCP server. Public-client form (no secret) is
|
|
298
|
+
* the default; a confidential client secret is included only when supplied.
|
|
299
|
+
*/
|
|
300
|
+
export async function exchangeAuthorizationCode(input) {
|
|
301
|
+
const values = {
|
|
302
|
+
grant_type: "authorization_code",
|
|
303
|
+
code: input.code,
|
|
304
|
+
redirect_uri: input.redirectUri,
|
|
305
|
+
client_id: input.clientId,
|
|
306
|
+
code_verifier: input.codeVerifier,
|
|
307
|
+
resource: input.resource,
|
|
308
|
+
};
|
|
309
|
+
if (input.clientSecret) {
|
|
310
|
+
values.client_secret = input.clientSecret;
|
|
311
|
+
}
|
|
312
|
+
return postTokenRequest({
|
|
313
|
+
tokenEndpoint: input.tokenEndpoint,
|
|
314
|
+
values,
|
|
315
|
+
fetch: input.fetch,
|
|
316
|
+
timeoutMs: input.timeoutMs,
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Refresh an access token. Per OAuth 2.1 the `resource` parameter is repeated so
|
|
321
|
+
* the refreshed token keeps the same audience; the requested `scope` is narrowed
|
|
322
|
+
* to what was originally granted (never broadened).
|
|
323
|
+
*/
|
|
324
|
+
export async function refreshAccessToken(input) {
|
|
325
|
+
const values = {
|
|
326
|
+
grant_type: "refresh_token",
|
|
327
|
+
refresh_token: input.refreshToken,
|
|
328
|
+
client_id: input.clientId,
|
|
329
|
+
resource: input.resource,
|
|
330
|
+
};
|
|
331
|
+
if (input.clientSecret) {
|
|
332
|
+
values.client_secret = input.clientSecret;
|
|
333
|
+
}
|
|
334
|
+
if (input.scopes && input.scopes.length > 0) {
|
|
335
|
+
values.scope = input.scopes.join(" ");
|
|
336
|
+
}
|
|
337
|
+
return postTokenRequest({
|
|
338
|
+
tokenEndpoint: input.tokenEndpoint,
|
|
339
|
+
values,
|
|
340
|
+
fetch: input.fetch,
|
|
341
|
+
timeoutMs: input.timeoutMs,
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
const RegistrationResponseSchema = z.object({
|
|
345
|
+
client_id: z.string().min(1),
|
|
346
|
+
client_secret: z.string().min(1).optional(),
|
|
347
|
+
client_id_issued_at: z.number().optional(),
|
|
348
|
+
client_secret_expires_at: z.number().optional(),
|
|
349
|
+
});
|
|
350
|
+
/**
|
|
351
|
+
* Register a public OAuth client via RFC 7591 Dynamic Client Registration. We
|
|
352
|
+
* register as a public client using PKCE (`token_endpoint_auth_method: none`)
|
|
353
|
+
* with the loopback redirect and the authorization-code grant, so no client
|
|
354
|
+
* secret is needed or stored. Returns the issued client id.
|
|
355
|
+
*/
|
|
356
|
+
export async function registerOAuthClient(input) {
|
|
357
|
+
const fetchImpl = input.fetch ?? globalThis.fetch;
|
|
358
|
+
if (!fetchImpl) {
|
|
359
|
+
throw new Error("mcp_oauth_fetch_required");
|
|
360
|
+
}
|
|
361
|
+
assertSafeOAuthEndpoint(input.registrationEndpoint);
|
|
362
|
+
const body = {
|
|
363
|
+
client_name: input.clientName,
|
|
364
|
+
redirect_uris: input.redirectUris,
|
|
365
|
+
grant_types: ["authorization_code", "refresh_token"],
|
|
366
|
+
response_types: ["code"],
|
|
367
|
+
token_endpoint_auth_method: "none",
|
|
368
|
+
};
|
|
369
|
+
if (input.scopes && input.scopes.length > 0) {
|
|
370
|
+
body.scope = input.scopes.join(" ");
|
|
371
|
+
}
|
|
372
|
+
const response = await fetchImpl(input.registrationEndpoint, {
|
|
373
|
+
method: "POST",
|
|
374
|
+
headers: { "content-type": "application/json", accept: "application/json" },
|
|
375
|
+
body: JSON.stringify(body),
|
|
376
|
+
signal: timeoutSignal(input.timeoutMs),
|
|
377
|
+
});
|
|
378
|
+
const json = (await response.json());
|
|
379
|
+
if (!response.ok) {
|
|
380
|
+
throw new Error(`mcp_oauth_registration_failed:${response.status}`);
|
|
381
|
+
}
|
|
382
|
+
const parsed = RegistrationResponseSchema.safeParse(json);
|
|
383
|
+
if (!parsed.success) {
|
|
384
|
+
throw new Error("mcp_oauth_invalid_registration_response");
|
|
385
|
+
}
|
|
386
|
+
return {
|
|
387
|
+
clientId: parsed.data.client_id,
|
|
388
|
+
clientSecret: parsed.data.client_secret ?? null,
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
async function postTokenRequest(input) {
|
|
392
|
+
const fetchImpl = input.fetch ?? globalThis.fetch;
|
|
393
|
+
if (!fetchImpl) {
|
|
394
|
+
throw new Error("mcp_oauth_fetch_required");
|
|
395
|
+
}
|
|
396
|
+
assertSafeOAuthEndpoint(input.tokenEndpoint);
|
|
397
|
+
const response = await fetchImpl(input.tokenEndpoint, {
|
|
398
|
+
method: "POST",
|
|
399
|
+
headers: {
|
|
400
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
401
|
+
accept: "application/json",
|
|
402
|
+
},
|
|
403
|
+
body: new URLSearchParams(input.values).toString(),
|
|
404
|
+
signal: timeoutSignal(input.timeoutMs),
|
|
405
|
+
});
|
|
406
|
+
const json = (await response.json().catch(() => null));
|
|
407
|
+
const parsed = TokenResponseSchema.safeParse(json);
|
|
408
|
+
if (!parsed.success) {
|
|
409
|
+
throw new Error(`mcp_oauth_token_request_failed:${response.status}`);
|
|
410
|
+
}
|
|
411
|
+
if (parsed.data.error) {
|
|
412
|
+
throw new Error(`mcp_oauth_token_error:${parsed.data.error}`);
|
|
413
|
+
}
|
|
414
|
+
if (!response.ok) {
|
|
415
|
+
throw new Error(`mcp_oauth_token_request_failed:${response.status}`);
|
|
416
|
+
}
|
|
417
|
+
const scopeRaw = parsed.data.scope ?? "";
|
|
418
|
+
return {
|
|
419
|
+
accessToken: parsed.data.access_token,
|
|
420
|
+
refreshToken: parsed.data.refresh_token ?? null,
|
|
421
|
+
tokenType: parsed.data.token_type ?? "Bearer",
|
|
422
|
+
scope: scopeRaw ? scopeRaw.split(/\s+/).filter(Boolean) : [],
|
|
423
|
+
expiresIn: parsed.data.expires_in ?? null,
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
async function fetchJson(fetchImpl, url, timeoutMs) {
|
|
427
|
+
const response = await fetchImpl(url, {
|
|
428
|
+
headers: { accept: "application/json" },
|
|
429
|
+
signal: timeoutSignal(timeoutMs),
|
|
430
|
+
});
|
|
431
|
+
if (!response.ok) {
|
|
432
|
+
throw new Error(`mcp_oauth_metadata_status:${response.status}`);
|
|
433
|
+
}
|
|
434
|
+
return (await response.json());
|
|
435
|
+
}
|
|
436
|
+
function timeoutSignal(timeoutMs) {
|
|
437
|
+
return AbortSignal.timeout(timeoutMs ?? 15_000);
|
|
438
|
+
}
|
|
439
|
+
function normalizeIssuer(issuer) {
|
|
440
|
+
return issuer.replace(/\/$/, "");
|
|
441
|
+
}
|
|
442
|
+
function base64Url(buffer) {
|
|
443
|
+
return buffer
|
|
444
|
+
.toString("base64")
|
|
445
|
+
.replace(/\+/g, "-")
|
|
446
|
+
.replace(/\//g, "_")
|
|
447
|
+
.replace(/=+$/, "");
|
|
448
|
+
}
|
|
449
|
+
//# sourceMappingURL=oauth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}
|
package/dist/pins.d.ts
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { McpToolDefinitionRecord } from "./core.js";
|
|
3
|
+
export declare const MCP_PINS_SCHEMA_VERSION = "axtary.mcp_pins.v1";
|
|
4
|
+
/** Legacy hash-only manifest; still loadable and upgraded in place. */
|
|
5
|
+
export declare const MCP_PINS_SCHEMA_VERSION_V0 = "axtary.mcp_pins.v0";
|
|
6
|
+
/**
|
|
7
|
+
* A pin is the human-reviewed, persisted identity of an MCP tool: the exact
|
|
8
|
+
* `definitionHash` that was approved for governance. Provenance enforcement is
|
|
9
|
+
* only meaningful if it survives across sessions — otherwise a server that
|
|
10
|
+
* poisons a tool definition between launches is silently re-trusted. The pin
|
|
11
|
+
* manifest is that durable record; the `description` is kept solely so a human
|
|
12
|
+
* can diff old vs new at review time.
|
|
13
|
+
*
|
|
14
|
+
* v1 adds publisher provenance (`publisher`/`kid`/`semver`) and the version
|
|
15
|
+
* chain link (`priorDefinitionHash`): the hash of the version this pin
|
|
16
|
+
* supersedes. The chain is what makes a silent re-definition (rug pull)
|
|
17
|
+
* detectable — a new signed version must reference the version it replaces and
|
|
18
|
+
* bump its semver. These fields are nullable so a hash-only (unsigned) pin and
|
|
19
|
+
* a legacy v0 manifest remain valid.
|
|
20
|
+
*/
|
|
21
|
+
export declare const McpToolPinSchema: z.ZodObject<{
|
|
22
|
+
toolName: z.ZodString;
|
|
23
|
+
definitionHash: z.ZodString;
|
|
24
|
+
schemaVersion: z.ZodString;
|
|
25
|
+
description: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
26
|
+
pinnedAt: z.ZodString;
|
|
27
|
+
publisher: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
28
|
+
kid: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
29
|
+
semver: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
30
|
+
priorDefinitionHash: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
31
|
+
}, z.core.$strip>;
|
|
32
|
+
export type McpToolPin = z.infer<typeof McpToolPinSchema>;
|
|
33
|
+
/** Provenance carried from a verified signed definition into a new pin. */
|
|
34
|
+
export type McpPinProvenance = {
|
|
35
|
+
publisher: string;
|
|
36
|
+
kid: string;
|
|
37
|
+
semver: string;
|
|
38
|
+
priorDefinitionHash: string | null;
|
|
39
|
+
};
|
|
40
|
+
export declare const McpServerPinsSchema: z.ZodObject<{
|
|
41
|
+
serverIdentity: z.ZodString;
|
|
42
|
+
serverVersion: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
43
|
+
tools: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
44
|
+
toolName: z.ZodString;
|
|
45
|
+
definitionHash: z.ZodString;
|
|
46
|
+
schemaVersion: z.ZodString;
|
|
47
|
+
description: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
48
|
+
pinnedAt: z.ZodString;
|
|
49
|
+
publisher: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
50
|
+
kid: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
51
|
+
semver: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
52
|
+
priorDefinitionHash: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
53
|
+
}, z.core.$strip>>>;
|
|
54
|
+
}, z.core.$strip>;
|
|
55
|
+
export type McpServerPins = z.infer<typeof McpServerPinsSchema>;
|
|
56
|
+
export declare const McpPinManifestSchema: z.ZodPipe<z.ZodObject<{
|
|
57
|
+
schemaVersion: z.ZodUnion<readonly [z.ZodLiteral<"axtary.mcp_pins.v1">, z.ZodLiteral<"axtary.mcp_pins.v0">]>;
|
|
58
|
+
servers: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
59
|
+
serverIdentity: z.ZodString;
|
|
60
|
+
serverVersion: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
61
|
+
tools: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
62
|
+
toolName: z.ZodString;
|
|
63
|
+
definitionHash: z.ZodString;
|
|
64
|
+
schemaVersion: z.ZodString;
|
|
65
|
+
description: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
66
|
+
pinnedAt: z.ZodString;
|
|
67
|
+
publisher: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
68
|
+
kid: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
69
|
+
semver: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
70
|
+
priorDefinitionHash: z.ZodDefault<z.ZodNullable<z.ZodString>>;
|
|
71
|
+
}, z.core.$strip>>>;
|
|
72
|
+
}, z.core.$strip>>>;
|
|
73
|
+
}, z.core.$strip>, z.ZodTransform<{
|
|
74
|
+
schemaVersion: string;
|
|
75
|
+
servers: {
|
|
76
|
+
serverIdentity: string;
|
|
77
|
+
serverVersion: string | null;
|
|
78
|
+
tools: {
|
|
79
|
+
toolName: string;
|
|
80
|
+
definitionHash: string;
|
|
81
|
+
schemaVersion: string;
|
|
82
|
+
description: string | null;
|
|
83
|
+
pinnedAt: string;
|
|
84
|
+
publisher: string | null;
|
|
85
|
+
kid: string | null;
|
|
86
|
+
semver: string | null;
|
|
87
|
+
priorDefinitionHash: string | null;
|
|
88
|
+
}[];
|
|
89
|
+
}[];
|
|
90
|
+
}, {
|
|
91
|
+
schemaVersion: "axtary.mcp_pins.v1" | "axtary.mcp_pins.v0";
|
|
92
|
+
servers: {
|
|
93
|
+
serverIdentity: string;
|
|
94
|
+
serverVersion: string | null;
|
|
95
|
+
tools: {
|
|
96
|
+
toolName: string;
|
|
97
|
+
definitionHash: string;
|
|
98
|
+
schemaVersion: string;
|
|
99
|
+
description: string | null;
|
|
100
|
+
pinnedAt: string;
|
|
101
|
+
publisher: string | null;
|
|
102
|
+
kid: string | null;
|
|
103
|
+
semver: string | null;
|
|
104
|
+
priorDefinitionHash: string | null;
|
|
105
|
+
}[];
|
|
106
|
+
}[];
|
|
107
|
+
}>>;
|
|
108
|
+
export type McpPinManifest = z.infer<typeof McpPinManifestSchema>;
|
|
109
|
+
export type McpPinStatus = "pinned" | "new" | "drifted";
|
|
110
|
+
export type McpPinReconcileEntry = {
|
|
111
|
+
status: McpPinStatus;
|
|
112
|
+
serverIdentity: string;
|
|
113
|
+
toolName: string;
|
|
114
|
+
/** Hash the upstream is advertising right now. */
|
|
115
|
+
discoveredHash: string;
|
|
116
|
+
discoveredDescription: string | null;
|
|
117
|
+
/** Hash that was previously pinned, when one exists (pinned/drifted). */
|
|
118
|
+
pinnedHash: string | null;
|
|
119
|
+
pinnedDescription: string | null;
|
|
120
|
+
};
|
|
121
|
+
export declare function emptyMcpPinManifest(): McpPinManifest;
|
|
122
|
+
export declare function parseMcpPinManifest(input: unknown): McpPinManifest;
|
|
123
|
+
/**
|
|
124
|
+
* Load the pin manifest. A missing file is the legitimate first-use state and
|
|
125
|
+
* yields an empty manifest; a present-but-corrupt file fails loud (we never
|
|
126
|
+
* silently fall back to "trust everything").
|
|
127
|
+
*/
|
|
128
|
+
export declare function loadMcpPinManifest(path: string): Promise<McpPinManifest>;
|
|
129
|
+
export declare function saveMcpPinManifest(path: string, manifest: McpPinManifest): Promise<void>;
|
|
130
|
+
export declare function findMcpToolPin(manifest: McpPinManifest, serverIdentity: string, toolName: string): McpToolPin | undefined;
|
|
131
|
+
/**
|
|
132
|
+
* Compare what the upstream advertises now against the persisted pins. Pure:
|
|
133
|
+
* no IO, no mutation. This is the heart of cross-session drift detection.
|
|
134
|
+
*/
|
|
135
|
+
export declare function reconcileMcpPins(manifest: McpPinManifest, definitions: McpToolDefinitionRecord[]): McpPinReconcileEntry[];
|
|
136
|
+
/**
|
|
137
|
+
* Return a new manifest with the given definitions pinned at their current
|
|
138
|
+
* hash. Used both for trust-on-first-use (new tools) and for the explicit
|
|
139
|
+
* `mcp review --accept` path (drifted tools). Never mutates the input.
|
|
140
|
+
*/
|
|
141
|
+
export declare function pinMcpDefinitions(manifest: McpPinManifest, definitions: McpToolDefinitionRecord[], options?: {
|
|
142
|
+
now?: () => string;
|
|
143
|
+
/**
|
|
144
|
+
* Provenance for a definition being pinned, keyed by `definitionHash`.
|
|
145
|
+
* When present, the pin records the publisher identity and version chain;
|
|
146
|
+
* when absent, the pin is hash-only (unsigned), exactly as in v0.
|
|
147
|
+
*/
|
|
148
|
+
provenance?: (definition: McpToolDefinitionRecord) => McpPinProvenance | undefined;
|
|
149
|
+
}): McpPinManifest;
|
|
150
|
+
/**
|
|
151
|
+
* The verdict for a candidate (signed) definition against the pinned history.
|
|
152
|
+
* This is the rug-pull defense at the chain level: a new signed version is
|
|
153
|
+
* only "continuous" if it both references the version it supersedes and bumps
|
|
154
|
+
* its semver. Anything else is surfaced, never silently accepted.
|
|
155
|
+
*/
|
|
156
|
+
export type McpChainVerdict = "first_pin" | "unchanged" | "continuous" | "version_not_incremented" | "broken_chain";
|
|
157
|
+
export type McpChainEvaluation = {
|
|
158
|
+
verdict: McpChainVerdict;
|
|
159
|
+
/** Stable reason code when the chain does not advance cleanly. */
|
|
160
|
+
reason: string | null;
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Pure: compare a verified candidate against the current pin. No IO. Used by
|
|
164
|
+
* the review/accept path to decide whether a drifted-but-signed definition is
|
|
165
|
+
* a legitimate next version or a broken/regressed chain that needs a human.
|
|
166
|
+
*/
|
|
167
|
+
export declare function evaluateMcpVersionChain(input: {
|
|
168
|
+
pin: McpToolPin | undefined;
|
|
169
|
+
candidateHash: string;
|
|
170
|
+
candidateSemver: string | null;
|
|
171
|
+
candidatePriorHash: string | null;
|
|
172
|
+
}): McpChainEvaluation;
|
|
173
|
+
/**
|
|
174
|
+
* Deterministic semver ordering: numeric major.minor.patch, then prerelease
|
|
175
|
+
* (a build *with* a prerelease tag is lower than the same release without).
|
|
176
|
+
* Returns <0, 0, or >0.
|
|
177
|
+
*/
|
|
178
|
+
export declare function compareSemver(left: string, right: string): number;
|
|
179
|
+
//# sourceMappingURL=pins.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pins.d.ts","sourceRoot":"","sources":["../src/pins.ts"],"names":[],"mappings":"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"}
|