Summary
Add an analytics MCP app — an embedded MCP Apps surface that renders the
agent-work-analytics dashboard inside an MCP host (e.g. a chat client), reusing
the shared <AnalyticsBoard> React component shipped in #1551.
This is the deferred MCP-app follow-up to #1373 / #1551. #1551 delivered the
reusable analytics UI (@moltnet/task-ui) and the Console integration; the design
explicitly scoped the MCP app as a follow-up built on the exported AnalyticsBoard.
Background
The one surface still missing is the MCP app, so an agent/human interacting
through an MCP host can pull up the same analytics without the Console.
Key constraint: MCP apps use tools, not REST
MCP apps never receive a bearer token or call REST directly — the iframe reads
data through the host bridge via app.callServerTool({ name, arguments })
against deterministic MCP server tools (see apps/mcp-server/src/task-app.ts:
"The iframe never receives a bearer token or talks to REST directly").
#1550 added only the REST endpoint — there is no analytics MCP tool yet. So
this issue has two cohesive parts (the app is inert without the tool → one PR).
Scope
1. MCP server tool tasks_analytics_activity
- New deterministic tool in
apps/mcp-server wrapping
@moltnet/task-analytics-service.getActivityAnalytics.
- TypeBox input schema mirroring the REST query:
completedAfter, completedBefore,
tags, taskTypes, profileIds, diaryIds, claimedByAgentIds, groupBy
(none|day|tag|taskType|profile|diary|agent|providerModel).
- Team scope resolved from the MCP session (not an
x-moltnet-team-id header).
- Returns
TaskActivityAnalyticsResponse (same shape as the REST endpoint /
the generated client / @moltnet/task-ui's type).
- Register in the legreffier MCP tool surface; add to the tool-schema tests.
2. Analytics MCP app libs/analytics-mcp-app (React)
Mirrors libs/entry-explore-mcp-app (the existing React MCP-app precedent —
task-mcp-app is vanilla DOM and can't render the React AnalyticsBoard):
metadata.ts — ANALYTICS_MCP_APP_NAME = 'moltnet_task_analytics', _TITLE,
_RESOURCE_URI = 'ui://moltnet/tasks/analytics.html'.
main.tsx — createRoot → <AnalyticsApp/>.
AnalyticsApp.tsx — useApp from @modelcontextprotocol/ext-apps/react; seed
filters from the ontoolinput opener payload; call tasks_analytics_activity
via a typed callTool; map the tool JSON result → TaskActivityAnalyticsResponse;
render <AnalyticsBoard> (from @moltnet/task-ui) under MoltThemeProvider.
Owns the explicit loading/error/empty/ready status mapping (same logic as the
Console TaskAnalyticsPage).
adapter/ — tool-caller.ts + tool-calls.ts (typed callTool for
tasks_analytics_activity, snake_case args mirroring the server schema) +
mcp-adapter.ts (camelCase filters → snake_case args; result JSON → response
type). Unit tests mirroring entry-explore-mcp-app/src/adapter/*.test.ts.
theme-tokens.ts, styles.css, index.ts (re-exports metadata constants),
singlefile vite.config.ts, tsconfigs, package.json
(react/react-dom + @modelcontextprotocol/ext-apps + @moltnet/task-ui +
@themoltnet/design-system).
- Registration:
apps/mcp-server/src/analytics-app.ts (mirror task-app.ts /
entry-explore-app.ts) serving the built HTML resource, plus
apps/mcp-server/__tests__/analytics-app.test.ts.
Reuse / non-goals
Acceptance criteria
References
Summary
Add an analytics MCP app — an embedded MCP Apps surface that renders the
agent-work-analytics dashboard inside an MCP host (e.g. a chat client), reusing
the shared
<AnalyticsBoard>React component shipped in #1551.This is the deferred MCP-app follow-up to #1373 / #1551. #1551 delivered the
reusable analytics UI (
@moltnet/task-ui) and the Console integration; the designexplicitly scoped the MCP app as a follow-up built on the exported
AnalyticsBoard.Background
task_attempt_activity_statstable,@moltnet/task-analytics-service, and theREST endpoint
GET /tasks/analytics/activityreturningTaskActivityAnalyticsResponse.@moltnet/task-uinow exportsAnalyticsBoard(+
TaskActivityAnalyticsResponse,AnalyticsFilters, states) as pure-propsReact components, plus the Console
/tasks/analyticspage wired to the liveendpoint (verified by an e2e).
The one surface still missing is the MCP app, so an agent/human interacting
through an MCP host can pull up the same analytics without the Console.
Key constraint: MCP apps use tools, not REST
MCP apps never receive a bearer token or call REST directly — the iframe reads
data through the host bridge via
app.callServerTool({ name, arguments })against deterministic MCP server tools (see
apps/mcp-server/src/task-app.ts:"The iframe never receives a bearer token or talks to REST directly").
#1550 added only the REST endpoint — there is no analytics MCP tool yet. So
this issue has two cohesive parts (the app is inert without the tool → one PR).
Scope
1. MCP server tool
tasks_analytics_activityapps/mcp-serverwrapping@moltnet/task-analytics-service.getActivityAnalytics.completedAfter,completedBefore,tags,taskTypes,profileIds,diaryIds,claimedByAgentIds,groupBy(
none|day|tag|taskType|profile|diary|agent|providerModel).x-moltnet-team-idheader).TaskActivityAnalyticsResponse(same shape as the REST endpoint /the generated client /
@moltnet/task-ui's type).2. Analytics MCP app
libs/analytics-mcp-app(React)Mirrors
libs/entry-explore-mcp-app(the existing React MCP-app precedent —task-mcp-appis vanilla DOM and can't render the ReactAnalyticsBoard):metadata.ts—ANALYTICS_MCP_APP_NAME = 'moltnet_task_analytics',_TITLE,_RESOURCE_URI = 'ui://moltnet/tasks/analytics.html'.main.tsx—createRoot→<AnalyticsApp/>.AnalyticsApp.tsx—useAppfrom@modelcontextprotocol/ext-apps/react; seedfilters from the
ontoolinputopener payload; calltasks_analytics_activityvia a typed
callTool; map the tool JSON result →TaskActivityAnalyticsResponse;render
<AnalyticsBoard>(from@moltnet/task-ui) underMoltThemeProvider.Owns the explicit loading/error/empty/ready status mapping (same logic as the
Console
TaskAnalyticsPage).adapter/—tool-caller.ts+tool-calls.ts(typedcallToolfortasks_analytics_activity, snake_case args mirroring the server schema) +mcp-adapter.ts(camelCase filters → snake_case args; result JSON → responsetype). Unit tests mirroring
entry-explore-mcp-app/src/adapter/*.test.ts.theme-tokens.ts,styles.css,index.ts(re-exports metadata constants),singlefile
vite.config.ts, tsconfigs,package.json(react/react-dom +
@modelcontextprotocol/ext-apps+@moltnet/task-ui+@themoltnet/design-system).apps/mcp-server/src/analytics-app.ts(mirrortask-app.ts/entry-explore-app.ts) serving the built HTML resource, plusapps/mcp-server/__tests__/analytics-app.test.ts.Reuse / non-goals
@moltnet/task-uianalytics surface (AnalyticsBoard,types, states) is used as-is — no UI re-implementation. Filter shape + status
mapping are lifted from the Console page.
@moltnet/task-ui'sTaskActivityAnalyticsResponse; the MCP tool's TypeBox output maps to it 1:1(same mirror-and-assert discipline used in feat: agent work analytics — shared UI surface (#1373) #1551).
(that's Add task and team budget controls for token, turn, and estimated cost usage #1412); no vanilla-DOM re-implementation of the dashboard.
Acceptance criteria
tasks_analytics_activityMCP tool returns a validTaskActivityAnalyticsResponsefor the caller's team, honouring all filters +
groupBy.libs/analytics-mcp-apprenders<AnalyticsBoard>with real data pulledthrough the host bridge, across loading/error/empty/ready states.
mcp-server; opener tool seeds initial filters.lint,typecheck,test,buildgreen for the new lib + mcp-server.References
libs/entry-explore-mcp-app(React MCP app)@moltnet/task-analytics-service,libs/task-ui/src/analytics