tiny-http-mcp-server 0.1.57 → 0.1.58

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.57",
21
+ "version": "0.1.58",
22
22
  "license": "MIT"
23
23
  },
24
24
  {
@@ -57,6 +57,11 @@ const verifier = createJwksTokenVerifier({
57
57
  - `authStore` optional `auth-store` backend config for the default session store
58
58
  - `now()` optional clock override
59
59
 
60
+ The default provider captures client, interaction, callback, landing-page and
61
+ lock policies when created. Create a new provider to change those settings.
62
+ Selected callbacks, stores, clocks and AbortSignals remain live host dependencies;
63
+ aborting the original signal still cancels authorization.
64
+
60
65
  `createJwksTokenVerifier(options)` accepts:
61
66
 
62
67
  | Option | Type | Default | Description |
@@ -20,7 +20,12 @@ export function createOAuthClientProvider(options) {
20
20
  return createDefaultOAuthClientProvider(options);
21
21
  }
22
22
  export function createDefaultOAuthClientProvider(options) {
23
- loopbackTarget(options.browser);
23
+ const browser = { ...options.browser,
24
+ ...(options.browser.landingPage === undefined ? {} : { landingPage: { ...options.browser.landingPage } }) };
25
+ const clientMode = options.client.mode;
26
+ const interactiveEnabled = options.allowInteractive !== false;
27
+ const sessionLockTimeoutMs = options.sessionLockTimeoutMs;
28
+ loopbackTarget(browser);
24
29
  assertPersistenceNamespace(options.persistenceNamespace);
25
30
  const clientMetadata = getClientMetadata(options.client);
26
31
  const requestedScope = clientMetadata?.scope;
@@ -187,7 +192,7 @@ export function createDefaultOAuthClientProvider(options) {
187
192
  if (forceRefresh && rejectedTokens !== undefined && (rejectedTokens === null || session?.tokens === undefined || !sameTokenGrant(session.tokens, rejectedTokens)))
188
193
  forceRefresh = false;
189
194
  const sessionDiscovery = resolveDiscovery(discovery, session);
190
- if ((options.client.mode === "static" || configuredClient !== null || initialGrant !== undefined) && session !== null && (session.tokens !== undefined || session.refreshState === "pending")) {
195
+ if ((clientMode === "static" || configuredClient !== null || initialGrant !== undefined) && session !== null && (session.tokens !== undefined || session.refreshState === "pending")) {
191
196
  const configured = configuredClient;
192
197
  if (configured === null || configured.clientId !== session.client.clientId || configured.clientSecret !== session.client.clientSecret)
193
198
  throw new Error("Stored session belongs to a different OAuth client; use separate persistence or explicitly reset it");
@@ -198,7 +203,7 @@ export function createDefaultOAuthClientProvider(options) {
198
203
  (session.client.tokenEndpointAuthMethod ?? (session.client.clientSecret === undefined ? "none" : "client_secret_post")) !== configuredTokenMethod)
199
204
  throw new Error("Stored session does not match the requested OAuth token endpoint authentication; select separate persistence or reset it");
200
205
  if (session?.refreshState === "pending") {
201
- if (!allowInteractive || options.allowInteractive === false || sessionDiscovery === undefined)
206
+ if (!allowInteractive || !interactiveEnabled || sessionDiscovery === undefined)
202
207
  throw new Error("OAuth refresh outcome is unknown; authorize again before using this resource");
203
208
  return authorizeSession(canonicalResource, clearSessionTokens(session), sessionDiscovery, fetch, signal);
204
209
  }
@@ -209,7 +214,7 @@ export function createDefaultOAuthClientProvider(options) {
209
214
  sessionDiscovery !== undefined &&
210
215
  (forceRefresh || isExpired(session.tokens, now))) {
211
216
  if (hasExpiredClientSecret(session.client, now)) {
212
- if (!allowInteractive || options.allowInteractive === false || options.client.mode === "static" || configuredClient?.registration !== undefined)
217
+ if (!allowInteractive || !interactiveEnabled || clientMode === "static" || configuredClient?.registration !== undefined)
213
218
  throw new Error("OAuth client secret has expired; authorize again or update the imported registration");
214
219
  return authorizeSession(canonicalResource, clearSessionTokens(session), sessionDiscovery, fetch, signal);
215
220
  }
@@ -225,10 +230,10 @@ export function createDefaultOAuthClientProvider(options) {
225
230
  if (!allowInteractive || sessionDiscovery === undefined) {
226
231
  return session;
227
232
  }
228
- if (options.allowInteractive === false)
233
+ if (!interactiveEnabled)
229
234
  throw new Error("OAuth interactive authorization is disabled");
230
235
  return authorizeSession(canonicalResource, session, sessionDiscovery, fetch, signal);
231
- }, { signal, timeoutMs: options.sessionLockTimeoutMs });
236
+ }, { signal, timeoutMs: sessionLockTimeoutMs });
232
237
  }
233
238
  async function refreshSession(resource, session, discovery, fetch, signal) {
234
239
  signal?.throwIfAborted();
@@ -303,13 +308,8 @@ export function createDefaultOAuthClientProvider(options) {
303
308
  let reRegistrationAttempted = false;
304
309
  while (true) {
305
310
  const loopback = await createLoopbackAuthorizationSession({
306
- openBrowser: options.browser.openBrowser,
307
- readLine: options.browser.readLine,
308
- createServer: options.browser.createServer,
309
- landingPage: options.browser.landingPage,
310
- redirectUri: options.browser.redirectUri,
311
- signal: options.browser.signal === undefined ? signal : signal === undefined ? options.browser.signal : AbortSignal.any([signal, options.browser.signal]),
312
- timeoutMs: options.browser.timeoutMs
311
+ ...browser,
312
+ signal: browser.signal === undefined ? signal : signal === undefined ? browser.signal : AbortSignal.any([signal, browser.signal])
313
313
  });
314
314
  let resolvedClient = null;
315
315
  try {
@@ -379,7 +379,7 @@ export function createDefaultOAuthClientProvider(options) {
379
379
  }
380
380
  async function resolveClient(existingSession, discovery, redirectUri, fetch, parentSignal) {
381
381
  parentSignal?.throwIfAborted();
382
- if (options.client.mode === "static" || configuredClient?.registration !== undefined) {
382
+ if (clientMode === "static" || configuredClient?.registration !== undefined) {
383
383
  if (configuredClient === null) {
384
384
  throw new Error("OAuth client_id must not be blank");
385
385
  }
@@ -134,6 +134,7 @@ export interface OAuthSessionStore {
134
134
  timeoutMs: number;
135
135
  }): Promise<T>;
136
136
  }
137
+ /** Configuration values are captured at creation; selected host dependencies remain live. */
137
138
  export interface DefaultOAuthClientProviderOptions {
138
139
  client: {
139
140
  mode: "dynamic";
@@ -237,6 +237,7 @@ interface OAuthSessionStore {
237
237
  timeoutMs: number;
238
238
  }): Promise<T>;
239
239
  }
240
+ /** Configuration values are captured at creation; selected host dependencies remain live. */
240
241
  interface DefaultOAuthClientProviderOptions {
241
242
  client: {
242
243
  mode: "dynamic";
@@ -5239,7 +5239,14 @@ function createOAuthClientProvider(options) {
5239
5239
  return createDefaultOAuthClientProvider(options);
5240
5240
  }
5241
5241
  function createDefaultOAuthClientProvider(options) {
5242
- loopbackTarget(options.browser);
5242
+ const browser = {
5243
+ ...options.browser,
5244
+ ...options.browser.landingPage === void 0 ? {} : { landingPage: { ...options.browser.landingPage } }
5245
+ };
5246
+ const clientMode = options.client.mode;
5247
+ const interactiveEnabled = options.allowInteractive !== false;
5248
+ const sessionLockTimeoutMs = options.sessionLockTimeoutMs;
5249
+ loopbackTarget(browser);
5243
5250
  assertPersistenceNamespace(options.persistenceNamespace);
5244
5251
  const clientMetadata = getClientMetadata(options.client);
5245
5252
  const requestedScope = clientMetadata?.scope;
@@ -5398,7 +5405,7 @@ function createDefaultOAuthClientProvider(options) {
5398
5405
  if (forceRefresh && rejectedTokens !== void 0 && (rejectedTokens === null || session?.tokens === void 0 || !sameTokenGrant(session.tokens, rejectedTokens)))
5399
5406
  forceRefresh = false;
5400
5407
  const sessionDiscovery = resolveDiscovery(discovery, session);
5401
- if ((options.client.mode === "static" || configuredClient !== null || initialGrant !== void 0) && session !== null && (session.tokens !== void 0 || session.refreshState === "pending")) {
5408
+ if ((clientMode === "static" || configuredClient !== null || initialGrant !== void 0) && session !== null && (session.tokens !== void 0 || session.refreshState === "pending")) {
5402
5409
  const configured = configuredClient;
5403
5410
  if (configured === null || configured.clientId !== session.client.clientId || configured.clientSecret !== session.client.clientSecret)
5404
5411
  throw new Error("Stored session belongs to a different OAuth client; use separate persistence or explicitly reset it");
@@ -5408,7 +5415,7 @@ function createDefaultOAuthClientProvider(options) {
5408
5415
  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)
5409
5416
  throw new Error("Stored session does not match the requested OAuth token endpoint authentication; select separate persistence or reset it");
5410
5417
  if (session?.refreshState === "pending") {
5411
- if (!allowInteractive || options.allowInteractive === false || sessionDiscovery === void 0)
5418
+ if (!allowInteractive || !interactiveEnabled || sessionDiscovery === void 0)
5412
5419
  throw new Error("OAuth refresh outcome is unknown; authorize again before using this resource");
5413
5420
  return authorizeSession(canonicalResource, clearSessionTokens(session), sessionDiscovery, fetch2, signal);
5414
5421
  }
@@ -5417,7 +5424,7 @@ function createDefaultOAuthClientProvider(options) {
5417
5424
  }
5418
5425
  if (session?.tokens?.refreshToken !== void 0 && sessionDiscovery !== void 0 && (forceRefresh || isExpired(session.tokens, now))) {
5419
5426
  if (hasExpiredClientSecret(session.client, now)) {
5420
- if (!allowInteractive || options.allowInteractive === false || options.client.mode === "static" || configuredClient?.registration !== void 0)
5427
+ if (!allowInteractive || !interactiveEnabled || clientMode === "static" || configuredClient?.registration !== void 0)
5421
5428
  throw new Error("OAuth client secret has expired; authorize again or update the imported registration");
5422
5429
  return authorizeSession(canonicalResource, clearSessionTokens(session), sessionDiscovery, fetch2, signal);
5423
5430
  }
@@ -5433,10 +5440,10 @@ function createDefaultOAuthClientProvider(options) {
5433
5440
  if (!allowInteractive || sessionDiscovery === void 0) {
5434
5441
  return session;
5435
5442
  }
5436
- if (options.allowInteractive === false)
5443
+ if (!interactiveEnabled)
5437
5444
  throw new Error("OAuth interactive authorization is disabled");
5438
5445
  return authorizeSession(canonicalResource, session, sessionDiscovery, fetch2, signal);
5439
- }, { signal, timeoutMs: options.sessionLockTimeoutMs });
5446
+ }, { signal, timeoutMs: sessionLockTimeoutMs });
5440
5447
  }
5441
5448
  async function refreshSession(resource, session, discovery, fetch2, signal) {
5442
5449
  signal?.throwIfAborted();
@@ -5509,13 +5516,8 @@ function createDefaultOAuthClientProvider(options) {
5509
5516
  let reRegistrationAttempted = false;
5510
5517
  while (true) {
5511
5518
  const loopback = await createLoopbackAuthorizationSession({
5512
- openBrowser: options.browser.openBrowser,
5513
- readLine: options.browser.readLine,
5514
- createServer: options.browser.createServer,
5515
- landingPage: options.browser.landingPage,
5516
- redirectUri: options.browser.redirectUri,
5517
- signal: options.browser.signal === void 0 ? signal : signal === void 0 ? options.browser.signal : AbortSignal.any([signal, options.browser.signal]),
5518
- timeoutMs: options.browser.timeoutMs
5519
+ ...browser,
5520
+ signal: browser.signal === void 0 ? signal : signal === void 0 ? browser.signal : AbortSignal.any([signal, browser.signal])
5519
5521
  });
5520
5522
  let resolvedClient = null;
5521
5523
  try {
@@ -5584,7 +5586,7 @@ function createDefaultOAuthClientProvider(options) {
5584
5586
  }
5585
5587
  async function resolveClient(existingSession, discovery, redirectUri, fetch2, parentSignal) {
5586
5588
  parentSignal?.throwIfAborted();
5587
- if (options.client.mode === "static" || configuredClient?.registration !== void 0) {
5589
+ if (clientMode === "static" || configuredClient?.registration !== void 0) {
5588
5590
  if (configuredClient === null) {
5589
5591
  throw new Error("OAuth client_id must not be blank");
5590
5592
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiny-http-mcp-server",
3
- "version": "0.1.57",
3
+ "version": "0.1.58",
4
4
  "description": "Minimal MCP server over HTTP built on tiny-stdio-mcp-server",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",