Skip to content

Conversation

@idosal
Copy link
Collaborator

@idosal idosal commented Jul 17, 2025

Hosts with strict frame-src CSP can't render arbitrary externalUrls. The proxy prop allows them to whitelist a specific domain (the "proxy"), and have that script render an internal sandboxed iframe with the target URL. For convenience, MCP-UI hosts https://proxy.mcpui.dev free of charge.

@idosal idosal requested a review from Copilot July 17, 2025 22:25

This comment was marked as outdated.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Jul 17, 2025

Deploying mcp-ui with  Cloudflare Pages  Cloudflare Pages

Latest commit: 8671501
Status: ✅  Deploy successful!
Preview URL: https://8cd3444d.mcp-ui.pages.dev

View logs

@idosal idosal requested a review from Copilot July 18, 2025 00:00

This comment was marked as outdated.

@idosal idosal requested a review from Copilot July 18, 2025 00:01

This comment was marked as outdated.

@idosal idosal requested a review from Copilot July 18, 2025 00:30

This comment was marked as outdated.

@idosal idosal requested a review from Copilot July 18, 2025 00:34

This comment was marked as outdated.

@idosal idosal requested a review from Copilot July 18, 2025 00:37
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds proxy functionality to the external URL feature in MCP-UI, allowing external URLs to be rendered through a proxy server to comply with strict Content Security Policies. The key changes include adding a proxy parameter to HTML resource processing, implementing security validation to prevent same-origin proxy usage, and providing a complete demonstration example.

  • Adds proxy prop to HTMLResourceRenderer and UIResourceRenderer components for external URL proxying
  • Implements proxy URL validation and security checks to prevent same-origin proxy usage
  • Creates a comprehensive demo example with proxy functionality and CSP demonstration

Reviewed Changes

Copilot reviewed 20 out of 21 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
packages/client/src/utils/processResource.ts Adds proxy parameter and implements proxy URL processing logic with security validation
packages/client/src/components/HTMLResourceRenderer.tsx Adds proxy prop to component interface and passes it to processHTMLResource
packages/client/src/components/UIResourceRenderer.tsx Handles proxy prop filtering for rawHtml vs externalUrl content types
packages/client/src/utils/tests/processResource.test.ts Comprehensive test coverage for proxy functionality including edge cases
packages/client/scripts/proxy/index.html Standalone proxy script for rendering external URLs in nested iframes
examples/external-url-demo/ Complete demo application showcasing proxy functionality with CSP
docs/src/guide/client/ Documentation updates explaining proxy functionality and usage
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

@idosal idosal merged commit 7b95cd0 into main Jul 18, 2025
3 checks passed
github-actions bot pushed a commit that referenced this pull request Jul 18, 2025
# [5.1.0](v5.0.0...v5.1.0) (2025-07-18)

### Features

* add proxy option to externalUrl ([#37](#37)) ([7b95cd0](7b95cd0))
github-actions bot pushed a commit that referenced this pull request Jul 19, 2025
# 1.0.0 (2025-07-19)

### Bug Fixes

* add a bridge to pass messages in and out of the proxy ([#38](#38)) ([30ccac0](30ccac0))
* **client:** specify iframe ([fd0b70a](fd0b70a))
* **client:** styling ([6ff9b68](6ff9b68))
* dependencies ([887f61f](887f61f))
* export RemoteDomResource ([2b86f2d](2b86f2d))
* export ResourceRenderer and HtmlResource ([2b841a5](2b841a5))
* exports ([3a93a16](3a93a16))
* iframe handle ([#15](#15)) ([66bd4fd](66bd4fd))
* lint ([4487820](4487820))
* lint ([d0a91f9](d0a91f9))
* package config ([8dc1e53](8dc1e53))
* packaging ([9e6babd](9e6babd))
* pass ref explicitly using iframeProps ([#33](#33)) ([d01b5d1](d01b5d1))
* publish ([0943e7a](0943e7a))
* ref passing to UIResourceRenderer ([#32](#32)) ([d28c23f](d28c23f))
* remove shared dependency ([e66e8f4](e66e8f4))
* rename components and methods to fit new scope ([#22](#22)) ([6bab1fe](6bab1fe))
* rename delivery -> encoding and flavor -> framework ([#36](#36)) ([9a509ed](9a509ed))
* support react-router ([21ffb95](21ffb95))
* text and blob support in RemoteDOM resources ([ec68eb9](ec68eb9))
* trigger release ([aaca831](aaca831))
* typescript types to be compatible with MCP SDK ([#10](#10)) ([74365d7](74365d7))
* update deps ([4091ef4](4091ef4))
* use targetOrigin in the proxy message relay ([#40](#40)) ([b3fb54e](b3fb54e))
* validate URL ([b7c994d](b7c994d))

### Documentation

* bump ([#4](#4)) ([ad4d163](ad4d163))

### Features

* add proxy option to externalUrl ([#37](#37)) ([7b95cd0](7b95cd0))
* add remote-dom content type ([#18](#18)) ([5dacf37](5dacf37))
* add Ruby server SDK ([#31](#31)) ([5ffcde4](5ffcde4))
* change onGenericMcpAction to optional onUiAction ([1913b59](1913b59))
* **client:** allow setting supportedContentTypes for HtmlResource ([#17](#17)) ([e009ef1](e009ef1))
* consolidate ui:// and ui-app:// ([#8](#8)) ([2e08035](2e08035))
* pass iframe props down ([#14](#14)) ([112539d](112539d))
* separate html and remote-dom props ([#24](#24)) ([a7f0529](a7f0529))
* support generic messages response ([#35](#35)) ([10b407b](10b407b))
* support ui action result types ([#6](#6)) ([899d152](899d152))
* switch to ResourceRenderer ([#21](#21)) ([6fe3166](6fe3166))

### BREAKING CHANGES

* The existing naming is ambiguous. Renaming delivery to encoding and flavor to framework should clarify the intent.
* exported names have changed
* removed deprecated client API
* (previous one didn't take due to semantic-release misalignment)
github-actions bot pushed a commit that referenced this pull request Oct 10, 2025
# 1.0.0-alpha.1 (2025-10-10)

### Bug Fixes

* adapter version ([259c842](259c842))
* add a bridge to pass messages in and out of the proxy ([#38](#38)) ([30ccac0](30ccac0))
* bump client version ([75c9236](75c9236))
* **client:** specify iframe ([fd0b70a](fd0b70a))
* **client:** styling ([6ff9b68](6ff9b68))
* dependencies ([887f61f](887f61f))
* export RemoteDomResource ([2b86f2d](2b86f2d))
* export ResourceRenderer and HtmlResource ([2b841a5](2b841a5))
* exports ([3a93a16](3a93a16))
* iframe handle ([#15](#15)) ([66bd4fd](66bd4fd))
* lint ([4487820](4487820))
* lint ([d0a91f9](d0a91f9))
* minor typo ([a0bee9c](a0bee9c))
* move react dependencies to be peer dependencies ([#91](#91)) ([f672f3e](f672f3e)), closes [#90](#90)
* package config ([8dc1e53](8dc1e53))
* packaging ([9e6babd](9e6babd))
* pass ref explicitly using iframeProps ([#33](#33)) ([d01b5d1](d01b5d1))
* publish ([0943e7a](0943e7a))
* ref passing to UIResourceRenderer ([#32](#32)) ([d28c23f](d28c23f))
* release ([420efc0](420efc0))
* remove shared dependency ([e66e8f4](e66e8f4))
* rename components and methods to fit new scope ([#22](#22)) ([6bab1fe](6bab1fe))
* rename delivery -> encoding and flavor -> framework ([#36](#36)) ([9a509ed](9a509ed))
* Ruby comment ([b22dc2e](b22dc2e))
* support react-router ([21ffb95](21ffb95))
* text and blob support in RemoteDOM resources ([ec68eb9](ec68eb9))
* trigger release ([aaca831](aaca831))
* typescript ci publish ([e7c0ebf](e7c0ebf))
* typescript types to be compatible with MCP SDK ([#10](#10)) ([74365d7](74365d7))
* update deps ([4091ef4](4091ef4))
* update isUIResource to use EmbeddedResource type ([#122](#122)) ([5a65a0b](5a65a0b)), closes [#117](#117)
* use targetOrigin in the proxy message relay ([#40](#40)) ([b3fb54e](b3fb54e))
* validate URL ([b7c994d](b7c994d))
* wc dist overwrite ([#63](#63)) ([9e46c56](9e46c56))

### Documentation

* bump ([#4](#4)) ([ad4d163](ad4d163))

### Features

* add adapters infra (appssdk) ([#125](#125)) ([2e016cd](2e016cd))
* add convenience function isUIResource to client SDK ([#86](#86)) ([607c6ad](607c6ad))
* add embeddedResourceProps for annotations ([#99](#99)) ([b96ec44](b96ec44))
* add proxy option to externalUrl ([#37](#37)) ([7b95cd0](7b95cd0))
* add remote-dom content type ([#18](#18)) ([5dacf37](5dacf37))
* add Ruby server SDK ([#31](#31)) ([5ffcde4](5ffcde4))
* add sandbox permissions instead of an override ([#83](#83)) ([b1068e9](b1068e9))
* add ui-request-render-data message type ([#111](#111)) ([26135ce](26135ce))
* add UIResourceRenderer Web Component ([#58](#58)) ([ec8f299](ec8f299))
* auto resize with the autoResizeIframe prop ([#56](#56)) ([76c867a](76c867a))
* change onGenericMcpAction to optional onUiAction ([1913b59](1913b59))
* **client:** allow setting supportedContentTypes for HtmlResource ([#17](#17)) ([e009ef1](e009ef1))
* consolidate ui:// and ui-app:// ([#8](#8)) ([2e08035](2e08035))
* pass iframe props down ([#14](#14)) ([112539d](112539d))
* refactor UTFtoB64 (bump server version) ([#95](#95)) ([2d5e16b](2d5e16b))
* send render data to the iframe ([#51](#51)) ([d38cfc7](d38cfc7))
* separate html and remote-dom props ([#24](#24)) ([a7f0529](a7f0529))
* support generic messages response ([#35](#35)) ([10b407b](10b407b))
* support passing resource metadata ([#87](#87)) ([f1c1c9b](f1c1c9b))
* support ui action result types ([#6](#6)) ([899d152](899d152))
* switch to ResourceRenderer ([#21](#21)) ([6fe3166](6fe3166))

### BREAKING CHANGES

* The existing naming is ambiguous. Renaming delivery to encoding and flavor to framework should clarify the intent.
* exported names have changed
* removed deprecated client API
* (previous one didn't take due to semantic-release misalignment)
github-actions bot pushed a commit that referenced this pull request Oct 10, 2025
# 1.0.0-alpha.1 (2025-10-10)

### Bug Fixes

* adapter version ([259c842](259c842))
* add a bridge to pass messages in and out of the proxy ([#38](#38)) ([30ccac0](30ccac0))
* bump client version ([75c9236](75c9236))
* **client:** specify iframe ([fd0b70a](fd0b70a))
* **client:** styling ([6ff9b68](6ff9b68))
* dependencies ([887f61f](887f61f))
* export RemoteDomResource ([2b86f2d](2b86f2d))
* export ResourceRenderer and HtmlResource ([2b841a5](2b841a5))
* exports ([3a93a16](3a93a16))
* iframe handle ([#15](#15)) ([66bd4fd](66bd4fd))
* lint ([4487820](4487820))
* lint ([d0a91f9](d0a91f9))
* minor typo ([a0bee9c](a0bee9c))
* move react dependencies to be peer dependencies ([#91](#91)) ([f672f3e](f672f3e)), closes [#90](#90)
* package config ([8dc1e53](8dc1e53))
* packaging ([9e6babd](9e6babd))
* pass ref explicitly using iframeProps ([#33](#33)) ([d01b5d1](d01b5d1))
* publish ([0943e7a](0943e7a))
* ref passing to UIResourceRenderer ([#32](#32)) ([d28c23f](d28c23f))
* release ([420efc0](420efc0))
* remove shared dependency ([e66e8f4](e66e8f4))
* rename components and methods to fit new scope ([#22](#22)) ([6bab1fe](6bab1fe))
* rename delivery -> encoding and flavor -> framework ([#36](#36)) ([9a509ed](9a509ed))
* Ruby comment ([b22dc2e](b22dc2e))
* server versioning ([2324371](2324371))
* support react-router ([21ffb95](21ffb95))
* text and blob support in RemoteDOM resources ([ec68eb9](ec68eb9))
* trigger release ([aaca831](aaca831))
* typescript ci publish ([e7c0ebf](e7c0ebf))
* typescript types to be compatible with MCP SDK ([#10](#10)) ([74365d7](74365d7))
* update deps ([4091ef4](4091ef4))
* update isUIResource to use EmbeddedResource type ([#122](#122)) ([5a65a0b](5a65a0b)), closes [#117](#117)
* use targetOrigin in the proxy message relay ([#40](#40)) ([b3fb54e](b3fb54e))
* validate URL ([b7c994d](b7c994d))
* wc dist overwrite ([#63](#63)) ([9e46c56](9e46c56))

### Documentation

* bump ([#4](#4)) ([ad4d163](ad4d163))

### Features

* add adapters infra (appssdk) ([#125](#125)) ([2e016cd](2e016cd))
* add convenience function isUIResource to client SDK ([#86](#86)) ([607c6ad](607c6ad))
* add embeddedResourceProps for annotations ([#99](#99)) ([b96ec44](b96ec44))
* add proxy option to externalUrl ([#37](#37)) ([7b95cd0](7b95cd0))
* add remote-dom content type ([#18](#18)) ([5dacf37](5dacf37))
* add Ruby server SDK ([#31](#31)) ([5ffcde4](5ffcde4))
* add sandbox permissions instead of an override ([#83](#83)) ([b1068e9](b1068e9))
* add ui-request-render-data message type ([#111](#111)) ([26135ce](26135ce))
* add UIResourceRenderer Web Component ([#58](#58)) ([ec8f299](ec8f299))
* auto resize with the autoResizeIframe prop ([#56](#56)) ([76c867a](76c867a))
* change onGenericMcpAction to optional onUiAction ([1913b59](1913b59))
* **client:** allow setting supportedContentTypes for HtmlResource ([#17](#17)) ([e009ef1](e009ef1))
* consolidate ui:// and ui-app:// ([#8](#8)) ([2e08035](2e08035))
* pass iframe props down ([#14](#14)) ([112539d](112539d))
* refactor UTFtoB64 (bump server version) ([#95](#95)) ([2d5e16b](2d5e16b))
* send render data to the iframe ([#51](#51)) ([d38cfc7](d38cfc7))
* separate html and remote-dom props ([#24](#24)) ([a7f0529](a7f0529))
* support generic messages response ([#35](#35)) ([10b407b](10b407b))
* support passing resource metadata ([#87](#87)) ([f1c1c9b](f1c1c9b))
* support ui action result types ([#6](#6)) ([899d152](899d152))
* switch to ResourceRenderer ([#21](#21)) ([6fe3166](6fe3166))

### BREAKING CHANGES

* The existing naming is ambiguous. Renaming delivery to encoding and flavor to framework should clarify the intent.
* exported names have changed
* removed deprecated client API
* (previous one didn't take due to semantic-release misalignment)
github-actions bot pushed a commit that referenced this pull request Nov 4, 2025
# 1.0.0 (2025-11-04)

### Bug Fixes

* add a bridge to pass messages in and out of the proxy ([#38](#38)) ([30ccac0](30ccac0))
* bump client version ([75c9236](75c9236))
* **client:** specify iframe ([fd0b70a](fd0b70a))
* **client:** styling ([6ff9b68](6ff9b68))
* dependencies ([887f61f](887f61f))
* Enable bidirectional message relay in rawhtml proxy mode ([#138](#138)) ([f0bdefb](f0bdefb))
* ensure Apps SDK adapter is bundled properly and initialized wth config ([#137](#137)) ([4f7c25c](4f7c25c))
* export RemoteDomResource ([2b86f2d](2b86f2d))
* export ResourceRenderer and HtmlResource ([2b841a5](2b841a5))
* exports ([3a93a16](3a93a16))
* fix file extension reference in package.json ([927989c](927989c))
* iframe handle ([#15](#15)) ([66bd4fd](66bd4fd))
* lint ([4487820](4487820))
* lint ([d0a91f9](d0a91f9))
* minor typo ([a0bee9c](a0bee9c))
* move react dependencies to be peer dependencies ([#91](#91)) ([f672f3e](f672f3e)), closes [#90](#90)
* package config ([8dc1e53](8dc1e53))
* packaging ([9e6babd](9e6babd))
* pass ref explicitly using iframeProps ([#33](#33)) ([d01b5d1](d01b5d1))
* publish ([0943e7a](0943e7a))
* ref passing to UIResourceRenderer ([#32](#32)) ([d28c23f](d28c23f))
* remove shared dependency ([e66e8f4](e66e8f4))
* rename components and methods to fit new scope ([#22](#22)) ([6bab1fe](6bab1fe))
* rename delivery -> encoding and flavor -> framework ([#36](#36)) ([9a509ed](9a509ed))
* Ruby comment ([b22dc2e](b22dc2e))
* support react-router ([21ffb95](21ffb95))
* text and blob support in RemoteDOM resources ([ec68eb9](ec68eb9))
* trigger release ([aaca831](aaca831))
* typescript ci publish ([e7c0ebf](e7c0ebf))
* typescript types to be compatible with MCP SDK ([#10](#10)) ([74365d7](74365d7))
* update deps ([4091ef4](4091ef4))
* update isUIResource to use EmbeddedResource type ([#122](#122)) ([5a65a0b](5a65a0b)), closes [#117](#117)
* use targetOrigin in the proxy message relay ([#40](#40)) ([b3fb54e](b3fb54e))
* validate URL ([b7c994d](b7c994d))
* wc dist overwrite ([#63](#63)) ([9e46c56](9e46c56))

### Documentation

* bump ([#4](#4)) ([ad4d163](ad4d163))

### Features

* add convenience function isUIResource to client SDK ([#86](#86)) ([607c6ad](607c6ad))
* add embeddedResourceProps for annotations ([#99](#99)) ([b96ec44](b96ec44))
* add proxy option to externalUrl ([#37](#37)) ([7b95cd0](7b95cd0))
* add remote-dom content type ([#18](#18)) ([5dacf37](5dacf37))
* add Ruby server SDK ([#31](#31)) ([5ffcde4](5ffcde4))
* add sandbox permissions instead of an override ([#83](#83)) ([b1068e9](b1068e9))
* add ui-request-render-data message type ([#111](#111)) ([26135ce](26135ce))
* add UIResourceRenderer Web Component ([#58](#58)) ([ec8f299](ec8f299))
* auto resize with the autoResizeIframe prop ([#56](#56)) ([76c867a](76c867a))
* change onGenericMcpAction to optional onUiAction ([1913b59](1913b59))
* **client:** allow setting supportedContentTypes for HtmlResource ([#17](#17)) ([e009ef1](e009ef1))
* consolidate ui:// and ui-app:// ([#8](#8)) ([2e08035](2e08035))
* pass iframe props down ([#14](#14)) ([112539d](112539d))
* refactor UTFtoB64 (bump server version) ([#95](#95)) ([2d5e16b](2d5e16b))
* send render data to the iframe ([#51](#51)) ([d38cfc7](d38cfc7))
* separate html and remote-dom props ([#24](#24)) ([a7f0529](a7f0529))
* support adapters ([#127](#127)) ([d4bd152](d4bd152))
* support generic messages response ([#35](#35)) ([10b407b](10b407b))
* support metadata in Python SDK ([#134](#134)) ([9bc3c64](9bc3c64))
* support passing resource metadata ([#87](#87)) ([f1c1c9b](f1c1c9b))
* support proxy for rawHtml ([#132](#132)) ([1bbeb09](1bbeb09))
* support ui action result types ([#6](#6)) ([899d152](899d152))
* switch to ResourceRenderer ([#21](#21)) ([6fe3166](6fe3166))

### BREAKING CHANGES

* The existing naming is ambiguous. Renaming delivery to encoding and flavor to framework should clarify the intent.
* exported names have changed
* removed deprecated client API
* (previous one didn't take due to semantic-release misalignment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants