Skip to content

feat(069-A3): GET /api/v1/activity/usage endpoint#565

Merged
Dumbris merged 1 commit into
mainfrom
069-a3-activity-usage-endpoint
Jun 2, 2026
Merged

feat(069-A3): GET /api/v1/activity/usage endpoint#565
Dumbris merged 1 commit into
mainfrom
069-a3-activity-usage-endpoint

Conversation

@Dumbris
Copy link
Copy Markdown
Member

@Dumbris Dumbris commented Jun 1, 2026

Spec 069 A3 (MCP-750) — usage statistics endpoint

Backend stream A3: GET /api/v1/activity/usage, serving the actor-owned usage aggregate (shipped in A2 / #560) over REST. This publishes the contract the frontend (B1/B2) consumes and unblocks those streams.

Reads the in-memory snapshot only — never a per-request full-log scan (SC-005).

What's in it (tasks T011–T015, T024–T026)

  • contractsUsageAggregateResponse + UsageToolStat / UsageOtherBucket / UsageTimeBucket.
  • handler handleActivityUsage:
    • window (24h/7d/all), server/tool/status membership filters (FR-008), sort (calls/resp_bytes/error_rate/p95), top N + other fold.
    • avg_resp_bytes/avg_req_bytes over sized (non-zero-byte) calls onlynull when none; tokens_saved echoed from ServerTokenMetrics (FR-007); token_source: "bytes" (FR-006).
    • empty-state 200 (FR-009); 400 on bad window/sort/status enum or non-positive top.
    • short-TTL read cache keyed on the query, honouring observability.usage_cache_ttl (FR-005), read per request so it hot-reloads.
  • controllerUsageSnapshot() exposed through server → runtime → ActivityService.
  • oas — swag-generated path + schemas; verify-oas-coverage.sh passes in CI.

Design note — windowing semantics

The A2 aggregate keeps cumulative per-tool rollups + global hourly timeline buckets (no per-tool-per-window data). So:

  • per-tool metrics are lifetime-cumulative;
  • window scopes the timeline span and filters the tool list to tools active within it (by last_used).

Exact per-tool windowed counts are a deferred follow-on (would require per-tool time buckets in the aggregate). Documented in the contract type, the swagger description, and tasks.md.

Deviation from tasks.md

T013 suggested reusing parseActivityFilters. That parser silently ignores bad input (no 400s) and handles unrelated pagination/detection filters. The usage endpoint needs strict enum validation for its own params (window/sort/top), so it uses a dedicated parseUsageParams while keeping the shared server/tool/status param names consistent.

Verification

  • go test ./internal/httpapi/ — new TestActivityUsage_* green (ranking, error_rate, avg-excludes-0-byte, window, top-N, filters, empty-state, 400). Tests replay records through the real Apply path so latency/sized math is exercised, not mocked.
  • TestActivityUsage_NoFullScanPerRequest — SC-005 perf assertion (handler never calls AggregateToolUsage).
  • go test ./internal/runtime/... -race — all green (canary safe).
  • ./scripts/test-api-e2e.sh — 65/65 passed.
  • ./scripts/run-linter.sh — 0 issues.
  • Manual smoke on a live server: empty-state 200 with tools: []/timeline: []; bad window/top → 400.

Related #745

🤖 Generated with Claude Code

Serve the actor-owned usage aggregate (spec 069 A2) over REST so the Web
UI usage graphs (B1/B2) have a contract to consume. Reads the in-memory
snapshot only — never a per-request full-log scan (SC-005).

- contracts: UsageAggregateResponse + UsageToolStat / UsageOtherBucket /
  UsageTimeBucket.
- handler: handleActivityUsage with window (24h/7d/all), server/tool/status
  membership filters (FR-008), sort (calls/resp_bytes/error_rate/p95),
  top-N + 'other' fold, empty-state 200 (FR-009), 400 on bad enum/top.
  avg_* computed over sized (non-zero-byte) calls only; tokens_saved echoed
  from ServerTokenMetrics (FR-007). Short-TTL read cache keyed on the query
  honours observability.usage_cache_ttl (FR-005, hot-reloaded per request).
- controller: UsageSnapshot() exposed through server -> runtime ->
  ActivityService.
- oas: swag-generated path + schemas; verify-oas-coverage passes.

Windowing note: per-tool metrics are lifetime-cumulative (the A2 aggregate
keeps cumulative per-tool rollups + global hourly timeline buckets, no
per-tool-per-window data); window scopes the timeline span and filters the
tool list to tools active within it. Exact per-tool windowed counts are a
deferred follow-on (would need per-tool time buckets in the aggregate).

Tests: TestActivityUsage_* (ranking/error_rate/avg-excludes-0-byte/window/
top-N/filters/empty-state/400) replay records through the real Apply path;
TestActivityUsage_NoFullScanPerRequest is the SC-005 perf assertion.

Related #745
@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying mcpproxy-docs with  Cloudflare Pages  Cloudflare Pages

Latest commit: f65d840
Status: ✅  Deploy successful!
Preview URL: https://01e322eb.mcpproxy-docs.pages.dev
Branch Preview URL: https://069-a3-activity-usage-endpoi.mcpproxy-docs.pages.dev

View logs

@codecov-commenter
Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 85.63830% with 27 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/httpapi/activity.go 89.63% 15 Missing and 2 partials ⚠️
internal/httpapi/server.go 77.77% 2 Missing and 2 partials ⚠️
internal/runtime/runtime.go 0.00% 4 Missing ⚠️
internal/server/server.go 0.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 1, 2026

📦 Build Artifacts

Workflow Run: View Run
Branch: 069-a3-activity-usage-endpoint

Available Artifacts

  • archive-darwin-amd64 (28 MB)
  • archive-darwin-arm64 (25 MB)
  • archive-linux-amd64 (16 MB)
  • archive-linux-arm64 (14 MB)
  • archive-windows-amd64 (27 MB)
  • archive-windows-arm64 (24 MB)
  • frontend-dist-pr (0 MB)
  • installer-dmg-darwin-amd64 (21 MB)
  • installer-dmg-darwin-arm64 (19 MB)

How to Download

Option 1: GitHub Web UI (easiest)

  1. Go to the workflow run page linked above
  2. Scroll to the bottom "Artifacts" section
  3. Click on the artifact you want to download

Option 2: GitHub CLI

gh run download 26765067958 --repo smart-mcp-proxy/mcpproxy-go

Note: Artifacts expire in 14 days.

@Dumbris Dumbris merged commit 33bb6e3 into main Jun 2, 2026
37 checks passed
@Dumbris Dumbris deleted the 069-a3-activity-usage-endpoint branch June 2, 2026 02:48
Dumbris added a commit that referenced this pull request Jun 2, 2026
)

Spec 069 Stream B1 (T016–T017). Adds the Overview↔Usage switcher to the
dashboard and the typed client for the A3 GET /api/v1/activity/usage
endpoint (#565).

- api: getActivityUsage(params) forwards only supplied filters
  (window/server/tool/status/top/sort); UsageAggregateResponse +
  UsageToolStat/UsageOtherBucket/UsageTimeBucket types mirror the contract.
- Dashboard: tabbed Overview↔Usage switcher rendered with v-show (never
  v-if) so Overview state survives a switch-back (SC-006). Usage panel has
  a 24h/7d/all window selector, tokens-saved headline (FR-007),
  loading/error/empty states (FR-009) and a baseline per-tool rollup table;
  the rich charts arrive in B2 (T018–T022).
- Lazy load: the aggregate is fetched on first Usage activation and on
  window change only, so the Overview first paint is never blocked (SC-004).
- Tests (TDD): activity-usage.spec (client param forwarding) +
  dashboard-usage-switcher.spec (default tab, lazy fetch, v-show preserve,
  window refetch). All 91 frontend unit tests green; vue-tsc clean.

Related #745
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