add-mcp-tool
GitHub指导在MCP服务器中新增工具,涵盖实现、路由注册、目录同步及状态变更处理。确保路由器与目录一致,遵循内部函数调用规范,并遵守竞技模式的信息限制。
Trigger Scenarios
Install
npx skills add openfootmanager/openfootmanager --skill add-mcp-tool -g -y
SKILL.md
Frontmatter
{
"name": "add-mcp-tool",
"description": "Add a tool to the MCP server that lets AI agents play OpenFoot Manager. Follows the six-step checklist in tools.rs — route registration, catalog entry, implementation in the right tools_impl module, game-state-changed emission, competition-mode gating, and the docs\/MCP_SERVER.md tables.",
"when_to_use": "Adding or changing an MCP tool, exposing an existing Tauri command to agents, or when a tool exists but help_find_tool cannot see it.",
"allowed-tools": "Read, Edit, Write, Grep, Glob, Bash(cargo build*), Bash(cargo test*), Bash(cargo clippy*)",
"argument-hint": "[tool name and what it does]"
}
Adding an MCP tool
The MCP server (src-tauri/src/mcp_server/, behind the mcp Cargo feature) lets AI agents play
the game over JSON-RPC. It is used for agent competitions — see docs/MCP_SERVER.md.
The authoritative checklist lives in the code, at tool_catalog() in
src-tauri/src/mcp_server/tools.rs. Read it; this skill expands on it.
The router and the catalog are two separate lists that must stay in sync. help_find_tool
searches only the catalog, so a tool registered in the router but missing from the catalog works
if an agent guesses its name and is otherwise invisible. The tools.rs tests
every_routed_tool_is_in_the_catalog, every_catalogued_tool_has_a_route, duplicate-name and
registration-parser checks enforce this when run with --lib --features mcp; they are not
executed by a default-feature test run.
1. Implement it in the right tools_impl/ module
src-tauri/src/mcp_server/tools_impl/ — info.rs, time.rs, squad.rs, training.rs,
transfers.rs, contracts.rs, inbox.rs, club.rs, scouting.rs, season.rs, game.rs,
live_match.rs, help.rs. Shared helpers (require_game, user_team, …) are in helpers.rs.
Call the same _internal function the Tauri command calls. Never reimplement game logic here.
If the behaviour has no _internal split yet, do that first — see /add-tauri-command. Check
that the shared function is reachable in default and mcp builds; application code never imports
MCP or commands. Apply the root Code quality limits and use /write-tests first.
Return text an agent can actually use. Tools return prose or JSON, not opaque ids: an agent
reading info_standings should be able to act on it without a second call. Follow the formatting
of the neighbouring tools in the module, and translate error keys through formatting.rs.
Respect competition-mode information limits. Full detail for the agent's own team; OVR,
position, age, and condition only for other teams unless the player has been scouted. A new
info_* tool that leaks opponent attributes silently breaks competition fairness.
2. Register the route
In build_tool_router() in tools.rs. Three macros cover most cases:
real_tool!— no parametersid_tool!— one required string parameter (the schema key and the impl function's second parameter name must match)custom_tool!— custom JSON schema plus custom extraction
Every registration is wrapped in a disabled.contains(…) check, which is how mode restrictions
and --mcp-disable-tools work.
3. Add the catalog entry
tool_catalog() in the same file: (name, description, category). Use an existing category
string exactly — a typo creates a phantom category in help_list_categories.
The description is what an agent reads when deciding whether to call the tool. Say what it does and when to use it.
4. Emit game-state-changed if it mutates
Any state-mutating tool must emit app.emit("game-state-changed", ()) via ctx.app_handle, so a
GUI watching the agent play refreshes. Read-only tools must not.
5. Decide competition-mode visibility
If agents must not have this tool in a competition, add its name to the Competition arm of
disabled_tools() in src-tauri/src/mcp_server/config.rs. Currently disabled there: game_new,
game_select_team, game_export_world, game_exit, game_load_save — anything that would let
an agent change its own starting conditions.
6. Update docs/MCP_SERVER.md
Add the row to the right category table and update the two counts in the header line ("N tools are available across M categories") and the per-category heading ("### Squad (7 tools)"). Stale counts are how this document rots.
Verify
Finish with /preflight for the full default and MCP gate set. These scoped commands use the
same lockfile and warning policy; they do not replace the full preflight.
cargo build --locked --manifest-path src-tauri/Cargo.toml --features mcp
cargo clippy --locked --manifest-path src-tauri/Cargo.toml --workspace --all-targets --features mcp -- -D warnings
cargo test --locked --manifest-path src-tauri/Cargo.toml --workspace
cargo test --locked --manifest-path src-tauri/Cargo.toml --lib --features mcp
The mcp feature is not compiled by default, so a normal cargo check will not catch a
mistake in this code. Build and test with --features mcp. Add one test per GWT scenario
through the shared seam and adapter: wrapper equivalence, errors, competition gating and event
emission. For persistence claims, read the saved database through a fresh reader; a returned
clone does not prove a write. Use ofm-test-reviewer for regression effectiveness evidence.
End-to-end, against a running instance:
# tools/list — confirm the tool appears (and does NOT in competition mode if gated)
curl -X POST http://localhost:3001/mcp -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
# call it
curl -X POST http://localhost:3001/mcp -H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"your_tool","arguments":{}}}'
docs/MCP_SERVER.md §"Quick Start" has the full launch command.
Checklist
- Implementation in the right
tools_impl/module, calling the shared_internalfunction - Route registered in
build_tool_router() - Entry added to
tool_catalog()with an existing category string -
game-state-changedemitted if and only if the tool mutates state - Competition-mode gating decided;
config.rsdisabled_tools()updated if needed - Information-visibility limits respected for other teams' players
-
docs/MCP_SERVER.mdtable row added and both tool counts updated - Builds and lints clean with
--features mcp - Verified via
tools/listandtools/callagainst a running instance
Version History
-
c3d8002
Current 2026-10-18 19:49
更新测试说明:指出缺少自动检查机制的已修正(现通过代码测试强制执行);增加关于使用/write-tests和代码质量限制的指引。
- 9d401d6 2026-07-30 22:45


