@usethrottle/mcp 0.2.0 → 0.2.1

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.
package/dist/lib.d.cts CHANGED
@@ -14,6 +14,21 @@ interface RequestOptions {
14
14
  * `(workspace, application, environment, key, method, path)`.
15
15
  */
16
16
  idempotencyKey?: string;
17
+ /**
18
+ * Sent as `X-Throttle-Application-Id` on this one request only — see
19
+ * `PerCallOptions`.
20
+ */
21
+ applicationId?: string;
22
+ }
23
+ interface PerCallOptions {
24
+ /**
25
+ * Overrides which application a single `get`/`list` call reads from (the
26
+ * `oauth_token` auth branch validates this against the grant's own
27
+ * workspace membership; see `resolveOAuthApplication`). Scoped to this one
28
+ * request — never stored on the client instance — so concurrent calls with
29
+ * different application ids cannot bleed into each other.
30
+ */
31
+ applicationId?: string;
17
32
  }
18
33
  interface Pagination {
19
34
  cursor: string | null;
@@ -25,14 +40,26 @@ interface ListResult<T> {
25
40
  }
26
41
  type Fetcher = typeof fetch;
27
42
  declare class ThrottleClient {
28
- private readonly auth;
43
+ private auth;
29
44
  private readonly fetchImpl;
30
45
  constructor(auth: AuthCtx, fetchImpl?: Fetcher);
46
+ /**
47
+ * Swap the credential every later request is sent with. The hosted remote
48
+ * server builds one client per MCP session at `initialize`, but an OAuth
49
+ * access token lives one hour and the MCP client refreshes it underneath
50
+ * the session — each request then arrives with a newer bearer than the one
51
+ * the session was opened with. Without this, the session keeps calling the
52
+ * REST API with the token it was born with and every tool fails with a 401
53
+ * the moment that first token expires, even though the caller is still
54
+ * perfectly authenticated.
55
+ */
56
+ setApiKey(apiKey: string): void;
31
57
  private requestJson;
32
58
  /** Unwraps the `{ data }` envelope. Key presence, not `??` — `{data: null}` unwraps to null. */
33
- get<T>(path: string, query?: Record<string, unknown>): Promise<T>;
34
- list<T>(path: string, query?: Record<string, unknown>): Promise<ListResult<T>>;
59
+ get<T>(path: string, query?: Record<string, unknown>, options?: PerCallOptions): Promise<T>;
60
+ list<T>(path: string, query?: Record<string, unknown>, options?: PerCallOptions): Promise<ListResult<T>>;
35
61
  post<T>(path: string, options?: RequestOptions): Promise<T>;
62
+ patch<T>(path: string, options?: RequestOptions): Promise<T>;
36
63
  }
37
64
 
38
65
  /**
@@ -67,7 +94,8 @@ interface ContractIndex {
67
94
  }
68
95
 
69
96
  /**
70
- * `search_docs`, answered from an index of `apps/docs` bundled at build time.
97
+ * `search_docs`, answered from an index of the docs pages in `apps/web`,
98
+ * bundled at build time.
71
99
  *
72
100
  * Scoring mirrors the CLI's proven approach: title hits beat heading hits, which
73
101
  * beat body hits, and an exact phrase beats scattered terms. Deliberately simple —
@@ -122,6 +150,22 @@ interface RegistrationPolicy {
122
150
  identity: Identity;
123
151
  allowWrites: boolean;
124
152
  allowLiveWrites: boolean;
153
+ /**
154
+ * Whether sandbox-only writes (`seed_test_data`) register without
155
+ * `allowWrites`. Defaults to true — the documented CLI behaviour, where
156
+ * seeding a non-production environment needs no flag. The hosted remote
157
+ * server passes false: it is published as strictly read-only, and a
158
+ * directory reviewer connecting with a non-production credential must not
159
+ * find a tool that creates customers and orders.
160
+ */
161
+ allowSandboxWrites?: boolean;
162
+ /**
163
+ * Whether `credentialScoped` actions (`api_get`) register. Defaults to true
164
+ * for the CLI. The hosted server passes false: on an OAuth surface every
165
+ * tool declares the scopes it asks consent for, and a tool that reads any
166
+ * path cannot.
167
+ */
168
+ allowCredentialScoped?: boolean;
125
169
  }
126
170
  /**
127
171
  * Which tools this session gets. Pure and exported so the policy is testable
@@ -156,6 +200,16 @@ interface CreateServerOptions extends RegistrationPolicy {
156
200
  client: ThrottleClient;
157
201
  contract: ContractIndex;
158
202
  docs: DocsIndex;
203
+ /**
204
+ * The `WWW-Authenticate` challenge value the hosting transport advertises
205
+ * (RFC 9728 `Bearer resource_metadata="..."`). When set, a tool call that
206
+ * fails because the REST API rejected the credential (HTTP 401 — an expired
207
+ * or revoked OAuth access token) carries it back as
208
+ * `_meta["mcp/www_authenticate"]`, which is what ChatGPT and other remote
209
+ * clients key their re-authorization UI on. The stdio CLI leaves it unset:
210
+ * its operator-provided key has no re-auth flow to trigger.
211
+ */
212
+ authChallenge?: string;
159
213
  }
160
214
  declare function createServer(options: CreateServerOptions): McpServer;
161
215
 
package/dist/lib.d.ts CHANGED
@@ -14,6 +14,21 @@ interface RequestOptions {
14
14
  * `(workspace, application, environment, key, method, path)`.
15
15
  */
16
16
  idempotencyKey?: string;
17
+ /**
18
+ * Sent as `X-Throttle-Application-Id` on this one request only — see
19
+ * `PerCallOptions`.
20
+ */
21
+ applicationId?: string;
22
+ }
23
+ interface PerCallOptions {
24
+ /**
25
+ * Overrides which application a single `get`/`list` call reads from (the
26
+ * `oauth_token` auth branch validates this against the grant's own
27
+ * workspace membership; see `resolveOAuthApplication`). Scoped to this one
28
+ * request — never stored on the client instance — so concurrent calls with
29
+ * different application ids cannot bleed into each other.
30
+ */
31
+ applicationId?: string;
17
32
  }
18
33
  interface Pagination {
19
34
  cursor: string | null;
@@ -25,14 +40,26 @@ interface ListResult<T> {
25
40
  }
26
41
  type Fetcher = typeof fetch;
27
42
  declare class ThrottleClient {
28
- private readonly auth;
43
+ private auth;
29
44
  private readonly fetchImpl;
30
45
  constructor(auth: AuthCtx, fetchImpl?: Fetcher);
46
+ /**
47
+ * Swap the credential every later request is sent with. The hosted remote
48
+ * server builds one client per MCP session at `initialize`, but an OAuth
49
+ * access token lives one hour and the MCP client refreshes it underneath
50
+ * the session — each request then arrives with a newer bearer than the one
51
+ * the session was opened with. Without this, the session keeps calling the
52
+ * REST API with the token it was born with and every tool fails with a 401
53
+ * the moment that first token expires, even though the caller is still
54
+ * perfectly authenticated.
55
+ */
56
+ setApiKey(apiKey: string): void;
31
57
  private requestJson;
32
58
  /** Unwraps the `{ data }` envelope. Key presence, not `??` — `{data: null}` unwraps to null. */
33
- get<T>(path: string, query?: Record<string, unknown>): Promise<T>;
34
- list<T>(path: string, query?: Record<string, unknown>): Promise<ListResult<T>>;
59
+ get<T>(path: string, query?: Record<string, unknown>, options?: PerCallOptions): Promise<T>;
60
+ list<T>(path: string, query?: Record<string, unknown>, options?: PerCallOptions): Promise<ListResult<T>>;
35
61
  post<T>(path: string, options?: RequestOptions): Promise<T>;
62
+ patch<T>(path: string, options?: RequestOptions): Promise<T>;
36
63
  }
37
64
 
38
65
  /**
@@ -67,7 +94,8 @@ interface ContractIndex {
67
94
  }
68
95
 
69
96
  /**
70
- * `search_docs`, answered from an index of `apps/docs` bundled at build time.
97
+ * `search_docs`, answered from an index of the docs pages in `apps/web`,
98
+ * bundled at build time.
71
99
  *
72
100
  * Scoring mirrors the CLI's proven approach: title hits beat heading hits, which
73
101
  * beat body hits, and an exact phrase beats scattered terms. Deliberately simple —
@@ -122,6 +150,22 @@ interface RegistrationPolicy {
122
150
  identity: Identity;
123
151
  allowWrites: boolean;
124
152
  allowLiveWrites: boolean;
153
+ /**
154
+ * Whether sandbox-only writes (`seed_test_data`) register without
155
+ * `allowWrites`. Defaults to true — the documented CLI behaviour, where
156
+ * seeding a non-production environment needs no flag. The hosted remote
157
+ * server passes false: it is published as strictly read-only, and a
158
+ * directory reviewer connecting with a non-production credential must not
159
+ * find a tool that creates customers and orders.
160
+ */
161
+ allowSandboxWrites?: boolean;
162
+ /**
163
+ * Whether `credentialScoped` actions (`api_get`) register. Defaults to true
164
+ * for the CLI. The hosted server passes false: on an OAuth surface every
165
+ * tool declares the scopes it asks consent for, and a tool that reads any
166
+ * path cannot.
167
+ */
168
+ allowCredentialScoped?: boolean;
125
169
  }
126
170
  /**
127
171
  * Which tools this session gets. Pure and exported so the policy is testable
@@ -156,6 +200,16 @@ interface CreateServerOptions extends RegistrationPolicy {
156
200
  client: ThrottleClient;
157
201
  contract: ContractIndex;
158
202
  docs: DocsIndex;
203
+ /**
204
+ * The `WWW-Authenticate` challenge value the hosting transport advertises
205
+ * (RFC 9728 `Bearer resource_metadata="..."`). When set, a tool call that
206
+ * fails because the REST API rejected the credential (HTTP 401 — an expired
207
+ * or revoked OAuth access token) carries it back as
208
+ * `_meta["mcp/www_authenticate"]`, which is what ChatGPT and other remote
209
+ * clients key their re-authorization UI on. The stdio CLI leaves it unset:
210
+ * its operator-provided key has no re-auth flow to trigger.
211
+ */
212
+ authChallenge?: string;
159
213
  }
160
214
  declare function createServer(options: CreateServerOptions): McpServer;
161
215