Skip to content

feat(mcp): add cross-platform pack workspace - #2631

Open
andrew-bierman wants to merge 5 commits into
mainfrom
feat/chatgpt-app
Open

feat(mcp): add cross-platform pack workspace#2631
andrew-bierman wants to merge 5 commits into
mainfrom
feat/chatgpt-app

Conversation

@andrew-bierman

@andrew-bierman andrew-bierman commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

Description

PackRat packs can now open as the same native workspace in ChatGPT and Claude while the existing
MCP endpoint remains fully usable by generic clients. Both hosts share one portable MCP Apps UI,
one OAuth flow, and the same thin Eden Treaty-backed tool layer—there is no provider-specific
backend or second data path to maintain.

The first workspace is read-only. get_pack retains its complete text fallback for clients that
ignore UI metadata while supplying a bounded structured snapshot to the sandboxed widget. The UI
uses the standard MCP Apps initialization lifecycle, renders untrusted values with safe DOM APIs,
reports dynamic size changes, and has no network access in its CSP.

Session-settled decision carried from planning: extend the existing MCP Worker and preserve Eden
Treaty as the sole business-data boundary (user-directed).

Type of change

  • 🐛 Bug fix
  • ✨ New feature
  • ♻️ Refactor / code improvement
  • 📝 Documentation update
  • 🔧 CI / configuration change
  • ⬆️ Dependency update
  • 🗄️ Database migration

Area(s) affected

  • Mobile app (apps/expo)
  • API / Backend (packages/mcp)
  • Landing page (apps/landing)
  • Guides site (apps/guides)
  • CI / CD (.github/)

Testing

  • Added / updated unit tests — the pre-crash branch passed all 80 MCP tests
  • Manually tested on iOS
  • Manually tested on Android
  • Manually tested on Web — exercised a host iframe through initialize, initialized,
    tool-result rendering, unit conversion, and sizing
  • API endpoints verified — Wrangler production dry-run bundled successfully with the existing
    bindings before the recovery update

The pre-crash branch also passed bun run check, the repository custom lint suite, package
ordering/catalog checks, and clean-tree hooks. After recovery, git diff --check passes and the
new commit hook completed, but the local dependency tree remained too slow to collect Vitest after
the crash; CI is the authoritative rerun for the final head. Live ChatGPT and Claude Team
registration require a public Worker with deployed KV bindings and were not exercised locally.

Screenshots / recordings

No artifact attached; the browser-host validation was local and is summarized above.

New concepts

MCP Apps as a presentation profile

MCP Apps is not a competing data protocol beside MCP. It is an MCP resource profile that lets a
tool result point at a sandboxed HTML view while retaining ordinary content for clients that do
not render apps.

flowchart TB
  Hosts[ChatGPT, Claude, or another MCP host] --> Worker[PackRat MCP Worker]
  Worker --> Treaty[Eden Treaty client]
  Treaty --> API[PackRat API]
  Worker --> Result[Text fallback + structured snapshot]
  Result --> Widget[Sandboxed pack workspace]
Loading

This keeps authorization and business behavior in the API instead of duplicating them in each AI
surface. A provider-specific backend would make sense only if a host required behavior outside the
portable MCP contract.

Pre-merge checklist

  • Formatting and clean-tree hooks report no new errors
  • bun check-types passes with no errors — MCP strict tsc is repo-disabled; Wrangler deploy
    dry-run is the package type/bundle gate
  • No new secrets or credentials are committed
  • Database migration not required
  • Feature flag added — not applicable; the workspace is attached only to get_pack metadata
    and generic MCP behavior is preserved
  • PR title follows conventional commits (feat:, fix:, chore:, etc.)

Summary by CodeRabbit

  • New Features
    • Added a read-only PackRat pack workspace widget (versioned UI resource) for ChatGPT Apps.
    • Enhanced the get_pack tool to return structured pack snapshots plus readable text fallback for broader MCP client support.
    • Implemented safe, bounded widget rendering with unit normalization and deterministic item/category truncation.
  • Documentation
    • Added end-to-end MCP /mcp documentation, including setup, health checks, Inspector validation, and live dev verification steps.
  • Tests
    • Added extensive coverage for widget contract, structured responses, normalization/truncation rules, and error/security behavior.

@github-actions github-actions Bot added documentation Improvements or additions to documentation dependencies Pull requests that update a dependency file labels Jul 18, 2026
@coderabbitai

coderabbitai Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@andrew-bierman, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 54 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 28b10b0e-4ba8-4550-89c3-0de7bccd0909

📥 Commits

Reviewing files that changed from the base of the PR and between 91e97b5 and 23ccb82.

📒 Files selected for processing (2)
  • docs/plans/2026-07-17-001-feat-chatgpt-pack-app-plan.md
  • packages/mcp/README.md

Walkthrough

Adds a versioned MCP Apps pack workspace widget, bounded structured get_pack results with text fallbacks, safe rendering and normalization tests, server wiring, and documentation for local, Inspector, deployment, and ChatGPT validation workflows.

Changes

Pack workspace MCP App

Layer / File(s) Summary
Widget resource and snapshot contract
packages/mcp/src/apps/pack-widget.ts, packages/mcp/src/client.ts, packages/mcp/package.json, packages/mcp/src/__tests__/apps.test.ts
Adds the versioned ui:// resource, CSP metadata, bounded PackSnapshot normalization, structured result support, safe DOM rendering, and coverage for rendering, validation, truncation, and weight calculations.
get_pack structured result integration
packages/mcp/src/tools/packs.ts, packages/mcp/src/index.ts, packages/mcp/src/__tests__/apps.test.ts
Registers the widget during MCP initialization and connects get_pack to normalized structured results, UI metadata, text fallbacks, and ordinary error handling.
Developer workflow and validation documentation
docs/plans/..., packages/mcp/README.md
Documents the product contract, implementation plan, MCP Inspector checks, ChatGPT Developer Mode setup, deployment steps, and validation checklist.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ChatGPT
  participant MCPWorker
  participant PackRatAPI
  participant PackWorkspaceWidget
  ChatGPT->>MCPWorker: call get_pack
  MCPWorker->>PackRatAPI: request pack data
  PackRatAPI-->>MCPWorker: return pack response
  MCPWorker->>MCPWorker: normalize bounded PackSnapshot
  MCPWorker-->>ChatGPT: structuredContent and text fallback
  ChatGPT->>PackWorkspaceWidget: render structured content
  PackWorkspaceWidget-->>ChatGPT: send initialization and resize messages
Loading

Suggested labels: api

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is concise and accurately describes the main change: adding a pack workspace to the MCP app.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/chatgpt-app

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for packages/units (./packages/units)

Status Category Percentage Covered / Total
🟢 Lines 100% (🎯 100%) 35 / 35
🟢 Statements 100% (🎯 100%) 35 / 35
🟢 Functions 100% (🎯 100%) 6 / 6
🟢 Branches 100% (🎯 100%) 11 / 11
File CoverageNo changed files found.
Generated in workflow #497 for commit 23ccb82 by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for packages/mcp (./packages/mcp)

Status Category Percentage Covered / Total
🟢 Lines 99.41% (🎯 95%) 337 / 339
🟢 Statements 99.41% (🎯 95%) 337 / 339
🟢 Functions 100% (🎯 95%) 18 / 18
🟢 Branches 98.11% (🎯 90%) 104 / 106
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/mcp/src/client.ts 98.23% 98.36% 100% 98.23% 187-188
packages/mcp/src/apps/pack-widget.ts 100% 97.14% 100% 100%
Generated in workflow #497 for commit 23ccb82 by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for apps/expo (./apps/expo)

Status Category Percentage Covered / Total
🟢 Lines 97.52% (🎯 95%) 590 / 605
🟢 Statements 97.52% (🎯 95%) 590 / 605
🟢 Functions 100% (🎯 97%) 51 / 51
🟢 Branches 95.3% (🎯 92%) 203 / 213
File CoverageNo changed files found.
Generated in workflow #497 for commit 23ccb82 by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for packages/overpass (./packages/overpass)

Status Category Percentage Covered / Total
🟢 Lines 100% (🎯 80%) 155 / 155
🟢 Statements 100% (🎯 80%) 155 / 155
🟢 Functions 100% (🎯 80%) 13 / 13
🟢 Branches 95.65% (🎯 70%) 44 / 46
File CoverageNo changed files found.
Generated in workflow #497 for commit 23ccb82 by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for packages/api (./packages/api)

Status Category Percentage Covered / Total
🟢 Lines 98.78% (🎯 95%) 1136 / 1150
🟢 Statements 98.78% (🎯 95%) 1136 / 1150
🟢 Functions 100% (🎯 97%) 58 / 58
🟢 Branches 95.23% (🎯 92%) 440 / 462
File CoverageNo changed files found.
Generated in workflow #497 for commit 23ccb82 by the Vitest Coverage Report Action

@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Coverage Report for packages/analytics (./packages/analytics)

Status Category Percentage Covered / Total
🟢 Lines 93.68% (🎯 80%) 697 / 744
🟢 Statements 93.68% (🎯 80%) 697 / 744
🟢 Functions 97.87% (🎯 85%) 46 / 47
🟢 Branches 85.8% (🎯 80%) 133 / 155
File CoverageNo changed files found.
Generated in workflow #497 for commit 23ccb82 by the Vitest Coverage Report Action

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/plans/2026-07-17-001-feat-chatgpt-pack-app-plan.md`:
- Line 54: Remove the unsupported serialized-size bound claim from the plan and
its associated test claim, unless implementing enforcement in the pack-widget
normalization and client serialization flow. Keep only bounds that are actually
enforced by the normalization logic, including field lengths, row counts, and
categories.
- Line 45: Update the documented MCP fallback contract to match client.ts:
describe content as the complete structured snapshot serialized as formatted
JSON rather than “terse.” In
docs/plans/2026-07-17-001-feat-chatgpt-pack-app-plan.md at line 45, update R3
and its acceptance wording; in packages/mcp/README.md at lines 75-76, update the
Inspector validation expectation accordingly.

In `@packages/mcp/README.md`:
- Line 150: Update the health-check checklist entry in the README to distinguish
protocols: specify that local checks use an HTTP origin, while tunneled and
deployed checks use HTTPS. Keep the existing health-check success requirement
unchanged.

In `@packages/mcp/src/__tests__/apps.test.ts`:
- Around line 247-264: Replace the source-string assertions in the “uses
parent-only bridge messages and safe text DOM APIs for API-derived values” test
with execution in a DOM harness using the generated resource HTML. Dispatch
representative host messages and assert observable rendered text plus emitted
protocol messages, including initialization, tool results, and size changes;
retain coverage for parent-origin filtering and safe API-derived text without
checking implementation strings.
- Around line 183-201: Update the normalizePackSnapshot overflow test fixture to
use weight and quantity values that each satisfy their individual schema limits
while their product exceeds the aggregate derived-weight bound. Keep the
existing item structure and null expectation unchanged.

In `@packages/mcp/src/apps/pack-widget.ts`:
- Line 23: Update the weight-unit conversion logic to explicitly support only g,
kg, oz, lb, and lbs, preserving each unit’s existing conversion behavior. In the
relevant conversion and calculation paths around weightUnit, ensure unsupported
values such as "stone" return null rather than defaulting to factor 1 or being
treated as grams.
- Line 36: Bound the input array before Zod parsing and downstream aggregation
in the pack-widget flow. Add a documented maximum item-count check around the
schema containing items and reject or truncate oversized API responses before
safeParse(), category aggregation, and sorting; preserve the existing 50-row
display cap for output rendering.

In `@packages/mcp/src/tools/packs.ts`:
- Around line 52-61: The get_pack handler currently uses the bounded
normalizePackSnapshot result for both response channels. In
packages/mcp/src/tools/packs.ts lines 52-61, update the onSuccess path to
preserve the original API data as text while attaching the bounded snapshot only
as structuredContent. In packages/mcp/src/__tests__/apps.test.ts lines 47-98,
extend the fixture with data beyond the snapshot boundary and assert text
includes it while structured content remains bounded.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 585d858c-9edb-4c7e-a20a-e6b03260400e

📥 Commits

Reviewing files that changed from the base of the PR and between d328194 and 3083d42.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock, !bun.lock
📒 Files selected for processing (8)
  • docs/plans/2026-07-17-001-feat-chatgpt-pack-app-plan.md
  • packages/mcp/README.md
  • packages/mcp/package.json
  • packages/mcp/src/__tests__/apps.test.ts
  • packages/mcp/src/apps/pack-widget.ts
  • packages/mcp/src/client.ts
  • packages/mcp/src/index.ts
  • packages/mcp/src/tools/packs.ts

Comment thread docs/plans/2026-07-17-001-feat-chatgpt-pack-app-plan.md Outdated
Comment thread docs/plans/2026-07-17-001-feat-chatgpt-pack-app-plan.md Outdated
Comment thread packages/mcp/README.md Outdated
Comment thread packages/mcp/src/__tests__/apps.test.ts
Comment thread packages/mcp/src/__tests__/apps.test.ts
Comment thread packages/mcp/src/apps/pack-widget.ts
Comment thread packages/mcp/src/apps/pack-widget.ts
Comment thread packages/mcp/src/tools/packs.ts
@andrew-bierman andrew-bierman changed the title feat(mcp): add ChatGPT pack workspace feat(mcp): add cross-platform pack workspace Jul 19, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/plans/2026-07-17-001-feat-chatgpt-pack-app-plan.md (1)

204-204: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Narrow the payload-bound guarantee.

okStructured preserves the complete Eden response in text content (packages/mcp/src/client.ts), while only structuredContent is bounded. This DoD item currently implies that the entire model/widget payload is bounded. Restrict the claim to the structured widget snapshot, or add a cap to the intentional text fallback.

Proposed wording
- oversized packs cannot create an unbounded model/widget payload.
+ oversized packs cannot create an unbounded structured widget snapshot.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/plans/2026-07-17-001-feat-chatgpt-pack-app-plan.md` at line 204, Update
the payload-bound guarantee in the plan to apply only to the bounded structured
widget snapshot, unless the intentional text fallback in okStructured is also
capped. Align the wording with the behavior of structuredContent and avoid
claiming that the complete Eden response text content is bounded.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/plans/2026-07-17-001-feat-chatgpt-pack-app-plan.md`:
- Line 54: Clarify the serialized-size guarantee across the plan and README: at
docs/plans/2026-07-17-001-feat-chatgpt-pack-app-plan.md:54, either specify and
enforce a UTF-8 byte ceiling or limit the claim to structural/character bounds;
at docs/plans/2026-07-17-001-feat-chatgpt-pack-app-plan.md:167, align the test
requirement with that guarantee, including non-ASCII inputs if validating bytes;
and at packages/mcp/README.md:216-217, remove any implication that the
32,000-character repository test proves Claude’s external host limit.

---

Outside diff comments:
In `@docs/plans/2026-07-17-001-feat-chatgpt-pack-app-plan.md`:
- Line 204: Update the payload-bound guarantee in the plan to apply only to the
bounded structured widget snapshot, unless the intentional text fallback in
okStructured is also capped. Align the wording with the behavior of
structuredContent and avoid claiming that the complete Eden response text
content is bounded.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d83752fc-0fbb-4e7d-aae4-cc6b4cb73002

📥 Commits

Reviewing files that changed from the base of the PR and between 3083d42 and 91e97b5.

📒 Files selected for processing (6)
  • docs/plans/2026-07-17-001-feat-chatgpt-pack-app-plan.md
  • packages/mcp/README.md
  • packages/mcp/src/__tests__/apps.test.ts
  • packages/mcp/src/apps/pack-widget.ts
  • packages/mcp/src/client.ts
  • packages/mcp/src/tools/packs.ts

Comment thread docs/plans/2026-07-17-001-feat-chatgpt-pack-app-plan.md Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant