fix(calendar): avoid remote avatars in MCP embeds#889
Conversation
When Calendar is rendered inside an MCP host iframe (ChatGPT / Claude embed *.agent-native.com through their own sandboxed wrapper with strict COEP/CORP headers), Google account / Google Contacts avatar images (`*.googleusercontent.com`) get blocked at the browser level and produce noisy console errors. Mirror the Mail PR #883 pattern: - New `templates/calendar/app/lib/mcp-embed.ts` helper exporting `isMcpEmbedSurface()` that detects the embed flag in the URL (`?embedded=1`). Same shape as the Mail-side helper. - Gate the account-avatar `<img>` in CalendarView.tsx and the contact-avatar `<img>` in AttendeeAutocomplete.tsx on `!isMcpEmbedSurface()`. In MCP embed mode they fall back to the existing same-origin initial chip / IconUserCircle, which is already the no-photo branch — same UX as Mail's COEP fix. Doesn't touch outside the embed surface — normal Calendar UI keeps the existing remote avatars. Tests: 4 new vitest cases in mcp-embed.spec.ts. Typecheck clean.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Builder reviewed your changes — looks good ✅
Review Details
Code Review Summary
This PR adds COEP/CORP compliance to the Calendar template by suppressing remote Google avatar images when rendered inside MCP host iframes (ChatGPT / Claude). The implementation is clean and straightforward:
What changed:
- New
isMcpEmbedSurface()helper detects the?embedded=1query parameter flag - Gated account avatars in
CalendarView.tsx(header avatar pile) and contact avatars inAttendeeAutocomplete.tsx(attendee list) to fall back to same-origin initials/icons when embedded - 4 unit tests cover the detection logic: non-browser environment,
?embedded=1, legacy?embedded=true, and ignoring unrelated params
Approach evaluation:
✅ Follows the established Mail PR #883 pattern exactly — mirrors the architecture, detection logic, and fallback behavior
✅ Minimal, surgical changes — only touches the two avatar locations that produce COEP errors
✅ Preserves normal Calendar UI — avatars remain unchanged outside embed surfaces
✅ Future-proof — comments acknowledge that lifting isMcpEmbedSurface to shared core library is a follow-up
Key qualities:
- Correct detection logic with safe server-side guards (
typeof window === "undefined") - Proper test coverage on the core utility function
- Clear, contextual comments explaining the COEP/CORP headers and fallback behavior
- No refactoring or complexity added — pure addition
🧪 Browser testing: Skipped — PR only modifies component rendering logic and adds a utility helper, no new routes or layout changes. Normal Calendar UI is untouched.
Summary
When Calendar is rendered inside an MCP host iframe (ChatGPT / Claude embed
*.agent-native.comthrough their own sandboxed wrapper with strict COEP/CORP headers), Google account / Google Contacts avatar images (*.googleusercontent.com) get blocked at the browser level and produce noisy console errors.Mirrors the Mail PR #883 pattern (Mail's avatar COEP fix landing concurrently from another agent):
templates/calendar/app/lib/mcp-embed.tshelper exportingisMcpEmbedSurface()that detects the embed flag in the URL (?embedded=1). Same shape as the Mail-side helper.<img>inCalendarView.tsx(header avatar pile) and the contact-avatar<img>inAttendeeAutocomplete.tsxon!isMcpEmbedSurface(). In MCP embed mode they fall back to the existing same-origin initial chip /IconUserCircle— same UX as Mail's COEP fix.Doesn't touch outside the embed surface — normal Calendar UI keeps the existing remote avatars.
A future cleanup could lift
isMcpEmbedSurfaceto@agent-native/core/clientso every template uses one helper instead of one-file copies per template. Leaving that as a follow-up to match the Mail PR's shape.Found by
The same audit pass that surfaced the Mail issue PR #883 fixed. Found by the chrome E2E agent's report on PR #884: "Google avatars get COEP-blocked in MCP iframe". Mail was fixed in PR #883; this PR fixes the equivalent two spots in Calendar (
CalendarView.tsx:1495andAttendeeAutocomplete.tsx:449).Tests
mcp-embed.spec.tscovering: outside-browser (false),?embedded=1(true), legacy?embedded=true(true), unrelated query params (false).pnpm --filter calendar typecheck✓ clean.