Repository navigation
feat(mcp): render assemble_document inline as an MCP App - #111
Open
ahnafnafee wants to merge 2 commits into
Open
ahnafnafee wants to merge 2 commits into
ahnafnafee wants to merge 2 commits into
Conversation
loadSkill guards against path traversal by checking that the resolved path starts with the skills directory followed by "/". On Windows, path.resolve returns backslash-separated paths, so every skill name failed the check and all skill resources and prompts threw "Invalid skill name". Compare against path.sep instead, and cover loading and traversal rejection in tests.
assemble_document returned the assembled page as plain text, so MCP Apps hosts such as Claude Desktop showed raw HTML instead of rendering it. - Register a ui://open-generative-ui/document.html view (text/html;profile=mcp-app) and link the tool to it through _meta.ui.resourceUri, plus the legacy ui/resourceUri key. - The view applies the design system and the host theme, runs the fragment's scripts in order, and maps sendPrompt and openLink to the MCP Apps bridge. It loads the pinned ext-apps app-with-deps bundle from jsDelivr, which is already on the CDN allowlist, and asks hosts for no border. - Clients that advertise the io.modelcontextprotocol/ui extension get a one-line result instead of the roughly 12 KB document, which keeps it out of the model's context. Other clients still receive the full document. - Bump @modelcontextprotocol/sdk to ^1.32.1, whose ClientCapabilities schema keeps the extensions field. - Share one CDN allowlist between the iframe CSP and the MCP Apps CSP.
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
assemble_documentreturns the assembled page as plain text, so MCP Apps hosts such as Claude Desktop show raw HTML instead of rendering it. This PR makes the tool an MCP App: hosts that support theio.modelcontextprotocol/uiextension now render the fragment inline in the conversation. It also fixes skill resources and prompts failing on Windows.Changes
fix(mcp): load skill documents on WindowsloadSkillcheckedresolved.startsWith(dir + "/").path.resolvereturns backslash paths on Windows, so every skill name failed the traversal guard and allskills://reads and prompts threwInvalid skill name. It now compares againstpath.sep.feat(mcp): render assemble_document inline as an MCP Appui://open-generative-ui/document.htmlview (text/html;profile=mcp-app) and links the tool to it via_meta.ui.resourceUri, plus the legacyui/resourceUrikey.applyDocumentTheme,applyHostStyleVariables,applyHostFonts). It runs the fragment's scripts in document order, awaiting external classic scripts so later inline code can use their globals. It mapssendPrompt(text)toui/messageandopenLink(url)toui/open-link. The resource declares the existing CDN allowlist as its CSP and setsprefersBorder: false.@modelcontextprotocol/sdkto^1.32.1: older 1.x versions stripextensionsfrom client capabilities, so the server could not detect MCP Apps hosts.Testing
pnpm --filter open-intelligent-ui-mcp test: 10 tests pass. New tests cover the tool's UI metadata; the view resource's MIME type, design system, bridge, CSP,prefersBorderand.sr-onlyrule; the capability-dependent result in both directions; and skill loading and traversal rejection.pnpm --filter open-intelligent-ui-mcp lintpasses, and the@repo/design-systemtests still pass.tools/list,resources/read,tools/call, a skill read and a prompt with an MCP Apps-capable client.AppBridgein a browser harness. The handshake completes; inline, CDN and module scripts run in order; host theme and style variables apply;sendPromptarrives asui/messageand link clicks asui/open-link.Notes
@modelcontextprotocol/ext-apps@2.0.3app-with-depsbundle from jsDelivr when it opens, so rendering needs network access, as the CDN-based widgets already do. Inlining the bundle into the view would remove that dependency if offline hosts matter.