build: auto-generate Zod schemas from TypeScript types using ts-to-zod (#116)
* feat: add ts-to-zod schema generation from spec.types.ts Add automated Zod schema generation using ts-to-zod: - New npm script `generate:schemas` to regenerate schemas from spec.types.ts - Post-processing script for Zod v4 compatibility and MCP SDK type imports - src/spec.types.ts: Pure TypeScript interface definitions (source of truth) - src/schemas.generated.ts: Auto-generated Zod schemas - src/schemas.ts: Re-exports with PascalCase naming for backwards compatibility The generated schemas provide a simpler alternative to the hand-written schemas in types.ts, useful for lighter validation or reference implementations. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: types.ts now re-exports from spec.types.ts and schemas.generated.ts - types.ts imports and re-exports types from spec.types.ts (source of truth) - types.ts imports and re-exports schemas from schemas.generated.ts - Added compile-time VerifySchemaMatches checks to flag mismatches between interfaces and generated schemas - Removed redundant schemas.ts (types.ts now handles all re-exports) - Applied prettier formatting to schemas.generated.ts 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: use ts-to-zod as library with integration tests Replace CLI-based schema generation with library API: - scripts/generate-schemas.ts: New script using ts-to-zod library API - Detailed documentation of why each post-processing step is needed - Generates integration tests via getIntegrationTestFile() - Better error reporting and control - src/schemas.generated.test.ts: Auto-generated integration tests - Compile-time verification that schemas match TypeScript types - Uses expectType<> pattern for bidirectional type checking - Removed scripts/postprocess-schemas.ts (merged into generate-schemas.ts) - Fixed McpUiResourceTeardownResult to include index signature for MCP SDK Protocol compatibility (detected by the new integration tests) Post-processing rationale (documented in generate-schemas.ts): 1. zod → zod/v4: Explicit v4 subpath for version clarity 2. z.any() → MCP SDK schemas: External types need real validation 3. z.record().and() → z.looseObject(): Index signatures need Zod v4 idiom 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: regenerate schemas during build + CI check - build script now runs generate:schemas before bun build - CI workflow verifies generated schemas are up-to-date (fails if spec.types.ts changed but schemas weren't regenerated) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: generate PascalCase schemas, move verification to tests - Add getSchemaName option to generate PascalCase schema names directly (McpUiOpenLinkRequestSchema instead of mcpUiOpenLinkRequestSchema) - Remove redundant compile-time verification from types.ts (already handled by generated test file's bidirectional expectType checks) - Simplify types.ts from 235 to 57 lines (just re-exports) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: add missing csp field, simplify schema generation - Add missing csp field to McpUiSandboxResourceReadyNotification (regression from merge) - Simplify generate-schemas.ts - remove complex .describe() conversion - Document that ts-to-zod supports @description JSDoc tags for .describe() - Improve z.looseObject() replacement with brace-counting for nested objects 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: add @description JSDoc tags for .describe() on schemas Added @description tags to all interfaces and fields in spec.types.ts. ts-to-zod now generates .describe() calls on all schema fields, making descriptions available at runtime for introspection and JSON Schema generation. Example: /** @description URL to open in the host's browser */ url: string; Generates: url: z.string().describe("URL to open in the host's browser") 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * feat: generate JSON Schema from Zod schemas Added JSON Schema generation to the schema generation pipeline: - Uses Zod v4's built-in toJSONSchema() to convert schemas - Generates src/schema.json with all message types in $defs - Includes descriptions from @description JSDoc tags - Added export "./schema.json" to package.json - Updated CI to verify schema.json is up-to-date Use cases: - Language-agnostic validation (Python, Go, Rust) - Documentation generation (Redoc, Swagger UI) - Code generation (quicktype) - IDE autocomplete for JSON/YAML 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: rename schema.json to schema.generated.json Renamed to match other generated files naming convention. Export path unchanged: ./schema.json -> ./dist/src/schema.generated.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: rename schemas.generated.* to schema.generated.* (singular) Consistent singular naming for all generated files: - schema.generated.ts - schema.generated.test.ts - schema.generated.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: rename schemas.generated.* to schema.generated.* (singular) Consistent singular naming for all generated files: - schema.generated.ts - schema.generated.test.ts - schema.generated.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * refactor: move generated files to src/generated/ with simpler names Moved: - src/schema.generated.ts → src/generated/schema.ts - src/schema.generated.test.ts → src/generated/schema.test.ts - src/schema.generated.json → src/generated/schema.json Benefits: - Cleaner organization (generated files isolated) - Simpler names without .generated suffix - Easier to gitignore if desired later 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: add missing type exports for backwards compatibility Added missing exports that existed in main: - McpUiTheme, McpUiThemeSchema - McpUiDisplayMode, McpUiDisplayModeSchema - McpUiResourceCsp, McpUiResourceCspSchema - McpUiResourceMeta, McpUiResourceMetaSchema Also fixed theme/displayMode to match original values: - theme: 'light' | 'dark' (removed 'system') - displayMode: 'inline' | 'fullscreen' | 'pip' (removed 'carousel') Verified: all 47 exports from main are preserved with compatible types. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: stage generated files after prettier in pre-commit hook The pre-commit hook runs build (which generates schemas) then prettier (which formats them). The formatted generated files weren't being staged, causing CI to fail with 'Generated schemas are out of date'. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> * update generated files * fix: run prettier after regenerating schemas in CI verification CI was comparing unformatted generated output against formatted committed files, causing false 'out of date' failures. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
parent
4953cd320e
commit
f06340b6d9
10 changed files with 5346 additions and 1043 deletions
6
.github/workflows/ci.yml
vendored
6
.github/workflows/ci.yml
vendored
|
|
@ -27,6 +27,12 @@ jobs:
|
||||||
|
|
||||||
- run: npm run build:all
|
- run: npm run build:all
|
||||||
|
|
||||||
|
- name: Verify generated schemas are up-to-date
|
||||||
|
run: |
|
||||||
|
npm run generate:schemas
|
||||||
|
npm run prettier:fix
|
||||||
|
git diff --exit-code src/generated/ || (echo "Generated schemas are out of date. Run 'npm run generate:schemas' and commit." && exit 1)
|
||||||
|
|
||||||
- run: npm test
|
- run: npm test
|
||||||
|
|
||||||
- run: npm run prettier
|
- run: npm run prettier
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,5 @@
|
||||||
npm run build:all
|
npm run build:all
|
||||||
npm run prettier:fix
|
npm run prettier:fix
|
||||||
|
|
||||||
|
# Stage any changes to generated files (they may have been reformatted by prettier)
|
||||||
|
git add src/generated/
|
||||||
|
|
|
||||||
1644
package-lock.json
generated
1644
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -22,7 +22,8 @@
|
||||||
"./app-bridge": {
|
"./app-bridge": {
|
||||||
"types": "./dist/src/app-bridge.d.ts",
|
"types": "./dist/src/app-bridge.d.ts",
|
||||||
"default": "./dist/src/app-bridge.js"
|
"default": "./dist/src/app-bridge.js"
|
||||||
}
|
},
|
||||||
|
"./schema.json": "./dist/src/generated/schema.json"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist"
|
"dist"
|
||||||
|
|
@ -31,7 +32,8 @@
|
||||||
"examples/*"
|
"examples/*"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "bun build.bun.ts",
|
"generate:schemas": "tsx scripts/generate-schemas.ts",
|
||||||
|
"build": "npm run generate:schemas && bun build.bun.ts",
|
||||||
"prepack": "npm run build",
|
"prepack": "npm run build",
|
||||||
"build:all": "npm run build && npm run examples:build",
|
"build:all": "npm run build && npm run examples:build",
|
||||||
"test": "bun test",
|
"test": "bun test",
|
||||||
|
|
@ -59,6 +61,8 @@
|
||||||
"husky": "^9.1.7",
|
"husky": "^9.1.7",
|
||||||
"nodemon": "^3.1.0",
|
"nodemon": "^3.1.0",
|
||||||
"prettier": "^3.6.2",
|
"prettier": "^3.6.2",
|
||||||
|
"ts-to-zod": "^5.1.0",
|
||||||
|
"tsx": "^4.21.0",
|
||||||
"typedoc": "^0.28.14",
|
"typedoc": "^0.28.14",
|
||||||
"typescript": "^5.9.3"
|
"typescript": "^5.9.3"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
281
scripts/generate-schemas.ts
Normal file
281
scripts/generate-schemas.ts
Normal file
|
|
@ -0,0 +1,281 @@
|
||||||
|
/**
|
||||||
|
* Schema Generation Script using ts-to-zod as a library
|
||||||
|
*
|
||||||
|
* This script generates Zod schemas from spec.types.ts and performs necessary
|
||||||
|
* post-processing for compatibility with this project.
|
||||||
|
*
|
||||||
|
* ## Why Post-Processing is Needed
|
||||||
|
*
|
||||||
|
* ts-to-zod is a powerful tool but has limitations that require post-processing:
|
||||||
|
*
|
||||||
|
* ### 1. Zod Import Path (`"zod"` → `"zod/v4"`)
|
||||||
|
*
|
||||||
|
* **Problem**: ts-to-zod generates `import { z } from "zod"` but this project
|
||||||
|
* uses the Zod v4 subpath import `"zod/v4"` for explicit version targeting.
|
||||||
|
*
|
||||||
|
* **Solution**: Replace the import path in the generated output.
|
||||||
|
*
|
||||||
|
* ### 2. External Type References (`z.any()` → actual schemas)
|
||||||
|
*
|
||||||
|
* **Problem**: ts-to-zod cannot resolve types imported from external packages.
|
||||||
|
* When it encounters types like `ContentBlock`, `CallToolResult`, `Implementation`,
|
||||||
|
* `RequestId`, and `Tool` from `@modelcontextprotocol/sdk`, it generates `z.any()`
|
||||||
|
* as a placeholder.
|
||||||
|
*
|
||||||
|
* **Solution**: Import the schemas from MCP SDK and remove the z.any() placeholders.
|
||||||
|
*
|
||||||
|
* ### 3. Index Signatures (`z.record().and()` → `z.looseObject()`)
|
||||||
|
*
|
||||||
|
* **Problem**: TypeScript index signatures like `[key: string]: unknown` are
|
||||||
|
* translated by ts-to-zod to `z.record(z.string(), z.unknown()).and(z.object({...}))`.
|
||||||
|
* This creates a `ZodIntersection` type which doesn't support `.extend()` etc.
|
||||||
|
*
|
||||||
|
* **Solution**: Replace the intersection pattern with `z.looseObject()`.
|
||||||
|
*
|
||||||
|
* ## Adding Schema Descriptions
|
||||||
|
*
|
||||||
|
* ts-to-zod supports `@description` JSDoc tags to generate `.describe()` calls:
|
||||||
|
*
|
||||||
|
* ```typescript
|
||||||
|
* interface MyType {
|
||||||
|
* /** @description The user's full name */
|
||||||
|
* name: string;
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Generates: `name: z.string().describe("The user's full name")`
|
||||||
|
*
|
||||||
|
* @see https://github.com/fabien0102/ts-to-zod
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { readFileSync, writeFileSync } from "node:fs";
|
||||||
|
import { dirname, join } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
import { generate } from "ts-to-zod";
|
||||||
|
import { toJSONSchema, type $ZodType } from "zod/v4/core";
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = dirname(__filename);
|
||||||
|
const PROJECT_ROOT = join(__dirname, "..");
|
||||||
|
|
||||||
|
const SPEC_TYPES_FILE = join(PROJECT_ROOT, "src", "spec.types.ts");
|
||||||
|
const GENERATED_DIR = join(PROJECT_ROOT, "src", "generated");
|
||||||
|
const SCHEMA_OUTPUT_FILE = join(GENERATED_DIR, "schema.ts");
|
||||||
|
const SCHEMA_TEST_OUTPUT_FILE = join(GENERATED_DIR, "schema.test.ts");
|
||||||
|
const JSON_SCHEMA_OUTPUT_FILE = join(GENERATED_DIR, "schema.json");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* External types from MCP SDK that ts-to-zod can't resolve.
|
||||||
|
* With PascalCase naming (via getSchemaName), generated placeholders match MCP SDK exports.
|
||||||
|
*/
|
||||||
|
const EXTERNAL_TYPE_SCHEMAS = [
|
||||||
|
"ContentBlockSchema",
|
||||||
|
"CallToolResultSchema",
|
||||||
|
"ImplementationSchema",
|
||||||
|
"RequestIdSchema",
|
||||||
|
"ToolSchema",
|
||||||
|
];
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
console.log("🔧 Generating Zod schemas from spec.types.ts...\n");
|
||||||
|
|
||||||
|
const sourceText = readFileSync(SPEC_TYPES_FILE, "utf-8");
|
||||||
|
|
||||||
|
const result = generate({
|
||||||
|
sourceText,
|
||||||
|
keepComments: true,
|
||||||
|
skipParseJSDoc: false,
|
||||||
|
// Generate PascalCase schema names: McpUiOpenLinkRequest → McpUiOpenLinkRequestSchema
|
||||||
|
getSchemaName: (typeName: string) => `${typeName}Schema`,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (result.errors.length > 0) {
|
||||||
|
console.error("❌ Generation errors:");
|
||||||
|
for (const error of result.errors) {
|
||||||
|
console.error(` - ${error}`);
|
||||||
|
}
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.hasCircularDependencies) {
|
||||||
|
console.warn("⚠️ Warning: Circular dependencies detected in types");
|
||||||
|
}
|
||||||
|
|
||||||
|
let schemasContent = result.getZodSchemasFile("../spec.types.js");
|
||||||
|
schemasContent = postProcess(schemasContent);
|
||||||
|
|
||||||
|
writeFileSync(SCHEMA_OUTPUT_FILE, schemasContent, "utf-8");
|
||||||
|
console.log(`✅ Written: ${SCHEMA_OUTPUT_FILE}`);
|
||||||
|
|
||||||
|
const testsContent = result.getIntegrationTestFile(
|
||||||
|
"../spec.types.js",
|
||||||
|
"./schema.js",
|
||||||
|
);
|
||||||
|
if (testsContent) {
|
||||||
|
const processedTests = postProcessTests(testsContent);
|
||||||
|
writeFileSync(SCHEMA_TEST_OUTPUT_FILE, processedTests, "utf-8");
|
||||||
|
console.log(`✅ Written: ${SCHEMA_TEST_OUTPUT_FILE}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate JSON Schema from the Zod schemas
|
||||||
|
await generateJsonSchema();
|
||||||
|
|
||||||
|
console.log("\n🎉 Schema generation complete!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate JSON Schema from the Zod schemas.
|
||||||
|
* Uses dynamic import to load the generated schemas after they're written.
|
||||||
|
*/
|
||||||
|
async function generateJsonSchema() {
|
||||||
|
// Dynamic import of the generated schemas
|
||||||
|
// tsx handles TypeScript imports at runtime
|
||||||
|
const schemas = await import("../src/generated/schema.js");
|
||||||
|
|
||||||
|
const jsonSchema: {
|
||||||
|
$schema: string;
|
||||||
|
$id: string;
|
||||||
|
title: string;
|
||||||
|
description: string;
|
||||||
|
$defs: Record<string, unknown>;
|
||||||
|
} = {
|
||||||
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
||||||
|
$id: "https://modelcontextprotocol.io/ext-apps/schema.json",
|
||||||
|
title: "MCP Apps Protocol",
|
||||||
|
description: "JSON Schema for MCP Apps UI protocol messages",
|
||||||
|
$defs: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert each exported Zod schema to JSON Schema
|
||||||
|
for (const [name, schema] of Object.entries(schemas)) {
|
||||||
|
if (
|
||||||
|
name.endsWith("Schema") &&
|
||||||
|
typeof schema === "object" &&
|
||||||
|
schema !== null
|
||||||
|
) {
|
||||||
|
const typeName = name.replace(/Schema$/, "");
|
||||||
|
try {
|
||||||
|
// Use unrepresentable: "any" to handle external types (MCP SDK schemas)
|
||||||
|
// that can't be directly represented in JSON Schema
|
||||||
|
jsonSchema.$defs[typeName] = toJSONSchema(schema as $ZodType, {
|
||||||
|
unrepresentable: "any",
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.warn(`⚠️ Could not convert ${name} to JSON Schema: ${error}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
writeFileSync(
|
||||||
|
JSON_SCHEMA_OUTPUT_FILE,
|
||||||
|
JSON.stringify(jsonSchema, null, 2) + "\n",
|
||||||
|
"utf-8",
|
||||||
|
);
|
||||||
|
console.log(`✅ Written: ${JSON_SCHEMA_OUTPUT_FILE}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Post-process generated schemas for project compatibility.
|
||||||
|
*/
|
||||||
|
function postProcess(content: string): string {
|
||||||
|
// 1. Update import to use zod/v4
|
||||||
|
content = content.replace(
|
||||||
|
'import { z } from "zod";',
|
||||||
|
'import { z } from "zod/v4";',
|
||||||
|
);
|
||||||
|
|
||||||
|
// 2. Add MCP SDK schema imports
|
||||||
|
const mcpImports = EXTERNAL_TYPE_SCHEMAS.join(",\n ");
|
||||||
|
content = content.replace(
|
||||||
|
'import { z } from "zod/v4";',
|
||||||
|
`import { z } from "zod/v4";
|
||||||
|
import {
|
||||||
|
${mcpImports},
|
||||||
|
} from "@modelcontextprotocol/sdk/types.js";`,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 3. Remove z.any() placeholders for external types (now imported from MCP SDK)
|
||||||
|
for (const schema of EXTERNAL_TYPE_SCHEMAS) {
|
||||||
|
content = content.replace(
|
||||||
|
new RegExp(`(?:export )?const ${schema} = z\\.any\\(\\);\\n?`, "g"),
|
||||||
|
"",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Replace z.record().and(z.object({...})) with z.looseObject({...})
|
||||||
|
// Uses brace-counting to handle nested objects correctly.
|
||||||
|
content = replaceRecordAndWithLooseObject(content);
|
||||||
|
|
||||||
|
// 5. Add header comment
|
||||||
|
content = content.replace(
|
||||||
|
"// Generated by ts-to-zod",
|
||||||
|
`// Generated by ts-to-zod
|
||||||
|
// Post-processed for Zod v4 and MCP SDK compatibility
|
||||||
|
// Run: npm run generate:schemas`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace z.record(z.string(), z.unknown()).and(z.object({...})) with z.looseObject({...})
|
||||||
|
* Uses brace-counting to handle nested objects correctly.
|
||||||
|
*/
|
||||||
|
function replaceRecordAndWithLooseObject(content: string): string {
|
||||||
|
const pattern = "z.record(z.string(), z.unknown()).and(z.object({";
|
||||||
|
let result = content;
|
||||||
|
let startIndex = 0;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const matchStart = result.indexOf(pattern, startIndex);
|
||||||
|
if (matchStart === -1) break;
|
||||||
|
|
||||||
|
// Find the matching closing brace for z.object({
|
||||||
|
const objectStart = matchStart + pattern.length;
|
||||||
|
let braceCount = 1;
|
||||||
|
let i = objectStart;
|
||||||
|
|
||||||
|
while (i < result.length && braceCount > 0) {
|
||||||
|
if (result[i] === "{") braceCount++;
|
||||||
|
else if (result[i] === "}") braceCount--;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// i now points after the closing } of z.object({...})
|
||||||
|
// Check if followed by ))
|
||||||
|
if (result.slice(i, i + 2) === "))") {
|
||||||
|
const objectContent = result.slice(objectStart, i - 1);
|
||||||
|
const replacement = `z.looseObject({${objectContent}})`;
|
||||||
|
result = result.slice(0, matchStart) + replacement + result.slice(i + 2);
|
||||||
|
startIndex = matchStart + replacement.length;
|
||||||
|
} else {
|
||||||
|
startIndex = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Post-process generated integration tests.
|
||||||
|
*/
|
||||||
|
function postProcessTests(content: string): string {
|
||||||
|
content = content.replace(
|
||||||
|
'import { z } from "zod";',
|
||||||
|
'import { z } from "zod/v4";',
|
||||||
|
);
|
||||||
|
|
||||||
|
content = content.replace(
|
||||||
|
"// Generated by ts-to-zod",
|
||||||
|
`// Generated by ts-to-zod
|
||||||
|
// Integration tests verifying schemas match TypeScript types
|
||||||
|
// Run: npm run generate:schemas`,
|
||||||
|
);
|
||||||
|
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch((error) => {
|
||||||
|
console.error("❌ Schema generation failed:", error);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
2151
src/generated/schema.json
Normal file
2151
src/generated/schema.json
Normal file
File diff suppressed because it is too large
Load diff
219
src/generated/schema.test.ts
Normal file
219
src/generated/schema.test.ts
Normal file
|
|
@ -0,0 +1,219 @@
|
||||||
|
// Generated by ts-to-zod
|
||||||
|
// Integration tests verifying schemas match TypeScript types
|
||||||
|
// Run: npm run generate:schemas
|
||||||
|
import { z } from "zod/v4";
|
||||||
|
|
||||||
|
import * as spec from "../spec.types.js";
|
||||||
|
import * as generated from "./schema.js";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
function expectType<T>(_: T) {
|
||||||
|
/* noop */
|
||||||
|
}
|
||||||
|
|
||||||
|
export type McpUiThemeSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiThemeSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiDisplayModeSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiDisplayModeSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiOpenLinkRequestSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiOpenLinkRequestSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiOpenLinkResultSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiOpenLinkResultSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiMessageResultSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiMessageResultSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiSandboxProxyReadyNotificationSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiSandboxProxyReadyNotificationSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiSandboxResourceReadyNotificationSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiSandboxResourceReadyNotificationSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiSizeChangedNotificationSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiSizeChangedNotificationSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiToolInputNotificationSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiToolInputNotificationSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiToolInputPartialNotificationSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiToolInputPartialNotificationSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiResourceTeardownRequestSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiResourceTeardownRequestSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiResourceTeardownResultSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiResourceTeardownResultSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiHostCapabilitiesSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiHostCapabilitiesSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiAppCapabilitiesSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiAppCapabilitiesSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiInitializedNotificationSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiInitializedNotificationSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiResourceCspSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiResourceCspSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiResourceMetaSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiResourceMetaSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiMessageRequestSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiMessageRequestSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiToolResultNotificationSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiToolResultNotificationSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiHostContextSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiHostContextSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiHostContextChangedNotificationSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiHostContextChangedNotificationSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiInitializeRequestSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiInitializeRequestSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
export type McpUiInitializeResultSchemaInferredType = z.infer<
|
||||||
|
typeof generated.McpUiInitializeResultSchema
|
||||||
|
>;
|
||||||
|
|
||||||
|
expectType<spec.McpUiTheme>({} as McpUiThemeSchemaInferredType);
|
||||||
|
expectType<McpUiThemeSchemaInferredType>({} as spec.McpUiTheme);
|
||||||
|
expectType<spec.McpUiDisplayMode>({} as McpUiDisplayModeSchemaInferredType);
|
||||||
|
expectType<McpUiDisplayModeSchemaInferredType>({} as spec.McpUiDisplayMode);
|
||||||
|
expectType<spec.McpUiOpenLinkRequest>(
|
||||||
|
{} as McpUiOpenLinkRequestSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiOpenLinkRequestSchemaInferredType>(
|
||||||
|
{} as spec.McpUiOpenLinkRequest,
|
||||||
|
);
|
||||||
|
expectType<spec.McpUiOpenLinkResult>(
|
||||||
|
{} as McpUiOpenLinkResultSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiOpenLinkResultSchemaInferredType>(
|
||||||
|
{} as spec.McpUiOpenLinkResult,
|
||||||
|
);
|
||||||
|
expectType<spec.McpUiMessageResult>({} as McpUiMessageResultSchemaInferredType);
|
||||||
|
expectType<McpUiMessageResultSchemaInferredType>({} as spec.McpUiMessageResult);
|
||||||
|
expectType<spec.McpUiSandboxProxyReadyNotification>(
|
||||||
|
{} as McpUiSandboxProxyReadyNotificationSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiSandboxProxyReadyNotificationSchemaInferredType>(
|
||||||
|
{} as spec.McpUiSandboxProxyReadyNotification,
|
||||||
|
);
|
||||||
|
expectType<spec.McpUiSandboxResourceReadyNotification>(
|
||||||
|
{} as McpUiSandboxResourceReadyNotificationSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiSandboxResourceReadyNotificationSchemaInferredType>(
|
||||||
|
{} as spec.McpUiSandboxResourceReadyNotification,
|
||||||
|
);
|
||||||
|
expectType<spec.McpUiSizeChangedNotification>(
|
||||||
|
{} as McpUiSizeChangedNotificationSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiSizeChangedNotificationSchemaInferredType>(
|
||||||
|
{} as spec.McpUiSizeChangedNotification,
|
||||||
|
);
|
||||||
|
expectType<spec.McpUiToolInputNotification>(
|
||||||
|
{} as McpUiToolInputNotificationSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiToolInputNotificationSchemaInferredType>(
|
||||||
|
{} as spec.McpUiToolInputNotification,
|
||||||
|
);
|
||||||
|
expectType<spec.McpUiToolInputPartialNotification>(
|
||||||
|
{} as McpUiToolInputPartialNotificationSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiToolInputPartialNotificationSchemaInferredType>(
|
||||||
|
{} as spec.McpUiToolInputPartialNotification,
|
||||||
|
);
|
||||||
|
expectType<spec.McpUiResourceTeardownRequest>(
|
||||||
|
{} as McpUiResourceTeardownRequestSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiResourceTeardownRequestSchemaInferredType>(
|
||||||
|
{} as spec.McpUiResourceTeardownRequest,
|
||||||
|
);
|
||||||
|
expectType<spec.McpUiResourceTeardownResult>(
|
||||||
|
{} as McpUiResourceTeardownResultSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiResourceTeardownResultSchemaInferredType>(
|
||||||
|
{} as spec.McpUiResourceTeardownResult,
|
||||||
|
);
|
||||||
|
expectType<spec.McpUiHostCapabilities>(
|
||||||
|
{} as McpUiHostCapabilitiesSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiHostCapabilitiesSchemaInferredType>(
|
||||||
|
{} as spec.McpUiHostCapabilities,
|
||||||
|
);
|
||||||
|
expectType<spec.McpUiAppCapabilities>(
|
||||||
|
{} as McpUiAppCapabilitiesSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiAppCapabilitiesSchemaInferredType>(
|
||||||
|
{} as spec.McpUiAppCapabilities,
|
||||||
|
);
|
||||||
|
expectType<spec.McpUiInitializedNotification>(
|
||||||
|
{} as McpUiInitializedNotificationSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiInitializedNotificationSchemaInferredType>(
|
||||||
|
{} as spec.McpUiInitializedNotification,
|
||||||
|
);
|
||||||
|
expectType<spec.McpUiResourceCsp>({} as McpUiResourceCspSchemaInferredType);
|
||||||
|
expectType<McpUiResourceCspSchemaInferredType>({} as spec.McpUiResourceCsp);
|
||||||
|
expectType<spec.McpUiResourceMeta>({} as McpUiResourceMetaSchemaInferredType);
|
||||||
|
expectType<McpUiResourceMetaSchemaInferredType>({} as spec.McpUiResourceMeta);
|
||||||
|
expectType<spec.McpUiMessageRequest>(
|
||||||
|
{} as McpUiMessageRequestSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiMessageRequestSchemaInferredType>(
|
||||||
|
{} as spec.McpUiMessageRequest,
|
||||||
|
);
|
||||||
|
expectType<spec.McpUiToolResultNotification>(
|
||||||
|
{} as McpUiToolResultNotificationSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiToolResultNotificationSchemaInferredType>(
|
||||||
|
{} as spec.McpUiToolResultNotification,
|
||||||
|
);
|
||||||
|
expectType<spec.McpUiHostContext>({} as McpUiHostContextSchemaInferredType);
|
||||||
|
expectType<McpUiHostContextSchemaInferredType>({} as spec.McpUiHostContext);
|
||||||
|
expectType<spec.McpUiHostContextChangedNotification>(
|
||||||
|
{} as McpUiHostContextChangedNotificationSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiHostContextChangedNotificationSchemaInferredType>(
|
||||||
|
{} as spec.McpUiHostContextChangedNotification,
|
||||||
|
);
|
||||||
|
expectType<spec.McpUiInitializeRequest>(
|
||||||
|
{} as McpUiInitializeRequestSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiInitializeRequestSchemaInferredType>(
|
||||||
|
{} as spec.McpUiInitializeRequest,
|
||||||
|
);
|
||||||
|
expectType<spec.McpUiInitializeResult>(
|
||||||
|
{} as McpUiInitializeResultSchemaInferredType,
|
||||||
|
);
|
||||||
|
expectType<McpUiInitializeResultSchemaInferredType>(
|
||||||
|
{} as spec.McpUiInitializeResult,
|
||||||
|
);
|
||||||
467
src/generated/schema.ts
Normal file
467
src/generated/schema.ts
Normal file
|
|
@ -0,0 +1,467 @@
|
||||||
|
// Generated by ts-to-zod
|
||||||
|
// Post-processed for Zod v4 and MCP SDK compatibility
|
||||||
|
// Run: npm run generate:schemas
|
||||||
|
import { z } from "zod/v4";
|
||||||
|
import {
|
||||||
|
ContentBlockSchema,
|
||||||
|
CallToolResultSchema,
|
||||||
|
ImplementationSchema,
|
||||||
|
RequestIdSchema,
|
||||||
|
ToolSchema,
|
||||||
|
} from "@modelcontextprotocol/sdk/types.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Color theme preference for the host environment.
|
||||||
|
*/
|
||||||
|
export const McpUiThemeSchema = z
|
||||||
|
.union([z.literal("light"), z.literal("dark")])
|
||||||
|
.describe("Color theme preference for the host environment.");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Display mode for UI presentation.
|
||||||
|
*/
|
||||||
|
export const McpUiDisplayModeSchema = z
|
||||||
|
.union([z.literal("inline"), z.literal("fullscreen"), z.literal("pip")])
|
||||||
|
.describe("Display mode for UI presentation.");
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Request to open an external URL in the host's default browser.
|
||||||
|
* @see {@link app.App.sendOpenLink} for the method that sends this request
|
||||||
|
*/
|
||||||
|
export const McpUiOpenLinkRequestSchema = z.object({
|
||||||
|
method: z.literal("ui/open-link"),
|
||||||
|
params: z.object({
|
||||||
|
/** @description URL to open in the host's browser */
|
||||||
|
url: z.string().describe("URL to open in the host's browser"),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Result from opening a URL.
|
||||||
|
* @see {@link McpUiOpenLinkRequest}
|
||||||
|
*/
|
||||||
|
export const McpUiOpenLinkResultSchema = z.looseObject({
|
||||||
|
/** @description True if the host failed to open the URL (e.g., due to security policy). */
|
||||||
|
isError: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe(
|
||||||
|
"True if the host failed to open the URL (e.g., due to security policy).",
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Result from sending a message.
|
||||||
|
* @see {@link McpUiMessageRequest}
|
||||||
|
*/
|
||||||
|
export const McpUiMessageResultSchema = z.looseObject({
|
||||||
|
/** @description True if the host rejected or failed to deliver the message. */
|
||||||
|
isError: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("True if the host rejected or failed to deliver the message."),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Notification that the sandbox proxy iframe is ready to receive content.
|
||||||
|
* @internal
|
||||||
|
* @see https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx#sandbox-proxy
|
||||||
|
*/
|
||||||
|
export const McpUiSandboxProxyReadyNotificationSchema = z.object({
|
||||||
|
method: z.literal("ui/notifications/sandbox-proxy-ready"),
|
||||||
|
params: z.object({}),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Notification containing HTML resource for the sandbox proxy to load.
|
||||||
|
* @internal
|
||||||
|
* @see https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx#sandbox-proxy
|
||||||
|
*/
|
||||||
|
export const McpUiSandboxResourceReadyNotificationSchema = z.object({
|
||||||
|
method: z.literal("ui/notifications/sandbox-resource-ready"),
|
||||||
|
params: z.object({
|
||||||
|
/** @description HTML content to load into the inner iframe. */
|
||||||
|
html: z.string().describe("HTML content to load into the inner iframe."),
|
||||||
|
/** @description Optional override for the inner iframe's sandbox attribute. */
|
||||||
|
sandbox: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Optional override for the inner iframe's sandbox attribute."),
|
||||||
|
/** @description CSP configuration from resource metadata. */
|
||||||
|
csp: z
|
||||||
|
.object({
|
||||||
|
/** @description Origins for network requests (fetch/XHR/WebSocket). */
|
||||||
|
connectDomains: z
|
||||||
|
.array(z.string())
|
||||||
|
.optional()
|
||||||
|
.describe("Origins for network requests (fetch/XHR/WebSocket)."),
|
||||||
|
/** @description Origins for static resources (scripts, images, styles, fonts). */
|
||||||
|
resourceDomains: z
|
||||||
|
.array(z.string())
|
||||||
|
.optional()
|
||||||
|
.describe(
|
||||||
|
"Origins for static resources (scripts, images, styles, fonts).",
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.describe("CSP configuration from resource metadata."),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Notification of UI size changes (bidirectional: Guest <-> Host).
|
||||||
|
* @see {@link app.App.sendSizeChanged} for the method to send this from Guest UI
|
||||||
|
*/
|
||||||
|
export const McpUiSizeChangedNotificationSchema = z.object({
|
||||||
|
method: z.literal("ui/notifications/size-changed"),
|
||||||
|
params: z.object({
|
||||||
|
/** @description New width in pixels. */
|
||||||
|
width: z.number().optional().describe("New width in pixels."),
|
||||||
|
/** @description New height in pixels. */
|
||||||
|
height: z.number().optional().describe("New height in pixels."),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Notification containing complete tool arguments (Host -> Guest UI).
|
||||||
|
*/
|
||||||
|
export const McpUiToolInputNotificationSchema = z.object({
|
||||||
|
method: z.literal("ui/notifications/tool-input"),
|
||||||
|
params: z.object({
|
||||||
|
/** @description Complete tool call arguments as key-value pairs. */
|
||||||
|
arguments: z
|
||||||
|
.record(
|
||||||
|
z.string(),
|
||||||
|
z
|
||||||
|
.unknown()
|
||||||
|
.describe("Complete tool call arguments as key-value pairs."),
|
||||||
|
)
|
||||||
|
.optional()
|
||||||
|
.describe("Complete tool call arguments as key-value pairs."),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Notification containing partial/streaming tool arguments (Host -> Guest UI).
|
||||||
|
*/
|
||||||
|
export const McpUiToolInputPartialNotificationSchema = z.object({
|
||||||
|
method: z.literal("ui/notifications/tool-input-partial"),
|
||||||
|
params: z.object({
|
||||||
|
/** @description Partial tool call arguments (incomplete, may change). */
|
||||||
|
arguments: z
|
||||||
|
.record(
|
||||||
|
z.string(),
|
||||||
|
z
|
||||||
|
.unknown()
|
||||||
|
.describe("Partial tool call arguments (incomplete, may change)."),
|
||||||
|
)
|
||||||
|
.optional()
|
||||||
|
.describe("Partial tool call arguments (incomplete, may change)."),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Request for graceful shutdown of the Guest UI (Host -> Guest UI).
|
||||||
|
* @see {@link app-bridge.AppBridge.sendResourceTeardown} for the host method that sends this
|
||||||
|
*/
|
||||||
|
export const McpUiResourceTeardownRequestSchema = z.object({
|
||||||
|
method: z.literal("ui/resource-teardown"),
|
||||||
|
params: z.object({}),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Result from graceful shutdown request.
|
||||||
|
* @see {@link McpUiResourceTeardownRequest}
|
||||||
|
*/
|
||||||
|
export const McpUiResourceTeardownResultSchema = z.record(
|
||||||
|
z.string(),
|
||||||
|
z.unknown(),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Capabilities supported by the host application.
|
||||||
|
* @see {@link McpUiInitializeResult} for the initialization result that includes these capabilities
|
||||||
|
*/
|
||||||
|
export const McpUiHostCapabilitiesSchema = z.object({
|
||||||
|
/** @description Experimental features (structure TBD). */
|
||||||
|
experimental: z
|
||||||
|
.object({})
|
||||||
|
.optional()
|
||||||
|
.describe("Experimental features (structure TBD)."),
|
||||||
|
/** @description Host supports opening external URLs. */
|
||||||
|
openLinks: z
|
||||||
|
.object({})
|
||||||
|
.optional()
|
||||||
|
.describe("Host supports opening external URLs."),
|
||||||
|
/** @description Host can proxy tool calls to the MCP server. */
|
||||||
|
serverTools: z
|
||||||
|
.object({
|
||||||
|
/** @description Host supports tools/list_changed notifications. */
|
||||||
|
listChanged: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Host supports tools/list_changed notifications."),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.describe("Host can proxy tool calls to the MCP server."),
|
||||||
|
/** @description Host can proxy resource reads to the MCP server. */
|
||||||
|
serverResources: z
|
||||||
|
.object({
|
||||||
|
/** @description Host supports resources/list_changed notifications. */
|
||||||
|
listChanged: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Host supports resources/list_changed notifications."),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.describe("Host can proxy resource reads to the MCP server."),
|
||||||
|
/** @description Host accepts log messages. */
|
||||||
|
logging: z.object({}).optional().describe("Host accepts log messages."),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Capabilities provided by the Guest UI (App).
|
||||||
|
* @see {@link McpUiInitializeRequest} for the initialization request that includes these capabilities
|
||||||
|
*/
|
||||||
|
export const McpUiAppCapabilitiesSchema = z.object({
|
||||||
|
/** @description Experimental features (structure TBD). */
|
||||||
|
experimental: z
|
||||||
|
.object({})
|
||||||
|
.optional()
|
||||||
|
.describe("Experimental features (structure TBD)."),
|
||||||
|
/** @description App exposes MCP-style tools that the host can call. */
|
||||||
|
tools: z
|
||||||
|
.object({
|
||||||
|
/** @description App supports tools/list_changed notifications. */
|
||||||
|
listChanged: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("App supports tools/list_changed notifications."),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.describe("App exposes MCP-style tools that the host can call."),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Notification that Guest UI has completed initialization (Guest UI -> Host).
|
||||||
|
* @see {@link app.App.connect} for the method that sends this notification
|
||||||
|
*/
|
||||||
|
export const McpUiInitializedNotificationSchema = z.object({
|
||||||
|
method: z.literal("ui/notifications/initialized"),
|
||||||
|
params: z.object({}).optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Content Security Policy configuration for UI resources.
|
||||||
|
*/
|
||||||
|
export const McpUiResourceCspSchema = z.object({
|
||||||
|
/** @description Origins for network requests (fetch/XHR/WebSocket). */
|
||||||
|
connectDomains: z
|
||||||
|
.array(z.string())
|
||||||
|
.optional()
|
||||||
|
.describe("Origins for network requests (fetch/XHR/WebSocket)."),
|
||||||
|
/** @description Origins for static resources (scripts, images, styles, fonts). */
|
||||||
|
resourceDomains: z
|
||||||
|
.array(z.string())
|
||||||
|
.optional()
|
||||||
|
.describe("Origins for static resources (scripts, images, styles, fonts)."),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description UI Resource metadata for security and rendering configuration.
|
||||||
|
*/
|
||||||
|
export const McpUiResourceMetaSchema = z.object({
|
||||||
|
/** @description Content Security Policy configuration. */
|
||||||
|
csp: McpUiResourceCspSchema.optional().describe(
|
||||||
|
"Content Security Policy configuration.",
|
||||||
|
),
|
||||||
|
/** @description Dedicated origin for widget sandbox. */
|
||||||
|
domain: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Dedicated origin for widget sandbox."),
|
||||||
|
/** @description Visual boundary preference - true if UI prefers a visible border. */
|
||||||
|
prefersBorder: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe(
|
||||||
|
"Visual boundary preference - true if UI prefers a visible border.",
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Request to send a message to the host's chat interface.
|
||||||
|
* @see {@link app.App.sendMessage} for the method that sends this request
|
||||||
|
*/
|
||||||
|
export const McpUiMessageRequestSchema = z.object({
|
||||||
|
method: z.literal("ui/message"),
|
||||||
|
params: z.object({
|
||||||
|
/** @description Message role, currently only "user" is supported. */
|
||||||
|
role: z
|
||||||
|
.literal("user")
|
||||||
|
.describe('Message role, currently only "user" is supported.'),
|
||||||
|
/** @description Message content blocks (text, image, etc.). */
|
||||||
|
content: z
|
||||||
|
.array(ContentBlockSchema)
|
||||||
|
.describe("Message content blocks (text, image, etc.)."),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Notification containing tool execution result (Host -> Guest UI).
|
||||||
|
*/
|
||||||
|
export const McpUiToolResultNotificationSchema = z.object({
|
||||||
|
method: z.literal("ui/notifications/tool-result"),
|
||||||
|
/** @description Standard MCP tool execution result. */
|
||||||
|
params: CallToolResultSchema.describe("Standard MCP tool execution result."),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Rich context about the host environment provided to Guest UIs.
|
||||||
|
*/
|
||||||
|
export const McpUiHostContextSchema = z.object({
|
||||||
|
/** @description Metadata of the tool call that instantiated this App. */
|
||||||
|
toolInfo: z
|
||||||
|
.object({
|
||||||
|
/** @description JSON-RPC id of the tools/call request. */
|
||||||
|
id: RequestIdSchema.describe("JSON-RPC id of the tools/call request."),
|
||||||
|
/** @description Tool definition including name, inputSchema, etc. */
|
||||||
|
tool: ToolSchema.describe(
|
||||||
|
"Tool definition including name, inputSchema, etc.",
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.describe("Metadata of the tool call that instantiated this App."),
|
||||||
|
/** @description Current color theme preference. */
|
||||||
|
theme: McpUiThemeSchema.optional().describe(
|
||||||
|
"Current color theme preference.",
|
||||||
|
),
|
||||||
|
/** @description How the UI is currently displayed. */
|
||||||
|
displayMode: McpUiDisplayModeSchema.optional().describe(
|
||||||
|
"How the UI is currently displayed.",
|
||||||
|
),
|
||||||
|
/** @description Display modes the host supports. */
|
||||||
|
availableDisplayModes: z
|
||||||
|
.array(z.string())
|
||||||
|
.optional()
|
||||||
|
.describe("Display modes the host supports."),
|
||||||
|
/** @description Current and maximum dimensions available to the UI. */
|
||||||
|
viewport: z
|
||||||
|
.object({
|
||||||
|
/** @description Current viewport width in pixels. */
|
||||||
|
width: z.number().describe("Current viewport width in pixels."),
|
||||||
|
/** @description Current viewport height in pixels. */
|
||||||
|
height: z.number().describe("Current viewport height in pixels."),
|
||||||
|
/** @description Maximum available height in pixels (if constrained). */
|
||||||
|
maxHeight: z
|
||||||
|
.number()
|
||||||
|
.optional()
|
||||||
|
.describe("Maximum available height in pixels (if constrained)."),
|
||||||
|
/** @description Maximum available width in pixels (if constrained). */
|
||||||
|
maxWidth: z
|
||||||
|
.number()
|
||||||
|
.optional()
|
||||||
|
.describe("Maximum available width in pixels (if constrained)."),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.describe("Current and maximum dimensions available to the UI."),
|
||||||
|
/** @description User's language and region preference in BCP 47 format. */
|
||||||
|
locale: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("User's language and region preference in BCP 47 format."),
|
||||||
|
/** @description User's timezone in IANA format. */
|
||||||
|
timeZone: z.string().optional().describe("User's timezone in IANA format."),
|
||||||
|
/** @description Host application identifier. */
|
||||||
|
userAgent: z.string().optional().describe("Host application identifier."),
|
||||||
|
/** @description Platform type for responsive design decisions. */
|
||||||
|
platform: z
|
||||||
|
.union([z.literal("web"), z.literal("desktop"), z.literal("mobile")])
|
||||||
|
.optional()
|
||||||
|
.describe("Platform type for responsive design decisions."),
|
||||||
|
/** @description Device input capabilities. */
|
||||||
|
deviceCapabilities: z
|
||||||
|
.object({
|
||||||
|
/** @description Whether the device supports touch input. */
|
||||||
|
touch: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Whether the device supports touch input."),
|
||||||
|
/** @description Whether the device supports hover interactions. */
|
||||||
|
hover: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Whether the device supports hover interactions."),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.describe("Device input capabilities."),
|
||||||
|
/** @description Mobile safe area boundaries in pixels. */
|
||||||
|
safeAreaInsets: z
|
||||||
|
.object({
|
||||||
|
/** @description Top safe area inset in pixels. */
|
||||||
|
top: z.number().describe("Top safe area inset in pixels."),
|
||||||
|
/** @description Right safe area inset in pixels. */
|
||||||
|
right: z.number().describe("Right safe area inset in pixels."),
|
||||||
|
/** @description Bottom safe area inset in pixels. */
|
||||||
|
bottom: z.number().describe("Bottom safe area inset in pixels."),
|
||||||
|
/** @description Left safe area inset in pixels. */
|
||||||
|
left: z.number().describe("Left safe area inset in pixels."),
|
||||||
|
})
|
||||||
|
.optional()
|
||||||
|
.describe("Mobile safe area boundaries in pixels."),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Notification that host context has changed (Host -> Guest UI).
|
||||||
|
* @see {@link McpUiHostContext} for the full context structure
|
||||||
|
*/
|
||||||
|
export const McpUiHostContextChangedNotificationSchema = z.object({
|
||||||
|
method: z.literal("ui/notifications/host-context-changed"),
|
||||||
|
/** @description Partial context update containing only changed fields. */
|
||||||
|
params: McpUiHostContextSchema.describe(
|
||||||
|
"Partial context update containing only changed fields.",
|
||||||
|
),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Initialization request sent from Guest UI to Host.
|
||||||
|
* @see {@link app.App.connect} for the method that sends this request
|
||||||
|
*/
|
||||||
|
export const McpUiInitializeRequestSchema = z.object({
|
||||||
|
method: z.literal("ui/initialize"),
|
||||||
|
params: z.object({
|
||||||
|
/** @description App identification (name and version). */
|
||||||
|
appInfo: ImplementationSchema.describe(
|
||||||
|
"App identification (name and version).",
|
||||||
|
),
|
||||||
|
/** @description Features and capabilities this app provides. */
|
||||||
|
appCapabilities: McpUiAppCapabilitiesSchema.describe(
|
||||||
|
"Features and capabilities this app provides.",
|
||||||
|
),
|
||||||
|
/** @description Protocol version this app supports. */
|
||||||
|
protocolVersion: z.string().describe("Protocol version this app supports."),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Initialization result returned from Host to Guest UI.
|
||||||
|
* @see {@link McpUiInitializeRequest}
|
||||||
|
*/
|
||||||
|
export const McpUiInitializeResultSchema = z.looseObject({
|
||||||
|
/** @description Negotiated protocol version string (e.g., "2025-11-21"). */
|
||||||
|
protocolVersion: z
|
||||||
|
.string()
|
||||||
|
.describe('Negotiated protocol version string (e.g., "2025-11-21").'),
|
||||||
|
/** @description Host application identification and version. */
|
||||||
|
hostInfo: ImplementationSchema.describe(
|
||||||
|
"Host application identification and version.",
|
||||||
|
),
|
||||||
|
/** @description Features and capabilities provided by the host. */
|
||||||
|
hostCapabilities: McpUiHostCapabilitiesSchema.describe(
|
||||||
|
"Features and capabilities provided by the host.",
|
||||||
|
),
|
||||||
|
/** @description Rich context about the host environment. */
|
||||||
|
hostContext: McpUiHostContextSchema.describe(
|
||||||
|
"Rich context about the host environment.",
|
||||||
|
),
|
||||||
|
});
|
||||||
358
src/spec.types.ts
Normal file
358
src/spec.types.ts
Normal file
|
|
@ -0,0 +1,358 @@
|
||||||
|
/**
|
||||||
|
* MCP Apps Protocol Types (spec.types.ts)
|
||||||
|
*
|
||||||
|
* This file contains pure TypeScript interface definitions for the MCP Apps protocol.
|
||||||
|
* These types are the source of truth and are used to generate Zod schemas via ts-to-zod.
|
||||||
|
*
|
||||||
|
* - Use `@description` JSDoc tags to generate `.describe()` calls on schemas
|
||||||
|
* - Run `npm run generate:schemas` to regenerate schemas from these types
|
||||||
|
*
|
||||||
|
* @see https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx
|
||||||
|
*/
|
||||||
|
|
||||||
|
import type {
|
||||||
|
CallToolResult,
|
||||||
|
ContentBlock,
|
||||||
|
Implementation,
|
||||||
|
RequestId,
|
||||||
|
Tool,
|
||||||
|
} from "@modelcontextprotocol/sdk/types.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Current protocol version supported by this SDK.
|
||||||
|
*
|
||||||
|
* The SDK automatically handles version negotiation during initialization.
|
||||||
|
* Apps and hosts don't need to manage protocol versions manually.
|
||||||
|
*/
|
||||||
|
export const LATEST_PROTOCOL_VERSION = "2025-11-21";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Color theme preference for the host environment.
|
||||||
|
*/
|
||||||
|
export type McpUiTheme = "light" | "dark";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Display mode for UI presentation.
|
||||||
|
*/
|
||||||
|
export type McpUiDisplayMode = "inline" | "fullscreen" | "pip";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Request to open an external URL in the host's default browser.
|
||||||
|
* @see {@link app.App.sendOpenLink} for the method that sends this request
|
||||||
|
*/
|
||||||
|
export interface McpUiOpenLinkRequest {
|
||||||
|
method: "ui/open-link";
|
||||||
|
params: {
|
||||||
|
/** @description URL to open in the host's browser */
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Result from opening a URL.
|
||||||
|
* @see {@link McpUiOpenLinkRequest}
|
||||||
|
*/
|
||||||
|
export interface McpUiOpenLinkResult {
|
||||||
|
/** @description True if the host failed to open the URL (e.g., due to security policy). */
|
||||||
|
isError?: boolean;
|
||||||
|
/**
|
||||||
|
* Index signature required for MCP SDK `Protocol` class compatibility.
|
||||||
|
* Note: The schema intentionally omits this to enforce strict validation.
|
||||||
|
*/
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Request to send a message to the host's chat interface.
|
||||||
|
* @see {@link app.App.sendMessage} for the method that sends this request
|
||||||
|
*/
|
||||||
|
export interface McpUiMessageRequest {
|
||||||
|
method: "ui/message";
|
||||||
|
params: {
|
||||||
|
/** @description Message role, currently only "user" is supported. */
|
||||||
|
role: "user";
|
||||||
|
/** @description Message content blocks (text, image, etc.). */
|
||||||
|
content: ContentBlock[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Result from sending a message.
|
||||||
|
* @see {@link McpUiMessageRequest}
|
||||||
|
*/
|
||||||
|
export interface McpUiMessageResult {
|
||||||
|
/** @description True if the host rejected or failed to deliver the message. */
|
||||||
|
isError?: boolean;
|
||||||
|
/**
|
||||||
|
* Index signature required for MCP SDK `Protocol` class compatibility.
|
||||||
|
* Note: The schema intentionally omits this to enforce strict validation.
|
||||||
|
*/
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Notification that the sandbox proxy iframe is ready to receive content.
|
||||||
|
* @internal
|
||||||
|
* @see https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx#sandbox-proxy
|
||||||
|
*/
|
||||||
|
export interface McpUiSandboxProxyReadyNotification {
|
||||||
|
method: "ui/notifications/sandbox-proxy-ready";
|
||||||
|
params: {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Notification containing HTML resource for the sandbox proxy to load.
|
||||||
|
* @internal
|
||||||
|
* @see https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx#sandbox-proxy
|
||||||
|
*/
|
||||||
|
export interface McpUiSandboxResourceReadyNotification {
|
||||||
|
method: "ui/notifications/sandbox-resource-ready";
|
||||||
|
params: {
|
||||||
|
/** @description HTML content to load into the inner iframe. */
|
||||||
|
html: string;
|
||||||
|
/** @description Optional override for the inner iframe's sandbox attribute. */
|
||||||
|
sandbox?: string;
|
||||||
|
/** @description CSP configuration from resource metadata. */
|
||||||
|
csp?: {
|
||||||
|
/** @description Origins for network requests (fetch/XHR/WebSocket). */
|
||||||
|
connectDomains?: string[];
|
||||||
|
/** @description Origins for static resources (scripts, images, styles, fonts). */
|
||||||
|
resourceDomains?: string[];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Notification of UI size changes (bidirectional: Guest <-> Host).
|
||||||
|
* @see {@link app.App.sendSizeChanged} for the method to send this from Guest UI
|
||||||
|
*/
|
||||||
|
export interface McpUiSizeChangedNotification {
|
||||||
|
method: "ui/notifications/size-changed";
|
||||||
|
params: {
|
||||||
|
/** @description New width in pixels. */
|
||||||
|
width?: number;
|
||||||
|
/** @description New height in pixels. */
|
||||||
|
height?: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Notification containing complete tool arguments (Host -> Guest UI).
|
||||||
|
*/
|
||||||
|
export interface McpUiToolInputNotification {
|
||||||
|
method: "ui/notifications/tool-input";
|
||||||
|
params: {
|
||||||
|
/** @description Complete tool call arguments as key-value pairs. */
|
||||||
|
arguments?: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Notification containing partial/streaming tool arguments (Host -> Guest UI).
|
||||||
|
*/
|
||||||
|
export interface McpUiToolInputPartialNotification {
|
||||||
|
method: "ui/notifications/tool-input-partial";
|
||||||
|
params: {
|
||||||
|
/** @description Partial tool call arguments (incomplete, may change). */
|
||||||
|
arguments?: Record<string, unknown>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Notification containing tool execution result (Host -> Guest UI).
|
||||||
|
*/
|
||||||
|
export interface McpUiToolResultNotification {
|
||||||
|
method: "ui/notifications/tool-result";
|
||||||
|
/** @description Standard MCP tool execution result. */
|
||||||
|
params: CallToolResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Rich context about the host environment provided to Guest UIs.
|
||||||
|
*/
|
||||||
|
export interface McpUiHostContext {
|
||||||
|
/** @description Metadata of the tool call that instantiated this App. */
|
||||||
|
toolInfo?: {
|
||||||
|
/** @description JSON-RPC id of the tools/call request. */
|
||||||
|
id: RequestId;
|
||||||
|
/** @description Tool definition including name, inputSchema, etc. */
|
||||||
|
tool: Tool;
|
||||||
|
};
|
||||||
|
/** @description Current color theme preference. */
|
||||||
|
theme?: McpUiTheme;
|
||||||
|
/** @description How the UI is currently displayed. */
|
||||||
|
displayMode?: McpUiDisplayMode;
|
||||||
|
/** @description Display modes the host supports. */
|
||||||
|
availableDisplayModes?: string[];
|
||||||
|
/** @description Current and maximum dimensions available to the UI. */
|
||||||
|
viewport?: {
|
||||||
|
/** @description Current viewport width in pixels. */
|
||||||
|
width: number;
|
||||||
|
/** @description Current viewport height in pixels. */
|
||||||
|
height: number;
|
||||||
|
/** @description Maximum available height in pixels (if constrained). */
|
||||||
|
maxHeight?: number;
|
||||||
|
/** @description Maximum available width in pixels (if constrained). */
|
||||||
|
maxWidth?: number;
|
||||||
|
};
|
||||||
|
/** @description User's language and region preference in BCP 47 format. */
|
||||||
|
locale?: string;
|
||||||
|
/** @description User's timezone in IANA format. */
|
||||||
|
timeZone?: string;
|
||||||
|
/** @description Host application identifier. */
|
||||||
|
userAgent?: string;
|
||||||
|
/** @description Platform type for responsive design decisions. */
|
||||||
|
platform?: "web" | "desktop" | "mobile";
|
||||||
|
/** @description Device input capabilities. */
|
||||||
|
deviceCapabilities?: {
|
||||||
|
/** @description Whether the device supports touch input. */
|
||||||
|
touch?: boolean;
|
||||||
|
/** @description Whether the device supports hover interactions. */
|
||||||
|
hover?: boolean;
|
||||||
|
};
|
||||||
|
/** @description Mobile safe area boundaries in pixels. */
|
||||||
|
safeAreaInsets?: {
|
||||||
|
/** @description Top safe area inset in pixels. */
|
||||||
|
top: number;
|
||||||
|
/** @description Right safe area inset in pixels. */
|
||||||
|
right: number;
|
||||||
|
/** @description Bottom safe area inset in pixels. */
|
||||||
|
bottom: number;
|
||||||
|
/** @description Left safe area inset in pixels. */
|
||||||
|
left: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Notification that host context has changed (Host -> Guest UI).
|
||||||
|
* @see {@link McpUiHostContext} for the full context structure
|
||||||
|
*/
|
||||||
|
export interface McpUiHostContextChangedNotification {
|
||||||
|
method: "ui/notifications/host-context-changed";
|
||||||
|
/** @description Partial context update containing only changed fields. */
|
||||||
|
params: McpUiHostContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Request for graceful shutdown of the Guest UI (Host -> Guest UI).
|
||||||
|
* @see {@link app-bridge.AppBridge.sendResourceTeardown} for the host method that sends this
|
||||||
|
*/
|
||||||
|
export interface McpUiResourceTeardownRequest {
|
||||||
|
method: "ui/resource-teardown";
|
||||||
|
params: {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Result from graceful shutdown request.
|
||||||
|
* @see {@link McpUiResourceTeardownRequest}
|
||||||
|
*/
|
||||||
|
export interface McpUiResourceTeardownResult {
|
||||||
|
/**
|
||||||
|
* Index signature required for MCP SDK `Protocol` class compatibility.
|
||||||
|
*/
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Capabilities supported by the host application.
|
||||||
|
* @see {@link McpUiInitializeResult} for the initialization result that includes these capabilities
|
||||||
|
*/
|
||||||
|
export interface McpUiHostCapabilities {
|
||||||
|
/** @description Experimental features (structure TBD). */
|
||||||
|
experimental?: {};
|
||||||
|
/** @description Host supports opening external URLs. */
|
||||||
|
openLinks?: {};
|
||||||
|
/** @description Host can proxy tool calls to the MCP server. */
|
||||||
|
serverTools?: {
|
||||||
|
/** @description Host supports tools/list_changed notifications. */
|
||||||
|
listChanged?: boolean;
|
||||||
|
};
|
||||||
|
/** @description Host can proxy resource reads to the MCP server. */
|
||||||
|
serverResources?: {
|
||||||
|
/** @description Host supports resources/list_changed notifications. */
|
||||||
|
listChanged?: boolean;
|
||||||
|
};
|
||||||
|
/** @description Host accepts log messages. */
|
||||||
|
logging?: {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Capabilities provided by the Guest UI (App).
|
||||||
|
* @see {@link McpUiInitializeRequest} for the initialization request that includes these capabilities
|
||||||
|
*/
|
||||||
|
export interface McpUiAppCapabilities {
|
||||||
|
/** @description Experimental features (structure TBD). */
|
||||||
|
experimental?: {};
|
||||||
|
/** @description App exposes MCP-style tools that the host can call. */
|
||||||
|
tools?: {
|
||||||
|
/** @description App supports tools/list_changed notifications. */
|
||||||
|
listChanged?: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Initialization request sent from Guest UI to Host.
|
||||||
|
* @see {@link app.App.connect} for the method that sends this request
|
||||||
|
*/
|
||||||
|
export interface McpUiInitializeRequest {
|
||||||
|
method: "ui/initialize";
|
||||||
|
params: {
|
||||||
|
/** @description App identification (name and version). */
|
||||||
|
appInfo: Implementation;
|
||||||
|
/** @description Features and capabilities this app provides. */
|
||||||
|
appCapabilities: McpUiAppCapabilities;
|
||||||
|
/** @description Protocol version this app supports. */
|
||||||
|
protocolVersion: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Initialization result returned from Host to Guest UI.
|
||||||
|
* @see {@link McpUiInitializeRequest}
|
||||||
|
*/
|
||||||
|
export interface McpUiInitializeResult {
|
||||||
|
/** @description Negotiated protocol version string (e.g., "2025-11-21"). */
|
||||||
|
protocolVersion: string;
|
||||||
|
/** @description Host application identification and version. */
|
||||||
|
hostInfo: Implementation;
|
||||||
|
/** @description Features and capabilities provided by the host. */
|
||||||
|
hostCapabilities: McpUiHostCapabilities;
|
||||||
|
/** @description Rich context about the host environment. */
|
||||||
|
hostContext: McpUiHostContext;
|
||||||
|
/**
|
||||||
|
* Index signature required for MCP SDK `Protocol` class compatibility.
|
||||||
|
* Note: The schema intentionally omits this to enforce strict validation.
|
||||||
|
*/
|
||||||
|
[key: string]: unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Notification that Guest UI has completed initialization (Guest UI -> Host).
|
||||||
|
* @see {@link app.App.connect} for the method that sends this notification
|
||||||
|
*/
|
||||||
|
export interface McpUiInitializedNotification {
|
||||||
|
method: "ui/notifications/initialized";
|
||||||
|
params?: {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Content Security Policy configuration for UI resources.
|
||||||
|
*/
|
||||||
|
export interface McpUiResourceCsp {
|
||||||
|
/** @description Origins for network requests (fetch/XHR/WebSocket). */
|
||||||
|
connectDomains?: string[];
|
||||||
|
/** @description Origins for static resources (scripts, images, styles, fonts). */
|
||||||
|
resourceDomains?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description UI Resource metadata for security and rendering configuration.
|
||||||
|
*/
|
||||||
|
export interface McpUiResourceMeta {
|
||||||
|
/** @description Content Security Policy configuration. */
|
||||||
|
csp?: McpUiResourceCsp;
|
||||||
|
/** @description Dedicated origin for widget sandbox. */
|
||||||
|
domain?: string;
|
||||||
|
/** @description Visual boundary preference - true if UI prefers a visible border. */
|
||||||
|
prefersBorder?: boolean;
|
||||||
|
}
|
||||||
948
src/types.ts
948
src/types.ts
|
|
@ -1,895 +1,65 @@
|
||||||
import {
|
|
||||||
CallToolResult,
|
|
||||||
CallToolResultSchema,
|
|
||||||
ContentBlock,
|
|
||||||
ContentBlockSchema,
|
|
||||||
EmptyResultSchema,
|
|
||||||
Implementation,
|
|
||||||
ImplementationSchema,
|
|
||||||
RequestId,
|
|
||||||
RequestIdSchema,
|
|
||||||
RequestSchema,
|
|
||||||
Tool,
|
|
||||||
ToolSchema,
|
|
||||||
} from "@modelcontextprotocol/sdk/types.js";
|
|
||||||
import { z } from "zod/v4";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Type-level assertion that validates a Zod schema produces the expected interface.
|
* MCP Apps Protocol Types and Schemas
|
||||||
*
|
*
|
||||||
* This helper is used for request and notification schemas that cannot use
|
* This file re-exports types from spec.types.ts and schemas from generated/schema.ts.
|
||||||
* `z.ZodType<Interface>` type annotations. Adding `: z.ZodType<Interface>` to
|
* Compile-time verification is handled by generated/schema.test.ts.
|
||||||
* schemas widens the type from the specific `ZodObject` to the generic `ZodType`,
|
|
||||||
* which breaks MCP SDK's `setRequestHandler()` and `setNotificationHandler()`
|
|
||||||
* methods that require the specific `ZodObject` type.
|
|
||||||
*
|
*
|
||||||
* By using this type-level assertion instead, we get compile-time validation that
|
* @see spec.types.ts for the source of truth TypeScript interfaces
|
||||||
* the schema matches the interface without affecting the runtime schema type.
|
* @see generated/schema.ts for auto-generated Zod schemas
|
||||||
*
|
* @see generated/schema.test.ts for compile-time verification
|
||||||
* @internal
|
|
||||||
*/
|
*/
|
||||||
type VerifySchemaMatches<TSchema extends z.ZodTypeAny, TInterface> =
|
|
||||||
z.infer<TSchema> extends TInterface
|
|
||||||
? TInterface extends z.infer<TSchema>
|
|
||||||
? true
|
|
||||||
: never
|
|
||||||
: never;
|
|
||||||
|
|
||||||
/**
|
// Re-export all types from spec.types.ts
|
||||||
* Current protocol version supported by this SDK.
|
export {
|
||||||
*
|
LATEST_PROTOCOL_VERSION,
|
||||||
* The SDK automatically handles version negotiation during initialization.
|
type McpUiTheme,
|
||||||
* Apps and hosts don't need to manage protocol versions manually.
|
type McpUiDisplayMode,
|
||||||
*/
|
type McpUiOpenLinkRequest,
|
||||||
export const LATEST_PROTOCOL_VERSION = "2025-11-21";
|
type McpUiOpenLinkResult,
|
||||||
|
type McpUiMessageRequest,
|
||||||
|
type McpUiMessageResult,
|
||||||
|
type McpUiSandboxProxyReadyNotification,
|
||||||
|
type McpUiSandboxResourceReadyNotification,
|
||||||
|
type McpUiSizeChangedNotification,
|
||||||
|
type McpUiToolInputNotification,
|
||||||
|
type McpUiToolInputPartialNotification,
|
||||||
|
type McpUiToolResultNotification,
|
||||||
|
type McpUiHostContext,
|
||||||
|
type McpUiHostContextChangedNotification,
|
||||||
|
type McpUiResourceTeardownRequest,
|
||||||
|
type McpUiResourceTeardownResult,
|
||||||
|
type McpUiHostCapabilities,
|
||||||
|
type McpUiAppCapabilities,
|
||||||
|
type McpUiInitializeRequest,
|
||||||
|
type McpUiInitializeResult,
|
||||||
|
type McpUiInitializedNotification,
|
||||||
|
type McpUiResourceCsp,
|
||||||
|
type McpUiResourceMeta,
|
||||||
|
} from "./spec.types.js";
|
||||||
|
|
||||||
/**
|
// Re-export all schemas from generated/schema.ts (already PascalCase)
|
||||||
* Color theme preference for the host environment.
|
export {
|
||||||
* @see {@link McpUiHostContext.theme}
|
McpUiThemeSchema,
|
||||||
*/
|
McpUiDisplayModeSchema,
|
||||||
export type McpUiTheme = "light" | "dark";
|
McpUiOpenLinkRequestSchema,
|
||||||
|
McpUiOpenLinkResultSchema,
|
||||||
/** Runtime validation schema for {@link McpUiTheme}. */
|
McpUiMessageRequestSchema,
|
||||||
export const McpUiThemeSchema = z.enum(["light", "dark"]);
|
McpUiMessageResultSchema,
|
||||||
|
McpUiSandboxProxyReadyNotificationSchema,
|
||||||
/**
|
McpUiSandboxResourceReadyNotificationSchema,
|
||||||
* Display mode for UI presentation.
|
McpUiSizeChangedNotificationSchema,
|
||||||
* - `inline`: Embedded within the conversation flow
|
McpUiToolInputNotificationSchema,
|
||||||
* - `fullscreen`: Expanded to fill the available viewport
|
McpUiToolInputPartialNotificationSchema,
|
||||||
* - `pip`: Picture-in-picture floating window
|
McpUiToolResultNotificationSchema,
|
||||||
*
|
McpUiHostContextSchema,
|
||||||
* @see {@link McpUiHostContext.displayMode}
|
McpUiHostContextChangedNotificationSchema,
|
||||||
*/
|
McpUiResourceTeardownRequestSchema,
|
||||||
export type McpUiDisplayMode = "inline" | "fullscreen" | "pip";
|
McpUiResourceTeardownResultSchema,
|
||||||
|
McpUiHostCapabilitiesSchema,
|
||||||
/** Runtime validation schema for {@link McpUiDisplayMode}. */
|
McpUiAppCapabilitiesSchema,
|
||||||
export const McpUiDisplayModeSchema = z.enum(["inline", "fullscreen", "pip"]);
|
McpUiInitializeRequestSchema,
|
||||||
|
McpUiInitializeResultSchema,
|
||||||
/**
|
McpUiInitializedNotificationSchema,
|
||||||
* Request to open an external URL in the host's default browser.
|
McpUiResourceCspSchema,
|
||||||
*
|
McpUiResourceMetaSchema,
|
||||||
* Sent from the Guest UI to the Host when requesting to open an external link.
|
} from "./generated/schema.js";
|
||||||
* The host may deny the request based on user preferences or security policy.
|
|
||||||
*
|
|
||||||
* @see {@link app.App.sendOpenLink} for the method that sends this request
|
|
||||||
*/
|
|
||||||
export interface McpUiOpenLinkRequest {
|
|
||||||
method: "ui/open-link";
|
|
||||||
params: {
|
|
||||||
/** URL to open in the host's browser */
|
|
||||||
url: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiOpenLinkRequest}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiOpenLinkRequestSchema = RequestSchema.extend({
|
|
||||||
method: z.literal("ui/open-link"),
|
|
||||||
params: z.object({
|
|
||||||
url: z.string().url(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
/** @internal - Compile-time verification that schema matches interface */
|
|
||||||
type _VerifyOpenLinkRequest = VerifySchemaMatches<
|
|
||||||
typeof McpUiOpenLinkRequestSchema,
|
|
||||||
McpUiOpenLinkRequest
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Result from a {@link McpUiOpenLinkRequest}.
|
|
||||||
*
|
|
||||||
* The host returns this result after attempting to open the requested URL.
|
|
||||||
*
|
|
||||||
* @see {@link McpUiOpenLinkRequest}
|
|
||||||
*/
|
|
||||||
export interface McpUiOpenLinkResult {
|
|
||||||
/**
|
|
||||||
* True if the host failed to open the URL (e.g., due to security policy,
|
|
||||||
* user cancellation, or system error). False or undefined indicates success.
|
|
||||||
*/
|
|
||||||
isError?: boolean;
|
|
||||||
/**
|
|
||||||
* Index signature required for MCP SDK `Protocol` class compatibility.
|
|
||||||
* Note: The schema intentionally omits this to enforce strict validation.
|
|
||||||
*/
|
|
||||||
[key: string]: unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiOpenLinkResult}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiOpenLinkResultSchema: z.ZodType<McpUiOpenLinkResult> =
|
|
||||||
z.object({
|
|
||||||
isError: z.boolean().optional(),
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request to send a message to the host's chat interface.
|
|
||||||
*
|
|
||||||
* Sent from the Guest UI to the Host when the app wants to add a message to the
|
|
||||||
* conversation thread. This enables interactive apps to communicate with the user
|
|
||||||
* through the host's chat interface.
|
|
||||||
*
|
|
||||||
* @see {@link app.App.sendMessage} for the method that sends this request
|
|
||||||
*/
|
|
||||||
export interface McpUiMessageRequest {
|
|
||||||
method: "ui/message";
|
|
||||||
params: {
|
|
||||||
/** Message role, currently only "user" is supported */
|
|
||||||
role: "user";
|
|
||||||
/** Message content blocks (text, image, etc.) */
|
|
||||||
content: ContentBlock[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiMessageRequest}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiMessageRequestSchema = RequestSchema.extend({
|
|
||||||
method: z.literal("ui/message"),
|
|
||||||
params: z.object({
|
|
||||||
role: z.literal("user"),
|
|
||||||
content: z.array(ContentBlockSchema),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
/** @internal - Compile-time verification that schema matches interface */
|
|
||||||
type _VerifyMessageRequest = VerifySchemaMatches<
|
|
||||||
typeof McpUiMessageRequestSchema,
|
|
||||||
McpUiMessageRequest
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Result from a {@link McpUiMessageRequest}.
|
|
||||||
*
|
|
||||||
* Note: The host does not return message content or follow-up results to prevent
|
|
||||||
* leaking information from the conversation. Only error status is provided.
|
|
||||||
*
|
|
||||||
* @see {@link McpUiMessageRequest}
|
|
||||||
*/
|
|
||||||
export interface McpUiMessageResult {
|
|
||||||
/**
|
|
||||||
* True if the host rejected or failed to deliver the message (e.g., due to
|
|
||||||
* rate limiting, content policy, or system error). False or undefined
|
|
||||||
* indicates the message was accepted.
|
|
||||||
*/
|
|
||||||
isError?: boolean;
|
|
||||||
/**
|
|
||||||
* Index signature required for MCP SDK `Protocol` class compatibility.
|
|
||||||
* Note: The schema intentionally omits this to enforce strict validation.
|
|
||||||
*/
|
|
||||||
[key: string]: unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiMessageResult}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiMessageResultSchema: z.ZodType<McpUiMessageResult> = z.object(
|
|
||||||
{
|
|
||||||
isError: z.boolean().optional(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// McpUiIframeReadyNotification removed - replaced by standard MCP initialization
|
|
||||||
// The SDK's oninitialized callback now handles the ready signal
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification that the sandbox proxy iframe is ready to receive content.
|
|
||||||
*
|
|
||||||
* This is an internal message used by web-based hosts implementing the
|
|
||||||
* double-iframe sandbox architecture. The sandbox proxy sends this to the host
|
|
||||||
* after it loads and is ready to receive HTML content via
|
|
||||||
* {@link McpUiSandboxResourceReadyNotification}.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
* @see https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx#sandbox-proxy
|
|
||||||
*/
|
|
||||||
export interface McpUiSandboxProxyReadyNotification {
|
|
||||||
method: "ui/notifications/sandbox-proxy-ready";
|
|
||||||
params: {};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiSandboxProxyReadyNotification}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiSandboxProxyReadyNotificationSchema = z.object({
|
|
||||||
method: z.literal("ui/notifications/sandbox-proxy-ready"),
|
|
||||||
params: z.object({}),
|
|
||||||
});
|
|
||||||
|
|
||||||
/** @internal - Compile-time verification that schema matches interface */
|
|
||||||
type _VerifySandboxProxyReadyNotification = VerifySchemaMatches<
|
|
||||||
typeof McpUiSandboxProxyReadyNotificationSchema,
|
|
||||||
McpUiSandboxProxyReadyNotification
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification containing HTML resource for the sandbox proxy to load.
|
|
||||||
*
|
|
||||||
* This is an internal message used by web-based hosts implementing the
|
|
||||||
* double-iframe sandbox architecture. After the sandbox proxy signals readiness,
|
|
||||||
* the host sends this notification with the HTML content and optional sandbox
|
|
||||||
* attributes to load into the inner iframe.
|
|
||||||
*
|
|
||||||
* @internal
|
|
||||||
* @see https://github.com/modelcontextprotocol/ext-apps/blob/main/specification/draft/apps.mdx#sandbox-proxy
|
|
||||||
*/
|
|
||||||
export interface McpUiSandboxResourceReadyNotification {
|
|
||||||
method: "ui/notifications/sandbox-resource-ready";
|
|
||||||
params: {
|
|
||||||
/** HTML content to load into the inner iframe */
|
|
||||||
html: string;
|
|
||||||
/** Optional override for the inner iframe's sandbox attribute */
|
|
||||||
sandbox?: string;
|
|
||||||
/** CSP configuration from resource metadata */
|
|
||||||
csp?: {
|
|
||||||
/** Origins for network requests (fetch/XHR/WebSocket) */
|
|
||||||
connectDomains?: string[];
|
|
||||||
/** Origins for static resources (scripts, images, styles, fonts) */
|
|
||||||
resourceDomains?: string[];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiSandboxResourceReadyNotification}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiSandboxResourceReadyNotificationSchema = z.object({
|
|
||||||
method: z.literal("ui/notifications/sandbox-resource-ready"),
|
|
||||||
params: z.object({
|
|
||||||
html: z.string(),
|
|
||||||
sandbox: z.string().optional(),
|
|
||||||
csp: z
|
|
||||||
.object({
|
|
||||||
connectDomains: z.array(z.string()).optional(),
|
|
||||||
resourceDomains: z.array(z.string()).optional(),
|
|
||||||
})
|
|
||||||
.optional(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
/** @internal - Compile-time verification that schema matches interface */
|
|
||||||
type _VerifySandboxResourceReadyNotification = VerifySchemaMatches<
|
|
||||||
typeof McpUiSandboxResourceReadyNotificationSchema,
|
|
||||||
McpUiSandboxResourceReadyNotification
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification of UI size changes (bidirectional: Guest ↔ Host).
|
|
||||||
*
|
|
||||||
* **Guest UI → Host**: Sent by the Guest UI when its rendered content size changes,
|
|
||||||
* typically using ResizeObserver. This helps the host adjust the iframe container.
|
|
||||||
* If {@link app.App} is configured with `autoResize: true` (default), this is sent
|
|
||||||
* automatically.
|
|
||||||
*
|
|
||||||
* **Host → Guest UI**: Sent by the Host when the viewport size changes (e.g.,
|
|
||||||
* window resize, orientation change). This allows the Guest UI to adjust its layout.
|
|
||||||
*
|
|
||||||
* @see {@link app.App.sendSizeChanged} for the method to send this from Guest UI
|
|
||||||
* @see {@link app.App.setupSizeChangedNotifications} for automatic size reporting
|
|
||||||
*/
|
|
||||||
export interface McpUiSizeChangedNotification {
|
|
||||||
method: "ui/notifications/size-changed";
|
|
||||||
params: {
|
|
||||||
/** New width in pixels */
|
|
||||||
width?: number;
|
|
||||||
/** New height in pixels */
|
|
||||||
height?: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiSizeChangedNotification}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiSizeChangedNotificationSchema = z.object({
|
|
||||||
method: z.literal("ui/notifications/size-changed"),
|
|
||||||
params: z.object({
|
|
||||||
width: z.number().optional(),
|
|
||||||
height: z.number().optional(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
/** @internal - Compile-time verification that schema matches interface */
|
|
||||||
type _VerifySizeChangeNotification = VerifySchemaMatches<
|
|
||||||
typeof McpUiSizeChangedNotificationSchema,
|
|
||||||
McpUiSizeChangedNotification
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification containing complete tool arguments (Host → Guest UI).
|
|
||||||
*
|
|
||||||
* The host MUST send this notification after the Guest UI's initialize request
|
|
||||||
* completes, when complete tool arguments become available. This notification is
|
|
||||||
* sent exactly once and is required before {@link McpUiToolResultNotification}.
|
|
||||||
*
|
|
||||||
* The arguments object contains the complete tool call parameters that triggered
|
|
||||||
* this App instance.
|
|
||||||
*/
|
|
||||||
export interface McpUiToolInputNotification {
|
|
||||||
method: "ui/notifications/tool-input";
|
|
||||||
params: {
|
|
||||||
/** Complete tool call arguments as key-value pairs */
|
|
||||||
arguments?: Record<string, unknown>;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiToolInputNotification}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiToolInputNotificationSchema = z.object({
|
|
||||||
method: z.literal("ui/notifications/tool-input"),
|
|
||||||
params: z.object({
|
|
||||||
arguments: z.record(z.string(), z.unknown()).optional(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
/** @internal - Compile-time verification that schema matches interface */
|
|
||||||
type _VerifyToolInputNotification = VerifySchemaMatches<
|
|
||||||
typeof McpUiToolInputNotificationSchema,
|
|
||||||
McpUiToolInputNotification
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification containing partial/streaming tool arguments (Host → Guest UI).
|
|
||||||
*
|
|
||||||
* The host MAY send this notification zero or more times while the agent is
|
|
||||||
* streaming tool arguments, before {@link McpUiToolInputNotification} is sent
|
|
||||||
* with complete arguments.
|
|
||||||
*
|
|
||||||
* The arguments object represents best-effort recovery of incomplete JSON, with
|
|
||||||
* unclosed structures automatically closed to produce valid JSON. Guest UIs may
|
|
||||||
* ignore these notifications or use them to render progressive loading states.
|
|
||||||
*
|
|
||||||
* Guest UIs MUST NOT rely on partial arguments for critical operations and SHOULD
|
|
||||||
* gracefully handle missing or changing fields between notifications.
|
|
||||||
*/
|
|
||||||
export interface McpUiToolInputPartialNotification {
|
|
||||||
method: "ui/notifications/tool-input-partial";
|
|
||||||
params: {
|
|
||||||
/** Partial tool call arguments (incomplete, may change) */
|
|
||||||
arguments?: Record<string, unknown>;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiToolInputPartialNotification}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiToolInputPartialNotificationSchema = z.object({
|
|
||||||
method: z.literal("ui/notifications/tool-input-partial"),
|
|
||||||
params: z.object({
|
|
||||||
arguments: z.record(z.string(), z.unknown()).optional(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
/** @internal - Compile-time verification that schema matches interface */
|
|
||||||
type _VerifyToolInputPartialNotification = VerifySchemaMatches<
|
|
||||||
typeof McpUiToolInputPartialNotificationSchema,
|
|
||||||
McpUiToolInputPartialNotification
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification containing tool execution result (Host → Guest UI).
|
|
||||||
*
|
|
||||||
* The host MUST send this notification when tool execution completes successfully,
|
|
||||||
* provided the UI is still displayed. If the UI was closed before execution
|
|
||||||
* completes, the host MAY skip this notification. This notification is sent after
|
|
||||||
* {@link McpUiToolInputNotification}.
|
|
||||||
*
|
|
||||||
* The result follows the standard MCP CallToolResult format, containing content
|
|
||||||
* for the model and optionally structuredContent optimized for UI rendering.
|
|
||||||
*/
|
|
||||||
export interface McpUiToolResultNotification {
|
|
||||||
method: "ui/notifications/tool-result";
|
|
||||||
/** Standard MCP tool execution result */
|
|
||||||
params: CallToolResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiToolResultNotification}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiToolResultNotificationSchema = z.object({
|
|
||||||
method: z.literal("ui/notifications/tool-result"),
|
|
||||||
params: CallToolResultSchema,
|
|
||||||
});
|
|
||||||
|
|
||||||
/** @internal - Compile-time verification that schema matches interface */
|
|
||||||
type _VerifyToolResultNotification = VerifySchemaMatches<
|
|
||||||
typeof McpUiToolResultNotificationSchema,
|
|
||||||
McpUiToolResultNotification
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rich context about the host environment provided to Guest UIs.
|
|
||||||
*
|
|
||||||
* Hosts provide this context in the {@link McpUiInitializeResult} response and send
|
|
||||||
* updates via {@link McpUiHostContextChangedNotification} when values change.
|
|
||||||
* All fields are optional and Guest UIs should handle missing fields gracefully.
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* ```typescript
|
|
||||||
* // Received during initialization
|
|
||||||
* const result = await app.connect(transport);
|
|
||||||
* const context = result.hostContext;
|
|
||||||
*
|
|
||||||
* if (context.theme === "dark") {
|
|
||||||
* document.body.classList.add("dark-mode");
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*/
|
|
||||||
export interface McpUiHostContext {
|
|
||||||
/** Metadata of the tool call that instantiated this App */
|
|
||||||
toolInfo?: {
|
|
||||||
/** JSON-RPC id of the tools/call request */
|
|
||||||
id: RequestId;
|
|
||||||
/** Tool definition including name, inputSchema, etc. */
|
|
||||||
tool: Tool;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Current color theme preference.
|
|
||||||
* @example "dark"
|
|
||||||
*/
|
|
||||||
theme?: McpUiTheme;
|
|
||||||
/**
|
|
||||||
* How the UI is currently displayed.
|
|
||||||
* @example "inline"
|
|
||||||
*/
|
|
||||||
displayMode?: McpUiDisplayMode;
|
|
||||||
/**
|
|
||||||
* Display modes the host supports.
|
|
||||||
* Apps can use this to offer mode-switching UI if applicable.
|
|
||||||
*/
|
|
||||||
availableDisplayModes?: string[];
|
|
||||||
/** Current and maximum dimensions available to the UI */
|
|
||||||
viewport?: {
|
|
||||||
/** Current viewport width in pixels */
|
|
||||||
width: number;
|
|
||||||
/** Current viewport height in pixels */
|
|
||||||
height: number;
|
|
||||||
/** Maximum available height in pixels (if constrained) */
|
|
||||||
maxHeight?: number;
|
|
||||||
/** Maximum available width in pixels (if constrained) */
|
|
||||||
maxWidth?: number;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* User's language and region preference in BCP 47 format.
|
|
||||||
* @example "en-US", "fr-CA", "ja-JP"
|
|
||||||
*/
|
|
||||||
locale?: string;
|
|
||||||
/**
|
|
||||||
* User's timezone in IANA format.
|
|
||||||
* @example "America/New_York", "Europe/London", "Asia/Tokyo"
|
|
||||||
*/
|
|
||||||
timeZone?: string;
|
|
||||||
/**
|
|
||||||
* Host application identifier.
|
|
||||||
* @example "claude-desktop/1.0.0"
|
|
||||||
*/
|
|
||||||
userAgent?: string;
|
|
||||||
/**
|
|
||||||
* Platform type for responsive design decisions.
|
|
||||||
* @example "desktop"
|
|
||||||
*/
|
|
||||||
platform?: "web" | "desktop" | "mobile";
|
|
||||||
/** Device input capabilities */
|
|
||||||
deviceCapabilities?: {
|
|
||||||
/** Whether the device supports touch input */
|
|
||||||
touch?: boolean;
|
|
||||||
/** Whether the device supports hover interactions */
|
|
||||||
hover?: boolean;
|
|
||||||
};
|
|
||||||
/**
|
|
||||||
* Safe area boundaries in pixels.
|
|
||||||
* Used to avoid notches, rounded corners, and system UI.
|
|
||||||
*/
|
|
||||||
safeAreaInsets?: {
|
|
||||||
/** Top safe area inset in pixels */
|
|
||||||
top: number;
|
|
||||||
/** Right safe area inset in pixels */
|
|
||||||
right: number;
|
|
||||||
/** Bottom safe area inset in pixels */
|
|
||||||
bottom: number;
|
|
||||||
/** Left safe area inset in pixels */
|
|
||||||
left: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiHostContext}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiHostContextSchema: z.ZodType<McpUiHostContext> = z.object({
|
|
||||||
toolInfo: z
|
|
||||||
.object({
|
|
||||||
id: RequestIdSchema,
|
|
||||||
tool: ToolSchema,
|
|
||||||
})
|
|
||||||
.optional(),
|
|
||||||
theme: McpUiThemeSchema.optional(),
|
|
||||||
displayMode: McpUiDisplayModeSchema.optional(),
|
|
||||||
availableDisplayModes: z.array(z.string()).optional(),
|
|
||||||
viewport: z
|
|
||||||
.object({
|
|
||||||
width: z.number(),
|
|
||||||
height: z.number(),
|
|
||||||
maxHeight: z.number().optional(),
|
|
||||||
maxWidth: z.number().optional(),
|
|
||||||
})
|
|
||||||
.optional(),
|
|
||||||
locale: z.string().optional(),
|
|
||||||
timeZone: z.string().optional(),
|
|
||||||
userAgent: z.string().optional(),
|
|
||||||
platform: z.enum(["web", "desktop", "mobile"]).optional(),
|
|
||||||
deviceCapabilities: z
|
|
||||||
.object({
|
|
||||||
touch: z.boolean().optional(),
|
|
||||||
hover: z.boolean().optional(),
|
|
||||||
})
|
|
||||||
.optional(),
|
|
||||||
safeAreaInsets: z
|
|
||||||
.object({
|
|
||||||
top: z.number(),
|
|
||||||
right: z.number(),
|
|
||||||
bottom: z.number(),
|
|
||||||
left: z.number(),
|
|
||||||
})
|
|
||||||
.optional(),
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification that host context has changed (Host → Guest UI).
|
|
||||||
*
|
|
||||||
* The host MAY send this notification when any context field changes, such as:
|
|
||||||
* - Theme toggled (light/dark)
|
|
||||||
* - Display mode changed (inline/fullscreen)
|
|
||||||
* - Device orientation changed
|
|
||||||
* - Window/panel resized
|
|
||||||
*
|
|
||||||
* This notification contains partial updates. Guest UIs SHOULD merge received
|
|
||||||
* fields with their current context state rather than replacing it entirely.
|
|
||||||
*
|
|
||||||
* @see {@link McpUiHostContext} for the full context structure
|
|
||||||
*/
|
|
||||||
export interface McpUiHostContextChangedNotification {
|
|
||||||
method: "ui/notifications/host-context-changed";
|
|
||||||
/** Partial context update containing only changed fields */
|
|
||||||
params: McpUiHostContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiHostContextChangedNotification}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiHostContextChangedNotificationSchema = z.object({
|
|
||||||
method: z.literal("ui/notifications/host-context-changed"),
|
|
||||||
params: McpUiHostContextSchema,
|
|
||||||
});
|
|
||||||
|
|
||||||
/** @internal - Compile-time verification that schema matches interface */
|
|
||||||
type _VerifyHostContextChangedNotification = VerifySchemaMatches<
|
|
||||||
typeof McpUiHostContextChangedNotificationSchema,
|
|
||||||
McpUiHostContextChangedNotification
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Request for graceful shutdown of the Guest UI (Host → Guest UI).
|
|
||||||
*
|
|
||||||
* The host MUST send this request before tearing down the UI resource, for any
|
|
||||||
* reason including user action, resource reallocation, or app closure. This gives
|
|
||||||
* the Guest UI an opportunity to save state, cancel pending operations, or show
|
|
||||||
* confirmation dialogs.
|
|
||||||
*
|
|
||||||
* The host SHOULD wait for the response before unmounting the iframe to prevent
|
|
||||||
* data loss.
|
|
||||||
*
|
|
||||||
* @see {@link app-bridge.AppBridge.sendResourceTeardown} for the host method that sends this
|
|
||||||
*/
|
|
||||||
export interface McpUiResourceTeardownRequest {
|
|
||||||
method: "ui/resource-teardown";
|
|
||||||
params: {};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiResourceTeardownRequest}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiResourceTeardownRequestSchema = RequestSchema.extend({
|
|
||||||
method: z.literal("ui/resource-teardown"),
|
|
||||||
params: z.object({}),
|
|
||||||
});
|
|
||||||
|
|
||||||
/** @internal - Compile-time verification that schema matches interface */
|
|
||||||
type _VerifyResourceTeardownRequest = VerifySchemaMatches<
|
|
||||||
typeof McpUiResourceTeardownRequestSchema,
|
|
||||||
McpUiResourceTeardownRequest
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Result from graceful shutdown request.
|
|
||||||
*
|
|
||||||
* Empty result indicates the Guest UI has completed cleanup and is ready to be
|
|
||||||
* torn down.
|
|
||||||
*
|
|
||||||
* @see {@link McpUiResourceTeardownRequest}
|
|
||||||
*/
|
|
||||||
export interface McpUiResourceTeardownResult {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiResourceTeardownResult}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiResourceTeardownResultSchema: z.ZodType<McpUiResourceTeardownResult> =
|
|
||||||
EmptyResultSchema;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Capabilities supported by the host application.
|
|
||||||
*
|
|
||||||
* Hosts declare these capabilities during the initialization handshake. Guest UIs
|
|
||||||
* can check capabilities before attempting to use specific features.
|
|
||||||
*
|
|
||||||
* @example Check if host supports opening links
|
|
||||||
* ```typescript
|
|
||||||
* const result = await app.connect(transport);
|
|
||||||
* if (result.hostCapabilities.openLinks) {
|
|
||||||
* await app.sendOpenLink({ url: "https://example.com" });
|
|
||||||
* }
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @see {@link McpUiInitializeResult} for the initialization result that includes these capabilities
|
|
||||||
*/
|
|
||||||
export interface McpUiHostCapabilities {
|
|
||||||
/** Experimental features (structure TBD) */
|
|
||||||
experimental?: {};
|
|
||||||
/** Host supports opening external URLs via {@link app.App.sendOpenLink} */
|
|
||||||
openLinks?: {};
|
|
||||||
/** Host can proxy tool calls to the MCP server */
|
|
||||||
serverTools?: {
|
|
||||||
/** Host supports tools/list_changed notifications */
|
|
||||||
listChanged?: boolean;
|
|
||||||
};
|
|
||||||
/** Host can proxy resource reads to the MCP server */
|
|
||||||
serverResources?: {
|
|
||||||
/** Host supports resources/list_changed notifications */
|
|
||||||
listChanged?: boolean;
|
|
||||||
};
|
|
||||||
/** Host accepts log messages via {@link app.App.sendLog} */
|
|
||||||
logging?: {};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiHostCapabilities}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiHostCapabilitiesSchema: z.ZodType<McpUiHostCapabilities> =
|
|
||||||
z.object({
|
|
||||||
experimental: z.object({}).optional(),
|
|
||||||
openLinks: z.object({}).optional(),
|
|
||||||
serverTools: z
|
|
||||||
.object({
|
|
||||||
listChanged: z.boolean().optional(),
|
|
||||||
})
|
|
||||||
.optional(),
|
|
||||||
serverResources: z
|
|
||||||
.object({
|
|
||||||
listChanged: z.boolean().optional(),
|
|
||||||
})
|
|
||||||
.optional(),
|
|
||||||
logging: z.object({}).optional(),
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Capabilities provided by the Guest UI (App).
|
|
||||||
*
|
|
||||||
* Apps declare these capabilities during the initialization handshake to indicate
|
|
||||||
* what features they provide to the host.
|
|
||||||
*
|
|
||||||
* @example Declare tool capabilities
|
|
||||||
* ```typescript
|
|
||||||
* const app = new App(
|
|
||||||
* { name: "MyApp", version: "1.0.0" },
|
|
||||||
* { tools: { listChanged: true } }
|
|
||||||
* );
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @see {@link McpUiInitializeRequest} for the initialization request that includes these capabilities
|
|
||||||
*/
|
|
||||||
export interface McpUiAppCapabilities {
|
|
||||||
/** Experimental features (structure TBD) */
|
|
||||||
experimental?: {};
|
|
||||||
/**
|
|
||||||
* App exposes MCP-style tools that the host can call.
|
|
||||||
* These are app-specific tools, not proxied from the server.
|
|
||||||
*/
|
|
||||||
tools?: {
|
|
||||||
/** App supports tools/list_changed notifications */
|
|
||||||
listChanged?: boolean;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiAppCapabilities}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiAppCapabilitiesSchema: z.ZodType<McpUiAppCapabilities> =
|
|
||||||
z.object({
|
|
||||||
experimental: z.object({}).optional(),
|
|
||||||
tools: z
|
|
||||||
.object({
|
|
||||||
listChanged: z.boolean().optional(),
|
|
||||||
})
|
|
||||||
.optional(),
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialization request sent from Guest UI to Host.
|
|
||||||
*
|
|
||||||
* This is the first message sent by the Guest UI after loading. The host responds
|
|
||||||
* with {@link McpUiInitializeResult} containing host capabilities and context.
|
|
||||||
* After receiving the response, the Guest UI MUST send
|
|
||||||
* {@link McpUiInitializedNotification}.
|
|
||||||
*
|
|
||||||
* This replaces the custom iframe-ready pattern used in pre-SEP MCP-UI.
|
|
||||||
*
|
|
||||||
* @see {@link app.App.connect} for the method that sends this request
|
|
||||||
*/
|
|
||||||
export interface McpUiInitializeRequest {
|
|
||||||
method: "ui/initialize";
|
|
||||||
params: {
|
|
||||||
/** App identification (name and version) */
|
|
||||||
appInfo: Implementation;
|
|
||||||
/** Features and capabilities this app provides */
|
|
||||||
appCapabilities: McpUiAppCapabilities;
|
|
||||||
/** Protocol version this app supports */
|
|
||||||
protocolVersion: string;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiInitializeRequest}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiInitializeRequestSchema = RequestSchema.extend({
|
|
||||||
method: z.literal("ui/initialize"),
|
|
||||||
params: z.object({
|
|
||||||
appInfo: ImplementationSchema,
|
|
||||||
appCapabilities: McpUiAppCapabilitiesSchema,
|
|
||||||
protocolVersion: z.string(),
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
|
|
||||||
/** @internal - Compile-time verification that schema matches interface */
|
|
||||||
type _VerifyInitializeRequest = VerifySchemaMatches<
|
|
||||||
typeof McpUiInitializeRequestSchema,
|
|
||||||
McpUiInitializeRequest
|
|
||||||
>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialization result returned from Host to Guest UI.
|
|
||||||
*
|
|
||||||
* Contains the negotiated protocol version, host information, capabilities,
|
|
||||||
* and rich context about the host environment.
|
|
||||||
*
|
|
||||||
* @see {@link McpUiInitializeRequest}
|
|
||||||
*/
|
|
||||||
export interface McpUiInitializeResult {
|
|
||||||
/** Negotiated protocol version string (e.g., "2025-11-21") */
|
|
||||||
protocolVersion: string;
|
|
||||||
/** Host application identification and version */
|
|
||||||
hostInfo: Implementation;
|
|
||||||
/** Features and capabilities provided by the host */
|
|
||||||
hostCapabilities: McpUiHostCapabilities;
|
|
||||||
/** Rich context about the host environment */
|
|
||||||
hostContext: McpUiHostContext;
|
|
||||||
/**
|
|
||||||
* Index signature required for MCP SDK `Protocol` class compatibility.
|
|
||||||
* Note: The schema intentionally omits this to enforce strict validation.
|
|
||||||
*/
|
|
||||||
[key: string]: unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiInitializeResult}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiInitializeResultSchema: z.ZodType<McpUiInitializeResult> =
|
|
||||||
z.object({
|
|
||||||
protocolVersion: z.string(),
|
|
||||||
hostInfo: ImplementationSchema,
|
|
||||||
hostCapabilities: McpUiHostCapabilitiesSchema,
|
|
||||||
hostContext: McpUiHostContextSchema,
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification that Guest UI has completed initialization (Guest UI → Host).
|
|
||||||
*
|
|
||||||
* The Guest UI MUST send this notification after receiving
|
|
||||||
* {@link McpUiInitializeResult} and completing any setup. The host waits for this
|
|
||||||
* notification before sending tool input and other data to the Guest UI.
|
|
||||||
*
|
|
||||||
* @see {@link app.App.connect} for the method that sends this notification
|
|
||||||
*/
|
|
||||||
export interface McpUiInitializedNotification {
|
|
||||||
method: "ui/notifications/initialized";
|
|
||||||
params?: {};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Runtime validation schema for {@link McpUiInitializedNotification}.
|
|
||||||
* @internal
|
|
||||||
*/
|
|
||||||
export const McpUiInitializedNotificationSchema = z.object({
|
|
||||||
method: z.literal("ui/notifications/initialized"),
|
|
||||||
params: z.object({}).optional(),
|
|
||||||
});
|
|
||||||
|
|
||||||
/** @internal - Compile-time verification that schema matches interface */
|
|
||||||
type _VerifyInitializedNotification = VerifySchemaMatches<
|
|
||||||
typeof McpUiInitializedNotificationSchema,
|
|
||||||
McpUiInitializedNotification
|
|
||||||
>;
|
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// UI Resource Metadata Types
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Content Security Policy configuration for UI resources.
|
|
||||||
*
|
|
||||||
* Servers declare which external origins their UI needs to access.
|
|
||||||
* Hosts use this to enforce appropriate CSP headers.
|
|
||||||
*/
|
|
||||||
export const McpUiResourceCspSchema = z.object({
|
|
||||||
/** Origins for network requests (fetch/XHR/WebSocket). Maps to CSP connect-src */
|
|
||||||
connectDomains: z.array(z.string()).optional(),
|
|
||||||
/** Origins for static resources (images, scripts, stylesheets, fonts, media). Maps to CSP img-src, script-src, style-src, font-src, media-src */
|
|
||||||
resourceDomains: z.array(z.string()).optional(),
|
|
||||||
});
|
|
||||||
export type McpUiResourceCsp = z.infer<typeof McpUiResourceCspSchema>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* UI Resource metadata for security and rendering configuration.
|
|
||||||
*
|
|
||||||
* Included in the `_meta.ui` field of UI resource content returned via `resources/read`.
|
|
||||||
*
|
|
||||||
* @see {@link McpUiResourceCspSchema} for CSP configuration
|
|
||||||
*/
|
|
||||||
export const McpUiResourceMetaSchema = z.object({
|
|
||||||
/** Content Security Policy configuration */
|
|
||||||
csp: McpUiResourceCspSchema.optional(),
|
|
||||||
/** Dedicated origin for widget sandbox */
|
|
||||||
domain: z.string().optional(),
|
|
||||||
/** Visual boundary preference - true if UI prefers a visible border */
|
|
||||||
prefersBorder: z.boolean().optional(),
|
|
||||||
});
|
|
||||||
export type McpUiResourceMeta = z.infer<typeof McpUiResourceMetaSchema>;
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue