Skip to content

feat: add bulk registration methods for tools, resources, and prompts #847

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 6 commits into
base: main
Choose a base branch
from

Conversation

cameroncooke
Copy link

Adds bulk registration methods (registerTools, registerResources, registerPrompts) to improve performance and
reduce notification spam when registering large numbers of MCP components in a single operation.

Motivation and Context

When MCP servers need to register many components (e.g., 80+ tools), the current API requires individual calls that
each trigger separate list_changed notifications. This creates performance issues and notification spam for
clients.

Problems solved:

  • Performance: Eliminates N notifications in favor of single batch notification
  • TypeScript compilation: Prevents TS2589 "Type instantiation is excessively deep" errors with complex schemas
  • Developer experience: Enables clean bulk registration patterns for large MCP servers

How Has This Been Tested?

  • Real application: Tested with XcodeBuildMCP server (83 tools with complex Zod schemas)
  • Scenarios tested:
    • Bulk registration of 100+ tools without TypeScript errors
    • Empty array handling
    • Error validation (duplicate names, invalid configs)
    • Single notification verification
    • Backward compatibility with existing individual registration methods
  • Test coverage: All existing SDK tests pass + new bulk registration tests added

Breaking Changes

None. This is a purely additive change. All existing tool(), resource(), and prompt() methods work
unchanged. The new bulk methods are optional enhancements.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Implementation notes:

  • Uses simplified ToolRegistration interface with unknown types to prevent TypeScript from attempting deep
    inference on complex schemas
  • Maintains full runtime type safety through existing Zod validation
  • Atomic operations: validates all components before registering any
  • Efficient notification strategy: single list_changed event after all registrations complete

Design decisions:

  • Chose unknown over any to maintain type safety while preventing compilation issues
  • Maintained consistent API patterns with existing individual registration methods
  • Added comprehensive error handling for edge cases (duplicates, validation failures)
  • Preserved all existing behavior for backward compatibility

Use cases:

  • Large development toolchain MCP servers
  • Dynamic tool loading scenarios
  • Performance-sensitive applications
  • Complex Zod schemas that cause TypeScript inference issues

@cameroncooke cameroncooke requested a review from a team as a code owner August 5, 2025 18:31
@cameroncooke cameroncooke requested a review from ihrpr August 5, 2025 18:31
@cameroncooke cameroncooke force-pushed the main branch 2 times, most recently from 24662c8 to eb95200 Compare August 6, 2025 19:29
…ublic methods

The _createRegisteredTool() method was calling setToolRequestHandlers() and
sendToolListChanged() internally, which caused issues when registering tools
after server connection due to capability registration restrictions.

This moves the notification responsibility to the public registerTool() and
tool() methods, making tool registration consistent and allowing registration
after connection when capabilities have already been established.

Fixes memory leak warnings caused by rapid tool registration after connection.
- Adds registerTools() method that accepts an array of tools
- Registers all tools and sends only one list_changed notification
- Prevents memory leak warnings when registering many tools
- Uses same pattern as individual registerTool() method
- Includes comprehensive test coverage

This solves the GitHub issue where registering 80+ tools caused EventEmitter
memory leak warnings due to multiple rapid notifications.
- Accepts array of resource configurations
- Registers all resources with single notification
- Supports both string URIs and ResourceTemplate objects
- Consistent with existing registration patterns
- Accepts array of prompt configurations
- Registers all prompts with single notification
- Follows existing registration patterns
- Comprehensive test coverage with notification validation
- Add early return for empty arrays to avoid unnecessary notifications
- Add comprehensive tests for empty array edge cases
- Addresses O3 feedback from code review
… registerTools

Simplifies the registerTools() method signature to prevent TypeScript from attempting complex tuple type inference when registering large numbers of tools with complex Zod schemas.

The simplified interface maintains full runtime safety through Zod validation while avoiding compile-time type complexity issues.
@domdomegg
Copy link
Member

domdomegg commented Aug 9, 2025

Would it be better to batch things with something a bit like the dataloader library, so that users don't have to worry about this and it just works if they batch register with the standard endpoints?

EDIT: this video has good context about the architecture of dataloader: https://youtu.be/ld2_AS4l19g?si=3fyLtc8xbhreDGZy&t=541

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.

Bulk tool registration causes EventEmitter memory leak warnings
2 participants