Skip to content

Commit 9532561

Browse files
committed
fix(mcp): register completions capability and unify generated handlers
This commit fixes an issue where `@McpCompletion` requests were failing with a "-32601 Missing handler" error because the `completions()` capability was omitted from the generated `ServerCapabilities`. It also introduces a major refactor to the APT generation to eliminate duplicate code. Details: * Added `capabilities.completions()` to the generated `capabilities()` method. * Safely stripped lingering AST quotes from `@McpCompletion` annotation values to ensure precise router matching. * Refactored `McpRoute` to generate a single, unified handler method accepting both `McpSyncServerExchange` and `McpTransportContext` alongside the request, dynamically extracting `io.jooby.Context` from the available transport. * Updated `McpRouter` to register tools, prompts, resources, and completions using clean lambda adapters that map the current server type (stateful vs. stateless) to the unified handler.
1 parent dcc65d3 commit 9532561

File tree

15 files changed

+1226
-356
lines changed

15 files changed

+1226
-356
lines changed

modules/jooby-apt/src/main/java/io/jooby/internal/apt/McpRoute.java

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ public List<String> generateMcpDefinitionMethod(boolean kt) {
138138
for (var param : getParameters(true)) {
139139
var type = param.getType().getRawType().toString();
140140
if (type.equals("io.modelcontextprotocol.server.McpSyncServerExchange")
141+
|| type.equals("io.modelcontextprotocol.common.McpTransportContext")
141142
|| type.equals("io.jooby.Context")) continue;
142143

143144
String mcpName = param.getMcpName();
@@ -276,6 +277,7 @@ public List<String> generateMcpDefinitionMethod(boolean kt) {
276277
for (var param : getParameters(true)) {
277278
var type = param.getType().getRawType().toString();
278279
if (type.equals("io.modelcontextprotocol.server.McpSyncServerExchange")
280+
|| type.equals("io.modelcontextprotocol.common.McpTransportContext")
279281
|| type.equals("io.jooby.Context")) continue;
280282

281283
var mcpName = param.getMcpName();
@@ -431,14 +433,16 @@ public List<String> generateMcpHandlerMethod(boolean kt) {
431433
}
432434

433435
List<String> buffer = new ArrayList<>();
436+
String handlerName = getMethodName();
434437

435438
if (kt) {
436439
buffer.add(
437440
statement(
438441
indent(4),
439442
"private fun ",
440-
getMethodName(),
441-
"(exchange: io.modelcontextprotocol.server.McpSyncServerExchange, req:"
443+
handlerName,
444+
"(exchange: io.modelcontextprotocol.server.McpSyncServerExchange?, transportContext:"
445+
+ " io.modelcontextprotocol.common.McpTransportContext?, req:"
442446
+ " io.modelcontextprotocol.spec.McpSchema.",
443447
reqType,
444448
"): io.modelcontextprotocol.spec.McpSchema.",
@@ -448,23 +452,27 @@ public List<String> generateMcpHandlerMethod(boolean kt) {
448452
statement(
449453
indent(6),
450454
"val ctx ="
451-
+ " exchange.transportContext().get<io.jooby.Context>(io.jooby.Context::class.java.name)"));
455+
+ " exchange?.transportContext()?.get<io.jooby.Context>(io.jooby.Context::class.java.name)"
456+
+ " ?: transportContext?.get<io.jooby.Context>(io.jooby.Context::class.java.name)"));
452457
} else {
453458
buffer.add(
454459
statement(
455460
indent(4),
456461
"private io.modelcontextprotocol.spec.McpSchema.",
457462
resType,
458463
" ",
459-
getMethodName(),
464+
handlerName,
460465
"(io.modelcontextprotocol.server.McpSyncServerExchange exchange,"
466+
+ " io.modelcontextprotocol.common.McpTransportContext transportContext,"
461467
+ " io.modelcontextprotocol.spec.McpSchema.",
462468
reqType,
463469
" req) {"));
464470
buffer.add(
465471
statement(
466472
indent(6),
467-
"var ctx = (io.jooby.Context) exchange.transportContext().get(\"CTX\")",
473+
"var ctx = exchange != null ? (io.jooby.Context)"
474+
+ " exchange.transportContext().get(\"CTX\") : (transportContext != null ?"
475+
+ " (io.jooby.Context) transportContext.get(\"CTX\") : null)",
468476
semicolon(kt)));
469477
}
470478

@@ -541,6 +549,24 @@ public List<String> generateMcpHandlerMethod(boolean kt) {
541549
buffer.add(
542550
statement(indent(6), kt ? "val " : "var ", javaName, " = exchange", semicolon(kt)));
543551
continue;
552+
} else if (type.equals("io.modelcontextprotocol.common.McpTransportContext")) {
553+
if (kt) {
554+
buffer.add(
555+
statement(
556+
indent(6),
557+
"val ",
558+
javaName,
559+
" = exchange?.transportContext() ?: transportContext"));
560+
} else {
561+
buffer.add(
562+
statement(
563+
indent(6),
564+
"var ",
565+
javaName,
566+
" = exchange != null ? exchange.transportContext() : transportContext",
567+
semicolon(kt)));
568+
}
569+
continue;
544570
} else if (type.equals("io.modelcontextprotocol.spec.McpSchema." + reqType)) {
545571
buffer.add(statement(indent(6), kt ? "val " : "var ", javaName, " = req", semicolon(kt)));
546572
continue;
@@ -687,7 +713,7 @@ public List<String> generateMcpHandlerMethod(boolean kt) {
687713
semicolon(kt)));
688714
}
689715
}
690-
buffer.add(statement(indent(4), "}\n"));
716+
buffer.add(statement(indent(4), "}", System.lineSeparator()));
691717

692718
return buffer;
693719
}

0 commit comments

Comments
 (0)