Skip to content

feat: dynamic tool discovery #198

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

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

rlcurrall
Copy link

Implement Dynamic Toolset Discovery

Overview

This PR implements dynamic toolset discovery in the MCP server, allowing for more efficient tool management and better scalability. Instead of loading all tools at startup, the server now exposes a core set of tools plus special "meta-tools" that enable the client to discover and enable additional toolsets as needed.

Feature Details

The implementation adds three key tools:

  • list_available_toolsets: Lists all available groups of tools and their current status
  • get_toolset_tools: Shows the specific tools available within a given toolset
  • enable_toolset: Activates a specific toolset, making its tools available for use

Implementation

The feature is implemented in a new dynamic module with the following structure:

  • types.ts: Type definitions for toolsets and API responses
  • schemas.ts: Zod schemas for request validation
  • tool-definitions.ts: Definitions for the dynamic discovery tools
  • index.ts: Core implementation of toolset management and request handlers
  • index.spec.unit.ts: Comprehensive unit tests for the feature

Key aspects of the implementation:

// Toolset management
export const toolsets = new Map<
  string,
  { description: string; tools: ToolDefinition[]; enabled: boolean }
>();

// Dynamic toolset initialization
export function initializeToolsets(allTools: { [key: string]: ToolDefinition[] }) {
  toolsets.clear();
  // Initialize toolsets with disabled state by default
  Object.entries(allTools).forEach(([name, tools]) => {
    if (name !== 'dynamic') {
      toolsets.set(name, {
        description: `${name} related tools`,
        tools,
        enabled: false,
      });
    }
  });
  // Dynamic toolset is always enabled
  toolsets.set('dynamic', {
    description: 'Tools for discovering and enabling other tools',
    tools: dynamicTools,
    enabled: true,
  });
}

Benefits

  • Improved Performance: Initial server response is smaller and more manageable
  • Better Resource Usage: Tools are only loaded when needed
  • Enhanced Flexibility: LLM can request specific capabilities as needed
  • Cleaner Architecture: Tools are organized into logical groupings
  • Type Safety: Full TypeScript type safety throughout the implementation

Testing

The implementation includes comprehensive unit tests that verify all aspects of the dynamic toolset feature:

Core Functionality Tests

  • Toolset Initialization: Verifies correct initial state of toolsets (enabled/disabled status)
  • Dynamic Request Detection: Ensures proper identification of dynamic tool requests
  • Toolset Management: Tests the enabling/disabling of toolsets

Tool-Specific Tests

  • list_available_toolsets: Validates correct listing of all toolsets with their status
  • get_toolset_tools: Confirms accurate retrieval of tools within specific toolsets
  • enable_toolset: Tests successful toolset activation and proper handling of already-enabled toolsets

Error Handling Tests

  • Validates proper error responses for invalid toolset requests
  • Tests error handling for unknown dynamic tools
  • Ensures appropriate handling of duplicate enable requests

All tests are colocated with the implementation code for better maintainability and are run as part of the unit test suite.

Example Usage

  1. Client requests available tools (tools/list)
  2. Server responds with core tools + dynamic discovery tools
  3. Client discovers additional toolsets via list_available_toolsets
  4. Client inspects specific toolset via get_toolset_tools
  5. Client enables desired toolset via enable_toolset
  6. Newly enabled tools become available in subsequent tools/list calls

@rlcurrall rlcurrall changed the title Feat/dynamic tool discovery feat: dynamic tool discovery May 1, 2025
@Tiberriver256
Copy link
Owner

This looks awesome 😎

Haven't tested it out yet locally but a few requests:

  • Would love to see some E2E tests on this functionality
  • I think, at least for now, this behavior should be opt-in somehow with an environment variable. If the environment variable isn't set, the three tools don't get added and all tool sets get added.

@Squixx
Copy link

Squixx commented May 2, 2025

I'd also love this to be opt-in, as the toolset limitiation is not something that is an issue on all platforms. (e.g. copilot in vscode just handles 101 tools and has its own mechanism for enabling / disabling). And all mcp users develop quite rapidly, so this might be less (or more) of an issue in a couple of days / weeks / months

Unless this would lead to weid maintenance issues of course.

looks awesome though, what is your experience with how agents recognise the need to enable tools?

@rlcurrall
Copy link
Author

Should be able to revisit this in the next few days to address the suggestions.

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.

3 participants