@cyanheads/jinaai-mcp-server
Version:
A Model Context Protocol (MCP) server that provides intelligent web reading capabilities using the Jina AI Reader API. It extracts clean, LLM-ready content from any URL.
139 lines • 5.25 kB
JavaScript
/**
* @fileoverview Provides a high-fidelity bridge between the MCP SDK's Node.js-style
* streamable HTTP transport and Hono's Web Standards-based streaming response.
* This class is essential for adapting the Node.js `http.ServerResponse` API
* to a format consumable by modern web frameworks.
* @module src/mcp-server/transports/core/honoNodeBridge
*/
import { PassThrough } from "stream";
/**
* A mock `http.ServerResponse` that pipes all written data to a `PassThrough` stream.
*
* This class serves as a critical compatibility layer, emulating the behavior of a
* Node.js `ServerResponse` to capture status codes, headers, and the response body.
* The captured data can then be used to construct a Web-standard `Response` object,
* for instance in a Hono application. It pays close attention to the timing of when
* headers are considered "sent" to mimic Node.js behavior accurately.
*/
export class HonoStreamResponse extends PassThrough {
statusCode = 200;
headers = {};
_headersSent = false;
constructor() {
super();
}
/**
* A getter that reports whether the headers have been sent.
* In this emulation, headers are considered sent the first time `write()` or `end()` is called.
*/
get headersSent() {
return this._headersSent;
}
/**
* Sets the status code and headers for the response, mimicking `http.ServerResponse.writeHead`.
*
* @param statusCode - The HTTP status code.
* @param statusMessageOrHeaders - An optional status message (string) or headers object.
* @param headers - An optional headers object, used if the second argument is a status message.
* @returns The instance of the class for chaining.
*/
writeHead(statusCode, statusMessageOrHeaders, headers) {
if (this._headersSent) {
// Per Node.js spec, do nothing if headers are already sent.
return this;
}
this.statusCode = statusCode;
const headersArg = typeof statusMessageOrHeaders === "string"
? headers
: statusMessageOrHeaders;
if (headersArg) {
for (const [key, value] of Object.entries(headersArg)) {
if (value !== undefined) {
this.setHeader(key, value);
}
}
}
return this;
}
/**
* Sets a single header value.
*
* @param name - The name of the header.
* @param value - The value of the header.
* @returns The instance of the class for chaining.
*/
setHeader(name, value) {
if (this._headersSent) {
// This is a deviation from Node.js (which would throw), but provides a
// more graceful warning for this emulation layer.
console.warn(`[HonoBridge] Warning: Cannot set header "${name}" after headers are sent.`);
return this;
}
this.headers[name.toLowerCase()] = value;
return this;
}
/**
* Gets a header that has been queued for the response.
* @param name - The name of the header.
* @returns The value of the header, or undefined if not set.
*/
getHeader(name) {
return this.headers[name.toLowerCase()];
}
/**
* Returns a copy of the current outgoing headers.
*/
getHeaders() {
return { ...this.headers };
}
/**
* Removes a header that has been queued for the response.
* @param name - The name of the header to remove.
*/
removeHeader(name) {
if (this._headersSent) {
console.warn(`[HonoBridge] Warning: Cannot remove header "${name}" after headers are sent.`);
return;
}
delete this.headers[name.toLowerCase()];
}
/**
* A private helper to mark headers as sent. This is called implicitly
* before any part of the body is written.
*/
ensureHeadersSent() {
if (!this._headersSent) {
this._headersSent = true;
}
}
/**
* Writes a chunk of the response body, mimicking `http.ServerResponse.write`.
* This is the first point where headers are implicitly flushed.
*/
write(chunk, encodingOrCallback, callback) {
this.ensureHeadersSent();
const encoding = typeof encodingOrCallback === "string" ? encodingOrCallback : undefined;
const cb = typeof encodingOrCallback === "function" ? encodingOrCallback : callback;
if (encoding) {
return super.write(chunk, encoding, cb);
}
return super.write(chunk, cb);
}
/**
* Finishes sending the response, mimicking `http.ServerResponse.end`.
* This also implicitly flushes headers if they haven't been sent yet.
*/
end(chunk, encodingOrCallback, callback) {
this.ensureHeadersSent();
const encoding = typeof encodingOrCallback === "string" ? encodingOrCallback : undefined;
const cb = typeof encodingOrCallback === "function" ? encodingOrCallback : callback;
if (encoding) {
super.end(chunk, encoding, cb);
}
else {
super.end(chunk, cb);
}
return this;
}
}
//# sourceMappingURL=honoNodeBridge.js.map