tiny-http-mcp-server 0.1.30 → 0.1.31

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.30",
21
+ "version": "0.1.31",
22
22
  "license": "MIT"
23
23
  },
24
24
  {
@@ -42,6 +42,7 @@ const verifier = createJwksTokenVerifier({
42
42
  - `mode: "static"` with `clientId`, optional `clientSecret`, optional `metadata`
43
43
  - `allowInteractive: false` prevents interactive login while retaining cached tokens and silent refresh
44
44
  - `sessionLockTimeoutMs` limits acquisition waits for a session transaction lock (default 30,000 ms; integer from 1 to 2147483647)
45
+ - `persistenceNamespace` isolates native sessions and registrations for a named profile (nonempty string, at most 1024 UTF-8 bytes)
45
46
  - `initialGrant: { resource, tokens }` optionally imports an existing Bearer grant for one HTTP resource; requires the original client ID
46
47
  - `browser.openBrowser(url)` optional
47
48
  - `browser.readLine()` optional
@@ -108,6 +109,13 @@ Static clients and dynamic initial-grant imports require cached grants to match
108
109
  the original normalized client ID and secret. A different client configuration
109
110
  fails before attaching or refreshing credentials and retains the stored record;
110
111
  select separate persistence or explicitly reset the session to change apps.
112
+ Use `persistenceNamespace: "personal"` or `"work"` to keep separate native
113
+ profiles for the same resource/issuer. `createAuthStoreSessionStore(options,
114
+ namespace)` addresses the same profile when seeding or inspecting credentials.
115
+ Namespaces are hashed into file/Keychain identities and transaction locks;
116
+ omitting one preserves the default storage keys. Switching namespaces selects a
117
+ different record and does not migrate or reset the previous profile. Host-owned
118
+ `sessionStore` implementations remain responsible for their own profile keys.
111
119
 
112
120
  `createAuthStoreSessionStore(options)` accepts the standard `auth-store` config.
113
121
 
@@ -9,6 +9,7 @@ export interface OAuthClientStore {
9
9
  save(issuer: string, client: StoredOAuthClient): Promise<void>;
10
10
  clear(issuer: string): Promise<void>;
11
11
  }
12
- export declare function createAuthStoreSessionStore(options?: CreateSecretStoreInput): OAuthSessionStore;
13
- export declare function createAuthStoreClientStore(options: CreateSecretStoreInput): OAuthClientStore;
12
+ export declare function createAuthStoreSessionStore(options?: CreateSecretStoreInput, namespace?: string): OAuthSessionStore;
13
+ export declare function createAuthStoreClientStore(options: CreateSecretStoreInput, namespace?: string): OAuthClientStore;
14
+ export declare function assertPersistenceNamespace(namespace: string | undefined): void;
14
15
  export {};
@@ -9,16 +9,17 @@ const DEFAULT_CLIENT_FILE_SALT = "poe-code:mcp-oauth:clients:v1";
9
9
  const DEFAULT_CLIENT_FILE_DIRECTORY = ".poe-code/mcp-oauth/clients";
10
10
  const DEFAULT_CLIENT_KEYCHAIN_SERVICE = "poe-code-mcp-oauth-clients";
11
11
  const MAX_JS_DATE_MS = 8_640_000_000_000_000;
12
- export function createAuthStoreSessionStore(options = {}) {
12
+ export function createAuthStoreSessionStore(options = {}, namespace) {
13
+ assertPersistenceNamespace(namespace);
13
14
  return {
14
15
  async withLock(resource, operation, lockOptions) {
15
- const store = createResourceSecretStore(resource, options);
16
+ const store = createResourceSecretStore(resource, options, namespace);
16
17
  if (store.withLock === undefined)
17
18
  throw new Error("OAuth secret-store backend does not support transaction locks");
18
19
  return store.withLock(operation, lockOptions);
19
20
  },
20
21
  async load(resource) {
21
- const store = createResourceSecretStore(resource, options);
22
+ const store = createResourceSecretStore(resource, options, namespace);
22
23
  const value = await store.get();
23
24
  if (value === null) {
24
25
  return null;
@@ -36,19 +37,20 @@ export function createAuthStoreSessionStore(options = {}) {
36
37
  throw new Error("Stored OAuth session must match the expected shape");
37
38
  },
38
39
  async save(resource, session) {
39
- const store = createResourceSecretStore(resource, options);
40
+ const store = createResourceSecretStore(resource, options, namespace);
40
41
  await store.set(JSON.stringify(session));
41
42
  },
42
43
  async clear(resource) {
43
- const store = createResourceSecretStore(resource, options);
44
+ const store = createResourceSecretStore(resource, options, namespace);
44
45
  await store.delete();
45
46
  }
46
47
  };
47
48
  }
48
- export function createAuthStoreClientStore(options) {
49
+ export function createAuthStoreClientStore(options, namespace) {
50
+ assertPersistenceNamespace(namespace);
49
51
  return {
50
52
  async load(issuer) {
51
- const store = createIssuerSecretStore(issuer, options);
53
+ const store = createIssuerSecretStore(issuer, options, namespace);
52
54
  const value = await store.get();
53
55
  if (value === null) {
54
56
  return null;
@@ -72,17 +74,17 @@ export function createAuthStoreClientStore(options) {
72
74
  throw new Error("Stored OAuth client must be a JSON object with clientId");
73
75
  },
74
76
  async save(issuer, client) {
75
- const store = createIssuerSecretStore(issuer, options);
77
+ const store = createIssuerSecretStore(issuer, options, namespace);
76
78
  await store.set(JSON.stringify(client));
77
79
  },
78
80
  async clear(issuer) {
79
- const store = createIssuerSecretStore(issuer, options);
81
+ const store = createIssuerSecretStore(issuer, options, namespace);
80
82
  await store.delete();
81
83
  }
82
84
  };
83
85
  }
84
- function createNamedSecretStore(key, options, defaults) {
85
- const hash = crypto.createHash("sha256").update(key).digest("hex");
86
+ function createNamedSecretStore(key, options, defaults, namespace) {
87
+ const hash = crypto.createHash("sha256").update(namespace === undefined ? key : JSON.stringify([namespace, key])).digest("hex");
86
88
  const configuredFilePath = options.fileStore?.filePath;
87
89
  const parsedFilePath = configuredFilePath === undefined ? null : path.parse(configuredFilePath);
88
90
  const fileStore = {
@@ -104,21 +106,25 @@ function createNamedSecretStore(key, options, defaults) {
104
106
  };
105
107
  return createSecretStore({ ...options, fileStore, keychainStore }).store;
106
108
  }
107
- function createResourceSecretStore(resource, options) {
109
+ function createResourceSecretStore(resource, options, namespace) {
108
110
  return createNamedSecretStore(canonicalizeResourceIndicator(resource), options, {
109
111
  salt: DEFAULT_FILE_SALT,
110
112
  directory: DEFAULT_FILE_DIRECTORY,
111
113
  service: DEFAULT_KEYCHAIN_SERVICE,
112
114
  accountPrefix: "provider"
113
- });
115
+ }, namespace);
114
116
  }
115
- function createIssuerSecretStore(issuer, options) {
117
+ function createIssuerSecretStore(issuer, options, namespace) {
116
118
  return createNamedSecretStore(issuer, options, {
117
119
  salt: DEFAULT_CLIENT_FILE_SALT,
118
120
  directory: DEFAULT_CLIENT_FILE_DIRECTORY,
119
121
  service: DEFAULT_CLIENT_KEYCHAIN_SERVICE,
120
122
  accountPrefix: "issuer"
121
- });
123
+ }, namespace);
124
+ }
125
+ export function assertPersistenceNamespace(namespace) {
126
+ if (namespace !== undefined && (typeof namespace !== "string" || namespace.trim() === "" || Buffer.byteLength(namespace, "utf8") > 1024))
127
+ throw new Error("OAuth persistence namespace must be a nonempty string within 1024 bytes");
122
128
  }
123
129
  function isObjectRecord(value) {
124
130
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -1,7 +1,7 @@
1
1
  import { isIP } from "node:net";
2
2
  import { fetchMcpResponse } from "../http-fetch.js";
3
3
  import { URL } from "node:url";
4
- import { createAuthStoreClientStore, createAuthStoreSessionStore } from "./auth-store-session-store.js";
4
+ import { createAuthStoreClientStore, createAuthStoreSessionStore, assertPersistenceNamespace } from "./auth-store-session-store.js";
5
5
  import { createLoopbackAuthorizationSession, loopbackTarget } from "./loopback-authorization.js";
6
6
  import { createAuthorizationState } from "./authorization-state.js";
7
7
  import { generateCodeChallenge, generateCodeVerifier } from "./pkce.js";
@@ -17,8 +17,9 @@ export function createOAuthClientProvider(options) {
17
17
  }
18
18
  export function createDefaultOAuthClientProvider(options) {
19
19
  loopbackTarget(options.browser);
20
- const sessionStore = options.sessionStore ?? createAuthStoreSessionStore(options.authStore);
21
- const clientStore = options.authStore === undefined ? null : createAuthStoreClientStore(options.authStore);
20
+ assertPersistenceNamespace(options.persistenceNamespace);
21
+ const sessionStore = options.sessionStore ?? createAuthStoreSessionStore(options.authStore, options.persistenceNamespace);
22
+ const clientStore = options.authStore === undefined ? null : createAuthStoreClientStore(options.authStore, options.persistenceNamespace);
22
23
  const now = options.now ?? Date.now;
23
24
  const registeredClients = new Map();
24
25
  if (options.initialGrant !== undefined) {
@@ -112,6 +112,8 @@ export interface DefaultOAuthClientProviderOptions {
112
112
  allowInteractive?: boolean;
113
113
  /** Maximum wait to acquire a session transaction lock (default 30,000 ms). */
114
114
  sessionLockTimeoutMs?: number;
115
+ /** Isolate native persisted sessions and registrations for a named profile. */
116
+ persistenceNamespace?: string;
115
117
  /** Import an existing grant for one resource. Persisted sessions take precedence. */
116
118
  initialGrant?: {
117
119
  resource: string;
@@ -215,6 +215,8 @@ interface DefaultOAuthClientProviderOptions {
215
215
  allowInteractive?: boolean;
216
216
  /** Maximum wait to acquire a session transaction lock (default 30,000 ms). */
217
217
  sessionLockTimeoutMs?: number;
218
+ /** Isolate native persisted sessions and registrations for a named profile. */
219
+ persistenceNamespace?: string;
218
220
  /** Import an existing grant for one resource. Persisted sessions take precedence. */
219
221
  initialGrant?: {
220
222
  resource: string;
@@ -4077,16 +4077,17 @@ var DEFAULT_CLIENT_FILE_SALT = "poe-code:mcp-oauth:clients:v1";
4077
4077
  var DEFAULT_CLIENT_FILE_DIRECTORY = ".poe-code/mcp-oauth/clients";
4078
4078
  var DEFAULT_CLIENT_KEYCHAIN_SERVICE = "poe-code-mcp-oauth-clients";
4079
4079
  var MAX_JS_DATE_MS = 864e13;
4080
- function createAuthStoreSessionStore(options = {}) {
4080
+ function createAuthStoreSessionStore(options = {}, namespace) {
4081
+ assertPersistenceNamespace(namespace);
4081
4082
  return {
4082
4083
  async withLock(resource, operation, lockOptions) {
4083
- const store = createResourceSecretStore(resource, options);
4084
+ const store = createResourceSecretStore(resource, options, namespace);
4084
4085
  if (store.withLock === void 0)
4085
4086
  throw new Error("OAuth secret-store backend does not support transaction locks");
4086
4087
  return store.withLock(operation, lockOptions);
4087
4088
  },
4088
4089
  async load(resource) {
4089
- const store = createResourceSecretStore(resource, options);
4090
+ const store = createResourceSecretStore(resource, options, namespace);
4090
4091
  const value = await store.get();
4091
4092
  if (value === null) {
4092
4093
  return null;
@@ -4103,19 +4104,20 @@ function createAuthStoreSessionStore(options = {}) {
4103
4104
  throw new Error("Stored OAuth session must match the expected shape");
4104
4105
  },
4105
4106
  async save(resource, session) {
4106
- const store = createResourceSecretStore(resource, options);
4107
+ const store = createResourceSecretStore(resource, options, namespace);
4107
4108
  await store.set(JSON.stringify(session));
4108
4109
  },
4109
4110
  async clear(resource) {
4110
- const store = createResourceSecretStore(resource, options);
4111
+ const store = createResourceSecretStore(resource, options, namespace);
4111
4112
  await store.delete();
4112
4113
  }
4113
4114
  };
4114
4115
  }
4115
- function createAuthStoreClientStore(options) {
4116
+ function createAuthStoreClientStore(options, namespace) {
4117
+ assertPersistenceNamespace(namespace);
4116
4118
  return {
4117
4119
  async load(issuer) {
4118
- const store = createIssuerSecretStore(issuer, options);
4120
+ const store = createIssuerSecretStore(issuer, options, namespace);
4119
4121
  const value = await store.get();
4120
4122
  if (value === null) {
4121
4123
  return null;
@@ -4137,17 +4139,17 @@ function createAuthStoreClientStore(options) {
4137
4139
  throw new Error("Stored OAuth client must be a JSON object with clientId");
4138
4140
  },
4139
4141
  async save(issuer, client) {
4140
- const store = createIssuerSecretStore(issuer, options);
4142
+ const store = createIssuerSecretStore(issuer, options, namespace);
4141
4143
  await store.set(JSON.stringify(client));
4142
4144
  },
4143
4145
  async clear(issuer) {
4144
- const store = createIssuerSecretStore(issuer, options);
4146
+ const store = createIssuerSecretStore(issuer, options, namespace);
4145
4147
  await store.delete();
4146
4148
  }
4147
4149
  };
4148
4150
  }
4149
- function createNamedSecretStore(key2, options, defaults) {
4150
- const hash = crypto.createHash("sha256").update(key2).digest("hex");
4151
+ function createNamedSecretStore(key2, options, defaults, namespace) {
4152
+ const hash = crypto.createHash("sha256").update(namespace === void 0 ? key2 : JSON.stringify([namespace, key2])).digest("hex");
4151
4153
  const configuredFilePath = options.fileStore?.filePath;
4152
4154
  const parsedFilePath = configuredFilePath === void 0 ? null : path4.parse(configuredFilePath);
4153
4155
  const fileStore = {
@@ -4165,21 +4167,25 @@ function createNamedSecretStore(key2, options, defaults) {
4165
4167
  };
4166
4168
  return createSecretStore({ ...options, fileStore, keychainStore }).store;
4167
4169
  }
4168
- function createResourceSecretStore(resource, options) {
4170
+ function createResourceSecretStore(resource, options, namespace) {
4169
4171
  return createNamedSecretStore(canonicalizeResourceIndicator(resource), options, {
4170
4172
  salt: DEFAULT_FILE_SALT,
4171
4173
  directory: DEFAULT_FILE_DIRECTORY,
4172
4174
  service: DEFAULT_KEYCHAIN_SERVICE,
4173
4175
  accountPrefix: "provider"
4174
- });
4176
+ }, namespace);
4175
4177
  }
4176
- function createIssuerSecretStore(issuer, options) {
4178
+ function createIssuerSecretStore(issuer, options, namespace) {
4177
4179
  return createNamedSecretStore(issuer, options, {
4178
4180
  salt: DEFAULT_CLIENT_FILE_SALT,
4179
4181
  directory: DEFAULT_CLIENT_FILE_DIRECTORY,
4180
4182
  service: DEFAULT_CLIENT_KEYCHAIN_SERVICE,
4181
4183
  accountPrefix: "issuer"
4182
- });
4184
+ }, namespace);
4185
+ }
4186
+ function assertPersistenceNamespace(namespace) {
4187
+ if (namespace !== void 0 && (typeof namespace !== "string" || namespace.trim() === "" || Buffer.byteLength(namespace, "utf8") > 1024))
4188
+ throw new Error("OAuth persistence namespace must be a nonempty string within 1024 bytes");
4183
4189
  }
4184
4190
  function isObjectRecord(value) {
4185
4191
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -4840,8 +4846,9 @@ function createOAuthClientProvider(options) {
4840
4846
  }
4841
4847
  function createDefaultOAuthClientProvider(options) {
4842
4848
  loopbackTarget(options.browser);
4843
- const sessionStore = options.sessionStore ?? createAuthStoreSessionStore(options.authStore);
4844
- const clientStore = options.authStore === void 0 ? null : createAuthStoreClientStore(options.authStore);
4849
+ assertPersistenceNamespace(options.persistenceNamespace);
4850
+ const sessionStore = options.sessionStore ?? createAuthStoreSessionStore(options.authStore, options.persistenceNamespace);
4851
+ const clientStore = options.authStore === void 0 ? null : createAuthStoreClientStore(options.authStore, options.persistenceNamespace);
4845
4852
  const now = options.now ?? Date.now;
4846
4853
  const registeredClients = /* @__PURE__ */ new Map();
4847
4854
  if (options.initialGrant !== void 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiny-http-mcp-server",
3
- "version": "0.1.30",
3
+ "version": "0.1.31",
4
4
  "description": "Minimal MCP server over HTTP built on tiny-stdio-mcp-server",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",