Skip to content

Commit 208599d

Browse files
authored
Merge pull request #57 from seuros/main
fix(transports): follow spec guideline
2 parents df733f9 + 25ed8e6 commit 208599d

File tree

5 files changed

+20
-19
lines changed

5 files changed

+20
-19
lines changed

src/core/MCPServer.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -432,8 +432,10 @@ export class MCPServer {
432432
}
433433
this.isRunning = true;
434434

435+
const frameworkPackageJson = require('../../package.json');
436+
const frameworkVersion = frameworkPackageJson.version || 'unknown';
435437
const sdkVersion = this.getSdkVersion();
436-
logger.info(`Starting MCP server with SDK ${sdkVersion}...`);
438+
logger.info(`Starting MCP server (Framework: ${frameworkVersion}, SDK: ${sdkVersion})...`);
437439

438440
const tools = await this.toolLoader.loadTools();
439441
this.toolsMap = new Map(

src/transports/http/server.ts

+8-7
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { logger } from "../../core/Logger.js";
2121
import { getRequestHeader, setResponseHeaders } from "../../utils/headers.js";
2222
import { DEFAULT_CORS_CONFIG } from "../sse/types.js";
2323
import { CORSConfig } from "../sse/types.js";
24+
import { PING_SSE_MESSAGE } from "../utils/ping-message.js";
2425

2526
function isRequest(msg: JsonRpcMessage): msg is JsonRpcRequest {
2627
return msg &&
@@ -185,14 +186,15 @@ export class HttpStreamTransport extends AbstractTransport {
185186
case "POST": await this.handlePost(req, res); break;
186187
case "GET": await this.handleGet(req, res); break;
187188
case "DELETE": await this.handleDelete(req, res); break;
188-
default:
189-
const allowHeader = this._config.enableGetSse ?
190-
'GET, POST, DELETE, OPTIONS' :
189+
default: { // Add block scope for the default case
190+
const allowHeader = this._config.enableGetSse ?
191+
'GET, POST, DELETE, OPTIONS' :
191192
'POST, DELETE, OPTIONS';
192-
res.writeHead(405, { 'Content-Type': 'text/plain', 'Allow': allowHeader });
193+
res.writeHead(405, { 'Content-Type': 'text/plain', 'Allow': allowHeader });
193194
res.end("Method Not Allowed");
194-
logger.warn(`Unsupported method: ${req.method}`);
195+
logger.warn(`Unsupported method: ${req.method}`);
195196
break;
197+
} // Close block scope
196198
}
197199
} catch (error: any) {
198200
logger.error(`Error processing ${req.method} ${url.pathname}: ${error.message}`);
@@ -481,7 +483,6 @@ export class HttpStreamTransport extends AbstractTransport {
481483
if (res.socket) { res.socket.setNoDelay(true); res.socket.setKeepAlive(true); res.socket.setTimeout(0); logger.debug(`Optimized socket for SSE stream ${streamId}`); }
482484
else { logger.warn(`Could not access socket for SSE stream ${streamId} to optimize.`); }
483485
this._activeSseConnections.add(connection);
484-
res.write(': stream opened\n\n');
485486
connection.pingInterval = setInterval(() => this.sendPing(connection), 15000);
486487
if (lastEventId && this._config.resumability.enabled) {
487488
this.handleResumption(connection, lastEventId, sessionId).catch(err => { logger.error(`Error during stream resumption for ${streamId}: ${err.message}`); this.cleanupConnection(connection, `Resumption error: ${err.message}`); });
@@ -646,7 +647,7 @@ export class HttpStreamTransport extends AbstractTransport {
646647
private sendPing(connection: ActiveSseConnection): void {
647648
if (!connection || !connection.res || connection.res.writableEnded) return;
648649
try {
649-
connection.res.write(': keep-alive\n\n');
650+
connection.res.write(PING_SSE_MESSAGE);
650651
logger.debug(`Sent keep-alive ping to stream ${connection.streamId}`);
651652
} catch (error: any) {
652653
logger.error(`Error sending ping to stream ${connection.streamId}: ${error.message}`);

src/transports/sse/server.ts

+2-10
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { AbstractTransport } from "../base.js"
99
import { DEFAULT_SSE_CONFIG, SSETransportConfig, SSETransportConfigInternal, DEFAULT_CORS_CONFIG, CORSConfig } from "./types.js"
1010
import { logger } from "../../core/Logger.js"
1111
import { getRequestHeader, setResponseHeaders } from "../../utils/headers.js"
12+
import { PING_SSE_MESSAGE } from "../utils/ping-message.js";
1213

1314
interface ExtendedIncomingMessage extends IncomingMessage {
1415
body?: ClientRequest
@@ -225,20 +226,11 @@ export class SSEServerTransport extends AbstractTransport {
225226
res.write(`event: endpoint\ndata: ${endpointUrl}\n\n`)
226227

227228
logger.debug('Sending initial keep-alive')
228-
res.write(": keep-alive\n\n")
229229

230230
this._keepAliveInterval = setInterval(() => {
231231
if (this._sseResponse && !this._sseResponse.writableEnded) {
232232
try {
233-
logger.debug('Sending keep-alive ping')
234-
this._sseResponse.write(": keep-alive\n\n")
235-
236-
const pingMessage = {
237-
jsonrpc: "2.0",
238-
method: "ping",
239-
params: { timestamp: Date.now() }
240-
}
241-
this._sseResponse.write(`data: ${JSON.stringify(pingMessage)}\n\n`)
233+
this._sseResponse.write(PING_SSE_MESSAGE);
242234
} catch (error) {
243235
logger.error(`Error sending keep-alive: ${error}`)
244236
this.cleanupConnection()

src/transports/utils/ping-message.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/**
2+
* Pre-stringified JSON-RPC ping message formatted for Server-Sent Events (SSE).
3+
* Includes the 'data: ' prefix and trailing newlines.
4+
*/
5+
export const PING_SSE_MESSAGE = 'data: {"jsonrpc":"2.0","method":"ping"}\n\n';

tsconfig.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@
99
"strict": true,
1010
"esModuleInterop": true,
1111
"skipLibCheck": true,
12-
"forceConsistentCasingInFileNames": true
12+
"forceConsistentCasingInFileNames": true,
13+
"resolveJsonModule": true
1314
},
1415
"include": ["src/**/*"],
1516
"exclude": ["node_modules", "**/*.test.ts"]

0 commit comments

Comments
 (0)