Skip to content

temp PR#7207

Closed
aharvard wants to merge 6 commits intomainfrom
aharvard/mcp-app-fallback-request
Closed

temp PR#7207
aharvard wants to merge 6 commits intomainfrom
aharvard/mcp-app-fallback-request

Conversation

@aharvard
Copy link
Collaborator

@aharvard aharvard commented Feb 13, 2026

accidental PR

Generate an ephemeral self-signed TLS certificate at startup so goosed
serves over HTTPS. This gives MCP app iframes a secure context, enabling
browser APIs (crypto.subtle, clipboard, etc.) and making 3rd-party
iframe injection viable.

Changes:
- Add tls module that generates a self-signed cert for 127.0.0.1/localhost
- Switch axum::serve to axum_server::bind_rustls for TLS termination
- Update Electron baseUrl from http to https
- Add certificate-error handler in Electron for localhost self-signed cert
- Set NODE_TLS_REJECT_UNAUTHORIZED=0 for main-process health checks
- Update CSP connect-src to allow https://127.0.0.1:*
MCP app guest iframes previously used srcdoc to inject HTML, which gave
them a URL of about:srcdoc. This caused third-party SDKs (like Square
Web Payments SDK) to fail because they check window.location.protocol
and reject anything that isn't https: or localhost.

This commit adds a /mcp-app-guest endpoint that stores guest HTML
server-side and serves it from a real https://localhost:{port} URL:

Server changes (mcp_app_proxy.rs):
- Added POST /mcp-app-guest to store HTML with a unique nonce
- Added GET /mcp-app-guest to retrieve and serve stored HTML with
  proper CSP headers (script-src, connect-src, frame-src, style-src)
- In-memory HashMap<String, StoredHtml> with 5-minute TTL and
  automatic cleanup on each request
- HTML is consumed on first retrieval (one-time use)

Proxy template changes (mcp_app_proxy.html):
- On receiving guest HTML via postMessage, the proxy now POSTs it
  to /mcp-app-guest to get a nonce, then sets the guest iframe src
  to GET /mcp-app-guest?secret=...&nonce=...
- Falls back to srcdoc if the endpoint is unavailable
- createGuestIframe is now async to support the fetch workflow

Auth changes (auth.rs):
- Added /mcp-app-guest to the auth exemption list (it uses its own
  secret query parameter for authentication, same as /mcp-app-proxy)

Desktop changes (goosed.ts, main.ts):
- Switched baseUrl from https://127.0.0.1:{port} to
  https://localhost:{port} so that SDKs with built-in localhost
  exceptions (like Square) recognize the origin
- Added http://localhost:* and https://localhost:* to the Electron
  CSP connect-src allowlist
- Updated default GOOSE_API_HOST to http://localhost
Replace process-wide NODE_TLS_REJECT_UNAUTHORIZED=0 with Electron's
net.fetch for the goosed API client. net.fetch uses Chromium's network
stack which respects the certificate-error handler already scoped to
localhost/127.0.0.1, so external fetch calls (fetch-metadata,
getAllowList) retain strict TLS verification.
The handler was inside appMain() but net.fetch needs it registered
before any createChat() call. Code paths like open-url and
second-instance can call createChat() before appMain() runs.
The certificate-error handler only applies to webContents (renderer)
requests. net.fetch in the main process needs
setCertificateVerifyProc on the default session to accept self-signed
certs from localhost. Registered via app.whenReady() before appMain()
to ensure it's active before any health check.
Wire up the onFallbackRequest callback on AppRenderer to handle
unrecognized MCP JSON-RPC requests. This is a stub that logs the
request method and returns success, with a todo to implement
sampling/createMessage per #7039.

- Import RequestHandlerExtra from @mcp-ui/client
- Import JSONRPCRequest from @modelcontextprotocol/sdk/types.js
- Add handleFallbackRequest callback with correct types
- Pass handler to AppRenderer's onFallbackRequest prop
Copilot AI review requested due to automatic review settings February 13, 2026 12:38
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 infrastructure for handling MCP app secure contexts and wires up a fallback request handler to McpAppRenderer. The changes enable MCP apps to run in HTTPS contexts (required by SDKs like Square Web Payments) by implementing self-signed TLS certificates for the local goosed server.

Changes:

  • Added onFallbackRequest handler to McpAppRenderer (stub implementation logging requests)
  • Implemented self-signed TLS certificate generation for localhost in goosed server
  • Modified goosed to serve over HTTPS instead of HTTP
  • Added guest HTML storage system to serve iframe content from real HTTPS URLs
  • Updated Electron to trust self-signed certificates from localhost/127.0.0.1

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
ui/desktop/src/components/McpApps/McpAppRenderer.tsx Added handleFallbackRequest callback with correct types and imports
crates/goose-server/src/tls.rs New module for generating self-signed TLS certificates using rcgen
ui/desktop/src/main.ts Added certificate error handlers and CSP updates for HTTPS support
ui/desktop/src/goosed.ts Changed base URL from http to https
crates/goose-server/src/routes/templates/mcp_app_proxy.html Added JavaScript to store guest HTML server-side and load via real HTTPS URLs
crates/goose-server/src/routes/mcp_app_proxy.rs Added endpoints for storing/serving guest HTML with nonce-based retrieval
crates/goose-server/src/commands/agent.rs Modified to use axum-server with TLS config and graceful shutdown
crates/goose-server/src/auth.rs Added /mcp-app-guest to public endpoint list
crates/goose-server/Cargo.toml Added rcgen and axum-server dependencies

Comment on lines +14 to +17
/// In-memory store for guest HTML content.
/// Maps nonce -> (html_content, csp_string)
/// Entries are consumed on first read (one-time use).
type GuestHtmlStore = Arc<RwLock<HashMap<String, (String, String)>>>;
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The guest HTML store could accumulate unconsumed entries if a nonce is stored but never retrieved. Consider adding a cleanup mechanism such as:

  • Entries with timestamps that expire after a timeout (e.g., 5 minutes)
  • A periodic cleanup task to remove stale entries
  • A size limit with eviction policy

Without cleanup, failed iframe loads or app crashes could leave entries in memory indefinitely.

Copilot uses AI. Check for mistakes.
Comment on lines +236 to +245
headers.insert(
header::HeaderName::from_static("referrer-policy"),
"strict-origin".parse().unwrap(),
);
if !csp.is_empty() {
headers.insert(
header::CONTENT_SECURITY_POLICY,
csp.parse().unwrap(),
);
}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

Using unwrap on CSP header parsing could panic if the CSP string contains invalid header value characters. Consider handling this error gracefully by either:

  • Validating the CSP string before inserting it into storage
  • Using a Result type and returning an error response if parsing fails
  • Providing a fallback CSP or omitting the header if invalid

The codebase convention (per HOWTOAI.md) is to use anyhow::Result for error handling rather than panic-prone patterns.

Suggested change
headers.insert(
header::HeaderName::from_static("referrer-policy"),
"strict-origin".parse().unwrap(),
);
if !csp.is_empty() {
headers.insert(
header::CONTENT_SECURITY_POLICY,
csp.parse().unwrap(),
);
}
if let Ok(referrer_policy) = "strict-origin".parse() {
headers.insert(
header::HeaderName::from_static("referrer-policy"),
referrer_policy,
);
}
if !csp.is_empty() {
if let Ok(csp_header) = csp.parse() {
headers.insert(
header::CONTENT_SECURITY_POLICY,
csp_header,
);
}
}

Copilot uses AI. Check for mistakes.
onLoggingMessage={handleLoggingMessage}
onSizeChanged={handleSizeChanged}
onError={handleError}
onFallbackRequest={handleFallbackRequest}
Copy link

Copilot AI Feb 13, 2026

Choose a reason for hiding this comment

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

The PR title and description focus on adding the onFallbackRequest handler to McpAppRenderer, but this PR includes substantial infrastructure changes:

  • Self-signed TLS certificate generation
  • Certificate verification bypass for localhost
  • Guest HTML storage system with nonce-based retrieval
  • CSP modifications
  • URL scheme changes from http to https

Consider splitting these into separate PRs or updating the description to accurately reflect all changes. This makes the PR easier to review and understand the full scope of modifications.

Copilot uses AI. Check for mistakes.
@aharvard aharvard closed this Feb 13, 2026
@aharvard aharvard changed the title Add onFallbackRequest handler to McpAppRenderer temp PR Feb 13, 2026
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.

1 participant