Dynamic Tool Groups for MCP Server
Enable dynamic tool groups on an MCP server using annotated Java interfaces to generate runtime tool specs and add or remove services seamlessly.
npx -y @ECF/MCPToolGroupsOverview
Dynamic Tool Groups for MCP Server lets you define tool groups and tool specifications in Java using small annotations, then exposes those definitions to a running MCP (Model Context Protocol) server at runtime. Instead of maintaining static JSON tool specs, you annotate interfaces and classes in your service module; the library scans those annotations, generates MCP-compatible tool descriptions on the fly, and registers them with the MCP server. This enables rapid iteration, simplified onboarding of new services, and clean separation between code and runtime tool registration.
The approach is particularly useful in microservice or plugin-driven architectures where services come and go, or when you want to keep tool descriptions close to the business logic. Because tool specs are generated at runtime from your Java types, adding or removing a service only requires deploying the service artifact — the MCP server sees the change and updates its tool registry automatically.
Source / code: https://github.com/ECF/MCPToolGroups
Features
- Annotated Java interfaces produce MCP tool specs at runtime
- Classpath scanning to discover tool groups and tool methods
- Dynamic registration and deregistration of tool groups without manual JSON editing
- Integration helpers for common build systems (Gradle / Maven) and runtime frameworks
- Lightweight API for programmatic control and introspection
- Runtime validation of tool signatures to produce safe MCP specs
Installation / Configuration
Add the library to your project. Replace the group/artifact/version with the release you use.
Maven:
com.ecf
mcp-toolgroups
1.0.0
Gradle (Groovy DSL):
implementation 'com.ecf:mcp-toolgroups:1.0.0'
Basic runtime configuration (example with a properties or YAML based MCP server):
application.yml
mcp:
toolgroups:
enabled: true
scan-packages:
- com.example.tools
poll-interval-seconds: 30 # optional periodic rescanning
Programmatic registration example (Java):
// create a registry, passing a reference to your MCP server API
DynamicToolGroupRegistry registry ;
// scan packages and register discovered tool-groups
registry.;
registry.;
// optionally stop and remove all tool-groups
registry.;
If your environment supports classpath scanning at startup, configure the scan package(s) so the runtime finds all annotated interfaces.
Available Tools / Resources
The library exposes a small set of annotations and helper classes to define and manage tools.
| Element | Purpose |
|---|---|
| @ToolGroup (annotation) | Applied to an interface or class to mark a logical group of tools (id, name, description). |
| @Tool (annotation) | Applied to methods to describe a single tool (id, description, input/output hints). |
| DynamicToolGroupRegistry | Core runtime service used to scan, generate, register, and unregister groups. |
| ToolSpecBuilder | Utility to convert annotated types into MCP tool spec JSON objects. |
| ClasspathScanner | Helper that finds annotated types in configured packages. |
Example annotated interface:
Use Cases
- Dynamic microservice onboarding: Deploy a new service that provides tools for a domain; the MCP server automatically publishes the new tool group without requiring manual JSON creation.
- Feature toggles and A/B: Register different tool implementations behind the same group id and flip between them by registering/unregistering implementations at runtime.
- Test and mock environments: Provide mock tool groups during integration testing that are scanned and published only in test profiles.
- Developer UX: Keep tool documentation and method signatures colocated with the implementation so generated tool specs are always current and type-safe.
Runtime Behavior and Best Practices
- The registry typically performs a classpath scan at startup and can optionally rescan periodically to discover newly deployed modules.
- Tool method signatures should use serializable request/response types (POJOs or schemas) that map cleanly to MCP models.
- Consider versioning tool-group ids and tool ids when making breaking changes.
- Use explicit ids in annotations to avoid relying on reflection names (ensures stable external contracts).
This dynamic approach reduces the maintenance burden of keeping separate tool spec files and makes MCP-driven integrations more resilient to frequent service changes.