Skip to content

feat(mcp): selective tool registration via --tools / --exclude-tools#8

Merged
codemug merged 2 commits into
mainfrom
feat/mcp-tool-selection
May 24, 2026
Merged

feat(mcp): selective tool registration via --tools / --exclude-tools#8
codemug merged 2 commits into
mainfrom
feat/mcp-tool-selection

Conversation

@codemug

@codemug codemug commented May 24, 2026

Copy link
Copy Markdown
Owner

Summary

177 MCP tools across 22 categories is a lot of surface area for an AI agent to reason about. This PR adds a small spec grammar that lets users restrict which tools the MCP server exposes, with both category-level and per-tool granularity.

  • --tools / --exclude-tools CLI flags (env equivalents: AIOFMP_MCP_TOOLS / AIOFMP_MCP_EXCLUDE_TOOLS). When both are set, --tools defines the universe and --exclude-tools prunes from it.
  • --list-tools prints the inventory and exits — no FMP_API_KEY required.
  • Spec grammar mixes category and per-tool selection in one comma-separated list:
    • chart or chart(*) — whole category
    • chart(get_intraday_1hour) — single tool
    • chart(t1,t2),quote(*),search — mix freely
    • * — every tool (default)

Design

  • aiofmp/mcp_selection.py discovers the inventory by AST-scanning *_tools.py modules. No imports during validation, so --list-tools and CLI errors don't side-effect the global mcp instance.
  • register_tools() imports only the categories present in the effective selection, then calls mcp.remove_tool() for tools outside each category's allow-set.
  • CLI validates the spec via click.UsageError so bad inputs fail fast with the valid category/tool list.
  • Default behavior (no flags) is unchanged: all 177 tools register.

Files

  • aiofmp/mcp_selection.py (new) — inventory + spec parser + selection compute
  • aiofmp/mcp_server.pyregister_tools() refactor, env-var resolution
  • aiofmp/cli.py — new flags + --list-tools short-circuit
  • tests/test_mcp_selection.py (new) — 34 tests for inventory, parser, selection compute, formatter
  • tests/test_cli_mcp_server.py (new) — 6 tests for CLI surface + validation
  • tests/test_mcp_server.py — 6 new tests for env-var resolution + register_tools() mocking
  • README.md — new "Selective Tool Registration" section + flags in CLI Reference + env vars in the table
  • CHANGELOG.md — backfilled from history (1.0.0 → 1.1.0 → 1.2.0) + Unreleased entry

Test plan

  • pytest — 928 passed (40 new)
  • ruff check — clean
  • ruff format --check — clean
  • Manual smoke: aiofmp-mcp-server --list-tools prints inventory, --tools bogus exits non-zero with the valid category list

🤖 Generated with Claude Code

codemug and others added 2 commits May 24, 2026 16:13
semantic-release bumps pyproject.toml on tag but does not refresh
uv.lock; bring it back in sync so subsequent `uv` runs do not leave
a dirty working tree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
177 MCP tools across 22 categories is a lot of surface area for an AI
agent to reason about. Add a spec grammar that mixes category-level and
per-tool granularity so users can dial the surface down to what the
agent actually needs:

  chart                   -> all tools in chart
  chart(*)                -> all tools in chart (explicit)
  chart(get_intraday_1hour) -> just that tool
  chart(t1,t2),quote(*)   -> comma-separated mix
  *                       -> everything (default)

New surface:
- --tools / --exclude-tools CLI flags (env: AIOFMP_MCP_TOOLS /
  AIOFMP_MCP_EXCLUDE_TOOLS). When both set, the include set is the
  universe and exclude prunes from it.
- --list-tools prints the inventory and exits; no API key required.

Implementation: aiofmp/mcp_selection.py discovers the inventory by
AST-scanning the *_tools.py modules (no imports → no global mcp
side effects during validation). register_tools() now imports only
the categories present in the effective selection, then calls
mcp.remove_tool() for any tool outside that category's allow-set.
Validation fails fast on unknown category / tool / malformed spec.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@codemug codemug merged commit a728bb3 into main May 24, 2026
1 check passed
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.

1 participant