toolcraft 0.0.313 → 0.0.315

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.
Files changed (24) hide show
  1. package/composition.json +3 -3
  2. package/dist/composition.json +3 -3
  3. package/node_modules/tiny-http-mcp-server/dist/composition.json +1 -1
  4. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/README.md +25 -1
  5. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/auth-store-session-store.d.ts +1 -6
  6. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/auth-store-session-store.js +7 -18
  7. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/client-registration.d.ts +4 -0
  8. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/client-registration.js +103 -0
  9. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/default-oauth-client-provider.js +76 -50
  10. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/scope.d.ts +2 -0
  11. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/scope.js +9 -0
  12. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/token-auth-method.d.ts +2 -0
  13. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/token-auth-method.js +7 -0
  14. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/token-endpoint.d.ts +3 -1
  15. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/token-endpoint.js +23 -10
  16. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/types.d.ts +27 -4
  17. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/index.d.ts +2 -1
  18. package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/index.js +1 -0
  19. package/node_modules/tiny-http-mcp-server/package.json +1 -1
  20. package/node_modules/tiny-mcp-client/dist/index.d.ts +27 -4
  21. package/node_modules/tiny-mcp-client/dist/index.js +226 -73
  22. package/node_modules/tiny-stdio-mcp-server/dist/composition.json +1 -1
  23. package/node_modules/toolcraft-schema/package.json +1 -1
  24. package/package.json +2 -2
@@ -3395,6 +3395,141 @@ var SubscriptionManager = class {
3395
3395
  }
3396
3396
  };
3397
3397
 
3398
+ // ../mcp-oauth/dist/client/scope.js
3399
+ function normalizeOAuthScope(scope) {
3400
+ if (scope === void 0)
3401
+ return void 0;
3402
+ if (typeof scope !== "string" || [...scope].some((char) => char.charCodeAt(0) < 32 || char.charCodeAt(0) > 126 || char === '"' || char === "\\"))
3403
+ throw new Error("Invalid OAuth scope syntax");
3404
+ const normalized = [...new Set(scope.split(" ").filter(Boolean))].sort().join(" ");
3405
+ return normalized || void 0;
3406
+ }
3407
+
3408
+ // ../mcp-oauth/dist/client/token-auth-method.js
3409
+ function normalizeOAuthTokenEndpointAuthMethod(value) {
3410
+ if (value === void 0 || value === null)
3411
+ return void 0;
3412
+ if (value !== "none" && value !== "client_secret_post" && value !== "client_secret_basic")
3413
+ throw new Error("Unsupported OAuth token endpoint authentication method");
3414
+ return value;
3415
+ }
3416
+
3417
+ // ../mcp-oauth/dist/client/client-registration.js
3418
+ function parseOAuthClientRegistration(value) {
3419
+ const invalid = () => new Error("Invalid OAuth client registration metadata");
3420
+ let nodes = 0;
3421
+ function copy(input, depth) {
3422
+ if (++nodes > 2e4 || depth > 64)
3423
+ throw invalid();
3424
+ if (input === null || typeof input === "boolean" || typeof input === "string")
3425
+ return input;
3426
+ if (typeof input === "number" && Number.isFinite(input))
3427
+ return input;
3428
+ if (typeof input !== "object" || input === null)
3429
+ throw invalid();
3430
+ const descriptors = Object.getOwnPropertyDescriptors(input);
3431
+ if (Array.isArray(input)) {
3432
+ const length = descriptors.length?.value;
3433
+ if (length > 2e4)
3434
+ throw invalid();
3435
+ const result2 = [];
3436
+ for (let index = 0; index < length; index++) {
3437
+ const descriptor = descriptors[String(index)];
3438
+ if (descriptor === void 0 || !Object.hasOwn(descriptor, "value"))
3439
+ throw invalid();
3440
+ result2.push(copy(descriptor.value, depth + 1));
3441
+ }
3442
+ return result2;
3443
+ }
3444
+ if (Object.getPrototypeOf(input) !== Object.prototype && Object.getPrototypeOf(input) !== null)
3445
+ throw invalid();
3446
+ return Object.fromEntries(Object.entries(descriptors).filter(([, descriptor]) => descriptor.enumerable).map(([key2, descriptor]) => {
3447
+ if (!Object.hasOwn(descriptor, "value"))
3448
+ throw invalid();
3449
+ return [key2, copy(descriptor.value, depth + 1)];
3450
+ }));
3451
+ }
3452
+ let result;
3453
+ try {
3454
+ result = copy(value, 0);
3455
+ } catch {
3456
+ throw invalid();
3457
+ }
3458
+ if (typeof result !== "object" || result === null || Array.isArray(result))
3459
+ throw invalid();
3460
+ const record2 = result;
3461
+ if (!Object.hasOwn(record2, "client_id") || typeof record2.client_id !== "string" || record2.client_id.trim() === "")
3462
+ throw new Error("OAuth client registration response missing client_id");
3463
+ for (const key2 of [
3464
+ "client_id",
3465
+ "client_secret",
3466
+ "token_endpoint_auth_method",
3467
+ "application_type",
3468
+ "client_name",
3469
+ "client_uri",
3470
+ "logo_uri",
3471
+ "scope",
3472
+ "tos_uri",
3473
+ "policy_uri",
3474
+ "jwks_uri",
3475
+ "software_id",
3476
+ "software_version",
3477
+ "software_statement",
3478
+ "registration_access_token",
3479
+ "registration_client_uri",
3480
+ "issuer"
3481
+ ]) {
3482
+ if (Object.hasOwn(record2, key2) && record2[key2] !== null && typeof record2[key2] !== "string")
3483
+ throw invalid();
3484
+ }
3485
+ if (typeof record2.client_secret === "string" && record2.client_secret.trim() === "")
3486
+ throw invalid();
3487
+ for (const key2 of ["redirect_uris", "grant_types", "response_types", "contacts"]) {
3488
+ const entry = record2[key2];
3489
+ if (Object.hasOwn(record2, key2) && entry !== null && (!Array.isArray(entry) || entry.some((item) => typeof item !== "string")))
3490
+ throw invalid();
3491
+ }
3492
+ for (const key2 of ["client_id_issued_at", "client_secret_expires_at"]) {
3493
+ const entry = record2[key2];
3494
+ if (Object.hasOwn(record2, key2) && entry !== null && (typeof entry !== "number" || !Number.isSafeInteger(entry) || entry < 0))
3495
+ throw invalid();
3496
+ }
3497
+ try {
3498
+ normalizeOAuthScope(Object.hasOwn(record2, "scope") && record2.scope !== null ? record2.scope : void 0);
3499
+ } catch {
3500
+ throw invalid();
3501
+ }
3502
+ if (Buffer.byteLength(JSON.stringify(record2), "utf8") > 64 * 1024)
3503
+ throw invalid();
3504
+ return record2;
3505
+ }
3506
+ function normalizeStoredOAuthClient(value) {
3507
+ if (typeof value !== "object" || value === null || Array.isArray(value))
3508
+ return null;
3509
+ const record2 = value;
3510
+ const clientId = Object.hasOwn(record2, "clientId") ? record2.clientId : void 0;
3511
+ const clientSecret = Object.hasOwn(record2, "clientSecret") ? record2.clientSecret : void 0;
3512
+ if (typeof clientId !== "string" || clientId.trim() === "" || clientSecret !== void 0 && (typeof clientSecret !== "string" || clientSecret.trim() === ""))
3513
+ return null;
3514
+ const client = { clientId: clientId.trim(), ...clientSecret === void 0 ? {} : { clientSecret: clientSecret.trim() } };
3515
+ const method = normalizeOAuthTokenEndpointAuthMethod(Object.hasOwn(record2, "tokenEndpointAuthMethod") ? record2.tokenEndpointAuthMethod : void 0);
3516
+ if (Object.hasOwn(record2, "registration") && record2.registration !== void 0) {
3517
+ const registration = parseOAuthClientRegistration(record2.registration);
3518
+ const registeredSecret = Object.hasOwn(registration, "client_secret") ? registration.client_secret?.trim() : void 0;
3519
+ if (registration.client_id.trim() !== client.clientId || registeredSecret !== client.clientSecret)
3520
+ throw new Error("OAuth client registration does not match the client identity");
3521
+ client.registration = registration;
3522
+ const registrationMethod = normalizeOAuthTokenEndpointAuthMethod(Object.hasOwn(registration, "token_endpoint_auth_method") ? registration.token_endpoint_auth_method : void 0);
3523
+ if (method !== void 0 && registrationMethod !== void 0 && method !== registrationMethod)
3524
+ throw new Error("OAuth token endpoint authentication conflicts with the client registration");
3525
+ if (registrationMethod !== void 0)
3526
+ client.tokenEndpointAuthMethod = registrationMethod;
3527
+ }
3528
+ if (method !== void 0)
3529
+ client.tokenEndpointAuthMethod = method;
3530
+ return client;
3531
+ }
3532
+
3398
3533
  // ../mcp-oauth/dist/client/auth-store-session-store.js
3399
3534
  import crypto from "node:crypto";
3400
3535
  import path4 from "node:path";
@@ -4128,14 +4263,8 @@ function createAuthStoreClientStore(options, namespace) {
4128
4263
  } catch {
4129
4264
  throw new Error("Stored OAuth client must be valid JSON; reset the store explicitly to recover");
4130
4265
  }
4131
- const clientId = isObjectRecord(parsed) ? getOwnString(parsed, "clientId") : void 0;
4132
- if (clientId !== void 0) {
4133
- const client = { clientId };
4134
- if (isObjectRecord(parsed) && Object.prototype.hasOwnProperty.call(parsed, "clientSecret")) {
4135
- client.clientSecret = getOwnEntry3(parsed, "clientSecret");
4136
- }
4137
- return client;
4138
- }
4266
+ if (isObjectRecord(parsed) && typeof getOwnEntry3(parsed, "clientId") === "string")
4267
+ return parsed;
4139
4268
  throw new Error("Stored OAuth client must be a JSON object with clientId");
4140
4269
  },
4141
4270
  async save(issuer, client) {
@@ -4201,14 +4330,7 @@ function isStoredOAuthSession(value) {
4201
4330
  if (!isObjectRecord(value)) {
4202
4331
  return false;
4203
4332
  }
4204
- return isNonBlankOwnString(value, "resource") && isNonBlankOwnString(value, "authorizationServer") && isStoredOAuthClient(getOwnEntry3(value, "client")) && isStoredOAuthDiscovery(getOwnEntry3(value, "discovery")) && (getOwnEntry3(value, "refreshState") === void 0 || getOwnEntry3(value, "refreshState") === "pending" && getOwnEntry3(value, "tokens") === void 0) && isStoredOAuthTokensOrMissing(getOwnEntry3(value, "tokens"));
4205
- }
4206
- function isStoredOAuthClient(value) {
4207
- if (!isObjectRecord(value) || !isNonBlankOwnString(value, "clientId")) {
4208
- return false;
4209
- }
4210
- const clientSecret = getOwnEntry3(value, "clientSecret");
4211
- return clientSecret === void 0 || typeof clientSecret === "string" && clientSecret.trim().length > 0;
4333
+ return isNonBlankOwnString(value, "resource") && isNonBlankOwnString(value, "authorizationServer") && normalizeStoredOAuthClient(getOwnEntry3(value, "client")) !== null && isStoredOAuthDiscovery(getOwnEntry3(value, "discovery")) && (getOwnEntry3(value, "requestedScope") === void 0 || isNonBlankOwnString(value, "requestedScope")) && (getOwnEntry3(value, "refreshState") === void 0 || getOwnEntry3(value, "refreshState") === "pending" && getOwnEntry3(value, "tokens") === void 0) && isStoredOAuthTokensOrMissing(getOwnEntry3(value, "tokens"));
4212
4334
  }
4213
4335
  function isStoredOAuthDiscovery(value) {
4214
4336
  if (!isObjectRecord(value)) {
@@ -4655,6 +4777,7 @@ async function exchangeAuthorizationCode(input) {
4655
4777
  tokenEndpoint: input.tokenEndpoint,
4656
4778
  clientId: input.clientId,
4657
4779
  clientSecret: input.clientSecret,
4780
+ tokenEndpointAuthMethod: input.tokenEndpointAuthMethod,
4658
4781
  params: {
4659
4782
  grant_type: "authorization_code",
4660
4783
  code: input.code,
@@ -4673,6 +4796,7 @@ async function refreshAccessToken(input) {
4673
4796
  tokenEndpoint: input.tokenEndpoint,
4674
4797
  clientId: input.clientId,
4675
4798
  clientSecret: input.clientSecret,
4799
+ tokenEndpointAuthMethod: input.tokenEndpointAuthMethod,
4676
4800
  params: {
4677
4801
  grant_type: "refresh_token",
4678
4802
  refresh_token: input.refreshToken,
@@ -4684,21 +4808,26 @@ async function refreshAccessToken(input) {
4684
4808
  });
4685
4809
  }
4686
4810
  async function requestTokens(input) {
4687
- const body = new URLSearchParams({
4688
- client_id: input.clientId,
4689
- ...input.params
4690
- });
4691
- if (input.clientSecret !== void 0) {
4692
- body.set("client_secret", input.clientSecret);
4811
+ const method = normalizeOAuthTokenEndpointAuthMethod(input.tokenEndpointAuthMethod) ?? (input.clientSecret === void 0 ? "none" : "client_secret_post");
4812
+ if (method !== "none" && (input.clientSecret === void 0 || input.clientSecret.trim() === ""))
4813
+ throw new Error("OAuth token endpoint authentication requires a client secret");
4814
+ const body = new URLSearchParams(input.params);
4815
+ const headers = new Headers({ "Content-Type": "application/x-www-form-urlencoded" });
4816
+ if (method === "client_secret_basic") {
4817
+ const encoded = new URLSearchParams({ credential: input.clientId }).toString().slice("credential=".length);
4818
+ const encodedSecret = new URLSearchParams({ credential: input.clientSecret }).toString().slice("credential=".length);
4819
+ headers.set("Authorization", `Basic ${Buffer.from(`${encoded}:${encodedSecret}`).toString("base64")}`);
4820
+ } else {
4821
+ body.set("client_id", input.clientId);
4822
+ if (method === "client_secret_post")
4823
+ body.set("client_secret", input.clientSecret);
4693
4824
  }
4694
4825
  input.signal?.throwIfAborted();
4695
4826
  const deadline = AbortSignal.timeout(3e4);
4696
4827
  const signal = input.signal === void 0 ? deadline : AbortSignal.any([input.signal, deadline]);
4697
4828
  const response = await fetchMcpResponse(input.fetch, input.tokenEndpoint, {
4698
4829
  method: "POST",
4699
- headers: {
4700
- "Content-Type": "application/x-www-form-urlencoded"
4701
- },
4830
+ headers,
4702
4831
  body: body.toString(),
4703
4832
  signal
4704
4833
  });
@@ -4726,7 +4855,9 @@ async function requestTokens(input) {
4726
4855
  const refreshToken = getOwnEntry5(payload, "refresh_token");
4727
4856
  const scope = getOwnEntry5(payload, "scope");
4728
4857
  const normalizedRefreshToken = typeof refreshToken === "string" && refreshToken.trim().length > 0 ? refreshToken.trim() : void 0;
4729
- const normalizedScope = typeof scope === "string" && scope.trim().length > 0 ? scope.trim() : void 0;
4858
+ const normalizedScope = normalizeOAuthScope(scope);
4859
+ if (scope !== void 0 && normalizedScope === void 0)
4860
+ throw new Error("Invalid OAuth scope syntax in token response");
4730
4861
  return {
4731
4862
  accessToken: normalizedAccessToken,
4732
4863
  refreshToken: normalizedRefreshToken === void 0 ? void 0 : normalizedRefreshToken,
@@ -4847,6 +4978,11 @@ function createOAuthClientProvider(options) {
4847
4978
  function createDefaultOAuthClientProvider(options) {
4848
4979
  loopbackTarget(options.browser);
4849
4980
  assertPersistenceNamespace(options.persistenceNamespace);
4981
+ const clientMetadata = getClientMetadata(options.client);
4982
+ const requestedScope = clientMetadata?.scope;
4983
+ const configuredClient = normalizeConfiguredClient(options.client);
4984
+ const requestedTokenMethod = normalizeOAuthTokenEndpointAuthMethod(options.client.tokenEndpointAuthMethod);
4985
+ const configuredTokenMethod = requestedTokenMethod ?? configuredClient?.tokenEndpointAuthMethod;
4850
4986
  const sessionStore = options.sessionStore ?? createAuthStoreSessionStore(options.authStore, options.persistenceNamespace);
4851
4987
  const clientStore = options.authStore === void 0 ? null : createAuthStoreClientStore(options.authStore, options.persistenceNamespace);
4852
4988
  const now = options.now ?? Date.now;
@@ -4864,11 +5000,13 @@ function createDefaultOAuthClientProvider(options) {
4864
5000
  const initialGrant = options.initialGrant === void 0 ? void 0 : {
4865
5001
  resource: canonicalizeResourceIndicator(options.initialGrant.resource),
4866
5002
  tokens: normalizeStoredTokens(options.initialGrant.tokens),
4867
- client: normalizeConfiguredClient(options.client)
5003
+ client: configuredClient
4868
5004
  };
4869
5005
  if (initialGrant !== void 0 && (initialGrant.tokens === void 0 || initialGrant.client === null))
4870
5006
  throw new Error("OAuth initial grant requires valid tokens and the original client ID");
4871
5007
  if (initialGrant?.tokens !== void 0) {
5008
+ if (requestedScope !== void 0 && initialGrant.tokens.scope !== requestedScope)
5009
+ throw new Error("OAuth initial grant does not match the requested OAuth scope");
4872
5010
  try {
4873
5011
  new Headers({ Authorization: `Bearer ${initialGrant.tokens.accessToken}` });
4874
5012
  } catch {
@@ -4956,6 +5094,7 @@ function createDefaultOAuthClientProvider(options) {
4956
5094
  authorizationServer: discovery.authorizationServer,
4957
5095
  client: initialGrant.client,
4958
5096
  tokens: initialGrant.tokens,
5097
+ ...requestedScope === void 0 ? {} : { requestedScope },
4959
5098
  discovery: toStoredDiscovery(discovery)
4960
5099
  };
4961
5100
  await saveSession(canonicalResource, session);
@@ -4965,11 +5104,15 @@ function createDefaultOAuthClientProvider(options) {
4965
5104
  if (forceRefresh && rejectedTokens !== void 0 && (rejectedTokens === null || session?.tokens === void 0 || !sameTokenGrant(session.tokens, rejectedTokens)))
4966
5105
  forceRefresh = false;
4967
5106
  const sessionDiscovery = resolveDiscovery(discovery, session);
4968
- if ((options.client.mode === "static" || initialGrant !== void 0) && session !== null && (session.tokens !== void 0 || session.refreshState === "pending")) {
4969
- const configured = normalizeConfiguredClient(options.client);
5107
+ if ((options.client.mode === "static" || configuredClient?.registration !== void 0 || initialGrant !== void 0) && session !== null && (session.tokens !== void 0 || session.refreshState === "pending")) {
5108
+ const configured = configuredClient;
4970
5109
  if (configured === null || configured.clientId !== session.client.clientId || configured.clientSecret !== session.client.clientSecret)
4971
5110
  throw new Error("Stored session belongs to a different OAuth client; use separate persistence or explicitly reset it");
4972
5111
  }
5112
+ if (requestedScope !== void 0 && session?.tokens !== void 0 && normalizeOAuthScope(session.tokens.scope ?? session.requestedScope) !== requestedScope)
5113
+ throw new Error("Stored session does not match the requested OAuth scope; authorize again or select separate persistence");
5114
+ if (configuredTokenMethod !== void 0 && session !== null && (session.tokens !== void 0 || session.refreshState === "pending") && (session.client.tokenEndpointAuthMethod ?? (session.client.clientSecret === void 0 ? "none" : "client_secret_post")) !== configuredTokenMethod)
5115
+ throw new Error("Stored session does not match the requested OAuth token endpoint authentication; select separate persistence or reset it");
4973
5116
  if (session?.refreshState === "pending") {
4974
5117
  if (!allowInteractive || options.allowInteractive === false || sessionDiscovery === void 0)
4975
5118
  throw new Error("OAuth refresh outcome is unknown; authorize again before using this resource");
@@ -5002,6 +5145,7 @@ function createDefaultOAuthClientProvider(options) {
5002
5145
  if (session.tokens?.refreshToken === void 0) {
5003
5146
  return session;
5004
5147
  }
5148
+ assertTokenEndpointAuthentication(session.client, discovery.authorizationServerMetadata);
5005
5149
  const pendingSession = { ...clearSessionTokens(session), refreshState: "pending" };
5006
5150
  await saveSession(resource, pendingSession);
5007
5151
  signal?.throwIfAborted();
@@ -5013,6 +5157,7 @@ function createDefaultOAuthClientProvider(options) {
5013
5157
  tokenEndpoint: requireOwnString(discovery.authorizationServerMetadata, "token_endpoint", "Authorization server metadata"),
5014
5158
  clientId: session.client.clientId,
5015
5159
  clientSecret: session.client.clientSecret,
5160
+ tokenEndpointAuthMethod: session.client.tokenEndpointAuthMethod,
5016
5161
  refreshToken: session.tokens.refreshToken,
5017
5162
  resource,
5018
5163
  fetch: fetch2,
@@ -5046,10 +5191,13 @@ function createDefaultOAuthClientProvider(options) {
5046
5191
  ...session,
5047
5192
  tokens: {
5048
5193
  ...refreshedTokens,
5049
- refreshToken: refreshedTokens.refreshToken ?? session.tokens.refreshToken
5194
+ refreshToken: refreshedTokens.refreshToken ?? session.tokens.refreshToken,
5195
+ scope: refreshedTokens.scope ?? session.tokens.scope
5050
5196
  },
5051
5197
  discovery: toStoredDiscovery(discovery)
5052
5198
  };
5199
+ if (requestedScope !== void 0 && normalizeOAuthScope(updatedSession.tokens?.scope ?? session.requestedScope) !== requestedScope)
5200
+ throw new Error("OAuth refresh response does not match the requested OAuth scope; authorize again");
5053
5201
  await saveSession(resource, updatedSession);
5054
5202
  return updatedSession;
5055
5203
  }
@@ -5073,10 +5221,12 @@ function createDefaultOAuthClientProvider(options) {
5073
5221
  let resolvedClient = null;
5074
5222
  try {
5075
5223
  resolvedClient = await resolveClient(currentSession, discovery, loopback.redirectUri, fetch2, signal);
5224
+ assertTokenEndpointAuthentication(resolvedClient.client, discovery.authorizationServerMetadata);
5076
5225
  const sessionWithoutTokens = {
5077
5226
  resource,
5078
5227
  authorizationServer: discovery.authorizationServer,
5079
5228
  client: resolvedClient.client,
5229
+ ...requestedScope === void 0 ? {} : { requestedScope },
5080
5230
  discovery: toStoredDiscovery(discovery)
5081
5231
  };
5082
5232
  await saveSession(resource, sessionWithoutTokens);
@@ -5088,13 +5238,14 @@ function createDefaultOAuthClientProvider(options) {
5088
5238
  clientId: resolvedClient.client.clientId,
5089
5239
  redirectUri: loopback.redirectUri,
5090
5240
  codeChallenge: challenge,
5091
- clientMetadata: getClientMetadata(options.client)
5241
+ clientMetadata
5092
5242
  });
5093
5243
  const code = await loopback.waitForCode(authorizationUrl);
5094
5244
  const tokens = await exchangeAuthorizationCode({
5095
5245
  tokenEndpoint: requireOwnString(discovery.authorizationServerMetadata, "token_endpoint", "Authorization server metadata"),
5096
5246
  clientId: resolvedClient.client.clientId,
5097
5247
  clientSecret: resolvedClient.client.clientSecret,
5248
+ tokenEndpointAuthMethod: resolvedClient.client.tokenEndpointAuthMethod,
5098
5249
  code,
5099
5250
  codeVerifier: verifier,
5100
5251
  redirectUri: loopback.redirectUri,
@@ -5103,6 +5254,8 @@ function createDefaultOAuthClientProvider(options) {
5103
5254
  signal,
5104
5255
  now
5105
5256
  });
5257
+ if (requestedScope !== void 0 && tokens.scope !== void 0 && normalizeOAuthScope(tokens.scope) !== requestedScope)
5258
+ throw new Error("OAuth authorization response does not match the requested OAuth scope");
5106
5259
  const session = {
5107
5260
  ...sessionWithoutTokens,
5108
5261
  tokens
@@ -5132,8 +5285,7 @@ function createDefaultOAuthClientProvider(options) {
5132
5285
  }
5133
5286
  async function resolveClient(existingSession, discovery, redirectUri, fetch2, parentSignal) {
5134
5287
  parentSignal?.throwIfAborted();
5135
- const configuredClient = normalizeConfiguredClient(options.client);
5136
- if (options.client.mode === "static") {
5288
+ if (options.client.mode === "static" || configuredClient?.registration !== void 0) {
5137
5289
  if (configuredClient === null) {
5138
5290
  throw new Error("OAuth client_id must not be blank");
5139
5291
  }
@@ -5180,7 +5332,11 @@ function createDefaultOAuthClientProvider(options) {
5180
5332
  };
5181
5333
  }
5182
5334
  }
5183
- const registrationBody = buildClientRegistrationBody(getClientMetadata(options.client), redirectUri);
5335
+ const supported = getSupportedTokenAuthMethods(discovery.authorizationServerMetadata);
5336
+ const registrationMethod = requestedTokenMethod ?? (supported === void 0 ? "none" : ["none", "client_secret_basic", "client_secret_post"].find((method) => supported.includes(method)));
5337
+ if (registrationMethod === void 0 || supported !== void 0 && !supported.includes(registrationMethod))
5338
+ throw new Error("Authorization server does not support the requested OAuth token endpoint authentication");
5339
+ const registrationBody = buildClientRegistrationBody(clientMetadata, redirectUri, registrationMethod);
5184
5340
  const deadline = AbortSignal.timeout(3e4);
5185
5341
  const signal = parentSignal === void 0 ? deadline : AbortSignal.any([parentSignal, deadline]);
5186
5342
  const response = await fetchMcpResponse(fetch2, registrationEndpoint, {
@@ -5192,14 +5348,14 @@ function createDefaultOAuthClientProvider(options) {
5192
5348
  signal
5193
5349
  });
5194
5350
  const payload = await readOAuthJsonObjectResponse(response, signal);
5195
- const clientId = getOwnString2(payload, "client_id");
5196
- if (clientId === void 0 || clientId.trim().length === 0) {
5197
- throw new Error("OAuth client registration response missing client_id");
5198
- }
5199
- const clientSecret = getOwnString2(payload, "client_secret");
5351
+ const registration = parseOAuthClientRegistration(payload);
5352
+ const registeredSecret = getOwnString2(registration, "client_secret");
5353
+ const responseMethod = normalizeOAuthTokenEndpointAuthMethod(getOwnEntry6(registration, "token_endpoint_auth_method")) ?? requestedTokenMethod ?? (supported === void 0 ? void 0 : normalizeOAuthTokenEndpointAuthMethod(registrationMethod));
5200
5354
  const registeredClient = {
5201
- clientId: clientId.trim(),
5202
- clientSecret: clientSecret !== void 0 && clientSecret.trim().length > 0 ? clientSecret.trim() : void 0
5355
+ clientId: registration.client_id.trim(),
5356
+ ...registeredSecret === void 0 ? {} : { clientSecret: registeredSecret.trim() },
5357
+ ...responseMethod === void 0 ? {} : { tokenEndpointAuthMethod: responseMethod },
5358
+ registration
5203
5359
  };
5204
5360
  await saveRegisteredClient(discovery.authorizationServer, registeredClient);
5205
5361
  return {
@@ -5212,7 +5368,7 @@ function createDefaultOAuthClientProvider(options) {
5212
5368
  return normalizeLoadedSession(await sessionStore.load(resource));
5213
5369
  }
5214
5370
  async function saveSession(resource, session) {
5215
- await sessionStore.save(resource, session);
5371
+ await sessionStore.save(resource, structuredClone(session));
5216
5372
  }
5217
5373
  async function clearSession(resource) {
5218
5374
  await sessionStore.clear(resource);
@@ -5225,7 +5381,7 @@ function createDefaultOAuthClientProvider(options) {
5225
5381
  return null;
5226
5382
  }
5227
5383
  const client = await clientStore.load(issuer);
5228
- const normalizedClient = client === null ? null : normalizeStoredClient(client);
5384
+ const normalizedClient = client === null ? null : normalizeStoredOAuthClient(client);
5229
5385
  if (client !== null && normalizedClient === null) {
5230
5386
  await clientStore.clear(issuer);
5231
5387
  return null;
@@ -5298,7 +5454,7 @@ function normalizeLoadedSession(session) {
5298
5454
  const refreshState = getOwnEntry6(session, "refreshState");
5299
5455
  if (refreshState !== void 0 && (refreshState !== "pending" || getOwnEntry6(session, "tokens") !== void 0))
5300
5456
  throw new Error("Stored OAuth refresh state is invalid");
5301
- const client = normalizeStoredClient(getOwnEntry6(session, "client"));
5457
+ const client = normalizeStoredOAuthClient(getOwnEntry6(session, "client"));
5302
5458
  if (client === null) {
5303
5459
  return { ...session, client: { clientId: "" }, tokens: void 0 };
5304
5460
  }
@@ -5308,25 +5464,6 @@ function normalizeLoadedSession(session) {
5308
5464
  tokens: normalizeStoredTokens(getOwnEntry6(session, "tokens"))
5309
5465
  };
5310
5466
  }
5311
- function normalizeStoredClient(value) {
5312
- if (!isObjectRecord3(value)) {
5313
- return null;
5314
- }
5315
- const clientId = getOwnString2(value, "clientId");
5316
- if (clientId === void 0 || clientId.trim().length === 0) {
5317
- return null;
5318
- }
5319
- const normalizedClientId = clientId.trim();
5320
- const clientSecret = getOwnEntry6(value, "clientSecret");
5321
- if (clientSecret === void 0) {
5322
- return { clientId: normalizedClientId };
5323
- }
5324
- if (typeof clientSecret !== "string" || clientSecret.trim().length === 0) {
5325
- return null;
5326
- }
5327
- const normalizedClientSecret = clientSecret.trim();
5328
- return { clientId: normalizedClientId, clientSecret: normalizedClientSecret };
5329
- }
5330
5467
  function normalizeStoredTokens(value) {
5331
5468
  if (value === void 0 || !isObjectRecord3(value)) {
5332
5469
  return void 0;
@@ -5335,10 +5472,10 @@ function normalizeStoredTokens(value) {
5335
5472
  const tokenType = getOwnString2(value, "tokenType");
5336
5473
  const expiresAt = getOwnEntry6(value, "expiresAt");
5337
5474
  const refreshToken = getOwnEntry6(value, "refreshToken");
5338
- const scope = getOwnString2(value, "scope");
5475
+ const scope = getOwnEntry6(value, "scope");
5339
5476
  const normalizedAccessToken = accessToken?.trim();
5340
5477
  const normalizedRefreshToken = typeof refreshToken === "string" ? refreshToken.trim() : void 0;
5341
- const normalizedScope = scope?.trim();
5478
+ const normalizedScope = normalizeOAuthScope(scope);
5342
5479
  if (accessToken === void 0 || normalizedAccessToken === void 0 || normalizedAccessToken.length === 0 || tokenType !== "Bearer" || !(expiresAt === null || typeof expiresAt === "number" && Number.isSafeInteger(expiresAt) && expiresAt <= MAX_JS_DATE_MS3 && Number.isFinite(new Date(expiresAt).getTime())) || refreshToken !== void 0 && (typeof refreshToken !== "string" || normalizedRefreshToken === void 0 || normalizedRefreshToken.length === 0)) {
5343
5480
  return void 0;
5344
5481
  }
@@ -5356,18 +5493,18 @@ function getClientMetadata(client) {
5356
5493
  }
5357
5494
  return {
5358
5495
  clientName: normalizeOptionalOAuthString(client.metadata.clientName),
5359
- scope: normalizeOptionalOAuthString(client.metadata.scope),
5496
+ scope: normalizeOAuthScope(client.metadata.scope),
5360
5497
  softwareId: normalizeOptionalOAuthString(client.metadata.softwareId),
5361
5498
  softwareVersion: normalizeOptionalOAuthString(client.metadata.softwareVersion)
5362
5499
  };
5363
5500
  }
5364
5501
  function normalizeConfiguredClient(client) {
5365
- const clientId = normalizeOptionalOAuthString(client.clientId);
5366
- if (clientId === void 0) {
5502
+ const registration = client.registration === void 0 ? void 0 : parseOAuthClientRegistration(client.registration);
5503
+ const clientId = normalizeOptionalOAuthString(client.clientId) ?? registration?.client_id.trim();
5504
+ if (clientId === void 0)
5367
5505
  return null;
5368
- }
5369
- const clientSecret = normalizeOptionalOAuthString(client.clientSecret);
5370
- return clientSecret === void 0 ? { clientId } : { clientId, clientSecret };
5506
+ const clientSecret = normalizeOptionalOAuthString(client.clientSecret) ?? (registration === void 0 ? void 0 : getOwnString2(registration, "client_secret")?.trim());
5507
+ return normalizeStoredOAuthClient({ clientId, clientSecret, registration, tokenEndpointAuthMethod: client.tokenEndpointAuthMethod });
5371
5508
  }
5372
5509
  function normalizeOptionalOAuthString(value) {
5373
5510
  if (value === void 0) {
@@ -5467,12 +5604,28 @@ function assertRequestMatchesResource(requestUrl, resource) {
5467
5604
  throw new Error(`OAuth request URL ${requestUrl} does not match discovered resource ${resource}`);
5468
5605
  }
5469
5606
  }
5470
- function buildClientRegistrationBody(metadata, redirectUri) {
5607
+ function getSupportedTokenAuthMethods(metadata) {
5608
+ const value = getOwnEntry6(metadata, "token_endpoint_auth_methods_supported");
5609
+ if (value === void 0)
5610
+ return void 0;
5611
+ if (!Array.isArray(value) || value.length > 128 || value.some((method) => typeof method !== "string"))
5612
+ throw new Error("Invalid OAuth token endpoint authentication metadata");
5613
+ return value;
5614
+ }
5615
+ function assertTokenEndpointAuthentication(client, metadata) {
5616
+ const method = client.tokenEndpointAuthMethod ?? (client.clientSecret === void 0 ? "none" : "client_secret_post");
5617
+ if (method !== "none" && client.clientSecret === void 0)
5618
+ throw new Error("OAuth token endpoint authentication requires a client secret");
5619
+ const supported = getSupportedTokenAuthMethods(metadata);
5620
+ if (supported !== void 0 && !supported.includes(method))
5621
+ throw new Error("Authorization server does not support the requested OAuth token endpoint authentication");
5622
+ }
5623
+ function buildClientRegistrationBody(metadata, redirectUri, tokenEndpointAuthMethod) {
5471
5624
  const body = {
5472
5625
  redirect_uris: [redirectUri],
5473
5626
  grant_types: ["authorization_code", "refresh_token"],
5474
5627
  response_types: ["code"],
5475
- token_endpoint_auth_method: "none"
5628
+ token_endpoint_auth_method: tokenEndpointAuthMethod
5476
5629
  };
5477
5630
  const clientName = metadata === void 0 ? void 0 : getOwnString2(metadata, "clientName");
5478
5631
  const scope = metadata === void 0 ? void 0 : getOwnString2(metadata, "scope");
@@ -8,7 +8,7 @@
8
8
  },
9
9
  {
10
10
  "name": "toolcraft-schema",
11
- "version": "0.0.313",
11
+ "version": "0.0.315",
12
12
  "license": "MIT"
13
13
  }
14
14
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft-schema",
3
- "version": "0.0.313",
3
+ "version": "0.0.315",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft",
3
- "version": "0.0.313",
3
+ "version": "0.0.315",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -158,7 +158,7 @@
158
158
  "yaml"
159
159
  ],
160
160
  "optionalDependencies": {
161
- "toolcraft-schema": "0.0.313",
161
+ "toolcraft-schema": "0.0.315",
162
162
  "toolcraft-design": "*",
163
163
  "@poe-code/frontmatter": "*",
164
164
  "@poe-code/agent-mcp-config": "*",