Skip to content

Conversation

@frontegg-david
Copy link
Contributor

@frontegg-david frontegg-david commented Dec 17, 2025

… project configuration

Summary by CodeRabbit

  • New Features

    • Platform-aware UI metadata, a Universal renderer/runtime (HTML/React/MDX/Markdown), static HTML bundling, and a TypeScript typings fetcher with caching.
  • Bug Fixes & Improvements

    • Graceful UI-render degradation, improved platform detection and test/client flows, runtime caching & diagnostics, CI E2E retry/cache-reset flow.
  • Removals

    • HTMX integration and legacy dual-payload removed; public API renamed to useStructuredContent and structuredContent response format introduced.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 17, 2025

Walkthrough

Adds a universal UI renderer and runtime, static-HTML bundler, TypeScript typings fetcher with LRU type cache, platform-aware test-client and meta plumbing, centralized machine-id and session platform detection, removes HTMX from UI components, updates flows to structuredContent, expands tests/fixtures, and adjusts CI and build configs.

Changes

Cohort / File(s) Summary
Universal renderer & runtime
libs/ui/src/universal/*, libs/ui/src/universal/__tests__/*
New universal rendering subsystem: types, store, context/providers, renderers (html/markdown/react/mdx), UniversalApp, runtime builders, cached runtime API and extensive tests.
Bundler & static HTML
libs/ui/src/bundler/*, libs/ui/src/bundler/__tests__/*, libs/ui/src/bundler/index.ts, libs/ui/src/bundler/types.ts
Adds bundleToStaticHTML, universal HTML assembly, esbuild transform typings, CDN/runtime builders, sanitization, and comprehensive bundler tests.
Typings fetcher & cache
libs/ui/src/typings/*, libs/ui/src/typings/__tests__/*, libs/ui/src/typings/cache/*
New TypeFetcher, .d.ts parser, Zod schemas, TypeCacheAdapter interface, MemoryTypeCache (LRU+TTL), API/exports and tests.
UI utils & escaping
libs/ui/src/utils/*, libs/ui/src/dependency/import-map.ts, libs/ui/src/handlebars/helpers.ts, libs/ui/src/layouts/base.ts
Centralizes escape helpers (escapeHtml, escapeHtmlAttr, escapeJsString) and replaces local implementations with re-exports/imports.
HTMX removal from UI components
libs/ui/src/components/*, libs/ui/src/components/__tests__/*, libs/ui/src/components/*.schema.ts
Removes HTMX-related schemas/options and hx-* attribute generation across many components; replaces HTMX flows with plain DOM/link behaviors; deletes dual-payload module/tests and renames/introduces structuredContent usage.
Web-components & attribute parsing
libs/ui/src/web-components/core/*, libs/ui/src/web-components/elements/*
Removes HTMX-specific observed attributes and special parsing/merge logic; simplifies attribute handling and removes related tests.
Adapters: structuredContent & platform meta
libs/ui/src/adapters/*, libs/ui/src/adapters/platform-meta.ts, libs/ui/src/adapters/__tests__/*
Replaces dual-payload with structuredContent flow, renames useDualPayload→useStructuredContent, and implements platform-scoped meta keys (openai/ui/frontmcp) with per-platform builders.
Runtime CSP & types
libs/ui/src/runtime/csp.ts, libs/ui/src/runtime/index.ts, libs/ui/src/types/*
Adds DEFAULT_CDN_DOMAINS, DEFAULT_CSP_DIRECTIVES, RESTRICTIVE_CSP_DIRECTIVES and UIContentSecurity types; merges default CDN domains into CSP construction.
Auth / session / machine-id
libs/sdk/src/auth/machine-id.ts, libs/sdk/src/auth/session/utils/session-id.utils.ts, libs/sdk/src/auth/flows/session.verify.flow.ts, libs/sdk/src/auth/authorization/authorization.class.ts
Introduces getMachineId module; centralizes machine-id usage, captures User-Agent in session.verify for platform detection, and includes platformType in session payload when detected.
Tool flows & graceful UI degradation
libs/sdk/src/tool/flows/call-tool.flow.ts, libs/sdk/src/tool/flows/tools-list.flow.ts, libs/sdk/src/flows/flow.instance.ts
Adds UI render-failure type/guard and graceful-degradation path, switches flows to structuredContent where applicable, makes tools-list platform-aware, and runFinalizeStage gains suppressErrors option (callers updated).
MCP test client & transport
libs/testing/src/client/*, libs/testing/src/transport/*, libs/testing/src/client/mcp-test-client.builder.ts
Adds ClientInfo and TestClientCapabilities types, builder methods withPlatform/withCapabilities, propagates clientInfo to transport, and conditionally emits User-Agent header; test client builder and fixtures updated.
Testing fixtures & platform helpers
libs/testing/src/fixtures/*, libs/testing/src/platform/*, libs/testing/src/example-tools/*, libs/testing/src/ui/*, libs/testing/src/index.ts
Adds ServerFixture.createClientBuilder, test-failure-aware cleanup, platform-types and platform-client-info modules, example tool configs, UI assertions/matchers, and new testing exports.
E2E apps & tests
apps/e2e/*/project.json, apps/e2e/*/tsconfig.app.json, apps/e2e/*/e2e/*.e2e.test.ts
Serve targets changed to nx:run-commands with build dependency; TSX enabled for e2e apps; many tests refactored to use McpTestClient and platform meta assertions.
TypeScript build configs & package/CI
libs/*/tsconfig.lib.json, package.json, .github/workflows/push.yml, .gitignore, CLAUDE.md
outDir→./dist and rootDir added across libs, added devDependency baseline-browser-mapping, CI E2E step given id + continue-on-error with cache reset & retry, added .gitignore entry and CLAUDE.md git guidance.
Exports & barrels
libs/ui/src/index.ts, libs/ui/src/bundler/index.ts, libs/ui/src/registry/index.ts, libs/ui/src/adapters/index.ts, libs/sdk/src/auth/ui/index.ts, libs/testing/src/index.ts, libs/ui/src/typings/index.ts
Expanded public API: universal, typings, bundler, runtime builders and caches; removed dual-payload exports; renamed platformUsesDualPayload→platformUsesStructuredContent; updated barrels accordingly.

Sequence Diagram(s)

sequenceDiagram
    participant Browser
    participant StreamTransport
    participant SessionFlow
    participant AuthService
    participant MachineID
    participant Server

    Browser->>StreamTransport: request (includes User-Agent)
    StreamTransport->>SessionFlow: forward input (userAgent)
    SessionFlow->>AuthService: detectPlatformFromUserAgent(userAgent)
    AuthService-->>SessionFlow: platformType
    SessionFlow->>MachineID: getMachineId()
    MachineID-->>SessionFlow: machineId
    SessionFlow->>Server: build/verify session payload (platformType, nodeId)
    Server-->>Browser: session response (platform-aware)
Loading
sequenceDiagram
    participant ToolFlow
    participant MetaBuilder
    participant Detector
    participant RendererRegistry
    participant Renderer
    participant Client

    ToolFlow->>MetaBuilder: request platform meta (platformType, capabilities)
    MetaBuilder-->>ToolFlow: platform-scoped meta keys
    ToolFlow->>Detector: supply tool output
    Detector-->>RendererRegistry: ask detect(content)
    RendererRegistry->>Renderer: select renderer
    Renderer->>Client: render UI (or return failure)
    ToolFlow->>Client: deliver structuredContent + platform meta
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

Areas to focus during review:

  • Universal renderer and cached runtime assembly (store/hooks, renderers, SSR/CSR boundaries, placeholder injection, minification).
  • TypeFetcher concurrency, recursive fetching, cache key determinism, and network/error paths.
  • Platform-scoped meta builders and namespace isolation (openai/ui/frontmcp correctness).
  • Auth/session changes: machine-id centralization, User-Agent capture, and session payload effects.
  • Broad HTMX removals across components, schemas, web-components, and tests — ensure no regressions in consumers.
  • Test infra: McpTestClient builder changes, fixture cleanup propagation, and updated e2e tests/matchers.

Possibly related PRs

Poem

🐰
I hopped through code with nimble paws,
Bundled HTML and rewired laws.
HTMX gone, structured content blooms,
Types cached snug in quiet rooms.
Platform-aware, the warren hums.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly describes three main changes: moving zod to peerDependencies, adding E2E test resilience, and enhancing test client with clientInfo support. These match the extensive changeset which includes tsconfig updates, E2E test improvements, client enhancements, and platform support additions.
Docstring Coverage ✅ Passed Docstring coverage is 98.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-frontmcp-ui

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 24e08ec and 548dee5.

📒 Files selected for processing (3)
  • docs/draft/docs/authentication/demo-servers.mdx (4 hunks)
  • docs/draft/docs/getting-started/quickstart.mdx (2 hunks)
  • docs/draft/docs/servers/tools.mdx (12 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/draft/docs/getting-started/quickstart.mdx
🧰 Additional context used
📓 Path-based instructions (2)
docs/draft/docs/**

⚙️ CodeRabbit configuration file

docs/draft/docs/**: This folder holds the draft/source docs that humans are expected to edit. When authors want to add or change documentation, they should do it here. The Codex workflow uses these drafts, together with the code diff, to generate the latest docs under docs/docs/. As a reviewer: - Encourage contributors to add/update content here instead of docs/docs/. - It is fine to do structural/content feedback here (clarity, examples, etc).

Files:

  • docs/draft/docs/servers/tools.mdx
  • docs/draft/docs/authentication/demo-servers.mdx
docs/**

⚙️ CodeRabbit configuration file

docs/**: Repository documentation for the SDK, using MDX and hosted by Mintlify. See more specific rules for: - docs/docs/** (latest rendered docs, automation-only) - docs/v/** (archived versions, read-only) - docs/draft/docs/** (human-editable drafts) - docs/blogs/** (blogs, human edited) - docs/docs.json (Mintlify navigation)

Files:

  • docs/draft/docs/servers/tools.mdx
  • docs/draft/docs/authentication/demo-servers.mdx
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Support platform-aware rendering by detecting network capabilities (open vs blocked) and script loading strategies (external vs inline)
⏰ 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: Build Libraries
  • GitHub Check: Lint & Format Checks
🔇 Additional comments (5)
docs/draft/docs/authentication/demo-servers.mdx (4)

56-62: LGTM! Transport configuration correctly moved to top-level.

The transport configuration has been appropriately extracted from the auth object to a top-level option, aligning with the API changes described in this PR.


90-97: LGTM! Transport and sessionMode correctly relocated.

The transport configuration and sessionMode have been appropriately moved to the top-level transport block, consistent with the public API changes in this PR.


103-103: LGTM! Link reference correctly updated.

The link text and anchor have been updated to reflect the transport configuration's new location at the top level, and the anchor #transport matches the target heading.


172-172: LGTM! Previous broken anchor issue resolved.

The link now correctly uses the #transport anchor, addressing the concern raised in the previous review about the broken #transport-controls reference.

docs/draft/docs/servers/tools.mdx (1)

172-794: Systematic update to extend ToolContext is consistent.

All class-based tool examples throughout the document have been consistently updated to extend ToolContext. This includes:

  • CalculateTotalTool (line 172)
  • CreateUserTool (line 311)
  • ContextExampleTool (line 392)
  • TracedTool (line 449)
  • CalculateTool (line 504)
  • CreateGitHubIssueTool (line 530)
  • UpdateUserStatusTool (line 575)
  • WriteFileTool (line 617)
  • GetWeatherTool (line 712)
  • GetOrderTool (line 794)

The consistency suggests this is an intentional documentation update. Verify this matches the actual SDK pattern as noted in the previous comment.


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

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 22b227a and 0f21ac3.

📒 Files selected for processing (1)
  • libs/ui/package.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/ui/package.json
🔇 Additional comments (2)
libs/ui/package.json (2)

71-74: Appropriate use of optionalDependencies.

Moving @swc/core to optionalDependencies is correct. This allows the library to function without SWC when not needed, while making it available for advanced build scenarios. Similarly, keeping @mdx-js/mdx as optional provides MDX support only when required.


69-69: No action required. The library code is fully compatible with Zod 4.0.0.

All component schemas use patterns that are compatible with both Zod 3 and 4, with no usage of breaking change APIs. The codebase already uses the Zod 4 format for z.record() with two arguments, indicating the code was designed for Zod 4 compatibility. No deprecated patterns (.email(), .uuid(), .message parameter, .default(), z.function()) are present in the schema definitions.

Likely an incorrect or invalid review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
libs/testing/src/transport/transport.interface.ts (1)

6-6: Consider relocating ClientInfo type definition to avoid layering concerns.

The transport layer now imports ClientInfo from the client types module, creating a dependency from lower-level (transport) to higher-level (client) code. While this is a type-only import and doesn't create runtime circular dependencies, it couples the layers.

Consider moving the ClientInfo type definition to either:

  • A shared types module (e.g., libs/testing/src/types/shared.types.ts)
  • The transport layer itself (if it's primarily transport-related metadata)

This would maintain clearer separation of concerns and make the transport layer more independently reusable.

Also applies to: 149-150

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9749c48 and f9973a6.

📒 Files selected for processing (4)
  • libs/testing/src/client/mcp-test-client.ts (1 hunks)
  • libs/testing/src/client/mcp-test-client.types.ts (3 hunks)
  • libs/testing/src/transport/streamable-http.transport.ts (4 hunks)
  • libs/testing/src/transport/transport.interface.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Enable strict TypeScript mode with no any types without strong justification - use unknown instead for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific errors instead
Use specific error classes with MCP error codes instead of generic errors
Use type parameters with constraints instead of unconstrained generics, and prefer unknown over any for generic type defaults
Follow the preset pattern for hierarchical configurations across the codebase

Files:

  • libs/testing/src/transport/transport.interface.ts
  • libs/testing/src/client/mcp-test-client.types.ts
  • libs/testing/src/transport/streamable-http.transport.ts
  • libs/testing/src/client/mcp-test-client.ts
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/testing/src/transport/transport.interface.ts
  • libs/testing/src/client/mcp-test-client.types.ts
  • libs/testing/src/transport/streamable-http.transport.ts
  • libs/testing/src/client/mcp-test-client.ts
🧠 Learnings (3)
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable

Applied to files:

  • libs/testing/src/transport/transport.interface.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of `unknown` for `execute()` and `read()` methods

Applied to files:

  • libs/testing/src/transport/transport.interface.ts
  • libs/testing/src/client/mcp-test-client.types.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Use FrontMCP's TypeScript-first schema validation framework philosophy - all types should align with MCP protocol definitions

Applied to files:

  • libs/testing/src/transport/transport.interface.ts
  • libs/testing/src/client/mcp-test-client.types.ts
🧬 Code graph analysis (1)
libs/testing/src/transport/transport.interface.ts (1)
libs/testing/src/client/mcp-test-client.types.ts (1)
  • ClientInfo (76-76)
⏰ 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: Build Libraries
  • GitHub Check: Lint & Format Checks
🔇 Additional comments (5)
libs/testing/src/client/mcp-test-client.ts (1)

805-805: LGTM!

The clientInfo is correctly forwarded from the config to the transport constructor, consistent with how other configuration properties are passed through.

libs/testing/src/client/mcp-test-client.types.ts (2)

101-102: Good type refinement from inline shape to typed alias.

The change from an inline type { name: string; version: string } to the ClientInfo type alias improves type safety and aligns with the MCP SDK's Implementation type, which may include additional optional metadata fields.


69-76: Correct the MCP SDK version reference.

The review comment references @modelcontextprotocol/sdk v1.24.3, but this version does not exist. The latest version is 1.18.1.

Regarding the concern about Implementation type properties: based on consistent usage across all MCP SDK examples, both name and version are provided as required properties when constructing servers and clients, and the code in streamable-http.transport.ts accesses them without null checks, indicating they are expected to be non-optional.

Likely an incorrect or invalid review comment.

libs/testing/src/transport/streamable-http.transport.ts (2)

14-14: LGTM! Type definitions are correct.

The import and config type updates correctly incorporate the optional clientInfo field, maintaining type safety and consistency with the transport interface definition.

Also applies to: 25-28, 46-46


418-422: Verify property access is safe or add defensive checks.

The User-Agent header generation accesses clientInfo.name and clientInfo.version directly:

headers['User-Agent'] = `${this.config.clientInfo.name}/${this.config.clientInfo.version}`;

If the Implementation type from the MCP SDK has name or version as optional properties, this could result in undefined being interpolated into the header string (e.g., undefined/undefined).

Based on coding guidelines (avoid non-null assertions, use proper error handling), consider adding defensive checks:

 if (this.config.clientInfo) {
-  headers['User-Agent'] = `${this.config.clientInfo.name}/${this.config.clientInfo.version}`;
+  const name = this.config.clientInfo.name ?? 'unknown';
+  const version = this.config.clientInfo.version ?? '0.0.0';
+  headers['User-Agent'] = `${name}/${version}`;
 }

Alternatively, if name and version are guaranteed to be required properties in the Implementation type, this is fine as-is, but the verification from the previous comment should confirm this.

As per coding guidelines, avoid assumptions about type properties without defensive checks.

@frontegg-david frontegg-david changed the title fix: Restore @swc/core dependency and update external dependencies in… fix: Update dependencies in frontmcp/ui Dec 17, 2025
@frontegg-david frontegg-david changed the title fix: Update dependencies in frontmcp/ui fix: moving zod to peerDependencies, adding E2E test resilience, and enhancing test client with clientInfo support. Dec 17, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
libs/sdk/src/auth/flows/session.verify.flow.ts (1)

112-112: Optional: Remove redundant nullish coalescing.

The ?? undefined is redundant since the expression already evaluates to string | undefined. While harmless, removing it would improve clarity.

Apply this diff:

-    const userAgent = (request.headers?.['user-agent'] as string | undefined) ?? undefined;
+    const userAgent = (request.headers?.['user-agent'] as string | undefined);
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f9973a6 and 83c6438.

📒 Files selected for processing (1)
  • libs/sdk/src/auth/flows/session.verify.flow.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Enable strict TypeScript mode with no any types without strong justification - use unknown instead for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific errors instead
Use specific error classes with MCP error codes instead of generic errors
Use type parameters with constraints instead of unconstrained generics, and prefer unknown over any for generic type defaults
Follow the preset pattern for hierarchical configurations across the codebase

Files:

  • libs/sdk/src/auth/flows/session.verify.flow.ts
libs/{sdk,adapters,plugins,cli}/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

libs/{sdk,adapters,plugins,cli}/src/**/*.ts: Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of unknown for execute() and read() methods
Validate URIs per RFC 3986 at metadata level using Zod validation with custom refinements
Use getCapabilities() for dynamic capability exposure instead of hardcoding capabilities in adapters
Use changeScope instead of scope for change event properties to avoid confusion with the Scope class
Validate hooks match their entry type and fail fast with InvalidHookFlowError for unsupported flows
Don't mutate rawInput in flows - use state.set() for managing flow state instead

Files:

  • libs/sdk/src/auth/flows/session.verify.flow.ts
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/sdk/src/auth/flows/session.verify.flow.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Don't mutate rawInput in flows - use state.set() for managing flow state instead

Applied to files:

  • libs/sdk/src/auth/flows/session.verify.flow.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: Build Libraries
  • GitHub Check: Lint & Format Checks
🔇 Additional comments (5)
libs/sdk/src/auth/flows/session.verify.flow.ts (5)

36-36: LGTM!

The userAgent field is properly typed as an optional string using correct Zod 4 syntax, which is appropriate since the User-Agent header may not always be present in requests.


117-126: LGTM!

The state management correctly uses state.set() to propagate the userAgent through the flow state, following the established pattern and coding guidelines.


26-26: The import and usage of detectPlatformFromUserAgent are correctly implemented. The function signature matches its usage, returning AIPlatformType which safely handles the 'unknown' value. State management properly uses state.set() to store the User-Agent, and the conditional spread operator correctly checks platformType !== 'unknown' before including it in the payload. No issues found.


195-202: [Your rewritten review comment text here]
[Exactly ONE classification tag]


189-191: Code is type-safe and correctly handles undefined values.

The implementation properly addresses the original concerns:

  • detectPlatformFromUserAgent safely handles undefined userAgent by returning 'unknown' (line 182 of notification.service.ts)
  • platformDetectionConfig type matches the function parameter (optional PlatformDetectionConfig)
  • Return type AIPlatformType includes the 'unknown' literal, making the !== 'unknown' comparison at line 201 valid
  • Optional chaining for this.scope.metadata.transport?.platformDetection is appropriate

No changes needed.

Add [PLATFORM_DEBUG] console.log statements at 5 key points to trace
platform detection flow and identify why tests fail in CI (Linux)
but pass locally (Mac).

Debug points:
1. Client - User-Agent header being sent
2. Server - User-Agent header received in parseInput
3. Server - Platform detection in handlePublicMode
4. Server - applyUI platform type resolution
5. Client - Response _meta check for hasToolUI
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (1)
libs/sdk/src/tool/flows/call-tool.flow.ts (1)

389-410: Replace console.log with this.logger.verbose() for consistency.

The applyUI method already uses this.logger.verbose() extensively for tracing (lines 368, 373, 415, etc.), but these new debug statements use console.log instead. This bypasses the logging infrastructure and will execute unconditionally regardless of configured log levels.

Apply this diff to use the existing logger:

-      console.log(
-        `[PLATFORM_DEBUG] applyUI - sessionIdPayload.platformType: ${authInfo?.sessionIdPayload?.platformType}`,
-      );
-      console.log(
-        `[PLATFORM_DEBUG] applyUI - notifications.getPlatformType: ${
-          sessionId ? scope.notifications.getPlatformType(sessionId) : 'no-session'
-        }`,
-      );
       const platformType =
         authInfo?.sessionIdPayload?.platformType ??
         (sessionId ? scope.notifications.getPlatformType(sessionId) : undefined) ??
         'unknown';
-      console.log(`[PLATFORM_DEBUG] applyUI - final platformType: ${platformType}`);
+      this.logger.verbose('applyUI: platform detection', {
+        sessionIdPayloadPlatform: authInfo?.sessionIdPayload?.platformType,
+        notificationsPlatform: sessionId ? scope.notifications.getPlatformType(sessionId) : 'no-session',
+        finalPlatform: platformType,
+      });
 
       // Resolve the effective serving mode based on configuration and client capabilities
       // Default is 'auto' which selects the best mode for the platform
       const configuredMode = tool.metadata.ui.servingMode ?? 'auto';
       const resolvedMode = resolveServingMode({
         configuredMode,
         platformType,
       });
-      console.log(`[PLATFORM_DEBUG] applyUI - supportsUI: ${resolvedMode.supportsUI}, reason: ${resolvedMode.reason}`);
+      this.logger.verbose('applyUI: resolved serving mode', {
+        configuredMode,
+        supportsUI: resolvedMode.supportsUI,
+        effectiveMode: resolvedMode.effectiveMode,
+        reason: resolvedMode.reason,
+      });
🧹 Nitpick comments (1)
libs/sdk/src/notification/notification.service.ts (1)

181-203: Consider making debug logs conditional or removing them before production.

The [PLATFORM_DEBUG] console.log statements will execute unconditionally in production. Since this is a module-level function without logger access, consider either:

  1. Making them conditional on an environment variable (e.g., process.env['DEBUG_PLATFORM'])
  2. Removing them if they were only needed for development debugging
  3. Accepting a logger parameter if this tracing is needed long-term

Apply this pattern to make debug logs conditional:

 export function detectPlatformFromUserAgent(userAgent?: string, config?: PlatformDetectionConfig): AIPlatformType {
-  console.log(`[PLATFORM_DEBUG] detectPlatformFromUserAgent input: "${userAgent}"`);
+  if (process.env['DEBUG_PLATFORM']) {
+    console.log(`[PLATFORM_DEBUG] detectPlatformFromUserAgent input: "${userAgent}"`);
+  }
   if (!userAgent) {
-    console.log(`[PLATFORM_DEBUG] No userAgent - returning 'unknown'`);
+    if (process.env['DEBUG_PLATFORM']) {
+      console.log(`[PLATFORM_DEBUG] No userAgent - returning 'unknown'`);
+    }
     return 'unknown';
   }
 
   // Check custom mappings first
   const customMatch = matchCustomMappings(userAgent, config?.mappings);
   if (customMatch) {
     return customMatch;
   }
 
   // If customOnly, don't use default detection
   if (config?.customOnly) {
     return 'unknown';
   }
 
   // Use default detection on user-agent
   const result = defaultPlatformDetection(userAgent);
-  console.log(`[PLATFORM_DEBUG] defaultPlatformDetection result: ${result}`);
+  if (process.env['DEBUG_PLATFORM']) {
+    console.log(`[PLATFORM_DEBUG] defaultPlatformDetection result: ${result}`);
+  }
   return result;
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 83c6438 and 358b8ee.

📒 Files selected for processing (6)
  • CLAUDE.md (1 hunks)
  • libs/sdk/src/auth/flows/session.verify.flow.ts (5 hunks)
  • libs/sdk/src/notification/notification.service.ts (2 hunks)
  • libs/sdk/src/tool/flows/call-tool.flow.ts (2 hunks)
  • libs/testing/src/client/mcp-test-client.ts (2 hunks)
  • libs/testing/src/transport/streamable-http.transport.ts (4 hunks)
✅ Files skipped from review due to trivial changes (1)
  • CLAUDE.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • libs/sdk/src/auth/flows/session.verify.flow.ts
  • libs/testing/src/client/mcp-test-client.ts
  • libs/testing/src/transport/streamable-http.transport.ts
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Enable strict TypeScript mode with no any types without strong justification - use unknown instead for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific errors instead
Use specific error classes with MCP error codes instead of generic errors
Use type parameters with constraints instead of unconstrained generics, and prefer unknown over any for generic type defaults
Follow the preset pattern for hierarchical configurations across the codebase

Files:

  • libs/sdk/src/notification/notification.service.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
libs/{sdk,adapters,plugins,cli}/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

libs/{sdk,adapters,plugins,cli}/src/**/*.ts: Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of unknown for execute() and read() methods
Validate URIs per RFC 3986 at metadata level using Zod validation with custom refinements
Use getCapabilities() for dynamic capability exposure instead of hardcoding capabilities in adapters
Use changeScope instead of scope for change event properties to avoid confusion with the Scope class
Validate hooks match their entry type and fail fast with InvalidHookFlowError for unsupported flows
Don't mutate rawInput in flows - use state.set() for managing flow state instead

Files:

  • libs/sdk/src/notification/notification.service.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/sdk/src/notification/notification.service.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Don't mutate rawInput in flows - use state.set() for managing flow state instead

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Support platform-aware rendering by detecting network capabilities (open vs blocked) and script loading strategies (external vs inline)

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
🧬 Code graph analysis (1)
libs/sdk/src/tool/flows/call-tool.flow.ts (1)
libs/testing/src/client/mcp-test-client.ts (1)
  • sessionId (202-204)

Add [PLATFORM_DEBUG] console.log statements at 5 key points to trace
platform detection flow and identify why tests fail in CI (Linux)
but pass locally (Mac).

Debug points:
1. Client - User-Agent header being sent
2. Server - User-Agent header received in parseInput
3. Server - Platform detection in handlePublicMode
4. Server - applyUI platform type resolution
5. Client - Response _meta check for hasToolUI
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c6fb068 and d3a5d90.

📒 Files selected for processing (3)
  • libs/sdk/src/auth/authorization/authorization.class.ts (2 hunks)
  • libs/sdk/src/auth/machine-id.ts (1 hunks)
  • libs/sdk/src/auth/session/utils/session-id.utils.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Enable strict TypeScript mode with no any types without strong justification - use unknown instead for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific errors instead
Use specific error classes with MCP error codes instead of generic errors
Use type parameters with constraints instead of unconstrained generics, and prefer unknown over any for generic type defaults
Follow the preset pattern for hierarchical configurations across the codebase

Files:

  • libs/sdk/src/auth/machine-id.ts
  • libs/sdk/src/auth/authorization/authorization.class.ts
  • libs/sdk/src/auth/session/utils/session-id.utils.ts
libs/{sdk,adapters,plugins,cli}/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

libs/{sdk,adapters,plugins,cli}/src/**/*.ts: Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of unknown for execute() and read() methods
Validate URIs per RFC 3986 at metadata level using Zod validation with custom refinements
Use getCapabilities() for dynamic capability exposure instead of hardcoding capabilities in adapters
Use changeScope instead of scope for change event properties to avoid confusion with the Scope class
Validate hooks match their entry type and fail fast with InvalidHookFlowError for unsupported flows
Don't mutate rawInput in flows - use state.set() for managing flow state instead

Files:

  • libs/sdk/src/auth/machine-id.ts
  • libs/sdk/src/auth/authorization/authorization.class.ts
  • libs/sdk/src/auth/session/utils/session-id.utils.ts
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/sdk/src/auth/machine-id.ts
  • libs/sdk/src/auth/authorization/authorization.class.ts
  • libs/sdk/src/auth/session/utils/session-id.utils.ts
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable
🧬 Code graph analysis (3)
libs/sdk/src/auth/machine-id.ts (1)
libs/sdk/src/auth/authorization/authorization.class.ts (1)
  • getMachineId (19-19)
libs/sdk/src/auth/authorization/authorization.class.ts (1)
libs/sdk/src/auth/machine-id.ts (1)
  • getMachineId (23-25)
libs/sdk/src/auth/session/utils/session-id.utils.ts (3)
libs/sdk/src/common/types/auth/session.types.ts (1)
  • SessionIdPayload (71-86)
libs/sdk/src/auth/authorization/authorization.class.ts (1)
  • getMachineId (19-19)
libs/sdk/src/auth/machine-id.ts (1)
  • getMachineId (23-25)
🔇 Additional comments (6)
libs/sdk/src/auth/machine-id.ts (1)

19-25: LGTM!

The getter implementation is clean and provides a stable machine ID for the process lifetime.

libs/sdk/src/auth/session/utils/session-id.utils.ts (3)

8-8: LGTM!

The import of getMachineId from the centralized module and the updated comment correctly reflect the new single source of truth pattern.

Also applies to: 14-14


15-18: LGTM!

The getKey() function correctly uses getMachineId() for key derivation, maintaining consistency with the centralized machine ID module.


191-198: LGTM!

The session payload correctly uses getMachineId() for the nodeId field, ensuring consistency with session validation logic.

libs/sdk/src/auth/authorization/authorization.class.ts (2)

16-16: LGTM!

The import and re-export pattern correctly maintains backwards compatibility for external consumers who may be importing getMachineId from this module.

Also applies to: 18-19


79-94: LGTM!

The createTransportSession method correctly uses getMachineId() for the nodeId field, ensuring consistency across all session-related operations.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (5)
libs/testing/src/fixtures/test-fixture.ts (2)

132-134: Clarify the "all logs" comment.

The comment states "show all logs", but the code actually shows only the last 50 logs via logs.slice(-50). This is a reasonable safeguard, but the comment should reflect this limitation.

Apply this diff to clarify the comment:

-        // On failure, show all logs
+        // On failure, show last 50 logs
         console.log('[DIAG:server-logs] No DIAG logs found, showing all logs:');

Or update the console message:

         // On failure, show all logs
-        console.log('[DIAG:server-logs] No DIAG logs found, showing all logs:');
+        console.log('[DIAG:server-logs] No DIAG logs found, showing last 50 logs:');

264-277: Consider extracting the testFailed tracking pattern.

The pattern of declaring testFailed, setting it in the catch block, and passing it to cleanupTestFixtures is duplicated across testWithFixtures, skip, and only. While the duplication is minimal, extracting this pattern could improve maintainability.

Consider creating a helper function:

async function runTestWithCleanup(
  name: string,
  fn: TestFn,
  jestFn: typeof it | typeof it.skip | typeof it.only
): void {
  jestFn(name, async () => {
    const fixtures = await createTestFixtures();
    let testFailed = false;
    try {
      await fn(fixtures);
    } catch (error) {
      testFailed = true;
      throw error;
    } finally {
      await cleanupTestFixtures(fixtures, testFailed);
    }
  });
}

Then simplify the three functions:

function testWithFixtures(name: string, fn: TestFn): void {
  runTestWithCleanup(name, fn, it);
}

function skip(name: string, fn: TestFn): void {
  runTestWithCleanup(name, fn, it.skip);
}

function only(name: string, fn: TestFn): void {
  runTestWithCleanup(name, fn, it.only);
}

Also applies to: 296-309, 314-327

libs/sdk/src/tool/flows/call-tool.flow.ts (1)

386-398: Consider guarding diagnostic logs or using the existing logger.

The new console.log('[DIAG:...]') statements are not guarded by environment checks (unlike the existing debug logging at lines 572-578 which checks DEBUG or NODE_ENV). These will output in production and may create log noise.

Options:

  1. Guard with environment check similar to the existing pattern
  2. Use the existing this.logger.debug() or this.logger.verbose() for consistent log levels
  3. Remove before merging if these are temporary CI debugging aids

If these are meant to be permanent, consider using the existing logger:

-      console.log('[DIAG:call-tool.applyUI] platform detection context', {
+      this.logger.debug('applyUI: platform detection context', {
         toolName: tool.metadata.name,
         sessionId: sessionId?.slice(0, 20),
         // ... rest of properties
       });

Or guard them like the existing debug pattern:

+      if (process.env['DEBUG'] || process.env['NODE_ENV'] === 'development') {
         console.log('[DIAG:call-tool.applyUI] platform detection context', {
           // ...
         });
+      }

Also applies to: 408-418, 428-437, 448-456, 528-540, 624-633

libs/sdk/src/transport/mcp-handlers/initialize-request.handler.ts (1)

38-46: Same diagnostic logging pattern - consider guarding or using structured logger.

Consistent with call-tool.flow.ts, these console.log('[DIAG:...]') statements will run in production. The file already has a structured logger (logger) created at line 25 - consider using it for consistency.

-      console.log('[DIAG:initialize] request received', {
+      logger.debug('initialize: request context', {
         clientInfo: request.params.clientInfo,
         hasCapabilities: !!request.params.capabilities,
         sessionId: ctx.authInfo?.sessionId?.slice(0, 20),
         // ...
       });

Also applies to: 69-75, 95-104, 114-120, 122-128, 136-141, 143-148

libs/sdk/src/auth/flows/session.verify.flow.ts (1)

154-162: Consider guarding diagnostic logs in SDK library code.

Same pattern as other files - unguarded console.log('[DIAG:...]') statements. In SDK library code that may be used by many consumers, production logging noise is a stronger concern.

Consider using the scope logger if available, or guard with environment check:

+    if (process.env['DEBUG'] || process.env['FRONTMCP_DEBUG']) {
       console.log('[DIAG:session.verify] handlePublicMode called', {
         // ...
       });
+    }

Also applies to: 171-180, 192-197, 223-229, 244-250

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d3a5d90 and 5a47049.

📒 Files selected for processing (7)
  • apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts (2 hunks)
  • libs/sdk/src/auth/flows/session.verify.flow.ts (7 hunks)
  • libs/sdk/src/auth/machine-id.ts (1 hunks)
  • libs/sdk/src/tool/flows/call-tool.flow.ts (6 hunks)
  • libs/sdk/src/transport/mcp-handlers/initialize-request.handler.ts (4 hunks)
  • libs/testing/src/client/mcp-test-client.ts (2 hunks)
  • libs/testing/src/fixtures/test-fixture.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • libs/testing/src/client/mcp-test-client.ts
🧰 Additional context used
📓 Path-based instructions (4)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Enable strict TypeScript mode with no any types without strong justification - use unknown instead for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific errors instead
Use specific error classes with MCP error codes instead of generic errors
Use type parameters with constraints instead of unconstrained generics, and prefer unknown over any for generic type defaults
Follow the preset pattern for hierarchical configurations across the codebase

Files:

  • libs/sdk/src/auth/machine-id.ts
  • libs/sdk/src/auth/flows/session.verify.flow.ts
  • apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts
  • libs/sdk/src/transport/mcp-handlers/initialize-request.handler.ts
  • libs/testing/src/fixtures/test-fixture.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
libs/{sdk,adapters,plugins,cli}/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

libs/{sdk,adapters,plugins,cli}/src/**/*.ts: Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of unknown for execute() and read() methods
Validate URIs per RFC 3986 at metadata level using Zod validation with custom refinements
Use getCapabilities() for dynamic capability exposure instead of hardcoding capabilities in adapters
Use changeScope instead of scope for change event properties to avoid confusion with the Scope class
Validate hooks match their entry type and fail fast with InvalidHookFlowError for unsupported flows
Don't mutate rawInput in flows - use state.set() for managing flow state instead

Files:

  • libs/sdk/src/auth/machine-id.ts
  • libs/sdk/src/auth/flows/session.verify.flow.ts
  • libs/sdk/src/transport/mcp-handlers/initialize-request.handler.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/sdk/src/auth/machine-id.ts
  • libs/sdk/src/auth/flows/session.verify.flow.ts
  • libs/sdk/src/transport/mcp-handlers/initialize-request.handler.ts
  • libs/testing/src/fixtures/test-fixture.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
**/*.test.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.ts: Achieve and maintain 95%+ test coverage across all metrics (statements, branches, functions, lines)
Test all code paths including errors, constructor validation, and error class instanceof checks

Files:

  • apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Validate URIs per RFC 3986 at metadata level using Zod validation with custom refinements
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Don't mutate rawInput in flows - use state.set() for managing flow state instead

Applied to files:

  • libs/sdk/src/auth/flows/session.verify.flow.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable

Applied to files:

  • apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts
  • libs/testing/src/fixtures/test-fixture.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to **/*.test.ts : Test all code paths including errors, constructor validation, and error class `instanceof` checks

Applied to files:

  • apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts
  • libs/testing/src/fixtures/test-fixture.ts
🧬 Code graph analysis (3)
libs/sdk/src/auth/machine-id.ts (1)
libs/sdk/src/auth/authorization/authorization.class.ts (1)
  • getMachineId (19-19)
libs/sdk/src/auth/flows/session.verify.flow.ts (2)
libs/sdk/src/auth/session/utils/session-id.utils.ts (2)
  • decryptPublicSession (97-112)
  • encryptJson (30-39)
libs/sdk/src/notification/notification.service.ts (1)
  • detectPlatformFromUserAgent (181-199)
libs/sdk/src/transport/mcp-handlers/initialize-request.handler.ts (1)
libs/sdk/src/auth/session/utils/session-id.utils.ts (1)
  • updateSessionPayload (224-247)
⏰ 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: Build Libraries
  • GitHub Check: Lint & Format Checks
🔇 Additional comments (6)
libs/testing/src/fixtures/test-fixture.ts (1)

121-137: LGTM! Diagnostic logging implementation is sound.

The implementation correctly:

  • Detects CI environment using the standard CI environment variable
  • Guards against null serverInstance before accessing logs
  • Prioritizes DIAG-prefixed logs for clarity
  • Falls back to the last 50 logs when no DIAG logs are available

The logging enhancement will significantly improve debugging for test failures in CI environments.

apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts (2)

14-22: LGTM - Diagnostic logging is appropriate for E2E tests.

Environment and context logging at module load and in beforeAll is valuable for debugging CI failures. The captured information (platform, node version, CI flag, timestamps) will help trace test failures.

Also applies to: 30-41


587-710: Good diagnostic test coverage for platform detection chain.

The new diagnostic tests provide valuable tracing for CI debugging:

  • Full flow tracing for OpenAI with detailed state logging
  • Platform persistence across multiple requests validates session caching
  • Concurrent tool calls validates thread safety of platform detection

The conditional error logging (lines 616-621, 700-704) before assertions is a good pattern for debugging test failures.

libs/sdk/src/auth/machine-id.ts (1)

1-30: LGTM - Documentation addresses production concerns.

The module now includes clear documentation (lines 14-17) about:

  • Session invalidation on restart when MACHINE_ID is not set
  • Production guidance for multi-instance deployments
  • Session affinity considerations

This addresses the concerns raised in the previous review. The IIFE pattern ensures the ID is computed once and remains stable for the process lifetime.

libs/sdk/src/auth/flows/session.verify.flow.ts (2)

219-240: LGTM - Platform detection integration is well-implemented.

The platform detection from User-Agent:

  1. Uses the configurable platformDetectionConfig from scope metadata
  2. Only includes platformType in session payload when it's not 'unknown'
  3. Propagates to subsequent requests via the encrypted session ID

The conditional spread at line 239 is clean and prevents payload bloat for unknown platforms.


183-210: LGTM - Secure session payload handling.

The logic correctly:

  1. Always uses the client's session ID for transport registry lookup (line 205)
  2. Only trusts the decrypted payload when nodeId matches current machine (line 190)
  3. Responds with finalPayload: undefined when validation fails, letting the transport layer handle errors appropriately

This prevents session payload spoofing across different server instances.

frontegg-david and others added 2 commits December 17, 2025 20:04
The CI logs revealed that React component rendering is failing silently.s
Added console.log in the catch block of applyUI to capture the actual
error message when UI rendering fails on Linux.
Adds a manually-triggerable workflow to debug platform detection test failures.
Allows running specific test patterns without full CI suite.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
.github/workflows/debug-ui-tests.yml (2)

3-10: Document the lifecycle of this branch-specific workflow.

This workflow is tied exclusively to the fix-frontmcp-ui branch and will become inactive once the branch is merged or deleted. If this is a temporary debug workflow, consider adding a comment in the workflow file explaining its purpose and expected lifecycle. If this workflow should persist, update the trigger to include main or other relevant branches.


38-45: Consider parallelizing builds for faster execution.

The three library builds are currently sequential. For faster execution, you could use:

      - name: Build dependencies
        run: |
          echo "Building libraries in parallel..."
          npx nx run-many --target=build --projects=ui,sdk,testing --parallel=3

However, sequential execution with explicit echo statements may be preferable for a debug workflow where clarity is prioritized over speed.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e789247 and ceed4f8.

📒 Files selected for processing (1)
  • .github/workflows/debug-ui-tests.yml (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Validate URIs per RFC 3986 at metadata level using Zod validation with custom refinements
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable

Applied to files:

  • .github/workflows/debug-ui-tests.yml
⏰ 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). (3)
  • GitHub Check: Lint & Format Checks
  • GitHub Check: Build Libraries
  • GitHub Check: Debug UI E2E Tests
🔇 Additional comments (4)
.github/workflows/debug-ui-tests.yml (4)

12-21: LGTM!

The environment configuration is appropriate for CI. Disabling the NX daemon and setting a fixed MACHINE_ID ensures deterministic behavior for debugging session-related issues.


22-36: LGTM!

The checkout and Node.js setup follow CI best practices. Using .nvmrc for version management, enabling yarn cache, and installing with --frozen-lockfile ensures reproducible builds.


47-57: LGTM!

Printing environment details is valuable for debugging and helps troubleshoot platform-specific issues. The output includes all relevant version and configuration information.


66-74: LGTM!

The cleanup step follows CI best practices by running always and using || true to prevent failures when no processes are found. The specific pattern matching (demo-e2e-ui) ensures only relevant processes are targeted, and showing remaining processes aids debugging.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (1)
libs/testing/src/fixtures/test-fixture.ts (1)

117-125: Implement the documented server log output or update the JSDoc.

The JSDoc states that the _testFailed parameter is used "to output server logs," but the parameter is not used in the function body. The underscore prefix conventionally indicates an intentionally unused parameter, creating an inconsistency with the documentation.

Since this is a publishable SDK library, either implement the intended behavior or update the JSDoc to reflect that this is a placeholder for future enhancement.

If the intent is to output server logs on test failure, consider implementing:

-async function cleanupTestFixtures(fixtures: TestFixtures, _testFailed = false): Promise<void> {
+async function cleanupTestFixtures(fixtures: TestFixtures, testFailed = false): Promise<void> {
   // Disconnect client
   if (fixtures.mcp.isConnected()) {
     await fixtures.mcp.disconnect();
   }
+  // Output server logs on failure for debugging
+  if (testFailed && serverInstance) {
+    const logs = serverInstance.getLogs();
+    if (logs.length > 0) {
+      console.error('Server logs from failed test:');
+      console.error(logs);
+    }
+  }
 }
♻️ Duplicate comments (1)
libs/testing/src/fixtures/test-fixture.ts (1)

296-309: Same duplication pattern as skip function.

The error handling is correct but duplicates the same pattern. See the previous comment on lines 278-291 for the optional refactoring suggestion.

🧹 Nitpick comments (2)
libs/testing/src/fixtures/test-fixture.ts (1)

278-291: Consider extracting the common error handling pattern.

The error handling logic is correct and identical to testWithFixtures. While functional, the duplication across three functions (testWithFixtures, skip, only) could be reduced by extracting a shared wrapper.

Optional refactor to reduce duplication:

async function runTestWithFixtures(fn: TestFn): Promise<void> {
  const fixtures = await createTestFixtures();
  let testFailed = false;
  try {
    await fn(fixtures);
  } catch (error) {
    testFailed = true;
    throw error;
  } finally {
    await cleanupTestFixtures(fixtures, testFailed);
  }
}

function testWithFixtures(name: string, fn: TestFn): void {
  it(name, () => runTestWithFixtures(fn));
}

function skip(name: string, fn: TestFn): void {
  it.skip(name, () => runTestWithFixtures(fn));
}

function only(name: string, fn: TestFn): void {
  it.only(name, () => runTestWithFixtures(fn));
}
libs/sdk/src/tool/flows/call-tool.flow.ts (1)

495-510: Extract duplicated template type inference into a helper method.

The template type detection logic (lines 500–508 in the console.log) is duplicated verbatim in the logger.error call below. Extract this into a private method to avoid maintenance issues:

private inferTemplateType(template: unknown): string {
  if (!template) return 'none';
  if (typeof template === 'function') return 'react-component';
  if (typeof template === 'string') {
    return template.endsWith('.tsx') || template.endsWith('.jsx') ? 'react-file' : 'html-file';
  }
  return 'unknown';
}

Then call it from both logging statements. This keeps the diagnostic logging intact while reducing duplication and improving maintainability.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ceed4f8 and af9c922.

📒 Files selected for processing (5)
  • CLAUDE.md (2 hunks)
  • libs/sdk/src/auth/flows/session.verify.flow.ts (6 hunks)
  • libs/sdk/src/tool/flows/call-tool.flow.ts (1 hunks)
  • libs/testing/src/client/mcp-test-client.ts (1 hunks)
  • libs/testing/src/fixtures/test-fixture.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • CLAUDE.md
🧰 Additional context used
📓 Path-based instructions (3)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Enable strict TypeScript mode with no any types without strong justification - use unknown instead for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific errors instead
Use specific error classes with MCP error codes instead of generic errors
Use type parameters with constraints instead of unconstrained generics, and prefer unknown over any for generic type defaults
Follow the preset pattern for hierarchical configurations across the codebase

Files:

  • libs/sdk/src/auth/flows/session.verify.flow.ts
  • libs/testing/src/fixtures/test-fixture.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/testing/src/client/mcp-test-client.ts
libs/{sdk,adapters,plugins,cli}/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

libs/{sdk,adapters,plugins,cli}/src/**/*.ts: Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of unknown for execute() and read() methods
Validate URIs per RFC 3986 at metadata level using Zod validation with custom refinements
Use getCapabilities() for dynamic capability exposure instead of hardcoding capabilities in adapters
Use changeScope instead of scope for change event properties to avoid confusion with the Scope class
Validate hooks match their entry type and fail fast with InvalidHookFlowError for unsupported flows
Don't mutate rawInput in flows - use state.set() for managing flow state instead

Files:

  • libs/sdk/src/auth/flows/session.verify.flow.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/sdk/src/auth/flows/session.verify.flow.ts
  • libs/testing/src/fixtures/test-fixture.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/testing/src/client/mcp-test-client.ts
🧠 Learnings (4)
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Don't mutate rawInput in flows - use state.set() for managing flow state instead

Applied to files:

  • libs/sdk/src/auth/flows/session.verify.flow.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable

Applied to files:

  • libs/testing/src/fixtures/test-fixture.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to **/*.test.ts : Test all code paths including errors, constructor validation, and error class `instanceof` checks

Applied to files:

  • libs/testing/src/fixtures/test-fixture.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.ts : Validate component options using `validateOptions()` helper and return error box on validation failure

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
🧬 Code graph analysis (1)
libs/sdk/src/auth/flows/session.verify.flow.ts (1)
libs/sdk/src/notification/notification.service.ts (1)
  • detectPlatformFromUserAgent (181-199)
⏰ 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). (3)
  • GitHub Check: Lint & Format Checks
  • GitHub Check: Build Libraries
  • GitHub Check: Debug UI E2E Tests
🔇 Additional comments (7)
libs/testing/src/client/mcp-test-client.ts (1)

805-805: LGTM! clientInfo correctly propagated to transport.

The addition of clientInfo to the transport configuration properly enables the transport layer to access client metadata for User-Agent header construction, aligning with the PR objectives.

libs/sdk/src/auth/flows/session.verify.flow.ts (5)

26-26: LGTM!

Import of detectPlatformFromUserAgent aligns with the platform detection usage below.


36-36: LGTM!

Adding userAgent to state schema follows the established pattern and correctly uses state.set() for flow state management per coding guidelines.


112-123: LGTM!

User-Agent extraction follows the established pattern and correctly propagates through state.set(). Based on learnings, this properly avoids mutating rawInput.


169-178: Verify behavior in multi-node deployments.

The finalPayload logic discards the existing session payload when nodeId doesn't match machineId. In distributed environments where different nodes may handle the same session, this could cause payload data (protocol info, etc.) to be lost when requests are routed to a different node than the one that created the session.

If this is intentional (e.g., for security or consistency), consider adding a brief comment explaining why payload from other nodes should not be trusted.


191-204: LGTM!

Platform detection implementation is clean:

  • Safely accesses optional config with ?.
  • detectPlatformFromUserAgent gracefully handles undefined inputs
  • Conditional spread avoids adding 'unknown' to payload

Good use of existing state (this.state.userAgent) rather than re-accessing the request.

libs/testing/src/fixtures/test-fixture.ts (1)

246-259: LGTM!

The error handling correctly tracks test failure status and propagates it to cleanup while maintaining proper error re-throwing for test failure reporting.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between af9c922 and f11c542.

📒 Files selected for processing (1)
  • libs/ui/src/registry/tool-ui.registry.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
libs/ui/src/**/*.ts

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

libs/ui/src/**/*.ts: Always use escapeHtml() utility for all user-provided content to prevent XSS vulnerabilities
Hard-code CDN URLs only in theme presets; always reference theme.cdn configuration in component code

Files:

  • libs/ui/src/registry/tool-ui.registry.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Enable strict TypeScript mode with no any types without strong justification - use unknown instead for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific errors instead
Use specific error classes with MCP error codes instead of generic errors
Use type parameters with constraints instead of unconstrained generics, and prefer unknown over any for generic type defaults
Follow the preset pattern for hierarchical configurations across the codebase

Files:

  • libs/ui/src/registry/tool-ui.registry.ts
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/ui/src/registry/tool-ui.registry.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.ts : Use pure HTML string generation without React/Vue/JSX - components return HTML strings only

Applied to files:

  • libs/ui/src/registry/tool-ui.registry.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: Build Libraries
  • GitHub Check: Debug UI E2E Tests

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
.github/workflows/debug-ui-tests.yml (1)

59-62: Add artifact collection for test failures.

As noted in a previous review, when tests fail there are no artifacts captured (test logs, screenshots, or diagnostic output), which limits the debugging value of this workflow.

Consider adding a step after test execution to capture artifacts:

      - name: Upload test artifacts on failure
        if: failure()
        uses: actions/upload-artifact@v4
        with:
          name: test-artifacts
          path: |
            apps/e2e/demo-e2e-ui/test-results/
            apps/e2e/demo-e2e-ui/screenshots/
            apps/e2e/demo-e2e-ui/**/*.log
          retention-days: 7
🧹 Nitpick comments (1)
.github/workflows/debug-ui-tests.yml (1)

3-6: Temporary debug workflow—remove or generalize before merge.

This workflow triggers only on the fix-frontmcp-ui branch (the source branch of this PR), indicating it's intended for debugging during development. Ensure this workflow is either removed or generalized to apply to other relevant branches before merging to main.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f11c542 and 9eafd34.

📒 Files selected for processing (1)
  • .github/workflows/debug-ui-tests.yml (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable

Applied to files:

  • .github/workflows/debug-ui-tests.yml
⏰ 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). (3)
  • GitHub Check: Build Libraries
  • GitHub Check: Lint & Format Checks
  • GitHub Check: Debug UI E2E Tests
🔇 Additional comments (1)
.github/workflows/debug-ui-tests.yml (1)

64-72: LGTM! Good cleanup pattern with diagnostic output.

The cleanup step appropriately uses if: always() to ensure orphan processes are terminated regardless of test outcome. The pattern matching (tsx.*demo-e2e-ui and node.*demo-e2e-ui) is specific enough to target only relevant processes, and the || true guards prevent workflow failure. The final diagnostic output is helpful for verifying cleanup success.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts (1)

50-68: Consider enhancing diagnostic robustness and consistency.

The diagnostic logging is helpful for CI debugging. A few optional improvements:

  1. Case-insensitive log filtering: Line 61 uses case-sensitive matching for 'DIAG' and 'react'. Consider using .toLowerCase() to catch variations like 'React' or 'DIAG'.

  2. Safe JSON serialization: Line 53's JSON.stringify(result.raw._meta) could throw on circular references. Wrap in a try-catch or use a safe stringify helper.

  3. Selective placement: Diagnostics appear only in this test (OpenAI variant with react-chart). If this is intentional for debugging a specific issue, consider adding a comment explaining why. Otherwise, consider extracting to a reusable helper if other tests would benefit.

Example for case-insensitive filtering:

-      const reactLogs = logs.filter((l) => l.includes('DIAG') || l.includes('react'));
+      const reactLogs = logs.filter((l) => {
+        const lower = l.toLowerCase();
+        return lower.includes('diag') || lower.includes('react');
+      });
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9eafd34 and b790ca9.

📒 Files selected for processing (1)
  • apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Enable strict TypeScript mode with no any types without strong justification - use unknown instead for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific errors instead
Use specific error classes with MCP error codes instead of generic errors
Use type parameters with constraints instead of unconstrained generics, and prefer unknown over any for generic type defaults
Follow the preset pattern for hierarchical configurations across the codebase

Files:

  • apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts
**/*.test.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.ts: Achieve and maintain 95%+ test coverage across all metrics (statements, branches, functions, lines)
Test all code paths including errors, constructor validation, and error class instanceof checks

Files:

  • apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable

Applied to files:

  • apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.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). (3)
  • GitHub Check: Build Libraries
  • GitHub Check: Lint & Format Checks
  • GitHub Check: Debug UI E2E Tests

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (1)
libs/ui/src/adapters/index.ts (1)

24-34: Breaking API change in public adapter exports: platformUsesDualPayload renamed to platformUsesStructuredContent.

Consumers of @frontmcp/ui importing platformUsesDualPayload will encounter a breaking change. While the documentation discusses the dual-payload/structured-content concept across multiple guides, there is no API reference documenting the adapter module exports. Per coding guidelines, public API changes in libs/** require matching docs/draft/docs/** updates. An API reference section for @frontmcp/ui/adapters should be added or updated to document the renamed function and its purpose.

🧹 Nitpick comments (1)
libs/ui/src/adapters/response-builder.ts (1)

179-187: Widget fallback path may be unreachable with current configuration.

Currently, all platforms with supportsWidgets: true also have useStructuredContent: true in PLATFORM_CAPABILITIES. This means the widget fallback path (lines 181-186) won't execute under the current configuration.

Consider whether this code path should be kept for future flexibility or documented as intentionally unreachable with current platform mappings. If it's intentional to preserve for future platforms that support widgets but not structuredContent, adding a comment would clarify this.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 424a079 and f895756.

📒 Files selected for processing (9)
  • libs/sdk/src/tool/flows/call-tool.flow.ts (5 hunks)
  • libs/ui/src/adapters/__tests__/dual-payload.test.ts (0 hunks)
  • libs/ui/src/adapters/__tests__/response-builder.test.ts (8 hunks)
  • libs/ui/src/adapters/__tests__/serving-mode.test.ts (5 hunks)
  • libs/ui/src/adapters/dual-payload.ts (0 hunks)
  • libs/ui/src/adapters/index.ts (1 hunks)
  • libs/ui/src/adapters/response-builder.ts (6 hunks)
  • libs/ui/src/adapters/serving-mode.ts (10 hunks)
  • libs/ui/src/index.ts (2 hunks)
💤 Files with no reviewable changes (2)
  • libs/ui/src/adapters/tests/dual-payload.test.ts
  • libs/ui/src/adapters/dual-payload.ts
🧰 Additional context used
📓 Path-based instructions (7)
libs/ui/src/**/*.ts

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

libs/ui/src/**/*.ts: Always use escapeHtml() utility for all user-provided content to prevent XSS vulnerabilities
Hard-code CDN URLs only in theme presets; always reference theme.cdn configuration in component code

Files:

  • libs/ui/src/adapters/index.ts
  • libs/ui/src/adapters/__tests__/serving-mode.test.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
  • libs/ui/src/adapters/serving-mode.ts
  • libs/ui/src/adapters/response-builder.ts
  • libs/ui/src/index.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Enable strict TypeScript mode with no any types without strong justification - use unknown instead for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific errors instead
Use specific error classes with MCP error codes instead of generic errors
Use type parameters with constraints instead of unconstrained generics, and prefer unknown over any for generic type defaults
Follow the preset pattern for hierarchical configurations across the codebase

Files:

  • libs/ui/src/adapters/index.ts
  • libs/ui/src/adapters/__tests__/serving-mode.test.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/ui/src/adapters/serving-mode.ts
  • libs/ui/src/adapters/response-builder.ts
  • libs/ui/src/index.ts
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/ui/src/adapters/index.ts
  • libs/ui/src/adapters/__tests__/serving-mode.test.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/ui/src/adapters/serving-mode.ts
  • libs/ui/src/adapters/response-builder.ts
  • libs/ui/src/index.ts
libs/ui/src/**/*.test.ts

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

libs/ui/src/**/*.test.ts: Maintain 95%+ test coverage across statements, branches, functions, and lines
Test HTML escaping for user-provided content to prevent XSS attacks
Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable

Files:

  • libs/ui/src/adapters/__tests__/serving-mode.test.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
**/*.test.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.ts: Achieve and maintain 95%+ test coverage across all metrics (statements, branches, functions, lines)
Test all code paths including errors, constructor validation, and error class instanceof checks

Files:

  • libs/ui/src/adapters/__tests__/serving-mode.test.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
libs/{sdk,adapters,plugins,cli}/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

libs/{sdk,adapters,plugins,cli}/src/**/*.ts: Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of unknown for execute() and read() methods
Validate URIs per RFC 3986 at metadata level using Zod validation with custom refinements
Use getCapabilities() for dynamic capability exposure instead of hardcoding capabilities in adapters
Use changeScope instead of scope for change event properties to avoid confusion with the Scope class
Validate hooks match their entry type and fail fast with InvalidHookFlowError for unsupported flows
Don't mutate rawInput in flows - use state.set() for managing flow state instead

Files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
libs/*/src/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use barrel exports (index.ts) to export all public API surface without legacy exports or aliases

Files:

  • libs/ui/src/index.ts
🧠 Learnings (17)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test HTML escaping for user-provided content to prevent XSS attacks
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/*/src/index.ts : Use barrel exports (index.ts) to export all public API surface without legacy exports or aliases

Applied to files:

  • libs/ui/src/adapters/index.ts
  • libs/ui/src/adapters/__tests__/serving-mode.test.ts
  • libs/ui/src/index.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Use `getCapabilities()` for dynamic capability exposure instead of hardcoding capabilities in adapters

Applied to files:

  • libs/ui/src/adapters/index.ts
  • libs/ui/src/adapters/__tests__/serving-mode.test.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
  • libs/ui/src/adapters/serving-mode.ts
  • libs/ui/src/index.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Use `changeScope` instead of `scope` for change event properties to avoid confusion with the Scope class

Applied to files:

  • libs/ui/src/adapters/index.ts
  • libs/ui/src/adapters/__tests__/serving-mode.test.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable

Applied to files:

  • libs/ui/src/adapters/index.ts
  • libs/ui/src/adapters/__tests__/serving-mode.test.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
  • libs/ui/src/adapters/serving-mode.ts
  • libs/ui/src/index.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Support platform-aware rendering by detecting network capabilities (open vs blocked) and script loading strategies (external vs inline)

Applied to files:

  • libs/ui/src/adapters/index.ts
  • libs/ui/src/adapters/serving-mode.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test HTML escaping for user-provided content to prevent XSS attacks

Applied to files:

  • libs/ui/src/adapters/__tests__/serving-mode.test.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.test.ts : Write validation tests covering invalid variant/options, unknown properties, and valid option acceptance

Applied to files:

  • libs/ui/src/adapters/__tests__/serving-mode.test.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Maintain 95%+ test coverage across statements, branches, functions, and lines

Applied to files:

  • libs/ui/src/adapters/__tests__/serving-mode.test.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.ts : Always use `escapeHtml()` utility for all user-provided content to prevent XSS vulnerabilities

Applied to files:

  • libs/ui/src/adapters/__tests__/response-builder.test.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Don't mutate rawInput in flows - use state.set() for managing flow state instead

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.schema.ts : Every component must have a Zod schema with `.strict()` mode to reject unknown properties

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.ts : Validate component options using `validateOptions()` helper and return error box on validation failure

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.schema.ts : Use HTMX schema with strict mode including get, post, put, delete, target, swap, and trigger properties

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/** : Organize components into schema.ts (definitions) and implementation .ts files with matching names

Applied to files:

  • libs/ui/src/index.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.ts : Use pure HTML string generation without React/Vue/JSX - components return HTML strings only

Applied to files:

  • libs/ui/src/index.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/*/src/common/records/**/*.ts : Centralize record types in common/records and import from there instead of from module-specific files

Applied to files:

  • libs/ui/src/index.ts
🧬 Code graph analysis (3)
libs/ui/src/adapters/__tests__/response-builder.test.ts (1)
libs/ui/src/adapters/response-builder.ts (1)
  • buildToolResponseContent (130-212)
libs/sdk/src/tool/flows/call-tool.flow.ts (2)
libs/ui/src/registry/tool-ui.registry.ts (1)
  • isUIRenderFailure (91-93)
libs/ui/src/adapters/response-builder.ts (1)
  • buildToolResponseContent (130-212)
libs/ui/src/adapters/serving-mode.ts (2)
libs/ui/src/adapters/index.ts (2)
  • AIPlatformType (13-13)
  • platformUsesStructuredContent (32-32)
libs/ui/src/index.ts (2)
  • AIPlatformType (51-51)
  • platformUsesStructuredContent (66-66)
⏰ 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: Build Libraries
  • GitHub Check: Lint & Format Checks
🔇 Additional comments (22)
libs/ui/src/adapters/serving-mode.ts (4)

26-49: Clean interface design for the structuredContent transition.

The ResolvedServingMode interface is well-structured with clear documentation. The addition of supportsUI alongside useStructuredContent provides good separation of concerns - widget support vs. content format.


89-150: Platform capabilities are consistently mapped.

The PLATFORM_CAPABILITIES map correctly aligns useStructuredContent with widget support across all platforms. The pattern of supportsWidgets: trueuseStructuredContent: true is consistent, which makes the behavior predictable.


185-228: Resolver logic correctly propagates structuredContent flag.

All four code paths in resolveServingMode correctly return useStructuredContent from the platform capabilities. The fallback to PLATFORM_CAPABILITIES.unknown on line 187 ensures graceful handling of unexpected platform types.


251-259: Helper function correctly renamed and documented.

The platformUsesStructuredContent function follows the established pattern and provides clear documentation about the structuredContent format behavior.

libs/ui/src/adapters/__tests__/serving-mode.test.ts (4)

6-11: Import updated correctly for renamed function.

The import correctly reflects the API change from platformUsesDualPayload to platformUsesStructuredContent.


15-115: Comprehensive auto mode test coverage across all platforms.

Tests cover all defined platforms (openai, ext-apps, claude, cursor, continue, cody, generic-mcp, gemini, unknown) with correct assertions for useStructuredContent behavior. This aligns with the coding guidelines to test behavior across platform configurations. Based on learnings.


117-191: Forced mode tests correctly validate structuredContent behavior.

The tests properly verify that useStructuredContent is returned when a supported mode is explicitly configured (line 167), and that UI is skipped when unsupported modes are forced on platforms like Claude and Continue.


243-258: Test suite for platformUsesStructuredContent covers all platforms.

The tests comprehensively verify the helper function returns true for all widget-supporting platforms and false for non-widget platforms (gemini, unknown).

libs/sdk/src/tool/flows/call-tool.flow.ts (3)

27-28: New import for UI render failure handling.

The isUIRenderFailure import enables proper discrimination of render failures for graceful degradation.


464-477: Graceful degradation for UI render failures is well-implemented.

The handling correctly logs a warning with useful context (tool, reason, platform) and proceeds without UI content. This ensures tool functionality isn't blocked by UI rendering issues, which aligns with the existing error handling approach in the outer try-catch (lines 501-530).


415-500: Correct propagation of useStructuredContent through applyUI.

The useStructuredContent flag is properly extracted from the resolved mode (line 416) and passed to buildToolResponseContent (line 485). The logging at line 497 aids debugging.

libs/ui/src/adapters/response-builder.ts (3)

33-59: Clean interface update with proper typing.

BuildToolResponseOptions correctly uses useStructuredContent: boolean instead of the old useDualPayload. The documentation clearly explains the behavior when true.


64-92: ToolResponseContent interface properly typed.

The structuredContent?: unknown type follows coding guidelines to use unknown instead of any. The updated format union removes dual-payload and adds structured-content to reflect the new semantics.


130-177: Inline mode structuredContent logic is correct.

The function properly handles:

  • useStructuredContent: true + HTML → structured-content format with raw HTML in content and rawOutput in structuredContent
  • useStructuredContent: true + no HTML → json-only format with structuredContent populated
  • Empty string HTML is correctly treated as falsy (line 159)
libs/ui/src/adapters/__tests__/response-builder.test.ts (6)

10-16: Test helper correctly defaults to new API.

The createOptions helper sets useStructuredContent: true as the default, aligning with the typical expected usage for widget-supporting platforms.


34-58: Static mode structuredContent tests are well-structured.

Tests properly verify that:

  • structuredContent is included when useStructuredContent: true (lines 34-45)
  • structuredContent is undefined when useStructuredContent: false (lines 47-58)

119-183: Comprehensive inline mode tests across all widget-supporting platforms.

The parameterized test (lines 130-152) efficiently covers all 7 widget-supporting platforms. Fallback behavior tests (lines 154-182) verify correct handling when HTML content is missing or empty. Based on learnings.


185-200: Widget fallback test covers legacy behavior.

The test verifies that when useStructuredContent: false on a widget-supporting platform, the legacy widget format is used with cleared content.


406-445: Dedicated structuredContent property tests cover all combinations.

The test suite provides focused coverage for the structuredContent property:

  • With HTML (line 407-418)
  • Without HTML (line 420-431)
  • When disabled (line 433-444)

246-260: Test correctly verifies HTML passthrough for client-side sandbox rendering.

The test accurately documents the intended security model: HTML is passed as-is because the structured-content format is designed for client-side sandbox rendering on the platform (OpenAI, Claude, etc.). This is a layered security approach where content protection relies on iframe sandboxing, not server-side HTML escaping. The htmlContent represents tool output (not user-provided input), which is appropriate for structured-content rendering. The coding guideline to use escapeHtml() applies to user-provided content in libs/ui/src/**/*.ts (form inputs, user text, labels), but htmlContent follows a different security pattern—trusted tool output rendered in an isolated sandbox context.

libs/ui/src/index.ts (2)

342-463: Well-organized expansion of the public API surface.

The new Universal Renderer Module and TypeScript Type Fetching Engine exports are well-documented and logically organized. The structure follows existing patterns in the file and maintains good separation of concerns.


66-66: No action required. Migration from platformUsesDualPayload to platformUsesStructuredContent is complete—no remaining references to the old function name exist in the codebase, and the new function is properly exported, tested, and implemented.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (9)
libs/ui/src/components/badge.ts (2)

132-132: XSS vulnerability: icon parameter is not escaped.

The icon parameter is directly injected into the HTML without escaping at Line 132. If user-provided content is passed as the icon, this creates an XSS vulnerability. All user-provided content must be escaped.

Based on coding guidelines: "Always use escapeHtml() utility for all user-provided content to prevent XSS vulnerabilities".

🔎 Apply this diff to escape the icon content:
- const iconHtml = icon ? `<span class="mr-1">${icon}</span>` : '';
+ const iconHtml = icon ? `<span class="mr-1">${escapeHtml(icon)}</span>` : '';

Note: If the icon is intentionally expected to contain trusted HTML (e.g., SVG markup), document this assumption clearly and consider adding a separate parameter like iconHtml for pre-sanitized HTML while keeping icon for plain text.


88-97: Missing schema validation per coding guidelines.

The badge function does not validate the options parameter using the BadgeOptionsSchema and validateOptions() helper. According to the coding guidelines, components should validate inputs and return an error box on validation failure.

Based on coding guidelines: "Validate component options using validateOptions() helper and return error box on validation failure".

Consider adding validation at the beginning of the function:

export function badge(text: string, options: BadgeOptions = {}): string {
  const validationResult = validateOptions(BadgeOptionsSchema, options);
  if (!validationResult.success) {
    return errorBox('Invalid badge options', validationResult.error);
  }
  
  const {
    variant = 'default',
    // ... rest of destructuring
  } = options;
  // ... rest of implementation
}
libs/ui/src/components/table.ts (1)

383-392: Potential XSS vulnerability in page size selector.

The baseUrl is interpolated directly into the onchange JavaScript handler without escaping. If baseUrl contains quotes or malicious content, it could break the handler or enable script injection.

🔎 Apply this diff to escape the URL:
   const pageSizeHtml = showPageSize
     ? `<select
         class="ml-4 px-2 py-1 text-sm border border-border rounded-lg bg-white"
-        onchange="window.location.href = '${baseUrl}${baseUrl.includes('?') ? '&' : '?'}page=1&pageSize=' + this.value"
+        onchange="window.location.href = '${escapeHtml(baseUrl)}${baseUrl.includes('?') ? '&' : '?'}page=1&pageSize=' + this.value"
       >
libs/ui/src/components/table.schema.ts (1)

122-147: Schema missing baseUrl field - inconsistent with implementation.

The PaginationOptions interface in table.ts (lines 293-294) includes a baseUrl?: string property, but PaginationOptionsSchema doesn't define it. With .strict() mode, passing baseUrl will cause validation to fail.

🔎 Apply this diff to add the missing field:
 export const PaginationOptionsSchema = z
   .object({
     /** Current page (1-indexed) */
     page: z.number().min(1),
     /** Total pages */
     totalPages: z.number().min(0),
     /** Total items count */
     totalItems: z.number().min(0).optional(),
     /** Items per page */
     pageSize: z.number().min(1).optional(),
     /** Page size options */
     pageSizeOptions: z.array(z.number()).optional(),
     /** Show first/last buttons */
     showFirstLast: z.boolean().optional(),
     /** Show page count */
     showPageCount: z.boolean().optional(),
     /** Show item count */
     showItemCount: z.boolean().optional(),
     /** Show page size selector */
     showPageSize: z.boolean().optional(),
     /** Max visible page buttons */
     maxVisiblePages: z.number().min(1).optional(),
     /** Additional CSS classes */
     className: z.string().optional(),
+    /** Base URL for page links */
+    baseUrl: z.string().optional(),
   })
   .strict();
libs/ui/src/components/alert.ts (2)

98-141: Add option validation per coding guidelines.

The coding guidelines require validating component options using the validateOptions() helper and returning an error box on validation failure. This pattern should be implemented at the start of the alert() function.

As per coding guidelines: "Validate component options using validateOptions() helper and return error box on validation failure" applies to libs/ui/src/components/**/*.ts.


21-38: Update alert documentation and add input validation.

  1. Breaking API change not documented: The onDismiss property has been removed from AlertOptions, but docs/draft/docs/ui/components/alert.mdx still references it (lines 100, 255) and includes example code using this removed option. Update the documentation to remove references to onDismiss and document the migration path for existing code.

  2. Missing input validation: Although alert.schema.ts exists with AlertOptionsSchema, the alert() and toast() functions do not validate options using validateOptions(). Add validation to match the pattern used in other components like button.ts.

  3. Missing JSDoc @example tags: Add @example tags to the alert() and toast() function documentation showing basic usage patterns and common options, as required by the component guidelines.

libs/ui/src/widgets/resource.ts (2)

63-71: Remove unused HTMX properties from the interface.

The htmx properties in ResourceAction are no longer used anywhere in the codebase. Lines 252-260 compute HTMX attributes but never pass them to the button component, making these interface properties dead code.

🔎 Apply this diff to remove the unused properties:
 export interface ResourceAction {
   /** Action label */
   label: string;
   /** Action icon */
   icon?: string;
   /** Action URL */
   href?: string;
-  /** HTMX attributes */
-  htmx?: {
-    get?: string;
-    post?: string;
-    delete?: string;
-    target?: string;
-    swap?: string;
-    confirm?: string;
-  };
   /** Variant */
   variant?: 'primary' | 'secondary' | 'danger' | 'ghost';
   /** Disabled */
   disabled?: boolean;
 }

252-260: Remove dead code that computes unused HTMX attributes.

The htmxAttrs array is built but never used. It's not passed to the button() function below (lines 262-268), making this entire block dead code.

🔎 Apply this diff to remove the dead code:
             const variant = action.variant ? variantMap[action.variant] : 'ghost';
 
-            const htmxAttrs: string[] = [];
-            if (action.htmx) {
-              if (action.htmx.get) htmxAttrs.push(`hx-get="${escapeHtml(action.htmx.get)}"`);
-              if (action.htmx.post) htmxAttrs.push(`hx-post="${escapeHtml(action.htmx.post)}"`);
-              if (action.htmx.delete) htmxAttrs.push(`hx-delete="${escapeHtml(action.htmx.delete)}"`);
-              if (action.htmx.target) htmxAttrs.push(`hx-target="${escapeHtml(action.htmx.target)}"`);
-              if (action.htmx.swap) htmxAttrs.push(`hx-swap="${escapeHtml(action.htmx.swap)}"`);
-              if (action.htmx.confirm) htmxAttrs.push(`hx-confirm="${escapeHtml(action.htmx.confirm)}"`);
-            }
-
             return button(action.label, {
               variant: variant as 'primary' | 'secondary' | 'danger' | 'ghost',
libs/sdk/src/auth/ui/templates.ts (1)

94-182: Form submission implementation is broken and will not work in production.

The consent page form POSTs to /oauth/consent endpoint which does not exist. Additionally, the actual callback handler at /oauth/callback is configured for GET requests only and reads parameters from request.query, not from the POST request body. The form data (consent selections) will be completely lost.

Critical issues:

  1. Missing endpoint: Form POSTs to /oauth/consent but no such endpoint exists
  2. POST body not parsed: oauth.callback.flow.ts only reads from request.query (lines 103-126), ignoring the POST body entirely
  3. Data loss: Consent checkbox selections sent in the POST body will never be processed
  4. No E2E test coverage: No tests found for form submission workflows

Required fixes:

  • Implement /oauth/consent POST endpoint or update form to POST to /oauth/callback with proper HTTP method configuration
  • Add POST body parsing to extract form data (pending_auth_id, tools checkbox selections)
  • Add E2E tests covering the complete consent form submission flow
  • Ensure form data validation and error handling
🧹 Nitpick comments (7)
libs/ui/src/components/badge.schema.ts (1)

27-36: Variant enums are consistent with codebase patterns.

The variant enum includes most standard variants. Consider adding 'ghost' to align fully with the coding guideline's recommended variant set, though the current set is reasonable for badge use cases.

Based on coding guidelines.

libs/ui/src/web-components/core/base-element.test.ts (1)

384-396: Consider verifying absence of HTMX attributes.

The test verifies that expected attributes are present but doesn't explicitly check that hx-get, hx-post, and other HTMX attributes are NOT included. Consider adding assertions to verify the complete removal of HTMX attribute support.

🔎 Suggested test enhancement
  it('should return observed attributes from schema', () => {
    const attrs = TestElement.observedAttributes;

    expect(attrs).toContain('variant');
    expect(attrs).toContain('size');
    expect(attrs).toContain('disabled');
    expect(attrs).toContain('full-width');
    // Common attrs
    expect(attrs).toContain('class');
    expect(attrs).toContain('id');
+   // Verify HTMX attributes are not included
+   expect(attrs).not.toContain('hx-get');
+   expect(attrs).not.toContain('hx-post');
  });
libs/ui/src/web-components/core/attribute-parser.ts (1)

130-148: Refactor to follow Zod 4 best practices and narrow the type signature.

The function currently accepts the generic ZodSchema<T> but only reliably works with object schemas. While the defensive check prevents crashes, it masks the true constraint. For Zod 4, library authors should use schema._zod.def.shape for schema introspection rather than direct property access.

Since all current usages pass z.object() schemas, improve the implementation by:

  • Narrowing the type signature to explicitly accept only ZodObject schemas
  • Using Zod 4-compliant introspection (._zod.def.shape when needed for Zod 4/Mini compatibility)
  • Making the schema type constraint explicit in the API

This prevents future misuse if non-object schemas are accidentally passed, and aligns with Zod 4's recommended library author patterns.

libs/ui/src/components/card.schema.ts (1)

27-42: Variant and size enums deviate from standard naming conventions.

Per coding guidelines, variants should use ('primary', 'secondary', 'outline', 'ghost', 'danger', 'success') and sizes should include ('xs', 'sm', 'md', 'lg', 'xl'). The card component uses semantic variants like 'default', 'outlined', 'elevated', 'filled' which are more appropriate for card styling, and omits 'xs'/'xl' sizes.

If this is intentional for card-specific semantics, consider documenting the rationale. Otherwise, align with the standard enums for consistency.

libs/ui/src/components/card.ts (1)

92-107: Missing JSDoc @example tags.

Per coding guidelines, components should include JSDoc examples with @example tags showing basic usage and options patterns. Consider adding documentation for the card() and cardGroup() functions.

Example documentation:
+/**
+ * Build a card component
+ *
+ * @example
+ * ```typescript
+ * // Basic card
+ * card('<p>Content</p>', { title: 'My Card' });
+ *
+ * // Elevated card with footer
+ * card('<p>Content</p>', {
+ *   variant: 'elevated',
+ *   title: 'Card Title',
+ *   footer: '<button>Action</button>'
+ * });
+ * ```
+ */
 export function card(content: string, options: CardOptions = {}): string {
libs/ui/src/components/alert.ts (2)

66-97: Add JSDoc examples for component functions.

The coding guidelines require adding @example tags showing basic usage and options patterns for all components. Consider adding examples to the JSDoc for alert(), toast(), and toastContainer() functions.

As per coding guidelines: "Add JSDoc examples with @example tags showing basic usage and options patterns for all components" applies to libs/ui/src/components/**/*.ts.

Example JSDoc pattern:
 /**
  * Build an alert component
+ *
+ * @example
+ * ```ts
+ * alert('Operation successful', { variant: 'success', dismissible: true })
+ * ```
+ *
+ * @example
+ * ```ts
+ * alert('Warning message', {
+ *   variant: 'warning',
+ *   title: 'Important',
+ *   showIcon: true
+ * })
+ * ```
  */
 export function alert(message: string, options: AlertOptions = {}): string {

Also applies to: 98-141, 186-243


37-37: Document escaping expectations for actions parameter.

The actions parameter accepts HTML strings that are inserted directly without escaping (line 126). Consider documenting that this parameter should contain pre-escaped HTML or HTML generated by trusted component functions to prevent XSS vulnerabilities.

Example documentation:
   /** Alert ID */
   id?: string;
-  /** Actions (buttons) */
+  /** Actions (buttons). Should contain pre-escaped HTML or HTML from trusted component functions. */
   actions?: string;
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f895756 and 2329ba5.

📒 Files selected for processing (36)
  • libs/sdk/src/auth/ui/__tests__/base-layout.test.ts (0 hunks)
  • libs/sdk/src/auth/ui/__tests__/htmx-templates.test.ts (0 hunks)
  • libs/sdk/src/auth/ui/base-layout.ts (0 hunks)
  • libs/sdk/src/auth/ui/index.ts (2 hunks)
  • libs/sdk/src/auth/ui/templates.ts (4 hunks)
  • libs/ui/src/components/alert.schema.ts (0 hunks)
  • libs/ui/src/components/alert.test.ts (0 hunks)
  • libs/ui/src/components/alert.ts (2 hunks)
  • libs/ui/src/components/badge.schema.ts (1 hunks)
  • libs/ui/src/components/badge.test.ts (0 hunks)
  • libs/ui/src/components/badge.ts (1 hunks)
  • libs/ui/src/components/button.schema.ts (1 hunks)
  • libs/ui/src/components/button.test.ts (0 hunks)
  • libs/ui/src/components/button.ts (1 hunks)
  • libs/ui/src/components/card.schema.ts (1 hunks)
  • libs/ui/src/components/card.test.ts (0 hunks)
  • libs/ui/src/components/card.ts (1 hunks)
  • libs/ui/src/components/form.schema.ts (0 hunks)
  • libs/ui/src/components/form.test.ts (0 hunks)
  • libs/ui/src/components/form.ts (1 hunks)
  • libs/ui/src/components/index.ts (0 hunks)
  • libs/ui/src/components/list.schema.ts (1 hunks)
  • libs/ui/src/components/list.test.ts (0 hunks)
  • libs/ui/src/components/list.ts (1 hunks)
  • libs/ui/src/components/modal.schema.ts (1 hunks)
  • libs/ui/src/components/modal.ts (4 hunks)
  • libs/ui/src/components/table.schema.ts (1 hunks)
  • libs/ui/src/components/table.ts (8 hunks)
  • libs/ui/src/web-components/core/attribute-parser.test.ts (0 hunks)
  • libs/ui/src/web-components/core/attribute-parser.ts (3 hunks)
  • libs/ui/src/web-components/core/base-element.test.ts (1 hunks)
  • libs/ui/src/web-components/core/base-element.ts (0 hunks)
  • libs/ui/src/web-components/elements/fmcp-button.ts (0 hunks)
  • libs/ui/src/web-components/elements/fmcp-input.ts (0 hunks)
  • libs/ui/src/web-components/elements/fmcp-select.ts (0 hunks)
  • libs/ui/src/widgets/resource.ts (1 hunks)
💤 Files with no reviewable changes (17)
  • libs/ui/src/components/alert.test.ts
  • libs/ui/src/components/button.test.ts
  • libs/ui/src/web-components/core/base-element.ts
  • libs/ui/src/components/alert.schema.ts
  • libs/ui/src/components/list.test.ts
  • libs/ui/src/components/card.test.ts
  • libs/ui/src/web-components/core/attribute-parser.test.ts
  • libs/ui/src/components/index.ts
  • libs/ui/src/components/form.test.ts
  • libs/ui/src/components/form.schema.ts
  • libs/ui/src/components/badge.test.ts
  • libs/ui/src/web-components/elements/fmcp-select.ts
  • libs/sdk/src/auth/ui/tests/htmx-templates.test.ts
  • libs/ui/src/web-components/elements/fmcp-input.ts
  • libs/ui/src/web-components/elements/fmcp-button.ts
  • libs/sdk/src/auth/ui/tests/base-layout.test.ts
  • libs/sdk/src/auth/ui/base-layout.ts
🧰 Additional context used
📓 Path-based instructions (9)
libs/ui/src/components/**/*.schema.ts

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

libs/ui/src/components/**/*.schema.ts: Every component must have a Zod schema with .strict() mode to reject unknown properties
Use consistent enum naming for variants ('primary', 'secondary', 'outline', 'ghost', 'danger', 'success') and sizes ('xs', 'sm', 'md', 'lg', 'xl')
Use HTMX schema with strict mode including get, post, put, delete, target, swap, and trigger properties

Files:

  • libs/ui/src/components/card.schema.ts
  • libs/ui/src/components/badge.schema.ts
  • libs/ui/src/components/list.schema.ts
  • libs/ui/src/components/table.schema.ts
  • libs/ui/src/components/button.schema.ts
  • libs/ui/src/components/modal.schema.ts
libs/ui/src/components/**/*.ts

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

libs/ui/src/components/**/*.ts: Validate component options using validateOptions() helper and return error box on validation failure
Add JSDoc examples with @example tags showing basic usage and options patterns for all components
Use pure HTML string generation without React/Vue/JSX - components return HTML strings only

Files:

  • libs/ui/src/components/card.schema.ts
  • libs/ui/src/components/list.ts
  • libs/ui/src/components/badge.schema.ts
  • libs/ui/src/components/card.ts
  • libs/ui/src/components/list.schema.ts
  • libs/ui/src/components/table.schema.ts
  • libs/ui/src/components/button.schema.ts
  • libs/ui/src/components/modal.schema.ts
  • libs/ui/src/components/alert.ts
  • libs/ui/src/components/table.ts
  • libs/ui/src/components/modal.ts
  • libs/ui/src/components/badge.ts
  • libs/ui/src/components/form.ts
  • libs/ui/src/components/button.ts
libs/ui/src/**/*.ts

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

libs/ui/src/**/*.ts: Always use escapeHtml() utility for all user-provided content to prevent XSS vulnerabilities
Hard-code CDN URLs only in theme presets; always reference theme.cdn configuration in component code

Files:

  • libs/ui/src/components/card.schema.ts
  • libs/ui/src/components/list.ts
  • libs/ui/src/components/badge.schema.ts
  • libs/ui/src/web-components/core/attribute-parser.ts
  • libs/ui/src/components/card.ts
  • libs/ui/src/widgets/resource.ts
  • libs/ui/src/components/list.schema.ts
  • libs/ui/src/components/table.schema.ts
  • libs/ui/src/components/button.schema.ts
  • libs/ui/src/components/modal.schema.ts
  • libs/ui/src/components/alert.ts
  • libs/ui/src/components/table.ts
  • libs/ui/src/components/modal.ts
  • libs/ui/src/components/badge.ts
  • libs/ui/src/components/form.ts
  • libs/ui/src/components/button.ts
  • libs/ui/src/web-components/core/base-element.test.ts
libs/ui/src/components/**

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

Organize components into schema.ts (definitions) and implementation .ts files with matching names

Files:

  • libs/ui/src/components/card.schema.ts
  • libs/ui/src/components/list.ts
  • libs/ui/src/components/badge.schema.ts
  • libs/ui/src/components/card.ts
  • libs/ui/src/components/list.schema.ts
  • libs/ui/src/components/table.schema.ts
  • libs/ui/src/components/button.schema.ts
  • libs/ui/src/components/modal.schema.ts
  • libs/ui/src/components/alert.ts
  • libs/ui/src/components/table.ts
  • libs/ui/src/components/modal.ts
  • libs/ui/src/components/badge.ts
  • libs/ui/src/components/form.ts
  • libs/ui/src/components/button.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Enable strict TypeScript mode with no any types without strong justification - use unknown instead for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific errors instead
Use specific error classes with MCP error codes instead of generic errors
Use type parameters with constraints instead of unconstrained generics, and prefer unknown over any for generic type defaults
Follow the preset pattern for hierarchical configurations across the codebase

Files:

  • libs/ui/src/components/card.schema.ts
  • libs/ui/src/components/list.ts
  • libs/ui/src/components/badge.schema.ts
  • libs/sdk/src/auth/ui/templates.ts
  • libs/ui/src/web-components/core/attribute-parser.ts
  • libs/ui/src/components/card.ts
  • libs/ui/src/widgets/resource.ts
  • libs/ui/src/components/list.schema.ts
  • libs/ui/src/components/table.schema.ts
  • libs/ui/src/components/button.schema.ts
  • libs/sdk/src/auth/ui/index.ts
  • libs/ui/src/components/modal.schema.ts
  • libs/ui/src/components/alert.ts
  • libs/ui/src/components/table.ts
  • libs/ui/src/components/modal.ts
  • libs/ui/src/components/badge.ts
  • libs/ui/src/components/form.ts
  • libs/ui/src/components/button.ts
  • libs/ui/src/web-components/core/base-element.test.ts
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/ui/src/components/card.schema.ts
  • libs/ui/src/components/list.ts
  • libs/ui/src/components/badge.schema.ts
  • libs/sdk/src/auth/ui/templates.ts
  • libs/ui/src/web-components/core/attribute-parser.ts
  • libs/ui/src/components/card.ts
  • libs/ui/src/widgets/resource.ts
  • libs/ui/src/components/list.schema.ts
  • libs/ui/src/components/table.schema.ts
  • libs/ui/src/components/button.schema.ts
  • libs/sdk/src/auth/ui/index.ts
  • libs/ui/src/components/modal.schema.ts
  • libs/ui/src/components/alert.ts
  • libs/ui/src/components/table.ts
  • libs/ui/src/components/modal.ts
  • libs/ui/src/components/badge.ts
  • libs/ui/src/components/form.ts
  • libs/ui/src/components/button.ts
  • libs/ui/src/web-components/core/base-element.test.ts
libs/{sdk,adapters,plugins,cli}/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

libs/{sdk,adapters,plugins,cli}/src/**/*.ts: Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of unknown for execute() and read() methods
Validate URIs per RFC 3986 at metadata level using Zod validation with custom refinements
Use getCapabilities() for dynamic capability exposure instead of hardcoding capabilities in adapters
Use changeScope instead of scope for change event properties to avoid confusion with the Scope class
Validate hooks match their entry type and fail fast with InvalidHookFlowError for unsupported flows
Don't mutate rawInput in flows - use state.set() for managing flow state instead

Files:

  • libs/sdk/src/auth/ui/templates.ts
  • libs/sdk/src/auth/ui/index.ts
libs/ui/src/**/*.test.ts

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

libs/ui/src/**/*.test.ts: Maintain 95%+ test coverage across statements, branches, functions, and lines
Test HTML escaping for user-provided content to prevent XSS attacks
Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable

Files:

  • libs/ui/src/web-components/core/base-element.test.ts
**/*.test.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.ts: Achieve and maintain 95%+ test coverage across all metrics (statements, branches, functions, lines)
Test all code paths including errors, constructor validation, and error class instanceof checks

Files:

  • libs/ui/src/web-components/core/base-element.test.ts
🧠 Learnings (15)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.ts : Use pure HTML string generation without React/Vue/JSX - components return HTML strings only
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test HTML escaping for user-provided content to prevent XSS attacks
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.schema.ts : Use HTMX schema with strict mode including get, post, put, delete, target, swap, and trigger properties

Applied to files:

  • libs/ui/src/components/card.schema.ts
  • libs/ui/src/components/list.ts
  • libs/ui/src/components/badge.schema.ts
  • libs/sdk/src/auth/ui/templates.ts
  • libs/ui/src/web-components/core/attribute-parser.ts
  • libs/ui/src/components/card.ts
  • libs/ui/src/widgets/resource.ts
  • libs/ui/src/components/list.schema.ts
  • libs/ui/src/components/table.schema.ts
  • libs/ui/src/components/button.schema.ts
  • libs/sdk/src/auth/ui/index.ts
  • libs/ui/src/components/modal.schema.ts
  • libs/ui/src/components/alert.ts
  • libs/ui/src/components/table.ts
  • libs/ui/src/components/modal.ts
  • libs/ui/src/components/badge.ts
  • libs/ui/src/components/form.ts
  • libs/ui/src/components/button.ts
  • libs/ui/src/web-components/core/base-element.test.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/** : Organize components into schema.ts (definitions) and implementation .ts files with matching names

Applied to files:

  • libs/ui/src/components/card.schema.ts
  • libs/ui/src/components/list.schema.ts
  • libs/ui/src/components/table.schema.ts
  • libs/ui/src/components/button.schema.ts
  • libs/ui/src/components/modal.schema.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.schema.ts : Use consistent enum naming for variants ('primary', 'secondary', 'outline', 'ghost', 'danger', 'success') and sizes ('xs', 'sm', 'md', 'lg', 'xl')

Applied to files:

  • libs/ui/src/components/card.schema.ts
  • libs/ui/src/components/badge.schema.ts
  • libs/ui/src/components/list.schema.ts
  • libs/ui/src/components/table.schema.ts
  • libs/ui/src/components/button.schema.ts
  • libs/ui/src/components/modal.schema.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.schema.ts : Every component must have a Zod schema with `.strict()` mode to reject unknown properties

Applied to files:

  • libs/ui/src/components/card.schema.ts
  • libs/ui/src/components/badge.schema.ts
  • libs/ui/src/components/list.schema.ts
  • libs/ui/src/components/table.schema.ts
  • libs/ui/src/components/button.schema.ts
  • libs/ui/src/components/modal.schema.ts
  • libs/ui/src/web-components/core/base-element.test.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.ts : Use pure HTML string generation without React/Vue/JSX - components return HTML strings only

Applied to files:

  • libs/ui/src/components/card.schema.ts
  • libs/ui/src/components/list.ts
  • libs/sdk/src/auth/ui/templates.ts
  • libs/ui/src/components/card.ts
  • libs/ui/src/components/form.ts
  • libs/ui/src/components/button.ts
  • libs/ui/src/web-components/core/base-element.test.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Use Zod schema validation for all component inputs as a core validation strategy

Applied to files:

  • libs/ui/src/components/card.schema.ts
  • libs/ui/src/components/badge.schema.ts
  • libs/ui/src/components/list.schema.ts
  • libs/ui/src/components/table.schema.ts
  • libs/ui/src/components/button.schema.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.test.ts : Write validation tests covering invalid variant/options, unknown properties, and valid option acceptance

Applied to files:

  • libs/ui/src/components/card.schema.ts
  • libs/ui/src/components/badge.schema.ts
  • libs/ui/src/components/list.schema.ts
  • libs/ui/src/components/table.schema.ts
  • libs/ui/src/components/button.schema.ts
  • libs/ui/src/components/form.ts
  • libs/ui/src/web-components/core/base-element.test.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.ts : Validate component options using `validateOptions()` helper and return error box on validation failure

Applied to files:

  • libs/ui/src/components/card.schema.ts
  • libs/ui/src/components/badge.schema.ts
  • libs/ui/src/components/list.schema.ts
  • libs/ui/src/components/table.schema.ts
  • libs/ui/src/components/button.schema.ts
  • libs/ui/src/components/alert.ts
  • libs/ui/src/components/form.ts
  • libs/ui/src/web-components/core/base-element.test.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Use FrontMCP's TypeScript-first schema validation framework philosophy - all types should align with MCP protocol definitions

Applied to files:

  • libs/ui/src/components/card.schema.ts
  • libs/ui/src/components/table.schema.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Validate URIs per RFC 3986 at metadata level using Zod validation with custom refinements

Applied to files:

  • libs/ui/src/components/card.schema.ts
  • libs/ui/src/components/badge.schema.ts
  • libs/ui/src/components/list.schema.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/*/src/index.ts : Use barrel exports (index.ts) to export all public API surface without legacy exports or aliases

Applied to files:

  • libs/sdk/src/auth/ui/index.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.ts : Hard-code CDN URLs only in theme presets; always reference theme.cdn configuration in component code

Applied to files:

  • libs/sdk/src/auth/ui/index.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test HTML escaping for user-provided content to prevent XSS attacks

Applied to files:

  • libs/ui/src/web-components/core/base-element.test.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable

Applied to files:

  • libs/ui/src/web-components/core/base-element.test.ts
🧬 Code graph analysis (2)
libs/ui/src/components/card.ts (2)
libs/sdk/src/auth/ui/templates.ts (1)
  • escapeHtml (87-87)
libs/sdk/src/auth/ui/base-layout.ts (1)
  • escapeHtml (165-173)
libs/ui/src/components/modal.ts (2)
libs/sdk/src/auth/ui/templates.ts (1)
  • escapeHtml (87-87)
libs/sdk/src/auth/ui/base-layout.ts (1)
  • escapeHtml (165-173)
⏰ 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: Build Libraries
  • GitHub Check: Lint & Format Checks
🔇 Additional comments (27)
libs/ui/src/components/form.ts (1)

585-601: LGTM! Clean removal of HTMX support from the form wrapper.

The destructuring at line 586 correctly excludes HTMX-related options, and the attribute construction (lines 588-598) appropriately omits HTMX attributes. This is consistent with the broader PR objective of removing HTMX integrations across UI components.

libs/ui/src/components/badge.schema.ts (2)

46-46: Size enums are appropriate for badge component.

The size enum ('sm' | 'md' | 'lg') is reasonable for badges. While the coding guidelines suggest 'xs' | 'sm' | 'md' | 'lg' | 'xl', the narrower range makes sense given badge dimensions.

Based on coding guidelines.


60-77: HTMX removal aligns with PR objectives; schema properly configured.

The removal of the onRemove field and BadgeOnRemoveSchema successfully eliminates HTMX-specific configuration from the badge component, consistent with the broader shift described in the PR summary. The schema correctly applies .strict() mode to reject unknown properties.

Based on coding guidelines and PR objectives.

libs/ui/src/components/badge.ts (1)

134-145: Inline onclick handler is a pragmatic replacement for HTMX.

The shift from HTMX attributes to a simple inline onclick="this.parentElement.remove()" handler successfully eliminates the HTMX dependency while maintaining removable badge functionality. The approach is straightforward and appropriate for this use case.

libs/ui/src/web-components/core/base-element.test.ts (1)

171-171: LGTM: Consistent with HTMX removal.

The simplified HTML rendering without HTMX attributes aligns with the broader refactoring to remove HTMX functionality across the codebase.

libs/ui/src/web-components/core/attribute-parser.ts (2)

6-6: LGTM: Documentation accurately reflects HTMX removal.

The updated comments correctly remove references to HTMX functionality, focusing on the remaining attribute handling capabilities (boolean attributes, data attributes, kebab-to-camel conversion).

Also applies to: 153-153


166-174: LGTM: Simplified logic after HTMX removal.

The condition now only checks for data attributes, which is correct after removing HTMX-specific handling. The logic properly nests data attributes under the data key while assigning other attributes directly.

libs/ui/src/components/card.schema.ts (1)

51-76: LGTM! Schema correctly uses .strict() mode.

The CardOptionsSchema properly enforces strict validation to reject unknown properties, aligning with coding guidelines. The HTMX field removal is clean.

libs/ui/src/components/card.ts (1)

134-145: LGTM! HTMX attributes cleanly removed.

The anchor and div rendering paths now correctly exclude HTMX attributes. All user-provided content (href, id, data values, title, subtitle) is properly escaped with escapeHtml().

libs/ui/src/components/table.ts (3)

109-142: LGTM! Header rendering cleanly updated.

HTMX attributes removed from sortable headers. The sort indicator rendering with buildSortIndicator() provides a clean visual indication of sort state. Header text is properly escaped.


155-160: LGTM! Body rendering simplified.

Destructuring cleanly removes HTMX-related fields. Row selection checkbox no longer emits HTMX attributes, aligning with the broader migration away from HTMX.


293-295: New baseUrl property added to PaginationOptions.

This is a public API addition. Ensure documentation is updated to reflect this new option for URL-based pagination.

libs/ui/src/components/table.schema.ts (1)

42-63: Using z.any() for render function is acceptable.

The comment correctly documents that function validation isn't possible at runtime with Zod. Consider using z.function() if Zod 4's function schema improvements apply, though z.any() is pragmatic here.

libs/ui/src/components/list.schema.ts (2)

170-185: LGTM! ActionItemSchema cleanly updated.

HTMX field removed while maintaining .strict() mode. The schema continues to properly validate action item properties.


1-207: All schemas correctly use .strict() mode.

All list-related schemas (PermissionItemSchema, FeatureItemSchema, DescriptionItemSchema, ActionItemSchema, and their options schemas) properly enforce strict validation per coding guidelines.

libs/ui/src/components/button.schema.ts (1)

1-123: LGTM! Clean HTMX removal with proper schema structure.

The ButtonOptionsSchema correctly follows coding guidelines with .strict() mode and consistent enum naming conventions. The removal of HTMX-related fields is complete and well-documented.

Based on coding guidelines: "Every component must have a Zod schema with .strict() mode to reject unknown properties" and "Use consistent enum naming for variants ('primary', 'secondary', 'outline', 'ghost', 'danger', 'success') and sizes ('xs', 'sm', 'md', 'lg', 'xl')."

libs/ui/src/components/list.ts (2)

368-381: LGTM! ActionItem interface correctly simplified.

The removal of the htmx property from ActionItem is clean and aligns with the broader HTMX removal effort across the codebase.


386-428: LGTM! Clean HTML rendering without HTMX.

The actionList function now renders pure HTML without HTMX attributes, correctly using escapeHtml for user-provided content to prevent XSS vulnerabilities.

Based on learnings: "Use pure HTML string generation without React/Vue/JSX - components return HTML strings only."

libs/ui/src/components/button.ts (1)

179-293: LGTM! Excellent security implementation.

The button function correctly:

  • Validates options using Zod schema
  • Validates href protocols with allowlist approach (lines 138-149, 224-227)
  • Escapes all user-provided content
  • Sanitizes data attribute keys
  • Removes all HTMX integration cleanly

The security considerations in the JSDoc are thorough and accurate.

libs/ui/src/components/modal.schema.ts (3)

44-65: Breaking change: onClose field removal is complete.

The removal of the onClose field from ModalOptionsSchema has been fully implemented across the codebase with no remaining references to onClose or the ModalOnClose type. The ModalOptions interface matches the schema with .strict() mode enabled, confirming all consumer code has been updated.


89-113: No migration needed: onConfirm field does not exist in the codebase.

Search results show zero references to onConfirm or ConfirmModalOnConfirm type across the entire repository. The schema currently uses confirmHref for URL-based confirm actions, which is correctly implemented in the modal component. However, the ConfirmModalOptionsSchema lacks HTMX properties specified in coding guidelines—add target, swap, and trigger properties to align with the HTMX schema pattern (get, post, put, delete, target, swap, trigger).

Likely an incorrect or invalid review comment.


132-156: The onClose removal is not substantiated as a breaking change.

The codebase search found no references to onClose in drawer-related code. This indicates one of two scenarios:

  1. onClose was never part of DrawerOptionsSchema – In which case the review comment conflates a non-existent field with a breaking change
  2. onClose was removed and cleanly refactored – In which case there are no dangling references to verify, and the concern is already handled

The review comment claims implementations "may still reference" onClose, but the search shows no evidence of this. Without proof of actual breaking impact (failed tests, orphaned implementations, or migration requirements), the major issue classification is premature.

Secondary concern: Verify footer HTML escaping is enforced at implementation level. The schema accepts footer: z.string().optional() but does not document that HTML content must use escaping. Per coding guidelines, implementations should validate and escape user-provided HTML content to prevent XSS.

Likely an incorrect or invalid review comment.

libs/sdk/src/auth/ui/index.ts (2)

4-5: LGTM! Documentation accurately reflects Tailwind-only approach.

The updated documentation correctly describes the module as using "Tailwind CSS (CDN)" and removes HTMX references, aligning with the broader migration away from HTMX.


42-42: No breaking changes detected in the export path refactor.

The migration from './htmx-templates' to './templates' is confirmed as complete with no remaining imports from the old path. The change is transparent to external consumers since the public API surface exported from the barrel file remains unchanged—only the internal source path has been reorganized as part of the HTMX removal refactor. No documentation updates are required.

libs/sdk/src/auth/ui/templates.ts (3)

2-15: LGTM! Documentation accurately reflects the Tailwind-only approach.

The header and features list have been correctly updated to remove HTMX references and emphasize Tailwind CSS with CDN usage. This aligns with the broader migration away from HTMX across the codebase.


185-249: LGTM! Incremental auth page correctly updated for Tailwind-only approach.

The incremental authorization page has been properly updated to remove HTMX references from comments. The form uses standard GET submission (line 227) with proper button semantics.


560-566: LGTM! Legacy compatibility wrapper appropriately documented.

The renderToHtml function documentation correctly notes that templates are already complete HTML documents, clarifying its purpose as a compatibility wrapper.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

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

⚠️ Outside diff range comments (5)
apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts (5)

353-367: Add missing assertions for Unknown platform behavior.

This test should verify that UI is not rendered for unknown clients and optionally validate the JSON response structure, consistent with other Unknown platform tests.

🔎 Apply this diff to add missing assertions:
     const result = await client.tools.call('html-card', {
       title: 'Test',
       content: 'Content',
     });

     expect(result).toBeSuccessful();
+    expect(result.hasToolUI()).toBe(false);

     await client.disconnect();

369-389: Add missing assertions for Unknown platform behavior.

This test should verify that UI is not rendered for unknown clients, consistent with the platform's JSON-only expectations and other Unknown platform tests.

🔎 Apply this diff to add missing assertions:
     results.forEach((result) => {
       expect(result).toBeSuccessful();
+      expect(result.hasToolUI()).toBe(false);
     });

     await client.disconnect();

458-476: Add missing UI presence verification for ChatGPT versions.

This test should verify that UI rendering works consistently across different ChatGPT versions, not just that calls succeed.

🔎 Apply this diff to add missing assertions:
       const result = await client.tools.call('html-card', {
         title: `Version ${version}`,
         content: 'Test',
       });

       expect(result).toBeSuccessful();
+      expect(result.hasToolUI()).toBe(true);

       await client.disconnect();

478-492: Add missing UI presence verification for Cursor pre-release version.

This test should verify UI rendering for Cursor platform, consistent with other Cursor platform tests.

🔎 Apply this diff to add missing assertions:
       const result = await client.tools.call('html-table', {
         headers: ['A'],
         rows: [['1']],
       });

       expect(result).toBeSuccessful();
+      expect(result.hasToolUI()).toBe(true);

       await client.disconnect();

532-548: Add platform-specific behavior verification for rapid client test.

The test creates unknown clients (RapidClient${i}) but doesn't verify the expected JSON-only behavior. Add assertions consistent with Unknown platform expectations.

🔎 Apply this diff to add missing assertions:
       const result = await client.tools.call('html-card', {
         title: `Rapid ${i}`,
         content: 'Content',
       });

       expect(result).toBeSuccessful();
+      expect(result.hasToolUI()).toBe(false);

       await client.disconnect();
♻️ Duplicate comments (4)
libs/sdk/src/tool/flows/call-tool.flow.ts (1)

585-589: Unsafe cast of structuredContent bypasses validation.

This concern was raised in a previous review. The code casts uiResult.structuredContent to Record<string, unknown> without validation. If rawOutput is a primitive (string, number, null) or an array, the MCP protocol may reject it since structuredContent expects an object type. The buildToolResponseContent function passes rawOutput directly to structuredContent without enforcing object shape.

Consider adding a runtime check before assignment:

Suggested fix
     // Set structuredContent from UI result (contains raw tool output)
-    // Cast to Record<string, unknown> since MCP protocol expects object type
-    if (uiResult.structuredContent !== undefined && uiResult.structuredContent !== null) {
-      result.structuredContent = uiResult.structuredContent as Record<string, unknown>;
+    // MCP protocol expects structuredContent to be an object type
+    if (
+      uiResult.structuredContent !== undefined &&
+      uiResult.structuredContent !== null &&
+      typeof uiResult.structuredContent === 'object' &&
+      !Array.isArray(uiResult.structuredContent)
+    ) {
+      result.structuredContent = uiResult.structuredContent as Record<string, unknown>;
     }
libs/ui/src/index.ts (3)

373-374: Export aliases still violate coding guidelines (duplicate issue).

The export aliases using as at lines 373-374 remain unaddressed from the previous review. These violate the coding guideline: "Use barrel exports (index.ts) to export all public API surface without legacy exports or aliases."

The previous review comment recommended:

  • Rename exports at their source in ./universal/index.ts to useUniversalToolOutput and useUniversalToolInput
  • Remove the aliases from this barrel export

Please address this issue as previously requested.

As per coding guidelines.


452-452: Export alias still violates coding guidelines (duplicate issue).

The export alias using as at line 452 remains unaddressed from the previous review. This violates the coding guideline: "Use barrel exports (index.ts) to export all public API surface without legacy exports or aliases."

The previous review comment recommended:

  • Rename the export at its source in ./typings/index.ts to DEFAULT_TYPE_CACHE_OPTIONS
  • Remove the alias from this barrel export

Please address this issue as previously requested.

As per coding guidelines.


66-66: Remove export aliases from barrel exports.

The following export aliases violate the guideline to export all public API surface without legacy exports or aliases:

  • Line 373: useToolOutput as useUniversalToolOutput
  • Line 374: useToolInput as useUniversalToolInput
  • Line 452: DEFAULT_CACHE_OPTIONS as DEFAULT_TYPE_CACHE_OPTIONS

Either remove these aliases and use the original names, or re-export them from the source modules directly rather than aliasing at the barrel export level.

🧹 Nitpick comments (19)
apps/e2e/demo-e2e-ui/e2e/openai-resource-flow.e2e.test.ts (2)

22-38: Consider using test fixtures or beforeEach/afterEach for client lifecycle management.

The client creation and disconnection pattern is repeated in every test (~20 times). If an assertion fails before client.disconnect(), the client connection may leak. Using Playwright's fixture pattern or hooks would ensure proper cleanup and reduce duplication.

🔎 Suggested approach using beforeEach/afterEach:
test.describe('Tools List Metadata', () => {
  let client: McpTestClient;

  test.beforeEach(async ({ server }) => {
    client = await server.createClient({
      transport: 'streamable-http',
      clientInfo: { name: 'ChatGPT', version: '1.0.0' },
    });
  });

  test.afterEach(async () => {
    await client.disconnect();
  });

  test('should include openai/outputTemplate for static mode tools', async () => {
    const tools = await client.tools.list();
    const staticTool = tools.find((t) => t.name === 'static-badge');

    expect(staticTool).toBeDefined();
    expect(staticTool?._meta?.['openai/outputTemplate']).toBeDefined();
    expect(staticTool?._meta?.['openai/outputTemplate']).toMatch(/^ui:\/\/widget\/.*\.html$/);
    expect(staticTool?._meta?.['openai/resultCanProduceWidget']).toBe(true);
  });
  // ... other tests
});

Alternatively, if the testing framework supports custom fixtures, you could define a reusable openaiClient fixture that handles lifecycle automatically.


250-258: Avoid unchecked type assertion; validate or use type guard.

Using as string bypasses TypeScript's type safety. If _meta['openai/html'] is not a string at runtime, subsequent operations could fail with confusing errors.

🔎 Suggested safer approach:
       expect(result).toBeSuccessful();
-      const html = result.raw._meta?.['openai/html'] as string;
-      expect(html).toBeDefined();
+      const html = result.raw._meta?.['openai/html'];
+      expect(html).toBeDefined();
+      expect(typeof html).toBe('string');
       expect(html).toContain('<!DOCTYPE html>');
       expect(html).toContain('HTML Validation'); // Title should be in HTML

This validates the type at runtime and provides a clearer error message if the assumption is violated.

apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts (3)

393-420: Consider adding platform-specific UI assertions.

While this test correctly verifies data structure consistency, it should also verify that UI-supporting platforms (ChatGPT, Claude Desktop, Cursor) return UI while Unknown platforms don't. This would make the test more comprehensive and align with the test suite's focus on platform detection.

🔎 View suggested enhancement:
     for (const platform of platforms) {
       const client = await server.createClient({
         transport: 'streamable-http',
         clientInfo: platform,
       });

       const result = await client.tools.call('html-table', {
         headers: ['Name', 'Value'],
         rows: [['Test', '123']],
         title: `${platform.name} Test`,
       });

       expect(result).toBeSuccessful();
       const json = result.json<{ rowCount: number; columnCount: number }>();
       expect(json.rowCount).toBe(1);
       expect(json.columnCount).toBe(2);
+
+      // Verify platform-specific UI behavior
+      if (platform.name === 'Unknown') {
+        expect(result.hasToolUI()).toBe(false);
+      } else {
+        expect(result.hasToolUI()).toBe(true);
+      }

       await client.disconnect();
     }

422-454: Add UI presence verification for concurrent cross-platform calls.

This test verifies data integrity but should also confirm UI rendering behavior for each platform, consistent with the test suite's platform detection focus.

🔎 View suggested enhancement:
     results.forEach((result, i) => {
       expect(result).toBeSuccessful();
+      expect(result.hasToolUI()).toBe(true);
       const json = result.json<{ maxValue: number }>();
       expect(json.maxValue).toBe((i + 1) * 100);
     });

14-550: Consider adding error scenario tests to meet 95%+ coverage requirement.

The current test suite comprehensively covers happy paths but lacks error scenario testing. According to coding guidelines, tests should cover all code paths including errors.

Consider adding test cases for:

  • Invalid or malformed clientInfo (missing name/version)
  • Tool call failures or invalid parameters
  • Network/transport errors during tool calls
  • Session timeout or disconnection errors
  • Invalid platform combinations

As per coding guidelines, test files should maintain 95%+ coverage across all metrics including error paths.

apps/e2e/demo-e2e-transparent/e2e/transparent-auth.e2e.test.ts (1)

111-128: Consider wrapping disconnect in try-finally for robustness.

If assertions fail before client.disconnect(), the client connection may leak. While this is test code and not critical, using try-finally ensures cleanup even on test failures.

🔎 Suggested pattern for all tests using McpTestClient:
     it('should accept valid tokens and connect successfully', async () => {
       const token = await tokenFactory.createTestToken({
         sub: 'user-123',
         scopes: ['read', 'write'],
       });

       // Use McpTestClient for clean connection
       const client = await McpTestClient.create({
         baseUrl: server.info.baseUrl,
         transport: 'streamable-http',
         auth: { token },
       }).buildAndConnect();

+      try {
         expect(client.isConnected()).toBe(true);
         expect(client.serverInfo.name).toBeDefined();
+      } finally {
         await client.disconnect();
+      }
     });
libs/testing/src/client/mcp-test-client.types.ts (1)

83-116: Duplicate type definitions with platform-client-info.ts.

The interfaces McpAppsExtension, ExperimentalCapabilities, TestClientCapabilities, and constant MCP_APPS_EXTENSION_KEY are defined both here and in libs/testing/src/platform/platform-client-info.ts. This creates maintenance overhead and potential for drift.

Consider consolidating these definitions in one location and re-exporting from the other.

🔎 Suggested approach:

Define the types in platform-client-info.ts (where they're used with platform logic) and re-export from mcp-test-client.types.ts:

// In mcp-test-client.types.ts
export {
  MCP_APPS_EXTENSION_KEY,
  McpAppsExtension,
  ExperimentalCapabilities,
  TestClientCapabilities,
} from '../platform/platform-client-info';
libs/testing/src/platform/platform-client-info.ts (1)

26-35: Duplicate TestClientInfo interface definition.

TestClientInfo is defined here as a local interface, but ClientInfo is also defined as a type alias in mcp-test-client.types.ts. While ClientInfo includes more fields (from Implementation), having two similar types could cause confusion.

Consider:

  • Using ClientInfo from mcp-test-client.types.ts with Pick<ClientInfo, 'name' | 'version'> if only those fields are needed
  • Or keeping TestClientInfo as a minimal interface for internal platform utilities only
libs/testing/src/client/mcp-test-client.builder.ts (1)

136-143: Consider documenting the override behavior between withPlatform and withCapabilities.

When withPlatform is called, it sets both clientInfo and capabilities. If a user subsequently calls withCapabilities, only the capabilities are overwritten. This ordering dependency could lead to unexpected behavior if not clearly understood.

Consider adding a note in the JSDoc that calling withPlatform after withCapabilities will overwrite the custom capabilities:

/**
 * Note: Calling `withPlatform()` after `withCapabilities()` will overwrite
 * the custom capabilities. Use `withCapabilities()` after `withPlatform()`
 * to merge or override specific capability settings.
 */
libs/sdk/src/tool/flows/tools-list.flow.ts (2)

24-25: Consider using a proper Zod schema for authInfo instead of z.any().

Per coding guidelines, avoid any types without strong justification. While AuthInfo is an external type from @modelcontextprotocol/sdk, the z.any() cast bypasses type validation entirely.

Consider using z.unknown() with a type assertion, or create a partial Zod schema that validates the fields you actually use (like sessionId and sessionIdPayload):

🔎 Suggested approach
 const stateSchema = z.object({
   cursor: z.string().optional(),
-  authInfo: z.any().optional() as z.ZodType<AuthInfo>,
+  authInfo: z.unknown().optional() as z.ZodType<AuthInfo | undefined>,
   platformType: z.string().optional() as z.ZodType<AIPlatformType | undefined>,

276-337: Platform-aware meta key generation is comprehensive but consider extracting to a helper.

The logic correctly implements the platform-specific namespace requirements:

  • OpenAI: openai/* keys only
  • ext-apps: ui/* keys per SEP-1865
  • Others: frontmcp/* + ui/* for compatibility

However, this block is ~60 lines with nested conditionals. Consider extracting the meta key building logic into a separate helper function (e.g., buildPlatformMeta) to improve readability and testability.

apps/e2e/demo-e2e-ui/e2e/platform-meta-keys.e2e.test.ts (1)

258-281: Consider adding a Gemini platform test case.

Based on learnings, tests should cover behavior across platform configurations including OpenAI, Claude, Gemini, and ngrok where applicable. Gemini is mentioned as a platform that doesn't support widgets (supportsWidgets: false in serving-mode.ts), but there's no test validating that Gemini receives no UI meta keys.

🔎 Suggested test
test.describe('Gemini Platform (No UI Support)', () => {
  test('should NOT have any ui meta keys for Gemini', async ({ server }) => {
    const client = await server.createClient({
      transport: 'streamable-http',
      clientInfo: { name: 'gemini', version: '1.0.0' },
    });

    const result = await client.tools.call('html-card', {
      title: 'Gemini Test',
      content: 'Testing no-UI platform',
    });

    expect(result).toBeSuccessful();

    // Gemini should NOT receive any UI meta keys
    expect(result).toNotHaveMetaKey('openai/html');
    expect(result).toNotHaveMetaKey('ui/html');
    expect(result).toNotHaveMetaKey('frontmcp/html');

    await client.disconnect();
  });
});
libs/sdk/src/tool/flows/call-tool.flow.ts (1)

606-621: Synchronous file I/O and dynamic require in debug block may block the event loop.

The debug logging uses synchronous fs.writeFileSync and a dynamic require('fs'), which could block the event loop under heavy load. While this is debug-only code, consider:

  1. Using import at the top and conditionally executing
  2. Using async fs.promises.writeFile to avoid blocking

Also, the eslint-disable comment suggests this pattern is intentional, but synchronous I/O in a flow's finalize stage could cause latency spikes.

Suggested async approach
     // Debug: Write full response to file if DEBUG_TOOL_RESPONSE is set
     if (process.env['DEBUG_TOOL_RESPONSE']) {
-      // eslint-disable-next-line @typescript-eslint/no-require-imports
-      const fs = require('fs');
+      const fs = await import('fs').then(m => m.promises);
       const debugOutput = {
         timestamp: new Date().toISOString(),
         tool: tool.metadata.name,
         rawOutput,
         uiResult,
         uiMeta,
         finalResult: result,
       };
       const outputPath = process.env['DEBUG_TOOL_RESPONSE_PATH'] || '/tmp/tool-response-debug.json';
-      fs.writeFileSync(outputPath, JSON.stringify(debugOutput, null, 2));
+      await fs.writeFile(outputPath, JSON.stringify(debugOutput, null, 2));
       console.log(`[DEBUG] Tool response written to: ${outputPath}`);
     }
libs/ui/src/runtime/csp.ts (1)

14-19: Default CDN domains are always included, preventing restrictive policies.

The buildCSPDirectives function merges DEFAULT_CDN_DOMAINS with user-provided domains (line 61), meaning users cannot configure a CSP that excludes these defaults. This may be intentional for convenience, but it prevents creating truly restrictive policies via the UIContentSecurityPolicy interface.

Consider adding an option to opt out of default CDNs for security-sensitive use cases:

Example approach
export interface UIContentSecurityPolicy {
  resourceDomains?: string[];
  connectDomains?: string[];
  /** If true, don't include DEFAULT_CDN_DOMAINS */
  excludeDefaultCDNs?: boolean;
}

// In buildCSPDirectives:
const allResourceDomains = csp.excludeDefaultCDNs
  ? validResourceDomains
  : [...new Set([...DEFAULT_CDN_DOMAINS, ...validResourceDomains])];
libs/ui/src/adapters/__tests__/response-builder.test.ts (1)

203-205: Consider adding 'unknown' platform to test coverage.

The comment on line 203-204 mentions "unknown now supports widgets with ui/html + text/html+mcp", but 'unknown' is not included in nonWidgetPlatforms or the structuredContentPlatforms array. Consider adding a test case for the 'unknown' platform to verify its expected behavior, per the coding guideline to test across platform configurations.

Example test addition
it('should handle unknown platform with widget support', () => {
  const result = buildToolResponseContent(
    createOptions({
      servingMode: 'inline',
      platformType: 'unknown',
      useStructuredContent: false,
      htmlContent: '<div>Test</div>',
    }),
  );

  // Verify unknown platform behavior matches expectations
  expect(result.format).toBe('widget'); // or expected format
});
libs/ui/src/adapters/platform-meta.ts (1)

195-226: Redundant case fall-through for gemini platform.

gemini is listed explicitly in the switch (line 200) but falls through to default, which then checks if (platformType === 'gemini') again (line 219). This creates redundant evaluation. Consider either:

  1. Giving gemini its own case block, or
  2. Removing gemini from the explicit cases since it's handled identically to default
Option: Remove redundant explicit case
     case 'claude':
     case 'cursor':
     case 'continue':
     case 'cody':
     case 'generic-mcp':
-    case 'gemini':
     default:
       // Other platforms use frontmcp/* namespace
libs/testing/src/ui/ui-assertions.ts (2)

329-351: Consider adding a usage caveat to the JSDoc.

The assertNoMixedNamespaces method strictly enforces a single namespace, which may surprise users testing FrontMCP platforms that legitimately use both frontmcp/* and ui/* keys. The JSDoc mentions the expected namespace but could benefit from a note directing users to assertPlatformMeta for multi-namespace platforms.

🔎 Suggested JSDoc enhancement:
   /**
    * Assert that no cross-namespace pollution exists in meta.
    * @param result - The tool result wrapper
    * @param expectedNamespace - The namespace that SHOULD be present
    * @throws Error if other namespaces are found
+   *
+   * @note For platforms like Claude that use both frontmcp/* and ui/* keys,
+   * use `assertPlatformMeta()` instead, which handles multi-namespace platforms.
    */

367-388: Consider extracting platform-specific key mapping to reduce duplication.

The switch statements for determining mimeTypeKey and htmlKey based on platform are duplicated between this file and ui-matchers.ts (lines 493-504 and 537-548). Consider adding helper functions like getPlatformMimeTypeKey(platform) and getPlatformHtmlKey(platform) to platform-types.ts to centralize this logic.

🔎 Example helper functions for platform-types.ts:
/**
 * Get the meta key for MIME type based on platform.
 */
export function getPlatformMimeTypeKey(platform: TestPlatformType): string {
  switch (platform) {
    case 'openai':
      return 'openai/mimeType';
    case 'ext-apps':
      return 'ui/mimeType';
    default:
      return 'frontmcp/mimeType';
  }
}

/**
 * Get the meta key for HTML based on platform.
 */
export function getPlatformHtmlKey(platform: TestPlatformType): string {
  switch (platform) {
    case 'openai':
      return 'openai/html';
    case 'ext-apps':
      return 'ui/html';
    default:
      return 'frontmcp/html';
  }
}

Also applies to: 404-427

libs/testing/src/platform/platform-types.ts (1)

97-122: Optional: Consider consolidating identical prefix functions or documenting future divergence.

getToolsListMetaPrefixes and getToolCallMetaPrefixes currently have identical implementations. If they're expected to diverge in the future (e.g., different keys for list vs. call responses), consider adding a brief comment explaining this. Otherwise, they could share a private helper to reduce duplication.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2329ba5 and 1ad05e6.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (29)
  • apps/e2e/demo-e2e-openapi/e2e/openapi.e2e.test.ts (4 hunks)
  • apps/e2e/demo-e2e-transparent/e2e/transparent-auth.e2e.test.ts (8 hunks)
  • apps/e2e/demo-e2e-ui/e2e/openai-resource-flow.e2e.test.ts (1 hunks)
  • apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts (6 hunks)
  • apps/e2e/demo-e2e-ui/e2e/platform-meta-keys.e2e.test.ts (1 hunks)
  • libs/sdk/src/flows/flow.instance.ts (1 hunks)
  • libs/sdk/src/tool/flows/call-tool.flow.ts (7 hunks)
  • libs/sdk/src/tool/flows/tools-list.flow.ts (7 hunks)
  • libs/testing/src/client/mcp-test-client.builder.ts (2 hunks)
  • libs/testing/src/client/mcp-test-client.ts (6 hunks)
  • libs/testing/src/client/mcp-test-client.types.ts (3 hunks)
  • libs/testing/src/example-tools/index.ts (1 hunks)
  • libs/testing/src/example-tools/tool-configs.ts (1 hunks)
  • libs/testing/src/fixtures/fixture-types.ts (2 hunks)
  • libs/testing/src/fixtures/test-fixture.ts (6 hunks)
  • libs/testing/src/index.ts (1 hunks)
  • libs/testing/src/platform/index.ts (1 hunks)
  • libs/testing/src/platform/platform-client-info.ts (1 hunks)
  • libs/testing/src/platform/platform-types.ts (1 hunks)
  • libs/testing/src/ui/ui-assertions.ts (2 hunks)
  • libs/testing/src/ui/ui-matchers.ts (4 hunks)
  • libs/ui/src/adapters/__tests__/platform-meta.test.ts (2 hunks)
  • libs/ui/src/adapters/__tests__/response-builder.test.ts (7 hunks)
  • libs/ui/src/adapters/__tests__/serving-mode.test.ts (5 hunks)
  • libs/ui/src/adapters/platform-meta.ts (1 hunks)
  • libs/ui/src/adapters/serving-mode.ts (10 hunks)
  • libs/ui/src/index.ts (3 hunks)
  • libs/ui/src/runtime/csp.ts (2 hunks)
  • libs/ui/src/runtime/index.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • libs/ui/src/adapters/tests/serving-mode.test.ts
  • libs/testing/src/client/mcp-test-client.ts
🧰 Additional context used
📓 Path-based instructions (7)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Enable strict TypeScript mode with no any types without strong justification - use unknown instead for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific errors instead
Use specific error classes with MCP error codes instead of generic errors
Use type parameters with constraints instead of unconstrained generics, and prefer unknown over any for generic type defaults
Follow the preset pattern for hierarchical configurations across the codebase

Files:

  • apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts
  • libs/sdk/src/flows/flow.instance.ts
  • libs/ui/src/runtime/index.ts
  • libs/ui/src/adapters/serving-mode.ts
  • libs/ui/src/adapters/__tests__/platform-meta.test.ts
  • apps/e2e/demo-e2e-ui/e2e/openai-resource-flow.e2e.test.ts
  • libs/testing/src/platform/index.ts
  • apps/e2e/demo-e2e-ui/e2e/platform-meta-keys.e2e.test.ts
  • libs/testing/src/platform/platform-types.ts
  • apps/e2e/demo-e2e-openapi/e2e/openapi.e2e.test.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/testing/src/ui/ui-matchers.ts
  • libs/testing/src/client/mcp-test-client.builder.ts
  • libs/testing/src/index.ts
  • libs/testing/src/platform/platform-client-info.ts
  • libs/testing/src/ui/ui-assertions.ts
  • libs/testing/src/fixtures/fixture-types.ts
  • libs/ui/src/runtime/csp.ts
  • libs/testing/src/fixtures/test-fixture.ts
  • libs/ui/src/adapters/platform-meta.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
  • libs/testing/src/example-tools/index.ts
  • libs/sdk/src/tool/flows/tools-list.flow.ts
  • libs/testing/src/client/mcp-test-client.types.ts
  • libs/testing/src/example-tools/tool-configs.ts
  • apps/e2e/demo-e2e-transparent/e2e/transparent-auth.e2e.test.ts
  • libs/ui/src/index.ts
**/*.test.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.test.ts: Achieve and maintain 95%+ test coverage across all metrics (statements, branches, functions, lines)
Test all code paths including errors, constructor validation, and error class instanceof checks

Files:

  • apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts
  • libs/ui/src/adapters/__tests__/platform-meta.test.ts
  • apps/e2e/demo-e2e-ui/e2e/openai-resource-flow.e2e.test.ts
  • apps/e2e/demo-e2e-ui/e2e/platform-meta-keys.e2e.test.ts
  • apps/e2e/demo-e2e-openapi/e2e/openapi.e2e.test.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
  • apps/e2e/demo-e2e-transparent/e2e/transparent-auth.e2e.test.ts
libs/{sdk,adapters,plugins,cli}/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

libs/{sdk,adapters,plugins,cli}/src/**/*.ts: Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of unknown for execute() and read() methods
Validate URIs per RFC 3986 at metadata level using Zod validation with custom refinements
Use getCapabilities() for dynamic capability exposure instead of hardcoding capabilities in adapters
Use changeScope instead of scope for change event properties to avoid confusion with the Scope class
Validate hooks match their entry type and fail fast with InvalidHookFlowError for unsupported flows
Don't mutate rawInput in flows - use state.set() for managing flow state instead

Files:

  • libs/sdk/src/flows/flow.instance.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/sdk/src/tool/flows/tools-list.flow.ts
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/sdk/src/flows/flow.instance.ts
  • libs/ui/src/runtime/index.ts
  • libs/ui/src/adapters/serving-mode.ts
  • libs/ui/src/adapters/__tests__/platform-meta.test.ts
  • libs/testing/src/platform/index.ts
  • libs/testing/src/platform/platform-types.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/testing/src/ui/ui-matchers.ts
  • libs/testing/src/client/mcp-test-client.builder.ts
  • libs/testing/src/index.ts
  • libs/testing/src/platform/platform-client-info.ts
  • libs/testing/src/ui/ui-assertions.ts
  • libs/testing/src/fixtures/fixture-types.ts
  • libs/ui/src/runtime/csp.ts
  • libs/testing/src/fixtures/test-fixture.ts
  • libs/ui/src/adapters/platform-meta.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
  • libs/testing/src/example-tools/index.ts
  • libs/sdk/src/tool/flows/tools-list.flow.ts
  • libs/testing/src/client/mcp-test-client.types.ts
  • libs/testing/src/example-tools/tool-configs.ts
  • libs/ui/src/index.ts
libs/ui/src/**/*.ts

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

libs/ui/src/**/*.ts: Always use escapeHtml() utility for all user-provided content to prevent XSS vulnerabilities
Hard-code CDN URLs only in theme presets; always reference theme.cdn configuration in component code

Files:

  • libs/ui/src/runtime/index.ts
  • libs/ui/src/adapters/serving-mode.ts
  • libs/ui/src/adapters/__tests__/platform-meta.test.ts
  • libs/ui/src/runtime/csp.ts
  • libs/ui/src/adapters/platform-meta.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
  • libs/ui/src/index.ts
libs/ui/src/**/*.test.ts

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

libs/ui/src/**/*.test.ts: Maintain 95%+ test coverage across statements, branches, functions, and lines
Test HTML escaping for user-provided content to prevent XSS attacks
Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable

Files:

  • libs/ui/src/adapters/__tests__/platform-meta.test.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
libs/*/src/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use barrel exports (index.ts) to export all public API surface without legacy exports or aliases

Files:

  • libs/testing/src/index.ts
  • libs/ui/src/index.ts
🧠 Learnings (22)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Support platform-aware rendering by detecting network capabilities (open vs blocked) and script loading strategies (external vs inline)
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable

Applied to files:

  • apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts
  • libs/ui/src/adapters/serving-mode.ts
  • libs/ui/src/adapters/__tests__/platform-meta.test.ts
  • apps/e2e/demo-e2e-ui/e2e/openai-resource-flow.e2e.test.ts
  • libs/testing/src/platform/index.ts
  • apps/e2e/demo-e2e-ui/e2e/platform-meta-keys.e2e.test.ts
  • libs/testing/src/platform/platform-types.ts
  • apps/e2e/demo-e2e-openapi/e2e/openapi.e2e.test.ts
  • libs/testing/src/ui/ui-matchers.ts
  • libs/testing/src/client/mcp-test-client.builder.ts
  • libs/testing/src/index.ts
  • libs/testing/src/platform/platform-client-info.ts
  • libs/testing/src/ui/ui-assertions.ts
  • libs/testing/src/fixtures/test-fixture.ts
  • libs/ui/src/adapters/platform-meta.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
  • libs/testing/src/example-tools/index.ts
  • libs/sdk/src/tool/flows/tools-list.flow.ts
  • libs/testing/src/client/mcp-test-client.types.ts
  • libs/testing/src/example-tools/tool-configs.ts
  • apps/e2e/demo-e2e-transparent/e2e/transparent-auth.e2e.test.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Maintain 95%+ test coverage across statements, branches, functions, and lines

Applied to files:

  • apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts
  • libs/ui/src/adapters/__tests__/platform-meta.test.ts
  • apps/e2e/demo-e2e-ui/e2e/platform-meta-keys.e2e.test.ts
  • libs/testing/src/ui/ui-matchers.ts
  • libs/testing/src/ui/ui-assertions.ts
  • libs/testing/src/example-tools/tool-configs.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test HTML escaping for user-provided content to prevent XSS attacks

Applied to files:

  • apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts
  • libs/ui/src/adapters/__tests__/platform-meta.test.ts
  • apps/e2e/demo-e2e-ui/e2e/platform-meta-keys.e2e.test.ts
  • libs/testing/src/ui/ui-matchers.ts
  • libs/testing/src/ui/ui-assertions.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.test.ts : Write validation tests covering invalid variant/options, unknown properties, and valid option acceptance

Applied to files:

  • apps/e2e/demo-e2e-ui/e2e/platform-detection.e2e.test.ts
  • libs/ui/src/adapters/__tests__/platform-meta.test.ts
  • apps/e2e/demo-e2e-ui/e2e/openai-resource-flow.e2e.test.ts
  • apps/e2e/demo-e2e-ui/e2e/platform-meta-keys.e2e.test.ts
  • libs/testing/src/ui/ui-matchers.ts
  • libs/testing/src/index.ts
  • libs/testing/src/ui/ui-assertions.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
  • libs/testing/src/example-tools/tool-configs.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.ts : Hard-code CDN URLs only in theme presets; always reference theme.cdn configuration in component code

Applied to files:

  • libs/ui/src/runtime/index.ts
  • libs/ui/src/runtime/csp.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/*/src/index.ts : Use barrel exports (index.ts) to export all public API surface without legacy exports or aliases

Applied to files:

  • libs/ui/src/runtime/index.ts
  • libs/testing/src/platform/index.ts
  • libs/testing/src/index.ts
  • libs/testing/src/example-tools/index.ts
  • libs/testing/src/example-tools/tool-configs.ts
  • libs/ui/src/index.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Use `getCapabilities()` for dynamic capability exposure instead of hardcoding capabilities in adapters

Applied to files:

  • libs/ui/src/adapters/serving-mode.ts
  • libs/ui/src/adapters/__tests__/platform-meta.test.ts
  • libs/testing/src/platform/index.ts
  • libs/testing/src/platform/platform-types.ts
  • libs/testing/src/client/mcp-test-client.builder.ts
  • libs/testing/src/index.ts
  • libs/testing/src/platform/platform-client-info.ts
  • libs/ui/src/adapters/platform-meta.ts
  • libs/ui/src/adapters/__tests__/response-builder.test.ts
  • libs/testing/src/client/mcp-test-client.types.ts
  • libs/testing/src/example-tools/tool-configs.ts
  • libs/ui/src/index.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Support platform-aware rendering by detecting network capabilities (open vs blocked) and script loading strategies (external vs inline)

Applied to files:

  • libs/ui/src/adapters/serving-mode.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.ts : Use pure HTML string generation without React/Vue/JSX - components return HTML strings only

Applied to files:

  • libs/ui/src/adapters/__tests__/platform-meta.test.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/*/src/common/records/**/*.ts : Centralize record types in common/records and import from there instead of from module-specific files

Applied to files:

  • libs/testing/src/platform/index.ts
  • libs/testing/src/platform/platform-types.ts
  • libs/testing/src/example-tools/index.ts
  • libs/testing/src/example-tools/tool-configs.ts
  • libs/ui/src/index.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Use FrontMCP's TypeScript-first schema validation framework philosophy - all types should align with MCP protocol definitions

Applied to files:

  • libs/testing/src/platform/platform-types.ts
  • apps/e2e/demo-e2e-openapi/e2e/openapi.e2e.test.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/testing/src/ui/ui-matchers.ts
  • libs/testing/src/ui/ui-assertions.ts
  • libs/testing/src/fixtures/fixture-types.ts
  • libs/testing/src/fixtures/test-fixture.ts
  • libs/sdk/src/tool/flows/tools-list.flow.ts
  • libs/testing/src/client/mcp-test-client.types.ts
  • apps/e2e/demo-e2e-transparent/e2e/transparent-auth.e2e.test.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of `unknown` for `execute()` and `read()` methods

Applied to files:

  • libs/testing/src/platform/platform-types.ts
  • apps/e2e/demo-e2e-openapi/e2e/openapi.e2e.test.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/testing/src/ui/ui-matchers.ts
  • libs/testing/src/platform/platform-client-info.ts
  • libs/testing/src/ui/ui-assertions.ts
  • libs/testing/src/fixtures/fixture-types.ts
  • libs/testing/src/client/mcp-test-client.types.ts
  • apps/e2e/demo-e2e-transparent/e2e/transparent-auth.e2e.test.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Don't mutate rawInput in flows - use state.set() for managing flow state instead

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/sdk/src/tool/flows/tools-list.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.schema.ts : Every component must have a Zod schema with `.strict()` mode to reject unknown properties

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.ts : Validate component options using `validateOptions()` helper and return error box on validation failure

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.schema.ts : Use HTMX schema with strict mode including get, post, put, delete, target, swap, and trigger properties

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to **/*.test.ts : Test all code paths including errors, constructor validation, and error class `instanceof` checks

Applied to files:

  • libs/testing/src/fixtures/test-fixture.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.ts : Always use `escapeHtml()` utility for all user-provided content to prevent XSS vulnerabilities

Applied to files:

  • libs/ui/src/adapters/__tests__/response-builder.test.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/** : Organize components into schema.ts (definitions) and implementation .ts files with matching names

Applied to files:

  • libs/testing/src/example-tools/index.ts
  • libs/testing/src/example-tools/tool-configs.ts
  • libs/ui/src/index.ts
📚 Learning: 2025-11-05T15:00:47.800Z
Learnt from: frontegg-david
Repo: agentfront/frontmcp PR: 11
File: libs/core/src/auth/jwks/jwks.service.ts:62-0
Timestamp: 2025-11-05T15:00:47.800Z
Learning: In the FrontMCP codebase (libs/core/src/auth/jwks/jwks.service.ts), the verifyGatewayToken method intentionally skips signature verification when running in development-only no-auth mode, using decodeJwtPayloadSafe instead of jwtVerify. This is a deliberate design for local development convenience and should not be flagged as a security issue when the PR or code context indicates development/no-auth mode.

Applied to files:

  • apps/e2e/demo-e2e-transparent/e2e/transparent-auth.e2e.test.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Use `changeScope` instead of `scope` for change event properties to avoid confusion with the Scope class

Applied to files:

  • libs/ui/src/index.ts
🧬 Code graph analysis (12)
libs/sdk/src/flows/flow.instance.ts (1)
libs/sdk/src/errors/mcp.error.ts (1)
  • InternalMcpError (129-142)
libs/ui/src/adapters/__tests__/platform-meta.test.ts (1)
libs/ui/src/adapters/platform-meta.ts (1)
  • buildUIMeta (166-228)
apps/e2e/demo-e2e-ui/e2e/openai-resource-flow.e2e.test.ts (1)
libs/testing/src/http-mock/http-mock.ts (1)
  • html (554-560)
apps/e2e/demo-e2e-ui/e2e/platform-meta-keys.e2e.test.ts (1)
libs/testing/src/ui/ui-assertions.ts (1)
  • UIAssertions (52-446)
libs/testing/src/platform/platform-types.ts (3)
libs/testing/src/index.ts (10)
  • TestPlatformType (221-221)
  • PlatformMetaNamespace (221-221)
  • getPlatformMetaNamespace (224-224)
  • getPlatformMimeType (225-225)
  • isOpenAIPlatform (226-226)
  • isExtAppsPlatform (227-227)
  • isFrontmcpPlatform (228-228)
  • getToolsListMetaPrefixes (229-229)
  • getToolCallMetaPrefixes (230-230)
  • getForbiddenMetaPrefixes (231-231)
libs/testing/src/platform/index.ts (10)
  • TestPlatformType (27-27)
  • PlatformMetaNamespace (27-27)
  • getPlatformMetaNamespace (31-31)
  • getPlatformMimeType (32-32)
  • isOpenAIPlatform (33-33)
  • isExtAppsPlatform (34-34)
  • isFrontmcpPlatform (35-35)
  • getToolsListMetaPrefixes (36-36)
  • getToolCallMetaPrefixes (37-37)
  • getForbiddenMetaPrefixes (38-38)
libs/sdk/src/common/interfaces/tool.interface.ts (1)
  • platform (120-133)
libs/sdk/src/tool/flows/call-tool.flow.ts (3)
libs/ui/src/registry/tool-ui.registry.ts (1)
  • isUIRenderFailure (91-93)
libs/ui/src/registry/index.ts (1)
  • isUIRenderFailure (45-45)
libs/ui/src/adapters/response-builder.ts (1)
  • buildToolResponseContent (130-212)
libs/testing/src/client/mcp-test-client.builder.ts (2)
libs/testing/src/platform/platform-types.ts (1)
  • TestPlatformType (29-38)
libs/testing/src/platform/platform-client-info.ts (3)
  • getPlatformClientInfo (44-93)
  • getPlatformCapabilities (171-189)
  • TestClientCapabilities (157-160)
libs/testing/src/platform/platform-client-info.ts (2)
libs/sdk/src/common/interfaces/tool.interface.ts (2)
  • platform (120-133)
  • clientInfo (149-155)
libs/testing/src/platform/platform-types.ts (1)
  • TestPlatformType (29-38)
libs/ui/src/adapters/__tests__/response-builder.test.ts (2)
libs/ui/src/adapters/response-builder.ts (1)
  • buildToolResponseContent (130-212)
libs/ui/src/adapters/platform-meta.ts (1)
  • AIPlatformType (24-33)
libs/testing/src/client/mcp-test-client.types.ts (1)
libs/testing/src/platform/platform-types.ts (1)
  • TestPlatformType (29-38)
libs/testing/src/example-tools/tool-configs.ts (2)
libs/testing/src/example-tools/index.ts (14)
  • basicUIToolInputSchema (22-22)
  • basicUIToolOutputSchema (23-23)
  • BASIC_UI_TOOL_CONFIG (20-20)
  • fullUIToolInputSchema (24-24)
  • fullUIToolOutputSchema (25-25)
  • FULL_UI_TOOL_CONFIG (21-21)
  • generateBasicUIToolOutput (29-29)
  • generateFullUIToolOutput (29-29)
  • EXPECTED_OPENAI_TOOLS_LIST_META_KEYS (33-33)
  • EXPECTED_OPENAI_TOOL_CALL_META_KEYS (34-34)
  • EXPECTED_EXTAPPS_TOOLS_LIST_META_KEYS (35-35)
  • EXPECTED_EXTAPPS_TOOL_CALL_META_KEYS (36-36)
  • EXPECTED_FRONTMCP_TOOLS_LIST_META_KEYS (37-37)
  • EXPECTED_FRONTMCP_TOOL_CALL_META_KEYS (38-38)
libs/testing/src/index.ts (14)
  • basicUIToolInputSchema (246-246)
  • basicUIToolOutputSchema (247-247)
  • BASIC_UI_TOOL_CONFIG (244-244)
  • fullUIToolInputSchema (248-248)
  • fullUIToolOutputSchema (249-249)
  • FULL_UI_TOOL_CONFIG (245-245)
  • generateBasicUIToolOutput (251-251)
  • generateFullUIToolOutput (252-252)
  • EXPECTED_OPENAI_TOOLS_LIST_META_KEYS (254-254)
  • EXPECTED_OPENAI_TOOL_CALL_META_KEYS (255-255)
  • EXPECTED_EXTAPPS_TOOLS_LIST_META_KEYS (256-256)
  • EXPECTED_EXTAPPS_TOOL_CALL_META_KEYS (257-257)
  • EXPECTED_FRONTMCP_TOOLS_LIST_META_KEYS (258-258)
  • EXPECTED_FRONTMCP_TOOL_CALL_META_KEYS (259-259)
apps/e2e/demo-e2e-transparent/e2e/transparent-auth.e2e.test.ts (2)
libs/testing/src/client/mcp-test-client.ts (1)
  • McpTestClient (63-1078)
libs/testing/src/index.ts (1)
  • McpTestClient (46-46)
⏰ 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: Lint & Format Checks
  • GitHub Check: Build Libraries

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (4)
apps/e2e/demo-e2e-multiapp/project.json (1)

28-35: The "exec node" concern from previous review has been resolved.

The previous review flagged the use of exec node as Unix-only. The current code correctly uses plain node without the exec prefix, making it cross-platform compatible.

apps/e2e/demo-e2e-serverless/project.json (1)

28-35: The "exec" prefix issue raised in previous review has been addressed.

The past review correctly identified that exec node wouldn't work on Windows. The current implementation uses plain node, which is cross-platform compatible.

libs/sdk/src/tool/flows/call-tool.flow.ts (1)

585-589: Validate structuredContent against output schema instead of unsafe cast.

The code assigns uiResult.structuredContent to result.structuredContent with an unsafe cast to Record<string, unknown>. This bypasses runtime validation—if the value is a primitive or array, it may fail MCP protocol validation despite the type assertion. The tool's output schema has already validated the content at line 570; consider preserving that validated result or explicitly validating uiResult.structuredContent before assignment.

libs/ui/src/components/modal.ts (1)

216-218: Document security constraints for confirmHref.

The JSDoc for confirmHref lacks security documentation. Developers need to understand which protocols are allowed and what happens when validation fails.

🔎 Add comprehensive security documentation
-  /** Confirm action URL */
+  /**
+   * Confirm action URL
+   * @remarks Only safe protocols are allowed: http://, https://, /, #, mailto:, tel:
+   * Unsafe protocols (javascript:, data:, vbscript:, etc.) will be rejected and the
+   * confirm button will fall back to a dismissal button. Never pass user-controlled
+   * or unvalidated URLs without proper sanitization.
+   * @example confirmHref: '/api/confirm'
+   * @example confirmHref: 'https://example.com/action'
+   */
   confirmHref?: string;

As per past review comments and coding guidelines requiring JSDoc examples.

🧹 Nitpick comments (5)
libs/sdk/src/tool/flows/call-tool.flow.ts (1)

606-623: Use cross-platform temporary directory for debug output.

The default path /tmp/tool-response-debug.json is Unix-specific and will fail on Windows. Use Node's os.tmpdir() for cross-platform compatibility.

🔎 Proposed fix for cross-platform compatibility
+    const os = require('os');
     const fs = require('fs').promises;
     const debugOutput = {
       timestamp: new Date().toISOString(),
       tool: tool.metadata.name,
       rawOutput,
       uiResult,
       uiMeta,
       finalResult: result,
     };
-    const outputPath = process.env['DEBUG_TOOL_RESPONSE_PATH'] || '/tmp/tool-response-debug.json';
+    const outputPath = process.env['DEBUG_TOOL_RESPONSE_PATH'] || 
+      `${os.tmpdir()}/tool-response-debug.json`;
     // Use async write to avoid blocking the event loop (fire-and-forget)
libs/sdk/src/flows/flow.instance.ts (1)

406-423: Excellent fix for the finalize-stage error masking issue! Consider using structured logging for consistency.

The implementation correctly addresses the critical issue flagged in the previous review by introducing the suppressErrors option. The error handling logic properly prevents finalize errors from masking original errors when suppression is enabled, while still throwing finalize errors in the normal flow when appropriate.

However, the logging pattern at lines 414-417 should follow the structured logging approach used at lines 115-118 to avoid the Node.js util.inspect bug with Zod errors (mentioned in the comment at lines 113-114). This ensures consistency and defensive coding across the codebase.

🔎 Suggested refactor for consistent structured logging
     if (res.outcome === 'unknown_error' || res.outcome === 'fail') {
       const finalizeError = res.control ?? new InternalMcpError('Finalize stage failed');
       if (options?.suppressErrors) {
-        // Log finalizes errors but doesn't throw when called from finally blocks
+        // Log finalize errors but don't throw when called from finally blocks
         // This prevents masking the original error
-        this.scope.logger.error(
-          '[FrontMCP] Finalize stage error (suppressed to preserve original error):',
-          finalizeError,
-        );
+        console.error('[FlowInstance] Finalize stage error (suppressed to preserve original error):', {
+          name: finalizeError instanceof Error ? finalizeError.name : 'UnknownError',
+          message: finalizeError instanceof Error ? finalizeError.message : String(finalizeError),
+        });
         return res;
       }
       throw finalizeError;
     }
libs/sdk/src/tool/flows/tools-list.flow.ts (1)

102-117: Add type guard for safe access to scope.notifications.

The code casts this.scope to Scope and directly accesses scope.notifications?.getPlatformType(sessionId) without validating that these methods exist. While the optional chaining (?.) provides some protection, a more robust type guard would prevent potential runtime issues.

Consider adding a type guard similar to the one used later in parseTools (lines 245-260) to verify the scope has the expected structure before accessing notifications.getPlatformType.

🔎 Suggested type guard
-    // Cast scope to access notifications service for platform detection
-    const scope = this.scope as Scope;
+    // Type guard for scope with notifications service
+    const hasNotifications = (obj: unknown): obj is Scope & {
+      notifications: { getPlatformType: (sessionId: string) => AIPlatformType | undefined };
+    } => {
+      return (
+        obj !== null &&
+        typeof obj === 'object' &&
+        'notifications' in obj &&
+        typeof (obj as any).notifications === 'object' &&
+        typeof (obj as any).notifications?.getPlatformType === 'function'
+      );
+    };
 
     // Get platform type: first check sessionIdPayload (detected from user-agent),
     // then fall back to notification service (detected from MCP clientInfo),
     // finally default to 'unknown'
     const platformType: AIPlatformType =
       authInfo?.sessionIdPayload?.platformType ??
-      (sessionId ? scope.notifications?.getPlatformType(sessionId) : undefined) ??
+      (sessionId && hasNotifications(this.scope) ? this.scope.notifications.getPlatformType(sessionId) : undefined) ??
       'unknown';
libs/ui/src/universal/runtime-builder.ts (1)

457-466: Basic minification may break code with regex or string edge cases.

The minification logic removes comments using simple regex patterns (lines 461-462) that could incorrectly match comment-like patterns in strings or regex literals. However, since this is only applied to controlled, generated code (not user input), the risk is low.

For improved robustness, consider using a proper JavaScript minifier like terser or esbuild when minification is enabled.

libs/ui/src/types/ui-config.ts (1)

289-334: Well-documented security field with practical examples.

The contentSecurity field addition includes excellent documentation with:

  • Security context explanation
  • Multiple usage examples (default, inline scripts, bypass)
  • Clear best practice guidance

Minor observation: Some security context is duplicated from the UIContentSecurity interface documentation (lines 37-70). Consider consolidating to reduce duplication, though the current approach does provide helpful context in both locations.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1ad05e6 and ec66ca5.

📒 Files selected for processing (24)
  • apps/e2e/demo-e2e-cache/project.json (1 hunks)
  • apps/e2e/demo-e2e-codecall/project.json (1 hunks)
  • apps/e2e/demo-e2e-errors/project.json (1 hunks)
  • apps/e2e/demo-e2e-hooks/project.json (1 hunks)
  • apps/e2e/demo-e2e-multiapp/project.json (1 hunks)
  • apps/e2e/demo-e2e-notifications/project.json (1 hunks)
  • apps/e2e/demo-e2e-openapi/project.json (1 hunks)
  • apps/e2e/demo-e2e-orchestrated/project.json (1 hunks)
  • apps/e2e/demo-e2e-providers/project.json (1 hunks)
  • apps/e2e/demo-e2e-public/project.json (1 hunks)
  • apps/e2e/demo-e2e-redis/project.json (1 hunks)
  • apps/e2e/demo-e2e-serverless/project.json (1 hunks)
  • apps/e2e/demo-e2e-transparent/project.json (1 hunks)
  • apps/e2e/demo-e2e-ui/project.json (1 hunks)
  • libs/sdk/src/flows/flow.instance.ts (5 hunks)
  • libs/sdk/src/tool/flows/call-tool.flow.ts (7 hunks)
  • libs/sdk/src/tool/flows/tools-list.flow.ts (7 hunks)
  • libs/ui/src/components/modal.ts (5 hunks)
  • libs/ui/src/types/index.ts (1 hunks)
  • libs/ui/src/types/ui-config.ts (2 hunks)
  • libs/ui/src/universal/cached-runtime.ts (1 hunks)
  • libs/ui/src/universal/index.ts (1 hunks)
  • libs/ui/src/universal/runtime-builder.ts (1 hunks)
  • libs/ui/src/universal/types.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • apps/e2e/demo-e2e-openapi/project.json
  • apps/e2e/demo-e2e-codecall/project.json
  • apps/e2e/demo-e2e-orchestrated/project.json
  • apps/e2e/demo-e2e-providers/project.json
  • libs/ui/src/universal/index.ts
  • apps/e2e/demo-e2e-cache/project.json
🧰 Additional context used
📓 Path-based instructions (6)
libs/ui/src/**/*.ts

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

libs/ui/src/**/*.ts: Always use escapeHtml() utility for all user-provided content to prevent XSS vulnerabilities
Hard-code CDN URLs only in theme presets; always reference theme.cdn configuration in component code

Files:

  • libs/ui/src/types/index.ts
  • libs/ui/src/types/ui-config.ts
  • libs/ui/src/universal/runtime-builder.ts
  • libs/ui/src/components/modal.ts
  • libs/ui/src/universal/types.ts
  • libs/ui/src/universal/cached-runtime.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Enable strict TypeScript mode with no any types without strong justification - use unknown instead for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific errors instead
Use specific error classes with MCP error codes instead of generic errors
Use type parameters with constraints instead of unconstrained generics, and prefer unknown over any for generic type defaults
Follow the preset pattern for hierarchical configurations across the codebase

Files:

  • libs/ui/src/types/index.ts
  • libs/ui/src/types/ui-config.ts
  • libs/ui/src/universal/runtime-builder.ts
  • libs/ui/src/components/modal.ts
  • libs/sdk/src/flows/flow.instance.ts
  • libs/sdk/src/tool/flows/tools-list.flow.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/ui/src/universal/types.ts
  • libs/ui/src/universal/cached-runtime.ts
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/ui/src/types/index.ts
  • libs/ui/src/types/ui-config.ts
  • libs/ui/src/universal/runtime-builder.ts
  • libs/ui/src/components/modal.ts
  • libs/sdk/src/flows/flow.instance.ts
  • libs/sdk/src/tool/flows/tools-list.flow.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/ui/src/universal/types.ts
  • libs/ui/src/universal/cached-runtime.ts
libs/ui/src/components/**/*.ts

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

libs/ui/src/components/**/*.ts: Validate component options using validateOptions() helper and return error box on validation failure
Add JSDoc examples with @example tags showing basic usage and options patterns for all components
Use pure HTML string generation without React/Vue/JSX - components return HTML strings only

Files:

  • libs/ui/src/components/modal.ts
libs/ui/src/components/**

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

Organize components into schema.ts (definitions) and implementation .ts files with matching names

Files:

  • libs/ui/src/components/modal.ts
libs/{sdk,adapters,plugins,cli}/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

libs/{sdk,adapters,plugins,cli}/src/**/*.ts: Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of unknown for execute() and read() methods
Validate URIs per RFC 3986 at metadata level using Zod validation with custom refinements
Use getCapabilities() for dynamic capability exposure instead of hardcoding capabilities in adapters
Use changeScope instead of scope for change event properties to avoid confusion with the Scope class
Validate hooks match their entry type and fail fast with InvalidHookFlowError for unsupported flows
Don't mutate rawInput in flows - use state.set() for managing flow state instead

Files:

  • libs/sdk/src/flows/flow.instance.ts
  • libs/sdk/src/tool/flows/tools-list.flow.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
🧠 Learnings (17)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.ts : Hard-code CDN URLs only in theme presets; always reference theme.cdn configuration in component code
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Use the Nx build system for all build commands (nx build sdk, nx test ast-guard, nx run-many -t test)

Applied to files:

  • apps/e2e/demo-e2e-redis/project.json
  • apps/e2e/demo-e2e-errors/project.json
  • apps/e2e/demo-e2e-hooks/project.json
  • apps/e2e/demo-e2e-public/project.json
  • apps/e2e/demo-e2e-multiapp/project.json
  • apps/e2e/demo-e2e-serverless/project.json
  • apps/e2e/demo-e2e-transparent/project.json
  • apps/e2e/demo-e2e-notifications/project.json
  • apps/e2e/demo-e2e-ui/project.json
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test HTML escaping for user-provided content to prevent XSS attacks

Applied to files:

  • libs/ui/src/types/index.ts
  • libs/ui/src/types/ui-config.ts
  • libs/ui/src/universal/runtime-builder.ts
  • libs/ui/src/components/modal.ts
  • libs/ui/src/universal/cached-runtime.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.ts : Always use `escapeHtml()` utility for all user-provided content to prevent XSS vulnerabilities

Applied to files:

  • libs/ui/src/types/index.ts
  • libs/ui/src/types/ui-config.ts
  • libs/ui/src/universal/runtime-builder.ts
  • libs/ui/src/components/modal.ts
  • libs/ui/src/universal/cached-runtime.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable

Applied to files:

  • apps/e2e/demo-e2e-multiapp/project.json
  • libs/sdk/src/tool/flows/tools-list.flow.ts
  • libs/ui/src/universal/types.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.schema.ts : Use HTMX schema with strict mode including get, post, put, delete, target, swap, and trigger properties

Applied to files:

  • libs/ui/src/components/modal.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.ts : Validate component options using `validateOptions()` helper and return error box on validation failure

Applied to files:

  • libs/ui/src/components/modal.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Don't mutate rawInput in flows - use state.set() for managing flow state instead

Applied to files:

  • libs/sdk/src/flows/flow.instance.ts
  • libs/sdk/src/tool/flows/tools-list.flow.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Use FrontMCP's TypeScript-first schema validation framework philosophy - all types should align with MCP protocol definitions

Applied to files:

  • libs/sdk/src/tool/flows/tools-list.flow.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.schema.ts : Every component must have a Zod schema with `.strict()` mode to reject unknown properties

Applied to files:

  • libs/sdk/src/tool/flows/tools-list.flow.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of `unknown` for `execute()` and `read()` methods

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/*/src/common/records/**/*.ts : Centralize record types in common/records and import from there instead of from module-specific files

Applied to files:

  • libs/ui/src/universal/types.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/** : Organize components into schema.ts (definitions) and implementation .ts files with matching names

Applied to files:

  • libs/ui/src/universal/types.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/*/src/index.ts : Use barrel exports (index.ts) to export all public API surface without legacy exports or aliases

Applied to files:

  • libs/ui/src/universal/types.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to **/*.ts : Enable strict TypeScript mode with no `any` types without strong justification - use `unknown` instead for generic type defaults

Applied to files:

  • libs/ui/src/universal/types.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.ts : Use pure HTML string generation without React/Vue/JSX - components return HTML strings only

Applied to files:

  • libs/ui/src/universal/types.ts
  • libs/ui/src/universal/cached-runtime.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.ts : Hard-code CDN URLs only in theme presets; always reference theme.cdn configuration in component code

Applied to files:

  • libs/ui/src/universal/cached-runtime.ts
🧬 Code graph analysis (7)
libs/ui/src/types/ui-config.ts (1)
libs/ui/src/types/index.ts (1)
  • UIContentSecurity (19-19)
libs/ui/src/universal/runtime-builder.ts (1)
libs/ui/src/universal/types.ts (3)
  • UniversalRuntimeOptions (222-240)
  • UNIVERSAL_CDN (263-271)
  • UniversalRuntimeResult (245-254)
libs/ui/src/components/modal.ts (3)
libs/sdk/src/auth/ui/base-layout.ts (1)
  • escapeHtml (165-173)
libs/sdk/src/auth/ui/templates.ts (1)
  • escapeHtml (87-87)
libs/ui/src/layouts/base.ts (1)
  • escapeHtml (146-146)
libs/sdk/src/flows/flow.instance.ts (1)
libs/sdk/src/errors/mcp.error.ts (1)
  • InternalMcpError (129-142)
libs/sdk/src/tool/flows/tools-list.flow.ts (9)
libs/ui/src/adapters/platform-meta.ts (1)
  • AIPlatformType (24-33)
libs/ui/src/index.ts (1)
  • AIPlatformType (51-51)
libs/sdk/src/notification/notification.service.ts (1)
  • AIPlatformType (19-19)
libs/sdk/src/common/types/auth/session.types.ts (1)
  • AIPlatformType (13-22)
libs/sdk/src/notification/index.ts (1)
  • AIPlatformType (12-12)
libs/sdk/src/tool/ui/platform-adapters.ts (1)
  • AIPlatformType (13-13)
libs/testing/src/client/mcp-test-client.ts (1)
  • sessionId (207-209)
libs/testing/src/index.ts (1)
  • isOpenAIPlatform (226-226)
libs/testing/src/platform/index.ts (1)
  • isOpenAIPlatform (33-33)
libs/sdk/src/tool/flows/call-tool.flow.ts (2)
libs/ui/src/registry/tool-ui.registry.ts (1)
  • isUIRenderFailure (91-93)
libs/ui/src/adapters/response-builder.ts (1)
  • buildToolResponseContent (130-212)
libs/ui/src/universal/cached-runtime.ts (5)
libs/ui/src/universal/index.ts (7)
  • RUNTIME_PLACEHOLDERS (154-154)
  • CachedRuntimeOptions (156-156)
  • CDNType (62-62)
  • ContentSecurityOptions (65-65)
  • UNIVERSAL_CDN (68-68)
  • CachedRuntimeResult (157-157)
  • buildComponentCode (152-152)
libs/ui/src/index.ts (6)
  • RUNTIME_PLACEHOLDERS (413-413)
  • CachedRuntimeOptions (414-414)
  • CDNType (364-364)
  • UNIVERSAL_CDN (418-418)
  • CachedRuntimeResult (415-415)
  • buildComponentCode (412-412)
libs/ui/src/universal/types.ts (3)
  • CDNType (194-194)
  • ContentSecurityOptions (199-217)
  • UNIVERSAL_CDN (263-271)
libs/ui/src/bundler/cache.ts (1)
  • keys (253-255)
libs/ui/src/registry/tool-ui.registry.ts (1)
  • buildComponentCode (635-662)
⏰ 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: Build Libraries
  • GitHub Check: Lint & Format Checks
🔇 Additional comments (23)
apps/e2e/demo-e2e-errors/project.json (1)

29-34: LGTM! Improved serve target configuration.

The migration from @nx/js:node executor to explicit nx:run-commands with dependsOn: ["build"] is a good change that:

  • Makes the execution flow more transparent and explicit
  • Ensures the build artifact exists before attempting to serve
  • Maintains path consistency with the build target's outputPath (line 15)
  • Aligns with the standardization effort across E2E demo projects

Based on learnings, this continues to use the Nx build system appropriately.

apps/e2e/demo-e2e-notifications/project.json (1)

28-35: LGTM! Appropriate migration for e2e testing.

The switch from @nx/js:node to nx:run-commands with explicit post-build execution is well-suited for an e2e test application. The dependsOn: ["build"] ensures correct execution order, and the explicit command path aligns with the build output configuration. While this removes watch mode capabilities, that's not typically needed for e2e tests and makes the execution flow more transparent and debuggable.

apps/e2e/demo-e2e-transparent/project.json (1)

28-35: LGTM—consistent E2E serve refactoring across all projects.

The migration from @nx/js:node to nx:run-commands with explicit build dependency and post-build command execution is implemented consistently across all 6 E2E projects. The approach is sound:

  • dependsOn: ["build"] ensures the artifact exists before serving
  • cwd: "{workspaceRoot}" provides consistent path resolution
  • ✅ Plain node command is cross-platform compatible (Windows, macOS, Linux)

This pattern aligns with the PR objective of "adding E2E test resilience" by making the execution flow explicit and controllable.

libs/sdk/src/tool/flows/call-tool.flow.ts (3)

464-484: LGTM: Graceful degradation for UI rendering failures.

The graceful degradation path properly handles UI rendering failures by logging a warning and proceeding without UI content. This ensures tool execution succeeds even when UI rendering fails, which aligns with the PR objective of enhancing test resilience.


556-567: Improved error handling: skip finalization on early failures.

The change from throwing errors to returning early is appropriate since the finalize stage runs even during cleanup after execution failures. This prevents masking the original error with a generic finalization error. The verbose logging provides debugging visibility while relying on the flow framework to propagate the original error.


545-550: LGTM: Improved documentation for finalize stage behavior.

The updated documentation clearly explains that the finalize stage runs during cleanup even after execution failures, and that error propagation is handled by the flow framework. This helps maintainers understand the error handling pattern.

apps/e2e/demo-e2e-redis/project.json (1)

29-34: Serve target configuration is correct and consistently applied across all e2e demo projects.

The configuration properly uses nx:run-commands with explicit dependsOn: ["build"] to ensure compilation completes before execution. The command path correctly references the webpack build output, and the workspace root cwd is appropriate for this use case. This pattern is standardized across all 14 e2e demo projects in the repository.

libs/ui/src/components/modal.ts (1)

271-286: Security implementation looks good.

The confirm button implementation correctly:

  • Validates confirmHref using isSafeUrl before rendering a link
  • Falls back to a safe dismissal button when the URL is unsafe or missing
  • Applies escapeHtml for defense-in-depth

This addresses the critical XSS vulnerability flagged in previous reviews.

Note: Once the warning is added to isSafeUrl (per earlier comment), rejected URLs will be properly logged for debugging.

libs/sdk/src/flows/flow.instance.ts (1)

434-434: LGTM! Call sites correctly implement the error suppression pattern.

All invocations of runFinalizeStage() follow the correct pattern:

  • Lines 434, 452, 474, 493: Suppression in finally blocks prevents finalize errors from masking the original error being thrown from the try block.
  • Lines 439, 457, 478, 498: Suppression before throwing FlowControl ensures the intended control flow signal is not overridden by a finalize error.
  • Lines 445, 507: No suppression in the happy path allows finalize errors to be properly thrown when no other error has occurred.

This implementation ensures robust error propagation throughout the flow lifecycle.

Also applies to: 439-439, 445-445, 452-452, 457-457, 474-474, 478-478, 493-493, 498-498, 507-507

libs/ui/src/types/index.ts (1)

18-19: LGTM! Clean type export for XSS protection configuration.

The addition of the UIContentSecurity export alongside UIContentSecurityPolicy provides a clear separation between CSP directives (external resource policies) and XSS protection settings (sanitization behavior). The comment accurately describes its purpose.

libs/sdk/src/tool/flows/tools-list.flow.ts (2)

22-27: Documented exception to strict typing for external SDK type.

The use of z.any() for authInfo is appropriately justified with an inline comment explaining that AuthInfo is an external type from @modelcontextprotocol/sdk that varies by SDK version. This is a reasonable exception to the strict typing rule when dealing with third-party types that may have version variance.


234-341: Excellent platform-aware meta generation with robust type guard.

The platform-specific meta generation is well-implemented with clear separation:

  • OpenAI: openai/* keys only (proprietary ChatGPT format)
  • ext-apps: ui/* keys only (SEP-1865 MCP Apps spec)
  • Other platforms: frontmcp/* + ui/* for compatibility

The type guard at lines 245-260 is exemplary—it thoroughly validates that toolUI exists with the required methods before accessing them. This prevents runtime errors and provides clear error messages.

libs/ui/src/universal/runtime-builder.ts (3)

93-160: URL validation properly prevents javascript: injection.

The markdown parser now includes proper URL scheme validation via isSafeUrl() (lines 106-117) that blocks dangerous schemes like javascript:, data:, and vbscript: by default. Links are validated before rendering (lines 136-139), and malicious links are rendered as plain text rather than clickable links.

The HTML escaping at line 122 prevents basic XSS via HTML tag injection. This addresses the XSS vulnerabilities noted in past reviews.

✅ Addresses past review concerns about javascript: URL injection.


169-302: HTML renderer properly sanitizes content by default.

The HTML renderer now includes XSS protection that removes <script> tags (line 191) and event handlers (line 192) before rendering with dangerouslySetInnerHTML. Sanitization is only bypassed when allowInlineScripts or bypassSanitization is explicitly enabled in the content security options.

This provides defense-in-depth protection and addresses the XSS concerns from past reviews.

✅ Addresses past review concerns about HTML renderer XSS vulnerability.


201-225: Markdown renderer fallback uses sanitized parser.

The markdown renderer fallback (line 219) now uses window.__frontmcp.parseMarkdown, which includes proper URL validation and HTML escaping (as reviewed above in lines 93-160). This resolves the XSS vulnerability concern from past reviews.

✅ Addresses past review concerns about markdown renderer XSS vulnerability.

libs/ui/src/types/ui-config.ts (1)

37-124: Excellent security-focused interface with comprehensive documentation.

The UIContentSecurity interface is exceptionally well-documented with:

  • Clear explanation of the platform isolation context (double-iframe sandbox)
  • Detailed security implications for each option
  • Default-secure approach (all protections enabled by default)
  • Appropriate warnings about when to disable protections

This sets a high bar for API documentation and security best practices.

libs/ui/src/universal/types.ts (3)

26-185: Justified use of any for React component types.

The use of any in React component types (React.ComponentType<any>) at lines 32, 39, 122, 163, and 170 is appropriately justified. React components require flexible prop types, and using unknown would break component composition. All instances include eslint-disable comments, indicating deliberate architectural decisions.


187-271: Well-structured runtime configuration types with clear documentation.

The runtime types (UniversalRuntimeOptions, UniversalRuntimeResult, ContentSecurityOptions) are clearly defined with appropriate documentation. The UNIVERSAL_CDN constant provides centralized CDN URL management, and the dual CDN type support (ESM/UMD) enables both network-open and network-blocked scenarios.


277-332: Comprehensive content type detection with clear priority order.

The detectContentType function implements a well-thought-out detection strategy with clear priority:

  1. Function components → 'react'
  2. Module syntax + JSX → 'react' (needs transpilation)
  3. JSX + Markdown (no modules) → 'mdx'
  4. Pure markdown → 'markdown'
  5. Default → 'html'

The logic handles edge cases well and includes helpful comments explaining each detection path. The heuristics cover the common patterns while avoiding false positives.

libs/ui/src/universal/cached-runtime.ts (4)

234-296: Markdown parser includes proper URL validation matching runtime-builder.ts.

The inline markdown parser implementation includes the same URL validation logic as runtime-builder.ts, with isSafeUrl() blocking dangerous schemes by default. HTML escaping (line 264) and link validation (lines 276-278) provide defense-in-depth protection.

✅ Consistent with fixes in runtime-builder.ts that address past XSS concerns.


298-428: HTML renderer properly sanitizes content by default.

The HTML renderer implementation (lines 316-333) matches the sanitization logic in runtime-builder.ts, removing <script> tags (line 325) and event handlers (line 326) unless explicitly bypassed. This provides consistent XSS protection across the codebase.


673-746: Cache implementation with proper TTL and eviction.

The cache implementation includes:

  • Comprehensive cache key generation based on all options (lines 83-104)
  • TTL expiration checking (line 681)
  • FIFO eviction when max entries reached (lines 728-734)

The cache logic is sound and will properly manage memory usage with the configurable limits.


822-871: Data injection safely handles serialization errors.

The buildDataInjectionCode function includes proper error handling for JSON serialization via the safeJson helper (lines 834-840), which catches serialization errors and falls back to 'null'. This prevents the builder from crashing on circular references or other unserializable data.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

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

⚠️ Outside diff range comments (1)
libs/ui/src/components/modal.ts (1)

102-186: Add option validation and documentation examples to modal and confirmModal functions.

The modal and confirmModal functions bypass option validation required by coding guidelines. Following the pattern established in button.ts, create modal.schema.ts with Zod schemas, then validate options using validateOptions() at the start of each function and return the error box on validation failure. Additionally, add @example JSDoc tags to both functions demonstrating basic usage and option patterns.

♻️ Duplicate comments (5)
libs/ui/src/universal/renderers/html.renderer.ts (2)

27-49: XSS risk remains: htmlRenderer still uses unsanitized dangerouslySetInnerHTML.

This issue was previously flagged but remains unresolved. The htmlRenderer renders raw HTML without any sanitization, creating an XSS vulnerability if the source contains user-controlled content.

As per coding guidelines, user-provided content should use the escapeHtml() utility. Consider either:

  1. Using safeHtmlRenderer as the default export, or
  2. Clearly documenting that htmlRenderer is for trusted content only

58-70: Regex-based sanitizeHtml() remains inadequate for production use.

This issue was previously flagged but remains unresolved. The regex-based approach has known limitations that allow XSS vectors to bypass:

  • HTML entity-encoded payloads (e.g., &#60;script&#62;)
  • javascript:, data:, and vbscript: URL schemes in attributes
  • <svg>, <iframe>, <object>, and <embed> tags with embedded scripts
  • Event handlers beyond those matched by the simple regex

The comment acknowledges this limitation but doesn't address it. For production use, replace with a robust HTML sanitization library like DOMPurify.

libs/sdk/src/tool/flows/call-tool.flow.ts (1)

585-589: Validate structuredContent against output schema instead of bypassing validation with unsafe cast.

The code assigns uiResult.structuredContent (which contains rawOutput) with an unsafe as Record<string, unknown> cast. Since rawOutput is typed as any, the cast doesn't enforce that the value is actually an object at runtime—if rawOutput is a primitive or array, the cast will succeed but MCP protocol validation may fail.

Instead of relying on the type assertion, validate uiResult.structuredContent against the tool's output schema, or ensure that rawOutput is validated as an object before being set as structuredContent.

Based on learnings: "Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of unknown for execute() and read() methods"

libs/ui/src/components/modal.ts (2)

13-29: Add @example tag to JSDoc.

The isSafeUrl function is missing @example documentation to illustrate usage, as previously requested and required by coding guidelines.

🔎 Add JSDoc example
 /**
  * Validates URL scheme to prevent XSS via javascript: URLs.
  *
  * Allowed protocols:
  * - `http://`, `https://` - Web URLs
  * - `/`, `#` - Relative paths and anchors
  * - `mailto:` - Email links
  * - `tel:` - Phone links
  *
  * Blocked protocols (XSS vectors):
  * - `javascript:` - Inline script execution
  * - `data:` - Data URIs (can contain scripts)
  * - `vbscript:` - Legacy script protocol
  *
+ * @example
+ * isSafeUrl('https://example.com') // true
+ * isSafeUrl('javascript:alert(1)') // false (logs warning)
+ * isSafeUrl('/relative/path') // true
+ * isSafeUrl('tel:+1234567890') // true
+ *
  * @param url - URL to validate
  * @returns true if URL uses a safe protocol, false otherwise
  */

As per coding guidelines.


236-238: Document security constraints for confirmHref.

The confirmHref property lacks security documentation. Developers need to understand which protocols are allowed and what happens when an unsafe URL is provided.

🔎 Add security documentation
   /** Icon */
   icon?: string;
-  /** Confirm action URL */
+  /**
+   * Confirm action URL
+   * 
+   * @remarks Only safe protocols are allowed: `http://`, `https://`, `/`, `#`, `mailto:`, `tel:`
+   * Other protocols (e.g., `javascript:`, `data:`) will be rejected and fall back to button behavior.
+   */
   confirmHref?: string;
 }

Based on past review comments.

🧹 Nitpick comments (1)
libs/ui/src/components/modal.ts (1)

102-186: Add JSDoc @example tags for modal and confirmModal functions.

Both functions lack usage examples in their JSDoc, which is required by coding guidelines to demonstrate basic usage and options patterns.

Example structure for modal function
/**
 * Build a modal component
 * 
 * @example
 * ```typescript
 * modal('<p>Modal content</p>', {
 *   id: 'my-modal',
 *   title: 'Example Modal',
 *   size: 'md'
 * })
 * ```
 */
export function modal(content: string, options: ModalOptions): string {
  // ...
}

As per coding guidelines.

Also applies to: 243-325

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ec66ca5 and 88380b9.

📒 Files selected for processing (5)
  • libs/sdk/src/tool/flows/call-tool.flow.ts (7 hunks)
  • libs/ui/src/components/modal.ts (5 hunks)
  • libs/ui/src/universal/renderers/html.renderer.ts (1 hunks)
  • libs/ui/src/universal/renderers/markdown.renderer.ts (1 hunks)
  • libs/ui/src/universal/renderers/mdx.renderer.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
libs/ui/src/components/**/*.ts

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

libs/ui/src/components/**/*.ts: Validate component options using validateOptions() helper and return error box on validation failure
Add JSDoc examples with @example tags showing basic usage and options patterns for all components
Use pure HTML string generation without React/Vue/JSX - components return HTML strings only

Files:

  • libs/ui/src/components/modal.ts
libs/ui/src/**/*.ts

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

libs/ui/src/**/*.ts: Always use escapeHtml() utility for all user-provided content to prevent XSS vulnerabilities
Hard-code CDN URLs only in theme presets; always reference theme.cdn configuration in component code

Files:

  • libs/ui/src/components/modal.ts
  • libs/ui/src/universal/renderers/html.renderer.ts
  • libs/ui/src/universal/renderers/mdx.renderer.ts
  • libs/ui/src/universal/renderers/markdown.renderer.ts
libs/ui/src/components/**

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

Organize components into schema.ts (definitions) and implementation .ts files with matching names

Files:

  • libs/ui/src/components/modal.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Enable strict TypeScript mode with no any types without strong justification - use unknown instead for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific errors instead
Use specific error classes with MCP error codes instead of generic errors
Use type parameters with constraints instead of unconstrained generics, and prefer unknown over any for generic type defaults
Follow the preset pattern for hierarchical configurations across the codebase

Files:

  • libs/ui/src/components/modal.ts
  • libs/ui/src/universal/renderers/html.renderer.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/ui/src/universal/renderers/mdx.renderer.ts
  • libs/ui/src/universal/renderers/markdown.renderer.ts
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/ui/src/components/modal.ts
  • libs/ui/src/universal/renderers/html.renderer.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/ui/src/universal/renderers/mdx.renderer.ts
  • libs/ui/src/universal/renderers/markdown.renderer.ts
libs/{sdk,adapters,plugins,cli}/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

libs/{sdk,adapters,plugins,cli}/src/**/*.ts: Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of unknown for execute() and read() methods
Validate URIs per RFC 3986 at metadata level using Zod validation with custom refinements
Use getCapabilities() for dynamic capability exposure instead of hardcoding capabilities in adapters
Use changeScope instead of scope for change event properties to avoid confusion with the Scope class
Validate hooks match their entry type and fail fast with InvalidHookFlowError for unsupported flows
Don't mutate rawInput in flows - use state.set() for managing flow state instead

Files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.ts : Use pure HTML string generation without React/Vue/JSX - components return HTML strings only
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.schema.ts : Use HTMX schema with strict mode including get, post, put, delete, target, swap, and trigger properties

Applied to files:

  • libs/ui/src/components/modal.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.ts : Always use `escapeHtml()` utility for all user-provided content to prevent XSS vulnerabilities

Applied to files:

  • libs/ui/src/components/modal.ts
  • libs/ui/src/universal/renderers/html.renderer.ts
  • libs/ui/src/universal/renderers/mdx.renderer.ts
  • libs/ui/src/universal/renderers/markdown.renderer.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.ts : Validate component options using `validateOptions()` helper and return error box on validation failure

Applied to files:

  • libs/ui/src/components/modal.ts
  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test HTML escaping for user-provided content to prevent XSS attacks

Applied to files:

  • libs/ui/src/components/modal.ts
  • libs/ui/src/universal/renderers/html.renderer.ts
  • libs/ui/src/universal/renderers/mdx.renderer.ts
  • libs/ui/src/universal/renderers/markdown.renderer.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Validate URIs per RFC 3986 at metadata level using Zod validation with custom refinements

Applied to files:

  • libs/ui/src/components/modal.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.ts : Use pure HTML string generation without React/Vue/JSX - components return HTML strings only

Applied to files:

  • libs/ui/src/universal/renderers/html.renderer.ts
  • libs/ui/src/universal/renderers/mdx.renderer.ts
  • libs/ui/src/universal/renderers/markdown.renderer.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Don't mutate rawInput in flows - use state.set() for managing flow state instead

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of `unknown` for `execute()` and `read()` methods

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Use FrontMCP's TypeScript-first schema validation framework philosophy - all types should align with MCP protocol definitions

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.schema.ts : Every component must have a Zod schema with `.strict()` mode to reject unknown properties

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
🧬 Code graph analysis (1)
libs/sdk/src/tool/flows/call-tool.flow.ts (3)
libs/ui/src/registry/tool-ui.registry.ts (1)
  • isUIRenderFailure (91-93)
libs/ui/src/registry/index.ts (1)
  • isUIRenderFailure (45-45)
libs/ui/src/adapters/response-builder.ts (1)
  • buildToolResponseContent (130-212)
🪛 Biome (2.1.2)
libs/ui/src/universal/renderers/html.renderer.ts

[error] 46-46: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)


[error] 94-94: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

libs/ui/src/universal/renderers/mdx.renderer.ts

[error] 121-121: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

libs/ui/src/universal/renderers/markdown.renderer.ts

[error] 163-163: Avoid passing children using a prop

The canonical way to pass children in React is to use additional arguments to React.createElement

(lint/correctness/noChildrenProp)


[error] 178-178: Avoid passing children using a prop

The canonical way to pass children in React is to use additional arguments to React.createElement

(lint/correctness/noChildrenProp)


[error] 188-188: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

⏰ 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: Lint & Format Checks
  • GitHub Check: Build Libraries
🔇 Additional comments (14)
libs/ui/src/universal/renderers/html.renderer.ts (1)

75-97: Good approach, but depends on fixing sanitizeHtml().

The safeHtmlRenderer correctly attempts to sanitize content before rendering, which is the right pattern. However, its security depends on fixing the sanitizeHtml() function (see previous comment). Once that function uses a robust library like DOMPurify, this renderer will provide proper XSS protection.

libs/ui/src/universal/renderers/markdown.renderer.ts (3)

29-40: LGTM: Good URL validation implementation.

The isSafeUrl() function properly validates URL schemes to prevent XSS attacks via javascript:, data:, and vbscript: URLs. The case-insensitive check is appropriate.

Minor suggestion: Consider explicitly checking for null/undefined at the start:

if (!url) return false;

This makes the guard more explicit (though the current code works correctly).


131-155: LGTM: Robust markdown detection logic.

The canHandle() method correctly detects markdown patterns while excluding JSX tags to avoid conflicts with the MDX renderer. The auto-detection logic is well-designed.


199-218: LGTM: Clean factory pattern for extensibility.

The createMarkdownRenderer() function provides a good pattern for injecting default components while allowing runtime override through context. The component merging order is correct (defaults → context → content).

libs/ui/src/universal/renderers/mdx.renderer.ts (6)

16-24: LGTM: Proper runtime detection.

The getMDXRuntime() function correctly checks for the MDX runtime availability. The use of any for window globals is acceptable in this context.


29-51: LGTM: Comprehensive MDX syntax detection.

The containsMdxSyntax() function correctly identifies MDX-specific patterns (JSX components, expressions, imports, and JSX attributes) to distinguish MDX from plain markdown.


72-87: LGTM: Well-structured content detection.

The canHandle() method correctly identifies MDX content through explicit type checking and auto-detection using containsMdxSyntax(). The logic properly requires both markdown and MDX syntax for auto-detection.


89-163: LGTM: Excellent fallback handling and proper XSS prevention.

The render method correctly addresses previous review concerns:

  • ✅ Uses escapeHtml() utility (line 104) as required by coding guidelines
  • ✅ Uses positional children arguments (line 93)
  • ✅ Provides graceful fallbacks for missing MDX runtime (lines 99-124) and uncompiled content (lines 153-161)

The dangerouslySetInnerHTML at line 121 is safe because the content is properly escaped via escapeHtml() at line 104 before rendering. The Biome warning is a false positive in this case.

Good defensive programming with the multiple fallback paths and clear console warnings.


170-172: LGTM: Simple and effective utility.

The isMdxSupported() function provides a clean public API for checking MDX runtime availability.


180-198: LGTM: Consistent factory pattern.

The createMdxRenderer() function follows the same extensibility pattern as createMarkdownRenderer(), providing consistency across the renderer implementations. Component merging order is correct.

libs/sdk/src/tool/flows/call-tool.flow.ts (2)

464-484: LGTM! Well-structured graceful degradation for UI rendering failures.

The type guard correctly identifies render failures and proceeds without UI content, maintaining tool functionality while logging diagnostic information. The platform-specific HTML key extraction with fallback to 'ui/html' ensures compatibility across different client types.


556-567: Error propagation is working correctly as designed.

The finalize stage returns silently when tool or rawOutput is undefined because the flow framework uses a suppressErrors flag during finalize to prevent masking errors from the execute stage. When execute fails, finalize runs in cleanup mode with error suppression enabled, then the original error is re-thrown. This is the correct and safe pattern already implemented in the flow execution logic.

libs/ui/src/components/modal.ts (2)

30-46: LGTM! Security validation correctly implemented.

The isSafeUrl function properly validates URL schemes and blocks dangerous protocols (javascript:, data:, vbscript:), effectively preventing XSS attacks via href attributes.


291-306: LGTM! Secure URL handling with proper fallback.

The confirm button logic correctly validates confirmHref using isSafeUrl before rendering an anchor tag, and safely falls back to a button when the URL is missing or unsafe. The use of escapeHtml on all dynamic content provides defense in depth.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
libs/sdk/src/tool/flows/call-tool.flow.ts (1)

585-589: Unsafe cast persists - runtime type mismatch possible.

The as Record<string, unknown> cast doesn't guarantee uiResult.structuredContent is actually an object at runtime. If the tool's rawOutput is a primitive or array, this cast will pass TypeScript checks but may violate MCP protocol expectations.

Consider adding a runtime check:

🔎 Proposed validation
      if (uiResult.structuredContent !== undefined && uiResult.structuredContent !== null) {
+       // Validate structuredContent is an object (MCP protocol requirement)
+       if (typeof uiResult.structuredContent === 'object' && !Array.isArray(uiResult.structuredContent)) {
          result.structuredContent = uiResult.structuredContent as Record<string, unknown>;
+       } else {
+         this.logger.warn('finalize: structuredContent is not an object, skipping', {
+           tool: tool.metadata.name,
+           type: typeof uiResult.structuredContent,
+         });
+       }
      }
🧹 Nitpick comments (1)
libs/sdk/src/tool/flows/call-tool.flow.ts (1)

606-650: Path traversal protection is adequate.

The implementation correctly validates that custom paths are within tempDir or cwd using proper path boundary checks (+ path.sep). This addresses the previous security concern.

Consider top-level imports and directory creation.

Minor improvements for robustness:

  1. The require() calls could be top-level ESM imports to avoid runtime cost on each invocation
  2. If DEBUG_TOOL_RESPONSE_PATH contains non-existent subdirectories, writeFile will fail silently
🔎 Optional: Add recursive directory creation
+     // Ensure parent directory exists
+     const dir = path.dirname(outputPath);
+     await fs.mkdir(dir, { recursive: true }).catch(() => {});
+
      // Use async write to avoid blocking the event loop (fire-and-forget)
      fs.writeFile(outputPath, JSON.stringify(debugOutput, null, 2))
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 88380b9 and 26b54bc.

📒 Files selected for processing (2)
  • libs/sdk/src/tool/flows/call-tool.flow.ts (7 hunks)
  • libs/ui/src/universal/renderers/markdown.renderer.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Enable strict TypeScript mode with no any types without strong justification - use unknown instead for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific errors instead
Use specific error classes with MCP error codes instead of generic errors
Use type parameters with constraints instead of unconstrained generics, and prefer unknown over any for generic type defaults
Follow the preset pattern for hierarchical configurations across the codebase

Files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/ui/src/universal/renderers/markdown.renderer.ts
libs/{sdk,adapters,plugins,cli}/src/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

libs/{sdk,adapters,plugins,cli}/src/**/*.ts: Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of unknown for execute() and read() methods
Validate URIs per RFC 3986 at metadata level using Zod validation with custom refinements
Use getCapabilities() for dynamic capability exposure instead of hardcoding capabilities in adapters
Use changeScope instead of scope for change event properties to avoid confusion with the Scope class
Validate hooks match their entry type and fail fast with InvalidHookFlowError for unsupported flows
Don't mutate rawInput in flows - use state.set() for managing flow state instead

Files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
libs/**

⚙️ CodeRabbit configuration file

libs/**: Contains publishable SDK libraries. Review for API correctness, breaking changes, and consistency with docs. When public APIs change, ensure there is a matching docs/draft/docs/** update (not direct edits under docs/docs/**).

Files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
  • libs/ui/src/universal/renderers/markdown.renderer.ts
libs/ui/src/**/*.ts

📄 CodeRabbit inference engine (libs/ui/CLAUDE.md)

libs/ui/src/**/*.ts: Always use escapeHtml() utility for all user-provided content to prevent XSS vulnerabilities
Hard-code CDN URLs only in theme presets; always reference theme.cdn configuration in component code

Files:

  • libs/ui/src/universal/renderers/markdown.renderer.ts
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Don't mutate rawInput in flows - use state.set() for managing flow state instead

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of `unknown` for `execute()` and `read()` methods

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Use FrontMCP's TypeScript-first schema validation framework philosophy - all types should align with MCP protocol definitions

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.schema.ts : Every component must have a Zod schema with `.strict()` mode to reject unknown properties

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.ts : Validate component options using `validateOptions()` helper and return error box on validation failure

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.schema.ts : Use HTMX schema with strict mode including get, post, put, delete, target, swap, and trigger properties

Applied to files:

  • libs/sdk/src/tool/flows/call-tool.flow.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/**/*.ts : Use pure HTML string generation without React/Vue/JSX - components return HTML strings only

Applied to files:

  • libs/ui/src/universal/renderers/markdown.renderer.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.ts : Always use `escapeHtml()` utility for all user-provided content to prevent XSS vulnerabilities

Applied to files:

  • libs/ui/src/universal/renderers/markdown.renderer.ts
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test HTML escaping for user-provided content to prevent XSS attacks

Applied to files:

  • libs/ui/src/universal/renderers/markdown.renderer.ts
🧬 Code graph analysis (2)
libs/sdk/src/tool/flows/call-tool.flow.ts (3)
libs/ui/src/registry/tool-ui.registry.ts (1)
  • isUIRenderFailure (91-93)
libs/ui/src/registry/index.ts (1)
  • isUIRenderFailure (45-45)
libs/ui/src/adapters/response-builder.ts (1)
  • buildToolResponseContent (130-212)
libs/ui/src/universal/renderers/markdown.renderer.ts (2)
libs/ui/src/utils/escape-html.ts (1)
  • escapeHtml (27-41)
libs/ui/src/universal/types.ts (3)
  • ClientRenderer (132-148)
  • UniversalContent (26-40)
  • RenderContext (113-126)
🪛 Biome (2.1.2)
libs/ui/src/universal/renderers/markdown.renderer.ts

[error] 182-182: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

⏰ 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: Lint & Format Checks
  • GitHub Check: Build Libraries
🔇 Additional comments (9)
libs/sdk/src/tool/flows/call-tool.flow.ts (6)

27-27: LGTM!

The import of isUIRenderFailure type guard is correctly added and properly used for graceful degradation handling in the applyUI stage.


416-416: LGTM!

The rename from useDualPayload to useStructuredContent aligns with the buildToolResponseContent API signature.


488-507: LGTM!

The useStructuredContent parameter is correctly passed to buildToolResponseContent and logged for debugging.


545-550: LGTM!

The updated JSDoc clearly documents the behavior when execute fails, explaining why finalization is skipped rather than throwing a new error.


556-567: LGTM!

The early returns for missing tool/output prevent cascading errors during cleanup. The original execution error will propagate correctly through the flow framework.


464-484: Graceful degradation pattern is solid.

The UI render failure handling correctly allows tool execution to proceed without UI when rendering fails. The type guard usage is appropriate.

Platform-specific HTML key mapping is correct as designed.

The htmlKey logic correctly defaults to frontmcp/html for Claude, Gemini, and other non-OpenAI/non-ext-apps platforms. This is intentional per the codebase strategy (documented in tools-list.flow.ts). Consider extracting the platform-key mapping to a constant or helper function for better readability and to consolidate the logic currently duplicated across flows.

libs/ui/src/universal/renderers/markdown.renderer.ts (3)

61-108: Excellent security implementation! Previous review feedback properly addressed.

The use of escapeHtml() at line 63 correctly addresses the previous review comment about manual HTML escaping. The security implementation is solid:

  • User content is escaped before markdown pattern replacements
  • Links are validated via isSafeUrl() to block XSS vectors (javascript:, data:, vbscript:)
  • The fallback parser provides safe rendering when ReactMarkdown is unavailable

126-185: Perfect! React.createElement usage corrected per previous review.

The render method now correctly passes children as positional arguments to React.createElement:

  • Line 160: Error message passed as third argument ✓
  • Line 174: Markdown source passed as third argument ✓

The dangerouslySetInnerHTML usage (lines 180-183) is safe here because the content has been sanitized through parseMarkdownToHtml(), which applies escapeHtml() and validates URLs with isSafeUrl(). This is the appropriate fallback when ReactMarkdown is unavailable.


193-212: LGTM! Clean factory pattern with proper component merging.

The factory function correctly:

  • Merges default components with context components
  • Maintains proper precedence order (defaultComponents overridden by context.components)
  • Delegates to the base renderer implementation

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 26b54bc and 7388b3b.

📒 Files selected for processing (1)
  • apps/demo/tsconfig.app.json (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
apps/demo/**

⚙️ CodeRabbit configuration file

apps/demo/**: apps/demo directory contains a demo application for testing purposes. It can be used as a reference for SDK usage examples.

Files:

  • apps/demo/tsconfig.app.json
🧠 Learnings (7)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Support platform-aware rendering by detecting network capabilities (open vs blocked) and script loading strategies (external vs inline)
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to **/*.ts : Enable strict TypeScript mode with no `any` types without strong justification - use `unknown` instead for generic type defaults

Applied to files:

  • apps/demo/tsconfig.app.json
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to **/*.ts : Follow the preset pattern for hierarchical configurations across the codebase

Applied to files:

  • apps/demo/tsconfig.app.json
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to **/*.ts : Use type parameters with constraints instead of unconstrained generics, and prefer `unknown` over `any` for generic type defaults

Applied to files:

  • apps/demo/tsconfig.app.json
📚 Learning: 2025-11-26T15:23:04.965Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/components/** : Organize components into schema.ts (definitions) and implementation .ts files with matching names

Applied to files:

  • apps/demo/tsconfig.app.json
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/*/src/common/records/**/*.ts : Centralize record types in common/records and import from there instead of from module-specific files

Applied to files:

  • apps/demo/tsconfig.app.json
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Use `changeScope` instead of `scope` for change event properties to avoid confusion with the Scope class

Applied to files:

  • apps/demo/tsconfig.app.json

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
docs/draft/docs/getting-started/welcome.mdx (1)

39-39: Consider adding a brief explanation of the http configuration.

The example introduces http: { port: 3000 } without explaining its purpose. Since this is the welcome page and likely the first code example new users will encounter, adding a sentence about what this HTTP server configuration does would improve clarity. For instance, you could add a comment above line 39 or extend the "Core concepts" section to mention HTTP transport.

💡 Suggested addition

You could add a brief inline comment:

 @FrontMcp({
   info: { name: 'Demo 🚀', version: '0.1.0' },
   apps: [CalcApp],
+  // Expose the MCP server over HTTP on port 3000
   http: { port: 3000 },
 })

Or extend the "Core concepts" section to include:

  • HTTP Transport — expose your server over HTTP with configurable ports

Based on coding guidelines, this is the correct location (draft/docs/**) for documentation edits.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7388b3b and 24e08ec.

📒 Files selected for processing (10)
  • docs/draft/docs.json (6 hunks)
  • docs/draft/docs/authentication/demo-servers.mdx (4 hunks)
  • docs/draft/docs/getting-started/quickstart.mdx (2 hunks)
  • docs/draft/docs/getting-started/welcome.mdx (1 hunks)
  • docs/draft/docs/guides/ast-guard.mdx (1 hunks)
  • docs/draft/docs/plugins/cache-plugin.mdx (2 hunks)
  • docs/draft/docs/servers/discovery.mdx (1 hunks)
  • docs/draft/docs/servers/prompts.mdx (1 hunks)
  • docs/draft/docs/servers/resources.mdx (1 hunks)
  • docs/draft/docs/servers/tools.mdx (1 hunks)
✅ Files skipped from review due to trivial changes (3)
  • docs/draft/docs/plugins/cache-plugin.mdx
  • docs/draft/docs/servers/prompts.mdx
  • docs/draft/docs/servers/resources.mdx
🧰 Additional context used
📓 Path-based instructions (2)
docs/draft/docs/**

⚙️ CodeRabbit configuration file

docs/draft/docs/**: This folder holds the draft/source docs that humans are expected to edit. When authors want to add or change documentation, they should do it here. The Codex workflow uses these drafts, together with the code diff, to generate the latest docs under docs/docs/. As a reviewer: - Encourage contributors to add/update content here instead of docs/docs/. - It is fine to do structural/content feedback here (clarity, examples, etc).

Files:

  • docs/draft/docs/servers/discovery.mdx
  • docs/draft/docs/servers/tools.mdx
  • docs/draft/docs/getting-started/quickstart.mdx
  • docs/draft/docs/guides/ast-guard.mdx
  • docs/draft/docs/authentication/demo-servers.mdx
  • docs/draft/docs/getting-started/welcome.mdx
docs/**

⚙️ CodeRabbit configuration file

docs/**: Repository documentation for the SDK, using MDX and hosted by Mintlify. See more specific rules for: - docs/docs/** (latest rendered docs, automation-only) - docs/v/** (archived versions, read-only) - docs/draft/docs/** (human-editable drafts) - docs/blogs/** (blogs, human edited) - docs/docs.json (Mintlify navigation)

Files:

  • docs/draft/docs/servers/discovery.mdx
  • docs/draft/docs/servers/tools.mdx
  • docs/draft/docs/getting-started/quickstart.mdx
  • docs/draft/docs/guides/ast-guard.mdx
  • docs/draft/docs/authentication/demo-servers.mdx
  • docs/draft/docs/getting-started/welcome.mdx
  • docs/draft/docs.json
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Support platform-aware rendering by detecting network capabilities (open vs blocked) and script loading strategies (external vs inline)
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Use FrontMCP's TypeScript-first schema validation framework philosophy - all types should align with MCP protocol definitions

Applied to files:

  • docs/draft/docs/servers/discovery.mdx
  • docs/draft/docs/getting-started/welcome.mdx
📚 Learning: 2025-12-01T00:33:33.644Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-12-01T00:33:33.644Z
Learning: Applies to libs/{sdk,adapters,plugins,cli}/src/**/*.ts : Return strictly typed MCP protocol responses (GetPromptResult, ReadResourceResult, etc.) instead of `unknown` for `execute()` and `read()` methods

Applied to files:

  • docs/draft/docs/servers/discovery.mdx
🔇 Additional comments (7)
docs/draft/docs/servers/discovery.mdx (1)

11-11: LGTM! Documentation cross-reference improvement.

The explicit, capitalized link text enhances readability and consistency across the discovery documentation. The note clearly directs readers to the appropriate pages for authoring guidance while maintaining focus on MCP wire format details.

docs/draft/docs/authentication/demo-servers.mdx (3)

56-62: LGTM! Transport configuration correctly reflects the API restructuring.

The transport configuration is now properly shown as a top-level field, aligning with the API changes that moved it out of the nested auth.transport structure. The settings appropriately demonstrate public mode with stateful and streamable HTTP enabled.


90-97: LGTM! Orchestrated mode correctly demonstrates sessionMode configuration.

The transport configuration properly includes sessionMode: 'stateful' (line 92), which aligns with the API restructuring that moved sessionMode to the top-level transport object. This is appropriate for the stateful OAuth flow used in orchestrated mode.


124-130: LGTM! Transport configuration is consistent with the API restructuring.

The top-level transport field correctly reflects the moved configuration structure, maintaining consistency across all three demo examples.

docs/draft/docs.json (2)

36-36: LGTM! Comprehensive SEO keywords added.

The expanded keyword list effectively covers the project's core features and technologies, which should improve discoverability for users searching for MCP-related frameworks, authentication solutions, and UI tooling.


90-91: All newly referenced documentation pages exist in the repository. The navigation structure additions are properly backed by documentation files and will not result in broken links.

docs/draft/docs/getting-started/quickstart.mdx (1)

345-345: Navigation links have been verified and exist.

Both target pages are correctly set up in the documentation:

  • /docs/authentication/overview exists with proper content about the three-tier authentication system
  • /docs/extensibility/plugins exists with proper documentation about plugin extensions

The API changes in the code example (lines 468-472) correctly reflect accessing logger and auth info through the context object, consistent with the SDK's FrontMcpContext pattern documented throughout the codebase.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

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

⚠️ Outside diff range comments (2)
docs/draft/docs/authentication/demo-servers.mdx (1)

182-182: Fix inconsistent anchor reference.

Line 182 still uses the broken #transport-controls anchor, while lines 103 and 172 were correctly updated to use #transport. This inconsistency will result in a broken link.

🔎 Proposed fix
-  <Card title="Transport controls" icon="server" href="/docs/servers/server#transport-controls">
+  <Card title="Transport controls" icon="server" href="/docs/servers/server#transport">
docs/draft/docs/servers/tools.mdx (1)

41-53: Remove incorrect ToolContext import and extends clauses from all tool class examples.

Class-based tools in @frontmcp/sdk should use the @tool decorator without extending a base class. The import of ToolContext on line 41 is incorrect—it does not exist in the official SDK exports. All tool classes (lines 49, 172, 311, 392, 449, 504, 530, 575, 617, 712, etc.) should remove the extends ToolContext clause and use plain class syntax instead.

Update the example to:

import { Tool } from '@frontmcp/sdk';
import { z } from 'zod';

@Tool({
  name: 'greet',
  description: 'Greets a user by name',
  inputSchema: { name: z.string() },
})
class GreetTool {
  async execute({ name }: { name: string }) {
    return `Hello, ${name}!`;
  }
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 24e08ec and 548dee5.

📒 Files selected for processing (3)
  • docs/draft/docs/authentication/demo-servers.mdx (4 hunks)
  • docs/draft/docs/getting-started/quickstart.mdx (2 hunks)
  • docs/draft/docs/servers/tools.mdx (12 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/draft/docs/getting-started/quickstart.mdx
🧰 Additional context used
📓 Path-based instructions (2)
docs/draft/docs/**

⚙️ CodeRabbit configuration file

docs/draft/docs/**: This folder holds the draft/source docs that humans are expected to edit. When authors want to add or change documentation, they should do it here. The Codex workflow uses these drafts, together with the code diff, to generate the latest docs under docs/docs/. As a reviewer: - Encourage contributors to add/update content here instead of docs/docs/. - It is fine to do structural/content feedback here (clarity, examples, etc).

Files:

  • docs/draft/docs/servers/tools.mdx
  • docs/draft/docs/authentication/demo-servers.mdx
docs/**

⚙️ CodeRabbit configuration file

docs/**: Repository documentation for the SDK, using MDX and hosted by Mintlify. See more specific rules for: - docs/docs/** (latest rendered docs, automation-only) - docs/v/** (archived versions, read-only) - docs/draft/docs/** (human-editable drafts) - docs/blogs/** (blogs, human edited) - docs/docs.json (Mintlify navigation)

Files:

  • docs/draft/docs/servers/tools.mdx
  • docs/draft/docs/authentication/demo-servers.mdx
🧠 Learnings (1)
📓 Common learnings
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Applies to libs/ui/src/**/*.test.ts : Test behavior across platform configurations (OpenAI, Claude, Gemini, ngrok) where applicable
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.965Z
Learning: Support platform-aware rendering by detecting network capabilities (open vs blocked) and script loading strategies (external vs inline)
⏰ 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: Build Libraries
  • GitHub Check: Lint & Format Checks
🔇 Additional comments (5)
docs/draft/docs/authentication/demo-servers.mdx (4)

56-62: LGTM! Transport configuration correctly moved to top-level.

The transport configuration has been appropriately extracted from the auth object to a top-level option, aligning with the API changes described in this PR.


90-97: LGTM! Transport and sessionMode correctly relocated.

The transport configuration and sessionMode have been appropriately moved to the top-level transport block, consistent with the public API changes in this PR.


103-103: LGTM! Link reference correctly updated.

The link text and anchor have been updated to reflect the transport configuration's new location at the top level, and the anchor #transport matches the target heading.


172-172: LGTM! Previous broken anchor issue resolved.

The link now correctly uses the #transport anchor, addressing the concern raised in the previous review about the broken #transport-controls reference.

docs/draft/docs/servers/tools.mdx (1)

172-794: Systematic update to extend ToolContext is consistent.

All class-based tool examples throughout the document have been consistently updated to extend ToolContext. This includes:

  • CalculateTotalTool (line 172)
  • CreateUserTool (line 311)
  • ContextExampleTool (line 392)
  • TracedTool (line 449)
  • CalculateTool (line 504)
  • CreateGitHubIssueTool (line 530)
  • UpdateUserStatusTool (line 575)
  • WriteFileTool (line 617)
  • GetWeatherTool (line 712)
  • GetOrderTool (line 794)

The consistency suggests this is an intentional documentation update. Verify this matches the actual SDK pattern as noted in the previous comment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants