toolcraft 0.0.348 → 0.0.349

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.76",
101
+ "version": "0.1.78",
102
102
  "license": "MIT"
103
103
  },
104
104
  {
@@ -113,7 +113,7 @@
113
113
  },
114
114
  {
115
115
  "name": "toolcraft",
116
- "version": "0.0.348",
116
+ "version": "0.0.349",
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.348",
126
+ "version": "0.0.349",
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.76",
101
+ "version": "0.1.78",
102
102
  "license": "MIT"
103
103
  },
104
104
  {
@@ -113,7 +113,7 @@
113
113
  },
114
114
  {
115
115
  "name": "toolcraft",
116
- "version": "0.0.348",
116
+ "version": "0.0.349",
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.348",
126
+ "version": "0.0.349",
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.76",
21
+ "version": "0.1.78",
22
22
  "license": "MIT"
23
23
  },
24
24
  {
@@ -92,6 +92,8 @@ Fixed redirects support `localhost`, `127.0.0.1`, and `::1` over HTTP. Their
92
92
  exact spelling, port, path and query are preserved through registration,
93
93
  authorization and code exchange. Credentials, fragments, port zero and reserved
94
94
  OAuth callback query parameters, including `error_uri`, are rejected before binding a listener.
95
+ Fragment rejection includes a trailing empty `#`. Empty queries and percent-escaped
96
+ hash data remain valid and keep their exact registered spelling.
95
97
  `createDefaultOAuthClientProvider` also checks the configured redirect before
96
98
  creating the provider. Imported tokens that cannot be sent as HTTP header
97
99
  values fail with diagnostics that omit their contents. Omit
@@ -86,7 +86,7 @@ export function loopbackTarget(options) {
86
86
  throw new Error("Invalid OAuth loopback redirect URI", { cause });
87
87
  }
88
88
  if (url.protocol !== "http:" || !["localhost", "127.0.0.1", "[::1]"].includes(url.hostname)
89
- || url.username || url.password || url.hash || url.port === "0"
89
+ || url.username || url.password || url.href.includes("#") || url.port === "0"
90
90
  || oauthCallbackParameters.some(name => url.searchParams.has(name))
91
91
  || [...options.redirectUri].some(char => char.codePointAt(0) <= 32)
92
92
  || (options.callbackPath !== undefined && options.callbackPath !== url.pathname))
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tiny-http-mcp-server",
3
- "version": "0.1.76",
3
+ "version": "0.1.78",
4
4
  "description": "Minimal MCP server over HTTP built on tiny-stdio-mcp-server",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -60,6 +60,8 @@ timer; a timeout releases request capacity so later operations can proceed.
60
60
  Legacy SSE mode opens a GET stream and posts messages to the endpoint announced
61
61
  by the server. Announced endpoints must remain on the original origin without
62
62
  embedded credentials or fragments; endpoint changes close the connection.
63
+ Empty fragment delimiters are rejected too; escaped hashes in an endpoint path
64
+ or query remain literal data.
63
65
  Both transports accept the same headers, OAuth provider and response limits.
64
66
  Static HTTP headers are copied and validated when the transport is constructed,
65
67
  before OAuth callbacks run. Invalid headers fail without reflecting their values.
@@ -117,6 +119,10 @@ Protected-resource metadata HTTP failures also expose their numeric `status`.
117
119
  Advertised resource identities reject named and empty fragments before issuer
118
120
  discovery; malformed shared-cache identities are evicted. Resource queries and
119
121
  percent-escaped hash data remain part of the exact resource identity.
122
+ Discovery lookup, metadata and endpoint URLs reject empty fragments too.
123
+ Issuer identifiers reject named or empty query/fragment components; escaped
124
+ delimiters in their paths remain valid. Original lookup fragments fail before
125
+ cache access, and cached metadata locations with empty fragments are evicted.
120
126
  Rejected metadata bodies start cleanup without delaying failure or caller
121
127
  cancellation. Host cleanup may finish later; its rejection remains observed.
122
128
  `OAuthMetadataError.is(value)` recognizes separately bundled native copies.
@@ -3601,7 +3601,7 @@ function loopbackTarget(options) {
3601
3601
  } catch (cause) {
3602
3602
  throw new Error("Invalid OAuth loopback redirect URI", { cause });
3603
3603
  }
3604
- if (url.protocol !== "http:" || !["localhost", "127.0.0.1", "[::1]"].includes(url.hostname) || url.username || url.password || url.hash || url.port === "0" || oauthCallbackParameters.some((name) => url.searchParams.has(name)) || [...options.redirectUri].some((char) => char.codePointAt(0) <= 32) || options.callbackPath !== void 0 && options.callbackPath !== url.pathname)
3604
+ if (url.protocol !== "http:" || !["localhost", "127.0.0.1", "[::1]"].includes(url.hostname) || url.username || url.password || url.href.includes("#") || url.port === "0" || oauthCallbackParameters.some((name) => url.searchParams.has(name)) || [...options.redirectUri].some((char) => char.codePointAt(0) <= 32) || options.callbackPath !== void 0 && options.callbackPath !== url.pathname)
3605
3605
  throw new Error("Invalid OAuth loopback redirect URI");
3606
3606
  return { port: url.port ? Number(url.port) : 80, host: url.hostname === "[::1]" ? "::1" : url.hostname, callbackPath: url.pathname };
3607
3607
  }
@@ -6276,7 +6276,7 @@ function isLoopbackHostname2(hostname2) {
6276
6276
  return normalizedHostname === "localhost" || normalizedHostname === "::1" || normalizedHostname === "[::1]" || isIP2(normalizedHostname) === 4 && normalizedHostname.startsWith("127.");
6277
6277
  }
6278
6278
  function assertSecureUrl2(url, label) {
6279
- if (url.username !== "" || url.password !== "" || url.hash !== "") {
6279
+ if (url.username !== "" || url.password !== "" || url.href.includes("#")) {
6280
6280
  throw new Error(`${label} must not include credentials or fragment`);
6281
6281
  }
6282
6282
  if (url.protocol === "https:") {
@@ -6346,11 +6346,6 @@ function validateAuthorizationServerMetadata(value, issuer) {
6346
6346
  } catch {
6347
6347
  throw new Error(`Authorization server metadata ${field} must be an absolute URL`);
6348
6348
  }
6349
- if (endpoint.username !== "" || endpoint.password !== "" || endpoint.hash !== "") {
6350
- throw new Error(
6351
- `Authorization server metadata ${field} must not include credentials or fragment`
6352
- );
6353
- }
6354
6349
  assertSecureUrl2(endpoint, `Authorization server metadata ${field}`);
6355
6350
  }
6356
6351
  if (!isStringArray(value.response_types_supported) || !value.response_types_supported.includes("code")) {
@@ -6397,7 +6392,7 @@ function resolveWellKnownMetadataUrl(inputUrl, suffix) {
6397
6392
  return url.toString();
6398
6393
  }
6399
6394
  function resolveProtectedResourceMetadataUrl(resourceUrl, resourceMetadataUrl) {
6400
- const resource = new URL(canonicalizeResourceIndicator(resourceUrl));
6395
+ const resource = new URL(typeof resourceUrl === "string" ? resourceUrl : resourceUrl.toString());
6401
6396
  assertSecureUrl2(resource, "Protected resource URL");
6402
6397
  if (resourceMetadataUrl !== void 0) {
6403
6398
  const resolvedResourceMetadataUrl2 = new URL(
@@ -6416,7 +6411,7 @@ function resolveProtectedResourceMetadataUrl(resourceUrl, resourceMetadataUrl) {
6416
6411
  function validateAuthorizationServerIssuer(issuer) {
6417
6412
  const input = typeof issuer === "string" ? issuer : issuer.toString();
6418
6413
  const url = new URL(input);
6419
- if (url.search.length > 0 || url.hash.length > 0) {
6414
+ if (url.href.includes("?") || url.href.includes("#")) {
6420
6415
  throw new Error("Authorization server issuer must not include query or fragment");
6421
6416
  }
6422
6417
  assertSecureUrl2(url, "Authorization server issuer");
@@ -6450,11 +6445,6 @@ function validateCachedDiscovery(value, resource) {
6450
6445
  }
6451
6446
  const resourceMetadata = validateProtectedResourceMetadata(value.resourceMetadata, resource);
6452
6447
  const resourceMetadataLocation = new URL(value.resourceMetadataUrl);
6453
- if (resourceMetadataLocation.username !== "" || resourceMetadataLocation.password !== "" || resourceMetadataLocation.hash !== "") {
6454
- throw new Error(
6455
- "Cached OAuth discovery metadata location must not include credentials or fragment"
6456
- );
6457
- }
6458
6448
  assertSecureUrl2(resourceMetadataLocation, "Cached OAuth discovery metadata location");
6459
6449
  const issuer = validateAuthorizationServerIssuer(value.authorizationServer);
6460
6450
  if (!resourceMetadata.authorization_servers.includes(issuer)) {
@@ -6521,7 +6511,7 @@ var OAuthMetadataDiscovery = class {
6521
6511
  async discover(resourceUrl, { resourceMetadataUrl, signal } = {}) {
6522
6512
  signal?.throwIfAborted();
6523
6513
  const cacheKey = canonicalizeResourceIndicator(resourceUrl);
6524
- resolveProtectedResourceMetadataUrl(cacheKey, resourceMetadataUrl);
6514
+ resolveProtectedResourceMetadataUrl(resourceUrl, resourceMetadataUrl);
6525
6515
  const memoryCachedResult = this.memoryCache.get(cacheKey);
6526
6516
  if (memoryCachedResult !== void 0 && resourceMetadataUrl === void 0) {
6527
6517
  return structuredClone(memoryCachedResult);
@@ -8333,7 +8323,7 @@ var HttpTransport = class {
8333
8323
  if (message.event === "endpoint") {
8334
8324
  const endpoint = new URL(message.data, this.url);
8335
8325
  const resource = new URL(this.url);
8336
- if (endpoint.protocol !== "http:" && endpoint.protocol !== "https:" || endpoint.origin !== resource.origin || endpoint.username || endpoint.password || endpoint.hash)
8326
+ if (endpoint.protocol !== "http:" && endpoint.protocol !== "https:" || endpoint.origin !== resource.origin || endpoint.username || endpoint.password || endpoint.href.includes("#"))
8337
8327
  throw new Error("Unsafe legacy SSE endpoint");
8338
8328
  if (this.legacyEndpoint !== void 0 && this.legacyEndpoint !== endpoint.href)
8339
8329
  throw new Error("Legacy SSE endpoint changed during the active connection");
@@ -8,7 +8,7 @@
8
8
  },
9
9
  {
10
10
  "name": "toolcraft-schema",
11
- "version": "0.0.348",
11
+ "version": "0.0.349",
12
12
  "license": "MIT"
13
13
  }
14
14
  ]
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolcraft-schema",
3
- "version": "0.0.348",
3
+ "version": "0.0.349",
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.348",
3
+ "version": "0.0.349",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -158,7 +158,7 @@
158
158
  "yaml"
159
159
  ],
160
160
  "optionalDependencies": {
161
- "toolcraft-schema": "0.0.348",
161
+ "toolcraft-schema": "0.0.349",
162
162
  "toolcraft-design": "*",
163
163
  "@poe-code/frontmatter": "*",
164
164
  "@poe-code/agent-mcp-config": "*",