tiny-http-mcp-server 0.1.41 → 0.1.42

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.
@@ -18,7 +18,7 @@
18
18
  },
19
19
  {
20
20
  "name": "tiny-http-mcp-server",
21
- "version": "0.1.41",
21
+ "version": "0.1.42",
22
22
  "license": "MIT"
23
23
  },
24
24
  {
@@ -165,6 +165,9 @@ Authorization and code exchange always use the actual listener URI. Silent
165
165
  refresh keeps its original client regardless of callback changes. At interactive
166
166
  authorization, a native registration with an obsolete captured callback is
167
167
  replaced; caller-owned full registration imports retain their original identity.
168
+ Their persisted `registrationOwnership: "caller"` survives reload and refresh;
169
+ invalid-client responses never silently replace these apps. Callback changes or
170
+ expired imported secrets require an explicit registration update.
168
171
  Set `client.tokenEndpointAuthMethod` to `none`, `client_secret_post` or
169
172
  `client_secret_basic`; a full registration can supply the same field as
170
173
  `token_endpoint_auth_method`. Public clients never transmit a stored secret.
@@ -112,6 +112,12 @@ export function normalizeStoredOAuthClient(value) {
112
112
  }
113
113
  if (method !== undefined)
114
114
  client.tokenEndpointAuthMethod = method;
115
+ const ownership = Object.hasOwn(record, "registrationOwnership") ? record.registrationOwnership : undefined;
116
+ if (ownership !== undefined) {
117
+ if (ownership !== "caller" || client.registration === undefined)
118
+ throw new Error("Invalid stored OAuth registration ownership");
119
+ client.registrationOwnership = "caller";
120
+ }
115
121
  return client;
116
122
  }
117
123
  /** Fresh DCR may describe a normalized loopback port; saved identity stays exact. */
@@ -401,6 +401,16 @@ export function createDefaultOAuthClientProvider(options) {
401
401
  };
402
402
  }
403
403
  let storedClient = await loadRegisteredClient(discovery.authorizationServer);
404
+ const importedClient = existingSession?.client.registrationOwnership === "caller" ? existingSession.client :
405
+ storedClient?.registrationOwnership === "caller" ? storedClient : undefined;
406
+ if (importedClient !== undefined) {
407
+ assertRegistrationIssuer(importedClient, discovery.authorizationServer);
408
+ if (hasExpiredClientSecret(importedClient, now))
409
+ throw new Error("OAuth client secret has expired; update the imported registration");
410
+ if (!registrationMatchesRedirect(importedClient, redirectUri))
411
+ throw new Error("OAuth imported registration does not match the configured redirect URI; update its callback configuration");
412
+ return { kind: "static", fromStoredRegistration: false, client: importedClient };
413
+ }
404
414
  if (storedClient !== null) {
405
415
  assertRegistrationIssuer(storedClient, discovery.authorizationServer);
406
416
  if (hasExpiredClientSecret(storedClient, now) || !registrationMatchesRedirect(storedClient, redirectUri)) {
@@ -653,7 +663,9 @@ function normalizeConfiguredClient(client) {
653
663
  if (clientId === undefined)
654
664
  return null;
655
665
  const clientSecret = normalizeOptionalOAuthString(client.clientSecret) ?? (registration === undefined ? undefined : getOwnString(registration, "client_secret")?.trim());
656
- return normalizeStoredOAuthClient({ clientId, clientSecret, registration, tokenEndpointAuthMethod: client.tokenEndpointAuthMethod });
666
+ return normalizeStoredOAuthClient({ clientId, clientSecret, registration,
667
+ ...(registration === undefined ? {} : { registrationOwnership: "caller" }),
668
+ tokenEndpointAuthMethod: client.tokenEndpointAuthMethod });
657
669
  }
658
670
  function normalizeOptionalOAuthString(value) {
659
671
  if (value === undefined) {
@@ -829,5 +841,5 @@ function shouldReRegisterStoredDynamicClient(error, client, alreadyAttempted) {
829
841
  if ("kind" in client) {
830
842
  return client.kind === "dynamic" && client.fromStoredRegistration;
831
843
  }
832
- return true;
844
+ return client.registrationOwnership !== "caller";
833
845
  }
@@ -100,6 +100,8 @@ export interface OAuthClientRegistration extends Record<string, unknown> {
100
100
  }
101
101
  export interface StoredOAuthClient {
102
102
  clientId: string;
103
+ /** Externally registered apps must never be replaced by native DCR on reload. */
104
+ registrationOwnership?: "caller";
103
105
  /** Actual listener URI submitted when this native client was registered. */
104
106
  requestedRedirectUri?: string;
105
107
  clientSecret?: string;
@@ -203,6 +203,8 @@ interface OAuthClientRegistration extends Record<string, unknown> {
203
203
  }
204
204
  interface StoredOAuthClient {
205
205
  clientId: string;
206
+ /** Externally registered apps must never be replaced by native DCR on reload. */
207
+ registrationOwnership?: "caller";
206
208
  /** Actual listener URI submitted when this native client was registered. */
207
209
  requestedRedirectUri?: string;
208
210
  clientSecret?: string;
@@ -3843,6 +3843,12 @@ function normalizeStoredOAuthClient(value) {
3843
3843
  }
3844
3844
  if (method !== void 0)
3845
3845
  client.tokenEndpointAuthMethod = method;
3846
+ const ownership = Object.hasOwn(record2, "registrationOwnership") ? record2.registrationOwnership : void 0;
3847
+ if (ownership !== void 0) {
3848
+ if (ownership !== "caller" || client.registration === void 0)
3849
+ throw new Error("Invalid stored OAuth registration ownership");
3850
+ client.registrationOwnership = "caller";
3851
+ }
3846
3852
  return client;
3847
3853
  }
3848
3854
  function registrationMatchesRedirect(client, requestedUri, fresh = false) {
@@ -5524,6 +5530,15 @@ function createDefaultOAuthClientProvider(options) {
5524
5530
  };
5525
5531
  }
5526
5532
  let storedClient = await loadRegisteredClient(discovery.authorizationServer);
5533
+ const importedClient = existingSession?.client.registrationOwnership === "caller" ? existingSession.client : storedClient?.registrationOwnership === "caller" ? storedClient : void 0;
5534
+ if (importedClient !== void 0) {
5535
+ assertRegistrationIssuer(importedClient, discovery.authorizationServer);
5536
+ if (hasExpiredClientSecret(importedClient, now))
5537
+ throw new Error("OAuth client secret has expired; update the imported registration");
5538
+ if (!registrationMatchesRedirect(importedClient, redirectUri))
5539
+ throw new Error("OAuth imported registration does not match the configured redirect URI; update its callback configuration");
5540
+ return { kind: "static", fromStoredRegistration: false, client: importedClient };
5541
+ }
5527
5542
  if (storedClient !== null) {
5528
5543
  assertRegistrationIssuer(storedClient, discovery.authorizationServer);
5529
5544
  if (hasExpiredClientSecret(storedClient, now) || !registrationMatchesRedirect(storedClient, redirectUri)) {
@@ -5750,7 +5765,13 @@ function normalizeConfiguredClient(client) {
5750
5765
  if (clientId === void 0)
5751
5766
  return null;
5752
5767
  const clientSecret = normalizeOptionalOAuthString(client.clientSecret) ?? (registration === void 0 ? void 0 : getOwnString2(registration, "client_secret")?.trim());
5753
- return normalizeStoredOAuthClient({ clientId, clientSecret, registration, tokenEndpointAuthMethod: client.tokenEndpointAuthMethod });
5768
+ return normalizeStoredOAuthClient({
5769
+ clientId,
5770
+ clientSecret,
5771
+ registration,
5772
+ ...registration === void 0 ? {} : { registrationOwnership: "caller" },
5773
+ tokenEndpointAuthMethod: client.tokenEndpointAuthMethod
5774
+ });
5754
5775
  }
5755
5776
  function normalizeOptionalOAuthString(value) {
5756
5777
  if (value === void 0) {
@@ -5919,7 +5940,7 @@ function shouldReRegisterStoredDynamicClient(error, client, alreadyAttempted) {
5919
5940
  if ("kind" in client) {
5920
5941
  return client.kind === "dynamic" && client.fromStoredRegistration;
5921
5942
  }
5922
- return true;
5943
+ return client.registrationOwnership !== "caller";
5923
5944
  }
5924
5945
 
5925
5946
  // ../tiny-stdio-mcp-server/dist/headers.js
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiny-http-mcp-server",
3
- "version": "0.1.41",
3
+ "version": "0.1.42",
4
4
  "description": "Minimal MCP server over HTTP built on tiny-stdio-mcp-server",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",