feat(ext-apps-support): Update ext-apps library to version 0.4.0 - #96
Conversation
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. 📝 WalkthroughSummary by CodeRabbit
✏️ Tip: You can customize this high-level summary in your review settings. WalkthroughAdds a Model Context API (AppsClient.updateModelContext + useUpdateModelContext), new types (ContainerDimensions, ContentBlock, UpdateModelContextParams), containerDimensions-driven viewport derivation in the MCP adapter, implementations of updateModelContext in MCP/OpenAI/Mock adapters, dependency/version updates, tests, build config adjustments, and a new UI error code INVALID_PARAMS. Changes
Sequence Diagram(s)sequenceDiagram
participant App as App (consumer)
participant Hook as useUpdateModelContext
participant Client as AppsClient
participant Adapter as ProtocolAdapter (MCP / OpenAI / Mock)
participant Host as Host/SDK (ext-apps / window.openai)
App->>Hook: call updateModelContext(params)
Hook->>Client: client.updateModelContext(params)
Client->>Adapter: adapter.updateModelContext(params)
Adapter->>Host: forward structured modelContext / setWidgetState / SDK call
Host-->>Adapter: ack / no-op
Adapter-->>Client: resolve
Client-->>Hook: resolve
Hook-->>App: Promise resolved
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Comment |
…y with 5 updates Bumps the production-dependencies group with 5 updates in the / directory: | Package | From | To | | --- | --- | --- | | [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk) | `1.25.1` | `1.25.2` | | [zod](https://github.com/colinhacks/zod) | `4.2.1` | `4.3.5` | | [@modelcontextprotocol/ext-apps](https://github.com/modelcontextprotocol/ext-apps) | `0.2.2` | `0.4.0` | | [@typescript-eslint/typescript-estree](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-estree) | `8.50.1` | `8.53.0` | | [esbuild](https://github.com/evanw/esbuild) | `0.25.12` | `0.27.2` | Updates `@modelcontextprotocol/sdk` from 1.25.1 to 1.25.2 - [Release notes](https://github.com/modelcontextprotocol/typescript-sdk/releases) - [Commits](modelcontextprotocol/typescript-sdk@1.25.1...v1.25.2) Updates `zod` from 4.2.1 to 4.3.5 - [Release notes](https://github.com/colinhacks/zod/releases) - [Commits](colinhacks/zod@v4.2.1...v4.3.5) Updates `@modelcontextprotocol/ext-apps` from 0.2.2 to 0.4.0 - [Release notes](https://github.com/modelcontextprotocol/ext-apps/releases) - [Changelog](https://github.com/modelcontextprotocol/ext-apps/blob/main/RELEASES.md) - [Commits](modelcontextprotocol/ext-apps@v0.2.2...v0.4.0) Updates `@typescript-eslint/typescript-estree` from 8.50.1 to 8.53.0 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-estree/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.53.0/packages/typescript-estree) Updates `esbuild` from 0.25.12 to 0.27.2 - [Release notes](https://github.com/evanw/esbuild/releases) - [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md) - [Commits](evanw/esbuild@v0.25.12...v0.27.2) --- updated-dependencies: - dependency-name: "@modelcontextprotocol/sdk" dependency-version: 1.25.2 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: production-dependencies - dependency-name: zod dependency-version: 4.3.5 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production-dependencies - dependency-name: "@modelcontextprotocol/ext-apps" dependency-version: 0.4.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production-dependencies - dependency-name: "@typescript-eslint/typescript-estree" dependency-version: 8.53.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production-dependencies - dependency-name: esbuild dependency-version: 0.27.2 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: production-dependencies ... Signed-off-by: dependabot[bot] <support@github.com>
Add support for ext-apps v0.4.0 features: - Add updateModelContext() method to inform AI model about app state without triggering follow-up actions - MCP Apps: Uses native protocol feature - ChatGPT: Uses setState/setWidgetState (which exposes to AI context) - Add containerDimensions type for new viewport semantics (fixed vs flexible) - Add new HostCapabilities: updateModelContext, message, sandbox - Add useUpdateModelContext() React hook for model context updates - Add tests for all new functionality Breaking changes in ext-apps handled: - containerDimensions replaces viewport (we derive viewport for backward compat) - New capability types for content block modalities Note: On ChatGPT, both setState and updateModelContext expose state to the AI model. Use setState for persistence-focused use cases, updateModelContext for context-focused use cases.
f0f2aa5 to
b47ee88
Compare
|
@claude Document the relationship - Make it clear that on ChatGPT, updateModelContext uses setState internally |
|
Claude finished @gabrypavanello's task in 2m 27s —— View job Documentation task completed ✓
Changes MadeUpdated documentation in three files to clarify the relationship between
All documentation now clearly states:
The key message is now clear: developers should use CommitPushed commit |
Document the relationship between updateModelContext() and setState() on ChatGPT platform: - On MCP Apps: Uses native protocol feature for pure context updates - On ChatGPT: Uses setState/setWidgetState internally (exposes to AI + persists) - Both methods expose state to AI model on ChatGPT Updated documentation in: - packages/ui/src/adapters/openai.ts - Implementation comment - packages/ui/src/types.ts - AppsClient interface JSDoc - packages/ui-react/src/hooks.ts - useUpdateModelContext hook JSDoc Co-authored-by: Gabe <gabrypavanello@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @packages/ui-react-builder/package.json:
- Around line 58-59: The package.json currently lists
"@typescript-eslint/typescript-estree" and "esbuild" under "dependencies" which
are build-time tools; move both entries into "devDependencies" (remove them from
"dependencies" and add them under "devDependencies") so the published package
only contains runtime deps referenced by the "files" exports; after updating
package.json run your package manager install to update lockfiles and verify
build/lint configs are compatible with esbuild 0.27 and typescript-eslint v8
(adjust parserOptions or esbuild usage if needed).
In @packages/ui/src/adapters/openai.ts:
- Around line 539-564: The updateModelContext function currently merges
params.structuredContent into modelContext which can overwrite reserved
properties like _type and _textContent; before calling Object.assign in
updateModelContext, check params.structuredContent for reserved
underscore-prefixed keys (e.g., "_type", "_textContent"), and if any are present
either remove those keys from the object or log/throw a clear warning via
clientDebugLogger (or throw an Error) so they aren’t merged; then merge the
cleaned structuredContent into modelContext and proceed to setState with the
safe object so reserved fields remain intact.
In @packages/ui/src/types.ts:
- Around line 537-566: The docstring for updateModelContext incorrectly claims
"On ChatGPT: Silent no-op"; update it to reflect that on ChatGPT the OpenAI
adapter uses setState (which maps to setWidgetState) to expose context to the
model. Edit the comment for updateModelContext to state that on ChatGPT the
adapter calls setState / setWidgetState to surface context to the model (and
that it still behaves as a non-triggering context update), referencing
updateModelContext, setState, and setWidgetState so readers can locate the
implementation in the OpenAI adapter.
🧹 Nitpick comments (2)
packages/ui/tests/unit/mcp-adapter.test.ts (1)
272-281: Consider adding a positive path test forupdateModelContext.The current tests verify error handling and method existence, but there's no test that calls
updateModelContextsuccessfully after connection. While the adapter may not have a real parent window in the test environment, you could verify it doesn't throw when connected (similar to howsetStateis tested on line 35).💡 Optional: Add positive path test
describe("updateModelContext (ext-apps v0.4.0+)", () => { it("should throw when not connected", async () => { await expect( adapter.updateModelContext({ structuredContent: { test: true } }) ).rejects.toThrow("MCP Apps adapter not connected"); }); it("should have updateModelContext method", async () => { await adapter.connect(); expect(typeof adapter.updateModelContext).toBe("function"); }); + + it("should accept valid params when connected", async () => { + await adapter.connect(); + // Without a real parent window, this may still fail, but validates the call path + await expect( + adapter.updateModelContext({ structuredContent: { key: "value" } }) + ).rejects.toThrow(); // Expected without real host + }); });packages/ui/src/types.ts (1)
443-463: Consider using a stricter discriminated union for ContentBlock.The current interface allows any combination of optional fields regardless of
type. A stricter discriminated union would provide better type safety:type ContentBlock = | { type: "text"; text: string } | { type: "image"; data: string; mimeType: string } | { type: "audio"; data: string; mimeType: string } | { type: "resource"; uri: string; text?: string } | { type: "resource_link"; uri: string; name?: string; description?: string };However, the current approach is simpler and acceptable for an
@internaltype. This is a minor refinement that could be deferred.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (19)
examples/minimal/package.jsonexamples/restaurant-finder/package.jsonexamples/weather-app/package.jsonpackages/core/package.jsonpackages/testing/package.jsonpackages/ui-react-builder/package.jsonpackages/ui-react/src/hooks.tspackages/ui-react/src/index.tspackages/ui/package.jsonpackages/ui/src/adapters/mcp.tspackages/ui/src/adapters/mock.tspackages/ui/src/adapters/openai.tspackages/ui/src/adapters/types.tspackages/ui/src/client.tspackages/ui/src/index.tspackages/ui/src/types.tspackages/ui/tests/unit/mcp-adapter.test.tspackages/ui/tests/unit/mock-adapter.test.tspackages/ui/tests/unit/openai-adapter.test.ts
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use Express 5 (not 4) - async error handling works differently
Files:
packages/ui/src/adapters/types.tspackages/ui-react/src/index.tspackages/ui/src/client.tspackages/ui/src/index.tspackages/ui/src/types.tspackages/ui/src/adapters/openai.tspackages/ui/tests/unit/mock-adapter.test.tspackages/ui/tests/unit/openai-adapter.test.tspackages/ui-react/src/hooks.tspackages/ui/tests/unit/mcp-adapter.test.tspackages/ui/src/adapters/mock.tspackages/ui/src/adapters/mcp.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Use strict TypeScript - noanytypes, useunknownwith type narrowing instead
UsedefineToolanddefineUI(ordefineReactUIfor React components) for type inference
Useexport typefor type-only exports to prevent runtime imports of types
Files:
packages/ui/src/adapters/types.tspackages/ui-react/src/index.tspackages/ui/src/client.tspackages/ui/src/index.tspackages/ui/src/types.tspackages/ui/src/adapters/openai.tspackages/ui/tests/unit/mock-adapter.test.tspackages/ui/tests/unit/openai-adapter.test.tspackages/ui-react/src/hooks.tspackages/ui/tests/unit/mcp-adapter.test.tspackages/ui/src/adapters/mock.tspackages/ui/src/adapters/mcp.ts
packages/ui/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (packages/ui/AGENTS.md)
packages/ui/**/*.{ts,tsx,js,jsx}: UsecreateClient()with proper await - it is an async function, not synchronous
Handle both MCP and OpenAI response formats when calling tools
Ensure adapter.connect() is awaited before subscribing to events or rendering
Set uponHostContextChangesubscription before first render to ensure theme applies correctly
Files:
packages/ui/src/adapters/types.tspackages/ui/src/client.tspackages/ui/src/index.tspackages/ui/src/types.tspackages/ui/src/adapters/openai.tspackages/ui/tests/unit/mock-adapter.test.tspackages/ui/tests/unit/openai-adapter.test.tspackages/ui/tests/unit/mcp-adapter.test.tspackages/ui/src/adapters/mock.tspackages/ui/src/adapters/mcp.ts
packages/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (packages/ui/AGENTS.md)
Provide type parameter to
createClient<typeof app.tools()>()for proper typed tool calls
Files:
packages/ui/src/adapters/types.tspackages/ui/src/client.tspackages/ui/src/index.tspackages/ui/src/types.tspackages/ui/src/adapters/openai.tspackages/ui/tests/unit/mock-adapter.test.tspackages/ui/tests/unit/openai-adapter.test.tspackages/ui/tests/unit/mcp-adapter.test.tspackages/ui/src/adapters/mock.tspackages/ui/src/adapters/mcp.ts
**/index.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Export only through
index.tsfiles to keep public API clean and enable safe refactoring
Files:
packages/ui-react/src/index.tspackages/ui/src/index.ts
packages/ui-react/**/*.{tsx,ts}
📄 CodeRabbit inference engine (packages/ui-react/AGENTS.md)
Always type the
useToolResult<T>()hook with a generic parameter specifying the tool output type
Files:
packages/ui-react/src/index.tspackages/ui-react/src/hooks.ts
🧠 Learnings (20)
📓 Common learnings
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui-react/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:36.676Z
Learning: Applies to packages/ui-react/**/*.{tsx,jsx} : Ensure components using MCP hooks (`useAppsClient`, `useToolResult`, `useHostContext`, `useDocumentTheme`, `useHostStyleVariables`) are rendered within an `AppsProvider` context wrapper
📚 Learning: 2026-01-11T17:08:13.651Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/core/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:13.651Z
Learning: Applies to packages/core/src/**/*.{ts,tsx} : Ensure Zod 4 APIs are used, not Zod 3 APIs which have breaking changes
Applied to files:
examples/minimal/package.jsonpackages/testing/package.jsonexamples/restaurant-finder/package.jsonexamples/weather-app/package.jsonpackages/core/package.json
📚 Learning: 2026-01-11T17:08:03.538Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T17:08:03.538Z
Learning: Use Zod 4 (not 3) - be aware of breaking changes from v3 migration
Applied to files:
examples/minimal/package.jsonexamples/restaurant-finder/package.jsonexamples/weather-app/package.jsonpackages/core/package.json
📚 Learning: 2026-01-11T17:08:30.346Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui-react-builder/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:30.346Z
Learning: Ensure the vite peer dependency is installed when using the mcp-apps-kit/ui-react-builder/vite plugin
Applied to files:
examples/minimal/package.jsonexamples/restaurant-finder/package.jsonpackages/ui-react-builder/package.jsonexamples/weather-app/package.json
📚 Learning: 2026-01-11T17:08:36.676Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui-react/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:36.676Z
Learning: Applies to packages/ui-react/**/*.{tsx,jsx} : Ensure components using MCP hooks (`useAppsClient`, `useToolResult`, `useHostContext`, `useDocumentTheme`, `useHostStyleVariables`) are rendered within an `AppsProvider` context wrapper
Applied to files:
examples/minimal/package.jsonpackages/ui-react/src/index.tspackages/ui/package.jsonexamples/restaurant-finder/package.jsonpackages/ui/src/index.tspackages/ui-react-builder/package.jsonpackages/ui-react/src/hooks.tspackages/ui/tests/unit/mcp-adapter.test.tsexamples/weather-app/package.jsonpackages/ui/src/adapters/mcp.ts
📚 Learning: 2026-01-11T17:08:19.638Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/create-app/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:19.638Z
Learning: Applies to packages/create-app/**/*.{ts,tsx,js} : Generate projects using npm (not pnpm) to avoid workspace conflicts in mcp-apps-kit/create-app scaffolded projects
Applied to files:
examples/minimal/package.jsonpackages/ui/package.jsonexamples/restaurant-finder/package.jsonpackages/ui-react-builder/package.jsonexamples/weather-app/package.json
📚 Learning: 2026-01-11T17:08:36.676Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui-react/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:36.676Z
Learning: Applies to packages/ui-react/**/*.{tsx,jsx} : Wrap your React application with `AppsProvider` context provider to enable access to MCP client and host context
Applied to files:
examples/minimal/package.jsonpackages/ui-react/src/index.tspackages/ui/package.jsonexamples/restaurant-finder/package.jsonpackages/ui-react/src/hooks.tsexamples/weather-app/package.jsonpackages/ui/src/adapters/mcp.ts
📚 Learning: 2026-01-11T17:08:19.638Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/create-app/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:19.638Z
Learning: Applies to packages/create-app/**/*.{ts,tsx,js} : Verify that package versions fetched from npm registry at runtime are valid before generating projects in mcp-apps-kit/create-app
Applied to files:
examples/minimal/package.jsonpackages/ui/package.jsonexamples/restaurant-finder/package.jsonpackages/ui-react-builder/package.jsonexamples/weather-app/package.json
📚 Learning: 2026-01-11T17:08:30.346Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui-react-builder/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:30.346Z
Learning: Applies to packages/ui-react-builder/**/*.tsx : Use .tsx extension for files containing JSX and ensure jsx: 'automatic' is configured in esbuild settings
Applied to files:
examples/minimal/package.jsonpackages/ui-react/src/index.tspackages/ui/package.jsonpackages/ui-react-builder/package.json
📚 Learning: 2026-01-11T17:08:36.676Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui-react/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:36.676Z
Learning: Applies to packages/ui-react/**/*.{tsx,jsx} : Use `useDocumentTheme()` and `useHostStyleVariables()` hooks to automatically apply theming based on host context (theme and locale)
Applied to files:
packages/ui-react/src/index.tspackages/ui-react/src/hooks.ts
📚 Learning: 2026-01-11T17:08:36.676Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui-react/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:36.676Z
Learning: Applies to packages/ui-react/**/*.{tsx,ts} : Always type the `useToolResult<T>()` hook with a generic parameter specifying the tool output type
Applied to files:
packages/ui-react/src/index.tspackages/ui-react/src/hooks.ts
📚 Learning: 2026-01-11T17:08:42.176Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:42.176Z
Learning: Applies to packages/ui/**/*.{ts,tsx} : Provide type parameter to `createClient<typeof app.tools()>()` for proper typed tool calls
Applied to files:
packages/ui-react/src/index.tspackages/ui/package.jsonpackages/ui/src/client.tspackages/ui/src/index.tspackages/ui-react-builder/package.jsonpackages/ui/src/adapters/openai.ts
📚 Learning: 2026-01-11T17:08:13.651Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/core/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:13.651Z
Learning: Applies to packages/core/src/**/*.{ts,tsx} : Use `defineTool` and `defineUI` for type inference instead of inline objects
Applied to files:
packages/ui-react/src/index.tspackages/ui/src/index.ts
📚 Learning: 2026-01-11T17:08:03.538Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T17:08:03.538Z
Learning: Applies to **/*.{ts,tsx} : Use `defineTool` and `defineUI` (or `defineReactUI` for React components) for type inference
Applied to files:
packages/ui-react/src/index.ts
📚 Learning: 2026-01-11T17:08:42.176Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:42.176Z
Learning: Applies to packages/ui/**/*.{ts,tsx,js,jsx} : Handle both MCP and OpenAI response formats when calling tools
Applied to files:
packages/ui-react/src/index.tsexamples/restaurant-finder/package.jsonpackages/ui/src/index.tspackages/ui/src/adapters/openai.tsexamples/weather-app/package.jsonpackages/ui/src/adapters/mcp.ts
📚 Learning: 2026-01-11T17:08:24.463Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/testing/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:24.463Z
Learning: Ensure optional peer dependencies (vitest, jest, fast-check, openai, anthropic-ai/sdk) are installed when using LLM evaluation features
Applied to files:
packages/testing/package.jsonpackages/ui/tests/unit/openai-adapter.test.ts
📚 Learning: 2026-01-11T17:08:03.538Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-11T17:08:03.538Z
Learning: Applies to tests/**/*.{ts,tsx,js,jsx} : Tests should mirror source structure in `tests/` directory
Applied to files:
packages/ui/tests/unit/mock-adapter.test.ts
📚 Learning: 2026-01-11T17:08:24.463Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/testing/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:24.463Z
Learning: Applies to packages/testing/**/vitest.config.ts : Import and set up vitest or jest matchers in the test setup file before tests run (e.g., setupVitestMatchers for vitest)
Applied to files:
packages/ui/tests/unit/openai-adapter.test.ts
📚 Learning: 2026-01-11T17:08:42.176Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:42.176Z
Learning: Applies to packages/ui/**/*.{ts,tsx,js,jsx} : Set up `onHostContextChange` subscription before first render to ensure theme applies correctly
Applied to files:
packages/ui-react/src/hooks.ts
📚 Learning: 2026-01-11T17:08:42.176Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:42.176Z
Learning: Applies to packages/ui/**/*.{ts,tsx,js,jsx} : Ensure adapter.connect() is awaited before subscribing to events or rendering
Applied to files:
packages/ui/tests/unit/mcp-adapter.test.ts
🧬 Code graph analysis (5)
packages/ui/src/adapters/types.ts (3)
packages/ui-react/src/index.ts (1)
UpdateModelContextParams(23-23)packages/ui/src/index.ts (1)
UpdateModelContextParams(58-58)packages/ui/src/types.ts (1)
UpdateModelContextParams(468-480)
packages/ui/src/client.ts (1)
packages/ui/src/types.ts (1)
UpdateModelContextParams(468-480)
packages/ui/src/types.ts (2)
packages/ui-react/src/index.ts (3)
ContainerDimensions(21-21)ContentBlock(22-22)UpdateModelContextParams(23-23)packages/ui/src/index.ts (3)
ContainerDimensions(29-29)ContentBlock(57-57)UpdateModelContextParams(58-58)
packages/ui/src/adapters/mock.ts (3)
packages/ui-react/src/index.ts (1)
UpdateModelContextParams(23-23)packages/ui/src/index.ts (1)
UpdateModelContextParams(58-58)packages/ui/src/types.ts (1)
UpdateModelContextParams(468-480)
packages/ui/src/adapters/mcp.ts (1)
packages/ui/src/types.ts (4)
ContainerDimensions(274-278)HostContext(317-364)UpdateModelContextParams(468-480)HostCapabilities(15-165)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: test-and-lint
- GitHub Check: claude-review
🔇 Additional comments (30)
examples/restaurant-finder/package.json (1)
22-22: LGTM!The zod version bump to ^4.3.5 aligns with the coordinated dependency updates across the monorepo.
examples/weather-app/package.json (1)
24-24: LGTM!Consistent zod version bump matching other examples in this PR.
examples/minimal/package.json (1)
25-25: LGTM!Consistent zod version bump across all example packages.
packages/testing/package.json (1)
64-66: LGTM!Both dependency bumps are appropriate:
- @modelcontextprotocol/sdk patch bump (1.25.1 → 1.25.2)
- zod version aligned with other packages in the monorepo
packages/ui/package.json (1)
47-47: Core dependency update driving this PR.The bump to @modelcontextprotocol/ext-apps ^0.4.0 enables the new features (updateModelContext, containerDimensions, HostCapabilities). The package version (0.4.0) appropriately aligns with the ext-apps dependency version, and all three features are extensively utilized throughout the codebase with comprehensive test coverage.
packages/ui/src/adapters/types.ts (2)
18-18: LGTM!The import is correctly added alongside other type imports from
../types.
72-82: LGTM!The
updateModelContextmethod is well-documented with clear platform-specific behavior (MCP Apps vs ChatGPT graceful degradation). The method signature correctly uses the newUpdateModelContextParamstype and follows the established patterns in this interface.packages/core/package.json (2)
45-49: LGTM!The dependency updates are appropriate:
@modelcontextprotocol/sdkpatch bump (1.25.1 → 1.25.2)zodstays within v4 (4.0.0 → 4.3.5), consistent with the project's Zod 4 requirement per learnings
56-56: LGTM!The
zodpeer dependency version correctly matches the regular dependency version (^4.3.5), ensuring consistency for consumers.packages/ui/src/index.ts (2)
29-29: LGTM!The
ContainerDimensionstype is correctly added to the public type exports, supporting the new viewport semantics introduced in ext-apps v0.4.0.
56-58: LGTM!The model context types (
ContentBlock,UpdateModelContextParams) are properly exported with a clear descriptive comment indicating they are for ext-apps v0.4.0+. This follows the established export organization pattern in this file.packages/ui/tests/unit/mcp-adapter.test.ts (1)
254-270: LGTM!Good test coverage for the
updateModelContextmethod:
- Validates error handling when adapter is not connected
- Confirms method availability after connection
The test pattern is consistent with other method tests in this file.
packages/ui-react/src/index.ts (2)
20-24: LGTM!The new model context types (
ContainerDimensions,ContentBlock,UpdateModelContextParams) are correctly exported usingexport typesyntax as required by coding guidelines, with clear version annotations.
58-60: LGTM!The
useUpdateModelContexthook is properly exported with a clear comment indicating the ext-apps v0.4.0+ requirement, maintaining consistency with the existing hook export pattern.packages/ui/src/client.ts (2)
23-24: LGTM!The
UpdateModelContextParamstype import is correctly added alongside other type imports.
121-126: LGTM!The
updateModelContextmethod correctly delegates to the adapter, following the same pattern as other methods likesendMessageandopenLink. The async/await handling is consistent with the existing codebase patterns.packages/ui-react/src/hooks.ts (2)
17-18: LGTM!The
UpdateModelContextParamstype import is correctly added with the other type imports from@mcp-apps-kit/ui.
254-303: LGTM!The
useUpdateModelContexthook is well-implemented:
- Follows the established pattern of using
useAppsContext()anduseCallbackwith proper dependencies- Provides graceful degradation with a console warning when client is unavailable
- The JSDoc example correctly demonstrates usage with
useEffectand proper dependency management- The memoized callback ensures stable function identity when client doesn't change
Based on learnings, components using this hook should be rendered within an
AppsProvidercontext wrapper.packages/ui/tests/unit/mock-adapter.test.ts (1)
407-461: LGTM!Comprehensive test coverage for the new
updateModelContextAPI:
- Tests console logging behavior for debugging
- Tests state storage via
getLastModelContext()helper- Tests both text content blocks and structured content input types
- Properly follows existing test patterns with
beforeEachsetup and console spy cleanuppackages/ui/tests/unit/openai-adapter.test.ts (2)
9-9: LGTM!The
afterEachimport is correctly added to support test cleanup.
404-485: LGTM!Excellent test coverage for the OpenAI adapter's
updateModelContextimplementation:
- Tests verify the transformation to
setWidgetStateformat with_type: "modelContext"marker- Tests text content concatenation logic (joining with newlines)
- Tests graceful degradation when SDK is unavailable, confirming local state storage still works
- Mock setup and cleanup is handled correctly in each test
packages/ui/src/adapters/mock.ts (1)
139-155: LGTM! Clean mock implementation for updateModelContext.The mock adapter correctly stores the last model context for test verification and follows the established logging pattern. The
getLastModelContext()helper enables straightforward unit test assertions.packages/ui/src/adapters/openai.ts (1)
550-559: LGTM! Text content extraction is correctly implemented.The filter ensures only text blocks with actual content are processed, and joining with newlines provides a readable format for the model context.
packages/ui/src/adapters/mcp.ts (4)
280-296: LGTM! Clean containerDimensions parsing with backward-compatible viewport derivation.The implementation correctly:
- Extracts
containerDimensionswhen provided by the host- Derives
viewportfrom container dimensions for backward compatibility- Falls back to explicit viewport or defaults when containerDimensions is absent
This ensures existing code using
viewportcontinues to work while supporting the new ext-apps v0.4.0+ semantics.
321-336: LGTM! Viewport derivation correctly handles both fixed and flexible dimension semantics.The helper properly maps:
- Fixed dimensions (
height/width) directly to viewport- Flexible dimensions (
maxHeight/maxWidth) preserved for apps that need them- Falls back to defaults when specific dimensions aren't provided
425-457: LGTM! Model context update implementation with appropriate type mappings.The method correctly:
- Validates connection state before proceeding
- Maps text, image, and audio content blocks to ext-apps format
- Provides sensible fallbacks for resource types (converting to text representation)
- Passes through structuredContent directly
The default mimeType values (
image/png,audio/wav) are reasonable fallbacks when the caller doesn't specify.
649-654: LGTM! New ext-apps v0.4.0+ capabilities correctly exposed.The capabilities mapping properly exposes
updateModelContext,message, andsandboxfrom the SDK, allowing apps to feature-detect these new capabilities.packages/ui/src/types.ts (3)
74-136: LGTM! Well-structured capability definitions for ext-apps v0.4.0+.The new capabilities follow the established pattern:
updateModelContextandmessageenumerate supported content block typessandboxproperly models permissions and CSP configuration domains- All use
Record<string, never>for boolean-like capability flags, consistent with existing definitions
265-278: LGTM! ContainerDimensions type correctly models the ext-apps dimension semantics.The union type captures the four valid combinations of fixed vs. flexible dimensions, with clear documentation explaining when each applies.
465-480: LGTM! Clean public interface for model context updates.The interface provides flexibility by making both
contentandstructuredContentoptional, allowing callers to use either or both as needed.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b47ee8808a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Use existing setState which calls setWidgetState | ||
| this.setState(modelContext); |
There was a problem hiding this comment.
Preserve widget state when updating model context
On ChatGPT, updateModelContext() builds a fresh modelContext object and passes it directly to setState, which replaces the entire widget state. Any app that uses useWidgetState/setState for persistence will lose its stored state as soon as updateModelContext runs (and getState() will return the model context on reload). This makes the new API incompatible with existing persisted state unless the update merges with prior state or stores model context under a namespaced key.
Useful? React with 👍 / 👎.
| default: | ||
| // For resource types, fall back to text representation | ||
| return { type: "text" as const, text: block.text ?? block.uri ?? "" }; |
There was a problem hiding this comment.
Preserve resource content blocks in MCP updateModelContext
UpdateModelContextParams allows resource/resource_link content blocks, but the MCP adapter maps every non-text/image/audio block to a text fallback. As a result, resource URIs/names/descriptions are dropped and the host never receives real resource blocks, even when HostCapabilities.updateModelContext advertises them. In MCP Apps contexts that send resource blocks, this silently downgrades content and breaks host-side handling.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (1)
packages/ui/src/adapters/openai.ts (1)
527-569: LGTM! Good documentation of platform-specific behavior.The JSDoc clearly documents that
updateModelContextusessetState/setWidgetStateinternally on ChatGPT, which addresses the PR objective about clarifying this relationship. The_type: "modelContext"marker is a nice touch for distinguishing context updates from regular state.Consider using a type guard or type assertion for slightly improved type safety in the content block filtering:
♻️ Optional type safety improvement
// Convert content blocks to text representation for the model if (params.content && params.content.length > 0) { const textContent = params.content - .filter((block) => block.type === "text" && block.text) - .map((block) => block.text) + .filter((block): block is { type: "text"; text: string } => + block.type === "text" && typeof block.text === "string" && block.text.length > 0) + .map((block) => block.text) .join("\n");
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
packages/ui-react/src/hooks.tspackages/ui/src/adapters/openai.tspackages/ui/src/types.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/ui/src/types.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use Express 5 (not 4) - async error handling works differently
Files:
packages/ui/src/adapters/openai.tspackages/ui-react/src/hooks.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Use strict TypeScript - noanytypes, useunknownwith type narrowing instead
UsedefineToolanddefineUI(ordefineReactUIfor React components) for type inference
Useexport typefor type-only exports to prevent runtime imports of types
Files:
packages/ui/src/adapters/openai.tspackages/ui-react/src/hooks.ts
packages/ui/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (packages/ui/AGENTS.md)
packages/ui/**/*.{ts,tsx,js,jsx}: UsecreateClient()with proper await - it is an async function, not synchronous
Handle both MCP and OpenAI response formats when calling tools
Ensure adapter.connect() is awaited before subscribing to events or rendering
Set uponHostContextChangesubscription before first render to ensure theme applies correctly
Files:
packages/ui/src/adapters/openai.ts
packages/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (packages/ui/AGENTS.md)
Provide type parameter to
createClient<typeof app.tools()>()for proper typed tool calls
Files:
packages/ui/src/adapters/openai.ts
packages/ui-react/**/*.{tsx,ts}
📄 CodeRabbit inference engine (packages/ui-react/AGENTS.md)
Always type the
useToolResult<T>()hook with a generic parameter specifying the tool output type
Files:
packages/ui-react/src/hooks.ts
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui-react/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:36.676Z
Learning: Applies to packages/ui-react/**/*.{tsx,jsx} : Ensure components using MCP hooks (`useAppsClient`, `useToolResult`, `useHostContext`, `useDocumentTheme`, `useHostStyleVariables`) are rendered within an `AppsProvider` context wrapper
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:42.176Z
Learning: Applies to packages/ui/**/*.{ts,tsx,js,jsx} : Handle both MCP and OpenAI response formats when calling tools
📚 Learning: 2026-01-11T17:08:42.176Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:42.176Z
Learning: Applies to packages/ui/**/*.{ts,tsx} : Provide type parameter to `createClient<typeof app.tools()>()` for proper typed tool calls
Applied to files:
packages/ui/src/adapters/openai.tspackages/ui-react/src/hooks.ts
📚 Learning: 2026-01-11T17:08:36.676Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui-react/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:36.676Z
Learning: Applies to packages/ui-react/**/*.{tsx,jsx} : Ensure components using MCP hooks (`useAppsClient`, `useToolResult`, `useHostContext`, `useDocumentTheme`, `useHostStyleVariables`) are rendered within an `AppsProvider` context wrapper
Applied to files:
packages/ui-react/src/hooks.ts
📚 Learning: 2026-01-11T17:08:36.676Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui-react/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:36.676Z
Learning: Applies to packages/ui-react/**/*.{tsx,jsx} : Use `useDocumentTheme()` and `useHostStyleVariables()` hooks to automatically apply theming based on host context (theme and locale)
Applied to files:
packages/ui-react/src/hooks.ts
📚 Learning: 2026-01-11T17:08:36.676Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui-react/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:36.676Z
Learning: Applies to packages/ui-react/**/*.{tsx,jsx} : Wrap your React application with `AppsProvider` context provider to enable access to MCP client and host context
Applied to files:
packages/ui-react/src/hooks.ts
📚 Learning: 2026-01-11T17:08:36.676Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui-react/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:36.676Z
Learning: Applies to packages/ui-react/**/*.{tsx,ts} : Always type the `useToolResult<T>()` hook with a generic parameter specifying the tool output type
Applied to files:
packages/ui-react/src/hooks.ts
📚 Learning: 2026-01-11T17:08:42.176Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:42.176Z
Learning: Applies to packages/ui/**/*.{ts,tsx,js,jsx} : Set up `onHostContextChange` subscription before first render to ensure theme applies correctly
Applied to files:
packages/ui-react/src/hooks.ts
🔇 Additional comments (3)
packages/ui-react/src/hooks.ts (2)
17-17: LGTM!Import addition for
UpdateModelContextParamsis correctly placed with other type imports from@mcp-apps-kit/ui.
254-308: LGTM! Well-documented hook with proper React patterns.The implementation correctly:
- Uses
useCallbackwith[client]dependency for a stable function reference- Handles the missing client case gracefully with a warning
- Documents the platform-specific behavior differences (MCP Apps vs ChatGPT)
- Is properly exported from the package's public API
packages/ui/src/adapters/openai.ts (1)
19-19: LGTM!Import addition for
UpdateModelContextParamsis correctly placed with other type imports.
- Move build-time deps (@typescript-eslint/typescript-estree, esbuild) to devDependencies in ui-react-builder package.json - Add filtering for reserved underscore-prefixed keys in updateModelContext to prevent overwriting internal fields like _type - Fix linting error by avoiding non-null assertion Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Code Review: ext-apps v0.4.0 SupportSummaryThis PR adds support for ext-apps v0.4.0 features including ✅ Strengths1. Excellent Documentation
2. Good Test Coverage
3. Backward Compatibility
4. Consistent API Design
|
- Moved @typescript-eslint/types and @typescript-eslint/typescript-estree from devDependencies to dependencies in package.json for ui-react-builder. - Updated tsup.config.ts to include these packages in the build configuration. This change ensures that the necessary TypeScript ESLint packages are available during runtime.
Code Review - PR #96: ext-apps v0.4.0 SupportOverviewThis PR adds comprehensive support for ext-apps v0.4.0 features, including the new ✅ Strengths1. Excellent Documentation
2. Strong Test Coverage
3. Type Safety
4. Backward Compatibility
5. Consistent Architecture
|
…pnpm-lock.yaml - Restored @typescript-eslint/types, @typescript-eslint/typescript-estree, and esbuild to dependencies for ui-react-builder. - This change ensures these packages are available during runtime, aligning with the recent updates in package management.
Code Review - PR #96: Update ext-apps to v0.4.0SummaryThis PR adds support for ext-apps v0.4.0 features, introducing ✅ Strengths1. Excellent Documentation
2. Strong Test Coverage
3. Backward Compatibility
4. Dependency Management
🔍 Issues & RecommendationsHigh Priority1. Type Safety Issue in
|
- Changed protocol from "openai" to "mcp" in the weather app server configuration. - Added new error code `INVALID_PARAMS` to handle missing fields in content blocks. - Enhanced content block validation in MCP adapter to ensure required fields are present for each type. - Updated `ContentBlock` type definition for improved type safety using discriminated unions. - Clarified documentation in `updateModelContext` regarding context persistence and reserved keys. These changes improve the robustness of the protocol handling and ensure that content blocks are validated correctly before processing.
Code Review: ext-apps v0.4.0 SupportSummaryThis PR successfully adds support for ext-apps v0.4.0 features, introducing 🔴 Critical Issues1. Non-exhaustive switch statement in MCP adapterLocation: The switch statement in Issue: const content = params.content?.map((block) => {
switch (block.type) {
case "text": ...
case "image": ...
case "audio": ...
case "resource": ...
case "resource_link": ...
// Missing default case - no exhaustiveness checking!
}
});Fix: Add a default case that performs exhaustiveness checking: switch (block.type) {
case "text": ...
case "image": ...
case "audio": ...
case "resource": ...
case "resource_link": ...
default: {
const _exhaustive: never = block;
throw new UIError(
UIErrorCode.INVALID_PARAMS,
\`Unsupported content block type: \${(_exhaustive as ContentBlock).type}\`
);
}
}This ensures TypeScript will error at compile time if new types are added to 2. Incomplete content handling in OpenAI adapterLocation: The OpenAI adapter only handles Issue: const textContent = params.content
.filter((block) => block.type === "text")
.map((block) => block.text)
.join("\n");This means
Recommendation: Add logging and documentation: if (params.content && params.content.length > 0) {
const nonTextBlocks = params.content.filter((block) => block.type !== "text");
if (nonTextBlocks.length > 0) {
clientDebugLogger.debug(
\`[OpenAI Adapter] Non-text content blocks not supported on ChatGPT, ignoring:\`,
nonTextBlocks.map(b => b.type)
);
}
const textContent = params.content
.filter((block) => block.type === "text")
.map((block) => block.text)
.join("\n");
// ...
}
|
- Added exhaustiveness check for content block types in MCP adapter to throw an error for unsupported types. - Updated OpenAI adapter to log dropped non-text content blocks, ensuring only text blocks are processed. These changes improve error handling and logging for content block processing across adapters.
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
packages/ui/src/adapters/mcp.tspackages/ui/src/adapters/openai.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/ui/src/adapters/openai.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use Express 5 (not 4) - async error handling works differently
Files:
packages/ui/src/adapters/mcp.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Use strict TypeScript - noanytypes, useunknownwith type narrowing instead
UsedefineToolanddefineUI(ordefineReactUIfor React components) for type inference
Useexport typefor type-only exports to prevent runtime imports of types
Files:
packages/ui/src/adapters/mcp.ts
packages/ui/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (packages/ui/AGENTS.md)
packages/ui/**/*.{ts,tsx,js,jsx}: UsecreateClient()with proper await - it is an async function, not synchronous
Handle both MCP and OpenAI response formats when calling tools
Ensure adapter.connect() is awaited before subscribing to events or rendering
Set uponHostContextChangesubscription before first render to ensure theme applies correctly
Files:
packages/ui/src/adapters/mcp.ts
packages/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (packages/ui/AGENTS.md)
Provide type parameter to
createClient<typeof app.tools()>()for proper typed tool calls
Files:
packages/ui/src/adapters/mcp.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui-react/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:36.676Z
Learning: Applies to packages/ui-react/**/*.{tsx,jsx} : Ensure components using MCP hooks (`useAppsClient`, `useToolResult`, `useHostContext`, `useDocumentTheme`, `useHostStyleVariables`) are rendered within an `AppsProvider` context wrapper
📚 Learning: 2026-01-11T17:08:36.676Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui-react/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:36.676Z
Learning: Applies to packages/ui-react/**/*.{tsx,jsx} : Ensure components using MCP hooks (`useAppsClient`, `useToolResult`, `useHostContext`, `useDocumentTheme`, `useHostStyleVariables`) are rendered within an `AppsProvider` context wrapper
Applied to files:
packages/ui/src/adapters/mcp.ts
📚 Learning: 2026-01-11T17:08:42.176Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:42.176Z
Learning: Applies to packages/ui/**/*.{ts,tsx,js,jsx} : Handle both MCP and OpenAI response formats when calling tools
Applied to files:
packages/ui/src/adapters/mcp.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: test-and-lint
- GitHub Check: claude-review
🔇 Additional comments (5)
packages/ui/src/adapters/mcp.ts (5)
12-12: LGTM!Type imports are correctly added for the new
updateModelContextandcontainerDimensionsfunctionality.Also applies to: 48-50
281-296: LGTM - tolerant parsing aligns with existing patterns.The
containerDimensionsparsing follows the file's established pattern of graceful/tolerant parsing. TheisObjectLikecheck combined with defensive handling inderiveViewportFromContainerDimensions(which validates each numeric field individually) ensures robustness without strict upfront validation.
322-337: LGTM!The method correctly derives viewport dimensions from
containerDimensionswith proper type guards and fallback to defaults. The defensive casting toRecord<string, unknown>allows flexible property checking.
486-493: Good exhaustiveness check.The
nevertype pattern ensures TypeScript will flag any unhandled content block types at compile time, while the runtime throw provides a safety net.
663-697: LGTM!The new ext-apps v0.4.0 capabilities (
updateModelContext,message,sandbox) are correctly mapped from the SDK capabilities object, following the established pattern for capability extraction.
Code Review: ext-apps v0.4.0 SupportCritical Issue Found: Test/Implementation Mismatch The implementation uses This will cause test failures. Please align the implementation with test expectations. Other Issues:
Strengths:
Action Items: Must fix:
Recommended: Overall: Good work! Main blocker is the test mismatch. Once fixed and build passes, ready to merge. |
…rmat - Modified the MCP adapter to return a nested resource object for content blocks, including both `uri` and `text/blob` fields. - Enhanced handling for `resource_link` blocks to match the new structure, ensuring compatibility with ext-apps v0.4.0. These changes improve the integration with external applications by standardizing the resource format.
Pull Request ReviewThis PR adds support for ext-apps v0.4.0 features, including the new ✅ Strengths
🔍 Code Quality Observations
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @packages/ui/src/adapters/mcp.ts:
- Around line 466-498: The resource_link branch currently returns a nested
ext-apps "resource" object; change the case "resource_link" handling in the
switch to return a flat ext-apps v0.4.0 shape with type: "resource_link" and
top-level fields uri: block.uri, name: block.name, description:
block.description (and keep the UIError check for missing uri using
UIError/UIErrorCode), and update or remove the misleading comment about ext-apps
expecting a nested resource object; also review the case "resource" mapping to
ensure it matches the spec and adjust its returned structure or comment
accordingly (symbols to edit: the switch cases for "resource" and
"resource_link" in packages/ui/src/adapters/mcp.ts).
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/ui/src/adapters/mcp.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use Express 5 (not 4) - async error handling works differently
Files:
packages/ui/src/adapters/mcp.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Use strict TypeScript - noanytypes, useunknownwith type narrowing instead
UsedefineToolanddefineUI(ordefineReactUIfor React components) for type inference
Useexport typefor type-only exports to prevent runtime imports of types
Files:
packages/ui/src/adapters/mcp.ts
packages/ui/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (packages/ui/AGENTS.md)
packages/ui/**/*.{ts,tsx,js,jsx}: UsecreateClient()with proper await - it is an async function, not synchronous
Handle both MCP and OpenAI response formats when calling tools
Ensure adapter.connect() is awaited before subscribing to events or rendering
Set uponHostContextChangesubscription before first render to ensure theme applies correctly
Files:
packages/ui/src/adapters/mcp.ts
packages/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (packages/ui/AGENTS.md)
Provide type parameter to
createClient<typeof app.tools()>()for proper typed tool calls
Files:
packages/ui/src/adapters/mcp.ts
🧠 Learnings (2)
📚 Learning: 2026-01-11T17:08:36.676Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui-react/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:36.676Z
Learning: Applies to packages/ui-react/**/*.{tsx,jsx} : Ensure components using MCP hooks (`useAppsClient`, `useToolResult`, `useHostContext`, `useDocumentTheme`, `useHostStyleVariables`) are rendered within an `AppsProvider` context wrapper
Applied to files:
packages/ui/src/adapters/mcp.ts
📚 Learning: 2026-01-11T17:08:42.176Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:42.176Z
Learning: Applies to packages/ui/**/*.{ts,tsx,js,jsx} : Handle both MCP and OpenAI response formats when calling tools
Applied to files:
packages/ui/src/adapters/mcp.ts
🧬 Code graph analysis (1)
packages/ui/src/adapters/mcp.ts (1)
packages/ui/src/types.ts (5)
ContainerDimensions(274-278)HostContext(317-364)UpdateModelContextParams(461-473)ContentBlock(451-456)HostCapabilities(15-165)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: test-and-lint
- GitHub Check: claude-review
🔇 Additional comments (5)
packages/ui/src/adapters/mcp.ts (5)
12-12: LGTM!Imports are properly organized and align with the new types for ext-apps v0.4.0 support.
Also applies to: 48-50
281-296: LGTM!The containerDimensions parsing and viewport derivation logic correctly maintains backward compatibility. The fallback chain (containerDimensions → explicit viewport → defaults) ensures existing code relying on
viewportcontinues to work.
322-337: LGTM!The derivation logic correctly distinguishes between fixed dimensions (width/height → fall back to defaults) and flexible dimensions (maxWidth/maxHeight → fall back to undefined). This properly reflects the ContainerDimensions semantics where absence of max dimensions means no constraint.
499-506: Exhaustiveness check is well-implemented.Using
const exhaustiveCheck: never = blockensures TypeScript will produce a compile-time error if a new ContentBlock type is added but not handled in the switch statement. This is a good defensive pattern for union type handling.
706-710: LGTM!The new v0.4.0 capability fields (
updateModelContext,message,sandbox) are properly exposed through the unified HostCapabilities interface. The type assertion pattern is consistent with the existing SDK capability mapping above.
- Updated the MCP adapter to clarify the mapping of resource and resource_link formats to align with ext-apps v0.4.0 specifications. - Adjusted comments for better understanding of the expected structure, ensuring that the 'name' field is now required for resource_link. These changes enhance the clarity and correctness of the resource handling in the MCP adapter.
Pull Request Review: ext-apps v0.4.0 SupportSummaryThis PR successfully updates the framework to support ext-apps v0.4.0 features, including model context updates, container dimensions, and new host capabilities. The implementation is comprehensive and well-tested. ✅ Strengths1. Excellent Type Safety
2. Strong Documentation
3. Backward Compatibility
4. Good Test Coverage
5. Clean Architecture
🔍 Issues FoundCriticalNone found - the core implementation is solid. Major1. OpenAI Adapter: State Key Naming Inconsistency Location: const modelContext: Record<string, unknown> = {
__mcp_type: "modelContext", // Double underscore
};But later: modelContext.__mcp_textContent = textContent; // Also double underscoreIssue: Documentation says "keys starting with underscore (_) are filtered" but uses double underscore (_mcp*) for internal keys. The distinction between single and double underscore is mentioned in code but not clearly documented in the JSDoc. Recommendation: Update the JSDoc to clarify:
2. Test Assertion Mismatch Location: The test expects expect(mockSetWidgetState).toHaveBeenCalledWith({
_type: "modelContext", // Should be __mcp_type
itemCount: 3,
total: 150,
});This test should fail but may be passing due to partial matching. Please update to match implementation. Minor3. Error Handling: Missing Validation Context Location: The content block validation throws errors for missing required fields, but there is no validation that Recommendation: Add a comment explaining that validation of data format is the caller responsibility, or add optional base64 validation. 4. Inconsistent Documentation Location: The extensive JSDoc comment is excellent but slightly redundant with the AppsClient interface documentation. Consider extracting common documentation to reduce duplication. 5. Package Version Changes The PR updates Zod from 4.0.0 to 4.3.5 across multiple packages. While this is good, the PR description does not mention why this specific version was chosen. Consider documenting any breaking changes from Zod if relevant. 6. ui-react-builder Dependency Reorganization Moving 🎯 SuggestionsPerformance1. Reserved Key Filtering Current code: const reservedKeys = Object.keys(structuredContent).filter((key) => key.startsWith("_"));This filters keys twice (once to log, once to skip). Consider: Object.entries(structuredContent).forEach(([key, value]) => {
if (key.startsWith("_")) {
// log if needed
return;
}
modelContext[key] = value;
});Code Quality1. Magic Strings Consider extracting magic strings to constants: const MODEL_CONTEXT_TYPE = "modelContext" as const;
const INTERNAL_KEY_PREFIX = "__mcp_" as const;2. Error Messages Enhancement The error messages are good, but could include more context: throw new UIError(
UIErrorCode.INVALID_PARAMS,
`Image content block requires data field (type: ${block.type})`
);Testing1. Missing Edge Cases Consider adding tests for:
2. Integration Tests The unit tests are solid, but consider adding integration tests that verify the full flow from React hook → client → adapter → protocol. 🔒 SecurityNo critical security issues found. Minor note: The base64 decoding in 📊 PerformanceNo significant performance concerns. The implementation is efficient for typical use cases. For apps sending frequent context updates with large payloads, document best practices in the user guide. ✅ Checklist CompliancePer CLAUDE.md requirements:
🎉 ConclusionRecommendation: APPROVE with minor fixes This is a high-quality PR that successfully implements ext-apps v0.4.0 support. The architecture is sound, the code is well-tested, and the documentation is thorough. The issues identified are minor and mostly cosmetic. Required Actions Before Merge:
Optional Improvements:
Great work on maintaining backward compatibility while adding substantial new functionality! 🚀 |
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/ui/src/adapters/mcp.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use Express 5 (not 4) - async error handling works differently
Files:
packages/ui/src/adapters/mcp.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Use strict TypeScript - noanytypes, useunknownwith type narrowing instead
UsedefineToolanddefineUI(ordefineReactUIfor React components) for type inference
Useexport typefor type-only exports to prevent runtime imports of types
Files:
packages/ui/src/adapters/mcp.ts
packages/ui/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (packages/ui/AGENTS.md)
packages/ui/**/*.{ts,tsx,js,jsx}: UsecreateClient()with proper await - it is an async function, not synchronous
Handle both MCP and OpenAI response formats when calling tools
Ensure adapter.connect() is awaited before subscribing to events or rendering
Set uponHostContextChangesubscription before first render to ensure theme applies correctly
Files:
packages/ui/src/adapters/mcp.ts
packages/ui/**/*.{ts,tsx}
📄 CodeRabbit inference engine (packages/ui/AGENTS.md)
Provide type parameter to
createClient<typeof app.tools()>()for proper typed tool calls
Files:
packages/ui/src/adapters/mcp.ts
🧠 Learnings (2)
📚 Learning: 2026-01-11T17:08:36.676Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui-react/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:36.676Z
Learning: Applies to packages/ui-react/**/*.{tsx,jsx} : Ensure components using MCP hooks (`useAppsClient`, `useToolResult`, `useHostContext`, `useDocumentTheme`, `useHostStyleVariables`) are rendered within an `AppsProvider` context wrapper
Applied to files:
packages/ui/src/adapters/mcp.ts
📚 Learning: 2026-01-11T17:08:42.176Z
Learnt from: CR
Repo: AndurilCode/mcp-apps-kit PR: 0
File: packages/ui/AGENTS.md:0-0
Timestamp: 2026-01-11T17:08:42.176Z
Learning: Applies to packages/ui/**/*.{ts,tsx,js,jsx} : Handle both MCP and OpenAI response formats when calling tools
Applied to files:
packages/ui/src/adapters/mcp.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: test-and-lint
- GitHub Check: claude-review
🔇 Additional comments (6)
packages/ui/src/adapters/mcp.ts (6)
12-12: LGTM!Type imports are correctly structured using
import typepattern to prevent runtime imports.Also applies to: 48-50
281-310: LGTM!The containerDimensions parsing and backward-compatible viewport derivation are well-implemented. The fallback chain (containerDimensions → explicit viewport → defaults) ensures existing code continues to work while supporting the new ext-apps v0.4.0 semantics.
322-337: LGTM!The viewport derivation correctly handles both fixed (width/height) and flexible (maxWidth/maxHeight) semantics from containerDimensions while falling back to defaults for missing values.
424-465: LGTM!The updateModelContext method properly validates connection state and content block requirements. Error handling uses appropriate UIError codes, and the text/image/audio block mappings with sensible mimeType defaults are well-structured.
481-506: LGTM - resource_link mapping now uses correct flat structure.The
resource_linkcase now correctly uses the flat structure withtype: "resource_link",uri,name, and optionaldescriptionas required by ext-apps v0.4.0. The fallback ofnametouriensures the required field is always present.The exhaustiveness check with
nevertype provides compile-time safety if new content block types are added.
674-708: LGTM!The capability mapping correctly exposes the new ext-apps v0.4.0 capabilities (
updateModelContext,message,sandbox) while maintaining the existing MCP SDK capability mappings. The casting toRecord<string, unknown>is appropriate for handling the external library's dynamic capability structure.
| case "resource": | ||
| if (!block.uri) { | ||
| throw new UIError( | ||
| UIErrorCode.INVALID_PARAMS, | ||
| "Resource content block requires 'uri' field" | ||
| ); | ||
| } | ||
| // Map to ext-apps v0.4.0 resource format (nested structure) | ||
| return { | ||
| type: "resource" as const, | ||
| resource: { | ||
| uri: block.uri, | ||
| text: block.description ?? block.uri, | ||
| }, | ||
| }; |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
# First, let's look at the file structure and context around the resource mapping
cd packages/ui && find . -name "*.ts" -o -name "*.tsx" | head -20Repository: AndurilCode/mcp-apps-kit
Length of output: 523
🏁 Script executed:
# Search for ext-apps references and resource-related code
rg "ext-apps" --type ts --type tsx -A 3 -B 3Repository: AndurilCode/mcp-apps-kit
Length of output: 95
🏁 Script executed:
# Look for tests or documentation about resource content blocks
rg "resource.*content.*block|content.*block.*resource" --type ts --type tsx -iRepository: AndurilCode/mcp-apps-kit
Length of output: 95
🌐 Web query:
ext-apps v0.4.0 MCP resource content block format specification
💡 Result:
Short summary of the ext-apps v0.4.0 MCP "resource content block" format
- Content blocks are polymorphic objects with a type discriminator (e.g., "text", "image", "audio", "resource" (embedded), "resourceLink"). [1][2]
- Common/metadata fields:
- name (display filename), title (optional), uri (resource URI), mimeType / mime_type (optional), annotations such as audience, lastModified (ISO‑8601), priority (0.0–1.0). [2][3]
- Text block ("text"):
- type: "text"
- text: UTF‑8 string
- optional mimeType/mime_type for richer typing. [2][3]
- Binary blocks ("image", "audio", etc.):
- type: e.g., "image" or "audio"
- blob (base64-encoded data) or data field, plus mimeType/mime_type. [2][3]
- Embedded resource block ("resource"):
- type: "resource"
- resource: object containing resource metadata and either text or blob content (uri, name, mimeType, text or blob). [1][2][3]
- Resource link ("resourceLink"):
- type: "resourceLink"
- name, uri (reference only — no inline content). [2]
- Implementation notes:
- text and blob are mutually exclusive for a single content item; URIs are canonical identifiers. [3]
Sources:
[1] modelcontextprotocol/ext-apps (repo & SDK).
[2] Model Context Protocol — Resources / schema (MCP specification).
[3] McpServer.Resource.Content (HTTP MCP Server v0.4.0) documentation.
🏁 Script executed:
# Find the ContentBlock or resource block type definition
rg "ContentBlock|resource.*block" --type ts -B 3 -A 5 -iRepository: AndurilCode/mcp-apps-kit
Length of output: 11896
🏁 Script executed:
# Look at the imports and surrounding context in the mcp.ts file
head -100 packages/ui/src/adapters/mcp.ts | tail -50Repository: AndurilCode/mcp-apps-kit
Length of output: 1814
🏁 Script executed:
# Search for where this function is defined and what input types it expects
rg "case.*resource" packages/ui/src/adapters/mcp.ts -B 10 -A 15Repository: AndurilCode/mcp-apps-kit
Length of output: 1449
🏁 Script executed:
# Look for any test files that show resource content block handling
rg "resource" packages/ui/tests -lRepository: AndurilCode/mcp-apps-kit
Length of output: 152
The resource block mapping has a semantic issue: description should not be mapped to text field, and defaulting to uri is incorrect.
The code maps the input description field to the output text field in the resource object. However, description is metadata about the resource, not its actual content. Per the ext-apps v0.4.0 specification, the text field should contain the actual resource content. Additionally, falling back to uri when description is absent (line 473) is semantically wrong—a URI is not resource content.
The input ContentBlock type for resource only provides uri and optional description fields, with no actual text or blob content. The current mapping conflates these concepts. Consider whether:
descriptionshould be used as-is (preserving it as separate metadata, not as content), or- The input type needs to be extended to include the actual resource content
Add support for ext-apps v0.4.0 features:
Breaking changes in ext-apps handled:
Note: On ChatGPT, both setState and updateModelContext expose state to the AI model. Use setState for persistence-focused use cases, updateModelContext for context-focused use cases.