Skip to content

Commit f22aa1f

Browse files
authored
Merge pull request #741 from cliffhall/stderr-handling
Handling of stderr on STDIO servers
2 parents d48164a + 4cf7aeb commit f22aa1f

File tree

5 files changed

+50
-77
lines changed

5 files changed

+50
-77
lines changed

client/src/App.tsx

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import {
3434
useDraggablePane,
3535
useDraggableSidebar,
3636
} from "./lib/hooks/useDraggablePane";
37-
import { StdErrNotification } from "./lib/notificationTypes";
3837

3938
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
4039
import { Button } from "@/components/ui/button";
@@ -106,9 +105,6 @@ const App = () => {
106105
>(getInitialTransportType);
107106
const [logLevel, setLogLevel] = useState<LoggingLevel>("debug");
108107
const [notifications, setNotifications] = useState<ServerNotification[]>([]);
109-
const [stdErrNotifications, setStdErrNotifications] = useState<
110-
StdErrNotification[]
111-
>([]);
112108
const [roots, setRoots] = useState<Root[]>([]);
113109
const [env, setEnv] = useState<Record<string, string>>({});
114110

@@ -224,12 +220,6 @@ const App = () => {
224220
onNotification: (notification) => {
225221
setNotifications((prev) => [...prev, notification as ServerNotification]);
226222
},
227-
onStdErrNotification: (notification) => {
228-
setStdErrNotifications((prev) => [
229-
...prev,
230-
notification as StdErrNotification,
231-
]);
232-
},
233223
onPendingRequest: (request, resolve, reject) => {
234224
setPendingSampleRequests((prev) => [
235225
...prev,
@@ -757,10 +747,6 @@ const App = () => {
757747
setLogLevel(level);
758748
};
759749

760-
const clearStdErrNotifications = () => {
761-
setStdErrNotifications([]);
762-
};
763-
764750
const AuthDebuggerWrapper = () => (
765751
<TabsContent value="auth">
766752
<AuthDebugger
@@ -829,11 +815,9 @@ const App = () => {
829815
setOauthScope={setOauthScope}
830816
onConnect={connectMcpServer}
831817
onDisconnect={disconnectMcpServer}
832-
stdErrNotifications={stdErrNotifications}
833818
logLevel={logLevel}
834819
sendLogLevelRequest={sendLogLevelRequest}
835820
loggingSupported={!!serverCapabilities?.logging || false}
836-
clearStdErrNotifications={clearStdErrNotifications}
837821
/>
838822
<div
839823
onMouseDown={handleSidebarDragStart}

client/src/components/Sidebar.tsx

Lines changed: 0 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ import {
2424
SelectTrigger,
2525
SelectValue,
2626
} from "@/components/ui/select";
27-
import { StdErrNotification } from "@/lib/notificationTypes";
2827
import {
2928
LoggingLevel,
3029
LoggingLevelSchema,
@@ -62,8 +61,6 @@ interface SidebarProps {
6261
setOauthScope: (scope: string) => void;
6362
onConnect: () => void;
6463
onDisconnect: () => void;
65-
stdErrNotifications: StdErrNotification[];
66-
clearStdErrNotifications: () => void;
6764
logLevel: LoggingLevel;
6865
sendLogLevelRequest: (level: LoggingLevel) => void;
6966
loggingSupported: boolean;
@@ -93,8 +90,6 @@ const Sidebar = ({
9390
setOauthScope,
9491
onConnect,
9592
onDisconnect,
96-
stdErrNotifications,
97-
clearStdErrNotifications,
9893
logLevel,
9994
sendLogLevelRequest,
10095
loggingSupported,
@@ -761,36 +756,6 @@ const Sidebar = ({
761756
</Select>
762757
</div>
763758
)}
764-
765-
{stdErrNotifications.length > 0 && (
766-
<>
767-
<div className="mt-4 border-t border-gray-200 pt-4">
768-
<div className="flex justify-between items-center">
769-
<h3 className="text-sm font-medium">
770-
Error output from MCP server
771-
</h3>
772-
<Button
773-
variant="outline"
774-
size="sm"
775-
onClick={clearStdErrNotifications}
776-
className="h-8 px-2"
777-
>
778-
Clear
779-
</Button>
780-
</div>
781-
<div className="mt-2 max-h-80 overflow-y-auto">
782-
{stdErrNotifications.map((notification, index) => (
783-
<div
784-
key={index}
785-
className="text-sm text-red-500 font-mono py-2 border-b border-gray-200 last:border-b-0"
786-
>
787-
{notification.params.content}
788-
</div>
789-
))}
790-
</div>
791-
</div>
792-
</>
793-
)}
794759
</div>
795760
</div>
796761
</div>

client/src/lib/hooks/useConnection.ts

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ import { useEffect, useState } from "react";
3636
import { useToast } from "@/lib/hooks/useToast";
3737
import { z } from "zod";
3838
import { ConnectionStatus } from "../constants";
39-
import { Notification, StdErrNotificationSchema } from "../notificationTypes";
39+
import { Notification } from "../notificationTypes";
4040
import {
4141
auth,
4242
discoverOAuthProtectedResourceMetadata,
@@ -92,7 +92,6 @@ export function useConnection({
9292
oauthScope,
9393
config,
9494
onNotification,
95-
onStdErrNotification,
9695
onPendingRequest,
9796
onElicitationRequest,
9897
getRoots,
@@ -505,13 +504,6 @@ export function useConnection({
505504
};
506505
}
507506

508-
if (onStdErrNotification) {
509-
client.setNotificationHandler(
510-
StdErrNotificationSchema,
511-
onStdErrNotification,
512-
);
513-
}
514-
515507
let capabilities;
516508
try {
517509
const transport =

client/src/lib/notificationTypes.ts

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,8 @@ import {
55
} from "@modelcontextprotocol/sdk/types.js";
66
import { z } from "zod";
77

8-
export const StdErrNotificationSchema = BaseNotificationSchema.extend({
9-
method: z.literal("notifications/stderr"),
10-
params: z.object({
11-
content: z.string(),
12-
}),
13-
});
14-
158
export const NotificationSchema = ClientNotificationSchema.or(
16-
StdErrNotificationSchema,
17-
)
18-
.or(ServerNotificationSchema)
19-
.or(BaseNotificationSchema);
9+
ServerNotificationSchema,
10+
).or(BaseNotificationSchema);
2011

21-
export type StdErrNotification = z.infer<typeof StdErrNotificationSchema>;
2212
export type Notification = z.infer<typeof NotificationSchema>;

server/src/index.ts

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -401,24 +401,66 @@ app.get(
401401

402402
(serverTransport as StdioClientTransport).stderr!.on("data", (chunk) => {
403403
if (chunk.toString().includes("MODULE_NOT_FOUND")) {
404+
// Server command not found, remove transports
405+
const message = "Command not found, transports removed";
404406
webAppTransport.send({
405407
jsonrpc: "2.0",
406-
method: "notifications/stderr",
408+
method: "notifications/message",
407409
params: {
408-
content: "Command not found, transports removed",
410+
level: "emergency",
411+
logger: "proxy",
412+
data: {
413+
message,
414+
},
409415
},
410416
});
411417
webAppTransport.close();
412418
serverTransport.close();
413419
webAppTransports.delete(webAppTransport.sessionId);
414420
serverTransports.delete(webAppTransport.sessionId);
415-
console.error("Command not found, transports removed");
421+
console.error(message);
416422
} else {
423+
// Inspect message and attempt to assign a RFC 5424 Syslog Protocol level
424+
let level;
425+
let message = chunk.toString().trim();
426+
let ucMsg = chunk.toString().toUpperCase();
427+
if (ucMsg.includes("DEBUG")) {
428+
level = "debug";
429+
} else if (ucMsg.includes("INFO")) {
430+
level = "info";
431+
} else if (ucMsg.includes("NOTICE")) {
432+
level = "notice";
433+
} else if (ucMsg.includes("WARN")) {
434+
level = "warning";
435+
} else if (ucMsg.includes("ERROR")) {
436+
level = "error";
437+
} else if (ucMsg.includes("CRITICAL")) {
438+
level = "critical";
439+
} else if (ucMsg.includes("ALERT")) {
440+
level = "alert";
441+
} else if (ucMsg.includes("EMERGENCY")) {
442+
level = "emergency";
443+
} else if (ucMsg.includes("SIGINT")) {
444+
message = "SIGINT received. Server shutdown.";
445+
level = "emergency";
446+
} else if (ucMsg.includes("SIGHUP")) {
447+
message = "SIGHUP received. Server shutdown.";
448+
level = "emergency";
449+
} else if (ucMsg.includes("SIGTERM")) {
450+
message = "SIGTERM received. Server shutdown.";
451+
level = "emergency";
452+
} else {
453+
level = "info";
454+
}
417455
webAppTransport.send({
418456
jsonrpc: "2.0",
419-
method: "notifications/stderr",
457+
method: "notifications/message",
420458
params: {
421-
content: chunk.toString(),
459+
level,
460+
logger: "stdio",
461+
data: {
462+
message,
463+
},
422464
},
423465
});
424466
}

0 commit comments

Comments
 (0)