update build
This commit is contained in:
parent
697a7ac658
commit
a0039ef150
8 changed files with 50 additions and 490 deletions
78
build.ts
78
build.ts
|
|
@ -25,45 +25,45 @@ async function buildJs(
|
|||
}
|
||||
|
||||
await Promise.all([
|
||||
buildJs("src/index.ts", { outdir: "dist/src" }),
|
||||
buildJs("src/react/useApp.tsx", { outdir: "dist/src/react" }),
|
||||
buildJs("examples/example-ui-react.tsx", { outdir: "dist/examples" }),
|
||||
buildJs("examples/example-ui.ts", { outdir: "dist/examples" }),
|
||||
buildJs("examples/example-server.ts", {
|
||||
target: "node",
|
||||
outdir: "dist/examples",
|
||||
}),
|
||||
buildJs("src/app.ts"),
|
||||
buildJs("src/react/index.tsx", { outdir: "dist/react" }),
|
||||
// buildJs("examples/example-ui-react.tsx", { outdir: "dist/examples" }),
|
||||
// buildJs("examples/example-ui.ts", { outdir: "dist/examples" }),
|
||||
// buildJs("examples/example-server.ts", {
|
||||
// target: "node",
|
||||
// outdir: "dist/examples",
|
||||
// }),
|
||||
]);
|
||||
|
||||
async function inlineHtml(htmlFilePath: string, outputFilePath: string) {
|
||||
let html = await readFile(htmlFilePath, "utf-8");
|
||||
// Find all src sources, then fetch them, then replace them
|
||||
const files = html.matchAll(
|
||||
/<script src="((?:\.\/)?dist\/.*?\.js)"><\/script>/g,
|
||||
);
|
||||
const fileContent = Object.fromEntries(
|
||||
await Promise.all(
|
||||
Array.from(files, async ([, filename]) => {
|
||||
const scriptContent = await readFile(filename, "utf-8");
|
||||
return [filename, scriptContent];
|
||||
}),
|
||||
),
|
||||
);
|
||||
html = html.replace(
|
||||
/<script src="((?:\.\/)?dist\/.*?\.js)"><\/script>/g,
|
||||
(_, filename) => {
|
||||
let scriptContent = fileContent[filename];
|
||||
// Escape </script> to prevent premature script tag closing
|
||||
// This is the standard way to inline scripts safely
|
||||
scriptContent = scriptContent.replace(/<\/script>/gi, "<\\/script>");
|
||||
return `<script>${scriptContent}</script>`;
|
||||
},
|
||||
);
|
||||
await writeFile(outputFilePath, html);
|
||||
}
|
||||
// async function inlineHtml(htmlFilePath: string, outputFilePath: string) {
|
||||
// let html = await readFile(htmlFilePath, "utf-8");
|
||||
// // Find all src sources, then fetch them, then replace them
|
||||
// const files = html.matchAll(
|
||||
// /<script src="((?:\.\/)?dist\/.*?\.js)"><\/script>/g,
|
||||
// );
|
||||
// const fileContent = Object.fromEntries(
|
||||
// await Promise.all(
|
||||
// Array.from(files, async ([, filename]) => {
|
||||
// const scriptContent = await readFile(filename, "utf-8");
|
||||
// return [filename, scriptContent];
|
||||
// }),
|
||||
// ),
|
||||
// );
|
||||
// html = html.replace(
|
||||
// /<script src="((?:\.\/)?dist\/.*?\.js)"><\/script>/g,
|
||||
// (_, filename) => {
|
||||
// let scriptContent = fileContent[filename];
|
||||
// // Escape </script> to prevent premature script tag closing
|
||||
// // This is the standard way to inline scripts safely
|
||||
// scriptContent = scriptContent.replace(/<\/script>/gi, "<\\/script>");
|
||||
// return `<script>${scriptContent}</script>`;
|
||||
// },
|
||||
// );
|
||||
// await writeFile(outputFilePath, html);
|
||||
// }
|
||||
|
||||
await inlineHtml("examples/example-ui.html", "dist/examples/example-ui.html");
|
||||
await inlineHtml(
|
||||
"examples/example-ui-react.html",
|
||||
"dist/examples/example-ui-react.html",
|
||||
);
|
||||
// await inlineHtml("examples/example-ui.html", "dist/examples/example-ui.html");
|
||||
// await inlineHtml(
|
||||
// "examples/example-ui-react.html",
|
||||
// "dist/examples/example-ui-react.html",
|
||||
// );
|
||||
|
|
|
|||
3
index.ts
3
index.ts
|
|
@ -1,3 +0,0 @@
|
|||
export { App } from "./app";
|
||||
export { PostMessageTransport } from "./message-transport";
|
||||
export * from "./types";
|
||||
13
package.json
13
package.json
|
|
@ -4,11 +4,16 @@
|
|||
"version": "1.0.0",
|
||||
"description": "Hey",
|
||||
"type": "module",
|
||||
"main": "./src/index.ts",
|
||||
"main": "./dist/app.js",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./types": "./src/types.ts",
|
||||
"./react/useApp": "./src/react/useApp.tsx"
|
||||
".": {
|
||||
"types": "./dist/app.d.ts",
|
||||
"default": "./dist/app.js"
|
||||
},
|
||||
"./react": {
|
||||
"types": "./dist/react/index.d.ts",
|
||||
"default": "./dist/react/index.js"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"start:example-server0": "tsx examples/example-server.ts",
|
||||
|
|
|
|||
|
|
@ -1,70 +0,0 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { Implementation } from "@modelcontextprotocol/sdk/types.js";
|
||||
import { Client } from "@modelcontextprotocol/sdk/client";
|
||||
import { App, McpUiAppCapabilities, PostMessageTransport } from "../app";
|
||||
export * from "../app";
|
||||
|
||||
export interface UseAppOptions {
|
||||
appInfo: Implementation;
|
||||
capabilities: McpUiAppCapabilities;
|
||||
/**
|
||||
* Called after client is created but before connection.
|
||||
* Use this to register request/notification handlers via
|
||||
* client.setRequestHandler() and client.setNotificationHandler().
|
||||
*/
|
||||
onAppCreated?: (app: App) => void;
|
||||
}
|
||||
|
||||
export interface AppState {
|
||||
app: App | null;
|
||||
isConnected: boolean;
|
||||
error: Error | null;
|
||||
}
|
||||
|
||||
export function useApp({
|
||||
appInfo,
|
||||
capabilities,
|
||||
onAppCreated,
|
||||
}: UseAppOptions): AppState {
|
||||
const [app, setApp] = useState<App | null>(null);
|
||||
const [isConnected, setIsConnected] = useState(false);
|
||||
const [error, setError] = useState<Error | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let mounted = true;
|
||||
|
||||
async function connect() {
|
||||
try {
|
||||
const transport = new PostMessageTransport(window.parent);
|
||||
const app = new App(appInfo, capabilities);
|
||||
|
||||
// Register handlers BEFORE connecting
|
||||
onAppCreated?.(app);
|
||||
|
||||
await app.connect(transport);
|
||||
|
||||
if (mounted) {
|
||||
setApp(app);
|
||||
setIsConnected(true);
|
||||
setError(null);
|
||||
}
|
||||
} catch (error) {
|
||||
if (mounted) {
|
||||
setApp(null);
|
||||
setIsConnected(false);
|
||||
setError(
|
||||
error instanceof Error ? error : new Error("Failed to connect"),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
connect();
|
||||
|
||||
return () => {
|
||||
mounted = false;
|
||||
};
|
||||
}, []); // Intentionally not including options to avoid reconnection
|
||||
|
||||
return { app, isConnected, error };
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
import { useEffect, RefObject } from "react";
|
||||
import { App } from "../app";
|
||||
|
||||
/**
|
||||
* Custom hook that automatically reports size changes to the parent window.
|
||||
*
|
||||
* @param client - MCP UI client for sending size notifications
|
||||
*/
|
||||
export function useAutoResize(
|
||||
app: App | null,
|
||||
elementRef?: RefObject<HTMLElement | null>,
|
||||
) {
|
||||
useEffect(() => {
|
||||
if (!app) {
|
||||
return;
|
||||
}
|
||||
|
||||
return app.setupSizeChangeNotifications();
|
||||
}, [app, elementRef]);
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
export { App } from "./app";
|
||||
export { PostMessageTransport } from "./message-transport";
|
||||
export * from "./types";
|
||||
351
src/peer.ts_
351
src/peer.ts_
|
|
@ -1,351 +0,0 @@
|
|||
// import {
|
||||
// z,
|
||||
// ZodRawShape,
|
||||
// ZodLiteral,
|
||||
// ZodObject,
|
||||
// ZodString,
|
||||
// ZodTypeAny,
|
||||
// ZodType,
|
||||
// ZodTypeDef,
|
||||
// ZodOptional,
|
||||
// } from "zod";
|
||||
// import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
||||
// import {
|
||||
// // ToolCallback,
|
||||
// RegisteredTool,
|
||||
// } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||
// import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
||||
// import {
|
||||
// Protocol,
|
||||
// type RequestOptions,
|
||||
// type RequestHandlerExtra,
|
||||
// } from "@modelcontextprotocol/sdk/shared/protocol.js";
|
||||
|
||||
// import {
|
||||
// CallToolRequestSchema,
|
||||
// CallToolResult,
|
||||
// CallToolResultSchema,
|
||||
// CancelledNotificationSchema,
|
||||
// ClientCapabilities,
|
||||
// ClientCapabilitiesSchema,
|
||||
// Request,
|
||||
// Implementation,
|
||||
// JSONRPCError,
|
||||
// JSONRPCMessage,
|
||||
// JSONRPCMessageSchema,
|
||||
// JSONRPCNotification,
|
||||
// JSONRPCResponse,
|
||||
// ListPromptsRequestSchema,
|
||||
// ListPromptsResultSchema,
|
||||
// ListResourcesRequestSchema,
|
||||
// ListResourcesResultSchema,
|
||||
// ListResourceTemplatesRequestSchema,
|
||||
// ListResourceTemplatesResultSchema,
|
||||
// LoggingMessageNotification,
|
||||
// LoggingMessageNotificationSchema,
|
||||
// MessageExtraInfo,
|
||||
// Notification,
|
||||
// PromptListChangedNotificationSchema,
|
||||
// RequestId,
|
||||
// ResourceListChangedNotificationSchema,
|
||||
// Result,
|
||||
// ServerCapabilities,
|
||||
// ServerCapabilitiesSchema,
|
||||
// ServerNotification,
|
||||
// ServerRequest,
|
||||
// ToolAnnotations,
|
||||
// ToolListChangedNotificationSchema,
|
||||
// } from "@modelcontextprotocol/sdk/types.js";
|
||||
// import {
|
||||
// Transport,
|
||||
// TransportSendOptions,
|
||||
// } from "@modelcontextprotocol/sdk/shared/transport.js";
|
||||
// import {
|
||||
// McpUiToolInputNotification,
|
||||
// McpUiToolInputNotificationSchema,
|
||||
// McpUiToolResultNotification,
|
||||
// McpUiToolResultNotificationSchema,
|
||||
// McpUiHostCapabilities,
|
||||
// McpUiHostInfo,
|
||||
// McpUiInitializedNotification,
|
||||
// McpUiInitializeRequest,
|
||||
// McpUiInitializeResultSchema,
|
||||
// McpUiIntentRequest,
|
||||
// McpUiIntentRequestSchema,
|
||||
// McpUiIntentResultSchema,
|
||||
// McpUiRenderDataRequest,
|
||||
// McpUiRenderDataRequestSchema,
|
||||
// McpUiMessageRequest,
|
||||
// McpUiMessageRequestSchema,
|
||||
// McpUiMessageResult,
|
||||
// McpUiMessageResultSchema,
|
||||
// McpUiOpenLinkRequest,
|
||||
// McpUiOpenLinkRequestSchema,
|
||||
// McpUiOpenLinkResultSchema,
|
||||
// McpUiRenderDataResultSchema,
|
||||
// McpUiSizeChangeNotification,
|
||||
// McpUiSizeChangeNotificationSchema,
|
||||
// } from "./types";
|
||||
|
||||
// export { PostMessageTransport } from "./message-transport.js";
|
||||
|
||||
// if (false) {
|
||||
// let server: Server;
|
||||
// let client: Client;
|
||||
// }
|
||||
|
||||
// const McpUiInitializeRequestSchema = z.object({
|
||||
// method: z.literal("ui/initialize"),
|
||||
// params: z.object({
|
||||
// name: z.string(),
|
||||
// version: z.string(),
|
||||
// capabilities: ServerCapabilitiesSchema.extend(
|
||||
// ClientCapabilitiesSchema.shape,
|
||||
// ),
|
||||
// }),
|
||||
// });
|
||||
|
||||
// /**
|
||||
// * Converts a provided Zod schema to a Zod object if it is a ZodRawShape,
|
||||
// * otherwise returns the schema as is.
|
||||
// */
|
||||
// function getZodSchemaObject(
|
||||
// schema: ZodRawShape | ZodType<object> | undefined,
|
||||
// ): ZodType<object> | undefined {
|
||||
// if (!schema) {
|
||||
// return undefined;
|
||||
// }
|
||||
|
||||
// if (isZodRawShape(schema)) {
|
||||
// return z.object(schema);
|
||||
// }
|
||||
|
||||
// return schema;
|
||||
// }
|
||||
|
||||
// export class McpUiGuest extends Protocol<Request, Notification, Result> {
|
||||
// private _registeredHostTools: Record<string, RegisteredTool> = {};
|
||||
|
||||
// assertCapabilityForMethod(method: Request["method"]): void {}
|
||||
// assertRequestHandlerCapability(method: Request["method"]): void {}
|
||||
// assertNotificationCapability(method: Notification["method"]): void {}
|
||||
|
||||
// async callServerTool(
|
||||
// name: string,
|
||||
// argsSchema: ZodTypeAny,
|
||||
// args: unknown,
|
||||
// options?: RequestOptions,
|
||||
// ) {
|
||||
// //: Promise<CallToolResult> {
|
||||
// }
|
||||
// async addUiToChat(
|
||||
// resourceUri: string,
|
||||
// state: Record<string, unknown>,
|
||||
// ): Promise<void> {}
|
||||
// // In future, could expose callHostTool
|
||||
|
||||
// registerHostTool<
|
||||
// InputArgs extends ZodRawShape | ZodType<object>,
|
||||
// OutputArgs extends ZodRawShape | ZodType<object>,
|
||||
// >(
|
||||
// name: string,
|
||||
// config: {
|
||||
// title?: string;
|
||||
// description?: string;
|
||||
// inputSchema?: InputArgs;
|
||||
// outputSchema?: OutputArgs;
|
||||
// annotations?: ToolAnnotations;
|
||||
// _meta?: Record<string, unknown>;
|
||||
// },
|
||||
// cb: ToolCallback<InputArgs>,
|
||||
// ): RegisteredTool {
|
||||
// if (this._registeredHostTools[name]) {
|
||||
// throw new Error(`Tool ${name} is already registered on host`);
|
||||
// }
|
||||
|
||||
// const {
|
||||
// title,
|
||||
// description,
|
||||
// inputSchema,
|
||||
// outputSchema,
|
||||
// annotations,
|
||||
// _meta,
|
||||
// } = config;
|
||||
|
||||
// return this._createRegisteredTool(
|
||||
// name,
|
||||
// title,
|
||||
// description,
|
||||
// inputSchema,
|
||||
// outputSchema,
|
||||
// annotations,
|
||||
// _meta,
|
||||
// cb as ToolCallback<ZodRawShape | undefined>,
|
||||
// );
|
||||
// }
|
||||
|
||||
// private _createRegisteredTool(
|
||||
// name: string,
|
||||
// title: string | undefined,
|
||||
// description: string | undefined,
|
||||
// inputSchema: ZodRawShape | ZodType<object> | undefined,
|
||||
// outputSchema: ZodRawShape | ZodType<object> | undefined,
|
||||
// annotations: ToolAnnotations | undefined,
|
||||
// _meta: Record<string, unknown> | undefined,
|
||||
// callback: ToolCallback<ZodRawShape | undefined>,
|
||||
// ): RegisteredTool {
|
||||
// const registeredTool: RegisteredTool = {
|
||||
// title,
|
||||
// description,
|
||||
// inputSchema: getZodSchemaObject(inputSchema) as any,
|
||||
// outputSchema: getZodSchemaObject(outputSchema) as any,
|
||||
// annotations,
|
||||
// _meta,
|
||||
// callback,
|
||||
// enabled: true,
|
||||
// disable: () => registeredTool.update({ enabled: false }),
|
||||
// enable: () => registeredTool.update({ enabled: true }),
|
||||
// remove: () => registeredTool.update({ name: null }),
|
||||
// update: (updates) => {
|
||||
// if (typeof updates.name !== "undefined" && updates.name !== name) {
|
||||
// delete this._registeredHostTools[name];
|
||||
// if (updates.name)
|
||||
// this._registeredHostTools[updates.name] = registeredTool;
|
||||
// }
|
||||
// if (typeof updates.title !== "undefined")
|
||||
// registeredTool.title = updates.title;
|
||||
// if (typeof updates.description !== "undefined")
|
||||
// registeredTool.description = updates.description;
|
||||
// if (typeof updates.paramsSchema !== "undefined")
|
||||
// registeredTool.inputSchema = z.object(updates.paramsSchema);
|
||||
// if (typeof updates.callback !== "undefined")
|
||||
// registeredTool.callback = updates.callback;
|
||||
// if (typeof updates.annotations !== "undefined")
|
||||
// registeredTool.annotations = updates.annotations;
|
||||
// if (typeof updates._meta !== "undefined")
|
||||
// registeredTool._meta = updates._meta;
|
||||
// if (typeof updates.enabled !== "undefined")
|
||||
// registeredTool.enabled = updates.enabled;
|
||||
// // this.sendToolListChanged();
|
||||
// },
|
||||
// };
|
||||
// this._registeredHostTools[name] = registeredTool;
|
||||
|
||||
// return registeredTool;
|
||||
// }
|
||||
|
||||
// sendMessage(params: McpUiMessageRequest["params"], options?: RequestOptions) {
|
||||
// return this.request(
|
||||
// <McpUiMessageRequest>{
|
||||
// method: "ui/message",
|
||||
// params,
|
||||
// },
|
||||
// McpUiMessageResultSchema,
|
||||
// options,
|
||||
// );
|
||||
// }
|
||||
|
||||
// sendLog(params: LoggingMessageNotification["params"]) {
|
||||
// return this.notification(<LoggingMessageNotification>{
|
||||
// method: "notifications/message",
|
||||
// params,
|
||||
// });
|
||||
// }
|
||||
|
||||
// sendOpenLink(
|
||||
// params: McpUiOpenLinkRequest["params"],
|
||||
// options?: RequestOptions,
|
||||
// ) {
|
||||
// return this.request(
|
||||
// <McpUiOpenLinkRequest>{
|
||||
// method: "ui/open-link",
|
||||
// params,
|
||||
// },
|
||||
// McpUiOpenLinkResultSchema,
|
||||
// options,
|
||||
// );
|
||||
// }
|
||||
|
||||
// sendSizeChange(params: McpUiSizeChangeNotification["params"]) {
|
||||
// return this.notification(<McpUiSizeChangeNotification>{
|
||||
// method: "ui/size-change",
|
||||
// params,
|
||||
// });
|
||||
// }
|
||||
|
||||
// private _hostCapabilities?: McpUiHostCapabilities;
|
||||
// private _hostInfo?: McpUiHostInfo;
|
||||
|
||||
// override async connect(
|
||||
// transport: Transport,
|
||||
// options?: RequestOptions,
|
||||
// ): Promise<void> {
|
||||
// await super.connect(transport);
|
||||
|
||||
// try {
|
||||
// const result = await this.request(
|
||||
// <McpUiInitializeRequest>{
|
||||
// method: "ui/initialize",
|
||||
// params: {
|
||||
// // TODO: protocolVersion: LATEST_PROTOCOL_VERSION,
|
||||
// },
|
||||
// },
|
||||
// McpUiInitializeResultSchema,
|
||||
// options,
|
||||
// );
|
||||
|
||||
// if (result === undefined) {
|
||||
// throw new Error(`Server sent invalid initialize result: ${result}`);
|
||||
// }
|
||||
|
||||
// this._hostCapabilities = result.hostCapabilities;
|
||||
// this._hostInfo = result.hostInfo;
|
||||
|
||||
// await this.notification(<McpUiInitializedNotification>{
|
||||
// method: "ui/notifications/initialized",
|
||||
// });
|
||||
// } catch (error) {
|
||||
// // Disconnect if initialization fails.
|
||||
// void this.close();
|
||||
// throw error;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// export type ToolCallback<
|
||||
// Args extends undefined | ZodRawShape | ZodType<object> = undefined,
|
||||
// > = Args extends ZodRawShape
|
||||
// ? (
|
||||
// args: z.objectOutputType<Args, ZodTypeAny>,
|
||||
// extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
|
||||
// ) => CallToolResult | Promise<CallToolResult>
|
||||
// : Args extends ZodType<infer T>
|
||||
// ? (
|
||||
// args: T,
|
||||
// extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
|
||||
// ) => CallToolResult | Promise<CallToolResult>
|
||||
// : (
|
||||
// extra: RequestHandlerExtra<ServerRequest, ServerNotification>,
|
||||
// ) => CallToolResult | Promise<CallToolResult>;
|
||||
|
||||
// // Helper to check if an object is a Zod schema (ZodRawShape)
|
||||
// function isZodRawShape(obj: unknown): obj is ZodRawShape {
|
||||
// if (typeof obj !== "object" || obj === null) return false;
|
||||
|
||||
// const isEmptyObject = Object.keys(obj).length === 0;
|
||||
|
||||
// // Check if object is empty or at least one property is a ZodType instance
|
||||
// // Note: use heuristic check to avoid instanceof failure across different Zod versions
|
||||
// return isEmptyObject || Object.values(obj as object).some(isZodTypeLike);
|
||||
// }
|
||||
|
||||
// function isZodTypeLike(value: unknown): value is ZodType {
|
||||
// return (
|
||||
// value !== null &&
|
||||
// typeof value === "object" &&
|
||||
// "parse" in value &&
|
||||
// typeof value.parse === "function" &&
|
||||
// "safeParse" in value &&
|
||||
// typeof value.safeParse === "function"
|
||||
// );
|
||||
// }
|
||||
2
src/react/index.tsx
Normal file
2
src/react/index.tsx
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
export * from "./useApp";
|
||||
export * from "./useAutoResize";
|
||||
Loading…
Reference in a new issue