MCP (Model Context Protocol) server module for Atmosphere. Exposes annotation-driven tools, resources, and prompt templates to AI agents over Streamable HTTP, WebSocket, or SSE transport.
<dependency>
<groupId>org.atmosphere</groupId>
<artifactId>atmosphere-mcp</artifactId>
<version>4.0.13</version>
</dependency>@McpServer(name = "my-server", path = "/atmosphere/mcp")
public class MyMcpServer {
@McpTool(name = "greet", description = "Say hello")
public String greet(@McpParam(name = "name", required = true) String name) {
return "Hello, " + name + "!";
}
@McpResource(uri = "atmosphere://server/status",
name = "Server Status",
description = "Current server status")
public String serverStatus() {
return "OK";
}
@McpPrompt(name = "summarize", description = "Summarize a topic")
public List<McpMessage> summarize(@McpParam(name = "topic") String topic) {
return List.of(
McpMessage.system("You are a summarization expert."),
McpMessage.user("Summarize: " + topic)
);
}
}| Annotation | Target | Description |
|---|---|---|
@McpServer |
Class | Marks the class as an MCP server and sets the endpoint path |
@McpTool |
Method | Exposes a method as a callable tool (tools/call) |
@McpResource |
Method | Exposes a method as a read-only resource (resources/read) |
@McpPrompt |
Method | Exposes a method as a prompt template (prompts/get) |
@McpParam |
Parameter | Annotates method parameters with name, description, and required flag |
| Transport | How to connect |
|---|---|
| Streamable HTTP (recommended) | POST http://host:port/atmosphere/mcp |
| WebSocket | ws://host:port/atmosphere/mcp |
| SSE | GET http://host:port/atmosphere/mcp |
Agents get automatic reconnection, heartbeats, and transport fallback from Atmosphere's transport layer.
Works with Claude Desktop, VS Code Copilot, Cursor, and any MCP-compatible agent:
{
"mcpServers": {
"my-server": { "url": "http://localhost:8080/atmosphere/mcp" }
}
}For clients that only support stdio, build the bridge JAR with mvn package -Pstdio-bridge -DskipTests and point the client at the resulting atmosphere-mcp-*-stdio-bridge.jar.
- Spring Boot MCP Server -- tools, resources, and prompts with a React frontend
@McpTool methods can declare framework types as parameters. These are auto-injected at invocation time and excluded from the tool's JSON Schema (MCP clients never see them):
| Type | What's injected | Requires |
|---|---|---|
Broadcaster |
BroadcasterFactory.lookup(topic, true) |
A @McpParam(name="topic") argument in the call |
StreamingSession |
BroadcasterStreamingSession wrapping the topic's Broadcaster |
A @McpParam(name="topic") argument + atmosphere-ai on classpath |
AtmosphereConfig |
The framework's AtmosphereConfig |
Nothing |
BroadcasterFactory |
The framework's BroadcasterFactory |
Nothing |
AtmosphereFramework |
The framework instance | Nothing |
@McpServer(name = "my-server", path = "/atmosphere/mcp")
public class MyMcpServer {
@McpTool(name = "broadcast", description = "Send a message to a chat topic")
public String broadcast(
@McpParam(name = "message") String message,
@McpParam(name = "topic") String topic,
Broadcaster broadcaster) {
broadcaster.broadcast(message);
return "sent to " + topic;
}
}When an AI agent calls this tool with {"message": "hello", "topic": "/chat"}, the message is broadcast to all WebSocket/SSE/gRPC clients subscribed to /chat.
With atmosphere-ai on the classpath, inject a StreamingSession that wraps the topic's Broadcaster:
@McpTool(name = "ask_ai", description = "Ask AI and stream answer to a topic")
public String askAi(
@McpParam(name = "question") String question,
@McpParam(name = "topic") String topic,
StreamingSession session) {
// session.send() broadcasts to all clients on the topic
Thread.startVirtualThread(() -> {
var request = ChatCompletionRequest.builder(model).user(question).build();
client.streamChatCompletion(request, session);
});
return "streaming to " + topic;
}See atmosphere-ai README for more on StreamingSession and wire protocol.
BiDirectionalToolBridge enables the server to call tools on connected clients (e.g., browser-side JavaScript functions) and receive results asynchronously. This complements the standard MCP flow (client calls server tools) with a reverse channel.
var bridge = new BiDirectionalToolBridge();
// Call a client-side tool — returns a CompletableFuture
CompletableFuture<String> result = bridge.callClientTool(
resource, "getLocation", Map.of("highAccuracy", true));
result.thenAccept(location -> log.info("Client location: {}", location));callClientTool()generates a UUID, writes a JSON request to the client viaAtmosphereResource, and returns aCompletableFuture- The client executes the tool and sends back a JSON response with the same ID
ToolResponseHandler(registered at/_mcp/tool-response) receives the response and completes the matching future
Server → Client (tool call request):
{"type":"tool_call","id":"uuid","name":"getLocation","args":{"highAccuracy":true}}Client → Server (tool call response):
{"id":"uuid","result":"40.7128,-74.0060"}Or on error:
{"id":"uuid","error":"Permission denied"}| Constructor | Timeout |
|---|---|
new BiDirectionalToolBridge() |
30 seconds (default) |
new BiDirectionalToolBridge(Duration.ofSeconds(10)) |
Custom timeout |
Timed-out calls complete exceptionally with TimeoutException. Error responses complete with ToolCallException.
framework.addAtmosphereHandler("/_mcp/tool-response",
new ToolResponseHandler(bridge));| Class | Description |
|---|---|
BiDirectionalToolBridge |
Core bridge — sends requests, tracks pending futures, completes on response |
ToolCallRequest |
Record: id, name, args with toJson() serialization |
ToolCallResponse |
Record: id, result, error with fromJson() parsing |
ToolResponseHandler |
AtmosphereHandler that routes client responses to the bridge |
McpTracing wraps every tools/call, resources/read, and prompts/get invocation in an OTel trace span. Add opentelemetry-api to your classpath:
<dependency>
<groupId>io.opentelemetry</groupId>
<artifactId>opentelemetry-api</artifactId>
<optional>true</optional>
</dependency>Wire it programmatically:
var tracing = new McpTracing(openTelemetry);
protocolHandler.setTracing(tracing);With the Spring Boot starter, McpTracing is auto-configured when an OpenTelemetry bean is present.
Span attributes:
| Attribute | Description |
|---|---|
mcp.tool.name |
Tool/resource/prompt name |
mcp.tool.type |
"tool", "resource", or "prompt" |
mcp.tool.arg_count |
Number of arguments provided |
mcp.tool.error |
true if invocation failed |
See docs/mcp.md for complete documentation.
- Java 21+
atmosphere-runtime(transitive)