Skip to content

Conversation

@frontegg-david
Copy link
Contributor

@frontegg-david frontegg-david commented Nov 26, 2025

Summary by CodeRabbit

  • New Features

    • Ownership-aware prompt registry with listing, subscriptions, exportable names and server capability reporting
    • New flows for listing prompts and fetching prompt outputs; supports class- and function-style prompts and multiple result formats
    • Demo app: example prompts and resources added
  • Bug Fixes

    • More specific prompt errors and stricter validation for inputs/outputs
  • Documentation

    • Expanded prompts guide with examples, registration, return formats, and MCP integration
  • Tests

    • Comprehensive tests for prompts, registry, flows, and utilities

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 26, 2025

Walkthrough

Adds a complete Prompts subsystem: registry with ownership/adoption/indexing and export resolution, PromptInstance and PromptContext, flows for listing/getting prompts, utilities, events, domain errors, scope and adapter integration, extensive tests and mocks, demo prompts/resources, docs updates, and CI workflow tweaks.

Changes

Cohort / File(s) Summary
Mocks & Test Utilities
libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts, libs/sdk/src/__test-utils__/mocks/provider-registry.mock.ts
New mock builders for prompt registries/entries and enhanced provider-registry mock (owner, scope, readiness, registry management, typed overrides, updated signatures).
Prompt Core: registry, instance, types, utils, events, barrel
libs/sdk/src/prompt/prompt.registry.ts, libs/sdk/src/prompt/prompt.instance.ts, libs/sdk/src/prompt/prompt.types.ts, libs/sdk/src/prompt/prompt.utils.ts, libs/sdk/src/prompt/prompt.events.ts, libs/sdk/src/prompt/index.ts
New PromptRegistry with adoption/lineage/indexing/export resolution/subscribe and owner wiring; PromptInstance/PromptContext implementation (including FunctionPromptContext), shared types/defaults and utilities, prompt change emitter, and new barrel exports.
Flows (list & get)
libs/sdk/src/prompt/flows/get-prompt.flow.ts, libs/sdk/src/prompt/flows/prompts-list.flow.ts
New multi-stage GetPromptFlow and PromptsListFlow: input validation, discovery, conflict resolution, execution, output validation, and FlowControl integration.
Entry & Interface surface
libs/sdk/src/common/entries/prompt.entry.ts, libs/sdk/src/common/entries/scope.entry.ts, libs/sdk/src/common/interfaces/prompt.interface.ts, libs/sdk/src/common/interfaces/internal/registry.interface.ts
Extended PromptEntry (owner/name/fullName + abstract methods); added PromptContext, PromptInterface, ctor args and related types; ScopeEntry now exposes prompts getter; PromptRegistryInterface updated (owner field, getPrompts includeHidden?, findByName).
Errors & Re-exports
libs/sdk/src/errors/mcp.error.ts, libs/sdk/src/errors/index.ts
Added PromptNotFoundError and PromptExecutionError; re-exported errors via errors index.
Scope & Integration
libs/sdk/src/scope/scope.instance.ts, libs/sdk/src/app/instances/app.local.instance.ts, libs/sdk/src/plugin/plugin.registry.ts, libs/sdk/src/transport/adapters/transport.local.adapter.ts
Integrated PromptRegistry into Scope initialization and accessors; PromptRegistry constructed with owner in app/plugin instances; transport adapter advertises prompts capability.
Tests: prompt unit & flow tests
libs/sdk/src/prompt/__tests__/*, libs/sdk/src/prompt/flows/__tests__/*
Large Jest suites for decorators, instances, registry, utils, and flows covering valid, invalid, and edge cases.
Demo app: prompts & resources
apps/demo/src/apps/expenses/**
Added expense demo prompts and resources, barrels, and wired prompts/resources into demo app metadata.
Docs & CI
docs/draft/docs/servers/prompts.mdx, docs/*, .github/workflows/update-draft-docs.yml, README.md, CLAUDE.md
Expanded prompts documentation, docs tweaks across servers/tools/resources, updated CI docs workflow (Codex home config), and minor README/CLAUDE edits.
Schemas & annotations
libs/sdk/src/common/schemas/annotated-class.schema.ts
Extended annotated-class schema to accept function-style builders for prompts/resources and added resource template tokens.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant GetPromptFlow
    participant PromptRegistry
    participant PromptInstance
    participant PromptContext

    Client->>GetPromptFlow: requests prompts/get (name + args + auth)
    GetPromptFlow->>GetPromptFlow: parseInput (validate method & payload)
    GetPromptFlow->>PromptRegistry: findByName(name)
    PromptRegistry-->>GetPromptFlow: PromptInstance | undefined

    alt prompt found
        GetPromptFlow->>PromptInstance: create(parsedArgs, { authInfo, scope, providers })
        PromptInstance-->>PromptContext: instantiate context (owner bound)
        GetPromptFlow->>PromptContext: execute(parsedArgs)
        PromptContext-->>GetPromptFlow: raw output (or throw)
        GetPromptFlow->>PromptInstance: safeParseOutput(raw)
        PromptInstance-->>GetPromptFlow: ParsedPromptResult
        GetPromptFlow-->>Client: respond(parsed result)
    else not found
        GetPromptFlow-->>Client: throw PromptNotFoundError
    end
Loading
sequenceDiagram
    participant Client
    participant PromptsListFlow
    participant PromptRegistry
    participant Resolver

    Client->>PromptsListFlow: requests prompts/list (cursor?)
    PromptsListFlow->>PromptsListFlow: parseInput (validate method)
    PromptsListFlow->>PromptRegistry: getPrompts()
    PromptRegistry-->>PromptsListFlow: PromptInstance[]
    PromptsListFlow->>Resolver: resolveConflicts(base names + owner keys)
    Resolver-->>PromptsListFlow: resolved names (prefixed if conflicts)
    PromptsListFlow->>PromptsListFlow: map to descriptors (name/title/args/icons)
    PromptsListFlow-->>Client: respond(list of prompt descriptors)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas needing extra attention:

  • libs/sdk/src/prompt/prompt.registry.ts — adoption/lineage, indexing, export/name resolution, subscribe semantics, owner propagation.
  • libs/sdk/src/prompt/prompt.instance.ts — PromptContext construction, FunctionPromptContext, parse/safeParseOutput and FlowControl interplay.
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts & prompts-list.flow.ts — multi-stage state transitions, error mapping, and logging.
  • Public type/interface changes: libs/sdk/src/common/entries/prompt.entry.ts and libs/sdk/src/common/interfaces/* — verify all implementations compile and conform.
  • Test mocks: libs/sdk/src/__test-utils__ updates must match runtime signatures (owner, ready, getActiveScope, createViews).

Possibly related PRs

Poem

🐰
I hopped through tokens, metadata in tow,
Built burrows of prompts where ideas grow.
Registries hum, flows leap and run,
Messages wag beneath the sun,
A rabbit cheers — the prompts now glow!

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 title clearly and concisely summarizes the main change: adding MCP prompts support (both list and content operations) to the SDK.
Docstring Coverage ✅ Passed Docstring coverage is 92.86% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch add-support-for-prompts

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

@frontegg-david frontegg-david changed the base branch from main to add-support-for-resources November 26, 2025 05:30
@agentfront agentfront deleted a comment from coderabbitai bot Nov 26, 2025
@frontegg-david
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 26, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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 (24)
libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts (2)

11-12: Consider stronger typing for the overrides parameter.

Per coding guidelines, strict TypeScript mode should avoid any types without justification. Consider using a more specific type or at least documenting why any is needed here.

-export function createMockPromptRegistry(overrides: Partial<any> = {}) {
+export function createMockPromptRegistry(overrides: Partial<Record<string, unknown>> = {}) {

55-61: Unused parameter opts in exportResolvedNames.

The opts parameter is declared but never used in the implementation. Consider removing it or documenting if it's for API compatibility.

-    exportResolvedNames: jest.fn((opts?: any) => {
+    exportResolvedNames: jest.fn(() => {
libs/sdk/src/index.ts (1)

15-18: Prompt hook exports look consistent with existing hook pattern

PromptHook and ListPromptsHook follow the same FlowHooksOf('<domain>:<action>') pattern as tools/resources; this is a sensible public API surface. Make sure the high‑level SDK docs draft under docs/draft/docs/** is updated to mention these new hooks so consumers discover them.

libs/sdk/src/common/interfaces/internal/registry.interface.ts (1)

140-152: Prompt registry interface mostly matches implementation; consider exposing includeHidden

Adding owner: EntryOwnerRef and findByName brings the interface in line with the new PromptRegistry behavior. Since the implementation also supports getPrompts(includeHidden?: boolean), you may want to update the interface signature to getPrompts(includeHidden?: boolean): PromptEntry[]; so callers using the interface (e.g., via Scope.prompts) can opt into hidden prompts without casting.

libs/sdk/src/prompt/__tests__/prompt.registry.test.ts (2)

5-33: Consider reusing shared provider-registry mocks to avoid drift

The local createMockProviderRegistry / createMockScope helpers duplicate behavior that likely exists under __test-utils__/mocks (e.g., provider-registry mocks). Reusing the shared mocks would reduce duplication and keep these tests aligned if provider behavior evolves.


403-418: Strengthen listByOwner assertion to validate behavior

expect(owned.length).toBeGreaterThanOrEqual(0) will always pass and doesn’t verify that listByOwner actually returns prompts for the given owner. If the intended behavior is that prompts from owner are discoverable, assert a specific length (e.g., toBe(1)) or at least toBeGreaterThan(0) and validate the prompt name/owner.

libs/sdk/src/prompt/__tests__/prompt.instance.test.ts (1)

29-456: PromptInstance behavior is well covered; a couple of edge paths could be added

The tests exercise constructor wiring, metadata exposure, argument parsing, multiple output shapes, and safeParseOutput success cases; they give good confidence in PromptInstance’s core behavior. As a follow‑up, consider adding (1) a small test for create() to ensure the correct context type is instantiated for each PromptKind, and (2) a safeParseOutput failure test that feeds clearly invalid output and asserts { success: false, error instanceof Error } to lock in the error path.

libs/sdk/src/prompt/__tests__/prompt.utils.test.ts (2)

191-194: Consider verifying the expected text for undefined input.

The test verifies that a message is created but doesn't assert on the expected text content. For consistency with other primitive tests (null → 'null', number → '42', boolean → 'true'), consider adding an assertion for what text is expected for undefined.

     it('should handle undefined raw value', () => {
       const result = buildParsedPromptResult(undefined, metadata);
       expect(result.messages).toHaveLength(1);
+      expect((result.messages[0].content as any).text).toBe('undefined');
     });

209-237: Consider adding assertions for actual dependency content.

The promptDiscoveryDeps tests only verify that the result is an array, but don't assert on the actual dependency values or expected behavior. This makes it difficult to catch regressions if the function's behavior changes.

     it('should return empty array for class without dependencies', () => {
       @Prompt({
         name: 'no-deps',
         arguments: [],
       })
       class NoDeps {
         execute(args: Record<string, string>) {
           return { messages: [] };
         }
       }

       const record = normalizePrompt(NoDeps);
       const deps = promptDiscoveryDeps(record);
-      expect(Array.isArray(deps)).toBe(true);
+      expect(deps).toEqual([]);
     });

     it('should return empty array for function prompt', () => {
       const functionPrompt = prompt({
         name: 'func-deps',
         arguments: [],
       })((args) => ({
         messages: [],
       }));

       const record = normalizePrompt(functionPrompt);
       const deps = promptDiscoveryDeps(record);
-      expect(Array.isArray(deps)).toBe(true);
+      expect(deps).toEqual([]);
     });
libs/sdk/src/prompt/flows/prompts-list.flow.ts (1)

76-77: Consider typing params more strictly.

The params variable is typed as any. Since you're only accessing params?.cursor, you could use a more specific type or inline the access.

     let method!: string;
-    let params: any;
+    let params: { cursor?: string } | undefined;
libs/sdk/src/prompt/flows/__tests__/prompts-list.flow.test.ts (2)

369-443: Add specific error type assertions.

The invalid configuration tests verify that an error is thrown but don't assert on the specific error type. Per the coding guidelines, error class instanceof checks should be tested. This ensures the correct error types are thrown for each scenario.

+import { InvalidMethodError, InvalidInputError } from '../../../errors';

// ... in the tests:

     it('should throw InvalidMethodError for wrong method', async () => {
       const promptRegistry = createMockPromptRegistry();
       const input = {
         request: { method: 'tools/list', params: {} },
         ctx: {},
       };

       const result = await runFlow(input, createMockDependencies(promptRegistry));

       expect(result.success).toBe(false);
       expect(result.error).toBeDefined();
-      // Error is either InvalidMethodError with method name or InvalidInputError
-      expect(result.error).toBeInstanceOf(Error);
+      expect(result.error).toBeInstanceOf(InvalidMethodError);
     });

     it('should throw InvalidInputError for missing request', async () => {
       const promptRegistry = createMockPromptRegistry();
       const input = {
         ctx: {},
       };

       const result = await runFlow(input, createMockDependencies(promptRegistry));

       expect(result.success).toBe(false);
-      expect(result.error).toBeDefined();
+      expect(result.error).toBeInstanceOf(InvalidInputError);
     });

Based on learnings, error class instanceof checks must be tested.


82-86: Consider testing stage isolation.

The runFlow helper runs all stages sequentially. Consider adding tests that verify individual stage behavior in isolation, or test that errors in early stages prevent later stages from running.

libs/sdk/src/prompt/prompt.events.ts (1)

26-28: Consider adding error handling for listener exceptions.

If a listener throws an exception, the current implementation will stop notifying remaining listeners. Consider wrapping each listener call in a try-catch to ensure all listeners are notified regardless of individual failures.

   emit(e: PromptChangeEvent) {
-    for (const l of [...this.listeners]) l(e);
+    for (const l of [...this.listeners]) {
+      try {
+        l(e);
+      } catch (err) {
+        // Optionally log error but continue notifying other listeners
+        console.error('PromptEmitter listener error:', err);
+      }
+    }
   }
libs/sdk/src/prompt/flows/__tests__/get-prompt.flow.test.ts (1)

366-472: Add instanceof checks for error classes.

The error scenario tests verify that errors occur but don't confirm the specific error class types. Per coding guidelines, error class instanceof checks should be tested.

Consider adding assertions like:

 it('should throw InvalidMethodError for wrong method', async () => {
   // ...
   expect(result.success).toBe(false);
   expect(result.error).toBeDefined();
-  // Error is either InvalidMethodError with method name or InvalidInputError
-  expect(result.error).toBeInstanceOf(Error);
+  // Import the specific error class and verify
+  expect(result.error).toBeInstanceOf(InvalidMethodError);
 });

Apply similar changes for PromptNotFoundError, InvalidInputError, and other domain-specific error classes.

libs/sdk/src/prompt/prompt.instance.ts (1)

73-81: Consider exhaustive type checking pattern.

The default case correctly throws for unhandled kinds. For stronger type safety, consider the exhaustive check pattern:

       case PromptKind.FUNCTION:
         return new FunctionPromptContext(record as PromptFunctionTokenRecord, promptCtorArgs);
       default:
-        // This should be unreachable if all PromptKind values are handled
-        throw new Error(`Unhandled prompt kind: ${(record as any).kind}`);
+        // Exhaustive check - TypeScript will error if a new PromptKind is added
+        const _exhaustive: never = record;
+        throw new Error(`Unhandled prompt kind: ${(record as { kind: string }).kind}`);
     }

This ensures compile-time errors if new PromptKind values are added without updating this switch.

libs/sdk/src/common/interfaces/prompt.interface.ts (1)

52-52: _error field is set but never accessed.

The _error field is assigned in fail() (line 112) but has no getter or public accessor. If this is intended for debugging or error inspection, consider adding a getter:

 private _error?: Error;
+
+public get error(): Error | undefined {
+  return this._error;
+}

Otherwise, if it's not needed, consider removing it to avoid confusion.

libs/sdk/src/prompt/prompt.utils.ts (3)

78-85: Add exhaustiveness check for switch statement.

The switch on rec.kind lacks a default case. While TypeScript may infer exhaustiveness from PromptKind, an explicit check ensures future-proofing if new kinds are added.

 export function promptDiscoveryDeps(rec: PromptRecord): Token[] {
   switch (rec.kind) {
     case PromptKind.FUNCTION:
       return depsOfFunc(rec.provide, 'discovery');
     case PromptKind.CLASS_TOKEN:
       return depsOfClass(rec.provide, 'discovery');
+    default: {
+      const _exhaustive: never = rec.kind;
+      throw new Error(`Unknown prompt kind: ${_exhaustive}`);
+    }
   }
 }

50-73: Consider adding a type guard or documenting the any usage.

The item: any parameter is justified given the need to handle multiple input types (function-prompt or class), but per coding guidelines requiring strict TypeScript mode with no any without justification, consider either:

  1. Adding a JSDoc explaining the any usage
  2. Creating a union type for valid prompt inputs
+/**
+ * Normalize any prompt input (class or function) to a PromptRecord.
+ * @param item - Accepts function-prompt handlers or class decorators; `any` is used
+ *               because the input may be a decorated function, a class, or an invalid type.
+ */
 export function normalizePrompt(item: any): PromptRecord {

125-136: Type assertion without validation may cause runtime issues.

In normalizePromptMessage, the check at line 127 validates msg.role and msg.content exist but doesn't validate their types. A malformed object with non-string role or invalid content structure would pass through.

 function normalizePromptMessage(msg: any): PromptMessage {
   // If already in correct format
-  if (msg && msg.role && msg.content) {
+  if (
+    msg &&
+    typeof msg.role === 'string' &&
+    msg.content &&
+    typeof msg.content === 'object'
+  ) {
     return msg as PromptMessage;
   }
libs/sdk/src/prompt/flows/get-prompt.flow.ts (2)

115-119: Mutating rawInput for hook filtering is a side effect that may cause issues.

Directly mutating this.rawInput to inject _promptOwnerId couples the flow to internal hook filtering mechanics and could cause unexpected behavior if rawInput is used elsewhere or if it's frozen/sealed.

Consider using a dedicated context object or flow state for hook filtering metadata.

     // Store prompt owner ID in the flow input for hook filtering.
     // This mutation allows hooks to filter by prompt owner during execution.
     if (prompt.owner) {
-      (this.rawInput as any)._promptOwnerId = prompt.owner.id;
+      // Consider storing in state instead:
+      this.state.set('promptOwnerId', prompt.owner.id);
     }

If mutation is required for hook infrastructure compatibility, add a comment explaining why state cannot be used.


155-176: Redundant parseArguments call in execute stage.

parseArguments is called in both createPromptContext (line 135) and execute (line 169). If the prompt context already has parsed arguments, re-parsing is unnecessary overhead and could produce inconsistent results if state changes between stages.

Consider storing parsed arguments in state during createPromptContext and reusing them:

   @Stage('createPromptContext')
   async createPromptContext() {
     // ...
     try {
       // Parse and validate arguments
       const parsedArgs = prompt.parseArguments(input.arguments);
+      this.state.set('parsedArgs', parsedArgs);
       // ...
   }

   @Stage('execute')
   async execute() {
     // ...
     try {
-      // Parse arguments again for execution
-      const parsedArgs = this.state.required.prompt.parseArguments(input.arguments);
+      const parsedArgs = this.state.required.parsedArgs;
       promptContext.output = await promptContext.execute(parsedArgs);
libs/sdk/src/prompt/prompt.registry.ts (3)

188-193: Use type-safe check for hideFromDiscovery.

The check (meta as any).hideFromDiscovery bypasses type safety. Since PromptMetadata may or may not include this field, use optional chaining with a type guard or extend the type.

     return all
       .filter((r) => {
         const meta = r.instance.metadata;
-        const hidden = 'hideFromDiscovery' in meta && (meta as any).hideFromDiscovery === true;
+        const hidden = 'hideFromDiscovery' in meta && meta.hideFromDiscovery === true;
         return !hidden || includeHidden;
       })
       .map((r) => r.instance);

If hideFromDiscovery is a valid metadata property, ensure it's added to the PromptMetadata type definition.


327-337: Extract magic number and nested function for clarity.

The disambiguate function is nested inside exportResolvedNames, which is fine for encapsulation, but the magic number 10000 should be a named constant.

+const MAX_DISAMBIGUATE_ATTEMPTS = 10000;
+
 // Inside exportResolvedNames:
     function disambiguate(candidate: string, pool: Map<string, any>, cfg: Required<PromptExportOptions>): string {
       if (!pool.has(candidate)) return candidate;
-      const maxAttempts = 10000;
+      const maxAttempts = MAX_DISAMBIGUATE_ATTEMPTS;
       let n = 2;

430-432: Empty catch block silently swallows errors.

The empty catch block at line 430 silently ignores any errors from getMetadata. While this may be intentional for robustness, consider at least logging at debug/trace level for troubleshooting.

-    } catch {
-      /* ignore */
+    } catch (e) {
+      // Metadata extraction is best-effort; log at trace level for debugging
+      // this.logger?.trace?.('providerIdOf: metadata extraction failed', e);
     }
📜 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 8370531 and f60d95f.

📒 Files selected for processing (26)
  • libs/sdk/src/__test-utils__/mocks/index.ts (1 hunks)
  • libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts (1 hunks)
  • libs/sdk/src/app/instances/app.local.instance.ts (1 hunks)
  • libs/sdk/src/common/entries/prompt.entry.ts (1 hunks)
  • libs/sdk/src/common/entries/scope.entry.ts (2 hunks)
  • libs/sdk/src/common/interfaces/internal/registry.interface.ts (1 hunks)
  • libs/sdk/src/common/interfaces/prompt.interface.ts (1 hunks)
  • libs/sdk/src/errors/index.ts (1 hunks)
  • libs/sdk/src/errors/mcp.error.ts (1 hunks)
  • libs/sdk/src/index.ts (1 hunks)
  • libs/sdk/src/plugin/plugin.registry.ts (1 hunks)
  • libs/sdk/src/prompt/__tests__/prompt.decorator.test.ts (1 hunks)
  • libs/sdk/src/prompt/__tests__/prompt.instance.test.ts (1 hunks)
  • libs/sdk/src/prompt/__tests__/prompt.registry.test.ts (1 hunks)
  • libs/sdk/src/prompt/__tests__/prompt.utils.test.ts (1 hunks)
  • libs/sdk/src/prompt/flows/__tests__/get-prompt.flow.test.ts (1 hunks)
  • libs/sdk/src/prompt/flows/__tests__/prompts-list.flow.test.ts (1 hunks)
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts (1 hunks)
  • libs/sdk/src/prompt/flows/prompts-list.flow.ts (1 hunks)
  • libs/sdk/src/prompt/index.ts (1 hunks)
  • libs/sdk/src/prompt/prompt.events.ts (1 hunks)
  • libs/sdk/src/prompt/prompt.instance.ts (1 hunks)
  • libs/sdk/src/prompt/prompt.registry.ts (1 hunks)
  • libs/sdk/src/prompt/prompt.types.ts (1 hunks)
  • libs/sdk/src/prompt/prompt.utils.ts (1 hunks)
  • libs/sdk/src/scope/scope.instance.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use strict TypeScript mode with no any types without strong justification

Files:

  • libs/sdk/src/index.ts
  • libs/sdk/src/__test-utils__/mocks/index.ts
  • libs/sdk/src/app/instances/app.local.instance.ts
  • libs/sdk/src/common/entries/scope.entry.ts
  • libs/sdk/src/errors/index.ts
  • libs/sdk/src/prompt/index.ts
  • libs/sdk/src/prompt/flows/prompts-list.flow.ts
  • libs/sdk/src/prompt/__tests__/prompt.utils.test.ts
  • libs/sdk/src/prompt/__tests__/prompt.decorator.test.ts
  • libs/sdk/src/prompt/__tests__/prompt.instance.test.ts
  • libs/sdk/src/prompt/prompt.utils.ts
  • libs/sdk/src/prompt/flows/__tests__/prompts-list.flow.test.ts
  • libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts
  • libs/sdk/src/prompt/__tests__/prompt.registry.test.ts
  • libs/sdk/src/prompt/flows/__tests__/get-prompt.flow.test.ts
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts
  • libs/sdk/src/prompt/prompt.events.ts
  • libs/sdk/src/prompt/prompt.types.ts
  • libs/sdk/src/common/interfaces/prompt.interface.ts
  • libs/sdk/src/errors/mcp.error.ts
  • libs/sdk/src/plugin/plugin.registry.ts
  • libs/sdk/src/scope/scope.instance.ts
  • libs/sdk/src/common/entries/prompt.entry.ts
  • libs/sdk/src/common/interfaces/internal/registry.interface.ts
  • libs/sdk/src/prompt/prompt.instance.ts
  • libs/sdk/src/prompt/prompt.registry.ts
**/src/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/src/index.ts: Barrel exports (index.ts) must export everything users need without legacy exports or aliased names
Don't add backwards compatibility exports in new libraries; use direct imports instead

Files:

  • libs/sdk/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/sdk/src/index.ts
  • libs/sdk/src/__test-utils__/mocks/index.ts
  • libs/sdk/src/app/instances/app.local.instance.ts
  • libs/sdk/src/common/entries/scope.entry.ts
  • libs/sdk/src/errors/index.ts
  • libs/sdk/src/prompt/index.ts
  • libs/sdk/src/prompt/flows/prompts-list.flow.ts
  • libs/sdk/src/prompt/__tests__/prompt.utils.test.ts
  • libs/sdk/src/prompt/__tests__/prompt.decorator.test.ts
  • libs/sdk/src/prompt/__tests__/prompt.instance.test.ts
  • libs/sdk/src/prompt/prompt.utils.ts
  • libs/sdk/src/prompt/flows/__tests__/prompts-list.flow.test.ts
  • libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts
  • libs/sdk/src/prompt/__tests__/prompt.registry.test.ts
  • libs/sdk/src/prompt/flows/__tests__/get-prompt.flow.test.ts
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts
  • libs/sdk/src/prompt/prompt.events.ts
  • libs/sdk/src/prompt/prompt.types.ts
  • libs/sdk/src/common/interfaces/prompt.interface.ts
  • libs/sdk/src/errors/mcp.error.ts
  • libs/sdk/src/plugin/plugin.registry.ts
  • libs/sdk/src/scope/scope.instance.ts
  • libs/sdk/src/common/entries/prompt.entry.ts
  • libs/sdk/src/common/interfaces/internal/registry.interface.ts
  • libs/sdk/src/prompt/prompt.instance.ts
  • libs/sdk/src/prompt/prompt.registry.ts
**/*.{test,spec}.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{test,spec}.{ts,tsx}: In Jest test files, don't use prefixes like 'PT-001' in test names; use clean, descriptive names
Constructor validation tests must not be skipped and error class instanceof checks must be tested
Test all code paths including error scenarios

Files:

  • libs/sdk/src/prompt/__tests__/prompt.utils.test.ts
  • libs/sdk/src/prompt/__tests__/prompt.decorator.test.ts
  • libs/sdk/src/prompt/__tests__/prompt.instance.test.ts
  • libs/sdk/src/prompt/flows/__tests__/prompts-list.flow.test.ts
  • libs/sdk/src/prompt/__tests__/prompt.registry.test.ts
  • libs/sdk/src/prompt/flows/__tests__/get-prompt.flow.test.ts
🧠 Learnings (5)
📚 Learning: 2025-11-25T19:34:36.034Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T19:34:36.034Z
Learning: Applies to **/src/index.ts : Don't add backwards compatibility exports in new libraries; use direct imports instead

Applied to files:

  • libs/sdk/src/__test-utils__/mocks/index.ts
📚 Learning: 2025-11-25T19:34:36.034Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T19:34:36.034Z
Learning: Applies to **/src/index.ts : Barrel exports (index.ts) must export everything users need without legacy exports or aliased names

Applied to files:

  • libs/sdk/src/__test-utils__/mocks/index.ts
  • libs/sdk/src/errors/index.ts
  • libs/sdk/src/prompt/index.ts
📚 Learning: 2025-11-25T19:34:36.034Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T19:34:36.034Z
Learning: Applies to **/*.{test,spec}.{ts,tsx} : Test all code paths including error scenarios

Applied to files:

  • libs/sdk/src/prompt/__tests__/prompt.utils.test.ts
  • libs/sdk/src/prompt/flows/__tests__/prompts-list.flow.test.ts
  • libs/sdk/src/prompt/flows/__tests__/get-prompt.flow.test.ts
📚 Learning: 2025-11-25T19:34:36.034Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T19:34:36.034Z
Learning: Applies to **/*.{test,spec}.{ts,tsx} : Constructor validation tests must not be skipped and error class `instanceof` checks must be tested

Applied to files:

  • libs/sdk/src/prompt/__tests__/prompt.instance.test.ts
📚 Learning: 2025-11-25T19:34:36.034Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T19:34:36.034Z
Learning: Applies to **/*.{test,spec}.{ts,tsx} : In Jest test files, don't use prefixes like 'PT-001' in test names; use clean, descriptive names

Applied to files:

  • libs/sdk/src/prompt/__tests__/prompt.instance.test.ts
  • libs/sdk/src/prompt/__tests__/prompt.registry.test.ts
🧬 Code graph analysis (11)
libs/sdk/src/app/instances/app.local.instance.ts (1)
libs/sdk/src/prompt/prompt.registry.ts (1)
  • PromptRegistry (33-440)
libs/sdk/src/common/entries/scope.entry.ts (1)
libs/sdk/src/common/interfaces/internal/registry.interface.ts (1)
  • PromptRegistryInterface (140-152)
libs/sdk/src/prompt/flows/prompts-list.flow.ts (1)
libs/sdk/src/errors/index.ts (2)
  • InvalidInputError (12-12)
  • InvalidMethodError (14-14)
libs/sdk/src/prompt/__tests__/prompt.instance.test.ts (3)
libs/sdk/src/__test-utils__/mocks/provider-registry.mock.ts (1)
  • createMockProviderRegistry (12-51)
libs/sdk/src/prompt/prompt.utils.ts (1)
  • normalizePrompt (50-73)
libs/sdk/src/prompt/prompt.instance.ts (1)
  • PromptInstance (22-133)
libs/sdk/src/prompt/flows/__tests__/prompts-list.flow.test.ts (1)
libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts (3)
  • createMockPromptRegistry (11-77)
  • createMockPromptEntry (82-162)
  • addPromptToMock (167-185)
libs/sdk/src/prompt/flows/__tests__/get-prompt.flow.test.ts (1)
libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts (3)
  • createMockPromptRegistry (11-77)
  • createMockPromptEntry (82-162)
  • addPromptToMock (167-185)
libs/sdk/src/prompt/prompt.types.ts (2)
libs/sdk/src/prompt/prompt.instance.ts (1)
  • PromptInstance (22-133)
libs/sdk/src/prompt/prompt.registry.ts (1)
  • PromptRegistry (33-440)
libs/sdk/src/common/interfaces/prompt.interface.ts (3)
libs/sdk/src/common/interfaces/internal/registry.interface.ts (1)
  • ProviderRegistryInterface (82-93)
libs/sdk/src/app/instances/app.local.instance.ts (1)
  • providers (53-55)
libs/sdk/src/scope/scope.instance.ts (1)
  • providers (149-151)
libs/sdk/src/scope/scope.instance.ts (1)
libs/sdk/src/prompt/prompt.registry.ts (1)
  • PromptRegistry (33-440)
libs/sdk/src/common/entries/prompt.entry.ts (1)
libs/sdk/src/common/interfaces/prompt.interface.ts (1)
  • PromptInterface (13-15)
libs/sdk/src/prompt/prompt.instance.ts (5)
libs/sdk/src/scope/scope.instance.ts (3)
  • Scope (30-192)
  • providers (149-151)
  • hooks (141-143)
libs/sdk/src/hooks/hook.registry.ts (1)
  • HookRegistry (19-193)
libs/sdk/src/common/entries/prompt.entry.ts (2)
  • PromptGetExtra (21-23)
  • ParsedPromptResult (25-25)
libs/sdk/src/common/interfaces/prompt.interface.ts (2)
  • scope (77-79)
  • PromptCtorArgs (26-32)
libs/sdk/src/prompt/prompt.utils.ts (1)
  • buildParsedPromptResult (90-120)
🔇 Additional comments (34)
libs/sdk/src/errors/index.ts (1)

10-11: LGTM!

The new prompt error exports follow the established pattern and maintain consistency with other error types like ToolNotFoundError and ResourceNotFoundError. Based on learnings, the barrel exports are clean without legacy exports or aliases.

libs/sdk/src/errors/mcp.error.ts (1)

173-202: LGTM!

The new error classes follow the established patterns perfectly:

  • PromptNotFoundError mirrors ToolNotFoundError and ResourceNotFoundError with consistent message formatting and 404 status.
  • PromptExecutionError mirrors ResourceReadError and ToolExecutionError, correctly storing originalError and overriding getInternalMessage() to include the stack trace.
libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts (1)

1-162: Well-structured mock utilities for PromptRegistry testing.

The mock factory provides comprehensive test utilities with proper Jest mocks for all registry operations. The addPromptToMock helper correctly rewires the mock implementations to reflect registry state changes.

libs/sdk/src/__test-utils__/mocks/index.ts (1)

11-11: LGTM!

The new mock export follows the established pattern and properly exposes the prompt registry mock utilities for test consumers. Based on learnings, this maintains clean barrel exports without legacy aliases.

libs/sdk/src/common/entries/scope.entry.ts (2)

18-19: LGTM!

The PromptRegistryInterface import is correctly added alongside other registry interface imports.


49-50: LGTM!

The abstract prompts getter follows the established pattern used by tools and resources getters, maintaining API consistency across the ScopeEntry class.

libs/sdk/src/plugin/plugin.registry.ts (1)

89-107: Owner propagation to PromptRegistry aligns with tools/resources

Passing pluginOwner into PromptRegistry keeps prompt ownership consistent with tools/resources and ensures provenance/lineage features work for plugin prompts as well. No issues spotted with the initialization ordering or readiness handling.

libs/sdk/src/app/instances/app.local.instance.ts (1)

34-51: App-level prompt registry wiring is consistent and ordered correctly

Constructing this.appPrompts with appOwner and including this.appPrompts.ready in the Promise.all keeps prompts aligned with existing app tools/resources semantics and ensures everything is ready before the app is considered initialized.

libs/sdk/src/prompt/__tests__/prompt.registry.test.ts (1)

35-468: Comprehensive PromptRegistry coverage

This suite exercises registration, lookup (getPrompts, findByName, findAllByName), indexing, export naming, subscriptions, ownership, and exported lookups; it’s a solid behavioral spec for the new registry.

libs/sdk/src/prompt/index.ts (1)

1-9: Prompt barrel cleanly exposes the prompt subsystem

The barrel exports the registry, instance, supporting types/events/utils, and both prompt flows without legacy aliases, so consumers can import everything prompt‑related from a single place.

libs/sdk/src/scope/scope.instance.ts (1)

27-43: Perfect. I have all the information needed to verify the review comment. Let me analyze the findings:

Verification Summary:

  1. PromptRegistry Integration Pattern: The code at lines 27-43, 95-97, and 165-167 correctly implements the pattern:

    • Single PromptRegistry instance per Scope (line 42: private scopePrompts)
    • Initialized once in initialize() method (line 95)
    • Follows identical pattern to ToolRegistry (line 40/89-90) and ResourceRegistry (line 41/92-93)
  2. Flow Registration Mechanism: PromptRegistry.initialize() calls scope.registryFlows(GetPromptFlow, PromptsListFlow) exactly once per PromptRegistry instance, and since each Scope has only one PromptRegistry, flows are registered once per scope.

  3. Deduplication Concern: The review's concern about "multiple PromptRegistry instances registering the same prompt flows" is not applicable:

    • Multiple PromptRegistry instances exist only across different Scopes (expected and intended)
    • Within a single Scope, there is exactly one PromptRegistry instance
    • Each Scope has its own FlowRegistry, so registering the same flow class across different scopes is fine
    • FlowRegistry uses token-based deduplication (Set/Map) within each registry instance
  4. Idempotency: Even if registryFlows() were called multiple times for the same token within a FlowRegistry, the Map/Set operations would be idempotent. However, this scenario doesn't occur in practice.

Conclusion: The implementation is correct and the architectural concern raised is moot. The code safely follows the established pattern without any risk of unintended duplicate flow registrations.


Scope-level prompts registry follows the established pattern correctly

Importing PromptRegistry, storing it as the single private scopePrompts field (line 42), initializing it once during scope setup (line 95), and exposing it via the prompts getter mirrors the ToolRegistry and ResourceRegistry implementations. Each registry instance registers its flows exactly once during initialization, and each Scope maintains its own separate registries, so no duplicate flow registration occurs. The implementation is sound.

libs/sdk/src/prompt/__tests__/prompt.decorator.test.ts (1)

1-349: LGTM! Comprehensive test coverage for the prompt decorator subsystem.

The test suite provides excellent coverage for:

  • Class-based and function-based prompt decorators
  • Alias behavior (FrontMcpPrompt/frontMcpPrompt)
  • Metadata storage and retrieval
  • Validation (empty name rejection)
  • Argument definitions (full, minimal, multiple)
  • Edge cases (empty arguments, undefined optional fields)

Test names are clean and descriptive, following the coding guidelines.

libs/sdk/src/prompt/__tests__/prompt.utils.test.ts (1)

1-295: Good test coverage for prompt utilities.

The test suite covers the key utility functions with various input types and edge cases. The error scenarios for normalizePrompt are tested (lines 94-98), and the buildParsedPromptResult function is tested with multiple input formats.

libs/sdk/src/prompt/flows/prompts-list.flow.ts (2)

1-189: Well-structured flow implementation.

The four-stage flow design is clean with good separation of concerns:

  • parseInput: Input validation and method checking
  • findPrompts: Collecting prompts from registry
  • resolveConflicts: Name collision resolution with owner prefixing
  • parsePrompts: Response formatting

The conflict resolution logic (lines 132-152) correctly handles name collisions by prefixing with owner ID. Logging is comprehensive throughout.


108-110: The review comment is incorrect. The owner property on PromptEntry is explicitly declared as required at line 29 of libs/sdk/src/common/entries/prompt.entry.ts:

export abstract class PromptEntry extends BaseEntry<AnyPromptRecord, PromptInterface, PromptMetadata> {
  owner: EntryOwnerRef;

Since owner lacks the optional marker (?), TypeScript's type system enforces that all PromptEntry instances—including those returned from getPrompts()—have owner defined. The access to prompt.owner.id at lines 108-110 is therefore safe and requires no null check.

libs/sdk/src/prompt/flows/__tests__/prompts-list.flow.test.ts (1)

1-589: Comprehensive test coverage for PromptsListFlow.

The test suite provides excellent coverage including:

  • Empty and populated prompt registries
  • Name conflict resolution with owner prefixing
  • Invalid inputs (wrong method, missing request, null input)
  • Edge cases (special characters, large number of prompts, undefined fields)
  • Context propagation

Test structure is clean with well-organized describe blocks.

libs/sdk/src/prompt/prompt.events.ts (1)

1-29: Clean event emitter implementation.

The PromptEmitter class provides a simple pub/sub mechanism for prompt change events. The design is appropriate:

  • Returns unsubscribe function from on() for easy cleanup
  • Creates array copy before iteration to allow safe modification during emit
  • Types are well-defined for change events
libs/sdk/src/prompt/prompt.types.ts (1)

1-46: Well-structured type definitions with sensible defaults.

The types are cleanly defined and the DEFAULT_PROMPT_EXPORT_OPTS provides reasonable defaults. The IndexedPrompt type correctly captures the provenance and ownership model.

One consideration: the source: PromptRegistry reference creates a coupling between this types file and the registry implementation. If this causes circular import issues in the future, consider using an interface abstraction instead.

libs/sdk/src/prompt/flows/__tests__/get-prompt.flow.test.ts (3)

10-101: Well-structured test setup with comprehensive mocks.

The createMockDependencies helper and runFlow helper provide clean abstractions for testing. The FlowControl handling in the catch block correctly distinguishes between successful responses and actual failures.


103-364: Good coverage of valid configuration scenarios.

The tests thoroughly cover:

  • Basic prompt execution with arguments
  • Prompts with no arguments and optional arguments
  • Auth info propagation
  • String and array output formats

Test names are clean and descriptive, following coding guidelines.


587-774: Thorough edge case coverage.

Good testing of:

  • Special characters in prompt names
  • Namespaced names with owner prefix
  • Empty arguments
  • Null and undefined outputs with expected failure behavior

The comment on line 759 documenting expected behavior is helpful.

libs/sdk/src/prompt/prompt.instance.ts (3)

22-37: Clean constructor initialization with proper wiring.

The constructor properly initializes all required dependencies and sets up the instance with owner context. The async initialization pattern with this.ready = this.initialize() follows the established pattern in the codebase.


89-113: Argument parsing logic is correct.

The implementation properly:

  1. Validates required arguments (checking both undefined and null)
  2. Copies defined arguments to result
  3. Includes additional arguments not in the definition (pass-through behavior)

This allows flexibility for prompts that accept arbitrary additional parameters.


138-145: Simple and effective FunctionPromptContext wrapper.

The FunctionPromptContext cleanly wraps function-based prompts by delegating execution to the underlying function, passing both args and the context itself.

libs/sdk/src/common/entries/prompt.entry.ts (2)

11-19: any types justified for generic record union.

The any types in AnyPromptRecord are acceptable here because:

  1. Type<any> is needed to match class constructors with varied instance types
  2. The function signature (...args: any[]) => any provides flexibility for different prompt implementations

This pattern is common for generic unions handling heterogeneous types.


21-26: Well-defined helper types for prompt operations.

The PromptGetExtra, ParsedPromptResult, and PromptSafeTransformResult types provide clear contracts for prompt context handling and safe parsing patterns.

libs/sdk/src/common/interfaces/prompt.interface.ts (3)

34-69: Well-designed PromptContext with clear separation of concerns.

The constructor properly initializes:

  • Unique runId per execution instance
  • Stable promptId based on metadata name
  • Child logger with prompt-specific context
  • All required dependencies from PromptCtorArgs

The separation of runId (instance) vs promptId (type) is a good design for tracing and debugging.


91-108: Output management with automatic history tracking.

The setter automatically records history entries with timestamps and current stage - useful for debugging and audit trails. The respond() method cleanly records output before triggering the control flow response.


81-89: Defensive tryGet with proper error logging.

Good pattern for optional provider resolution with warning logging on failure. The error message extraction handles both Error instances and other thrown values.

libs/sdk/src/prompt/flows/get-prompt.flow.ts (2)

161-164: Silent early return when promptContext is missing may mask errors.

In the execute stage, returning early without throwing when promptContext is undefined could lead to silent failures. If createPromptContext succeeded, promptContext should always exist. If it failed, the flow should have already thrown.

Is the early return intentional for a specific scenario (e.g., optional execution)? If promptContext is required for execution, consider throwing instead:

     if (!promptContext) {
-      this.logger.warn('execute: promptContext not found, skipping execution');
-      return;
+      this.logger.error('execute: promptContext not found');
+      throw new PromptExecutionError(input.name, new Error('Prompt context not created'));
     }

22-36: Well-documented z.any() usage for complex external types.

The comments on lines 27-33 clearly justify the use of z.any() for complex external types like AuthInfo, PromptEntry, and PromptContext. This aligns with the coding guideline requiring justification for any types.

libs/sdk/src/prompt/prompt.registry.ts (3)

63-71: Constructor initialization pattern looks correct.

The pattern of storing the promise from initialize() in this.ready (inherited from RegistryAbstract) is a valid lazy-init pattern. Consumers can await registry.ready when needed. The false parameter to super() correctly disables auto-init so subclass fields initialize first.


168-174: Subscription callback may fire during initial adoption.

The subscribe call with immediate: false sets up a live listener for child changes. However, if child emits during the same tick (e.g., during its own initialization), this could cause unexpected reindexing. The subsequent this.reindex() and this.bump('reset') on lines 176-177 should handle the initial state, but verify the timing is correct.


113-113: The type cast is correct and necessary for type safety.

The instances map in RegistryAbstract is typed as Map<Token<Interface>, Interface>. Since PromptRegistry extends RegistryAbstract<PromptInstance, PromptRecord, PromptType[]>, the instances map becomes Map<Token<PromptInstance>, PromptInstance>. The token variable is typed as bare Token (from this.tokens: Set<Token>), so the cast to Token<PromptInstance> is necessary and correct to match the map's key type parameter.

Base automatically changed from add-support-for-resources to main November 26, 2025 14:48
# Conflicts:
#	libs/sdk/src/__test-utils__/mocks/index.ts
#	libs/sdk/src/app/instances/app.local.instance.ts
#	libs/sdk/src/auth/auth.registry.ts
#	libs/sdk/src/common/entries/resource.entry.ts
#	libs/sdk/src/common/entries/scope.entry.ts
#	libs/sdk/src/common/interfaces/resource.interface.ts
#	libs/sdk/src/errors/index.ts
#	libs/sdk/src/errors/mcp.error.ts
#	libs/sdk/src/index.ts
#	libs/sdk/src/plugin/plugin.registry.ts
#	libs/sdk/src/resource/__tests__/resource.utils.test.ts
#	libs/sdk/src/resource/flows/read-resource.flow.ts
#	libs/sdk/src/resource/flows/resource-templates-list.flow.ts
#	libs/sdk/src/resource/flows/resources-list.flow.ts
#	libs/sdk/src/resource/resource.events.ts
#	libs/sdk/src/resource/resource.instance.ts
#	libs/sdk/src/resource/resource.registry.ts
#	libs/sdk/src/resource/resource.types.ts
#	libs/sdk/src/resource/resource.utils.ts
#	libs/sdk/src/scope/scope.instance.ts
#	libs/sdk/src/transport/adapters/transport.local.adapter.ts
@frontegg-david
Copy link
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 26, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

♻️ Duplicate comments (1)
libs/sdk/src/common/entries/prompt.entry.ts (1)

55-64: Previous type mismatch issue has been addressed.

The parseOutput signature now correctly uses raw: unknown instead of GetPromptResult, matching the implementation in prompt.instance.ts and the docstring describing raw output normalization.

🧹 Nitpick comments (16)
.github/workflows/update-draft-docs.yml (1)

164-171: Align prompt guidance with verified MCP server availability.

The updated prompt documentation references mintlify_docs MCP server as available and usable (lines 164–166, 170). Once the MCP endpoint validity (flagged above) is confirmed, consider:

  • Explicitly documenting how Codex should query the server (e.g., available tools, expected response format).
  • Adding error-handling guidance if the MCP server is unavailable or times out.
  • Providing fallback instructions for Codex if MCP queries fail.
docs/draft/docs/servers/prompts.mdx (2)

399-411: Consider showing explicit error handling patterns.

The error handling example (lines 399-411) shows error messaging within the return value, which works but is implicit. Per the PR objectives mentioning PromptNotFoundError and PromptExecutionError, consider whether examples should showcase throwing/catching these error classes for clarity on proper error handling in prompts.

This could be clarified by adding a brief note or additional example showing proper error handling with error classes, but the current approach is functional.


443-456: Add error handling to MCP Protocol Integration section.

The MCP Protocol Integration section documents the happy path for prompts/list and prompts/get flows, but doesn't describe error cases (e.g., when a prompt is not found, validation fails, or execution fails). Given that the PR introduces PromptNotFoundError and PromptExecutionError, consider documenting these error scenarios in the protocol flow.

When a client requests `prompts/get` with a name and arguments:
1. The SDK locates the prompt by name
2. (NEW) If prompt not found → PromptNotFoundError is returned
3. Arguments are validated against the prompt's definition
4. (NEW) If validation fails → error response with details
5. The `execute()` method is called with the arguments
6. (NEW) If execution fails → PromptExecutionError is returned
7. The return value is converted to MCP `GetPromptResult` format

This would align better with the error classes mentioned in the PR summary.

libs/sdk/src/errors/mcp.error.ts (1)

361-389: Align prompt error behavior with existing execution/not-found errors

The new prompt errors look consistent overall, but two small inconsistencies with existing errors are worth tightening up:

  • PromptNotFoundError currently uses the default statusCode = 400. Given ToolNotFoundError and ResourceNotFoundError both use 404, consider also passing 404 here for consistency and clearer semantics.
  • PromptExecutionError stores originalError but does not override getInternalMessage(), unlike ResourceReadError, ToolExecutionError, and GenericServerError. This means internal logs won’t automatically include the wrapped stack trace.

You can mirror the existing pattern:

export class PromptNotFoundError extends PublicMcpError {
  constructor(promptName: string) {
-    super(`Prompt not found: ${promptName}`, 'PROMPT_NOT_FOUND');
+    super(`Prompt not found: ${promptName}`, 'PROMPT_NOT_FOUND', 404);
  }
}

export class PromptExecutionError extends InternalMcpError {
  readonly promptName: string;
  readonly originalError?: Error;

  constructor(promptName: string, cause?: Error) {
    super(
      cause ? `Prompt execution failed: ${cause.message}` : `Prompt execution failed: ${promptName}`,
      'PROMPT_EXECUTION_FAILED',
    );
    this.promptName = promptName;
    this.originalError = cause;
  }

+  override getInternalMessage(): string {
+    if (this.originalError?.stack) {
+      return `${this.message}\n\nOriginal error:\n${this.originalError.stack}`;
+    }
+    return this.message;
+  }
}
libs/sdk/src/common/interfaces/prompt.interface.ts (1)

34-124: PromptContext design and flow control wiring look solid

The PromptContext abstraction cleanly encapsulates providers, scope, metadata, auth, and output/error state, and the respond/fail helpers correctly delegate to FlowControl while recording output and error. The automatic outputHistory tracking on the setter is a nice touch for observability.

If you want to go further later, you could:

  • Return a shallow copy in outputHistory (e.g. return [...this._outputHistory];) or freeze the array for stronger immutability guarantees.
  • Consider eventually differentiating promptId vs promptName if you introduce a separate stable identifier.

But functionally this looks good as-is.

libs/sdk/src/prompt/__tests__/prompt.instance.test.ts (1)

1-523: PromptInstance test coverage is thorough and well-aligned with implementation

This suite does a good job exercising all major PromptInstance behaviors: constructor wiring, metadata exposure, argument parsing (required/optional/extra/undefined), multiple output shapes, safeParseOutput success/failure, and both CLASS_TOKEN and FUNCTION contexts via create(). It also validates record/metadata passthrough and error wrapping.

If you want to tighten it further later, you could add an assertion in the create tests that context.authInfo matches the injected mockCtx.authInfo, but overall these tests are in great shape.

libs/sdk/src/prompt/flows/__tests__/get-prompt.flow.test.ts (1)

450-472: Tighten error-path expectations with explicit instanceof checks

The flow tests do a nice job covering happy paths, argument variants, auth propagation, and many edge cases. For a few of the error scenarios you currently only assert that an error is “defined” or that the run failed:

  • prompt execution throwing error (Lines 476–506)
  • invalid output format (Lines 508–545)
  • prompt returning undefined output / rawOutput missing in finalize (Lines 760–775)

Given GetPromptFlow is explicitly mapping to domain errors like PromptExecutionError and InvalidOutputError, it would be safer to assert the concrete error type as well, similar to what you’re already doing for InvalidInputError and PromptNotFoundError. For example:

expect(result.success).toBe(false);
expect(result.error).toBeInstanceOf(PromptExecutionError); // or InvalidOutputError, as appropriate

This will catch regressions where those errors accidentally degrade back to generic Error or GenericServerError.

Also applies to: 476-506, 508-545, 760-775

libs/sdk/src/prompt/prompt.instance.ts (2)

139-147: Use unknown instead of any for the execute return type.

Per coding guidelines, avoid any types without strong justification. The execute method should use unknown or match the interface contract.

-  execute(args: Record<string, string>): Promise<any> {
+  execute(args: Record<string, string>): Promise<unknown> {
     return this.record.provide(args, this);
   }

94-103: Consider edge case: extra arguments not in definition could mask typos.

The implementation accepts additional arguments not defined in argDefs (lines 106-112). This is flexible but could silently pass typo'd argument names. Consider logging a warning for unexpected arguments.

libs/sdk/src/prompt/prompt.utils.ts (1)

101-108: Prefer unknown over any for the raw parameter.

Per coding guidelines, use unknown for generic type defaults. The function already handles type narrowing internally.

-export function buildParsedPromptResult(raw: any, metadata: PromptMetadata): GetPromptResult {
+export function buildParsedPromptResult(raw: unknown, metadata: PromptMetadata): GetPromptResult {
   // If already in GetPromptResult format
   if (raw && typeof raw === 'object' && 'messages' in raw && Array.isArray(raw.messages)) {
     return {
-      description: raw.description ?? metadata.description,
+      description: (raw as { description?: string }).description ?? metadata.description,
       messages: raw.messages as PromptMessage[],
     };
   }
libs/sdk/src/prompt/flows/get-prompt.flow.ts (1)

15-38: Appropriate use of z.any() with explanatory comments.

The comments on lines 27-35 justify the any usage for complex external types (AuthInfo, PromptEntry, PromptContext). For line 17 (ctx: z.any()), consider adding a similar comment explaining the context type.

 const inputSchema = z.object({
   request: GetPromptRequestSchema,
+  // z.any() used because ctx is a complex RequestHandlerExtra type from @modelcontextprotocol/sdk
   ctx: z.any(),
 });
libs/sdk/src/common/entries/prompt.entry.ts (1)

28-39: Consider using definite assignment assertion or making properties abstract.

The owner, name, and fullName properties are declared but not initialized in the abstract class. Since subclasses must set these in their constructors, consider using the definite assignment assertion (!) or documenting this contract.

 export abstract class PromptEntry extends BaseEntry<AnyPromptRecord, PromptInterface, PromptMetadata> {
-  owner: EntryOwnerRef;
+  owner!: EntryOwnerRef;

   /**
    * The name of the prompt, as declared in the metadata.
    */
-  name: string;
+  name!: string;

   /**
    * The full name of the prompt, including the owner name as prefix.
    */
-  fullName: string;
+  fullName!: string;

Note: Per coding guidelines, non-null assertions should be avoided, but for abstract class properties that subclasses must initialize, this is an acceptable pattern. Alternatively, make these abstract getters.

libs/sdk/src/prompt/prompt.registry.ts (4)

156-181: Adoption logic from child registries looks solid; watch out for potential cycles

The adoptFromChild implementation correctly:

  • Guards against double‑adoption with this.children.has(child).
  • Clones IndexedPrompt rows via relineage while preserving the original instance reference and source.
  • Subscribes to child changes and recomputes adopted rows + indexes on updates.

Two small considerations:

  • If other parts of the system allow a child to also adopt this registry (or form longer cycles), you could end up with cyclical subscription/update chains. If that’s a possibility, you may want an additional lineage/owner‑based guard against cycles.
  • _childOwner is currently unused and intentionally named as such; if you don’t expect to need it for prefixing, consider removing it to reduce noise.

Overall, the adoption & live‑update behavior itself looks good.


188-205: Make hideFromDiscovery handling more robust to unexpected metadata shapes

getPrompts does:

const meta = r.instance.metadata;
const hidden =
  'hideFromDiscovery' in meta &&
  (meta as { hideFromDiscovery?: boolean }).hideFromDiscovery === true;

If metadata were ever null or a primitive at runtime, 'hideFromDiscovery' in meta would throw. Given this is library code, it’s safer to defensively gate:

const meta = r.instance.metadata as { hideFromDiscovery?: boolean } | null | undefined;
const hidden = !!meta && meta.hideFromDiscovery === true;

This maintains the behavior while avoiding hard failures on unexpected metadata.


269-345: Align export‑name errors with SDK error types and consider maxLen/suffix edge‑case

exportResolvedNames and disambiguate are nicely structured and cover most collision scenarios, but there are two points to tighten:

  1. Generic Error use
throw new Error(
  `Failed to disambiguate name "${candidate}" after ${MAX_DISAMBIGUATE_ATTEMPTS} attempts`,
);

Per the SDK guidelines, this should use a specific error class extending PublicMcpError (or your internal registry error type) with an appropriate MCP error code. That keeps error handling consistent across the SDK and easier to surface to clients.

  1. maxLen and suffix truncation

When candidate is already at cfg.maxLen, appending ${sepFor(cfg.case)}${n} and then applying ensureMaxLen can truncate the suffix back off, yielding the same string for multiple n values. In that degenerate case you’ll exhaust MAX_DISAMBIGUATE_ATTEMPTS and throw even though there might be viable shorter names.

If that’s a concern for your workloads, consider:

  • Reserving a few characters for the numeric suffix when computing the base; or
  • Falling back to a hashed suffix when repeated truncation keeps colliding.

For most realistic name lengths this won’t bite, but it’s a low‑level edge worth being explicit about.


355-374: Event payload naming vs guidelines; good use of getCapabilities()

The subscription pipeline is clean:

  • subscribe supports immediate snapshots and an optional filter.
  • bump centralizes versioning and event emission.
  • getCapabilities() correctly derives listChanged from hasAny(), so capabilities reflect actual registry state rather than being hardcoded in adapters (this matches the stored learnings about using getCapabilities() for dynamic capability exposure). Based on learnings, this aligns with the registry capability guideline.

One naming concern:

  • Events are emitted with { kind, scope: 'global', ... } and the subscriber also assumes a scope field.
  • The SDK guidelines call for using changeScope instead of scope in change event types to avoid confusion with the Scope class.

If PromptChangeEvent has already been updated to use changeScope, this code will fail type‑checking and should be switched to changeScope. If it still uses scope, consider scheduling a follow‑up pass to rename the field in the event type and here for consistency with the rest of the SDK.

Also applies to: 445-458

📜 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 f60d95f and 9864586.

📒 Files selected for processing (25)
  • .github/workflows/update-draft-docs.yml (3 hunks)
  • docs/draft/docs/guides/enclave.mdx (1 hunks)
  • docs/draft/docs/plugins/codecall-plugin.mdx (1 hunks)
  • docs/draft/docs/servers/prompts.mdx (1 hunks)
  • libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts (1 hunks)
  • libs/sdk/src/__test-utils__/mocks/provider-registry.mock.ts (3 hunks)
  • libs/sdk/src/common/entries/prompt.entry.ts (1 hunks)
  • libs/sdk/src/common/interfaces/internal/registry.interface.ts (1 hunks)
  • libs/sdk/src/common/interfaces/prompt.interface.ts (1 hunks)
  • libs/sdk/src/errors/index.ts (1 hunks)
  • libs/sdk/src/errors/mcp.error.ts (1 hunks)
  • libs/sdk/src/prompt/__tests__/prompt.decorator.test.ts (1 hunks)
  • libs/sdk/src/prompt/__tests__/prompt.instance.test.ts (1 hunks)
  • libs/sdk/src/prompt/__tests__/prompt.registry.test.ts (1 hunks)
  • libs/sdk/src/prompt/__tests__/prompt.utils.test.ts (1 hunks)
  • libs/sdk/src/prompt/flows/__tests__/get-prompt.flow.test.ts (1 hunks)
  • libs/sdk/src/prompt/flows/__tests__/prompts-list.flow.test.ts (1 hunks)
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts (1 hunks)
  • libs/sdk/src/prompt/flows/prompts-list.flow.ts (1 hunks)
  • libs/sdk/src/prompt/prompt.events.ts (1 hunks)
  • libs/sdk/src/prompt/prompt.instance.ts (1 hunks)
  • libs/sdk/src/prompt/prompt.registry.ts (1 hunks)
  • libs/sdk/src/prompt/prompt.utils.ts (1 hunks)
  • libs/sdk/src/scope/scope.instance.ts (4 hunks)
  • libs/sdk/src/transport/adapters/transport.local.adapter.ts (1 hunks)
✅ Files skipped from review due to trivial changes (2)
  • docs/draft/docs/plugins/codecall-plugin.mdx
  • docs/draft/docs/guides/enclave.mdx
🚧 Files skipped from review as they are similar to previous changes (7)
  • libs/sdk/src/prompt/tests/prompt.decorator.test.ts
  • libs/sdk/src/prompt/flows/tests/prompts-list.flow.test.ts
  • libs/sdk/src/prompt/tests/prompt.registry.test.ts
  • libs/sdk/src/test-utils/mocks/prompt-registry.mock.ts
  • libs/sdk/src/prompt/flows/prompts-list.flow.ts
  • libs/sdk/src/prompt/prompt.events.ts
  • libs/sdk/src/prompt/tests/prompt.utils.test.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use strict TypeScript mode with no any types without strong justification; prefer unknown for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific error classes instead

Files:

  • libs/sdk/src/transport/adapters/transport.local.adapter.ts
  • libs/sdk/src/common/interfaces/internal/registry.interface.ts
  • libs/sdk/src/scope/scope.instance.ts
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts
  • libs/sdk/src/errors/index.ts
  • libs/sdk/src/prompt/prompt.instance.ts
  • libs/sdk/src/common/interfaces/prompt.interface.ts
  • libs/sdk/src/prompt/flows/__tests__/get-prompt.flow.test.ts
  • libs/sdk/src/prompt/prompt.utils.ts
  • libs/sdk/src/errors/mcp.error.ts
  • libs/sdk/src/prompt/__tests__/prompt.instance.test.ts
  • libs/sdk/src/prompt/prompt.registry.ts
  • libs/sdk/src/common/entries/prompt.entry.ts
  • libs/sdk/src/__test-utils__/mocks/provider-registry.mock.ts
libs/sdk/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

libs/sdk/**/*.{ts,tsx}: Create shared base classes for common functionality (e.g., ExecutionContextBase) to reduce code duplication
Use specific error classes extending PublicMcpError with MCP error codes instead of generic errors
Use getCapabilities() for dynamic capability exposure in registries instead of hardcoding capabilities in adapters
Use changeScope instead of scope in change event types to avoid confusion with the Scope class
Validate URIs per RFC 3986 at metadata level using Zod schema validation
Fail fast on invalid hook flows by validating hooks match their entry type during initialization
Use type parameters with constraints instead of unconstrained or any defaults in generic types
Do not mutate rawInput in flows - use state.set() for flow state management instead

Files:

  • libs/sdk/src/transport/adapters/transport.local.adapter.ts
  • libs/sdk/src/common/interfaces/internal/registry.interface.ts
  • libs/sdk/src/scope/scope.instance.ts
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts
  • libs/sdk/src/errors/index.ts
  • libs/sdk/src/prompt/prompt.instance.ts
  • libs/sdk/src/common/interfaces/prompt.interface.ts
  • libs/sdk/src/prompt/flows/__tests__/get-prompt.flow.test.ts
  • libs/sdk/src/prompt/prompt.utils.ts
  • libs/sdk/src/errors/mcp.error.ts
  • libs/sdk/src/prompt/__tests__/prompt.instance.test.ts
  • libs/sdk/src/prompt/prompt.registry.ts
  • libs/sdk/src/common/entries/prompt.entry.ts
  • libs/sdk/src/__test-utils__/mocks/provider-registry.mock.ts
libs/sdk/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Centralize record types in common/records directory and import from there rather than module-specific files

Files:

  • libs/sdk/src/transport/adapters/transport.local.adapter.ts
  • libs/sdk/src/common/interfaces/internal/registry.interface.ts
  • libs/sdk/src/scope/scope.instance.ts
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts
  • libs/sdk/src/errors/index.ts
  • libs/sdk/src/prompt/prompt.instance.ts
  • libs/sdk/src/common/interfaces/prompt.interface.ts
  • libs/sdk/src/prompt/flows/__tests__/get-prompt.flow.test.ts
  • libs/sdk/src/prompt/prompt.utils.ts
  • libs/sdk/src/errors/mcp.error.ts
  • libs/sdk/src/prompt/__tests__/prompt.instance.test.ts
  • libs/sdk/src/prompt/prompt.registry.ts
  • libs/sdk/src/common/entries/prompt.entry.ts
  • libs/sdk/src/__test-utils__/mocks/provider-registry.mock.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/transport/adapters/transport.local.adapter.ts
  • libs/sdk/src/common/interfaces/internal/registry.interface.ts
  • libs/sdk/src/scope/scope.instance.ts
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts
  • libs/sdk/src/errors/index.ts
  • libs/sdk/src/prompt/prompt.instance.ts
  • libs/sdk/src/common/interfaces/prompt.interface.ts
  • libs/sdk/src/prompt/flows/__tests__/get-prompt.flow.test.ts
  • libs/sdk/src/prompt/prompt.utils.ts
  • libs/sdk/src/errors/mcp.error.ts
  • libs/sdk/src/prompt/__tests__/prompt.instance.test.ts
  • libs/sdk/src/prompt/prompt.registry.ts
  • libs/sdk/src/common/entries/prompt.entry.ts
  • libs/sdk/src/__test-utils__/mocks/provider-registry.mock.ts
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/prompts.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/prompts.mdx
**/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Export barrel exports in index.ts with clean, direct exports; do not add legacy or backwards compatibility exports

Files:

  • libs/sdk/src/errors/index.ts
**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • libs/sdk/src/prompt/flows/__tests__/get-prompt.flow.test.ts
  • libs/sdk/src/prompt/__tests__/prompt.instance.test.ts
🧠 Learnings (8)
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/**/*.{ts,tsx} : Use `getCapabilities()` for dynamic capability exposure in registries instead of hardcoding capabilities in adapters

Applied to files:

  • libs/sdk/src/transport/adapters/transport.local.adapter.ts
  • libs/sdk/src/prompt/prompt.registry.ts
  • libs/sdk/src/__test-utils__/mocks/provider-registry.mock.ts
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/**/*.{ts,tsx} : Use `changeScope` instead of `scope` in change event types to avoid confusion with the Scope class

Applied to files:

  • libs/sdk/src/scope/scope.instance.ts
📚 Learning: 2025-11-16T22:47:05.139Z
Learnt from: frontegg-david
Repo: agentfront/frontmcp PR: 50
File: docs/docs/v/0.1/getting-started/welcome.mdx:2-3
Timestamp: 2025-11-16T22:47:05.139Z
Learning: In the agentfront/frontmcp repository, the docs/docs/v/** directory governance rule prohibiting manual edits applies to already-frozen releases, but does not preclude initial setup and bootstrap commits that establish the versioned docs structure.

Applied to files:

  • .github/workflows/update-draft-docs.yml
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/**/*.{ts,tsx} : Use specific error classes extending PublicMcpError with MCP error codes instead of generic errors

Applied to files:

  • libs/sdk/src/errors/index.ts
  • libs/sdk/src/errors/mcp.error.ts
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/**/*.{ts,tsx} : Fail fast on invalid hook flows by validating hooks match their entry type during initialization

Applied to files:

  • libs/sdk/src/errors/index.ts
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/src/**/*.{ts,tsx} : Centralize record types in common/records directory and import from there rather than module-specific files

Applied to files:

  • libs/sdk/src/prompt/prompt.utils.ts
  • libs/sdk/src/common/entries/prompt.entry.ts
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/**/*.{ts,tsx} : Create shared base classes for common functionality (e.g., ExecutionContextBase) to reduce code duplication

Applied to files:

  • libs/sdk/src/prompt/prompt.utils.ts
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to **/*.test.{ts,tsx} : Test constructor validation, error class instanceof checks, and all code paths including error conditions

Applied to files:

  • libs/sdk/src/prompt/__tests__/prompt.instance.test.ts
🧬 Code graph analysis (6)
libs/sdk/src/common/interfaces/prompt.interface.ts (3)
libs/sdk/src/common/interfaces/internal/registry.interface.ts (1)
  • ProviderRegistryInterface (82-93)
libs/sdk/src/app/instances/app.local.instance.ts (1)
  • providers (53-55)
libs/sdk/src/scope/scope.instance.ts (1)
  • providers (149-151)
libs/sdk/src/prompt/flows/__tests__/get-prompt.flow.test.ts (2)
libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts (3)
  • createMockPromptRegistry (11-77)
  • createMockPromptEntry (82-162)
  • addPromptToMock (167-185)
libs/sdk/src/errors/mcp.error.ts (3)
  • InvalidInputError (223-240)
  • PromptNotFoundError (368-372)
  • PromptExecutionError (377-389)
libs/sdk/src/prompt/prompt.utils.ts (3)
libs/sdk/src/common/interfaces/prompt.interface.ts (1)
  • PromptType (17-17)
libs/sdk/src/prompt/prompt.instance.ts (1)
  • getMetadata (49-51)
libs/sdk/src/utils/index.ts (3)
  • isClass (34-34)
  • depsOfFunc (34-34)
  • depsOfClass (34-34)
libs/sdk/src/prompt/__tests__/prompt.instance.test.ts (3)
libs/sdk/src/prompt/prompt.utils.ts (1)
  • normalizePrompt (56-79)
libs/sdk/src/prompt/prompt.instance.ts (1)
  • PromptInstance (22-134)
libs/sdk/src/__test-utils__/mocks/provider-registry.mock.ts (2)
  • createMockProviderRegistry (71-118)
  • createMockOwner (60-66)
libs/sdk/src/common/entries/prompt.entry.ts (1)
libs/sdk/src/common/interfaces/prompt.interface.ts (1)
  • PromptInterface (13-15)
libs/sdk/src/__test-utils__/mocks/provider-registry.mock.ts (1)
libs/sdk/src/__test-utils__/fixtures/scope.fixtures.ts (1)
  • createMockScope (14-41)
🔇 Additional comments (18)
.github/workflows/update-draft-docs.yml (2)

62-92: Verify the MCP server endpoint and configuration validity.

The new MCP configuration setup introduces several details that need validation before deployment:

  1. Line 82: The endpoint https://mintlify.com/docs/mcp looks like a documentation URL rather than an operational MCP server. Confirm this is the correct MCP server endpoint.
  2. Line 84: The custom header X-MCP-Readonly is not a standard MCP protocol header. Verify this is supported by the Mintlify MCP server implementation.
  3. Line 77: Enabling rmcp_client = true for HTTP/OAuth support—confirm this feature flag is necessary and available in your Codex/MCP setup.
  4. Timeouts (lines 85–86): The startup timeout of 30s and tool timeout of 60s—confirm these are appropriate for the Mintlify server's response characteristics.

Additionally, has this MCP server configuration been tested end-to-end with Codex to ensure it works as expected in the workflow?


64-90: Good: RUNNER_TEMP usage and output threading.

The use of ${{ runner.temp }} to create an isolated, temporary Codex home directory is a solid approach for sandboxing MCP configuration per workflow run. The output (codex_home) is correctly threaded into the Codex action step (line 366), ensuring consistency.

docs/draft/docs/servers/prompts.mdx (2)

200-262: I'll help you verify the documented context properties and service resolution API for prompts. Let me search the codebase to confirm these features are accurately documented.
<function_calls>

#!/bin/bash

Search for prompt context class/interface definitions

rg -n "interface.*PromptContext|class.*PromptContext|type PromptContext" --type ts --type tsx

Search for prompt base class with context methods

rg -n "class.*Prompt\b" --type ts --type tsx -A 10 | head -50


</function_calls>

<function_calls>

#!/bin/bash

Find prompt-related files

fd -t f -e ts -e tsx "prompt" | grep -v node_modules | head -20


</function_calls>

<function_calls>

#!/bin/bash

List repository structure to find source files

ls -la

Find TypeScript/source files

find . -name ".ts" -o -name ".tsx" | grep -v node_modules | grep -v dist | head -30


</function_calls>


118-168: Verification confirms all documented return value conversions are accurate and implemented correctly.

The review comment requests verification that the four documented return formats are actually supported. After examining the SDK codebase:

Findings:

All four return formats documented in lines 118-168 are correctly implemented:

  1. Simple string (line 124 conversion claim): Verified in buildParsedPromptResult (prompt.utils.ts:111-115) — strings are wrapped in a user message
  2. Message array (line 127-136): Verified (prompt.utils.ts:119-123) — each message is normalized via normalizePromptMessage
  3. Full MCP format (line 138-157): Verified (prompt.utils.ts:103-108) — already-formatted results are preserved
  4. Object return (line 167 conversion claim): Verified (prompt.utils.ts:127-130) — objects are JSON-serialized to text in a user message

The conversion pipeline is: execute()executeOutput()prompt.safeParseOutput()buildParsedPromptResult().

No issues found with the documentation accuracy.

libs/sdk/src/transport/adapters/transport.local.adapter.ts (1)

52-59: Prompts capability wiring matches existing pattern

Using this.scope.prompts.getCapabilities() alongside resources.getCapabilities() is consistent with the existing design and the guideline to avoid hardcoded capabilities in adapters. No issues here.

libs/sdk/src/scope/scope.instance.ts (1)

28-29: PromptRegistry integration into Scope follows existing registry patterns

The new scopePrompts registry is wired consistently with tools/resources: constructed with scopeProviders and scopeRef, awaited in initialize(), and exposed via a dedicated prompts getter. Assuming existing callers already respect await scope.ready before accessing registries (which they must for tools/resources), this addition should be safe.

If there are any code paths that construct a Scope and immediately create a LocalTransportAdapter (or otherwise access scope.prompts) without awaiting scope.ready, it’s worth double‑checking those call sites for potential race conditions.

Also applies to: 42-43, 95-97, 165-167

libs/sdk/src/errors/index.ts (1)

18-21: Public error surface expanded – ensure docs/API references are updated

Re‑exporting DependencyNotFoundError, InvalidHookFlowError, PromptNotFoundError, and PromptExecutionError from the main errors barrel is a good move for usability. Since this grows the public SDK API, please ensure the corresponding docs under docs/draft/docs/** are updated to describe these errors and when they’re emitted.

libs/sdk/src/common/interfaces/internal/registry.interface.ts (1)

140-152: PromptRegistryInterface extension is consistent with other registries

The PromptRegistryInterface updates (owner field, getPrompts(includeHidden?: boolean), and findByName) line up with the patterns already used for tools and resources and match how the mocks and flows consume the registry.

Just make sure all concrete PromptRegistry implementations and any custom registries in plugins are updated to implement owner, respect includeHidden, and provide findByName to avoid subtle runtime type mismatches.

libs/sdk/src/prompt/prompt.instance.ts (1)

27-37: LGTM on constructor and initialization.

The constructor properly initializes owner, providers, and computes fullName. The async initialize() pattern correctly handles hook registration with proper flow filtering.

libs/sdk/src/prompt/prompt.utils.ts (2)

56-79: The any type usage is appropriately documented.

The JSDoc comment on lines 50-54 explains why any is intentional here—to handle both decorator patterns and provide meaningful error messages. The implementation correctly narrows types before use.


84-96: Well-implemented exhaustive check pattern.

The exhaustive switch with never type assertion ensures compile-time safety if new PromptKind values are added.

libs/sdk/src/__test-utils__/mocks/provider-registry.mock.ts (2)

71-118: Good improvements to type safety in the mock registry.

The changes correctly use Map<Token, unknown> instead of any, and the mock properly returns undefined for missing tokens rather than throwing. The addition of getActiveScope, getRegistries, and addRegistry aligns with the registry interface updates.


26-55: I'll verify the duplication claim by locating and comparing the createMockScope functions in both files.
<function_calls>


#!/bin/bash

Locate scope.fixtures.ts

fd -type f "scope.fixtures.ts" --type ts


</function_calls>

Let me search for the file more broadly:
<function_calls>


#!/bin/bash

Search for any file with "scope" and "fixtures" in the name

fd -type f "fixtures" --type ts | grep -i scope


</function_calls>

Let me try a different approach:
<function_calls>


#!/bin/bash

Search for createMockScope definitions

rg -n "export function createMockScope" --type ts


</function_calls>

libs/sdk/src/prompt/flows/get-prompt.flow.ts (1)

196-226: Solid finalize stage with proper error handling.

The stage correctly validates state, uses safeParseOutput for safe parsing, and throws domain-specific InvalidOutputError on failure. The structured logging captures useful debug context.

libs/sdk/src/common/entries/prompt.entry.ts (1)

11-19: Well-typed union for both prompt kinds.

AnyPromptRecord appropriately uses Type<unknown> and (...args: unknown[]) => unknown to cover both class-based and function-based prompts without resorting to any.

libs/sdk/src/prompt/prompt.registry.ts (3)

27-31: Verify ../regsitry import path for RegistryAbstract

The segment from '../regsitry' looks like it might be a typo for ../registry. If the directory/module isn’t actually spelled regsitry, this will break compilation for all registries. Please confirm the path and align it with the real module name to avoid subtle import failures.


223-262: Indexing and lookup maps are straightforward and appropriate

The listAllIndexed/listAllInstances/listByOwner helpers plus reindex() give you:

  • A single source of truth (IndexedPrompt) for both local and adopted prompts.
  • O(1) lookups by qualified id, name, owner, and owner+name.
  • Deterministic iteration order based on listAllIndexed().

The logic in reindex() is clean and side‑effect free beyond the four maps, which should make future maintenance low‑risk.


378-419: Helper utilities (makeRow, relineage, providerIdOf, dedupLineage) look correct

  • makeRow and relineage correctly derive ownerKey, qualifiedName, and qualifiedId from lineage + token, while keeping instance references stable.
  • relineage’s use of dedupLineage to remove only adjacent duplicates preserves meaningful repeated owner segments while avoiding double‑prefixing from adoption.
  • providerIdOf is safely wrapped in a try/catch and treats provider IDs as best‑effort metadata, which is appropriate for name prefixing.
  • hasAny leverages both listAllIndexed() and tokens.size so capabilities can be accurate even before adoption completes.

These helpers are cohesive and align well with the registry’s responsibilities.

Also applies to: 422-447, 463-471

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 (2)
libs/sdk/src/prompt/flows/get-prompt.flow.ts (1)

118-122: Do not mutate rawInput in flows.

Per coding guidelines, rawInput should not be mutated. Use state.set() for flow state management instead. This issue was flagged in a previous review.

Apply this diff to use state instead of mutating rawInput:

     // Store prompt owner ID in the flow input for hook filtering.
-    // This mutation allows hooks to filter by prompt owner during execution.
-    if (prompt.owner) {
-      (this.rawInput as any)._promptOwnerId = prompt.owner.id;
-    }
+    // Store prompt owner ID in state for hook filtering during execution.
+    this.state.set('promptOwnerId', prompt.owner?.id);

You'll also need to add promptOwnerId to the state schema:

 const stateSchema = z.object({
   input: z.object({
     name: z.string().min(1),
     arguments: z.record(z.string()).optional(),
   }),
+  promptOwnerId: z.string().optional(),
   // z.any() used because AuthInfo is a complex external type from @modelcontextprotocol/sdk
   authInfo: z.any().optional() as z.ZodType<AuthInfo>,
docs/draft/docs/servers/prompts.mdx (1)

74-95: Verify the functional prompt builder API before publishing.

This section documents a functional builder pattern. As previously flagged, the documented usage should be verified against the actual SDK implementation in libs/sdk/src/common/decorators/prompt.decorator.ts to ensure the type signatures and runtime behavior align.

🧹 Nitpick comments (3)
libs/sdk/src/prompt/prompt.instance.ts (1)

145-149: Return type cast may not match all function prompt implementations.

The cast to Promise<GetPromptResult> assumes all function prompts return this type directly. However, buildParsedPromptResult in prompt.utils.ts handles various return types (string, array, object). This cast could mask type mismatches at compile time.

Consider using unknown or the actual return type and letting parseOutput handle normalization:

-  execute(args: Record<string, string>): Promise<GetPromptResult> {
-    return this.record.provide(args, this) as Promise<GetPromptResult>;
+  execute(args: Record<string, string>): Promise<unknown> {
+    return this.record.provide(args, this);
   }

This aligns with the parseOutput stage that already normalizes various return types.

libs/sdk/src/prompt/prompt.utils.ts (1)

137-155: Message normalization assumes valid structure after type guards.

The function checks for role and content properties with string/object types, then casts to PromptMessage. This trusts that the structure matches the MCP schema without deeper validation.

Consider validating the role value against allowed roles ('user' | 'assistant') for stricter type safety:

   if (
     msg &&
     typeof msg === 'object' &&
     'role' in msg &&
     'content' in msg &&
     typeof (msg as Record<string, unknown>)['role'] === 'string' &&
     typeof (msg as Record<string, unknown>)['content'] === 'object'
   ) {
+    const role = (msg as Record<string, unknown>)['role'];
+    if (role !== 'user' && role !== 'assistant') {
+      // Fall through to default user message
+    } else {
       return msg as PromptMessage;
+    }
   }
libs/sdk/src/common/entries/prompt.entry.ts (1)

28-39: Consider using abstract getters or constructor initialization instead of definite assignment assertions.

Lines 29, 34, and 39 use definite assignment assertions (!). Per coding guidelines, non-null assertions should be avoided. For abstract class members that must be set by subclasses, consider:

  1. Abstract getters (preferred for enforced implementation):
-  owner!: EntryOwnerRef;
-  name!: string;
-  fullName!: string;
+  abstract get owner(): EntryOwnerRef;
+  abstract get name(): string;
+  abstract get fullName(): string;
  1. Constructor-based initialization in the concrete subclass with proper validation.

This pattern ensures compile-time enforcement that subclasses provide these values.

📜 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 9864586 and a52dc3e.

📒 Files selected for processing (9)
  • README.md (1 hunks)
  • docs/draft/docs/servers/prompts.mdx (1 hunks)
  • docs/draft/docs/servers/resources.mdx (2 hunks)
  • docs/draft/docs/servers/tools.mdx (2 hunks)
  • libs/sdk/src/common/entries/prompt.entry.ts (1 hunks)
  • libs/sdk/src/errors/mcp.error.ts (1 hunks)
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts (1 hunks)
  • libs/sdk/src/prompt/prompt.instance.ts (1 hunks)
  • libs/sdk/src/prompt/prompt.utils.ts (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • docs/draft/docs/servers/resources.mdx
🚧 Files skipped from review as they are similar to previous changes (1)
  • libs/sdk/src/errors/mcp.error.ts
🧰 Additional context used
📓 Path-based instructions (6)
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/servers/prompts.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/servers/prompts.mdx
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use strict TypeScript mode with no any types without strong justification; prefer unknown for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific error classes instead

Files:

  • libs/sdk/src/prompt/prompt.utils.ts
  • libs/sdk/src/prompt/prompt.instance.ts
  • libs/sdk/src/common/entries/prompt.entry.ts
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts
libs/sdk/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

libs/sdk/**/*.{ts,tsx}: Create shared base classes for common functionality (e.g., ExecutionContextBase) to reduce code duplication
Use specific error classes extending PublicMcpError with MCP error codes instead of generic errors
Use getCapabilities() for dynamic capability exposure in registries instead of hardcoding capabilities in adapters
Use changeScope instead of scope in change event types to avoid confusion with the Scope class
Validate URIs per RFC 3986 at metadata level using Zod schema validation
Fail fast on invalid hook flows by validating hooks match their entry type during initialization
Use type parameters with constraints instead of unconstrained or any defaults in generic types
Do not mutate rawInput in flows - use state.set() for flow state management instead

Files:

  • libs/sdk/src/prompt/prompt.utils.ts
  • libs/sdk/src/prompt/prompt.instance.ts
  • libs/sdk/src/common/entries/prompt.entry.ts
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts
libs/sdk/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Centralize record types in common/records directory and import from there rather than module-specific files

Files:

  • libs/sdk/src/prompt/prompt.utils.ts
  • libs/sdk/src/prompt/prompt.instance.ts
  • libs/sdk/src/common/entries/prompt.entry.ts
  • libs/sdk/src/prompt/flows/get-prompt.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/prompt/prompt.utils.ts
  • libs/sdk/src/prompt/prompt.instance.ts
  • libs/sdk/src/common/entries/prompt.entry.ts
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts
🧠 Learnings (3)
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/src/**/*.{ts,tsx} : Centralize record types in common/records directory and import from there rather than module-specific files

Applied to files:

  • libs/sdk/src/prompt/prompt.utils.ts
  • libs/sdk/src/common/entries/prompt.entry.ts
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/**/*.{ts,tsx} : Create shared base classes for common functionality (e.g., ExecutionContextBase) to reduce code duplication

Applied to files:

  • libs/sdk/src/prompt/prompt.utils.ts
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/**/*.{ts,tsx} : Do not mutate rawInput in flows - use state.set() for flow state management instead

Applied to files:

  • libs/sdk/src/prompt/flows/get-prompt.flow.ts
🧬 Code graph analysis (3)
libs/sdk/src/prompt/prompt.utils.ts (3)
libs/sdk/src/common/interfaces/prompt.interface.ts (1)
  • PromptType (17-17)
libs/sdk/src/prompt/prompt.instance.ts (1)
  • getMetadata (50-52)
libs/sdk/src/utils/index.ts (3)
  • isClass (34-34)
  • depsOfFunc (34-34)
  • depsOfClass (34-34)
libs/sdk/src/common/entries/prompt.entry.ts (1)
libs/sdk/src/common/interfaces/prompt.interface.ts (1)
  • PromptInterface (13-15)
libs/sdk/src/prompt/flows/get-prompt.flow.ts (1)
libs/sdk/src/errors/mcp.error.ts (5)
  • InvalidInputError (223-240)
  • InvalidMethodError (269-273)
  • PromptNotFoundError (368-372)
  • PromptExecutionError (377-396)
  • InvalidOutputError (245-264)
⏰ 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). (1)
  • GitHub Check: build
🔇 Additional comments (22)
docs/draft/docs/servers/tools.mdx (2)

7-11: LGTM - Clear introduction with protocol reference.

The updated opening paragraph with the MCP Tools specification reference provides helpful context for developers.


97-140: MCP specification link date verified as current.

The date 2025-11-25 in the specification link is correct—it matches the latest MCP spec release published on November 25, 2025, which includes the updated Tools features. The documentation is using the intended version.

libs/sdk/src/prompt/prompt.instance.ts (4)

23-38: Well-structured PromptInstance initialization.

The constructor properly wires up providers, scope, hooks, and owner context. The deferred initialization pattern via this.ready = this.initialize() is appropriate for async hook registration.


40-48: Appropriate hook filtering for prompt flows.

The initialization correctly filters hooks to only those relevant to prompt flows (prompts:get-prompt and prompts:list-prompts).


74-84: Good exhaustive switch with runtime safety.

The switch statement handles both CLASS_TOKEN and FUNCTION kinds with a proper exhaustive check in the default case. The error message includes the actual kind value for debugging.


91-116: Argument parsing includes undefined arguments not in schema.

The method validates required arguments and includes any additional arguments not defined in the metadata. This open-world approach allows flexibility but may pass through unexpected data.

Verify this is the intended behavior - allowing arbitrary extra arguments could have security implications if downstream code doesn't expect them. Consider whether extra arguments should be logged or filtered based on use case.

libs/sdk/src/prompt/prompt.utils.ts (4)

17-31: Good centralization of shared utilities via re-exports.

Re-exporting naming and lineage utilities from a central location promotes code reuse and aligns with the coding guidelines for centralizing common functionality.


56-79: The any type usage is justified with clear documentation.

The JSDoc explains why any is used here - to handle both decorator patterns and provide meaningful error messages. The implementation properly type-guards and throws informative errors for invalid inputs.


84-96: Exhaustive switch with compile-time and runtime safety.

The exhaustive check using never type ensures all PromptKind values are handled, with a clear runtime error for unexpected cases.


101-132: Flexible output normalization handles multiple return types.

The function properly handles GetPromptResult, string, array, and fallback cases. This provides good developer ergonomics for prompt implementations.

libs/sdk/src/prompt/flows/get-prompt.flow.ts (5)

15-39: Well-defined schemas with appropriate type annotations.

The schema definitions use z.any() with proper type casts for complex external types (AuthInfo, PromptEntry, PromptContext). The comments explain why any is used in each case.


72-101: Robust input parsing with proper error handling.

The parseInput stage validates input using Zod schema, checks the method, and stores parsed data in state. Error handling wraps Zod errors appropriately.


130-157: Good context creation with cached argument parsing.

The stage parses arguments once and caches them in state (parsedArgs) to avoid redundant parsing in the execute stage. Error handling properly wraps exceptions in PromptExecutionError.


159-179: Proper use of cached parsed arguments in execute stage.

The execute stage correctly retrieves parsedArgs from state, avoiding duplicate parsing. The null check for promptContext provides a safe early return.


197-227: Robust finalization with safe output parsing.

The finalize stage properly validates state, uses safeParseOutput for error-safe output conversion, and throws appropriate errors with context. The respond() call returns the MCP-compliant result.

README.md (1)

451-453: Documentation links verified — all URLs are accessible.

The authentication documentation links have been updated to reflect a restructured docs hierarchy. All three URLs (overview, remote, and local) are accessible and return HTTP 200, confirming the migration to the new authentication path structure is complete.

[10]: https://docs.agentfront.dev/docs/authentication/overview 'Authentication - FrontMCP'
[11]: https://docs.agentfront.dev/docs/authentication/remote 'Remote OAuth - FrontMCP'
[12]: https://docs.agentfront.dev/docs/authentication/local 'Local OAuth - FrontMCP'
libs/sdk/src/common/entries/prompt.entry.ts (2)

11-26: LGTM on the type definitions.

The types are well-designed:

  • AnyPromptRecord properly uses Type<unknown> and (...args: unknown[]) => unknown avoiding any
  • PromptSafeTransformResult<T> is a proper discriminated union for safe error handling
  • The parseOutput(raw: unknown) signature correctly addresses the concern from previous reviews

41-64: Well-structured abstract method contracts.

The abstract methods establish a clear contract:

  • create for context instantiation with proper typing of PromptGetExtra
  • parseArguments for validation with optional input
  • Both parseOutput and safeParseOutput variants for flexibility in error handling

This design allows callers to choose between exception-based and result-based error handling patterns.

docs/draft/docs/servers/prompts.mdx (4)

270-443: Excellent real-world examples demonstrating key patterns.

The examples effectively showcase:

  • Optional argument handling with sensible defaults
  • Multi-turn conversation patterns (Interview Prep)
  • Provider-based data fetching with proper error handling (Project Summary)
  • Consistent use of Record<string, string> for argument typing

These provide clear guidance for developers implementing various prompt patterns.


447-488: MCP Protocol Integration section is accurate and well-documented.

The section correctly explains:

  • The prompts/list and prompts/get flows aligning with SDK implementations
  • The listChanged capability and its purpose
  • Automatic change notification behavior

This provides users with essential protocol context.


492-506: Best practices section provides clear and actionable guidance.

The Do/Don't format effectively communicates:

  • Separation of concerns between prompts (message generation) and tools (side effects)
  • Importance of descriptive metadata and argument definitions
  • Keeping prompts focused and avoiding complexity

Good alignment with MCP design principles.


213-236: Documentation accurately reflects the PromptContext API implementation.

Verification confirms all documented properties and methods exist and are properly exposed in the PromptContext class:

  • args (line 45) ✓
  • metadata (line 41) ✓
  • authInfo (line 36) ✓
  • get() method (lines 73–75) ✓
  • tryGet() method (lines 81–89) ✓
  • scope property (lines 77–79) ✓
  • respond() method (lines 104–108) ✓

No corrections needed.

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

🧹 Nitpick comments (9)
libs/sdk/src/tool/tool.registry.ts (1)

391-404: Consider aligning getCapabilities shape and semantics with registry guidelines

Implementation is fine, but right now getCapabilities exposes only listChanged, and it’s coupled to whether any tools are currently registered. Given the emitter-based subscription already exists, consider:

  • Returning a richer shape (e.g., { subscribe: true, listChanged: this.hasAny() }) to match the documented pattern for registries.
  • Deciding if listChanged should reflect capability (can emit change events) rather than current population (has tools).

This keeps ToolRegistry consistent with other registries and the guidance in CLAUDE.md.

apps/demo/src/apps/expenses/prompts/expense-report.prompt.ts (1)

1-52: Prompt implementation looks good; consider explicit MCP return typing

The prompt metadata and execute implementation look correct and align with the MCP prompt result shape. To keep the demo aligned with the “MCP Response Types” guideline, consider explicitly typing the method as returning the concrete MCP result type (e.g., Promise<GetPromptResult>) rather than relying on inference.

libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts (1)

11-77: Mocks are solid; consider adding getCapabilities for parity with real registries

The mock registry and prompt entries cover the main methods used in flows and tests (lookups, exports, owner filtering). To keep them in sync with the real PromptRegistry/registry guidelines, consider adding a simple getCapabilities() implementation, for example:

   return {
     prompts,
     ready: Promise.resolve(),
     owner: { kind: 'app', id: 'test-app', ref: {} },

+    getCapabilities: jest.fn(() => ({
+      // mirror the pattern used in other registries
+      listChanged: prompts.size > 0,
+    })),

This will make the mock safer to reuse in tests that rely on dynamic capability discovery.

Also applies to: 169-194

libs/sdk/src/prompt/flows/get-prompt.flow.ts (1)

1-227: Flow design and error handling look solid; minor typing refinements possible

This flow matches the documented pattern well: input validation, prompt lookup, context creation, cached argument parsing, raw output capture, and safeParseOutput-based finalization with domain-specific errors. Nice job also moving owner information into state instead of mutating rawInput.

Two small typing refinements you might consider:

  • In parseInput, avoid any locals and the definite-assignment method! by destructuring directly from the parsed input:

    const { request, ctx } = inputSchema.parse(this.rawInput);
    const { method, params } = request;

    This removes method!: string, params: any, and ctx: any entirely.

  • Since stateSchema already captures the full state shape, you can keep future changes safer by leaning on those inferred types (e.g., prefer z.infer<typeof inputSchema> / z.infer<typeof stateSchema> helpers for local annotations if you need them later).

These are purely type-safety/clarity nits; the runtime behavior looks correct.

apps/demo/src/apps/expenses/resources/expense-categories.resource.ts (1)

11-79: Hoist static categories to module scope to avoid per-call re-allocation

Since categories is immutable demo data, consider defining it once at the module level and just referencing it inside the handler. This avoids re-creating the array on every request and makes the static nature of the data clearer, without changing behavior.

apps/demo/src/apps/expenses/resources/expense-by-id.resource.ts (1)

18-38: Be aware of non-deterministic fields in the mock expense

amount and the various timestamp fields use Math.random() / new Date(), so the same expenseId will yield different responses over time. That’s fine for a demo, but if you later add tests or documentation examples that assert on this resource’s output, you may want to switch to deterministic values or a seeded random source.

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

136-148: Complete the “Complex Types” example with a tool definition

The “Complex Types” section shows an @Tool({ ... }) decorator but omits what it decorates (class or function-style tool). For consistency with earlier sections and to avoid reader confusion, consider expanding this to:

@Tool({
  name: 'create-order',
  inputSchema: {
    /* ... */
  },
})
class CreateOrderTool {
  /* execute(...) { ... } */
}

or a corresponding tool(...) functional example.


243-260: Clarify inputSchema type to match the earlier object-shaped examples

Here inputSchema is documented as ZodSchema, but most examples above use an object of fields (e.g., { userId: z.string(), ... }). If the implementation accepts both a Zod schema and an object map, it may help to state that explicitly (e.g., “ZodSchema or an object mapping field names to Zod schemas”) to keep the examples and the signature in sync.


307-337: Fix minor issues in the Tool Context example

Two small tweaks would improve this example:

  • this.fetch(url); uses url without defining it; consider inlining a literal URL or declaring a const url = ... above.
  • If this.respond(value) is intended to terminate execution, it may be worth adding a short comment noting that it ends the tool call, since the subsequent return could otherwise look contradictory.

These changes make the snippet easier to follow without altering the conceptual intent.

📜 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 a52dc3e and b6b3989.

📒 Files selected for processing (17)
  • CLAUDE.md (1 hunks)
  • apps/demo/src/apps/expenses/index.ts (2 hunks)
  • apps/demo/src/apps/expenses/prompts/categorize-expense.prompt.ts (1 hunks)
  • apps/demo/src/apps/expenses/prompts/expense-report.prompt.ts (1 hunks)
  • apps/demo/src/apps/expenses/prompts/index.ts (1 hunks)
  • apps/demo/src/apps/expenses/resources/expense-by-id.resource.ts (1 hunks)
  • apps/demo/src/apps/expenses/resources/expense-categories.resource.ts (1 hunks)
  • apps/demo/src/apps/expenses/resources/expense-policy.resource.ts (1 hunks)
  • apps/demo/src/apps/expenses/resources/index.ts (1 hunks)
  • docs/draft/docs/servers/tools.mdx (2 hunks)
  • libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts (1 hunks)
  • libs/sdk/src/common/entries/prompt.entry.ts (1 hunks)
  • libs/sdk/src/common/schemas/annotated-class.schema.ts (2 hunks)
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts (1 hunks)
  • libs/sdk/src/prompt/prompt.instance.ts (1 hunks)
  • libs/sdk/src/tool/tool.registry.ts (1 hunks)
  • libs/sdk/src/transport/adapters/transport.local.adapter.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • libs/sdk/src/transport/adapters/transport.local.adapter.ts
  • libs/sdk/src/common/entries/prompt.entry.ts
  • libs/sdk/src/prompt/prompt.instance.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use strict TypeScript mode with no any types without strong justification; prefer unknown for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific error classes instead

Files:

  • apps/demo/src/apps/expenses/index.ts
  • apps/demo/src/apps/expenses/resources/expense-categories.resource.ts
  • libs/sdk/src/tool/tool.registry.ts
  • apps/demo/src/apps/expenses/resources/index.ts
  • apps/demo/src/apps/expenses/prompts/index.ts
  • apps/demo/src/apps/expenses/prompts/expense-report.prompt.ts
  • apps/demo/src/apps/expenses/resources/expense-by-id.resource.ts
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts
  • apps/demo/src/apps/expenses/resources/expense-policy.resource.ts
  • libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts
  • apps/demo/src/apps/expenses/prompts/categorize-expense.prompt.ts
  • libs/sdk/src/common/schemas/annotated-class.schema.ts
**/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Export barrel exports in index.ts with clean, direct exports; do not add legacy or backwards compatibility exports

Files:

  • apps/demo/src/apps/expenses/index.ts
  • apps/demo/src/apps/expenses/resources/index.ts
  • apps/demo/src/apps/expenses/prompts/index.ts
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/src/apps/expenses/index.ts
  • apps/demo/src/apps/expenses/resources/expense-categories.resource.ts
  • apps/demo/src/apps/expenses/resources/index.ts
  • apps/demo/src/apps/expenses/prompts/index.ts
  • apps/demo/src/apps/expenses/prompts/expense-report.prompt.ts
  • apps/demo/src/apps/expenses/resources/expense-by-id.resource.ts
  • apps/demo/src/apps/expenses/resources/expense-policy.resource.ts
  • apps/demo/src/apps/expenses/prompts/categorize-expense.prompt.ts
libs/sdk/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

libs/sdk/**/*.{ts,tsx}: Create shared base classes for common functionality (e.g., ExecutionContextBase) to reduce code duplication
Use specific error classes extending PublicMcpError with MCP error codes instead of generic errors
Use getCapabilities() for dynamic capability exposure in registries instead of hardcoding capabilities in adapters
Use changeScope instead of scope in change event types to avoid confusion with the Scope class
Validate URIs per RFC 3986 at metadata level using Zod schema validation
Fail fast on invalid hook flows by validating hooks match their entry type during initialization
Use type parameters with constraints instead of unconstrained or any defaults in generic types
Do not mutate rawInput in flows - use state.set() for flow state management instead

Files:

  • libs/sdk/src/tool/tool.registry.ts
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts
  • libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts
  • libs/sdk/src/common/schemas/annotated-class.schema.ts
libs/sdk/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Centralize record types in common/records directory and import from there rather than module-specific files

Files:

  • libs/sdk/src/tool/tool.registry.ts
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts
  • libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts
  • libs/sdk/src/common/schemas/annotated-class.schema.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/tool.registry.ts
  • libs/sdk/src/prompt/flows/get-prompt.flow.ts
  • libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts
  • libs/sdk/src/common/schemas/annotated-class.schema.ts
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/**

⚙️ 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
🧠 Learnings (13)
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/**/*.{ts,tsx} : Use `getCapabilities()` for dynamic capability exposure in registries instead of hardcoding capabilities in adapters

Applied to files:

  • libs/sdk/src/tool/tool.registry.ts
  • libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to **/index.ts : Export barrel exports in index.ts with clean, direct exports; do not add legacy or backwards compatibility exports

Applied to files:

  • apps/demo/src/apps/expenses/resources/index.ts
  • apps/demo/src/apps/expenses/prompts/index.ts
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/src/**/*.{ts,tsx} : Centralize record types in common/records directory and import from there rather than module-specific files

Applied to files:

  • apps/demo/src/apps/expenses/resources/index.ts
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/**/*.{ts,tsx} : Do not mutate rawInput in flows - use state.set() for flow state management instead

Applied to files:

  • libs/sdk/src/prompt/flows/get-prompt.flow.ts
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/**/*.{ts,tsx} : Use specific error classes extending PublicMcpError with MCP error codes instead of generic errors

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to **/*.{ts,tsx} : Use strict TypeScript mode with no `any` types without strong justification; prefer `unknown` for generic type defaults

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/**/*.{ts,tsx} : Use type parameters with constraints instead of unconstrained or `any` defaults in generic types

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/**/*.{ts,tsx} : Fail fast on invalid hook flows by validating hooks match their entry type during initialization

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to **/*.test.{ts,tsx} : Test constructor validation, error class instanceof checks, and all code paths including error conditions

Applied to files:

  • CLAUDE.md
  • libs/sdk/src/common/schemas/annotated-class.schema.ts
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/**/*.{ts,tsx} : Create shared base classes for common functionality (e.g., ExecutionContextBase) to reduce code duplication

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to **/*.{ts,tsx} : Avoid non-null assertions (`!`) - use proper error handling and throw specific error classes instead

Applied to files:

  • CLAUDE.md
📚 Learning: 2025-11-26T15:23:04.938Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.938Z
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:

  • CLAUDE.md
  • libs/sdk/src/common/schemas/annotated-class.schema.ts
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/**/*.{ts,tsx} : Validate URIs per RFC 3986 at metadata level using Zod schema validation

Applied to files:

  • libs/sdk/src/common/schemas/annotated-class.schema.ts
🧬 Code graph analysis (3)
libs/sdk/src/prompt/flows/get-prompt.flow.ts (1)
libs/sdk/src/errors/mcp.error.ts (5)
  • InvalidInputError (223-240)
  • InvalidMethodError (269-273)
  • PromptNotFoundError (368-372)
  • PromptExecutionError (377-396)
  • InvalidOutputError (245-264)
libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts (3)
libs/sdk/src/app/instances/app.local.instance.ts (1)
  • prompts (73-75)
libs/sdk/src/scope/scope.instance.ts (1)
  • prompts (165-167)
libs/sdk/src/common/interfaces/prompt.interface.ts (3)
  • output (91-93)
  • output (95-98)
  • error (111-113)
libs/sdk/src/common/schemas/annotated-class.schema.ts (2)
libs/sdk/src/common/tokens/tool.tokens.ts (1)
  • FrontMcpToolTokens (5-17)
libs/sdk/src/common/tokens/resource.tokens.ts (2)
  • FrontMcpResourceTokens (5-14)
  • FrontMcpResourceTemplateTokens (16-25)
⏰ 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). (1)
  • GitHub Check: build
🔇 Additional comments (7)
libs/sdk/src/common/schemas/annotated-class.schema.ts (2)

81-99: LGTM! Comprehensive resource validation.

The expanded validation correctly handles both Resource and ResourceTemplate forms, supporting both decorator-based and builder-style patterns. The inline comments and updated error message clearly document the accepted forms.


101-112: LGTM! Clear prompt validation logic.

The validation correctly handles both decorator-based and builder-style patterns for prompts. The inline comments and updated error message make the accepted forms explicit.

CLAUDE.md (1)

128-311: SDK guideline updates are consistent and helpful

The added guidance on MCP response types, validation flows, generic defaults (unknown), registry capabilities, and anti-patterns matches the existing coding guidelines and the new prompt/tool flows in this PR. No changes needed.

apps/demo/src/apps/expenses/prompts/categorize-expense.prompt.ts (1)

1-62: Function-style prompt definition is clean and consistent

The prompt configuration, argument handling, and returned message structure are clear and consistent with the rest of the demo prompts. No issues from a correctness or style perspective.

apps/demo/src/apps/expenses/index.ts (1)

11-40: Expenses app wiring for prompts/resources looks correct

The new prompts and resources are imported via their barrels and correctly registered on the @App config. This keeps the app configuration consistent and declarative.

apps/demo/src/apps/expenses/resources/index.ts (1)

1-3: Barrel exports are clean and aligned with guidelines

Directly re-exporting the default resources under descriptive names matches the index.ts barrel export guidance and keeps imports tidy.

apps/demo/src/apps/expenses/prompts/index.ts (1)

1-2: Barrel exports look clean and follow the index.ts guideline

Re-exporting the two prompt modules as named exports is clear and matches the preferred barrel style for index.ts.

Based on learnings, this aligns with the index.ts export guidance.

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 (1)
libs/sdk/src/common/schemas/annotated-class.schema.ts (1)

81-99: Resource schema correctly unifies Resource and ResourceTemplate decorators and builders

annotatedFrontMcpResourcesSchema now:

  • Accepts classes decorated with either FrontMcpResourceTokens.type or FrontMcpResourceTemplateTokens.type.
  • Accepts function-style builders that attach those token keys as properties (for resource() and resourceTemplate()).

The predicate is guarded with typeof v === 'function' before accessing token keys, so it’s safe, and the updated error message clearly explains the accepted forms. If you also expose any @FrontMcpResource* aliases, you might optionally mention them in the message for consistency with providers/auth/providers/plugins/adapters, but the current wording is already accurate.

📜 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 b6b3989 and ca577a2.

📒 Files selected for processing (3)
  • apps/demo/src/apps/expenses/resources/expense-policy.resource.ts (1 hunks)
  • libs/sdk/src/__test-utils__/mocks/prompt-registry.mock.ts (1 hunks)
  • libs/sdk/src/common/schemas/annotated-class.schema.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • libs/sdk/src/test-utils/mocks/prompt-registry.mock.ts
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx}: Use strict TypeScript mode with no any types without strong justification; prefer unknown for generic type defaults
Avoid non-null assertions (!) - use proper error handling and throw specific error classes instead

Files:

  • libs/sdk/src/common/schemas/annotated-class.schema.ts
  • apps/demo/src/apps/expenses/resources/expense-policy.resource.ts
libs/sdk/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

libs/sdk/**/*.{ts,tsx}: Create shared base classes for common functionality (e.g., ExecutionContextBase) to reduce code duplication
Use specific error classes extending PublicMcpError with MCP error codes instead of generic errors
Use getCapabilities() for dynamic capability exposure in registries instead of hardcoding capabilities in adapters
Use changeScope instead of scope in change event types to avoid confusion with the Scope class
Validate URIs per RFC 3986 at metadata level using Zod schema validation
Fail fast on invalid hook flows by validating hooks match their entry type during initialization
Use type parameters with constraints instead of unconstrained or any defaults in generic types
Do not mutate rawInput in flows - use state.set() for flow state management instead

Files:

  • libs/sdk/src/common/schemas/annotated-class.schema.ts
libs/sdk/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Centralize record types in common/records directory and import from there rather than module-specific files

Files:

  • libs/sdk/src/common/schemas/annotated-class.schema.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/common/schemas/annotated-class.schema.ts
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/src/apps/expenses/resources/expense-policy.resource.ts
🧠 Learnings (3)
📚 Learning: 2025-11-26T15:23:04.938Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: libs/ui/CLAUDE.md:0-0
Timestamp: 2025-11-26T15:23:04.938Z
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/common/schemas/annotated-class.schema.ts
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to libs/sdk/**/*.{ts,tsx} : Validate URIs per RFC 3986 at metadata level using Zod schema validation

Applied to files:

  • libs/sdk/src/common/schemas/annotated-class.schema.ts
📚 Learning: 2025-11-26T14:49:12.253Z
Learnt from: CR
Repo: agentfront/frontmcp PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-26T14:49:12.253Z
Learning: Applies to **/*.test.{ts,tsx} : Test constructor validation, error class instanceof checks, and all code paths including error conditions

Applied to files:

  • libs/sdk/src/common/schemas/annotated-class.schema.ts
🧬 Code graph analysis (1)
libs/sdk/src/common/schemas/annotated-class.schema.ts (2)
libs/sdk/src/common/tokens/tool.tokens.ts (1)
  • FrontMcpToolTokens (5-17)
libs/sdk/src/common/tokens/resource.tokens.ts (2)
  • FrontMcpResourceTokens (5-14)
  • FrontMcpResourceTemplateTokens (16-25)
⏰ 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). (1)
  • GitHub Check: build
🔇 Additional comments (4)
apps/demo/src/apps/expenses/resources/expense-policy.resource.ts (1)

1-59: Expense policy resource is well-structured and demo-appropriate

The resource wiring and execute implementation look clean: static policy data is clearly organized, fully JSON-serializable, and returned in a single contents entry with mimeType: 'application/json'. Using Number.MAX_SAFE_INTEGER for the top approvalLevels threshold avoids the earlier Infinity-serialization pitfall while remaining effectively “unbounded” for demo purposes. No correctness or typing issues stand out here.

libs/sdk/src/common/schemas/annotated-class.schema.ts (3)

3-20: Import and metadata wiring for new resource template support looks correct

The addition of FrontMcpResourceTemplateTokens to the tokens import and the extra metadata schema imports are consistent with the usages below (resources and auth/provider/plugin/adapters schemas). No issues from an API or typing perspective here.


71-79: Tool schema now correctly recognizes both decorator- and builder-style tools

The annotatedFrontMcpToolsSchema predicate cleanly handles:

  • Class/function tools annotated via @Tool() / @FrontMcpTool() (metadata on the constructor), and
  • Function-style builders that set FrontMcpToolTokens.type directly on the function object.

The typeof v === 'function' guard before metadata/property checks keeps this safe. No changes needed.


101-112: Prompt schema extension for builder-style prompts looks consistent

annotatedFrontMcpPromptsSchema now validates both:

  • Class-based prompts with FrontMcpPromptTokens metadata, and
  • Function-style prompt() builders that attach FrontMcpPromptTokens.type as a property.

The typeof v === 'function' guard ensures the property access is safe, and the error message clearly mentions both decorator and builder usage. This aligns well with the tools/resources handling.

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