Repository navigation
Add MCP diagnostic tools for Flipper server status and control #26
Description
Summary
@player-devtools/mcp connects to Player through a shared flipper-server
daemon (FlipperServerTransport in devtools/client/flipper/src/transport.ts),
but none of that connection's state is exposed to the agent as a tool today.
All existing tools (list_players, get_player_status, etc.) operate one
level up, on Player instances that are already reachable through a working
transport.
When the daemon isn't running, isn't owned by this process, or a required
Flipper plugin isn't installed, an agent currently just sees every
player-scoped tool call fail generically — it has no way to distinguish "no
Player instance is connected" from "the Flipper transport itself is down" or
self-diagnose/self-heal.
Proposal
Add a new devtools/mcp/src/tools/flipper.ts with a small set of
daemon-scoped diagnostic tools, following the existing ToolDef pattern
(devtools/mcp/src/tools/index.ts). Tool names stay flat and un-prefixed,
consistent with existing naming (list_players, get_player_status) — they
register into the same TOOL_DEFS list as the core Player tools. To keep
them visually distinct from the core Player tools (the actual value the MCP
server provides) without touching the wire protocol, the README documents
them under a separate "Diagnostics" table beneath the existing "Player"
tools table, rather than under one combined list.
get_flipper_status— is the transport currently connected to a
flipper-serverdaemon; if so, host/port, and whether this MCP process
started (owns) the daemon vs. attached to one another process started
(surfacing the existing refcount/ownership state).get_flipper_consumers— when this process owns the daemon, how many
clients/consumers are currently attached (e.g. current refcount, and/or the
connected device/app client IDs already tracked internally).restart_flipper_server— restart the daemon, scoped to the existing
refcount/ownership model:- If the calling process owns the daemon (per
FlipperRefcount), it may
restart it directly — tear down and respawn the child process, since it's
already responsible for that daemon's lifecycle. - If the calling process does not own the daemon (it only attached to
one another process started), the tool returns a soft error explaining
that only the owning process can restart it, rather than silently killing
a daemon other consumers depend on. This mirrors the existing
acquire/release discipline inFlipperRefcount— no new coordination
primitive is needed, just surfacing the ownership check that already
exists before performing a destructive action.
- If the calling process owns the daemon (per
get_flipper_plugin_install_status— report whether the
player-ui-devtoolsFlipper plugin specifically is installed/enabled on the
daemon. (Plugin installation itself is already handled elsewhere — this is
status-only, not a general-purpose plugin manager.)
Tool annotations
ToolDef (devtools/mcp/src/tools/index.ts) doesn't carry MCP's
annotations field today, and registerTools() in server.ts only passes
description/inputSchema to registerTool() — annotations is silently
dropped even though the SDK supports it. This issue proposes:
- Adding an optional
annotationsfield toToolDef, forwarded through in
registerTools(). - Setting it on the new tools:
{ readOnlyHint: true, destructiveHint: false }
on the threeget_*tools, and{ readOnlyHint: false, destructiveHint: true }
onrestart_flipper_server.
Per the MCP spec, annotations are hints the client may use, and clients
"MUST consider tool annotations untrusted unless they come from trusted
servers" — they're not guaranteed to reach the calling model, and aren't a
substitute for the ownership check above, which remains the actual safety
mechanism preventing a non-owning process from tearing down a daemon other
consumers depend on. Adding annotations here is about standards-compliant
correctness and giving well-behaved MCP clients an honest signal, not a claim
that it alone makes restart "safe."
Retrofitting annotations onto existing tools (e.g. invoke_action) is a
reasonable follow-up but out of scope for this issue.
Motivation
Better observability and self-service recovery for agents driving Player
devtools over MCP — surfacing existing internal state
(FlipperRefcount, activeClientIds, waitForPort) that the transport
already tracks, rather than requiring a human to intervene when the shared
daemon needs attention.
Activity
[-]Add MCP tools for Flipper server status and control[/-][+]Add MCP diagnostic tools for Flipper server status and control[/+]sugarmanz commentedon Sep 25, 2026
Closed with #29