tiny-http-mcp-server 0.1.40 → 0.1.41

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.40",
21
+ "version": "0.1.41",
22
22
  "license": "MIT"
23
23
  },
24
24
  {
@@ -103,6 +103,14 @@ returns `void` if a new discovery lookup is needed. It honors `allowInteractive`
103
103
  recovers pending refresh outcomes through consent, and returns an owned token
104
104
  snapshot. Normal transport request authorization remains noninteractive.
105
105
 
106
+ `createResourceBoundOAuthStores(authStore, persistenceNamespace, resourceIdentity)`
107
+ exposes the native named session/client stores and `reset(resource, { signal,
108
+ timeoutMs })`. Reset acquires the raw identity backend lock, so it can recover
109
+ corrupt or undecryptable records without reading their old contents. It atomically
110
+ retires the identity's grant and registrations and writes a marker that suppresses
111
+ stale initial grants. The default lock wait is 30 seconds. Other names/profiles
112
+ are untouched, and symlink paths are still refused.
113
+
106
114
  Configure `client.metadata.scope` to request a precise scope set; broader
107
115
  discovery metadata does not override it. Explicit scopes must match the cached
108
116
  or imported grant's scope set; ordering, repeated spaces and duplicates are
@@ -1,9 +1,15 @@
1
1
  import type { CreateSecretStoreInput } from "auth-store";
2
2
  import { type OAuthClientStore } from "./auth-store-session-store.js";
3
3
  import type { OAuthSessionStore } from "./types.js";
4
+ export interface ResourceBoundOAuthStores {
5
+ readonly sessionStore: OAuthSessionStore;
6
+ readonly clientStore: OAuthClientStore;
7
+ readonly initialGrantAllowed: boolean;
8
+ /** Retire grants/clients even when their document cannot be decrypted or parsed. */
9
+ reset(resource: string, options?: {
10
+ signal?: AbortSignal;
11
+ timeoutMs?: number;
12
+ }): Promise<void>;
13
+ }
4
14
  /** One locked document owns a logical server's URL history, grant and clients. */
5
- export declare function createResourceBoundOAuthStores(options: CreateSecretStoreInput, namespace: string | undefined, identity: string): {
6
- sessionStore: OAuthSessionStore;
7
- clientStore: OAuthClientStore;
8
- initialGrantAllowed: boolean;
9
- };
15
+ export declare function createResourceBoundOAuthStores(options: CreateSecretStoreInput, namespace: string | undefined, identity: string): ResourceBoundOAuthStores;
@@ -4,9 +4,36 @@ import { normalizeStoredOAuthClient } from "./client-registration.js";
4
4
  /** One locked document owns a logical server's URL history, grant and clients. */
5
5
  export function createResourceBoundOAuthStores(options, namespace, identity) {
6
6
  assertPersistenceNamespace(identity);
7
+ assertPersistenceNamespace(namespace);
7
8
  const store = createNamedSecretStore(identity, options, { salt: "poe-code:mcp-oauth:resources:v1",
8
9
  directory: ".poe-code/mcp-oauth/resources", service: "poe-code-mcp-oauth-resources", accountPrefix: "resource" }, namespace);
9
- const result = { initialGrantAllowed: true, sessionStore: {}, clientStore: {} };
10
+ const result = { initialGrantAllowed: true, sessionStore: {}, clientStore: {},
11
+ async reset(resource, options = {}) {
12
+ options.signal?.throwIfAborted();
13
+ let url;
14
+ try {
15
+ url = new URL(resource);
16
+ }
17
+ catch {
18
+ throw new Error("OAuth reset resource must be an absolute HTTP URL");
19
+ }
20
+ if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.hash)
21
+ throw new Error("OAuth reset resource must be an HTTP URL without credentials or fragment");
22
+ const timeoutMs = options.timeoutMs ?? 30_000;
23
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 2_147_483_647)
24
+ throw new Error("OAuth reset timeoutMs must be a positive supported timer interval");
25
+ if (store.withLock === undefined)
26
+ throw new Error("OAuth resource identity backend must support transaction locks");
27
+ // Acquire the raw backend lock: the session lock reconciles by strictly
28
+ // reading the document, which must be bypassed for explicit corruption recovery.
29
+ await store.withLock(async () => {
30
+ options.signal?.throwIfAborted();
31
+ const record = { version: 1, resource: canonicalizeResourceIndicator(url), generation: 1, session: null, clients: {} };
32
+ await store.set(JSON.stringify(record));
33
+ result.initialGrantAllowed = false;
34
+ }, { signal: options.signal, timeoutMs });
35
+ }
36
+ };
10
37
  async function read() {
11
38
  const raw = await store.get();
12
39
  if (raw === null)
@@ -1,4 +1,6 @@
1
1
  export { createAuthStoreSessionStore, } from "./client/auth-store-session-store.js";
2
+ export { createResourceBoundOAuthStores } from "./client/resource-bound-store.js";
3
+ export type { ResourceBoundOAuthStores } from "./client/resource-bound-store.js";
2
4
  export { parseOAuthClientRegistration } from "./client/client-registration.js";
3
5
  export { createDefaultOAuthClientProvider, createOAuthClientProvider, } from "./client/default-oauth-client-provider.js";
4
6
  export { buildSuccessPage, createLoopbackAuthorizationSession, extractCodeFromInput, } from "./client/loopback-authorization.js";
@@ -1,4 +1,5 @@
1
1
  export { createAuthStoreSessionStore, } from "./client/auth-store-session-store.js";
2
+ export { createResourceBoundOAuthStores } from "./client/resource-bound-store.js";
2
3
  export { parseOAuthClientRegistration } from "./client/client-registration.js";
3
4
  export { createDefaultOAuthClientProvider, createOAuthClientProvider, } from "./client/default-oauth-client-provider.js";
4
5
  export { buildSuccessPage, createLoopbackAuthorizationSession, extractCodeFromInput, } from "./client/loopback-authorization.js";
@@ -4712,13 +4712,40 @@ function isNonBlankOwnString(record2, key2) {
4712
4712
  // ../mcp-oauth/dist/client/resource-bound-store.js
4713
4713
  function createResourceBoundOAuthStores(options, namespace, identity) {
4714
4714
  assertPersistenceNamespace(identity);
4715
+ assertPersistenceNamespace(namespace);
4715
4716
  const store = createNamedSecretStore(identity, options, {
4716
4717
  salt: "poe-code:mcp-oauth:resources:v1",
4717
4718
  directory: ".poe-code/mcp-oauth/resources",
4718
4719
  service: "poe-code-mcp-oauth-resources",
4719
4720
  accountPrefix: "resource"
4720
4721
  }, namespace);
4721
- const result = { initialGrantAllowed: true, sessionStore: {}, clientStore: {} };
4722
+ const result = {
4723
+ initialGrantAllowed: true,
4724
+ sessionStore: {},
4725
+ clientStore: {},
4726
+ async reset(resource, options2 = {}) {
4727
+ options2.signal?.throwIfAborted();
4728
+ let url;
4729
+ try {
4730
+ url = new URL(resource);
4731
+ } catch {
4732
+ throw new Error("OAuth reset resource must be an absolute HTTP URL");
4733
+ }
4734
+ if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.hash)
4735
+ throw new Error("OAuth reset resource must be an HTTP URL without credentials or fragment");
4736
+ const timeoutMs = options2.timeoutMs ?? 3e4;
4737
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 2147483647)
4738
+ throw new Error("OAuth reset timeoutMs must be a positive supported timer interval");
4739
+ if (store.withLock === void 0)
4740
+ throw new Error("OAuth resource identity backend must support transaction locks");
4741
+ await store.withLock(async () => {
4742
+ options2.signal?.throwIfAborted();
4743
+ const record2 = { version: 1, resource: canonicalizeResourceIndicator(url), generation: 1, session: null, clients: {} };
4744
+ await store.set(JSON.stringify(record2));
4745
+ result.initialGrantAllowed = false;
4746
+ }, { signal: options2.signal, timeoutMs });
4747
+ }
4748
+ };
4722
4749
  async function read() {
4723
4750
  const raw = await store.get();
4724
4751
  if (raw === null)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiny-http-mcp-server",
3
- "version": "0.1.40",
3
+ "version": "0.1.41",
4
4
  "description": "Minimal MCP server over HTTP built on tiny-stdio-mcp-server",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",