fastMCP4J
Fast lightweight Java MCP server framework - Build Model Context Protocol servers with minimal boilerplate and full TypeScript SDK compatibility
FastMCP4J
Java library for building MCP servers — annotation-driven, minimal dependencies
AI Agents → Share this skill with Claude for code generation
Lightweight. 12 dependencies. No containers.
Just annotate and run. See below →
Note: Beta release (v0.3.1-beta) — Multi-class modules, bash tools, telemetry. API stable.
Quick Start (2 minutes)
Add dependency
Maven:
<dependency>
<groupId>io.github.terseprompts.fastmcp</groupId>
<artifactId>fastmcp-java</artifactId>
<version>0.3.1-beta</version>
</dependency>
Gradle:
dependencies {
implementation 'io.github.terseprompts.fastmcp:fastmcp-java:0.3.1-beta'
}
Create your server
@McpServer(name = "Assistant", version = "1.0")
public class MyAssistant {
@McpTool(description = "Summarize text")
public String summarize(@McpParam(description = "Text") String text) {
return "Summary: " + text.substring(0, Math.min(100, text.length()));
}
public static void main(String[] args) {
FastMCP.server(MyAssistant.class)
.stdio() // or .sse() or .streamable()
.run();
}
}
Run it
mvn exec:java -Dexec.mainClass="com.example.MyAssistant"
That's it. Your MCP server is running.
Working example: EchoServer.java
Who This Is For
| You want to... | FastMCP4J |
|---|---|
| Expose Java tools to AI agents | ✅ Perfect fit |
| Build MCP servers quickly | ✅ Annotation-driven, minimal code |
| Add MCP to existing Spring app | ✅ Drop-in, no framework lock-in |
| Lightweight MCP-only solution | ✅ 12 dependencies, not 50+ |
| Fast startup & low memory | ✅ <500ms cold start, ~64MB |
How to Use
Make a tool
@McpTool(description = "Add two numbers")
public int add(int a, int b) {
return a + b;
}
Make it async
@McpTool(description = "Process data")
@McpAsync // ← just add this
public Mono<String> process(@McpContext Context ctx, String input) {
return Mono.fromCallable(() -> {
ctx.reportProgress(50, "Processing...");
return slowOperation(input);
});
}
Add memory
@McpServer(name = "MyServer", version = "1.0")
@McpMemory // ← just add this
public class MyServer {
// AI now remembers things across sessions
}
Add all built-in tools
@McpServer(name = "MyServer", version = "1.0")
@McpMemory // AI remembers
@McpTodo // AI manages tasks
@McpPlanner // AI breaks tasks into steps
@McpFileRead // AI reads your files
@McpFileWrite // AI writes files
public class MyServer {
// All tools enabled, zero implementation needed
}
Organize tools across multiple classes
@McpServer(
name = "MyServer",
version = "1.0",
modules = {StringTools.class, MathTools.class} // Explicit modules
)
public class MyServer {
// Tools from StringTools and MathTools are included
}
Or use package scanning for auto-discovery:
@McpServer(
name = "MyServer",
version = "1.0",
scanBasePackage = "com.example.tools" // Auto-discover all tools
)
public class MyServer {
// All @McpTool classes in the package are included
}
Add bash/shell execution
@McpServer(name = "MyServer", version = "1.0")
@McpBash(timeout = 30) // Shell command execution with security guardrails
public class MyServer {
// Provides 'execute_command' tool with OS-aware shell selection
}
Add telemetry
@McpServer(name = "MyServer", version = "1.0")
@McpTelemetry(enabled = true, exportConsole = true) // Metrics & tracing
public class MyServer {
// Automatic tool invocation tracking with console export
}
Choose transport
FastMCP.server(MyServer.class)
.stdio() // For CLI tools, local agents
.sse() // For web clients, long-lived connections
.streamable() // For bidirectional streaming (recommended)
.run();
Configure port, timeout, capabilities
FastMCP.server(MyServer.class)
.port(3000) // HTTP port
.requestTimeout(Duration.ofMinutes(5)) // Request timeout
.keepAliveSeconds(30) // Keep-alive interval
.capabilities(c -> c
.tools(true)
.resources(true, true)
.prompts(true))
.run();
Icons
Add visual polish to your server, tools, resources, and prompts.
@McpServer(
name = "my-server",
icons = {
"data:image/svg+xml;base64,...:image/svg+xml:64x64:light",
"data:image/svg+xml;base64,...:image/svg+xml:64x64:dark"
}
)
@McpTool(
description = "My tool",
icons = {"https://example.com/icon.png"}
)
public class MyServer { }
Resources & Prompts
@McpResource(uri = "config://settings")
public String getSettings() {
return "{\"theme\": \"dark\"}";
}
@McpPrompt(name = "code-review")
public String codeReviewPrompt(@McpParam(description = "Code to review") String code) {
return "Review this code:\n" + code;
}
Built-in Tools
Add ONE annotation, get complete functionality.
| Annotation | Tools You Get |
|---|---|
@McpMemory | list, read, create, replace, insert, delete, rename |
@McpTodo | add, list, updateStatus, updateTask, delete, clearCompleted |
@McpPlanner | createPlan, listPlans, getPlan, addTask, addSubtask |
@McpFileRead | readLines, readFile, grep, getStats |
@McpFileWrite | writeFile, appendFile, writeLines, deleteFile, createDirectory |
Annotations Reference
| Annotation | Target | Purpose |
|---|---|---|
@McpServer | TYPE | Define your MCP server |
@McpTool | METHOD | Expose as callable tool |
@McpResource | METHOD | Expose as resource |
@McpPrompt | METHOD | Expose as prompt template |
@McpParam | PARAMETER | Add description, examples, constraints, defaults |
@McpAsync | METHOD | Make tool async (return Mono<?>) |
@McpContext | PARAMETER | Inject request context |
@McpPreHook | METHOD | Run before tool call (params: toolName, order) |
@McpPostHook | METHOD | Run after tool call (params: toolName, order) |
@McpBash | TYPE | Enable bash/shell command execution tool |
@McpTelemetry | TYPE | Enable metrics and tracing (params: enabled, exportConsole, exportOtlp, sampleRate) |
@McpMemory | TYPE | Enable memory tools |
@McpTodo | TYPE | Enable todo/task management tools |
@McpPlanner | TYPE | Enable planning tools |
@McpFileRead | TYPE | Enable file reading tools |
@McpFileWrite | TYPE | Enable file writing tools |
@McpParam advanced options:
@McpTool(description = "Create task")
public String createTask(
@McpParam(
description = "Task name",
examples = {"backup", "sync"},
constraints = "Cannot be empty",
defaultValue = "default",
required = false
) String taskName
) { return "Created: " + taskName; }
Hooks — Run Code Before/After Tools
Two hook types supported:
@McpPreHook — Runs before tool is called. Receives Map<String, Object> arguments.
@McpPostHook — Runs after tool completes. Receives Map<String, Object> arguments, Object result.
Use for logging, validation, authentication, audit trails, metrics.
@McpServer(name = "MyServer", version = "1.0")
public class MyServer {
@McpTool(description = "Calculate")
public int calculate(int x, int y) {
return x + y;
}
// Run before ALL tools (*)
@McpPreHook(toolName = "*", order = 1)
void authenticate(Map<String, Object> args) {
String token = (String) args.get("token");
if (!isValid(token)) throw new SecurityException("Unauthorized");
}
// Run after specific tool only
@McpPostHook(toolName = "calculate", order = 1)
void logResult(Map<String, Object> args, Object result) {
System.out.println("Result: " + result);
}
public static void main(String[] args) {
FastMCP.server(MyServer.class).stdio().run();
}
}
Hook options:
toolName— Target specific tool name, or"*"for all tools. Empty = inferred from method nameorder— Execution priority (lower = first). Default:0
Hook parameters:
- Pre-hook:
Map<String, Object> arguments— Tool input arguments - Post-hook:
Map<String, Object> arguments, Object result— Input + output
Context Access — Request Metadata
@McpContext — Inject request context into your tool.
Access client info, session data, request metadata.
@McpServer(name = "MyServer", version = "1.0")
public class MyServer {
@McpTool(description = "Get client info")
public String getClientInfo(@McpContext Context context) {
return "Client: " + context.getClientId();
}
@McpTool(description = "Get session ID")
public String getSessionId(@McpContext Context context) {
return "Session: " + context.getSessionId();
}
@McpTool(description = "Read file with context")
public String readFile(@McpContext Context context, String path) {
context.info("Reading file: " + path);
// Access request headers (e.g., for auth)
Map<String, String> headers = context.getRequestHeaders();
String authHeader = headers.get("Authorization");
// ... read file
return "Content";
}
public static void main(String[] args) {
FastMCP.server(MyServer.class).stdio().run();
}
}
Context capabilities:
getClientId()— Client identifiergetSessionId()— Session identifiergetToolName()— Current tool namegetRequestHeaders()— Client request headers (e.g., auth tokens, custom headers)info(String)— Log info messagewarning(String)— Log warningerror(String)— Log errorreportProgress(int, String)— Report progress percentagelistResources()— List available resourceslistPrompts()— List available prompts
New Features
@McpBash — Shell Command Execution
Execute shell commands with OS-aware shell selection and built-in security guardrails.
@McpServer(name = "MyServer", version = "1.0")
@McpBash(
timeout = 30, // Command timeout in seconds
visibleAfterBasePath = "/sandbox/*", // Whitelist allowed directories
notAllowedPaths = {"/etc", "/root"} // Blacklist dangerous paths
)
public class MyServer { }
Security features:
- Directory validation (whitelist/blacklist)
- Dangerous command blocking (rm -rf, wget, curl, ssh, etc.)
- Directory traversal prevention
- Cross-platform path handling (Windows/Unix)
Supported shells:
- Windows:
cmd.exe - macOS:
/bin/zsh - Linux:
/bin/bash
@McpTelemetry — Metrics & Tracing
Collect metrics and traces for tool invocations.
@McpServer(name = "MyServer", version = "1.0")
@McpTelemetry(
enabled = true,
exportConsole = true, // Human-readable output
exportOtlp = false, // OpenTelemetry export
sampleRate = 1.0, // 100% sampling
includeArguments = false, // Don't log sensitive args
metricExportIntervalMs = 60_000
)
public class MyServer { }
Collected metrics:
- Tool invocation counters
- Execution duration histograms
- Error rates
Multi-Class Tool Organization
Split tools across multiple classes for better organization.
Manual modules (fast, explicit):
@McpServer(
name = "MyServer",
version = "1.0",
modules = {StringTools.class, MathTools.class}
)
Package scanning (convenient):
@McpServer(
name = "MyServer",
version = "1.0",
scanBasePackage = "com.example.tools"
)
Why FastMCP4J?
Less code
Raw MCP SDK: 35+ lines per tool FastMCP4J: ~8 lines per tool
Lightweight
| Framework | Dependencies | Best For |
|---|---|---|
| Spring AI | 50+ jars | Full-stack AI apps |
| LangChain4j | 30+ jars | Enterprise AI pipelines |
| Quarkus AI | 40+ jars | Cloud-native microservices |
| FastMCP4J | 12 jars | MCP servers only |
Fast & focused
- Cold start: <500ms
- Tool invocation: <5ms
- Memory: ~64MB
- Purpose-built for MCP — not a general AI framework
Documentation
- Architecture — How it works
- Roadmap — What's next
- Contributing — PRs welcome
- Changelog — Version history
- Claude Skill — For AI agents
License
MIT © 2026
Less boilerplate. More shipping.
Get started • Examples • Docs
Made with ❤️ for the Java community
Related Servers
Scout Monitoring MCP
sponsorPut performance and error data directly in the hands of your AI assistant.
Alpha Vantage MCP Server
sponsorAccess financial market data: realtime & historical stock, ETF, options, forex, crypto, commodities, fundamentals, technical indicators, & more
Odoo XML-RPC MCP Server
Interact with Odoo instances using the XML-RPC API. Requires configuration via environment variables or config files.
CocoaPods Package README
Retrieve README files and package information from CocoaPods.
Flux Schnell MCP Server
Generate images using the Flux Schnell model via the Replicate API.
APIMatic MCP
APIMatic MCP Server is used to validate OpenAPI specifications using APIMatic. The server processes OpenAPI files and returns validation summaries by leveraging APIMatic’s API.
Remote MCP Server (Authless)
An example of a remote MCP server deployable on Cloudflare Workers without authentication.
ForeverVM
Run Python in a code sandbox.
Lisply-MCP
A Node.js middleware that allows AI agents to interact with Lisp-based systems using the Lisply protocol.
Remote MCP Server (Authless)
An example of a remote MCP server without authentication, deployable on Cloudflare Workers.
DALL-E Image Generator
Generate images using OpenAI's DALL-E API.
ocireg
An SSE-based MCP server that allows LLM-powered applications to interact with OCI registries. It provides tools for retrieving information about container images, listing tags, and more.