Tool

Generate MCP tool specs from annotated Java interfaces

A Java/OSGi example showing annotation-driven MCP tool registration with hierarchical tool groups and sync/async tool methods.

Works with mcp

66
Spark score
out of 100
Updated 11 days ago
Version 1.0.0

Add to Favorites

Why it matters

Enable developers to dynamically create and manage MCP server tools by automatically generating tool specifications from annotated Java interfaces and classes at runtime, eliminating manual tool definition work.

Outcomes

What it gets done

01

Annotate Java interfaces and classes to define tool groups

02

Generate MCP tool specifications automatically from annotations

03

Add or remove tools dynamically from running MCP servers

04

Implement service APIs that map directly to MCP tool definitions

Install

Add it to your toolbox

Run in your project directory:

curl -fsSL https://spark.entire.vc/get/mcp-mcp-dynamic-tool-groups | bash

Overview

MCP Dynamic Tool Groups

MCP Dynamic Tool Groups is a Java/OSGi example project demonstrating annotation-based MCP tool declaration via the mcp_annotations_java library. It shows a hierarchical tool-group structure and both sync and async tool methods. Use it as a reference when building an MCP server on Java/OSGi and wanting annotation-driven tool metadata instead of manual registration; not a general-purpose MCP gateway or client.

What it does

MCP Dynamic Tool Groups is a Java/OSGi example project (part of ECF's MCPToolGroups) that shows how to expose a set of related methods as MCP tools using annotations rather than hand-written boilerplate. It demonstrates the McpToolGroup, McpTool, and McpToolParam annotations from the mcp_annotations_java project, applied to an ExampleToolGroup interface that declares four arithmetic operations: synchronous add and multiply, plus asynchronous asyncAdd and asyncMultiply, both returning a Reactor Mono<Double>. Each parameter and each method carries a description string, which is how the annotation layer supplies the metadata MCP tool-discovery calls need on top of the input/output plumbing.

When to use - and when NOT to

Use this project as a reference when building an MCP server on the Java/OSGi stack and wanting tool metadata declared once, in annotations on an interface, rather than duplicated across a hand-rolled registration call. It specifically demonstrates a hierarchical structure: the parent Java package is the top-level tool group, the ExampleToolGroup interface/class is a nested child group, and its two core methods are the leaf tools - useful when a project has many related tools that benefit from being organized rather than listed flat. It is not a general-purpose MCP client or gateway - it is a narrow example of the annotation and registration pattern, built around a toy arithmetic use case, and it assumes an existing OSGi component runtime.

Capabilities

  • McpToolGroup annotation to mark an interface (and its containing package) as a tool group, with a group-level description.
  • McpTool and McpToolParam annotations to describe individual methods and their parameters for MCP tool-discovery metadata.
  • Both synchronous (add, multiply) and asynchronous (asyncAdd, asyncMultiply, returning Mono<Double>) tool method support.
  • An OSGi Declarative Services component (ToolGroupComponent) that implements the annotated interface and registers itself with both a sync and an async tool-group server component via @Reference injection and an @Activate lifecycle method.
  • Static, hierarchical grouping of tools: parent package as top-level group, child interface/class as a nested group, methods as leaf tools.

How to install

syncServer.addToolGroups(this, ExampleToolGroup.class);

This is the registration call the example's @Activate method uses to hand its implemented tool-group interface off to the sync (and, in a parallel call, the async) tool-group server component at OSGi component activation time.

Who it's for

Java and OSGi developers building MCP-compliant servers who want an annotation-driven way to declare tool metadata and organize many tools into a group hierarchy, instead of registering each tool by hand. Most relevant to teams already using OSGi Declarative Services who are adding MCP tool support to an existing component-based Java application.

Source README

MCP Dynamic Tool Groups

The Model Context Protocol (MCP) includes support for tools, allowing AI models to a) Get metadata (descriptions) of tool input and output; b) Provide input, call/take action and c) get output via the use of one or more of the available tools.

In this example application the com.composent.ai.mcp.examples.toolgroup.api project declares a ExampleToolGroup interface class, with McpTool and McpToolGroup metadata:

@McpToolGroup(description="Arithmetic operations exposed as mcp tools")
public interface ExampleToolGroup {

	@McpTool(description = "computes the sum of the two double precision input arguments a and b")
	double add(@McpToolParam(description = "x is the first argument") double x,
			@McpToolParam(description = "y is the second argument") double y);

	@McpTool(description = "return the product of the two given double precision arguments named a and b")
	double multiply(@McpToolParam(description = "x is the first argument") double x,
			@McpToolParam(description = "y is the second argument") double y);

	@McpTool(description = "return asynchronously the sum of the two double precision input arguments a and b")
	Mono<Double> asyncAdd(@McpToolParam(description = "x is the first argument") double x,
			@McpToolParam(description = "y is the second argument") double y);

	@McpTool(description = "return asynchronously the product of the two given double precision arguments named a and b")
	Mono<Double> asyncMultiply(@McpToolParam(description = "x is the first argument") double x,
			@McpToolParam(description = "y is the second argument") double y);
}

Each method is annotated with the @McpTool and @McpToolParam annotations from the mcp_annotations_java project. There are both synchronous mcp server methods (add, multiply) and asynchronous mcp server methods (asyncAdd and asyncMultiply).

Notice also the use of @McpToolGroup annotation for the ExampleToolGroup class along with the parent package. This shows the static creation of a hierarchical relationship between the top-level toolgroup (package), and a child toolgroup (class) with two tools (add and multiply) as leaves of this simple toolgroup tree.

Here is an OSGi component implementing the ExampleToolGroup interface.

public class ToolGroupComponent implements ExampleToolGroup {

	private static Logger logger = LoggerFactory.getLogger(ToolGroupComponent.class);

	// This reference will wait for the SyncToolGroupServerComponent
	// to be activated
	@Reference
	private SyncToolGroupServerComponent syncServer;
	// This reference will wait for the AsyncToolGroupServerComponent
	// to be activated
	@Reference
	private AsyncToolgroupServerComponent asyncServer;

	@Activate
	void activate() {
		// Add to syncServer
		syncServer.addToolGroups(this, ExampleToolGroup.class);
		// Add to asyncServer
		asyncServer.addToolGroups(this, ExampleToolGroup.class);
	}

	@Override
	public double add(double x, double y) {
		logger.debug("Adding x={} y={}", x, y);
		return x + y;
	}

	@Override
	public double multiply(double x, double y) {
		logger.debug("Multiplying x={} y={}", x, y);
		return x * y;
	}

	@Override
	public Mono<Double> asyncAdd(double x, double y) {
		logger.debug("Async Adding x={} y={}", x, y);
		return Mono.just(add(x, y));
	}

	@Override
	public Mono<Double> asyncMultiply(double x, double y) {
		logger.debug("Async Multiplying x={} y={}", x, y);
		return Mono.just(multiply(x, y));
	}

}

The ExampleToolGroup tools are processed and added to the appropriate (sync or async) server at runtime with this line:

		syncServer.addToolGroups(this, ExampleToolGroup.class);

FAQ

Common questions

Discussion

Questions & comments ยท 0

Sign In Sign in to leave a comment.