-
Notifications
You must be signed in to change notification settings - Fork 5
Add iframe support to canvas panel for MCP tool responses #106
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Added support for iframe type artifacts in CanvasPanel - Updated DOMPurify configuration to allow iframes with proper sandboxing - Added handling for display.canvas.type = "iframe" from v2 MCP spec - Created demo MCP tool to test iframe functionality - Configured proper security attributes (sandbox) for iframes Co-authored-by: garland3 <1162675+garland3@users.noreply.github.com>
Co-authored-by: garland3 <1162675+garland3@users.noreply.github.com>
Added create_html_with_iframe tool to demonstrate HTML artifacts that include embedded iframes within the HTML content Co-authored-by: garland3 <1162675+garland3@users.noreply.github.com>
Co-authored-by: garland3 <1162675+garland3@users.noreply.github.com>
- Extract DOMPurify config to constant to avoid duplication - Simplify download check logic with helper variable - Make default sandbox more restrictive (removed allow-forms) - Update documentation with more secure defaults Co-authored-by: garland3 <1162675+garland3@users.noreply.github.com>
- Add DEFAULT_IFRAME_SANDBOX constant for consistency - Extract canDownloadFile helper function for readability - Use constants in both CanvasPanel and websocketHandlers Co-authored-by: garland3 <1162675+garland3@users.noreply.github.com>
…loading-in-canvas
🔒 Security Scan ResultsSecurity Scan SummaryScan ResultsPython SAST (Bandit)Recommendations
|
…tions Improve documentation for the create_button_demo function to provide clearer descriptions of its capabilities, use cases, technical implementation, and integration features. This update helps developers and users better understand the tool's features and benefits for UI prototyping and demonstrations.
🔒 Security Scan ResultsSecurity Scan SummaryScan ResultsPython SAST (Bandit)Recommendations
|
…ding and document requirements in the configuration
…ate documentation
🔒 Security Scan ResultsSecurity Scan SummaryScan ResultsPython SAST (Bandit)Recommendations
|
… configuration and update related tests
…e backend test script output
…improve config loading
🔒 Security Scan ResultsSecurity Scan SummaryScan ResultsPython SAST (Bandit)Recommendations
|
There was a problem hiding this 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 comprehensive iframe support to the canvas panel, enabling MCP tools to display external content such as dashboards, visualizations, and web applications. The implementation follows the v2 MCP contract specification and includes two approaches: direct iframe display via display config and HTML artifacts with embedded iframes. The changes include extensive security hardening through DOMPurify sanitization, CSP configuration, and restrictive iframe sandboxing by default.
Key Changes
- Frontend iframe rendering with configurable sandbox attributes and DOMPurify sanitization
- Backend support for iframe-only display configurations (no artifacts required)
- Demo tools showcasing both iframe approaches
- Comprehensive documentation covering CSP configuration requirements and security considerations
Reviewed changes
Copilot reviewed 44 out of 44 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/components/CanvasPanel.jsx | Added iframe viewer type with DOMPurify config for safe HTML sanitization and canDownloadFile helper |
| frontend/src/handlers/chat/websocketHandlers.js | Creates virtual canvas files from iframe display configs, handles open_canvas flag |
| frontend/src/handlers/chat/websocketHandlers.test.js | Test coverage for iframe canvas file creation from display config |
| frontend/src/hooks/chat/useChatConfig.js | Added isCanvasOpen state for programmatic canvas panel control |
| frontend/src/contexts/ChatContext.jsx | Wired setIsCanvasOpen to websocket handlers |
| backend/application/chat/utilities/file_utils.py | Enhanced process_tool_artifacts and notify_canvas_files_v2 to handle iframe-only displays |
| backend/mcp/ui-demo/main.py | Added create_iframe_demo and create_html_with_iframe demo tools |
| backend/modules/mcp_tools/client.py | Enhanced config loading to support custom config paths for testing |
| backend/tests/test_mcp_prompts_server.py | Updated to use mcp-example-configs for isolated test configuration |
| backend/tests/test_mcp_prompt_override_system_prompt.py | Updated to use mcp-example-configs for isolated test configuration |
| config/overrides/mcp.json | Added ui-demo server configuration, removed external-api-example (moved to example configs) |
| config/overrides/mcp-test.json | Deleted (servers moved to individual example configs) |
| config/overrides/env-var-mcp.json | Deleted (moved to mcp-example-configs/mcp-env-demo.json) |
| config/mcp-example-configs/*.json | Created individual MCP server example configurations for isolated testing |
| docs/developer/creating-mcp-servers.md | Added iframe support section with CSP configuration requirements |
| docs/developer/canvas-renderers.md | Documented iframe viewer type and CSP configuration for external URLs |
| docs/archive/03_developer_guide.md | Added iframe support examples and security considerations |
| docs/admin/configuration.md | Added Security Configuration section with CSP guidance for iframe URLs |
| .env.example | Added CSP configuration comments and example with www.sandia.gov allowed |
| GEMINI.md, CLAUDE.md, .github/copilot-instructions.md | Added note about mcp-example-configs location |
| test/backend_tests.sh | Added debug output for BACKEND_DIR |
Comments suppressed due to low confidence (7)
frontend/src/components/CanvasPanel.jsx:51
- Unused variable MAX_WIDTH.
frontend/src/contexts/ChatContext.jsx:41 - Unused variable pendingFileEvents.
frontend/src/components/CanvasPanel.jsx:408 - Avoid automated semicolon insertion (94% of all statements in the enclosing function have an explicit semicolon).
backend/modules/mcp_tools/client.py:733 - This comment appears to contain commented-out code.
# try:
# logger.info(
# f"get_tools_schema: requested={tool_names} matched={len(matched)} missing={missing} available_index_size={len(index)}"
backend/modules/mcp_tools/client.py:737
- This comment appears to contain commented-out code.
# if missing:
# logger.warning(
# "Some requested tools were not found. This usually means discover_tools() ran before those tools were available, or the tool names contain unexpected characters. Missing: %s", missing
backend/modules/mcp_tools/client.py:740
- This comment appears to contain commented-out code.
# except Exception:
# pass
backend/modules/mcp_tools/client.py:11
- Import of 'create_authorization_manager' is not used.
from core.auth_utils import create_authorization_manager
| # To allow https://dashboard.example.com and https://www.sandia.gov/ | ||
| SECURITY_CSP_VALUE="default-src 'self'; img-src 'self' data: blob:; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self'; frame-src 'self' blob: data: https://dashboard.example.com https://www.sandia.gov/; frame-ancestors 'self'" |
Copilot
AI
Nov 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Inconsistent URL formatting: Line 164 uses https://www.sandia.gov/ (with trailing slash) but line 163's comment refers to the same URL without a trailing slash. The CSP directive should match the actual URL used in the code examples. Consider using https://www.sandia.gov (without trailing slash) in line 164 to match the comment, or update the comment to include the trailing slash.
| ############################################# | ||
| # SPLASH_CONFIG_FILE=splash-config.json # Splash screen configuration file name | ||
| # MCP_CONFIG_FILE=mcp.json # MCP servers configuration file name | ||
| # MCP_CONFIG_FILE=mcp.json # MCP servers configuration file name |
Copilot
AI
Nov 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Inconsistent spacing alignment in the comment. Line 88 has extra spaces before the comment delimiter, while other lines (87, 89, 90) have a single space. For consistency, align with the pattern used in lines 87, 89, and 90.
| # MCP_CONFIG_FILE=mcp.json # MCP servers configuration file name | |
| # MCP_CONFIG_FILE=mcp.json # MCP servers configuration file name |
| print(backend_root) | ||
| project_root = backend_root.parent | ||
| print(project_root) | ||
| config_path = project_root / "config" / "mcp-example-configs" / "mcp-prompts.json" | ||
| print(config_path) |
Copilot
AI
Nov 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Debug print statements should be removed before merging. The print() calls on lines 15, 17, and 19 appear to be left over from debugging and should be replaced with proper logging using the logger module if needed, or removed entirely.
| print(backend_root) | |
| project_root = backend_root.parent | |
| print(project_root) | |
| config_path = project_root / "config" / "mcp-example-configs" / "mcp-prompts.json" | |
| print(config_path) | |
| project_root = backend_root.parent | |
| config_path = project_root / "config" / "mcp-example-configs" / "mcp-prompts.json" | |
| # IMPORTANT: To allow external URLs in iframes (for MCP tools that use iframe display), | ||
| # add the URLs to the frame-src directive. Example: | ||
| # SECURITY_CSP_VALUE="... frame-src 'self' blob: data: https://example.com https://dashboard.example.com; ..." | ||
| # HERE the www.sandia.gov is added as an allowed iframe source. |
Copilot
AI
Nov 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment "HERE the www.sandia.gov is added as an allowed iframe source" is unclear and grammatically awkward. Consider rephrasing to: "In this example, https://www.sandia.gov is added as an allowed iframe source."
| # HERE the www.sandia.gov is added as an allowed iframe source. | |
| # In this example, https://www.sandia.gov is added as an allowed iframe source. |
| return JSON.stringify(content, null, 2) | ||
| } catch (e) { | ||
| } catch { | ||
| return String(content || '') |
Copilot
AI
Nov 22, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This use of variable 'content' always evaluates to true.
MCP tools can now display external content via iframes in the canvas panel, following the v2 MCP contract spec for dashboard/visualization embedding.
Implementation
Frontend (
CanvasPanel.jsx,websocketHandlers.js)iframefile type rendering with configurable sandbox attributes<iframe>tags with whitelisted attributes (src, sandbox, allow, allowfullscreen, frameborder, scrolling)display.type = "iframe"from v2 MCP spec to create virtual canvas filesIFRAME_SANITIZE_CONFIGandDEFAULT_IFRAME_SANDBOXconstantsBackend (
mcp/ui-demo/main.py)Security
allow-scripts allow-same-origin(restrictive by default)display.sandboxfield if neededUsage
Approach 1: Direct iframe via display config
Approach 2: HTML artifact with embedded iframe
Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
astral.sh/usr/bin/curl curl -LsSf REDACTED(dns block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.