The Spring Boot framework for when Model Context Protocol (MCP) is a real surface of your product — not a prototype.
Define tools, prompts, and resources as annotated Spring beans. Pull in optional modules for OAuth2, per-handler authorization, Jakarta Bean Validation, structured audit logs, Micrometer observations, MDC correlation, an /actuator/mcp inventory endpoint, and GraalVM native-image support — all wired through one customizer SPI.
Requirements: Java 25+ (current LTS) · Spring Boot 4 · Maven 3.9+.
Status: stable. 1.0.0 implements MCP
2026-07-28exclusively and follows semantic versioning — breaking changes only in a new major. Features deliberately not implemented are enumerated, with rationale, in ADR-0022. We'd love feedback and real-world usage reports.
Building an MCP server from scratch means solving the same problems every team solves: JSON-RPC dispatch, the _meta envelope and routing-header validation, SSE response streaming, multi-round-trip elicitation, schema generation, OAuth2, tracing, metrics, audit. Mocapi ships those pieces as Spring Boot autoconfiguration you wire by adding a transport starter, and extend through a single customizer SPI.
- MCP 2026-07-28 surface. Tools, prompts, resources, resource templates, completions,
server/discover, multi-round-trip (MRTR) elicitation, progress notifications, cacheable results, and the OAuth2 authorization flow — fully stateless, as the revision requires. Exercised by the official conformance suite. Deliberate omissions (deprecated Roots/Sampling/Logging,subscriptions/listen) are recorded with rationale in ADR-0022. - Transport-agnostic handler code. Write a
@McpToolonce; run it over Streamable HTTP (for web clients) or stdio (for Claude Desktop / Cursor / IDE integrations) with no code change. - Observability modules. Metrics and tracing via Micrometer Observation, SLF4J MDC correlation, structured audit logs — each activates by dropping in a module.
- Authorization. OAuth2 resource server (MCP 2026-07-28 spec), per-handler
GuardSPI, and@RequiresScope/@RequiresRoleannotations backed by Spring Security. New to securing an MCP server? Start with the security guide — the endpoint is unauthenticated until you addmocapi-oauth2. - Stateless by design. No sessions, no sticky routing, no shared store: any node serves any request, and elicitation round trips travel as self-contained AES-GCM-encrypted
requestStatetokens. Scale-to-zero and serverless deployments are the natural shape. - Typed extension SPI. One customizer interface per handler kind. Attach interceptors, guards, or parameter resolvers with full access to the handler's descriptor, method, and bean — no blind bean-list autowiring.
- Virtual-thread-friendly. Context propagates across the per-call virtual-thread spawn so tracing spans parent correctly and
SecurityContextHolderworks on the handler thread. A standing soak test sustained ~565 req/s with full observability on a laptop (see Performance Benchmarking). - MCP Apps (the server half). Serve interactive
ui://HTML resources and link them to tools — declare them with@McpAppResource, or serve a bundle straight from the classpath with@McpUi(resource=…); mocapi emits theio.modelcontextprotocol/uicapability,_meta.ui(CSP/sandbox), and fails fast on dangling links. Addmocapi-apps. See MCP Apps. - MCP Tasks. Add
@McpTaskto any tool and it transparently runs as a polled background task (io.modelcontextprotocol/tasks) for clients that declare the extension — same tool code serves everyone else synchronously. Progress emits become the task'sstatusMessage, mid-task elicitation flows throughtasks/get/tasks/update, and state lives behind a pluggableTaskStore(in-memory default; contract TCK for custom stores). For durable, multi-node task state addmocapi-tasks-substrate— a Substrate-backed store that works across any of its nine backends (Redis, PostgreSQL, MongoDB, …) and survives application restarts. Addmocapi-tasks. See MCP Tasks. - GraalVM native-image hints included.
Add the starter dependency:
<dependency>
<groupId>com.callibrity.mocapi</groupId>
<artifactId>mocapi-streamable-http-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>If you depend on multiple mocapi artifacts (e.g., a starter plus one of the mocapi-prompts-* modules), import the BOM to keep versions aligned:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.callibrity.mocapi</groupId>
<artifactId>mocapi-bom</artifactId>
<version>1.3.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>Then declare individual mocapi artifacts without a <version> — the BOM pins them.
Define a tool:
import com.callibrity.mocapi.api.tools.McpTool;
import org.springframework.stereotype.Component;
@Component
public class GreetingTool {
@McpTool(name = "greet", description = "Returns a greeting message")
public GreetingResponse greet(String name) {
return new GreetingResponse("Hello, " + name + "!");
}
public record GreetingResponse(String message) {}
}Define a prompt:
import com.callibrity.mocapi.api.prompts.McpPrompt;
import com.callibrity.mocapi.model.GetPromptResult;
import com.callibrity.mocapi.model.PromptMessage;
import com.callibrity.mocapi.model.Role;
import com.callibrity.mocapi.model.TextContent;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class SummarizationPrompts {
@McpPrompt(name = "summarize", description = "Summarize the provided text")
public GetPromptResult summarize(String text) {
return new GetPromptResult(
"Summarization prompt",
List.of(new PromptMessage(
Role.USER,
new TextContent("Summarize the following:\n\n" + text, null))));
}
}Define a resource (fixed URI) and a resource template (pattern-matched URI):
import com.callibrity.mocapi.api.resources.McpResource;
import com.callibrity.mocapi.api.resources.McpResourceTemplate;
import com.callibrity.mocapi.model.ReadResourceResult;
import com.callibrity.mocapi.model.TextResourceContents;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class DocResources {
@McpResource(uri = "docs://readme", mimeType = "text/markdown")
public ReadResourceResult readme() {
return new ReadResourceResult(
List.of(new TextResourceContents("docs://readme", "text/markdown", "# Hello")));
}
@McpResourceTemplate(uriTemplate = "docs://pages/{slug}", mimeType = "text/markdown")
public ReadResourceResult page(String slug) {
return new ReadResourceResult(
List.of(new TextResourceContents(
"docs://pages/" + slug, "text/markdown", "Content for " + slug)));
}
}Run your Spring Boot application. With mocapi-streamable-http-spring-boot-starter, Mocapi exposes a Streamable HTTP endpoint at /mcp. For clients that launch the server as a subprocess (Claude Desktop, Cursor, and other IDE integrations), depend on mocapi-stdio-spring-boot-starter instead and set mocapi.stdio.enabled=true — same tools, same code, different pipe.
Docs live under docs/ in three trees:
docs/guides/— how to use mocapi as a library consumer.docs/design/— internal architecture, kept synchronized with the code.docs/adr/— point-in-time architecture decisions with status.
- Writing Tools -- defining tools, parameters, return values, and error handling
- Writing Prompts -- defining prompts, argument binding, and return messages
- Writing Resources -- fixed resources, templated resources, and path-variable binding
- Externalizing Annotation Metadata --
${...}property placeholders for tool/prompt/resource descriptions, URIs, and names - Securing your MCP Server -- pre-production hardening checklist: authentication, MRTR secret, argument validation, per-handler authorization, TLS/CORS
- Authorization -- OAuth2 resource-server setup for the Streamable HTTP transport (MCP 2026-07-28)
- Guards -- per-handler visibility + call-time authorization via the
GuardSPI;@RequiresScope/@RequiresRoleviamocapi-spring-security-guards - Validation -- Jakarta Bean Validation on user
@McpTool/@McpPrompt/@McpResourceTemplateparameters via the optionalmocapi-jakarta-validation - Interactive Tools -- progress notifications and multi-round-trip elicitation
- MCP Apps -- serve
ui://HTML resources and link them to tools viamocapi-apps(@McpAppResource/@McpUi), including classpath serve-mode - MCP Tasks --
@McpTaskbackground tasks viamocapi-tasks: the capability-based decision rule, polling, mid-task elicitation, customTaskStores + the contract TCK - Observability -- metrics + tracing (Micrometer Observation), MDC correlation, and structured audit logging
- OpenTelemetry -- drop-in OTel tracing via
mocapi-otel: bundlesmocapi-o11y+ Spring Boot 4's OTel SDK + tracing bridge; emits a two-layerjsonrpc.server/mcp.handler.executiontrace with OTel MCP / JSON-RPC / GenAI semconv attrs - Logging -- MDC correlation keys via
mocapi-logging - Audit -- structured audit logging via
mocapi-auditfor compliance queries and SIEM ingestion - Actuator Endpoint --
/actuator/mcphandler-inventory endpoint shape and operational checks - Extending mocapi -- the seam taxonomy (
*Contributor/*Customizer/*Interceptor/*Store-*Source-*Strategy/*Sink), one worked example per seam, the dispatch-interceptor contract, and API-vs-SPI classification - Customizers -- the
*HandlerCustomizerSPI for extending mocapi: attach interceptors, guards, and parameter resolvers per handler - Custom Parameter Resolvers -- writing
@CurrentTenant-style parameter resolvers via the customizer SPI - Configuration Reference -- all
mocapi.*properties - Performance Benchmarking -- periodic soak-test + JFR-profiling runbook to track regressions
- Architecture Overview -- module layering, request flow, ScopedValues
- Transports -- Streamable HTTP, stdio, the
McpServer↔McpTransportcontract - Extension SPI -- customizer model, six interceptor strata, parameter resolvers
- Authorization Model -- how OAuth2 + Guard SPI compose
- Observability Stack -- design of the four-module observability story
- Elicitation — MRTR Replay -- requestState tokens, the replay ledger, schema constraints
- MCP Apps -- the
mocapi-appsmodule,_meta.uishapes, descriptor customizers, serve-mode, and the scope boundary - MCP Tasks -- the
mocapi-tasksmodule: replay-through-store execution, theTaskStoreSPI, cancel semantics, and deployment topology
See docs/adr/ for the full list of architecture
decision records.
mocapi-api— user-facing API:@McpTool,@McpPrompt,@McpResource/@McpResourceTemplate,PromptTemplate/PromptTemplateFactory,McpToolContext, provider interfacesmocapi-model— MCP protocol types (Tool, CallToolResult, ElicitResult, etc.) — mechanical mapping from the MCP specmocapi-server— stateless MCP server:_metaenvelope parsing, JSON-RPC dispatch, tool/prompt/resource invocation,server/discover, the MRTR elicitation replay engine
mocapi-streamable-http-transport— HTTP + SSE, encrypted event IDsmocapi-stdio-transport— newline-delimited JSON-RPC on stdin/stdout, for subprocess-launched MCP clients
Only two starters. Every mocapi application adds exactly one.
mocapi-streamable-http-spring-boot-starter— bundlesmocapi-server+ streamable-HTTP transport +spring-boot-starter-web. Expose an/mcpendpoint accessible over the network.mocapi-stdio-spring-boot-starter— bundlesmocapi-server+ stdio transport. For subprocess-launched MCP clients (Claude Desktop, Cursor, IDE integrations); no web stack.
Each module is plain Java + an optional Spring Boot autoconfig (hosted in mocapi-autoconfigure). Add the module to your pom; the corresponding feature activates automatically.
mocapi-oauth2— OAuth2 resource-server protection on the MCP endpoint (MCP 2026-07-28 authorization); wraps Spring Boot's OAuth2 resource-server starter and adds the RFC 9728 protected-resource metadata document. Ships twoSecurityFilterChainbeans (public metadata + authenticated MCP) each with its own customizer SPI (McpMetadataFilterChainCustomizer,McpFilterChainCustomizer), a swappableMcpTokenStrategyfor JWT vs. opaque tokens, and a facet-basedMcpMetadataCustomizerSPI for shaping the metadata document. See Authorization.mocapi-spring-security-guards— annotation-drivenGuardimplementations backed by Spring Security. Reads@RequiresScope/@RequiresRoleoff user handler methods at startup and attaches matching guards via the customizer SPI; denied handlers disappear fromtools/listetc. and call-time returns JSON-RPC-32010 Forbidden. See Guards.mocapi-jakarta-validation— Jakarta Bean Validation on user@McpTool/@McpPrompt/@McpResourceTemplateparameters. Annotations like@NotBlank/@Size/@Patternsurface asCallToolResult.isError=truefor tools (MCP-spec-idiomatic for LLM self-correction) and JSON-RPC-32602 Invalid paramswith per-violation detail for prompts and resources. See Validation.mocapi-logging— SLF4J MDC correlation for MCP handler invocations. Stampsmcp.protocol.version,mcp.client.name,mcp.handler.kind,mcp.handler.name, andmcp.request.idonto the MDC for the duration of every handler call so every log line from user code carries correlation context automatically. See Logging.mocapi-o11y— metrics + distributed tracing via Micrometer'sObservationAPI. Two layers: a filter enriches ripcurl-o11y's outerjsonrpc.serverobservation withmcp.method.name/mcp.protocol.versiontags (joining inbound W3C trace context from the_metaenvelope); a per-handler interceptor emits an innermcp.handler.executionobservation carrying GenAI / MCP-resource attrs (gen_ai.tool.name,gen_ai.prompt.name,mcp.resource.uri). Self-sufficient — transitively pullsspring-boot-micrometer-observationso anObservationRegistryis always present. See Observability.mocapi-otel— drop-in OpenTelemetry tracing. Source-less dependency bundle that pullsmocapi-o11yplusspring-boot-starter-opentelemetry(OTel SDK + Micrometer Observation → OTel tracing bridge + autoconfig). Add this module plus the exporter for your backend — OTLP for Jaeger/Tempo, Azure Monitor starter for App Insights, Datadog, etc. — andjsonrpc.server/mcp.handler.executionspans flow end-to-end. See OTel guide.mocapi-audit— structured audit logging for every MCP handler invocation. Emits one INFO event on themocapi.auditSLF4J logger per call with caller identity, protocol version, client name, handler kind/name, outcome (success/forbidden/invalid_params/error), duration, and (opt-in) a SHA-256 hash of the arguments — everything compliance / SIEM queries need, nothing PII-shaped. See Audit.mocapi-actuator— Spring Boot Actuator endpoint (/actuator/mcp) exposing a read-only inventory of the tools, prompts, resources, and resource templates registered on this node. Publishes handler names + schema digests. See Actuator Endpoint.mocapi-apps— the MCP Apps server surface (io.modelcontextprotocol/ui). Declareui://HTML resources with@McpAppResource(or serve a classpath bundle via@McpUi(resource=…)) and link them to tools with@McpUi; contributes theuicapability plus_meta.ui(CSP/sandbox) on descriptors, and fails startup fast on a@McpUipointing at an undeclared resource. mocapi is the server half only — the in-iframe JS is the host's and the official ext-apps SDK's. See MCP Apps.mocapi-tasks— the MCP Tasks extension (io.modelcontextprotocol/tasks). Add@McpTaskto a tool and task-capable clients get a polled background task (tasks/get/tasks/update/tasks/cancel) while everyone else runs it synchronously — the tool body never changes. Progress emitters feed the task'sstatusMessage; mid-task elicitation replays through a pluggableTaskStore(in-memory default with a multi-node warning; ship your own store bean for clusters and prove it with the bundled contract TCK). See MCP Tasks.mocapi-autoconfigure— one module hosting every mocapi autoconfig (pulled in by either transport starter; you normally don't depend on it directly).
mocapi-prompts-spring—PromptTemplateFactoryusing Spring's${name}placeholder syntax; no extra dependenciesmocapi-prompts-mustache—PromptTemplateFactorybacked by JMustache for richer{{name}}templates with sections
mocapi-bom— imports into your<dependencyManagement>to align versions across multiple mocapi artifacts without hard-coding each one
Working examples are in the examples/ directory:
| Example | Transport | Description |
|---|---|---|
| HTTP | Streamable HTTP | Comprehensive app: tools, resources, prompts, elicitation, and Jakarta Bean Validation |
| Stdio | stdio | Minimal echo server launchable by Claude Desktop or MCP Inspector over stdio |
| Apps | Streamable HTTP | MCP Apps: a get-time tool linked to a ui:// React UI served via @McpUi(resource=…), built by Vite into a single self-contained bundle |
| Tasks | Streamable HTTP | MCP Tasks: @McpTask tools showing the task lifecycle — progress-driven statusMessage polling, mid-task elicitation via tasks/update, sync degrade, and required = true |
| Tasks + Redis | Streamable HTTP | The tasks example on a durable Redis TaskStore (mocapi-tasks-substrate): Spring Boot's Docker Compose support starts Redis, and task state survives application restarts — kill the app at input_required, restart, answer, and MRTR replay completes the task |
To run the HTTP example:
cd examples/http
mvn spring-boot:runThen connect with the MCP Inspector:
npx @modelcontextprotocol/inspectorEnter http://localhost:8080/mcp and select "Streamable HTTP" transport.
To run the stdio example (no HTTP server — MCP client launches it as a subprocess):
mvn -pl examples/stdio -am package
npx @modelcontextprotocol/inspector \
java -jar examples/stdio/target/mocapi-example-stdio-*.jarSee examples/stdio/README.md for Claude Desktop configuration.
Mocapi targets the MCP 2026-07-28 specification and is validated against the official conformance suite: core 79 checks pass / 13 baselined; tasks extension 33 pass / 2 baselined — every baselined failure is a deliberate omission (see ADR-0022) or a documented suite defect, not a protocol-correctness gap. Mocapi passes every check that tests actual protocol behavior. The expected-failures baseline records each exception with its reason; see mocapi-conformance/README.md to reproduce:
# Start the conformance server
cd mocapi-conformance
mvn spring-boot:run
# In another terminal
npx @modelcontextprotocol/conformance server --url http://localhost:8081/mcpmvn clean installRequires Java 25+ and Maven 3.9+.
We welcome contributions! Please see CONTRIBUTING.md for guidelines.
Apache License 2.0 -- see LICENSE.
Mocapi is a made-up word that includes the letters MCP (Model Context Protocol). It's pronounced moh-cap-ee (/ˈmoʊˌkæpi/), like a friendly little robot who speaks protocol.