fastMCP4J
Framework ligero y rápido de servidor MCP en Java: crea servidores del Protocolo de Contexto de Modelo con mínimo código repetitivo y compatibilidad total con el SDK de TypeScript.
Documentación
FastMCP4J
Anota una clase Java. Despliega un servidor MCP.
Herramientas, recursos, prompts, memoria — y una terminal bash aislada que no puede tocar tu máquina. Sin código repetitivo, sin contenedores, sin un framework de 50 JARs.
Agentes de IA → Comparte esta habilidad con Claude para generación de código
FastMCP4J es un SDK basado en anotaciones para el Protocolo de Contexto de Modelos (especificación 2.0.1) en Java 17+. Una anotación convierte una clase en un servidor MCP; una más le da a tu agente de IA una terminal real — un sandbox de bash donde el host es inalcanzable por construcción. Arranque en frío en menos de 500 ms, doce dependencias, todo comprobable en proceso.
Estado: beta (v0.5.0-beta) — API estable, 235 pruebas pasando, publicado en Maven Central.
Inicio rápido (2 minutos)
Maven
<dependency>
<groupId>io.github.terseprompts.fastmcp</groupId>
<artifactId>fastmcp-java</artifactId>
<version>0.5.0-beta</version>
</dependency>
Gradle
implementation 'io.github.terseprompts.fastmcp:fastmcp-java:0.5.0-beta'
Esa es toda la historia de instalación: Java 17+, un artefacto en Maven Central, SDK de Java MCP 2.0.1 por debajo. Sin procesador de anotaciones, sin paso de generación de código, sin runtime de contenedores.
Crea tu servidor
@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();
}
}
mvn exec:java -Dexec.mainClass="com.example.MyAssistant"
Eso es todo. Tu servidor MCP está en ejecución.
Ejemplo funcional: EchoServer.java
Por qué existe esto
Cada equipo de Java que conecta agentes de IA a herramientas enfrenta la misma elección, y cada opción duele:
| SDK MCP puro | Spring AI / LangChain4j | FastMCP4J | |
|---|---|---|---|
| Líneas por herramienta | 35+ | varía, más pegamento de framework | ~8 |
| Dependencias | 1 + tu paciencia | 30–50+ JARs | 12 JARs |
| Arranque | rápido | del tamaño de un framework | <500 ms, ~64 MB |
| Bash aislado | hazlo tú mismo | no incluido | ✅ integrado (bashkit4j) |
| Memoria / todo / planificador / herramientas de archivos integradas | no | no | ✅ una anotación cada una |
| Bloqueo | ninguno | framework | ninguno — MCP entra, MCP sale |
Antes: un día de configuración de esquemas JSON por herramienta, y el acceso al shell significa que un prompt malicioso es un nodo caído. Después: anotaciones el martes, agentes en producción el miércoles — y la terminal que usan no puede tocar tu disco.
El recorrido por la API
1 · Crea una herramienta — síncrona o asíncrona
@McpTool(description = "Add two numbers")
public int add(int a, int b) {
return a + b;
}
@McpTool(description = "Process data")
@McpAsync // ← just add this; return Mono<?>
public Mono<String> process(@McpContext Context ctx, String input) {
return Mono.fromCallable(() -> {
ctx.reportProgress(50, "Processing...");
return slowOperation(input);
});
}
2 · Cerebros integrados — una anotación cada uno
@McpServer(name = "MyServer", version = "1.0")
@McpMemory // AI remembers things across sessions
@McpTodo // AI manages tasks
@McpPlanner // AI breaks work into plans
@McpFileRead // AI reads your files
@McpFileWrite // AI writes files
public class MyServer {
// complete tool sets enabled, zero implementation
}
| Anotación | Herramientas que obtienes |
|---|---|
@McpMemory | listar, leer, crear, reemplazar, insertar, eliminar, renombrar |
@McpTodo | agregar, listar, actualizarEstado, actualizarTarea, eliminar, limpiarCompletadas |
@McpPlanner | crearPlan, listarPlanes, obtenerPlan, agregarTarea, agregarSubtarea |
@McpFileRead | leerLíneas, leerArchivo, grep, obtenerEstadísticas |
@McpFileWrite | escribirArchivo, agregarArchivo, escribirLíneas, eliminarArchivo, crearDirectorio |
3 · Bash aislado — dale al agente una terminal, no tu máquina
@McpServer(name = "Reviewer", version = "1.0")
@McpBash(
allowMountsUnder = "C:/dev", // opt in: all it may ever see
mounts = {"/project=C:/dev/my-app"}, // mount the project — read-only
timeout = 30, maxCommands = 10_000 // bounds runaway scripts
)
public class Reviewer { }
Los scripts se ejecutan en un bashkit4j
sandbox en memoria: bash estilo POSIX con más de 160 comandos reimplementados
de forma nativa, un sistema de archivos virtual, red denegada por defecto. Nunca se ejecuta
bash real. Luego el agente llama a la herramienta bash:
grep -rn TODO /project/src | head -5 # real files, zero risk
echo "findings..." > /notes.md # writes stay in the sandbox
Shell del host (ProcessBuilder, Docker) | Modo sandbox | |
|---|---|---|
| Bash real en el host | ✅ se ejecuta — superficie de ataque completa | ❌ nunca — bash reimplementado de forma nativa |
| Sistema de archivos del host visible | ✅ todo | ❌ invisible hasta que lo montas, solo lectura por defecto |
| Procesos del SO por comando | ✅ uno por llamada | ❌ cero — en proceso |
| Acceso a red | ✅ abierto | ❌ denegado por defecto |
| Un script malicioso | nodo caído | sandbox reiniciado |
El estado persiste entre llamadas (directorio actual, entorno, archivos) — los flujos de trabajo
de agentes de varios pasos funcionan. Los montajes se aplican dentro de la biblioteca nativa:
canonicalizados, seguros contra enlaces simbólicos, e imposibles sin allowMountsUnder. ¿Necesitas el shell real
para automatización confiable? mode = BashMode.HOST mantiene la herramienta heredada con sus
protecciones de rutas.
El modo sandbox requiere la dependencia opcional
io.github.terseprompts:bashkit4j:0.2.0— las bibliotecas nativas para Windows/Linux/macOS (x86-64 + ARM64) están incluidas y se detectan automáticamente.
🔭 Alcance futuro — un tercer modo,
BashMode.DOCKER. La escalera de aislamiento gana un peldaño más:HOST= la computadora completa (uso confiable) →SANDBOX= una computadora virtual, sin ejecución de código real (por defecto) →DOCKER= bash real dentro de una jaula de contenedor por sesión. El esquema: un contenedor por sesión MCP, creado de forma diferida y endurecido en ejecución (--network none --memory 512m --cpus 1 --pids-limit 64 --security-opt no-new-privileges --read-only --tmpfs /tmp); el comando se pasa como un solo elemento argv (sin interpolación del shell del host → sin superficie de inyección); el tiempo de espera se aplica dentro del contenedor para que el tiempo de pared sobreviva a un fallo del servidor; códigos de salida con nombre ([exit 124: timed out],[exit 137: OOM]), salida limitada, expulsión por TTL de inactividad con un respaldo de reaper — los contenedores permanecen sin estado, el estado duradero vive solo en el árbol de trabajo montado. La configuración sigue siendo solo de entorno (FASTMCP_DOCKER_IMAGE, tiempo de espera). No iniciado — consulta Hoja de ruta; se busca ayuda.
4 · Elige un transporte
FastMCP.server(MyServer.class)
.stdio() // CLI tools, local agents
.sse() // web clients, long-lived connections
.streamable() // bidirectional streaming (recommended)
.run();
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();
5 · Recursos y 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;
}
6 · Hooks — antes/después de cada llamada a herramienta
// 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 a specific tool only
@McpPostHook(toolName = "calculate", order = 1)
void logResult(Map<String, Object> args, Object result) {
System.out.println("Result: " + result);
}
toolName— herramienta objetivo, o"*"para todas (vacío = inferido del nombre del método)order— prioridad de ejecución, menor se ejecuta primero (por defecto0)- Los pre-hooks reciben los argumentos; los post-hooks reciben argumentos + resultado
7 · Contexto de solicitud
@McpTool(description = "Read file with auth")
public String readFile(@McpContext Context context, String path) {
context.info("Reading file: " + path);
String auth = context.getRequestHeaders().get("Authorization");
// ...
}
Context te da getClientId(), getSessionId(), getToolName(),
getRequestHeaders(), registro de info/warning/error, reportProgress,
listResources(), listPrompts().
8 · Organiza a escala
// explicit modules
@McpServer(name = "MyServer", version = "1.0",
modules = {StringTools.class, MathTools.class})
// or package scanning
@McpServer(name = "MyServer", version = "1.0",
scanBasePackage = "com.example.tools")
9 · Iconos y telemetría
@McpServer(
name = "my-server",
icons = {"data:image/svg+xml;base64,...:image/svg+xml:64x64:light"}
)
@McpTelemetry(enabled = true, exportConsole = true, sampleRate = 1.0)
public class MyServer { }
La telemetría recopila contadores de invocación de herramientas, histogramas de duración y tasas de error — exportación a consola o OpenTelemetry.
Referencia de anotaciones
| Anotación | Objetivo | Propósito |
|---|---|---|
@McpServer | TIPO | Define tu servidor MCP |
@McpTool | MÉTODO | Expón como herramienta invocable |
@McpResource | MÉTODO | Expón como recurso |
@McpPrompt | MÉTODO | Expón como plantilla de prompt |
@McpParam | PARÁMETRO | Descripción, ejemplos, restricciones, valores por defecto |
@McpAsync | MÉTODO | Haz la herramienta asíncrona (devuelve Mono<?>) |
@McpContext | PARÁMETRO | Inyecta contexto de solicitud |
@McpPreHook / @McpPostHook | MÉTODO | Ejecuta código antes/después de llamadas a herramientas |
@McpBash | TIPO | Herramienta bash — aislada (por defecto) o shell del host vía mode |
@McpTelemetry | TIPO | Métricas y trazabilidad |
@McpMemory / @McpTodo / @McpPlanner | TIPO | Conjuntos de herramientas integrados |
@McpFileRead / @McpFileWrite | TIPO | Herramientas de archivos integradas |
Opciones avanzadas de @McpParam:
@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; }
Lo que el sandbox realmente hace (medido, no afirmado)
FastMCP4J incluye 235 pruebas (mvn test) — la suite del sandbox se ejecuta contra
la biblioteca nativa real en CI de Windows y Linux, incluyendo sondas de escape
deliberadas:
| Sonda | Resultado |
|---|---|
ls / dentro del sandbox | solo raíz virtual — pom.xml, target, rutas del host ausentes |
whoami / hostname | agent@sandbox — identidad virtual, no tu usuario del SO |
| Escribir en un montaje de solo lectura | falla; el archivo del host nunca aparece de forma demostrable |
| Montaje de lectura-escritura | viajes de ida y vuelta al host a través de la API de Java |
cd + archivo entre llamadas a herramientas | persiste dentro de un servidor; sellado entre servidores |
| Script que excede el tiempo de espera | el llamador recibe TIMEOUT; el sandbox se reemplaza fresco para la siguiente llamada |
| 4 llamadas a herramientas concurrentes | todas se completan — las llamadas se serializan en el sandbox |
Sandbox sin bashkit4j en el classpath | error de arranque claro que nombra la dependencia |
Para quién es
- Ingenieros de IA/LLM — expón servicios Java a Claude, Cursor o cualquier cliente MCP con esfuerzo a nivel de anotación.
- Equipos que envían herramientas de agentes — memoria, todo, planificación, acceso a archivos y una terminal aislada listos para usar; hooks y telemetría para producción.
- Plataformas conscientes de la seguridad — acceso de terminal de agentes con el host inalcanzable por construcción, no por ingeniería de prompts.
- Bases de código existentes con Spring/DI — servidor de inserción directa, sin bloqueo de framework; tus beans se convierten en herramientas con una anotación.
Requisitos y rendimiento
Solo Java 17+ y Maven 3.8+. Especificación MCP 2.0.1 vía el SDK oficial de Java
(mcp-core + mcp-json-jackson2).
- Arranque en frío: <500 ms
- Invocación de herramientas: <5 ms
- Memoria: ~64 MB
- Diseñado específicamente para MCP — no un framework general de IA
CI/CD
| Rama | Qué se ejecuta |
|---|---|
development (staging) | Suite de pruebas completa + pruebas de integración MCP (STDIO / SSE / Streamable / Bash aislado) en cada push y PR |
main | Misma suite + publicación en Maven Central (en etapas; aprobación manual en Sonatype Central) |
Flujo: rama de características → development → main (lanzamiento).
Documentación
- Arquitectura — cómo funciona
- Hoja de ruta — qué sigue
- Contribuciones — los PRs son bienvenidos
- Registro de cambios — historial de versiones
- Habilidad de Claude — para agentes de IA
Licencia
MIT © 2026
Menos código repetitivo. Más envíos.
Comenzar • Ejemplos • Documentación
Hecho con ❤️ para la comunidad de Java