toolcraft 0.0.348 → 0.0.350
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 +3 -3
- package/dist/composition.json +3 -3
- package/node_modules/tiny-http-mcp-server/dist/composition.json +1 -1
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/README.md +10 -1
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/default-oauth-client-provider.js +9 -3
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/loopback-authorization.js +1 -1
- package/node_modules/tiny-http-mcp-server/package.json +1 -1
- package/node_modules/tiny-mcp-client/README.md +6 -0
- package/node_modules/tiny-mcp-client/dist/index.js +15 -19
- package/node_modules/tiny-stdio-mcp-server/dist/composition.json +1 -1
- package/node_modules/toolcraft-schema/package.json +1 -1
- package/package.json +2 -2
package/composition.json
CHANGED
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
},
|
|
99
99
|
{
|
|
100
100
|
"name": "tiny-http-mcp-server",
|
|
101
|
-
"version": "0.1.
|
|
101
|
+
"version": "0.1.80",
|
|
102
102
|
"license": "MIT"
|
|
103
103
|
},
|
|
104
104
|
{
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
},
|
|
114
114
|
{
|
|
115
115
|
"name": "toolcraft",
|
|
116
|
-
"version": "0.0.
|
|
116
|
+
"version": "0.0.350",
|
|
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.
|
|
126
|
+
"version": "0.0.350",
|
|
127
127
|
"license": "MIT"
|
|
128
128
|
},
|
|
129
129
|
{
|
package/dist/composition.json
CHANGED
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
},
|
|
99
99
|
{
|
|
100
100
|
"name": "tiny-http-mcp-server",
|
|
101
|
-
"version": "0.1.
|
|
101
|
+
"version": "0.1.80",
|
|
102
102
|
"license": "MIT"
|
|
103
103
|
},
|
|
104
104
|
{
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
},
|
|
114
114
|
{
|
|
115
115
|
"name": "toolcraft",
|
|
116
|
-
"version": "0.0.
|
|
116
|
+
"version": "0.0.350",
|
|
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.
|
|
126
|
+
"version": "0.0.350",
|
|
127
127
|
"license": "MIT"
|
|
128
128
|
},
|
|
129
129
|
{
|
|
@@ -61,12 +61,16 @@ alone do not establish either native error type.
|
|
|
61
61
|
- `browser.timeoutMs` optional authorization deadline (default 120,000 ms)
|
|
62
62
|
- `sessionStore` optional
|
|
63
63
|
- `authStore` optional `auth-store` backend config for the default session store
|
|
64
|
-
- `now()` optional clock override
|
|
64
|
+
- `now()` optional clock override returning integer Unix epoch milliseconds within the JavaScript Date range
|
|
65
65
|
|
|
66
66
|
The default provider captures client, interaction, callback, landing-page and
|
|
67
67
|
lock policies when created. Create a new provider to change those settings.
|
|
68
68
|
Selected callbacks, stores, clocks and AbortSignals remain live host dependencies;
|
|
69
69
|
aborting the original signal still cancels authorization.
|
|
70
|
+
An invalid clock fails before attaching or refreshing a grant with a known
|
|
71
|
+
expiry or redeeming a time-limited client secret. Unknown access lifetimes and
|
|
72
|
+
unlimited secret lifetimes do not require a clock read. Valid negative epoch
|
|
73
|
+
times remain supported.
|
|
70
74
|
Native session and client persistence factories also capture file paths, salts,
|
|
71
75
|
Keychain identities, lock locations and selected filesystem/command handles.
|
|
72
76
|
Mutating these settings cannot redirect a later read or write.
|
|
@@ -92,6 +96,11 @@ Fixed redirects support `localhost`, `127.0.0.1`, and `::1` over HTTP. Their
|
|
|
92
96
|
exact spelling, port, path and query are preserved through registration,
|
|
93
97
|
authorization and code exchange. Credentials, fragments, port zero and reserved
|
|
94
98
|
OAuth callback query parameters, including `error_uri`, are rejected before binding a listener.
|
|
99
|
+
Fragment rejection includes a trailing empty `#`. Empty queries and percent-escaped
|
|
100
|
+
hash data remain valid and keep their exact registered spelling.
|
|
101
|
+
Direct initial grants and host-supplied or stored authorization, token and
|
|
102
|
+
registration endpoints also reject empty fragment components before consent or
|
|
103
|
+
credential redemption. Percent-escaped hashes remain ordinary path/query data.
|
|
95
104
|
`createDefaultOAuthClientProvider` also checks the configured redirect before
|
|
96
105
|
creating the provider. Imported tokens that cannot be sent as HTTP header
|
|
97
106
|
values fail with diagnostics that omit their contents. Omit
|
|
@@ -40,7 +40,13 @@ export function createDefaultOAuthClientProvider(options) {
|
|
|
40
40
|
const sessionStore = resourceStores?.sessionStore ?? options.sessionStore ?? createAuthStoreSessionStore(options.authStore, options.persistenceNamespace);
|
|
41
41
|
const clientStore = resourceStores?.clientStore ??
|
|
42
42
|
(options.authStore === undefined ? null : createAuthStoreClientStore(options.authStore, options.persistenceNamespace));
|
|
43
|
-
const
|
|
43
|
+
const clock = options.now ?? Date.now;
|
|
44
|
+
const now = () => {
|
|
45
|
+
const timestamp = clock();
|
|
46
|
+
if (!Number.isSafeInteger(timestamp) || Math.abs(timestamp) > MAX_JS_DATE_MS)
|
|
47
|
+
throw new Error("OAuth clock must return valid epoch milliseconds");
|
|
48
|
+
return timestamp;
|
|
49
|
+
};
|
|
44
50
|
const registeredClients = new Map();
|
|
45
51
|
if (options.initialGrant !== undefined) {
|
|
46
52
|
let resource;
|
|
@@ -50,7 +56,7 @@ export function createDefaultOAuthClientProvider(options) {
|
|
|
50
56
|
catch {
|
|
51
57
|
throw new Error("OAuth initial grant resource must be an absolute HTTP URL");
|
|
52
58
|
}
|
|
53
|
-
if ((resource.protocol !== "http:" && resource.protocol !== "https:") || resource.username || resource.password || resource.
|
|
59
|
+
if ((resource.protocol !== "http:" && resource.protocol !== "https:") || resource.username || resource.password || resource.href.includes("#"))
|
|
54
60
|
throw new Error("OAuth initial grant resource must be an HTTP URL without credentials or fragments");
|
|
55
61
|
}
|
|
56
62
|
const initialGrant = options.initialGrant === undefined ? undefined : {
|
|
@@ -756,7 +762,7 @@ function isLoopbackHostname(hostname) {
|
|
|
756
762
|
}
|
|
757
763
|
function assertSecureUrl(value, label) {
|
|
758
764
|
const url = new URL(value);
|
|
759
|
-
if (url.username !== "" || url.password !== "" || url.
|
|
765
|
+
if (url.username !== "" || url.password !== "" || url.href.includes("#")) {
|
|
760
766
|
throw new Error(`${label} must not include credentials or fragment`);
|
|
761
767
|
}
|
|
762
768
|
if (url.protocol === "https:") {
|
|
@@ -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.
|
|
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))
|
|
@@ -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.
|
|
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
|
}
|
|
@@ -5335,7 +5335,13 @@ function createDefaultOAuthClientProvider(options) {
|
|
|
5335
5335
|
const resourceStores = options.resourceIdentity === void 0 ? void 0 : createResourceBoundOAuthStores(options.authStore ?? {}, options.persistenceNamespace, options.resourceIdentity);
|
|
5336
5336
|
const sessionStore = resourceStores?.sessionStore ?? options.sessionStore ?? createAuthStoreSessionStore(options.authStore, options.persistenceNamespace);
|
|
5337
5337
|
const clientStore = resourceStores?.clientStore ?? (options.authStore === void 0 ? null : createAuthStoreClientStore(options.authStore, options.persistenceNamespace));
|
|
5338
|
-
const
|
|
5338
|
+
const clock = options.now ?? Date.now;
|
|
5339
|
+
const now = () => {
|
|
5340
|
+
const timestamp = clock();
|
|
5341
|
+
if (!Number.isSafeInteger(timestamp) || Math.abs(timestamp) > MAX_JS_DATE_MS3)
|
|
5342
|
+
throw new Error("OAuth clock must return valid epoch milliseconds");
|
|
5343
|
+
return timestamp;
|
|
5344
|
+
};
|
|
5339
5345
|
const registeredClients = /* @__PURE__ */ new Map();
|
|
5340
5346
|
if (options.initialGrant !== void 0) {
|
|
5341
5347
|
let resource;
|
|
@@ -5344,7 +5350,7 @@ function createDefaultOAuthClientProvider(options) {
|
|
|
5344
5350
|
} catch {
|
|
5345
5351
|
throw new Error("OAuth initial grant resource must be an absolute HTTP URL");
|
|
5346
5352
|
}
|
|
5347
|
-
if (resource.protocol !== "http:" && resource.protocol !== "https:" || resource.username || resource.password || resource.
|
|
5353
|
+
if (resource.protocol !== "http:" && resource.protocol !== "https:" || resource.username || resource.password || resource.href.includes("#"))
|
|
5348
5354
|
throw new Error("OAuth initial grant resource must be an HTTP URL without credentials or fragments");
|
|
5349
5355
|
}
|
|
5350
5356
|
const initialGrant = options.initialGrant === void 0 ? void 0 : {
|
|
@@ -6011,7 +6017,7 @@ function isLoopbackHostname(hostname2) {
|
|
|
6011
6017
|
}
|
|
6012
6018
|
function assertSecureUrl(value, label) {
|
|
6013
6019
|
const url = new URL2(value);
|
|
6014
|
-
if (url.username !== "" || url.password !== "" || url.
|
|
6020
|
+
if (url.username !== "" || url.password !== "" || url.href.includes("#")) {
|
|
6015
6021
|
throw new Error(`${label} must not include credentials or fragment`);
|
|
6016
6022
|
}
|
|
6017
6023
|
if (url.protocol === "https:") {
|
|
@@ -6276,7 +6282,7 @@ function isLoopbackHostname2(hostname2) {
|
|
|
6276
6282
|
return normalizedHostname === "localhost" || normalizedHostname === "::1" || normalizedHostname === "[::1]" || isIP2(normalizedHostname) === 4 && normalizedHostname.startsWith("127.");
|
|
6277
6283
|
}
|
|
6278
6284
|
function assertSecureUrl2(url, label) {
|
|
6279
|
-
if (url.username !== "" || url.password !== "" || url.
|
|
6285
|
+
if (url.username !== "" || url.password !== "" || url.href.includes("#")) {
|
|
6280
6286
|
throw new Error(`${label} must not include credentials or fragment`);
|
|
6281
6287
|
}
|
|
6282
6288
|
if (url.protocol === "https:") {
|
|
@@ -6346,11 +6352,6 @@ function validateAuthorizationServerMetadata(value, issuer) {
|
|
|
6346
6352
|
} catch {
|
|
6347
6353
|
throw new Error(`Authorization server metadata ${field} must be an absolute URL`);
|
|
6348
6354
|
}
|
|
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
6355
|
assertSecureUrl2(endpoint, `Authorization server metadata ${field}`);
|
|
6355
6356
|
}
|
|
6356
6357
|
if (!isStringArray(value.response_types_supported) || !value.response_types_supported.includes("code")) {
|
|
@@ -6397,7 +6398,7 @@ function resolveWellKnownMetadataUrl(inputUrl, suffix) {
|
|
|
6397
6398
|
return url.toString();
|
|
6398
6399
|
}
|
|
6399
6400
|
function resolveProtectedResourceMetadataUrl(resourceUrl, resourceMetadataUrl) {
|
|
6400
|
-
const resource = new URL(
|
|
6401
|
+
const resource = new URL(typeof resourceUrl === "string" ? resourceUrl : resourceUrl.toString());
|
|
6401
6402
|
assertSecureUrl2(resource, "Protected resource URL");
|
|
6402
6403
|
if (resourceMetadataUrl !== void 0) {
|
|
6403
6404
|
const resolvedResourceMetadataUrl2 = new URL(
|
|
@@ -6416,7 +6417,7 @@ function resolveProtectedResourceMetadataUrl(resourceUrl, resourceMetadataUrl) {
|
|
|
6416
6417
|
function validateAuthorizationServerIssuer(issuer) {
|
|
6417
6418
|
const input = typeof issuer === "string" ? issuer : issuer.toString();
|
|
6418
6419
|
const url = new URL(input);
|
|
6419
|
-
if (url.
|
|
6420
|
+
if (url.href.includes("?") || url.href.includes("#")) {
|
|
6420
6421
|
throw new Error("Authorization server issuer must not include query or fragment");
|
|
6421
6422
|
}
|
|
6422
6423
|
assertSecureUrl2(url, "Authorization server issuer");
|
|
@@ -6450,11 +6451,6 @@ function validateCachedDiscovery(value, resource) {
|
|
|
6450
6451
|
}
|
|
6451
6452
|
const resourceMetadata = validateProtectedResourceMetadata(value.resourceMetadata, resource);
|
|
6452
6453
|
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
6454
|
assertSecureUrl2(resourceMetadataLocation, "Cached OAuth discovery metadata location");
|
|
6459
6455
|
const issuer = validateAuthorizationServerIssuer(value.authorizationServer);
|
|
6460
6456
|
if (!resourceMetadata.authorization_servers.includes(issuer)) {
|
|
@@ -6521,7 +6517,7 @@ var OAuthMetadataDiscovery = class {
|
|
|
6521
6517
|
async discover(resourceUrl, { resourceMetadataUrl, signal } = {}) {
|
|
6522
6518
|
signal?.throwIfAborted();
|
|
6523
6519
|
const cacheKey = canonicalizeResourceIndicator(resourceUrl);
|
|
6524
|
-
resolveProtectedResourceMetadataUrl(
|
|
6520
|
+
resolveProtectedResourceMetadataUrl(resourceUrl, resourceMetadataUrl);
|
|
6525
6521
|
const memoryCachedResult = this.memoryCache.get(cacheKey);
|
|
6526
6522
|
if (memoryCachedResult !== void 0 && resourceMetadataUrl === void 0) {
|
|
6527
6523
|
return structuredClone(memoryCachedResult);
|
|
@@ -8333,7 +8329,7 @@ var HttpTransport = class {
|
|
|
8333
8329
|
if (message.event === "endpoint") {
|
|
8334
8330
|
const endpoint = new URL(message.data, this.url);
|
|
8335
8331
|
const resource = new URL(this.url);
|
|
8336
|
-
if (endpoint.protocol !== "http:" && endpoint.protocol !== "https:" || endpoint.origin !== resource.origin || endpoint.username || endpoint.password || endpoint.
|
|
8332
|
+
if (endpoint.protocol !== "http:" && endpoint.protocol !== "https:" || endpoint.origin !== resource.origin || endpoint.username || endpoint.password || endpoint.href.includes("#"))
|
|
8337
8333
|
throw new Error("Unsafe legacy SSE endpoint");
|
|
8338
8334
|
if (this.legacyEndpoint !== void 0 && this.legacyEndpoint !== endpoint.href)
|
|
8339
8335
|
throw new Error("Legacy SSE endpoint changed during the active connection");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolcraft",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.350",
|
|
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.
|
|
161
|
+
"toolcraft-schema": "0.0.350",
|
|
162
162
|
"toolcraft-design": "*",
|
|
163
163
|
"@poe-code/frontmatter": "*",
|
|
164
164
|
"@poe-code/agent-mcp-config": "*",
|