Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 17 additions & 54 deletions server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ let backingServerTransport: Transport | undefined;

app.get("/mcp", async (req, res) => {
const sessionId = req.headers["mcp-session-id"] as string;
console.log(`GET /mcp for sessionId ${sessionId}`);
console.log(`Received GET message for sessionId ${sessionId}`);
try {
const transport = webAppTransports.get(
sessionId,
Expand All @@ -160,7 +160,7 @@ app.get("/mcp", async (req, res) => {

app.post("/mcp", async (req, res) => {
const sessionId = req.headers["mcp-session-id"] as string | undefined;
console.log(`POST /mcp for sessionId ${sessionId}`);
console.log(`Received POST message for sessionId ${sessionId}`);
if (!sessionId) {
try {
console.log("New streamable-http connection");
Expand Down Expand Up @@ -228,7 +228,7 @@ app.post("/mcp", async (req, res) => {

app.get("/stdio", async (req, res) => {
try {
console.log("GET /stdio");
console.log("New connection");

try {
await backingServerTransport?.close();
Expand All @@ -254,53 +254,18 @@ app.get("/stdio", async (req, res) => {
console.log("Created web app transport");

await webAppTransport.start();

// Handle client disconnection
res.on("close", () => {
console.log(
`Client disconnected from session ${webAppTransport.sessionId}`,
);
// Clean up the transport map
webAppTransports.delete(webAppTransport.sessionId);
});

// Create a stderr handler that checks connection state
const stderrHandler = (chunk: Buffer) => {
// Only send if the transport exists in our map (meaning it's still active)
if (webAppTransports.has(webAppTransport.sessionId)) {
webAppTransport
.send({
jsonrpc: "2.0",
method: "notifications/stderr",
params: {
content: chunk.toString(),
},
})
.catch((error: any) => {
console.error(
`Error sending stderr data to client: ${error.message}`,
);
// If we hit an error sending, clean up the transport
webAppTransports.delete(webAppTransport.sessionId);
});
}
};

if ((backingServerTransport as StdioClientTransport).stderr) {
(backingServerTransport as StdioClientTransport).stderr!.on(
"data",
stderrHandler,
);

// Store the handler reference so we can remove it when client disconnects
res.on("close", () => {
if ((backingServerTransport as StdioClientTransport).stderr) {
(
backingServerTransport as StdioClientTransport
).stderr!.removeListener("data", stderrHandler);
}
});
}
(backingServerTransport as StdioClientTransport).stderr!.on(
"data",
(chunk) => {
webAppTransport.send({
jsonrpc: "2.0",
method: "notifications/stderr",
params: {
content: chunk.toString(),
},
});
},
);

mcpProxy({
transportToClient: webAppTransport,
Expand All @@ -317,7 +282,7 @@ app.get("/stdio", async (req, res) => {
app.get("/sse", async (req, res) => {
try {
console.log(
"GET /sse (NOTE: The sse transport is deprecated and has been replaced by streamable-http)",
"New SSE connection. NOTE: The sse transport is deprecated and has been replaced by streamable-http",
);

try {
Expand Down Expand Up @@ -359,7 +324,7 @@ app.get("/sse", async (req, res) => {
app.post("/message", async (req, res) => {
try {
const sessionId = req.query.sessionId;
console.log(`POST /message for sessionId ${sessionId}`);
console.log(`Received message for sessionId ${sessionId}`);

const transport = webAppTransports.get(
sessionId as string,
Expand All @@ -376,15 +341,13 @@ app.post("/message", async (req, res) => {
});

app.get("/health", (req, res) => {
console.log("GET /health");
res.json({
status: "ok",
});
});

app.get("/config", (req, res) => {
try {
console.log("GET /config");
res.json({
defaultEnvironment,
defaultCommand: values.env,
Expand Down