|
34 | 34 | /** |
35 | 35 | * MCP (Model Context Protocol) module for Jooby. |
36 | 36 | * |
37 | | - * <p>The MCP module provides integration with the Model Context Protocol server, enabling |
38 | | - * standardized communication between clients and servers. It allows applications to: |
| 37 | + * <p>The MCP module provides seamless integration with the Model Context Protocol, allowing your |
| 38 | + * application to act as a standardized AI context server. It automatically bridges your Java/Kotlin |
| 39 | + * methods with LLM clients by exposing them as Tools, Resources, and Prompts. |
| 40 | + * |
| 41 | + * <h2>Key Features</h2> |
39 | 42 | * |
40 | 43 | * <ul> |
41 | | - * <li>Expose server capabilities as tools, resources, and prompts |
42 | | - * <li>Handle client connections and sessions via SSE |
43 | | - * <li>Process protocol messages and events |
44 | | - * <li>Manage server capabilities and tool specifications |
| 44 | + * <li><b>Compile-Time Discovery:</b> Automatically generates routing logic for {@code @McpTool}, |
| 45 | + * {@code @McpPrompt}, and {@code @McpResource} annotations with zero reflection overhead via |
| 46 | + * APT. |
| 47 | + * <li><b>Rich Schema Generation:</b> Tool and parameter descriptions are extracted directly from |
| 48 | + * your MCP annotations, gracefully falling back to standard JavaDoc comments if omitted. |
| 49 | + * <li><b>Transport Flexibility:</b> Supports {@link Transport#STREAMABLE_HTTP} (default), {@link |
| 50 | + * Transport#SSE}, {@link Transport#WEBSOCKET}, and {@link |
| 51 | + * Transport#STATELESS_STREAMABLE_HTTP}. |
| 52 | + * <li><b>Execution Interception:</b> Chain custom {@link McpInvoker} instances to seamlessly |
| 53 | + * inject MDC context, telemetry, or custom error handling around executions. |
| 54 | + * <li><b>LLM Self-Healing:</b> Automatically catches internal business exceptions and translates |
| 55 | + * them into valid MCP error payloads, allowing LLMs to auto-correct their own mistakes. |
45 | 56 | * </ul> |
46 | 57 | * |
47 | | - * <h2>Usage</h2> |
| 58 | + * <h2>Basic Usage</h2> |
| 59 | + * |
| 60 | + * <p>By default, the module requires zero configuration in {@code application.conf} and will spin |
| 61 | + * up a single {@code streamable-http} server. |
48 | 62 | * |
49 | | - * <p>Add the module to your application: |
| 63 | + * <p>The module relies on Jackson for JSON-RPC message serialization. Here is the standard setup |
| 64 | + * using Jackson 3: |
50 | 65 | * |
51 | 66 | * <pre>{@code |
52 | 67 | * { |
53 | | - * install(new JacksonModule()); |
54 | | - * install(new McpModule(new DefaultMcpServer())); |
| 68 | + * // 1. Install Jackson 3 support |
| 69 | + * install(new Jackson3Module()); |
| 70 | + * install(new McpJackson3Module()); |
| 71 | + * // 2. Install the MCP module with your APT-generated McpService |
| 72 | + * install(new McpModule(new MyServiceMcp_())); |
55 | 73 | * } |
56 | 74 | * }</pre> |
57 | 75 | * |
58 | | - * <h2>Configuration</h2> |
| 76 | + * <i>Note: If your project still uses Jackson 2, simply swap the modules to {@code install(new |
| 77 | + * JacksonModule());} and {@code install(new McpJackson2Module());}.</i> |
59 | 78 | * |
60 | | - * <p>The module requires the following configuration in your application.conf: |
| 79 | + * <h2>Changing the Default Transport</h2> |
| 80 | + * |
| 81 | + * <p>If you want to use a different transport protocol for the default server, you can configure it |
| 82 | + * directly in the Java DSL: |
61 | 83 | * |
62 | 84 | * <pre>{@code |
63 | | - * mcp.default { |
64 | | - * name: "my-awesome-mcp-server" # Required |
65 | | - * version: "0.0.1" # Required |
66 | | - * sseEndpoint: "/mcp/sse" # Optional (default: /mcp/sse) |
67 | | - * messageEndpoint: "/mcp/message" # Optional (default: /mcp/message) |
| 85 | + * { |
| 86 | + * install(new McpModule(new MyServiceMcp_()) |
| 87 | + * .transport(Transport.SSE)); // Or Transport.WEBSOCKET, Transport.STATELESS_STREAMABLE_HTTP |
68 | 88 | * } |
69 | 89 | * }</pre> |
70 | 90 | * |
71 | | - * <h2>Features</h2> |
| 91 | + * <h2>Custom Invokers & Telemetry</h2> |
72 | 92 | * |
73 | | - * <ul> |
74 | | - * <li>MCP server implementation with SSE transport |
75 | | - * <li>Tools Auto-discovery at build time |
76 | | - * <li>Server capabilities configuration |
77 | | - * <li>Configurable endpoints |
78 | | - * <li>Multiple servers support |
79 | | - * </ul> |
| 93 | + * <p>You can inject custom logic (like SLF4J MDC context propagation or Tracing spans) around every |
| 94 | + * tool, prompt, or resource call by providing a custom {@link McpInvoker}: |
| 95 | + * |
| 96 | + * <pre>{@code |
| 97 | + * { |
| 98 | + * install(new McpModule(new MyServiceMcp_()) |
| 99 | + * .invoker(new MyCustomMdcInvoker())); // Chains automatically with the Default Exception Mapper |
| 100 | + * } |
| 101 | + * }</pre> |
| 102 | + * |
| 103 | + * <h2>Multiple Servers</h2> |
80 | 104 | * |
81 | | - * <h2>Multiple servers</h2> |
| 105 | + * <p>The generated {@link McpService} instances do not represent servers themselves; they are |
| 106 | + * mapped to specific server instances using the {@code @McpServer("serverKey")} annotation on your |
| 107 | + * original class. |
82 | 108 | * |
83 | | - * <p>To run multiple MCP server instances in the same application, use a @McpServer("calculator") |
84 | | - * annotation: |
| 109 | + * <p>If you route services to multiple, isolated servers, you <b>must</b> define their specific |
| 110 | + * configurations in your {@code application.conf}: |
85 | 111 | * |
86 | 112 | * <pre>{@code |
87 | 113 | * { |
88 | | - * |
89 | | - * install(new JacksonModule()); |
90 | | - * install(new McpModule(new DefaultMcpServer(), new CalculatorMcpServer())); |
| 114 | + * // Jooby will boot two separate MCP servers based on the @McpServer mapping of these services |
| 115 | + * install(new McpModule(new DefaultServiceMcp_(), new CalculatorServiceMcp_())); |
91 | 116 | * } |
92 | 117 | * }</pre> |
93 | 118 | * |
94 | | - * <p>Each instance requires its own configuration block: |
| 119 | + * <p>{@code application.conf}: |
95 | 120 | * |
96 | 121 | * <pre>{@code |
97 | | - * mcp { |
98 | | - * default { |
99 | | - * name: "default-mcp-server" |
100 | | - * version: "1.0.0" |
101 | | - * sseEndpoint: "/mcp/sse" |
102 | | - * messageEndpoint: "/mcp/message" |
103 | | - * } |
104 | | - * calculator { |
105 | | - * name: "calculator-mcp-server" |
106 | | - * version: "1.0.0" |
107 | | - * sseEndpoint: "/mcp/calculator/sse" |
108 | | - * messageEndpoint: "/mcp/calculator/message" |
109 | | - * } |
| 122 | + * mcp.calculator { |
| 123 | + * name: "calculator-mcp-server" |
| 124 | + * version: "1.0.0" |
| 125 | + * transport: "web-socket" |
| 126 | + * mcpEndpoint: "/mcp/calculator/ws" |
110 | 127 | * } |
111 | | - * |
112 | 128 | * }</pre> |
113 | 129 | * |
| 130 | + * <h2>Testing and Debugging</h2> |
| 131 | + * |
| 132 | + * <p>For local development, Jooby provides a built-in UI to test your AI capabilities. Simply |
| 133 | + * install the {@link McpInspectorModule} alongside this module to interactively execute your tools, |
| 134 | + * prompts, and resources straight from your browser. |
| 135 | + * |
114 | 136 | * @author kliushnichenko |
115 | | - * @since 1.0.0 |
| 137 | + * @author edgar |
| 138 | + * @since 4.2.0 |
116 | 139 | */ |
117 | 140 | public class McpModule implements Extension { |
118 | 141 |
|
|
0 commit comments