toolcraft 0.0.350 → 0.0.351
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 +11 -2
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/default-oauth-client-provider.js +10 -6
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/resource-bound-store.js +9 -8
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/token-endpoint.js +4 -1
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/token-grant.js +4 -1
- package/node_modules/tiny-http-mcp-server/package.json +1 -1
- package/node_modules/tiny-mcp-client/README.md +5 -0
- package/node_modules/tiny-mcp-client/dist/index.js +28 -12
- 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.82",
|
|
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.351",
|
|
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.351",
|
|
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.82",
|
|
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.351",
|
|
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.351",
|
|
127
127
|
"license": "MIT"
|
|
128
128
|
},
|
|
129
129
|
{
|
|
@@ -171,7 +171,14 @@ refresh retains the previous granted set. Mismatched responses never activate
|
|
|
171
171
|
credentials; an unusable refresh response retains the pending refresh record.
|
|
172
172
|
`resourceIdentity` selects a native-owned logical server within its optional
|
|
173
173
|
persistence namespace. One encrypted, locked document owns that identity's
|
|
174
|
-
current resource URL, sessions and registrations.
|
|
174
|
+
current resource URL, sessions and registrations. Explicit imports and resets
|
|
175
|
+
reject fragment components, including an empty trailing `#`; imported protected-
|
|
176
|
+
resource metadata and stored client issuers obey the same fragment-free policy.
|
|
177
|
+
Issuer identifiers must also omit query components, including an empty `?`.
|
|
178
|
+
Direct and stored authorization flows enforce the same issuer URL policy before
|
|
179
|
+
consent or token redemption. New discovery identity and endpoint policy checks
|
|
180
|
+
run before acquiring the session transaction, so invalid replacement metadata
|
|
181
|
+
cannot retire a valid old grant. Escaped delimiter data stays valid. Changing the URL retires its
|
|
175
182
|
credentials permanently; returning to the old URL does not restore them.
|
|
176
183
|
Retired identities also withhold stale initial grants; authorize again or select
|
|
177
184
|
a fresh explicit profile to import a new grant. This option requires native persistence; custom
|
|
@@ -194,7 +201,9 @@ using the original configured client. Persisted sessions take precedence,
|
|
|
194
201
|
including sessions whose tokens have been cleared; an import cannot revive them.
|
|
195
202
|
Input tokens are copied before any host clock anchors a relative lifetime;
|
|
196
203
|
clock mutation cannot replace the selected access/refresh/scope values. Invalid
|
|
197
|
-
expiry values fail before authorization.
|
|
204
|
+
expiry values fail before authorization. Relative-lifetime clock anchors must
|
|
205
|
+
also be valid epoch milliseconds; adding the lifetime cannot make an invalid
|
|
206
|
+
issuance clock acceptable. This applies to raw-grant parsing and token responses.
|
|
198
207
|
For a raw OAuth response, `parseOAuthTokenGrant(response, { issuedAt, expiresAt })`
|
|
199
208
|
returns normalized `StoredOAuthTokens`. Timing options are captured before the
|
|
200
209
|
host clock runs, so it cannot bypass their earlier validation. The parser accepts
|
|
@@ -172,6 +172,11 @@ export function createDefaultOAuthClientProvider(options) {
|
|
|
172
172
|
};
|
|
173
173
|
async function ensureAuthorizedSession(resource, discovery, fetch, allowInteractive, forceRefresh = false, signal, rejectedTokens) {
|
|
174
174
|
signal?.throwIfAborted();
|
|
175
|
+
if (discovery !== undefined) {
|
|
176
|
+
if (getOwnString(discovery.authorizationServerMetadata, "issuer") !== discovery.authorizationServer)
|
|
177
|
+
throw new Error("OAuth discovery authorization-server issuer mismatch");
|
|
178
|
+
assertSecureOAuthFlowEndpoints(discovery.authorizationServerMetadata);
|
|
179
|
+
}
|
|
175
180
|
const canonicalResource = canonicalizeResourceIndicator(resource);
|
|
176
181
|
return withOAuthSessionTransaction(sessionStore, canonicalResource, async () => {
|
|
177
182
|
let session = await loadSession(canonicalResource);
|
|
@@ -187,9 +192,6 @@ export function createDefaultOAuthClientProvider(options) {
|
|
|
187
192
|
if (session !== null && initialGrant?.resource === canonicalResource)
|
|
188
193
|
initialGrantConsumed = true;
|
|
189
194
|
signal?.throwIfAborted();
|
|
190
|
-
if (discovery !== undefined && getOwnString(discovery.authorizationServerMetadata, "issuer") !== discovery.authorizationServer) {
|
|
191
|
-
throw new Error("OAuth discovery authorization-server issuer mismatch");
|
|
192
|
-
}
|
|
193
195
|
if (session !== null && (canonicalizeResourceIndicator(session.resource) !== canonicalResource
|
|
194
196
|
|| getOwnString(session.discovery.authorizationServerMetadata, "issuer") !== session.authorizationServer
|
|
195
197
|
|| (discovery !== undefined && discovery.authorizationServer !== session.authorizationServer))) {
|
|
@@ -198,7 +200,6 @@ export function createDefaultOAuthClientProvider(options) {
|
|
|
198
200
|
}
|
|
199
201
|
if (session === null && discovery !== undefined && !initialGrantConsumed && initialGrant?.resource === canonicalResource &&
|
|
200
202
|
initialGrant.tokens !== undefined && initialGrant.client !== null) {
|
|
201
|
-
assertSecureOAuthFlowEndpoints(discovery.authorizationServerMetadata);
|
|
202
203
|
session = { resource: canonicalResource, authorizationServer: discovery.authorizationServer,
|
|
203
204
|
client: initialGrant.client, tokens: initialGrant.tokens,
|
|
204
205
|
...(requestedScope === undefined ? {} : { requestedScope }), discovery: toStoredDiscovery(discovery) };
|
|
@@ -766,14 +767,17 @@ function assertSecureUrl(value, label) {
|
|
|
766
767
|
throw new Error(`${label} must not include credentials or fragment`);
|
|
767
768
|
}
|
|
768
769
|
if (url.protocol === "https:") {
|
|
769
|
-
return;
|
|
770
|
+
return url;
|
|
770
771
|
}
|
|
771
772
|
if (url.protocol === "http:" && isLoopbackHostname(url.hostname)) {
|
|
772
|
-
return;
|
|
773
|
+
return url;
|
|
773
774
|
}
|
|
774
775
|
throw new Error(`${label} must use https unless it targets a loopback host`);
|
|
775
776
|
}
|
|
776
777
|
function assertSecureOAuthFlowEndpoints(metadata) {
|
|
778
|
+
const issuer = assertSecureUrl(requireOwnString(metadata, "issuer", "Authorization server metadata"), "Authorization server issuer");
|
|
779
|
+
if (issuer.href.includes("?"))
|
|
780
|
+
throw new Error("Authorization server issuer must not include query or fragment");
|
|
777
781
|
const authorizationEndpoint = requireOwnString(metadata, "authorization_endpoint", "Authorization server metadata");
|
|
778
782
|
const tokenEndpoint = requireOwnString(metadata, "token_endpoint", "Authorization server metadata");
|
|
779
783
|
const registrationEndpoint = getOwnString(metadata, "registration_endpoint");
|
package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/resource-bound-store.js
CHANGED
|
@@ -18,7 +18,7 @@ export function createResourceBoundOAuthStores(options, namespace, identity) {
|
|
|
18
18
|
catch {
|
|
19
19
|
throw new Error("OAuth reset resource must be an absolute HTTP URL");
|
|
20
20
|
}
|
|
21
|
-
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.
|
|
21
|
+
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.href.includes("#"))
|
|
22
22
|
throw new Error("OAuth reset resource must be an HTTP URL without credentials or fragment");
|
|
23
23
|
await replace({ version: 1, resource: canonicalizeResourceIndicator(url), generation: 1, session: null, clients: {} }, options);
|
|
24
24
|
},
|
|
@@ -28,11 +28,12 @@ export function createResourceBoundOAuthStores(options, namespace, identity) {
|
|
|
28
28
|
try {
|
|
29
29
|
if (!isStoredOAuthSession(session) || session.tokens === undefined || session.refreshState !== undefined)
|
|
30
30
|
throw new Error("Invalid session");
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
if (typeof session.discovery.resourceMetadata.resource !== "string")
|
|
32
|
+
throw new Error("Invalid resource metadata");
|
|
33
|
+
const resource = new URL(session.resource), issuer = new URL(session.authorizationServer), advertisedResource = new URL(session.discovery.resourceMetadata.resource);
|
|
34
|
+
if ([resource, issuer, advertisedResource].some(url => !["http:", "https:"].includes(url.protocol) || url.username || url.password || url.href.includes("#")) ||
|
|
35
|
+
issuer.href.includes("?") || session.discovery.authorizationServerMetadata.issuer !== session.authorizationServer ||
|
|
36
|
+
canonicalizeResourceIndicator(advertisedResource) !== canonicalizeResourceIndicator(resource))
|
|
36
37
|
throw new Error("Invalid binding");
|
|
37
38
|
session.client = normalizeStoredOAuthClient(session.client);
|
|
38
39
|
if (session.client.registration !== undefined)
|
|
@@ -92,7 +93,7 @@ export function createResourceBoundOAuthStores(options, namespace, identity) {
|
|
|
92
93
|
catch {
|
|
93
94
|
throw new Error("Invalid stored OAuth resource identity URL");
|
|
94
95
|
}
|
|
95
|
-
if (!["http:", "https:"].includes(resourceUrl.protocol) || resourceUrl.username || resourceUrl.password || resourceUrl.
|
|
96
|
+
if (!["http:", "https:"].includes(resourceUrl.protocol) || resourceUrl.username || resourceUrl.password || resourceUrl.href.includes("#"))
|
|
96
97
|
throw new Error("Invalid stored OAuth resource identity URL");
|
|
97
98
|
for (const [issuer, client] of Object.entries(record.clients)) {
|
|
98
99
|
const normalized = normalizeStoredOAuthClient(client);
|
|
@@ -103,7 +104,7 @@ export function createResourceBoundOAuthStores(options, namespace, identity) {
|
|
|
103
104
|
catch {
|
|
104
105
|
throw new Error("Invalid stored OAuth resource client issuer");
|
|
105
106
|
}
|
|
106
|
-
if (normalized === null || !["http:", "https:"].includes(url.protocol) || url.username || url.password || url.
|
|
107
|
+
if (normalized === null || !["http:", "https:"].includes(url.protocol) || url.username || url.password || url.href.includes("?") || url.href.includes("#"))
|
|
107
108
|
throw new Error("Invalid stored OAuth resource client");
|
|
108
109
|
Object.defineProperty(record.clients, issuer, { value: normalized, enumerable: true, configurable: true, writable: true });
|
|
109
110
|
}
|
package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/token-endpoint.js
CHANGED
|
@@ -130,7 +130,10 @@ async function requestTokens(input) {
|
|
|
130
130
|
expiresIn < 0) {
|
|
131
131
|
throw new Error("OAuth token response has invalid expires_in");
|
|
132
132
|
}
|
|
133
|
-
|
|
133
|
+
const issuedAt = input.now();
|
|
134
|
+
if (!Number.isSafeInteger(issuedAt) || Math.abs(issuedAt) > MAX_JS_DATE_MS)
|
|
135
|
+
throw new Error("OAuth token response has invalid expires_in");
|
|
136
|
+
expiresAt = issuedAt + expiresIn * 1000;
|
|
134
137
|
if (!Number.isSafeInteger(expiresAt) ||
|
|
135
138
|
expiresAt > MAX_JS_DATE_MS ||
|
|
136
139
|
!Number.isFinite(new Date(expiresAt).getTime())) {
|
|
@@ -34,7 +34,10 @@ export function parseOAuthTokenGrant(value, options = {}) {
|
|
|
34
34
|
const absoluteSeconds = typeof seconds === "number" ? seconds * 1000 : undefined;
|
|
35
35
|
if (absoluteSeconds !== undefined && !validTimestamp(absoluteSeconds))
|
|
36
36
|
throw invalid();
|
|
37
|
-
const
|
|
37
|
+
const anchor = typeof lifetime === "number" ? options.issuedAt ?? (options.now ?? Date.now)() : undefined;
|
|
38
|
+
if (typeof lifetime === "number" && !validTimestamp(anchor))
|
|
39
|
+
throw invalid();
|
|
40
|
+
const relative = typeof lifetime === "number" ? anchor + lifetime * 1000 : undefined;
|
|
38
41
|
if (relative !== undefined && !validTimestamp(relative))
|
|
39
42
|
throw invalid();
|
|
40
43
|
const expiresAt = options.expiresAt ?? (typeof milliseconds === "number" ? milliseconds : undefined) ?? absoluteSeconds ?? relative ?? null;
|
|
@@ -63,6 +63,11 @@ embedded credentials or fragments; endpoint changes close the connection.
|
|
|
63
63
|
Empty fragment delimiters are rejected too; escaped hashes in an endpoint path
|
|
64
64
|
or query remain literal data.
|
|
65
65
|
Both transports accept the same headers, OAuth provider and response limits.
|
|
66
|
+
The original HTTP transport target must be an absolute HTTP/HTTPS URL without
|
|
67
|
+
credentials or a fragment, including an empty trailing `#`. Invalid targets fail
|
|
68
|
+
before OAuth provider construction or clock reads. Empty queries and escaped
|
|
69
|
+
path/query delimiters remain valid; accepted target strings keep their spelling.
|
|
70
|
+
|
|
66
71
|
Static HTTP headers are copied and validated when the transport is constructed,
|
|
67
72
|
before OAuth callbacks run. Invalid headers fail without reflecting their values.
|
|
68
73
|
Use `snapshotHttpTransportHeaders(headers)` to apply the same ownership and safe
|
|
@@ -4801,7 +4801,7 @@ function createResourceBoundOAuthStores(options, namespace, identity) {
|
|
|
4801
4801
|
} catch {
|
|
4802
4802
|
throw new Error("OAuth reset resource must be an absolute HTTP URL");
|
|
4803
4803
|
}
|
|
4804
|
-
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.
|
|
4804
|
+
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.href.includes("#"))
|
|
4805
4805
|
throw new Error("OAuth reset resource must be an HTTP URL without credentials or fragment");
|
|
4806
4806
|
await replace({ version: 1, resource: canonicalizeResourceIndicator(url), generation: 1, session: null, clients: {} }, options2);
|
|
4807
4807
|
},
|
|
@@ -4811,8 +4811,10 @@ function createResourceBoundOAuthStores(options, namespace, identity) {
|
|
|
4811
4811
|
try {
|
|
4812
4812
|
if (!isStoredOAuthSession(session) || session.tokens === void 0 || session.refreshState !== void 0)
|
|
4813
4813
|
throw new Error("Invalid session");
|
|
4814
|
-
|
|
4815
|
-
|
|
4814
|
+
if (typeof session.discovery.resourceMetadata.resource !== "string")
|
|
4815
|
+
throw new Error("Invalid resource metadata");
|
|
4816
|
+
const resource = new URL(session.resource), issuer = new URL(session.authorizationServer), advertisedResource = new URL(session.discovery.resourceMetadata.resource);
|
|
4817
|
+
if ([resource, issuer, advertisedResource].some((url) => !["http:", "https:"].includes(url.protocol) || url.username || url.password || url.href.includes("#")) || issuer.href.includes("?") || session.discovery.authorizationServerMetadata.issuer !== session.authorizationServer || canonicalizeResourceIndicator(advertisedResource) !== canonicalizeResourceIndicator(resource))
|
|
4816
4818
|
throw new Error("Invalid binding");
|
|
4817
4819
|
session.client = normalizeStoredOAuthClient(session.client);
|
|
4818
4820
|
if (session.client.registration !== void 0)
|
|
@@ -4868,7 +4870,7 @@ function createResourceBoundOAuthStores(options, namespace, identity) {
|
|
|
4868
4870
|
} catch {
|
|
4869
4871
|
throw new Error("Invalid stored OAuth resource identity URL");
|
|
4870
4872
|
}
|
|
4871
|
-
if (!["http:", "https:"].includes(resourceUrl.protocol) || resourceUrl.username || resourceUrl.password || resourceUrl.
|
|
4873
|
+
if (!["http:", "https:"].includes(resourceUrl.protocol) || resourceUrl.username || resourceUrl.password || resourceUrl.href.includes("#"))
|
|
4872
4874
|
throw new Error("Invalid stored OAuth resource identity URL");
|
|
4873
4875
|
for (const [issuer, client] of Object.entries(record2.clients)) {
|
|
4874
4876
|
const normalized = normalizeStoredOAuthClient(client);
|
|
@@ -4878,7 +4880,7 @@ function createResourceBoundOAuthStores(options, namespace, identity) {
|
|
|
4878
4880
|
} catch {
|
|
4879
4881
|
throw new Error("Invalid stored OAuth resource client issuer");
|
|
4880
4882
|
}
|
|
4881
|
-
if (normalized === null || !["http:", "https:"].includes(url.protocol) || url.username || url.password || url.
|
|
4883
|
+
if (normalized === null || !["http:", "https:"].includes(url.protocol) || url.username || url.password || url.href.includes("?") || url.href.includes("#"))
|
|
4882
4884
|
throw new Error("Invalid stored OAuth resource client");
|
|
4883
4885
|
Object.defineProperty(record2.clients, issuer, { value: normalized, enumerable: true, configurable: true, writable: true });
|
|
4884
4886
|
}
|
|
@@ -5178,7 +5180,10 @@ async function requestTokens(input) {
|
|
|
5178
5180
|
if (typeof expiresIn !== "number" || !Number.isFinite(expiresIn) || !Number.isInteger(expiresIn) || expiresIn < 0) {
|
|
5179
5181
|
throw new Error("OAuth token response has invalid expires_in");
|
|
5180
5182
|
}
|
|
5181
|
-
|
|
5183
|
+
const issuedAt = input.now();
|
|
5184
|
+
if (!Number.isSafeInteger(issuedAt) || Math.abs(issuedAt) > MAX_JS_DATE_MS2)
|
|
5185
|
+
throw new Error("OAuth token response has invalid expires_in");
|
|
5186
|
+
expiresAt = issuedAt + expiresIn * 1e3;
|
|
5182
5187
|
if (!Number.isSafeInteger(expiresAt) || expiresAt > MAX_JS_DATE_MS2 || !Number.isFinite(new Date(expiresAt).getTime())) {
|
|
5183
5188
|
throw new Error("OAuth token response has invalid expires_in");
|
|
5184
5189
|
}
|
|
@@ -5462,6 +5467,11 @@ function createDefaultOAuthClientProvider(options) {
|
|
|
5462
5467
|
};
|
|
5463
5468
|
async function ensureAuthorizedSession(resource, discovery, fetch2, allowInteractive, forceRefresh = false, signal, rejectedTokens) {
|
|
5464
5469
|
signal?.throwIfAborted();
|
|
5470
|
+
if (discovery !== void 0) {
|
|
5471
|
+
if (getOwnString2(discovery.authorizationServerMetadata, "issuer") !== discovery.authorizationServer)
|
|
5472
|
+
throw new Error("OAuth discovery authorization-server issuer mismatch");
|
|
5473
|
+
assertSecureOAuthFlowEndpoints(discovery.authorizationServerMetadata);
|
|
5474
|
+
}
|
|
5465
5475
|
const canonicalResource = canonicalizeResourceIndicator(resource);
|
|
5466
5476
|
return withOAuthSessionTransaction(sessionStore, canonicalResource, async () => {
|
|
5467
5477
|
let session = await loadSession(canonicalResource);
|
|
@@ -5477,15 +5487,11 @@ function createDefaultOAuthClientProvider(options) {
|
|
|
5477
5487
|
if (session !== null && initialGrant?.resource === canonicalResource)
|
|
5478
5488
|
initialGrantConsumed = true;
|
|
5479
5489
|
signal?.throwIfAborted();
|
|
5480
|
-
if (discovery !== void 0 && getOwnString2(discovery.authorizationServerMetadata, "issuer") !== discovery.authorizationServer) {
|
|
5481
|
-
throw new Error("OAuth discovery authorization-server issuer mismatch");
|
|
5482
|
-
}
|
|
5483
5490
|
if (session !== null && (canonicalizeResourceIndicator(session.resource) !== canonicalResource || getOwnString2(session.discovery.authorizationServerMetadata, "issuer") !== session.authorizationServer || discovery !== void 0 && discovery.authorizationServer !== session.authorizationServer)) {
|
|
5484
5491
|
await clearSession(canonicalResource);
|
|
5485
5492
|
session = null;
|
|
5486
5493
|
}
|
|
5487
5494
|
if (session === null && discovery !== void 0 && !initialGrantConsumed && initialGrant?.resource === canonicalResource && initialGrant.tokens !== void 0 && initialGrant.client !== null) {
|
|
5488
|
-
assertSecureOAuthFlowEndpoints(discovery.authorizationServerMetadata);
|
|
5489
5495
|
session = {
|
|
5490
5496
|
resource: canonicalResource,
|
|
5491
5497
|
authorizationServer: discovery.authorizationServer,
|
|
@@ -6021,14 +6027,17 @@ function assertSecureUrl(value, label) {
|
|
|
6021
6027
|
throw new Error(`${label} must not include credentials or fragment`);
|
|
6022
6028
|
}
|
|
6023
6029
|
if (url.protocol === "https:") {
|
|
6024
|
-
return;
|
|
6030
|
+
return url;
|
|
6025
6031
|
}
|
|
6026
6032
|
if (url.protocol === "http:" && isLoopbackHostname(url.hostname)) {
|
|
6027
|
-
return;
|
|
6033
|
+
return url;
|
|
6028
6034
|
}
|
|
6029
6035
|
throw new Error(`${label} must use https unless it targets a loopback host`);
|
|
6030
6036
|
}
|
|
6031
6037
|
function assertSecureOAuthFlowEndpoints(metadata) {
|
|
6038
|
+
const issuer = assertSecureUrl(requireOwnString(metadata, "issuer", "Authorization server metadata"), "Authorization server issuer");
|
|
6039
|
+
if (issuer.href.includes("?"))
|
|
6040
|
+
throw new Error("Authorization server issuer must not include query or fragment");
|
|
6032
6041
|
const authorizationEndpoint = requireOwnString(metadata, "authorization_endpoint", "Authorization server metadata");
|
|
6033
6042
|
const tokenEndpoint = requireOwnString(metadata, "token_endpoint", "Authorization server metadata");
|
|
6034
6043
|
const registrationEndpoint = getOwnString2(metadata, "registration_endpoint");
|
|
@@ -7747,6 +7756,13 @@ var HttpTransport = class {
|
|
|
7747
7756
|
}) {
|
|
7748
7757
|
if (!Number.isSafeInteger(maxResponseBytes) || maxResponseBytes < 1)
|
|
7749
7758
|
throw new Error("HTTP response byte limit must be a positive safe integer");
|
|
7759
|
+
try {
|
|
7760
|
+
const target = new URL(url);
|
|
7761
|
+
if (!["http:", "https:"].includes(target.protocol) || target.username || target.password || target.href.includes("#"))
|
|
7762
|
+
throw new Error("Invalid HTTP transport target");
|
|
7763
|
+
} catch {
|
|
7764
|
+
throw new Error("HTTP transport URL must be an absolute HTTP URL without credentials or fragment");
|
|
7765
|
+
}
|
|
7750
7766
|
this.maxResponseBytes = maxResponseBytes;
|
|
7751
7767
|
this.url = url;
|
|
7752
7768
|
this.mode = mode;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolcraft",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.351",
|
|
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.351",
|
|
162
162
|
"toolcraft-design": "*",
|
|
163
163
|
"@poe-code/frontmatter": "*",
|
|
164
164
|
"@poe-code/agent-mcp-config": "*",
|