-
Notifications
You must be signed in to change notification settings - Fork 7
Dynamic tool registration based on MCP client capabilities #61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
This commit introduces capability-aware tool registration that adapts to
client features, ensuring users only see tools that work with their client.
Key changes:
1. Tool Categorization (src/tools/toolRegistry.ts):
- Split tools into three categories by capability requirements:
* CORE_TOOLS (23 tools): Work in all MCP clients
* ELICITATION_TOOLS (2 tools): Require elicitation capability
- PreviewStyleTool
- StyleComparisonTool
* RESOURCE_FALLBACK_TOOLS (1 tool): Bridge for missing resource support
- GetReferenceTool
- Added new getter functions:
* getCoreTools()
* getElicitationTools()
* getResourceFallbackTools()
- Deprecated getAllTools() in favor of capability-aware functions
- Maintained ALL_TOOLS for backward compatibility and testing
2. Dynamic Registration (src/index.ts):
- Register CORE tools before connection (always available)
- After connection, check client capabilities via getClientCapabilities()
- Conditionally register ELICITATION_TOOLS if client supports elicitation
- Conditionally register RESOURCE_FALLBACK_TOOLS if client lacks resource support
- Send notifications/tools/list_changed notification after dynamic registration
- Added comprehensive logging for registration decisions
- Advertise listChanged: true capability to inform clients that tool list
can change dynamically
Benefits:
- Users only see tools that actually work with their client
- No confusing runtime capability errors
- Cleaner UX for capability-limited clients
- Backward compatible with existing tool configuration system
- Zero breaking changes (all tools still work, just registered conditionally)
All 520 tests pass.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add comprehensive unit tests to verify: - Tool categorization correctness - Getter functions return expected tools - No overlap between categories - Tool counts are correct 15 tests covering: - getCoreTools() - 4 tests - getElicitationTools() - 3 tests - getResourceFallbackTools() - 2 tests - getAllTools() - 3 tests - Tool categorization consistency - 3 tests All tests pass. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…ged yet) The elicitation support for preview_style_tool and style_comparison_tool exists only in the add-preview-token-elicitation branch, which hasn't been merged to main yet. Moving these tools to ELICITATION_TOOLS made them unavailable to all clients. Changes: - Move preview_style_tool back to CORE_TOOLS - Move style_comparison_tool back to CORE_TOOLS - Keep ELICITATION_TOOLS as empty array (ready for future use) - Update tests to reflect empty ELICITATION_TOOLS - Add comments explaining this is temporary until elicitation support merges When elicitation support is merged in the future, these tools can be moved to ELICITATION_TOOLS in a follow-up PR. All 535 tests pass. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The get_latest_mapbox_docs_tool duplicates functionality of the resource://mapbox-documentation resource. It should only be available to clients that don't properly support resources. Changes: - Move GetMapboxDocSourceTool from CORE_TOOLS to RESOURCE_FALLBACK_TOOLS - CORE_TOOLS now has 24 tools (down from 25) - RESOURCE_FALLBACK_TOOLS now has 2 tools (up from 1): * get_reference_tool (reference resources) * get_latest_mapbox_docs_tool (documentation resource) - Update tests to reflect new categorization - Add test for get_latest_mapbox_docs_tool in resource fallback tools Clients that properly support resources will no longer see this tool, reducing clutter in their tool list. All 536 tests pass. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
The previous logic incorrectly checked clientCapabilities.resources which doesn't exist (resources is a SERVER capability, not a CLIENT capability). Now correctly detects clients by name using getClientVersion() and only registers fallback tools for clients with known resource support issues (e.g., Claude Desktop). Result: MCP Inspector and other proper clients now see 23 tools instead of 26, with resource fallback tools only appearing for Claude clients. MCP Inspector Output After Fix: Tools (23): [ "bounding_box_tool", "check_color_contrast_tool", "compare_styles_tool", "coordinate_conversion_tool", "country_bounding_box_tool", "create_style_tool", "create_token_tool", "delete_style_tool", "geojson_preview_tool", "get_feedback_tool", "list_feedback_tool", "list_styles_tool", "list_tokens_tool", "optimize_style_tool", "preview_style_tool", "retrieve_style_tool", "style_builder_tool", "style_comparison_tool", "tilequery_tool", "update_style_tool", "validate_expression_tool", "validate_geojson_tool", "validate_style_tool" ] Resources (5): [ "resource://mapbox-documentation", "resource://mapbox-layer-type-mapping", "resource://mapbox-streets-v8-fields", "resource://mapbox-style-layers", "resource://mapbox-token-scopes" ] Fixes dynamic tool registration to work as intended.
cefb9e1 to
b29c23f
Compare
src/index.ts
Outdated
| const clientName = clientVersion?.name?.toLowerCase() || ''; | ||
|
|
||
| // Known clients with resource support issues | ||
| const needsResourceFallback = clientName.includes('claude'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doubt it's the only client that needs it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if client needs it and we don't know that - we don't provide fallback tools, this is risky. Should the logic be inverted - we provide fallback tools to all clients unless we know they do not need them?
| ); | ||
| }); | ||
|
|
||
| it('should have no duplicate tools', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup, good edge case 👍
…compatibility Per @Valiunia's review feedback, invert the resource fallback tool logic to use an allowlist approach instead of blocklist. This is safer for unknown clients. Changes: - OLD: Only provide fallback tools if client name includes 'claude' (blocklist) - NEW: Provide fallback tools to ALL clients UNLESS we know they support resources (allowlist) Known clients with proper resource support (skip fallback tools): - inspector - vscode Benefits: - Unknown/new clients get fallback tools by default (safer) - No risk of missing clients that need resource fallback - More defensive approach for ecosystem compatibility Related: PR #61 review comments All tests passing (536 tests).
|
✅ Addressed review feedback - inverted the resource fallback logic: Old approach (blocklist): Only provide fallback tools if client name includes 'claude'
New approach (allowlist): Provide fallback tools to ALL clients UNLESS we know they support resources
Known clients with proper resource support (skip fallback tools):
All other clients (including Claude Desktop, Claude Code, and any unknown clients) will receive resource fallback tools to ensure compatibility. Commit: 5e89269 |
… (like smolagents) Update comments and logic to reflect the real use case: resource fallback tools are for clients that don't support resources at all (like smolagents), not for buggy resource implementations. Changes: - Add 'claude' to allowlist (Claude Desktop now supports resources properly) - Update comments to clarify this is for clients without resource support - Change from "may not support properly" to "don't support resources" - Document smolagents as the primary use case Known clients WITH resource support (skip fallback tools): - inspector - vscode - claude (Claude Desktop/Code) Clients WITHOUT resource support (get fallback tools): - smolagents - unknown/new clients (safer default) All tests passing (536 tests).
|
📝 Further clarification - the real use case is smolagents: Claude Desktop now supports resources properly, so the resource fallback tools aren't for "buggy" implementations - they're for clients that don't support resources at all (like smolagents). Updated approach: Known clients WITH resource support (skip fallback tools):
Clients WITHOUT resource support (get fallback tools):
The resource fallback tools ( |
…(opt-in) Remove fragile name-based client detection and replace with explicit environment variable configuration. Use opt-in approach since most MCP clients support resources. Changes: - Remove client name checking logic entirely - Add CLIENT_NEEDS_RESOURCE_FALLBACK environment variable - Default (unset): Assume client supports resources, skip fallback tools - Set to "true": Client needs fallback tools (e.g., smolagents) Benefits: - No maintenance burden tracking client names/versions - Better default (most clients support resources) - Opt-in only for exceptions (smolagents, etc.) - Explicit configuration by users who know their client Configuration: ```bash # smolagents or clients without resource support export CLIENT_NEEDS_RESOURCE_FALLBACK=true # Claude Desktop, VS Code, Inspector, etc. (default) # Leave unset - assumes resource support ``` Documentation updated in README.md explaining when to set this variable. All tests passing (536 tests).
|
✅ Final solution: Explicit opt-in via environment variable Removed all client name detection logic and replaced with Why this approach?The problem with name-based detection:
The solution: ConfigurationDefault (unset): Skip resource fallback tools
Opt-in:
Benefits✅ No maintenance burden (no client tracking) DocumentationAdded new section in README explaining:
Commit: 638569d |
Summary
Implements capability-aware tool registration infrastructure that adapts to client features. Fixes incorrect resource capability detection that caused all clients to receive fallback tools.
Key Changes
1. Fixed Resource Capability Detection (
src/index.ts)Problem: Checked
clientCapabilities?.resourceswhich doesn't exist (resources is a SERVER capability, not CLIENT capability)Solution: Detect clients by name using
getClientVersion()- only register fallback tools for clients with 'claude' in their name2. Tool Categorization (
src/tools/toolRegistry.ts)Split tools into three capability-based categories:
get_reference_tool- Access to reference resourcesget_latest_mapbox_docs_tool- Access to Mapbox documentation resource3. Dynamic Registration Infrastructure
elicitation(none yet)notifications/tools/list_changedafter dynamic registrationtools: { listChanged: true }capability4. Tests (
test/tools/toolRegistry.test.ts)Added 16 comprehensive unit tests covering tool categorization, no overlap between categories, and proper counts.
MCP Inspector Output (After Fix)
Clients with proper resource support (Inspector, VS Code, etc.) now see:
Tools (23):
Resources (5):
Result: Inspector shows 23 tools (down from 26) - resource fallback tools only appear for Claude clients.
Benefits
✅ Correct behavior: Inspector and proper clients no longer see duplicate resource fallback tools
✅ Better UX: Resource fallback tools only for clients that need them (Claude Desktop)
✅ Infrastructure ready: Framework in place for capability-dependent tools
✅ Zero breaking changes: Claude Desktop still gets fallback tools
Testing
MCP Specification Compliance
Follows MCP 1.0 specification for dynamic tool registration:
notifications/tools/list_changednotificationlistChangedcapability