toolcraft 0.0.703 → 0.0.705

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/composition.json CHANGED
@@ -98,7 +98,7 @@
98
98
  },
99
99
  {
100
100
  "name": "tiny-http-mcp-server",
101
- "version": "0.1.105",
101
+ "version": "0.1.106",
102
102
  "license": "MIT"
103
103
  },
104
104
  {
@@ -113,7 +113,7 @@
113
113
  },
114
114
  {
115
115
  "name": "toolcraft",
116
- "version": "0.0.703",
116
+ "version": "0.0.705",
117
117
  "license": "MIT"
118
118
  },
119
119
  {
@@ -123,7 +123,7 @@
123
123
  },
124
124
  {
125
125
  "name": "toolcraft-schema",
126
- "version": "0.0.703",
126
+ "version": "0.0.705",
127
127
  "license": "MIT"
128
128
  },
129
129
  {
@@ -98,7 +98,7 @@
98
98
  },
99
99
  {
100
100
  "name": "tiny-http-mcp-server",
101
- "version": "0.1.105",
101
+ "version": "0.1.106",
102
102
  "license": "MIT"
103
103
  },
104
104
  {
@@ -113,7 +113,7 @@
113
113
  },
114
114
  {
115
115
  "name": "toolcraft",
116
- "version": "0.0.703",
116
+ "version": "0.0.705",
117
117
  "license": "MIT"
118
118
  },
119
119
  {
@@ -123,7 +123,7 @@
123
123
  },
124
124
  {
125
125
  "name": "toolcraft-schema",
126
- "version": "0.0.703",
126
+ "version": "0.0.705",
127
127
  "license": "MIT"
128
128
  },
129
129
  {
@@ -18,7 +18,7 @@
18
18
  },
19
19
  {
20
20
  "name": "tiny-http-mcp-server",
21
- "version": "0.1.105",
21
+ "version": "0.1.106",
22
22
  "license": "MIT"
23
23
  },
24
24
  {
@@ -149,7 +149,11 @@ observe the supplied signal and pass it to any work they start.
149
149
  `authorizeRequest` may return an owned token snapshot for the request it
150
150
  authorized. The HTTP client supplies that snapshot as `presentedTokens`, along
151
151
  with the actual request's `requestHeaders`, to `handleUnauthorized`. Providers
152
- that return `void` remain supported. The native provider compares the rejected
152
+ that return `void` remain supported. HTTP transports supply lazy `discover()`
153
+ instead of eagerly fetching metadata before the handler. A custom handler can
154
+ return `{ action: "fail" }` without metadata access or replay; call `discover()`
155
+ only when recovery needs validated metadata. Direct callers may still supply
156
+ already validated `discovery`. The native provider compares the rejected
153
157
  snapshot with persisted credentials: delayed 401s retry with a newer grant
154
158
  without redeeming its refresh token again. A proven current token is refreshed
155
159
  on 401 even when the server omits `error="invalid_token"`. Invalid provenance
@@ -137,7 +137,10 @@ export function createDefaultOAuthClientProvider(options) {
137
137
  ...(presented === undefined ? {} : { presentedTokens: presented }) };
138
138
  assertNoAccessTokenInUrl(input.requestUrl, "Protected resource request URL");
139
139
  const requestUrl = canonicalizeResourceIndicator(input.requestUrl);
140
- const resource = canonicalizeResourceIndicator(input.discovery.resource);
140
+ const discovery = input.discovery ?? structuredClone(await waitForOAuthOperation(input.discover?.() ?? Promise.reject(new Error("OAuth recovery requires metadata discovery")), input.signal));
141
+ if (discovery === undefined)
142
+ throw new Error("OAuth recovery requires metadata discovery");
143
+ const resource = canonicalizeResourceIndicator(discovery.resource);
141
144
  assertRequestMatchesResource(requestUrl, resource);
142
145
  const cached = await waitForOAuthOperation(loadSession(resource), input.signal);
143
146
  const currentTokens = cached?.tokens ?? (!initialGrantConsumed && initialGrant?.resource === resource ? initialGrant.tokens : undefined);
@@ -157,7 +160,7 @@ export function createDefaultOAuthClientProvider(options) {
157
160
  }
158
161
  const forceRefresh = rejectedCurrentGrant && (challengeError === "invalid_token" || (input.presentedTokens !== undefined && challengeError === undefined));
159
162
  const session = await ensureAuthorizedSession(resource, {
160
- ...input.discovery,
163
+ ...discovery,
161
164
  resource
162
165
  }, input.fetch, true, forceRefresh, input.signal, presentedTokens);
163
166
  if (session?.tokens?.accessToken === undefined) {
@@ -46,7 +46,10 @@ export interface OAuthClientProvider {
46
46
  requestUrl: URL;
47
47
  response: Response;
48
48
  challenge: OAuthUnauthorizedChallenge | null;
49
- discovery: OAuthDiscoveryResult;
49
+ /** Validated metadata supplied by direct callers, if already available. */
50
+ discovery?: OAuthDiscoveryResult;
51
+ /** Lazy validated metadata; invoke only when OAuth recovery needs it. */
52
+ discover?: () => Promise<OAuthDiscoveryResult>;
50
53
  fetch: OAuthMetadataFetch;
51
54
  signal?: AbortSignal;
52
55
  /** Headers actually attached to this rejected request. */
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiny-http-mcp-server",
3
- "version": "0.1.105",
3
+ "version": "0.1.106",
4
4
  "description": "Minimal MCP server over HTTP built on tiny-stdio-mcp-server",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -103,7 +103,7 @@ the same optional `closeReason` promise when closing requires asynchronous work.
103
103
 
104
104
  ## OAuth HTTP support
105
105
 
106
- `HttpTransport` accepts `oauth` options from `mcp-oauth`. When a protected server returns a Bearer `WWW-Authenticate` challenge, the transport discovers protected-resource metadata, loads authorization-server metadata, lets the OAuth provider handle authorization, and retries the request when credentials are available.
106
+ `HttpTransport` accepts `oauth` options from `mcp-oauth`. On HTTP 401, the transport calls the OAuth provider before fetching metadata. Custom providers can reject the presented token and return `{ action: "fail" }` without discovery or request replay. The handler receives a memoized `discover()` callback for validated protected-resource and authorization-server metadata when recovery needs it. The built-in provider invokes this callback and requests a retry when credentials are available.
107
107
 
108
108
  ```ts
109
109
  import { HttpTransport } from "tiny-mcp-client";
@@ -149,7 +149,10 @@ interface OAuthClientProvider {
149
149
  requestUrl: URL;
150
150
  response: Response;
151
151
  challenge: OAuthUnauthorizedChallenge | null;
152
- discovery: OAuthDiscoveryResult;
152
+ /** Validated metadata supplied by direct callers, if already available. */
153
+ discovery?: OAuthDiscoveryResult;
154
+ /** Lazy validated metadata; invoke only when OAuth recovery needs it. */
155
+ discover?: () => Promise<OAuthDiscoveryResult>;
153
156
  fetch: OAuthMetadataFetch;
154
157
  signal?: AbortSignal;
155
158
  /** Headers actually attached to this rejected request. */
@@ -5527,7 +5527,10 @@ function createDefaultOAuthClientProvider(options) {
5527
5527
  };
5528
5528
  assertNoAccessTokenInUrl(input.requestUrl, "Protected resource request URL");
5529
5529
  const requestUrl = canonicalizeResourceIndicator(input.requestUrl);
5530
- const resource = canonicalizeResourceIndicator(input.discovery.resource);
5530
+ const discovery = input.discovery ?? structuredClone(await waitForOAuthOperation(input.discover?.() ?? Promise.reject(new Error("OAuth recovery requires metadata discovery")), input.signal));
5531
+ if (discovery === void 0)
5532
+ throw new Error("OAuth recovery requires metadata discovery");
5533
+ const resource = canonicalizeResourceIndicator(discovery.resource);
5531
5534
  assertRequestMatchesResource(requestUrl, resource);
5532
5535
  const cached = await waitForOAuthOperation(loadSession(resource), input.signal);
5533
5536
  const currentTokens = cached?.tokens ?? (!initialGrantConsumed && initialGrant?.resource === resource ? initialGrant.tokens : void 0);
@@ -5547,7 +5550,7 @@ function createDefaultOAuthClientProvider(options) {
5547
5550
  }
5548
5551
  const forceRefresh = rejectedCurrentGrant && (challengeError === "invalid_token" || input.presentedTokens !== void 0 && challengeError === void 0);
5549
5552
  const session = await ensureAuthorizedSession(resource, {
5550
- ...input.discovery,
5553
+ ...discovery,
5551
5554
  resource
5552
5555
  }, input.fetch, true, forceRefresh, input.signal, presentedTokens);
5553
5556
  if (session?.tokens?.accessToken === void 0) {
@@ -8315,7 +8318,8 @@ var HttpTransport = class {
8315
8318
  try {
8316
8319
  const challenge = parseBearerWwwAuthenticateHeader(response.headers.get("WWW-Authenticate"));
8317
8320
  const resourceMetadataUrl = challenge?.params.resource_metadata;
8318
- const discovery = await discoveryClient.discover(this.url, { resourceMetadataUrl, signal });
8321
+ let discovery;
8322
+ const discover = () => discovery ??= discoveryClient.discover(this.url, { resourceMetadataUrl, signal });
8319
8323
  const providerResponse = response.clone();
8320
8324
  let result;
8321
8325
  try {
@@ -8323,7 +8327,7 @@ var HttpTransport = class {
8323
8327
  requestUrl: new URL(this.url),
8324
8328
  response: providerResponse,
8325
8329
  challenge,
8326
- discovery,
8330
+ discover,
8327
8331
  signal,
8328
8332
  requestHeaders: new Headers(requestHeaders),
8329
8333
  presentedTokens,
@@ -8,7 +8,7 @@
8
8
  },
9
9
  {
10
10
  "name": "toolcraft-schema",
11
- "version": "0.0.703",
11
+ "version": "0.0.705",
12
12
  "license": "MIT"
13
13
  }
14
14
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft-schema",
3
- "version": "0.0.703",
3
+ "version": "0.0.705",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft",
3
- "version": "0.0.703",
3
+ "version": "0.0.705",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -162,7 +162,7 @@
162
162
  "yaml"
163
163
  ],
164
164
  "optionalDependencies": {
165
- "toolcraft-schema": "0.0.703",
165
+ "toolcraft-schema": "0.0.705",
166
166
  "toolcraft-design": "*",
167
167
  "@poe-code/frontmatter": "*",
168
168
  "@poe-code/agent-mcp-config": "*",