143 lines
3.8 KiB
TypeScript
143 lines
3.8 KiB
TypeScript
import { App, PostMessageTransport } from "../src/app.js";
|
|
import {
|
|
McpUiToolInputNotificationSchema,
|
|
McpUiSizeChangeNotificationSchema,
|
|
McpUiToolResultNotificationSchema,
|
|
} from "../src/types.js";
|
|
|
|
window.addEventListener("load", async () => {
|
|
const root = document.getElementById("root")!;
|
|
const appendText = (textContent: string, opts = {}) => {
|
|
root.appendChild(
|
|
Object.assign(document.createElement("div"), {
|
|
textContent,
|
|
...opts,
|
|
}),
|
|
);
|
|
};
|
|
const appendError = (error: unknown) =>
|
|
appendText(
|
|
`Error: ${error instanceof Error ? error.message : String(error)}`,
|
|
{ style: "color: red;" },
|
|
);
|
|
|
|
const transport = new PostMessageTransport(window.parent);
|
|
const app = new App({
|
|
name: "MCP UI Client",
|
|
version: "1.0.0",
|
|
});
|
|
|
|
app.setNotificationHandler(
|
|
McpUiToolResultNotificationSchema,
|
|
async ({ params: { content, structuredContent, isError } }) => {
|
|
appendText(
|
|
`Tool call result received: isError=${isError}, content=${content}, structuredContent=${JSON.stringify(structuredContent)}`,
|
|
);
|
|
},
|
|
);
|
|
app.setNotificationHandler(
|
|
McpUiSizeChangeNotificationSchema,
|
|
async ({ params: { width, height } }) => {
|
|
appendText(
|
|
`Size change notification received: width=${width}, height=${height}`,
|
|
);
|
|
},
|
|
);
|
|
app.setNotificationHandler(
|
|
McpUiToolInputNotificationSchema,
|
|
async ({ params }) => {
|
|
appendText(
|
|
`Tool call input received: ${JSON.stringify(params.arguments)}`,
|
|
);
|
|
},
|
|
);
|
|
|
|
document.body.addEventListener("resize", () => {
|
|
app.sendSizeChange({
|
|
width: document.body.scrollWidth,
|
|
height: document.body.scrollHeight,
|
|
});
|
|
});
|
|
|
|
root.appendChild(
|
|
Object.assign(document.createElement("button"), {
|
|
textContent: "Get Weather (Tool)",
|
|
onclick: async () => {
|
|
const signal = AbortSignal.timeout(5000);
|
|
try {
|
|
const result = await app.callServerTool({
|
|
name: "get-weather",
|
|
arguments: { location: "Tokyo" },
|
|
});
|
|
appendText(`Weather tool result: ${JSON.stringify(result)}`);
|
|
} catch (e) {
|
|
appendError(e);
|
|
}
|
|
},
|
|
}),
|
|
);
|
|
|
|
root.appendChild(
|
|
Object.assign(document.createElement("button"), {
|
|
textContent: "Notify Cart Updated",
|
|
onclick: async () => {
|
|
try {
|
|
await app.sendLog({
|
|
level: "info",
|
|
data: "cart-updated",
|
|
});
|
|
} catch (e) {
|
|
appendError(e);
|
|
}
|
|
},
|
|
}),
|
|
);
|
|
|
|
root.appendChild(
|
|
Object.assign(document.createElement("button"), {
|
|
textContent: "Prompt Weather in Tokyo",
|
|
onclick: async () => {
|
|
const signal = AbortSignal.timeout(5000);
|
|
try {
|
|
const { isError } = await app.sendMessage(
|
|
{
|
|
role: "user", // Forced.
|
|
content: [
|
|
{
|
|
type: "text",
|
|
text: "What is the weather in Tokyo?",
|
|
},
|
|
],
|
|
},
|
|
{ signal },
|
|
);
|
|
appendText(`Prompt result: ${isError ? "error" : "success"}`);
|
|
} catch (e) {
|
|
if (signal.aborted) {
|
|
appendError("Prompt request timed out");
|
|
return;
|
|
}
|
|
appendError(e);
|
|
}
|
|
},
|
|
}),
|
|
);
|
|
|
|
root.appendChild(
|
|
Object.assign(document.createElement("button"), {
|
|
textContent: "Open Link to Google",
|
|
onclick: async () => {
|
|
try {
|
|
const { isError } = await app.sendOpenLink({
|
|
url: "https://www.google.com",
|
|
});
|
|
appendText(`Open link result: ${isError ? "error" : "success"}`);
|
|
} catch (e) {
|
|
appendError(e);
|
|
}
|
|
},
|
|
}),
|
|
);
|
|
|
|
await app.connect(transport);
|
|
});
|