poe-code 3.0.301 → 3.0.302
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/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/packages/tiny-http-mcp-server/dist/auth.js +22 -2
- package/packages/tiny-http-mcp-server/dist/cli.js +38 -14
- package/packages/tiny-http-mcp-server/dist/http-transport.d.ts +1 -0
- package/packages/tiny-http-mcp-server/dist/http-transport.js +25 -8
package/package.json
CHANGED
|
@@ -66,6 +66,19 @@ function formatScope(scope) {
|
|
|
66
66
|
}
|
|
67
67
|
return scope.join(" ");
|
|
68
68
|
}
|
|
69
|
+
function hasBearerTokenWhitespace(value) {
|
|
70
|
+
for (const character of value) {
|
|
71
|
+
if (character === " "
|
|
72
|
+
|| character === "\t"
|
|
73
|
+
|| character === "\n"
|
|
74
|
+
|| character === "\r"
|
|
75
|
+
|| character === "\f"
|
|
76
|
+
|| character === "\v") {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
69
82
|
function readBearerToken(req) {
|
|
70
83
|
const authorization = readSingleHeaderValue(req.headers.authorization);
|
|
71
84
|
if (authorization === undefined || authorization.length === 0) {
|
|
@@ -80,7 +93,7 @@ function readBearerToken(req) {
|
|
|
80
93
|
}
|
|
81
94
|
const scheme = authorization.slice(0, separatorIndex);
|
|
82
95
|
const token = authorization.slice(separatorIndex + 1).trim();
|
|
83
|
-
if (scheme.toLowerCase() !== "bearer" || token.length === 0 || token
|
|
96
|
+
if (scheme.toLowerCase() !== "bearer" || token.length === 0 || hasBearerTokenWhitespace(token)) {
|
|
84
97
|
return {
|
|
85
98
|
kind: "malformed",
|
|
86
99
|
errorDescription: "malformed bearer token",
|
|
@@ -153,7 +166,14 @@ function toRequestAuthInfo(verifiedToken, resource) {
|
|
|
153
166
|
};
|
|
154
167
|
}
|
|
155
168
|
export function getProtectedResourceMetadataUrl(req, protectedResourcePath, trustedProxy = false) {
|
|
156
|
-
|
|
169
|
+
const path = `${PROTECTED_RESOURCE_METADATA_PATH}${normalizeProtectedResourcePath(protectedResourcePath)}`;
|
|
170
|
+
const protocol = getRequestProtocol(req, trustedProxy);
|
|
171
|
+
try {
|
|
172
|
+
return new URL(path, `${protocol}://${getRequestHost(req, trustedProxy)}`).toString();
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return new URL(path, `${protocol}://127.0.0.1`).toString();
|
|
176
|
+
}
|
|
157
177
|
}
|
|
158
178
|
export function createBearerChallenge(req, options = {}, protectedResourcePath, trustedProxy = false) {
|
|
159
179
|
const parts = [
|
|
@@ -73,7 +73,7 @@ function parsePort(value) {
|
|
|
73
73
|
if (value === undefined) {
|
|
74
74
|
return 3000;
|
|
75
75
|
}
|
|
76
|
-
const port =
|
|
76
|
+
const port = parseDecimalInteger(value, "--port");
|
|
77
77
|
if (!Number.isInteger(port) || port < 0 || port > 65535) {
|
|
78
78
|
throw new Error("--port must be an integer between 0 and 65535.");
|
|
79
79
|
}
|
|
@@ -95,11 +95,24 @@ function parseOrigin(value, flagName) {
|
|
|
95
95
|
throw new Error(`${flagName} must be an absolute URL.`);
|
|
96
96
|
}
|
|
97
97
|
}
|
|
98
|
+
function parseDecimalInteger(value, flagName) {
|
|
99
|
+
const trimmed = value.trim();
|
|
100
|
+
if (trimmed.length === 0) {
|
|
101
|
+
throw new Error(`${flagName} must be an integer.`);
|
|
102
|
+
}
|
|
103
|
+
for (const character of trimmed) {
|
|
104
|
+
const codePoint = character.codePointAt(0);
|
|
105
|
+
if (codePoint === undefined || codePoint < 48 || codePoint > 57) {
|
|
106
|
+
throw new Error(`${flagName} must be an integer.`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return Number(trimmed);
|
|
110
|
+
}
|
|
98
111
|
function parseOptionalInteger(value, flagName, minimum) {
|
|
99
112
|
if (value === undefined) {
|
|
100
113
|
return undefined;
|
|
101
114
|
}
|
|
102
|
-
const parsed =
|
|
115
|
+
const parsed = parseDecimalInteger(value, flagName);
|
|
103
116
|
if (!Number.isInteger(parsed) || parsed < minimum) {
|
|
104
117
|
throw new Error(`${flagName} must be an integer greater than or equal to ${minimum}.`);
|
|
105
118
|
}
|
|
@@ -116,6 +129,23 @@ function hasConfiguredOAuthFlag(values) {
|
|
|
116
129
|
values["oauth-verifier-export"],
|
|
117
130
|
].some((value) => value !== undefined);
|
|
118
131
|
}
|
|
132
|
+
function parseRepeatableStrings(value, flagName) {
|
|
133
|
+
if (!Array.isArray(value) || value.length === 0) {
|
|
134
|
+
return undefined;
|
|
135
|
+
}
|
|
136
|
+
const normalized = [];
|
|
137
|
+
for (const item of value) {
|
|
138
|
+
if (typeof item !== "string") {
|
|
139
|
+
throw new Error(`${flagName} must be provided as a string.`);
|
|
140
|
+
}
|
|
141
|
+
const trimmed = item.trim();
|
|
142
|
+
if (trimmed.length === 0) {
|
|
143
|
+
throw new Error(`${flagName} must not be blank.`);
|
|
144
|
+
}
|
|
145
|
+
normalized.push(trimmed);
|
|
146
|
+
}
|
|
147
|
+
return normalized;
|
|
148
|
+
}
|
|
119
149
|
function parseCliOAuthOptions(values) {
|
|
120
150
|
const resource = values["oauth-resource"];
|
|
121
151
|
const authorizationServers = values["oauth-authorization-server"];
|
|
@@ -134,21 +164,15 @@ function parseCliOAuthOptions(values) {
|
|
|
134
164
|
if (typeof verifierModule !== "string" || verifierModule.length === 0) {
|
|
135
165
|
throw new Error("--oauth-verifier-module is required when --oauth-resource is set.");
|
|
136
166
|
}
|
|
137
|
-
const supportedScopes = values["oauth-supported-scope"];
|
|
138
|
-
const requiredScopes = values["oauth-required-scope"];
|
|
139
|
-
const bearerMethods = values["oauth-bearer-method"];
|
|
167
|
+
const supportedScopes = parseRepeatableStrings(values["oauth-supported-scope"], "--oauth-supported-scope");
|
|
168
|
+
const requiredScopes = parseRepeatableStrings(values["oauth-required-scope"], "--oauth-required-scope");
|
|
169
|
+
const bearerMethods = parseRepeatableStrings(values["oauth-bearer-method"], "--oauth-bearer-method");
|
|
140
170
|
return {
|
|
141
171
|
resource: parseAbsoluteUrl(resource, "--oauth-resource"),
|
|
142
172
|
authorizationServers: authorizationServers.map((value) => parseAbsoluteUrl(value, "--oauth-authorization-server")),
|
|
143
|
-
...(
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
...(Array.isArray(supportedScopes) && supportedScopes.length > 0
|
|
147
|
-
? { scopesSupported: [...supportedScopes] }
|
|
148
|
-
: {}),
|
|
149
|
-
...(Array.isArray(bearerMethods) && bearerMethods.length > 0
|
|
150
|
-
? { bearerMethodsSupported: [...bearerMethods] }
|
|
151
|
-
: {}),
|
|
173
|
+
...(requiredScopes === undefined ? {} : { requiredScopes }),
|
|
174
|
+
...(supportedScopes === undefined ? {} : { scopesSupported: supportedScopes }),
|
|
175
|
+
...(bearerMethods === undefined ? {} : { bearerMethodsSupported: bearerMethods }),
|
|
152
176
|
verifierModule,
|
|
153
177
|
verifierExport: typeof verifierExport === "string" && verifierExport.length > 0
|
|
154
178
|
? verifierExport
|
|
@@ -8,6 +8,15 @@ const ALLOWED_METHODS = "POST, GET, DELETE, OPTIONS";
|
|
|
8
8
|
const MCP_SESSION_ID_HEADER = "Mcp-Session-Id";
|
|
9
9
|
const LOCAL_HOSTS = ["localhost", "127.0.0.1", "::1"];
|
|
10
10
|
const DEFAULT_ALLOWED_HEADERS = "Accept, Authorization, Content-Type, Mcp-Session-Id, MCP-Protocol-Version";
|
|
11
|
+
function validateOptionalIntegerOption(name, value, minimum) {
|
|
12
|
+
if (value === undefined) {
|
|
13
|
+
return undefined;
|
|
14
|
+
}
|
|
15
|
+
if (!Number.isInteger(value) || value < minimum) {
|
|
16
|
+
throw new Error(`${name} must be an integer greater than or equal to ${minimum}.`);
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
11
20
|
export class StreamableHttpTransport {
|
|
12
21
|
server;
|
|
13
22
|
runWithRequestContext;
|
|
@@ -44,13 +53,14 @@ export class StreamableHttpTransport {
|
|
|
44
53
|
this.enableJsonResponse = options.enableJsonResponse ?? false;
|
|
45
54
|
this.allowedOrigins = new Set(options.allowedOrigins ?? []);
|
|
46
55
|
this.allowedHosts = new Set((options.allowedHosts ?? LOCAL_HOSTS).map((host) => this.normalizeHost(host)));
|
|
47
|
-
this.maxRequestBytes = options.maxRequestBytes;
|
|
48
|
-
this.maxBatchSize = options.maxBatchSize;
|
|
49
|
-
this.maxSessions = options.maxSessions;
|
|
50
|
-
this.sessionTtlMs = options.sessionTtlMs;
|
|
51
|
-
this.maxStreamsPerSession = options.maxStreamsPerSession;
|
|
52
|
-
this.maxSseEventHistory =
|
|
53
|
-
|
|
56
|
+
this.maxRequestBytes = validateOptionalIntegerOption("maxRequestBytes", options.maxRequestBytes, 1);
|
|
57
|
+
this.maxBatchSize = validateOptionalIntegerOption("maxBatchSize", options.maxBatchSize, 1);
|
|
58
|
+
this.maxSessions = validateOptionalIntegerOption("maxSessions", options.maxSessions, 1);
|
|
59
|
+
this.sessionTtlMs = validateOptionalIntegerOption("sessionTtlMs", options.sessionTtlMs, 1);
|
|
60
|
+
this.maxStreamsPerSession = validateOptionalIntegerOption("maxStreamsPerSession", options.maxStreamsPerSession, 1);
|
|
61
|
+
this.maxSseEventHistory =
|
|
62
|
+
validateOptionalIntegerOption("maxSseEventHistory", options.maxSseEventHistory, 0) ?? 100;
|
|
63
|
+
this.maxConcurrentToolCalls = validateOptionalIntegerOption("maxConcurrentToolCalls", options.maxConcurrentToolCalls, 1);
|
|
54
64
|
this.sessionStore = options.sessionStore ?? createSessionStore();
|
|
55
65
|
this.requestIdGenerator =
|
|
56
66
|
options.requestIdGenerator ?? (() => `req-${this.nextRequestId++}`);
|
|
@@ -328,6 +338,10 @@ export class StreamableHttpTransport {
|
|
|
328
338
|
});
|
|
329
339
|
return;
|
|
330
340
|
}
|
|
341
|
+
if (!this.acceptsResponseType(req, "text/event-stream")) {
|
|
342
|
+
this.respondWithStatus(res, 406);
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
331
345
|
const sessionId = this.readSessionId(req);
|
|
332
346
|
if (sessionId === undefined) {
|
|
333
347
|
this.respondWithStatus(res, 400);
|
|
@@ -673,11 +687,14 @@ export class StreamableHttpTransport {
|
|
|
673
687
|
: normalized;
|
|
674
688
|
}
|
|
675
689
|
acceptsConfiguredResponse(req) {
|
|
690
|
+
const expectedType = this.enableJsonResponse ? "application/json" : "text/event-stream";
|
|
691
|
+
return this.acceptsResponseType(req, expectedType);
|
|
692
|
+
}
|
|
693
|
+
acceptsResponseType(req, expectedType) {
|
|
676
694
|
const accept = req.headers.accept;
|
|
677
695
|
if (accept === undefined) {
|
|
678
696
|
return true;
|
|
679
697
|
}
|
|
680
|
-
const expectedType = this.enableJsonResponse ? "application/json" : "text/event-stream";
|
|
681
698
|
const value = Array.isArray(accept) ? accept.join(",") : accept;
|
|
682
699
|
return value
|
|
683
700
|
.split(",")
|