ext-apps/src/message-transport.ts
2025-11-21 11:56:27 +00:00

58 lines
1.8 KiB
TypeScript

import {
JSONRPCMessage,
JSONRPCMessageSchema,
MessageExtraInfo,
} from "@modelcontextprotocol/sdk/types.js";
import type { RequestHandlerExtra } from "@modelcontextprotocol/sdk/shared/protocol.js";
import {
Transport,
TransportSendOptions,
} from "@modelcontextprotocol/sdk/shared/transport.js";
import { z } from "zod";
export class PostMessageTransport implements Transport {
private messageListener: (
this: Window,
ev: WindowEventMap["message"],
) => any | undefined;
constructor(
private eventTarget: Window = window.parent,
private eventSource?: MessageEventSource,
) {
this.messageListener = (event) => {
if (eventSource && event.source !== this.eventSource) {
console.error("Ignoring message from unknown source", event);
return;
}
const parsed = JSONRPCMessageSchema.safeParse(event.data);
if (parsed.success) {
console.info("[host] Parsed message", parsed.data);
this.onmessage?.(parsed.data);
} else {
console.error("Failed to parse message", parsed.error.message, event);
this.onerror?.(
new Error(
"Invalid JSON-RPC message received: " + parsed.error.message,
),
);
}
};
}
async start() {
window.addEventListener("message", this.messageListener);
}
async send(message: JSONRPCMessage, options?: TransportSendOptions) {
console.info("[host] Sending message", message);
this.eventTarget.postMessage(message, "*");
}
async close() {
window.removeEventListener("message", this.messageListener);
this.onclose?.();
}
onclose?: () => void;
onerror?: (error: Error) => void;
onmessage?: (message: JSONRPCMessage, extra?: MessageExtraInfo) => void;
sessionId?: string;
setProtocolVersion?: (version: string) => void;
}