poe-code 3.0.435 → 3.0.437
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/package.json
CHANGED
|
@@ -242,7 +242,9 @@ export function createHttpServer(options) {
|
|
|
242
242
|
};
|
|
243
243
|
};
|
|
244
244
|
httpServer.handleRequest = async (req, res) => {
|
|
245
|
-
|
|
245
|
+
const { baseUrl } = req;
|
|
246
|
+
const protectedResourcePath = typeof baseUrl === "string" && baseUrl.length > 0 ? baseUrl : "/mcp";
|
|
247
|
+
if (!(await authorizeHttpRequest(req, res, protectedResourcePath))) {
|
|
246
248
|
return;
|
|
247
249
|
}
|
|
248
250
|
await transport.handleRequest(req, res);
|
|
@@ -14,6 +14,7 @@ export type HttpObservabilityEvent = {
|
|
|
14
14
|
statusCode: number;
|
|
15
15
|
durationMs: number;
|
|
16
16
|
sessionId?: string;
|
|
17
|
+
reason?: string;
|
|
17
18
|
} | {
|
|
18
19
|
type: "request.error";
|
|
19
20
|
requestId: string;
|
|
@@ -103,6 +104,7 @@ export declare class StreamableHttpTransport {
|
|
|
103
104
|
private readonly sseEventHistory;
|
|
104
105
|
private readonly responseRequestIds;
|
|
105
106
|
private readonly responseOrigins;
|
|
107
|
+
private readonly responseRejectionReasons;
|
|
106
108
|
private nextNotificationEventId;
|
|
107
109
|
private nextRequestId;
|
|
108
110
|
private activeToolCalls;
|
|
@@ -154,6 +156,7 @@ export declare class StreamableHttpTransport {
|
|
|
154
156
|
private isRequest;
|
|
155
157
|
private isToolCallOk;
|
|
156
158
|
private respondWithJsonRpcError;
|
|
159
|
+
private respondWithRejection;
|
|
157
160
|
private respondWithStatus;
|
|
158
161
|
private withSessionHeader;
|
|
159
162
|
private emit;
|
|
@@ -43,6 +43,7 @@ export class StreamableHttpTransport {
|
|
|
43
43
|
sseEventHistory = new Map();
|
|
44
44
|
responseRequestIds = new WeakMap();
|
|
45
45
|
responseOrigins = new WeakMap();
|
|
46
|
+
responseRejectionReasons = new WeakMap();
|
|
46
47
|
nextNotificationEventId = 1;
|
|
47
48
|
nextRequestId = 1;
|
|
48
49
|
activeToolCalls = 0;
|
|
@@ -105,11 +106,15 @@ export class StreamableHttpTransport {
|
|
|
105
106
|
});
|
|
106
107
|
try {
|
|
107
108
|
if (this.closed) {
|
|
108
|
-
this.
|
|
109
|
+
this.respondWithRejection(res, 503, "transport_closed", "The transport is closed; create or use an active transport.");
|
|
109
110
|
return;
|
|
110
111
|
}
|
|
111
|
-
if (!this.acceptsHost(req)
|
|
112
|
-
this.
|
|
112
|
+
if (!this.acceptsHost(req)) {
|
|
113
|
+
this.respondWithRejection(res, 403, "host_not_allowed", `Host ${JSON.stringify(this.readRequestHost(req))} is not allowed; add it to allowedHosts.`);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (!this.acceptsOrigin(req)) {
|
|
117
|
+
this.respondWithRejection(res, 403, "origin_not_allowed", `Origin ${JSON.stringify(this.readOrigin(req) ?? "")} is not allowed; add it to allowedOrigins.`);
|
|
113
118
|
return;
|
|
114
119
|
}
|
|
115
120
|
switch (req.method) {
|
|
@@ -155,7 +160,10 @@ export class StreamableHttpTransport {
|
|
|
155
160
|
method: req.method ?? "",
|
|
156
161
|
statusCode: res.statusCode,
|
|
157
162
|
durationMs: Date.now() - startedAt,
|
|
158
|
-
sessionId: this.readSessionId(req)
|
|
163
|
+
sessionId: this.readSessionId(req),
|
|
164
|
+
...(res.statusCode < 200 || res.statusCode >= 300
|
|
165
|
+
? { reason: this.responseRejectionReasons.get(res) ?? "http_error" }
|
|
166
|
+
: {})
|
|
159
167
|
});
|
|
160
168
|
}
|
|
161
169
|
}
|
|
@@ -184,7 +192,8 @@ export class StreamableHttpTransport {
|
|
|
184
192
|
return;
|
|
185
193
|
}
|
|
186
194
|
if (!this.acceptsConfiguredResponse(req)) {
|
|
187
|
-
this.
|
|
195
|
+
const expectedType = this.enableJsonResponse ? "application/json" : "text/event-stream";
|
|
196
|
+
this.respondWithRejection(res, 406, "response_type_not_acceptable", `Accept must allow ${expectedType}.`);
|
|
188
197
|
return;
|
|
189
198
|
}
|
|
190
199
|
let classified;
|
|
@@ -216,11 +225,11 @@ export class StreamableHttpTransport {
|
|
|
216
225
|
const headerSessionId = this.readSessionId(req);
|
|
217
226
|
if (headerSessionId === undefined) {
|
|
218
227
|
if (initMessage === undefined) {
|
|
219
|
-
this.
|
|
228
|
+
this.respondWithRejection(res, 400, "session_id_required", "Mcp-Session-Id is required; initialize a session first.");
|
|
220
229
|
return;
|
|
221
230
|
}
|
|
222
231
|
if (this.maxSessions !== undefined && this.sessionCount() >= this.maxSessions) {
|
|
223
|
-
this.
|
|
232
|
+
this.respondWithRejection(res, 503, "session_limit_reached", "The server has reached its session limit; close a session or retry later.");
|
|
224
233
|
return;
|
|
225
234
|
}
|
|
226
235
|
const newSessionId = this.sessionIdGenerator();
|
|
@@ -240,14 +249,14 @@ export class StreamableHttpTransport {
|
|
|
240
249
|
else {
|
|
241
250
|
activeSession = this.getActiveSession(headerSessionId, req);
|
|
242
251
|
if (activeSession === undefined) {
|
|
243
|
-
this.
|
|
252
|
+
this.respondWithRejection(res, 404, "session_not_found", "Session was not found or has expired; reinitialize the session.");
|
|
244
253
|
return;
|
|
245
254
|
}
|
|
246
255
|
sessionId = headerSessionId;
|
|
247
256
|
this.touchSession(sessionId);
|
|
248
257
|
if (activeSession.protocolVersion !== undefined &&
|
|
249
258
|
!this.acceptsProtocolVersion(req, activeSession.protocolVersion)) {
|
|
250
|
-
this.
|
|
259
|
+
this.respondWithRejection(res, 400, "protocol_version_mismatch", `MCP-Protocol-Version must match the session protocol version ${activeSession.protocolVersion}.`);
|
|
251
260
|
return;
|
|
252
261
|
}
|
|
253
262
|
await this.ensureLocalMessageSession(sessionId, activeSession);
|
|
@@ -377,30 +386,30 @@ export class StreamableHttpTransport {
|
|
|
377
386
|
return;
|
|
378
387
|
}
|
|
379
388
|
if (!this.acceptsResponseType(req, "text/event-stream")) {
|
|
380
|
-
this.
|
|
389
|
+
this.respondWithRejection(res, 406, "response_type_not_acceptable", "Accept must allow text/event-stream.");
|
|
381
390
|
return;
|
|
382
391
|
}
|
|
383
392
|
const sessionId = this.readSessionId(req);
|
|
384
393
|
if (sessionId === undefined) {
|
|
385
|
-
this.
|
|
394
|
+
this.respondWithRejection(res, 400, "session_id_required", "Mcp-Session-Id is required; initialize a session first.");
|
|
386
395
|
return;
|
|
387
396
|
}
|
|
388
397
|
const session = this.getActiveSession(sessionId, req);
|
|
389
398
|
if (session === undefined) {
|
|
390
|
-
this.
|
|
399
|
+
this.respondWithRejection(res, 404, "session_not_found", "Session was not found or has expired; reinitialize the session.");
|
|
391
400
|
return;
|
|
392
401
|
}
|
|
393
402
|
this.touchSession(sessionId);
|
|
394
403
|
if (session.initialized &&
|
|
395
404
|
session.protocolVersion !== undefined &&
|
|
396
405
|
!this.acceptsProtocolVersion(req, session.protocolVersion)) {
|
|
397
|
-
this.
|
|
406
|
+
this.respondWithRejection(res, 400, "protocol_version_mismatch", `MCP-Protocol-Version must match the session protocol version ${session.protocolVersion}.`);
|
|
398
407
|
return;
|
|
399
408
|
}
|
|
400
409
|
await this.ensureLocalMessageSession(sessionId, session);
|
|
401
410
|
const existingStreams = this.sseStreams.get(sessionId);
|
|
402
411
|
if ((existingStreams?.size ?? 0) >= this.maxStreamsPerSession) {
|
|
403
|
-
this.
|
|
412
|
+
this.respondWithRejection(res, 409, "stream_limit_reached", "This session already has the maximum number of streams; close a stream and retry.");
|
|
404
413
|
return;
|
|
405
414
|
}
|
|
406
415
|
let streams = this.sseStreams.get(sessionId);
|
|
@@ -454,21 +463,21 @@ export class StreamableHttpTransport {
|
|
|
454
463
|
}
|
|
455
464
|
const sessionId = this.readSessionId(req);
|
|
456
465
|
if (sessionId === undefined) {
|
|
457
|
-
this.
|
|
466
|
+
this.respondWithRejection(res, 400, "session_id_required", "Mcp-Session-Id is required; initialize a session first.");
|
|
458
467
|
return;
|
|
459
468
|
}
|
|
460
469
|
const session = this.getActiveSession(sessionId, req);
|
|
461
470
|
if (session === undefined) {
|
|
462
|
-
this.
|
|
471
|
+
this.respondWithRejection(res, 404, "session_not_found", "Session was not found or has expired; reinitialize the session.");
|
|
463
472
|
return;
|
|
464
473
|
}
|
|
465
474
|
if (session.protocolVersion !== undefined &&
|
|
466
475
|
!this.acceptsProtocolVersion(req, session.protocolVersion)) {
|
|
467
|
-
this.
|
|
476
|
+
this.respondWithRejection(res, 400, "protocol_version_mismatch", `MCP-Protocol-Version must match the session protocol version ${session.protocolVersion}.`);
|
|
468
477
|
return;
|
|
469
478
|
}
|
|
470
479
|
if (!this.deleteSession(sessionId, "client")) {
|
|
471
|
-
this.
|
|
480
|
+
this.respondWithRejection(res, 404, "session_not_found", "Session was not found or has expired; reinitialize the session.");
|
|
472
481
|
return;
|
|
473
482
|
}
|
|
474
483
|
this.respondWithStatus(res, 204);
|
|
@@ -841,8 +850,13 @@ export class StreamableHttpTransport {
|
|
|
841
850
|
return !(hasOwnProperty(result, "isError") && result.isError === true);
|
|
842
851
|
}
|
|
843
852
|
respondWithJsonRpcError(res, statusCode, errorCode, message, id = null) {
|
|
853
|
+
this.responseRejectionReasons.set(res, "json_rpc_error");
|
|
844
854
|
this.respondWithStatus(res, statusCode, undefined, { "Content-Type": "application/json" }, formatErrorResponse(id, { code: errorCode, message }));
|
|
845
855
|
}
|
|
856
|
+
respondWithRejection(res, statusCode, reason, message) {
|
|
857
|
+
this.responseRejectionReasons.set(res, reason);
|
|
858
|
+
this.respondWithStatus(res, statusCode, undefined, { "Content-Type": "application/json" }, JSON.stringify({ error: reason, message }));
|
|
859
|
+
}
|
|
846
860
|
respondWithStatus(res, statusCode, sessionId, headers, body) {
|
|
847
861
|
res.writeHead(statusCode, this.withSessionHeader(headers, sessionId, res));
|
|
848
862
|
res.end(body);
|