Add MCP usage server and richer spend analytics - #87
Conversation
Expose quota and estimated spend over stdio via `codexbar mcp`, and persist the widget snapshot on desktop refresh so cache-only tools work.
Show cache-read %, cost/call, and output/call on the model breakdown, and surface Today/30d dollar deltas on the estimated API value card.
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
ceiling | 910c8b1 | Commit Preview URL Branch Preview URL |
Jul 20 2026, 04:04 AM |
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 35 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the 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 configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (4)
📝 WalkthroughWalkthroughThe changes add cache and call-based usage metrics, four-period API value comparisons, richer model-breakdown rendering, provider snapshot persistence, and a local MCP stdio server exposing quota and spend tools. ChangesLocal usage analytics
Local MCP access
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant MCPClient
participant CeilingMcp
participant WidgetSnapshotStore
participant CostScanner
MCPClient->>CeilingMcp: call get_status
CeilingMcp->>WidgetSnapshotStore: load provider snapshot
WidgetSnapshotStore-->>CeilingMcp: return cached quota
CeilingMcp->>CostScanner: scan local spend
CostScanner-->>CeilingMcp: return spend summary
CeilingMcp-->>MCPClient: return combined JSON status
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/desktop-tauri/src-tauri/src/commands/chart.rs (1)
569-628: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winOff-by-one: the "30 days" window is actually 31 days, while "prior 30 days" is exactly 30 days.
thirty_start = today - 30 dayscombined withthirty_end = today + 1 dayyields a half-open window[today-30, today+1)spanning 31 calendar dates (today-30 … today inclusive). Meanwhileprior_start = today - 60 dayscombined with the samethirty_startas the end yields[today-60, today-30), which is exactly 30 dates. Comparing a 31-day window against an adjacent 30-day window for "30d vs prior 30d" dollar period-over-period skews the reported percent change (the current period always has one extra day of activity baked in).Shift both boundaries back by one day so both windows are exactly 30 days:
🐛 Proposed fix to align both 30-day windows
- let thirty_start = local_midnight_utc(today - chrono::Duration::days(30)); + let thirty_start = local_midnight_utc(today - chrono::Duration::days(29)); let thirty_end = local_midnight_utc(today + chrono::Duration::days(1)); - let prior_start = local_midnight_utc(today - chrono::Duration::days(60)); + let prior_start = local_midnight_utc(today - chrono::Duration::days(59));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop-tauri/src-tauri/src/commands/chart.rs` around lines 569 - 628, Update load_local_api_value_totals so the thirty-day window is exactly 30 calendar days: set thirty_start to today minus 30 days and thirty_end to today (not tomorrow), while retaining prior_start at today minus 60 days and the adjacent [prior_start, thirty_start) prior_thirty window.
🧹 Nitpick comments (1)
rust/src/cost_scanner.rs (1)
101-118: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winConsider adding local unit tests for
processed()/merge_from().These are new, non-trivial aggregation helpers; today they're only exercised indirectly via
chart.rstests (model_breakdown_orders_priced_first_and_keeps_unpriced, etc.). A focused#[cfg(test)]module here would pin down behavior (e.g.,merge_fromsumming all buckets,processed()excludingcached_tokens) independent of the UI-facing consumer.Also note: Rust tests could not be executed in this review environment, so this suggestion is unverified against
cargo test.As per path instructions, "rust/src/**/*.rs: Add or extend focused Rust tests near the changed module, commonly using
#[cfg(test)]unit tests."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@rust/src/cost_scanner.rs` around lines 101 - 118, Add a focused #[cfg(test)] module near ModelTokenCounts with unit tests for processed() and merge_from(). Verify processed() sums input, output, cache-read, and cache-write tokens while excluding cached_tokens, and verify merge_from() accumulates every token bucket and calls field.Source: Path instructions
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/desktop-tauri/src-tauri/src/commands/providers.rs`:
- Around line 534-563: The widget snapshot mapper function
widget_entry_from_usage_snapshot must also populate token_usage from snap.cost
so provider-refresh snapshots emit the session cost value. Extend the existing
cost-handling block to set token_usage using the appropriate cost value while
preserving the current credits_remaining mapping.
In `@rust/src/cli/mcp.rs`:
- Around line 282-331: Update the get_status flow around choose_status_provider
and status_payload to distinguish an explicitly supplied but unrecognized
provider from an absent provider. Return the same clear “Unknown provider
'{name}'” error used by usage_payload and spend_payload instead of producing a
status payload with ok: false; preserve existing provider selection for
recognized or omitted names.
---
Outside diff comments:
In `@apps/desktop-tauri/src-tauri/src/commands/chart.rs`:
- Around line 569-628: Update load_local_api_value_totals so the thirty-day
window is exactly 30 calendar days: set thirty_start to today minus 30 days and
thirty_end to today (not tomorrow), while retaining prior_start at today minus
60 days and the adjacent [prior_start, thirty_start) prior_thirty window.
---
Nitpick comments:
In `@rust/src/cost_scanner.rs`:
- Around line 101-118: Add a focused #[cfg(test)] module near ModelTokenCounts
with unit tests for processed() and merge_from(). Verify processed() sums input,
output, cache-read, and cache-write tokens while excluding cached_tokens, and
verify merge_from() accumulates every token bucket and calls field.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: bbc2da87-e44b-4cb8-a075-d8ccc6920948
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (15)
apps/desktop-tauri/src-tauri/src/commands/chart.rsapps/desktop-tauri/src-tauri/src/commands/providers.rsapps/desktop-tauri/src/components/TotalApiValueCard.test.tsxapps/desktop-tauri/src/components/TotalApiValueCard.tsxapps/desktop-tauri/src/lib/apiValueCard.test.tsapps/desktop-tauri/src/lib/apiValueCard.tsapps/desktop-tauri/src/styles.cssapps/desktop-tauri/src/surfaces/settings/providers/sections/charts/ChartsSection.tsxapps/desktop-tauri/src/types/bridge.tsrust/Cargo.tomlrust/src/cli/mcp.rsrust/src/cli/mod.rsrust/src/codex_costs.rsrust/src/cost_scanner.rsrust/src/main.rs
Align 30d windows, persist session cost in widget snapshots, reject unknown providers in get_status, and add ModelTokenCounts unit tests.
Summary
codexbar mcpstdio MCP server (list_providers,get_usage,get_spend,get_status) and persist widget snapshots on desktop refresh so cache-only quota tools work (SOU-276).Test plan
cargo test --manifest-path rust/Cargo.toml --lib cli::mcpcargo test --manifest-path apps/desktop-tauri/src-tauri/Cargo.toml model_breakdownpnpm --dir apps/desktop-tauri test -- run src/lib/apiValueCard.test.ts src/components/TotalApiValueCard.test.tsxcodexbar mcp --helpthen configure Claude Code/Cursor MCP tocodexbar mcpand callget_statusSummary by CodeRabbit
New Features
Improvements