Skip to content

feat(app): WebMCP tools for leaderboard and XP (Agent-Ready quest, part A) - #610

Open
mschilling wants to merge 2 commits into
mainfrom
feat/webmcp-agent-ready
Open

mschilling wants to merge 2 commits into
mainfrom
feat/webmcp-agent-ready

Conversation

@mschilling

Copy link
Copy Markdown
Contributor

What

This is the first step of the "Agent-Ready" quest. The player app (apps/frontend/app) now exposes read-only WebMCP tools, so an in-browser AI agent can drive the screens players already use. Each tool changes what the user sees and returns a short text summary (≤1,500 chars).

Tool Where Input On screen
show_leaderboard /leaderboard, /leaderboard/{heroes,bots,projects} { period: 'day' | 'week' } Switches the period toggle (same path as clicking it). Returns the top 5 plus your rank. On the overview it says "not in top 5" when that applies.
explain_xp /hq { period, compare?: boolean } Scrolls to and outlines the Daily Progress or Weekly Stats card. Summarises XP and activity counts from data already loaded. compare adds the daily goal (day) or your weekly Heroes rank (week).
compare_with /leaderboard/heroes { user: string } Highlights and scrolls to the matched hero's row. Compares their rank, XP and level with yours. If the name is ambiguous it returns the candidates; if there is no match it returns isError.
  • All tools are readOnlyHint: true. The leaderboard tools also set untrustedContentHint: true, because display names are user-controlled. Names are quoted, collapsed and capped in the output.
  • No dependency was added. Local TypeScript types in core/webmcp/model-context.ts follow the WebMCP draft.

Plan

  1. core/webmcp/model-context.ts
    • Feature-detects document.modelContext, falling back to navigator.modelContext. Without either it is a silent no-op.
    • registerWebMcpTools(tools, destroyRef) registers each tool with { signal } from an AbortController and aborts it on DestroyRef.onDestroy. It also calls unregisterTool(name) on early Chromium builds that ignore the signal.
    • A module-level registry keyed by tool name lets the newest owner win. Angular can create the next route's component before it destroys the old one: /leaderboard → /leaderboard/heroes both register show_leaderboard. Destroying the old component then doesn't remove the new tool.
    • waitUntil() polls a signal-backed condition. execute runs outside an injection context, so toObservable can't be used there.
    • Local-only debug registry window.__codeheroesWebMcp, gated on environment.name === 'local'. Headless Chrome has no WebMCP, so screenshots and manual checks call execute through it.
  2. core/webmcp/webmcp-format.ts: pure formatters (leaderboard summary, XP breakdown, comparison, name matching) and budget clamping.
  3. core/webmcp/code-heroes-tools.ts: tool factories that take accessor callbacks over the components' existing signals. The components stay the source of truth, and the tools can be tested without TestBed.
  4. Wiring:
    • LeaderboardComponent registers show_leaderboard.
    • FullLeaderboardComponent registers show_leaderboard, plus compare_with on heroes only. It adds a highlightedId signal and an .is-highlighted row style.
    • HqComponent registers explain_xp. It adds a focusedCard signal and an outline that clears after 4s.

The plan was rubber-ducked before implementation. That review led to the duplicate-name registry, no toObservable in execute, partial-board wording on the overview, ambiguous matches returning candidates, and quoted names.

Part B: "Agent-Ready" achievement (design only, follow-up)

Goal: award a special badge when a merged PR introduces WebMCP (modelContext.registerTool( or a toolname= form attribute).

Why it is not in this PR: the pull_request (closed + merged) and push webhook payloads carry no diffs. Detection needs the GitHub REST API:

  1. github-receiver keeps doing what it does. The merged PR event already produces a pull_request_merge game action.
  2. In game-engine (or a small dedicated Firestore-triggered function, so game-engine stays I/O-free), on pull_request_merge:
    • mint an installation token via the existing GitHubAppService (libs/server/integrations), using installation.id from the stored event;
    • call GET /repos/{owner}/{repo}/pulls/{number}/files?per_page=100 (max 3,000 files; patch is omitted for very large diffs);
    • scan only added lines (+ lines in patch) for /\bmodelContext\.registerTool\s*\(/ or /\btoolname\s*=/. Skip node_modules, lockfiles and dist/.
  3. On a hit, award a new agent_ready entry in SPECIAL_BADGES (metadata: { trigger: 'webmcp_introduced' }) through SpecialBadgeService. The badge is idempotent per user, like the other special badges.
  4. Costs and risks:
    • adds GITHUB_APP_ID / GITHUB_APP_PRIVATE_KEY secrets to another function;
    • one or more API calls per merged PR (rate limit 5k/h per installation);
    • only repos where the Code Heroes GitHub App is installed (not legacy webhooks);
    • Azure DevOps and Bitbucket would need their own diff endpoints.

Each of these warrants its own PR and review, so it is a follow-up issue.

How to test

  1. npx nx test app runs the new specs in core/webmcp/*.spec.ts: 24 tests covering formatting, budgets, matching, registration/abort lifecycle and the newest-owner-wins rule.
  2. Locally (nx serve app, emulators), open /leaderboard/heroes and in DevTools run:
    await __codeheroesWebMcp.show_leaderboard({ period: 'day' })   // toggle flips to "Today"
    await __codeheroesWebMcp.compare_with({ user: 'captain' })     // row gets highlighted
    On /hq: await __codeheroesWebMcp.explain_xp({ period: 'week', compare: true }).
  3. In a WebMCP-enabled browser (Chrome with the WebMCP flag / an agent extension), the tools show up per route and disappear on navigation.

Test plan

  • Unit tests for the new code pass (nx test app: 24/24)
  • nx build app (production) succeeds; no new budget warnings (the two existing component-style warnings are in settings/badges-modal)
  • eslint on touched files: no new findings (the 4 errors in leaderboard-section.component.ts and the unused computed warning were already on main)
  • New files are Prettier-formatted (touched components were already not Prettier-clean on main, so they were not reformatted, to keep the diff small)
  • Manual check against the local auth emulator with mocked leaderboard API (fictional heroes): show_leaderboard switched Week → Today; compare_with highlighted the matched row
  • Verify in a browser with native document.modelContext (tool list changes on route navigation)

Notes

  • Pre-existing, unrelated:
    • nx lint app already fails on main (a11y click/key and prefer-inject errors in other files).
    • After npm run setup, Jest also picks up the generated src/environments/environment.test.ts, because it matches *.test.ts, and reports it as an empty failing suite. Without that generated file all suites pass. CI doesn't run setup, so this doesn't affect CI.
  • The weekly breakdown reports activity counts. Per-action XP isn't stored in the weekly stats record, so the tool doesn't invent it.
  • compare_with works on the current period of the heroes leaderboard only. It doesn't add a new compare view.
  • Follow-ups: Part B (above); optionally a /users/:id profile-level compare once a compare view exists.

…ebMCP

Register read-only WebMCP tools tied to component lifecycle:
show_leaderboard (switches the visible period), explain_xp (summarises
HQ XP cards) and compare_with (highlights another hero's row and
compares XP). Tools unregister through an AbortController on DestroyRef
and are a silent no-op without document.modelContext.
Copilot AI balanced review requested due to automatic review settings October 6, 2026 21:14
@mschilling mschilling added enhancement Improvement to existing feature app: app Main PWA app (apps/frontend/app) xp-system XP calculation/rewards leaderboard Ranking/leaderboard features labels Oct 6, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

Period races and ignored loading timeouts can produce inaccurate or unsuccessful tool responses.

Review effort: Balanced
Findings: 2 Medium severity · 2 Low severity

Open (4)
What changed in this PR

Adds read-only WebMCP tools to the Angular player app for leaderboard navigation, hero comparison, and XP summaries.

Changes:

  • Introduces WebMCP registration, lifecycle handling, and local debugging.
  • Adds formatting and tool factories with unit tests.
  • Wires tools and visual highlighting into leaderboard and HQ screens.
File Description
leaderboard.component.ts Registers the overview leaderboard tool.
full-leaderboard.component.ts Registers leaderboard/comparison tools and row highlighting.
hq.component.ts Registers XP explanation and card highlighting.
model-context.ts Implements WebMCP types, registration, cleanup, and utilities.
model-context.spec.ts Tests registration lifecycle and tool execution.
code-heroes-tools.ts Defines the three WebMCP tools.
webmcp-format.ts Formats leaderboard, XP, and comparison responses.
webmcp-format.spec.ts Tests formatting, matching, and output limits.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread apps/frontend/app/src/app/core/webmcp/code-heroes-tools.ts
Comment thread apps/frontend/app/src/app/core/webmcp/code-heroes-tools.ts Outdated
Comment thread apps/frontend/app/src/app/core/webmcp/webmcp-format.ts
Comment thread apps/frontend/app/src/app/core/webmcp/webmcp-format.ts Outdated
- show_leaderboard errors if the visible period changed while loading
- explain_xp errors when HQ data does not finish loading in time
- daily goal reached exactly no longer reports '0 XP over'
- singular nouns for activity counts of one

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: app Main PWA app (apps/frontend/app) enhancement Improvement to existing feature leaderboard Ranking/leaderboard features xp-system XP calculation/rewards

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants