Skip to content

fix(api): invalidate analytics cache on MCP conversation writes - #415

Open
duyetbot wants to merge 2 commits into
mainfrom
fix/mcp-analytics-cache-372
Open

fix(api): invalidate analytics cache on MCP conversation writes#415
duyetbot wants to merge 2 commits into
mainfrom
fix/mcp-analytics-cache-372

Conversation

@duyetbot

@duyetbot duyetbot commented Aug 14, 2026

Copy link
Copy Markdown
Collaborator

Summary

MCP store_conversation writes the same conversations/messages tables as REST but skipped invalidateAnalyticsCache(). Dashboard analytics could stay stale for the full cache TTL (60–300s).

  • Call the existing helper from mcp-conversations create/delete, matching REST #370
  • Pass c.executionCtx and c.env.AUTH_CACHE from the MCP store_conversation tool
  • Add an analytics test that writes via MCP and asserts counts update immediately (no stale cache)

Closes #372

Test plan

  • cd packages/api && bunx vitest run test/analytics.test.ts test/mcp.test.ts (20 passed)
  • CI green on this PR

Summary by Sourcery

Invalidate analytics cache when MCP conversations are created or deleted to keep dashboard metrics in sync with MCP writes.

Bug Fixes:

  • Ensure analytics counts update immediately after MCP store_conversation calls by invalidating the cache for the affected project.

Enhancements:

  • Wire execution context and auth cache into MCP conversation creation/deletion to reuse the existing analytics cache invalidation helper.

Tests:

  • Add an analytics test that verifies MCP-based conversation writes update analytics counts without stale cache.

MCP store_conversation writes the same conversations/messages tables
as REST but skipped the invalidateAnalyticsCache() helper added in
#370. Dashboard analytics could stay stale for the full cache TTL.

Call the helper from mcp-conversations create/delete, matching REST,
and cover the live MCP write path in the existing analytics suite.

Closes #372

Co-Authored-By: Duyet Le <me@duyet.net>
Co-Authored-By: duyetbot <bot@duyet.net>
@sourcery-ai

sourcery-ai Bot commented Aug 14, 2026

Copy link
Copy Markdown

Reviewer's Guide

This PR ensures MCP conversation writes invalidate the analytics cache just like REST, by threading execution context and cache into the MCP tools and wiring invalidateAnalyticsCache into the MCP conversations service, plus a regression test to guard against stale analytics after MCP store_conversation.

Sequence diagram for MCP store_conversation analytics cache invalidation

sequenceDiagram
  actor MCPClient
  participant StoreConversationTool as store_conversation_tool
  participant ConversationsService as conversationsService
  participant AnalyticsCache as AUTH_CACHE

  MCPClient->>StoreConversationTool: invoke handler
  StoreConversationTool->>ConversationsService: createConversation(db, input, executionCtx, AUTH_CACHE)
  ConversationsService->>ConversationsService: insert conversations
  ConversationsService->>ConversationsService: insert messages
  ConversationsService->>AnalyticsCache: invalidateAnalyticsCache(AUTH_CACHE, executionCtx, projectId)
  ConversationsService-->>StoreConversationTool: CreateConversationResult
  StoreConversationTool-->>MCPClient: conversation id, project_id
Loading

File-Level Changes

Change Details Files
Wire analytics cache invalidation into MCP conversation create/delete paths to match REST behavior.
  • Update MCP tools.store_conversation handler to pass execution context and AUTH_CACHE through to the conversations service createConversation call.
  • Extend mcp-conversations createConversation signature to accept ExecutionContext and optional KVNamespace and call invalidateAnalyticsCache after inserting conversations/messages.
  • Extend mcp-conversations deleteConversation signature to accept projectId, ExecutionContext, and optional KVNamespace and call invalidateAnalyticsCache after batch deleting related rows.
packages/api/src/routes/mcp/tools.ts
packages/api/src/services/mcp-conversations.ts
Add a regression test verifying analytics counts update immediately after MCP store_conversation writes.
  • Add a vitest test case that calls MCP tools/call store_conversation over HTTP, parses the created conversation id, and then fetches analytics.
  • Assert that total_conversations, total_messages, and total_tokens increase by the expected amounts immediately, ensuring no stale cache behavior.
packages/api/test/analytics.test.ts

Assessment against linked issues

Issue Objective Addressed Explanation
#372 Ensure MCP service createConversation path in packages/api/src/services/mcp-conversations.ts invalidates the analytics cache using the shared invalidateAnalyticsCache helper so dashboard analytics are not stale after MCP writes.
#372 Ensure MCP service deleteConversation path in packages/api/src/services/mcp-conversations.ts invalidates the analytics cache using the shared invalidateAnalyticsCache helper so dashboard analytics are not stale after MCP deletions.

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Aug 14, 2026

Copy link
Copy Markdown

Warning

Review limit reached

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

Next review available in: 113 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

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

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

How do review limits work?

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

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

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: fd24bb6e-ca71-4914-8d3d-3db0291c4402

📥 Commits

Reviewing files that changed from the base of the PR and between 39c28e4 and 9a8f32c.

📒 Files selected for processing (3)
  • packages/api/src/routes/mcp/tools.ts
  • packages/api/src/services/mcp-conversations.ts
  • packages/api/test/analytics.test.ts

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

❤️ Share

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

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • The new createConversation/deleteConversation signatures in mcp-conversations add executionCtx and cache parameters; consider either providing sensible defaults or a backwards-compatible wrapper to avoid breaking existing internal callers.
  • The analytics test for MCP store_conversation hardcodes the expected token delta (10); making the assertion derive from the token_count values in the test input would make it less brittle if message/token handling changes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `createConversation`/`deleteConversation` signatures in `mcp-conversations` add `executionCtx` and `cache` parameters; consider either providing sensible defaults or a backwards-compatible wrapper to avoid breaking existing internal callers.
- The analytics test for MCP `store_conversation` hardcodes the expected token delta (10); making the assertion derive from the `token_count` values in the test input would make it less brittle if message/token handling changes.

## Individual Comments

### Comment 1
<location path="packages/api/test/analytics.test.ts" line_range="206" />
<code_context>
+
+      expect(after.summary.total_conversations).toBe(baseConvs + 1);
+      expect(after.summary.total_messages).toBe(baseMsgs + 2);
+      expect(after.summary.total_tokens).toBe(baseTokens + 10);
+    });
+
</code_context>
<issue_to_address>
**suggestion (testing):** Derive the expected token delta from the request payload instead of hardcoding `10`.

This test couples the assertion to the current payload by hardcoding `10` as the token delta. Instead, derive the expected delta from the `messages` array (e.g., sum their `token_count` values) and assert against `baseTokens + expectedTokenDelta`. That keeps the test validating that analytics mirror the stored conversation while remaining resilient to future changes in message content or token-counting logic.

Suggested implementation:

```typescript
      expect(after.summary.total_conversations).toBe(baseConvs + 1);
      expect(after.summary.total_messages).toBe(baseMsgs + 2);

      const expectedTokenDelta = messages.reduce(
        (sum, message) => sum + (message.token_count ?? 0),
        0,
      );
      expect(after.summary.total_tokens).toBe(baseTokens + expectedTokenDelta);

```

The above edit assumes there is a `messages` array in scope corresponding to the request payload used in the `store` call (each element having a `token_count` field). You may need to:
1. Ensure the `messages` variable is defined in this test and matches the structure sent in the POST body (e.g., extracted or reused from the payload object).
2. Adjust the reducer if the shape is different (for example, `message.token_count` might live under `message.metadata.token_count` or similar).
3. If the request payload is not directly accessible here, derive `messages` from whatever object you use to construct the POST body, and place its definition above these expectations within the same `it` block.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread packages/api/test/analytics.test.ts Outdated
Address Sourcery review on the #372 cache-invalidation test.

Co-Authored-By: Duyet Le <me@duyet.net>
Co-Authored-By: duyetbot <bot@duyet.net>
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.

[api] services/mcp-conversations.ts has the same analytics-cache staleness gap being fixed in #352

2 participants