Install
$ agentstack add mcp-thought2code-mcp-annotated-java-sdk ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
English · [简体中文](README.zh-CN.md)
MCP Annotated Java SDK
Annotation-driven MCP servers for lightweight Java applications.
A small, Spring-free annotation layer on top of the official MCP Java SDK.
[Quick Start](#-quick-start) · [Why This SDK](#-why-this-sdk) · [Documentation](#-documentation) · [License](#-license)
[](https://central.sonatype.com/artifact/io.github.thought2code/mcp-annotated-java-sdk) [](https://app.codecov.io/github/thought2code/mcp-annotated-java-sdk) [](https://github.com/thought2code/mcp-annotated-java-sdk/actions/workflows/maven-build.yml)
Overview
This SDK is a lightweight, annotation-based framework for building MCP servers in plain Java. Define MCP Resources / Prompts / Tools / Completions with ordinary Java methods, let the SDK generate the low-level MCP bindings, and run the server without bringing in Spring.
It is intentionally not a Spring AI replacement. Spring AI is the standard MCP entry point for Spring applications. This project focuses on the rest of the Java server space: CLI tools, embedded servers, local automation, small service processes, and teams that want annotation-driven MCP development without a Spring runtime.
> Workflow: Add dependency → Configure mcp-server.yml → Annotate Resources / Tools / Prompts / Completions → Run with McpApplication
✨ Why This SDK?
Positioning
| Project | Best fit | Role | |---------------------------------------------------------------------------------------|--------------------------------------------------------|------------------------------| | Official MCP Java SDK | Library authors and low-level protocol integration | Foundation | | Spring AI MCP | Spring Boot / Spring Framework applications | Spring ecosystem standard | | MCP Annotated Java SDK | Plain Java, CLI, embedded, and lightweight MCP servers | Spring-free annotation layer |
Rule of thumb: Spring AI for Spring apps; MCP Annotated Java SDK for lightweight Java MCP servers without Spring.
Key Advantages
- 🚫 No Spring Framework Required - Pure Java, lightweight and fast
- ⚡ Instant MCP Server - Get your server running with just 1 line of code
- 🎉 Low Boilerplate - No need to write repetitive low-level MCP SDK registration code
- 👏 Generated JSON Schema - Derive tool schemas from annotated Java signatures and metadata
- 🎯 Focus on Logic - Concentrate on your core business logic
- 🧩 Compile-Time Binding Generation - Annotation processing creates deterministic MCP component providers
- 🔌 Spring AI-Friendly Configuration - Familiar configuration shape for teams that may also use Spring AI
- 📦 Type-Aware - Leverage Java signatures and compile-time checks for safer MCP components
Comparison
| Feature | Official MCP Java SDK | Spring AI MCP | This SDK | |------------------|-----------------------------|--------------------------------|--------------------------------------------| | Primary audience | Low-level Java integrations | Spring applications | Plain Java MCP servers | | Spring required | No | Yes, for Spring integration | No | | Component model | Programmatic registration | Spring beans and annotations | Plain classes and annotations | | JSON Schema | Manual or app-provided | Generated by Spring AI | Generated by annotation processor | | Startup model | You assemble the server | Spring Boot auto-configuration | McpApplication.run(...) | | Best use case | Maximum control | Enterprise Spring apps | CLI, embedded, local tools, small services |
Roadmap Focus
This project deliberately stays focused:
- Keep close compatibility with the official MCP Java SDK.
- Make plain Java MCP servers faster to write, test, and ship.
- Improve compile-time validation, generated bindings, schema support, and examples.
- Avoid competing with Spring AI on Boot auto-configuration, WebMVC/WebFlux integration, enterprise security, or observability.
🎯 Quick Start
Prerequisites
- Java 17 or later (required by official MCP Java SDK)
5-Minutes Tutorial
Step 1: Add Dependency
Maven:
io.github.thought2code
mcp-annotated-java-sdk
0.20.0
Gradle:
implementation 'io.github.thought2code:mcp-annotated-java-sdk:0.20.0'
Step 2: Create Configuration File
Create mcp-server.yml in your src/main/resources:
enabled: true
mode: STDIO
name: my-first-mcp-server
version: 1.0.0
type: SYNC
instructions: You are a helpful AI assistant
request-timeout: 20000
capabilities:
resource: true
subscribe-resource: true
prompt: true
tool: true
completion: true
change-notification:
resource: true
prompt: true
tool: true
Step 3: Create Your MCP Server
@McpServerApplication
public class MyFirstMcpServer {
public static void main(String[] args) {
McpApplication.run(MyFirstMcpServer.class, args);
}
}
Step 4: Define MCP Resources (if needed)
public class MyResources {
@McpResource(uri = "system://info", description = "System information")
public Map getSystemInfo() {
Map info = new HashMap<>();
info.put("os", System.getProperty("os.name"));
info.put("java", System.getProperty("java.version"));
info.put("cores", String.valueOf(Runtime.getRuntime().availableProcessors()));
return info;
}
}
Step 5: Define MCP Tools
public class MyTools {
@McpTool(description = "Calculate the sum of two numbers")
public int add(
@McpToolParam(name = "a", description = "First number") int a,
@McpToolParam(name = "b", description = "Second number") int b
) {
return a + b;
}
}
Step 6: Define MCP Prompts (if needed)
public class MyPrompts {
@McpPrompt(description = "Generate code for a given task")
public String generateCode(
@McpPromptParam(name = "language", description = "Programming language") String language,
@McpPromptParam(name = "task", description = "Task description") String task
) {
return String.format("Write %s code to: %s", language, task);
}
}
Step 7: Run Your Server
# Compile your project
./mvnw clean package
Run MyFirstMcpServer from your IDE, or use java -cp ... with your compiled classes and dependencies on the classpath. Your own project needs an executable JAR setup (for example Spring Boot or the Maven Shade plugin) if you want java -jar with a single file.
For deployment, build an executable fat JAR so runtime dependencies are included. If you use Maven Shade, configure the JAR manifest main class:
org.apache.maven.plugins
maven-shade-plugin
3.6.2
package
shade
false
com.example.MyFirstMcpServer
Keep mcp-server.yml in src/main/resources so it is packaged on the classpath.
That's it! Your MCP server is now ready to serve resources, tools, and prompts!
📚 Core Concepts
What is MCP?
The Model Context Protocol (MCP) is a standardized protocol for building servers that expose data and functionality to LLM applications. Think of it like a web API, but specifically designed for LLM interactions.
MCP Components
| Component | Purpose | Analogy | |---------------|--------------------|----------------| | Resources | Expose data to LLM | GET endpoints | | Tools | Execute actions | POST endpoints | | Prompts | Reusable templates | Form templates |
Supported Server Modes
This SDK supports two MCP server modes:
| Mode | Description | Use Case | |----------------|-------------------------------------|--------------------------------------------------------| | STDIO | Standard input/output communication | CLI tools, local development | | STREAMABLE | HTTP streaming | Web applications, recommended for production |
🔧 Advanced Usage
Configuration File
Create mcp-server.yml in your classpath:
enabled: true
mode: STREAMABLE
name: my-mcp-server
version: 1.0.0
type: SYNC
instructions: You are a helpful AI assistant
request-timeout: 20000
capabilities:
resource: true
subscribe-resource: true
prompt: true
tool: true
completion: true
change-notification:
resource: true
prompt: true
tool: true
streamable:
mcp-endpoint: /mcp/message
disallow-delete: false
keep-alive-interval: 20000
port: 8080
Configuration Properties
| Property | Description | Default | |-----------------------------------|-----------------------------------------------------------------|------------------------------| | enabled | Enable/disable MCP server | true | | mode | Server mode: STDIO, STREAMABLE | STREAMABLE | | name | Server name | mcp-server | | version | Server version | 1.0.0 | | type | Server type: SYNC, ASYNC | SYNC | | instructions | Instructions for the LLM client | Required (non-blank in YAML) | | request-timeout | Request timeout in milliseconds | 20000 | | capabilities.resource | Enable resource support | true | | capabilities.subscribe-resource | Enable resource subscription | true | | capabilities.prompt | Enable prompt support | true | | capabilities.tool | Enable tool support | true | | capabilities.completion | Enable completion support | true | | change-notification.resource | Notify clients on resource change | true | | change-notification.prompt | Notify clients on prompt change | true | | change-notification.tool | Notify clients on tool change | true | | streamable.mcp-endpoint | Streamable HTTP MCP path | /mcp/message | | streamable.disallow-delete | Reject HTTP DELETE on session | false | | streamable.keep-alive-interval | Keep-alive interval (ms) | 20000 | | streamable.port | HTTP port for STREAMABLE mode | 8080 |
Profile-based Configuration
Set profile in the base file to load mcp-server-{profile}.yml from the classpath. Profile values are merged into the base configuration with Jackson deep merge; nested objects such as capabilities and streamable are merged field-by-field. The profile name always comes from the base file. After merge, transport settings that do not match the resolved mode are cleared (for example, streamable is removed when mode is STDIO).
You can use profiles for different environments:
# mcp-server.yml (base configuration)
enabled: true
mode: STREAMABLE
name: my-mcp-server
version: 1.0.0
profile: dev
# mcp-server-dev.yml (profile-specific configuration)
streamable:
port: 8080
Runtime model and stability
SYNC vs ASYNC (type)
The type setting selects which MCP Java SDK server API the framework uses. It does not turn your component methods into reactive code.
| type | What happens | |---------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | SYNC | Handlers invoke your @McpTool / @McpPrompt / @McpResource methods on the request thread. | | ASYNC | Handlers return Reactor Mono values for MCP SDK compatibility. The SDK wraps each call in Mono.fromCallable(...) — your method body is still a normal blocking Java invocation. |
ASYNC is not a non-blocking or Project Reactor programming model. You do not implement Mono/Flux in annotated methods. Long-running or CPU-heavy work still occupies a Reactor worker thread. Use SYNC unless your deployment specifically requires the async MCP server API. For high concurrency, keep handlers short and tune request-timeout.
Component instances and concurrency
The SDK creates one instance per component class (no-arg constructor) and reuses it for every MCP request to methods on that class. Concurrent calls share the same object.
- Prefer stateless component classes, or thread-safe mutable state only.
- Do not store per-request data in instance fields without proper synchronization.
- Delegate shared mutable state to thread-safe services when needed.
McpApplicationContext.from(...) currently uses this default singleton-per-class factory. Component classes must provide a public no-arg constructor. There is no built-in Spring/CDI wiring in the public API today.
McpApplication.run(mainClass, args) loads mcp-server.yml by default; pass a third argument to use another classpath config file name.
- STREAMABLE is the supported HTTP transport.
🏗️ Project Structure
A typical project structure:
your-mcp-project/
├── pom.xml
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── example/
│ │ │ ├── MyMcpServer.java # Main entry point
│ │ │ ├── components/
│ │ │ │ ├── MyResources.java # MCP Resources
│ │ │ │ ├── MyTools.java # MCP Tools
│ │ │ │ └── MyPrompts.java # MCP Prompts
│ │ │ └── ser
…
## Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [thought2code](https://github.com/thought2code)
- **Source:** [thought2code/mcp-annotated-java-sdk](https://github.com/thought2code/mcp-annotated-java-sdk)
- **License:** MIT
- **Homepage:** https://thought2code.github.io/mcp-annotated-java-sdk
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.