This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git

commit 03153783dd76b92149cbd671eb7a105b17d6265b
Author: James Bognar <[email protected]>
AuthorDate: Tue Jul 28 18:08:37 2026 -0400

    refactor: make juneau-rest-server-mcp revision-neutral
    
    Retypes the handler interfaces and McpServerConfig onto the neutral model, 
adds
    the bidirectional neutral/wire boundary in the 2025-06-18 adapter, moves the
    explicit-capabilities override from a core setter to a typed adapter hook, 
and
    drops core's dependency on the revision bean module. Characterization 
fixtures
    replay byte-identical, including the explicit-capabilities initialize 
response.
    
    Note: McpServerConfig.setProtocolVersion had no equivalent hook and is 
removed
    outright, so a v1 endpoint can no longer report a non-2025-06-18 version.
    
    Co-authored-by: Cursor <[email protected]>
---
 .../juneau/rest/server/mcp/McpConfigCore_Test.java | 126 +++++++++++
 .../mcp/v20250618/Mcp20250618Revision_Test.java    |  65 +++---
 .../mcp/v20250618/McpHandlerDefaults_Test.java     |   7 +-
 .../mcp/v20250618/McpRestServlet20250618_Test.java |  18 +-
 .../server/mcp/v20250618/McpServerConfig_Test.java | 137 ------------
 .../mcp/v20250618/McpTypedHandlers_Test.java       |   6 +-
 .../server/mcp/v20250618/Mcp20250618Revision.java  |  27 ++-
 .../rest/server/mcp/v20250618/Mcp20250618Wire.java | 244 +++++++++++++++++++++
 .../server/mcp/v20250618/McpTypedHandlers.java     |  16 +-
 .../mcp/v20250618/Characterization_Test.java       |  61 +++---
 .../mcp/v20250618/Mcp20250618Revision_Test.java    |  65 +++---
 .../mcp/v20250618/McpHandlerDefaults_Test.java     |   7 +-
 .../mcp/v20250618/McpRestServlet20250618_Test.java |  18 +-
 .../server/mcp/v20250618/McpServerConfig_Test.java | 137 ------------
 .../mcp/v20250618/McpTypedHandlers_Test.java       |   6 +-
 juneau-rest/juneau-rest-server-mcp/pom.xml         |   5 -
 .../juneau/rest/server/mcp/McpPromptHandler.java   |  12 +-
 .../juneau/rest/server/mcp/McpResourceHandler.java |  12 +-
 .../juneau/rest/server/mcp/McpRestServlet.java     |   1 -
 .../juneau/rest/server/mcp/McpServerConfig.java    |  75 +++----
 .../juneau/rest/server/mcp/McpToolHandler.java     |  17 +-
 .../juneau/rest/server/mcp/package-info.java       |  15 +-
 .../rest/server/mcp/FakeMcpRevision_Test.java      |  17 +-
 .../juneau/rest/server/mcp/McpConfigCore_Test.java | 126 +++++++++++
 24 files changed, 720 insertions(+), 500 deletions(-)

diff --git 
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/McpConfigCore_Test.java
 
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/McpConfigCore_Test.java
new file mode 100644
index 0000000000..3452f72a78
--- /dev/null
+++ 
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/McpConfigCore_Test.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.juneau.rest.server.mcp;
+
+import static org.apache.juneau.test.bct.BctAssertions.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.*;
+
+import org.apache.juneau.commons.inject.*;
+import org.junit.jupiter.api.*;
+
+/**
+ * Coverage for the revision-neutral {@link McpServerConfig}.
+ */
+class McpConfigCore_Test {
+
+       private static McpToolHandler dummyTool(String name) {
+               return new McpToolHandler() {
+                       @Override public McpToolSpec descriptor() { return new 
McpToolSpec().setName(name); }
+                       @Override public McpToolOutcome call(Map<String,Object> 
arguments, BeanStore ctx) { return new McpToolOutcome(); }
+               };
+       }
+
+       private static McpPromptHandler dummyPrompt(String name) {
+               return new McpPromptHandler() {
+                       @Override public McpPromptSpec descriptor() { return 
new McpPromptSpec().setName(name); }
+                       @Override public McpPromptOutcome 
get(Map<String,Object> arguments, BeanStore ctx) { return new 
McpPromptOutcome(); }
+               };
+       }
+
+       private static McpResourceHandler dummyResource(String uri) {
+               return new McpResourceHandler() {
+                       @Override public McpResourceSpec descriptor() { return 
new McpResourceSpec().setUri(uri); }
+                       @Override public McpResourceOutcome read(String u, 
BeanStore ctx) { return new McpResourceOutcome(); }
+               };
+       }
+
+       @Test
+       void defaults() {
+               var a = new McpServerConfig();
+               assertNull(a.getName());
+               assertNull(a.getVersion());
+               assertNull(a.getInstructions());
+               assertNotNull(a.getTools());
+               assertNotNull(a.getPrompts());
+               assertNotNull(a.getResources());
+               assertSame(McpCursor.SINGLE_PAGE, a.getCursor());
+       }
+
+       @Test
+       void setters_and_addCalls() {
+               var a = new McpServerConfig()
+                       .setName("x")
+                       .setVersion("1")
+                       .setInstructions("hello")
+                       .setCursor(McpCursor.fixedSize(5))
+                       .addTool(dummyTool("t1"), dummyTool("t2"))
+                       .addPrompt(dummyPrompt("p1"))
+                       .addResource(dummyResource("r://a"));
+
+               assertString("x", a.getName());
+               assertString("1", a.getVersion());
+               assertString("hello", a.getInstructions());
+               assertNotSame(McpCursor.SINGLE_PAGE, a.getCursor());
+               assertSize(2, a.getTools());
+               assertSize(1, a.getPrompts());
+               assertSize(1, a.getResources());
+       }
+
+       @Test
+       void setLists_replacingAndNullClears() {
+               var a = new 
McpServerConfig().addTool(dummyTool("t")).addPrompt(dummyPrompt("p")).addResource(dummyResource("r"));
+               a.setTools(null);
+               a.setPrompts(null);
+               a.setResources(null);
+               assertEmpty(a.getTools());
+               assertEmpty(a.getPrompts());
+               assertEmpty(a.getResources());
+
+               a.setTools(List.of(dummyTool("a")));
+               a.setPrompts(List.of(dummyPrompt("a")));
+               a.setResources(List.of(dummyResource("a")));
+               assertSize(1, a.getTools());
+               assertSize(1, a.getPrompts());
+               assertSize(1, a.getResources());
+       }
+
+       @Test
+       void setCursor_nullResets() {
+               var a = new McpServerConfig().setCursor(McpCursor.fixedSize(2));
+               a.setCursor(null);
+               assertSame(McpCursor.SINGLE_PAGE, a.getCursor());
+       }
+
+       @Test
+       void noRevisionSpecificSurfaceRemains() {
+               var m = 
Arrays.stream(McpServerConfig.class.getMethods()).map(java.lang.reflect.Method::getName).toList();
+               assertFalse(m.contains("getCapabilities"), "capabilities are 
revision-owned; core must hold none");
+               assertFalse(m.contains("setCapabilities"), "capabilities are 
revision-owned; core must hold none");
+               assertFalse(m.contains("getProtocolVersion"), "the protocol 
version is owned by McpRevision.protocolVersion()");
+               assertFalse(m.contains("setProtocolVersion"), "the protocol 
version is owned by McpRevision.protocolVersion()");
+               assertFalse(m.contains("getServerInfo"), "server identity is 
plain name/version on the neutral config");
+       }
+
+       @Test
+       void nullListElementsAreDistinctFromEmpty() {
+               assertNull(new McpToolOutcome().getContent());
+               assertNull(new McpPromptOutcome().getMessages());
+               assertNull(new McpResourceOutcome().getContents());
+       }
+}
diff --git 
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/Mcp20250618Revision_Test.java
 
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/Mcp20250618Revision_Test.java
index 5deec891fa..1db6ef9aa4 100644
--- 
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/Mcp20250618Revision_Test.java
+++ 
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/Mcp20250618Revision_Test.java
@@ -35,43 +35,43 @@ class Mcp20250618Revision_Test {
 
        private final BeanStore ctx = new BasicBeanStore();
 
-       private static McpToolHandler tool(String name, 
java.util.function.Function<Map<String,Object>,CallToolResult> fn) {
+       private static McpToolHandler tool(String name, 
java.util.function.Function<Map<String,Object>,McpToolOutcome> fn) {
                return new McpToolHandler() {
                        @Override
-                       public Tool descriptor() {
-                               return new 
Tool().setName(name).setDescription("desc:" + name);
+                       public McpToolSpec descriptor() {
+                               return new 
McpToolSpec().setName(name).setDescription("desc:" + name);
                        }
 
                        @Override
-                       public CallToolResult call(Map<String,Object> 
arguments, BeanStore ctx) {
+                       public McpToolOutcome call(Map<String,Object> 
arguments, BeanStore ctx) {
                                return fn.apply(arguments);
                        }
                };
        }
 
-       private static McpPromptHandler prompt(String name, 
java.util.function.Function<Map<String,Object>,GetPromptResult> fn) {
+       private static McpPromptHandler prompt(String name, 
java.util.function.Function<Map<String,Object>,McpPromptOutcome> fn) {
                return new McpPromptHandler() {
                        @Override
-                       public Prompt descriptor() {
-                               return new Prompt().setName(name);
+                       public McpPromptSpec descriptor() {
+                               return new McpPromptSpec().setName(name);
                        }
 
                        @Override
-                       public GetPromptResult get(Map<String,Object> 
arguments, BeanStore ctx) {
+                       public McpPromptOutcome get(Map<String,Object> 
arguments, BeanStore ctx) {
                                return fn.apply(arguments);
                        }
                };
        }
 
-       private static McpResourceHandler resource(String uri, 
java.util.function.Function<String,ReadResourceResult> fn) {
+       private static McpResourceHandler resource(String uri, 
java.util.function.Function<String,McpResourceOutcome> fn) {
                return new McpResourceHandler() {
                        @Override
-                       public Resource descriptor() {
-                               return new 
Resource().setUri(uri).setName("res");
+                       public McpResourceSpec descriptor() {
+                               return new 
McpResourceSpec().setUri(uri).setName("res");
                        }
 
                        @Override
-                       public ReadResourceResult read(String u, BeanStore ctx) 
{
+                       public McpResourceOutcome read(String u, BeanStore ctx) 
{
                                return fn.apply(u);
                        }
                };
@@ -88,9 +88,9 @@ class Mcp20250618Revision_Test {
        @Test
        void initialize_default_capabilities() {
                var config = new McpServerConfig()
-                       .addTool(tool("a", a -> new CallToolResult()))
-                       .addPrompt(prompt("p", a -> new GetPromptResult()))
-                       .addResource(resource("r://x", u -> new 
ReadResourceResult()));
+                       .addTool(tool("a", a -> new McpToolOutcome()))
+                       .addPrompt(prompt("p", a -> new McpPromptOutcome()))
+                       .addResource(resource("r://x", u -> new 
McpResourceOutcome()));
 
                var resp = send(config, req(1, McpMethods.INITIALIZE, null));
                assertNotNull(resp);
@@ -103,14 +103,11 @@ class Mcp20250618Revision_Test {
        }
 
        @Test
-       void initialize_explicit_capabilitiesAndServerInfo() {
-               var caps = new ServerCapabilities().setLogging(new 
LoggingCapability());
-               var info = new 
Implementation().setName("custom").setVersion("9.9");
-               var config = new 
McpServerConfig().setCapabilities(caps).setServerInfo(info).setInstructions("hi");
+       void initialize_explicitServerInfoAndInstructions() {
+               var config = new 
McpServerConfig().setName("custom").setVersion("9.9").setInstructions("hi");
                var resp = send(config, req(1, McpMethods.INITIALIZE, null));
                var result = (InitializeResult) resp.getResult();
-               assertSame(caps, result.getCapabilities());
-               assertSame(info, result.getServerInfo());
+               assertBean(result.getServerInfo(), "name,version", 
"custom,9.9");
                assertString("hi", result.getInstructions());
        }
 
@@ -166,7 +163,7 @@ class Mcp20250618Revision_Test {
 
        @Test
        void notification_returnsNullResponse() {
-               var config = new McpServerConfig().addTool(tool("a", args -> 
new CallToolResult()));
+               var config = new McpServerConfig().addTool(tool("a", args -> 
new McpToolOutcome()));
                var notif = req(null, McpMethods.TOOLS_CALL, JsonMap.of("name", 
"a"));
                assertNull(send(config, notif));
        }
@@ -192,8 +189,8 @@ class Mcp20250618Revision_Test {
        @Test
        void tools_list_singlePage() {
                var config = new McpServerConfig()
-                       .addTool(tool("a", args -> new CallToolResult()))
-                       .addTool(tool("b", args -> new CallToolResult()));
+                       .addTool(tool("a", args -> new McpToolOutcome()))
+                       .addTool(tool("b", args -> new McpToolOutcome()));
                var resp = send(config, req(1, McpMethods.TOOLS_LIST, null));
                var result = (ListToolsResult) resp.getResult();
                assertSize(2, result.getTools());
@@ -203,8 +200,8 @@ class Mcp20250618Revision_Test {
        @Test
        void tools_list_paged() {
                var config = new 
McpServerConfig().setCursor(McpCursor.fixedSize(1))
-                       .addTool(tool("a", args -> new CallToolResult()))
-                       .addTool(tool("b", args -> new CallToolResult()));
+                       .addTool(tool("a", args -> new McpToolOutcome()))
+                       .addTool(tool("b", args -> new McpToolOutcome()));
                var first = (ListToolsResult) send(config, req(1, 
McpMethods.TOOLS_LIST, null)).getResult();
                assertSize(1, first.getTools());
                assertString("1", first.getNextCursor());
@@ -218,9 +215,9 @@ class Mcp20250618Revision_Test {
        @Test
        void tools_call_routes_byName() {
                var config = new McpServerConfig().addTool(tool("echo", args -> 
{
-                       var ctr = new CallToolResult();
-                       ctr.setContent(List.of(new 
TextContent().setText(String.valueOf(args.get("text")))));
-                       return ctr;
+                       var outcome = new McpToolOutcome();
+                       
outcome.setContent(List.of(McpContentBlock.text(String.valueOf(args.get("text")))));
+                       return outcome;
                }));
                var resp = send(config, req(1, McpMethods.TOOLS_CALL, 
JsonMap.of("name", "echo", "arguments", JsonMap.of("text", "hi"))));
                var ctr = (CallToolResult) resp.getResult();
@@ -241,14 +238,14 @@ class Mcp20250618Revision_Test {
 
        @Test
        void tools_call_argumentsNotObject_throwsInvalidParams() {
-               var config = new McpServerConfig().addTool(tool("e", a -> new 
CallToolResult()));
+               var config = new McpServerConfig().addTool(tool("e", a -> new 
McpToolOutcome()));
                var resp = send(config, req(1, McpMethods.TOOLS_CALL, 
JsonMap.of("name", "e", "arguments", "string-not-map")));
                assertEquals(Mcp20250618Revision.CODE_INVALID_PARAMS, 
resp.getError().getCode());
        }
 
        @Test
        void tools_call_paramsNotMap_invalidParams() {
-               var config = new McpServerConfig().addTool(tool("e", a -> new 
CallToolResult()));
+               var config = new McpServerConfig().addTool(tool("e", a -> new 
McpToolOutcome()));
                var resp = send(config, req(1, McpMethods.TOOLS_CALL, 
"not-a-map"));
                assertEquals(Mcp20250618Revision.CODE_INVALID_PARAMS, 
resp.getError().getCode());
        }
@@ -288,7 +285,7 @@ class Mcp20250618Revision_Test {
 
        @Test
        void prompts_list_and_get() {
-               var config = new McpServerConfig().addPrompt(prompt("p", args 
-> new GetPromptResult().setDescription("ok")));
+               var config = new McpServerConfig().addPrompt(prompt("p", args 
-> new McpPromptOutcome().setDescription("ok")));
                var list = (ListPromptsResult) send(config, req(1, 
McpMethods.PROMPTS_LIST, null)).getResult();
                assertSize(1, list.getPrompts());
                var get = (GetPromptResult) send(config, req(1, 
McpMethods.PROMPTS_GET, JsonMap.of("name", "p"))).getResult();
@@ -311,7 +308,7 @@ class Mcp20250618Revision_Test {
 
        @Test
        void resources_list_and_read() {
-               var config = new 
McpServerConfig().addResource(resource("file://a", uri -> new 
ReadResourceResult().setContents(List.of(new 
TextResourceContents().setUri(uri).setText("ok")))));
+               var config = new 
McpServerConfig().addResource(resource("file://a", uri -> new 
McpResourceOutcome().setContents(List.of(McpResourceContents.text(uri, null, 
"ok")))));
                var list = (ListResourcesResult) send(config, req(1, 
McpMethods.RESOURCES_LIST, null)).getResult();
                assertSize(1, list.getResources());
                var read = (ReadResourceResult) send(config, req(1, 
McpMethods.RESOURCES_READ, JsonMap.of("uri", "file://a"))).getResult();
@@ -334,7 +331,7 @@ class Mcp20250618Revision_Test {
 
        @Test
        void cursor_paramsAreOptional() {
-               var config = new 
McpServerConfig().setCursor(McpCursor.fixedSize(1)).addPrompt(prompt("a", args 
-> new GetPromptResult())).addPrompt(prompt("b", args -> new 
GetPromptResult()));
+               var config = new 
McpServerConfig().setCursor(McpCursor.fixedSize(1)).addPrompt(prompt("a", args 
-> new McpPromptOutcome())).addPrompt(prompt("b", args -> new 
McpPromptOutcome()));
                // params null
                var resp = (ListPromptsResult) send(config, req(1, 
McpMethods.PROMPTS_LIST, null)).getResult();
                assertSize(1, resp.getPrompts());
diff --git 
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpHandlerDefaults_Test.java
 
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpHandlerDefaults_Test.java
index 55b78d910e..d7400d8d86 100644
--- 
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpHandlerDefaults_Test.java
+++ 
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpHandlerDefaults_Test.java
@@ -19,7 +19,6 @@ package org.apache.juneau.rest.server.mcp.v20250618;
 import static org.apache.juneau.test.bct.BctAssertions.*;
 import static org.junit.jupiter.api.Assertions.*;
 
-import org.apache.juneau.bean.mcp.v20250618.*;
 import org.apache.juneau.commons.inject.*;
 import org.apache.juneau.rest.server.mcp.*;
 import org.junit.jupiter.api.*;
@@ -32,19 +31,19 @@ class McpHandlerDefaults_Test {
 
        @Test
        void toolHandler_defaultDescriptor_throws() {
-               McpToolHandler h = (args, ctx) -> new CallToolResult();
+               McpToolHandler h = (args, ctx) -> new McpToolOutcome();
                assertThrows(UnsupportedOperationException.class, 
h::descriptor);
        }
 
        @Test
        void promptHandler_defaultDescriptor_throws() {
-               McpPromptHandler h = (args, ctx) -> new GetPromptResult();
+               McpPromptHandler h = (args, ctx) -> new McpPromptOutcome();
                assertThrows(UnsupportedOperationException.class, 
h::descriptor);
        }
 
        @Test
        void resourceHandler_defaultDescriptor_throws() {
-               McpResourceHandler h = (uri, ctx) -> new ReadResourceResult();
+               McpResourceHandler h = (uri, ctx) -> new McpResourceOutcome();
                assertThrows(UnsupportedOperationException.class, 
h::descriptor);
        }
 
diff --git 
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpRestServlet20250618_Test.java
 
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpRestServlet20250618_Test.java
index ca289b1eaf..12c54c1b34 100644
--- 
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpRestServlet20250618_Test.java
+++ 
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpRestServlet20250618_Test.java
@@ -51,18 +51,16 @@ class McpRestServlet20250618_Test extends TestBase {
                @Override
                protected McpServerConfig createMcpConfig() {
                        return new McpServerConfig()
-                               .setServerInfo(new 
Implementation().setName("test").setVersion("1.0.0"))
+                               .setName("test").setVersion("1.0.0")
                                .addTool(new McpToolHandler() {
                                        @Override
-                                       public Tool descriptor() {
-                                               return new 
Tool().setName("echo").setDescription("Echoes back");
+                                       public McpToolSpec descriptor() {
+                                               return new 
McpToolSpec().setName("echo").setDescription("Echoes back");
                                        }
 
                                        @Override
-                                       public CallToolResult 
call(Map<String,Object> arguments, BeanStore ctx) {
-                                               var ctr = new CallToolResult();
-                                               ctr.setContent(List.of(new 
TextContent().setText(String.valueOf(arguments.get("text")))));
-                                               return ctr;
+                                       public McpToolOutcome 
call(Map<String,Object> arguments, BeanStore ctx) {
+                                               return 
McpToolOutcome.text(String.valueOf(arguments.get("text")));
                                        }
                                });
                }
@@ -123,11 +121,11 @@ class McpRestServlet20250618_Test extends TestBase {
                public McpServerConfig getMcpConfig() {
                        return new McpServerConfig().addTool(new 
McpToolHandler() {
                                @Override
-                               public Tool descriptor() { return new 
Tool().setName("ping"); }
+                               public McpToolSpec descriptor() { return new 
McpToolSpec().setName("ping"); }
 
                                @Override
-                               public CallToolResult call(Map<String,Object> 
arguments, BeanStore ctx) {
-                                       return new 
CallToolResult().setContent(List.of(new TextContent().setText("pong")));
+                               public McpToolOutcome call(Map<String,Object> 
arguments, BeanStore ctx) {
+                                       return McpToolOutcome.text("pong");
                                }
                        });
                }
diff --git 
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpServerConfig_Test.java
 
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpServerConfig_Test.java
deleted file mode 100644
index 155c7798a7..0000000000
--- 
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpServerConfig_Test.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.juneau.rest.server.mcp.v20250618;
-
-import static org.apache.juneau.test.bct.BctAssertions.*;
-import static org.junit.jupiter.api.Assertions.*;
-
-import java.util.*;
-
-import org.apache.juneau.bean.mcp.v20250618.*;
-import org.apache.juneau.commons.inject.*;
-import org.apache.juneau.rest.server.mcp.*;
-import org.junit.jupiter.api.*;
-
-/**
- * Coverage for {@link McpServerConfig}.
- */
-class McpServerConfig_Test {
-
-       private static McpToolHandler dummyTool(String name) {
-               return new McpToolHandler() {
-                       @Override
-                       public Tool descriptor() {
-                               return new Tool().setName(name);
-                       }
-
-                       @Override
-                       public CallToolResult call(Map<String,Object> 
arguments, BeanStore ctx) {
-                               return new CallToolResult();
-                       }
-               };
-       }
-
-       private static McpPromptHandler dummyPrompt(String name) {
-               return new McpPromptHandler() {
-                       @Override
-                       public Prompt descriptor() {
-                               return new Prompt().setName(name);
-                       }
-
-                       @Override
-                       public GetPromptResult get(Map<String,Object> 
arguments, BeanStore ctx) {
-                               return new GetPromptResult();
-                       }
-               };
-       }
-
-       private static McpResourceHandler dummyResource(String uri) {
-               return new McpResourceHandler() {
-                       @Override
-                       public Resource descriptor() {
-                               return new Resource().setUri(uri);
-                       }
-
-                       @Override
-                       public ReadResourceResult read(String u, BeanStore ctx) 
{
-                               return new ReadResourceResult();
-                       }
-               };
-       }
-
-       @Test
-       void defaults() {
-               var c = new McpServerConfig();
-               assertNull(c.getServerInfo());
-               assertString(McpProtocol.VERSION_2025_06_18, 
c.getProtocolVersion());
-               assertNull(c.getInstructions());
-               assertNotNull(c.getTools());
-               assertNotNull(c.getPrompts());
-               assertNotNull(c.getResources());
-               assertNull(c.getCapabilities());
-               assertSame(McpCursor.SINGLE_PAGE, c.getCursor());
-       }
-
-       @Test
-       void setters_and_addCalls() {
-               var info = new Implementation().setName("x").setVersion("1");
-               var caps = new ServerCapabilities().setLogging(new 
LoggingCapability());
-               var c = new McpServerConfig()
-                       .setServerInfo(info)
-                       .setProtocolVersion("2024-11-05")
-                       .setInstructions("hello")
-                       .setCapabilities(caps)
-                       .setCursor(McpCursor.fixedSize(5))
-                       .addTool(dummyTool("t1"), dummyTool("t2"))
-                       .addPrompt(dummyPrompt("p1"))
-                       .addResource(dummyResource("r://a"));
-
-               assertSame(info, c.getServerInfo());
-               assertString("2024-11-05", c.getProtocolVersion());
-               assertString("hello", c.getInstructions());
-               assertSame(caps, c.getCapabilities());
-               assertNotSame(McpCursor.SINGLE_PAGE, c.getCursor());
-               assertSize(2, c.getTools());
-               assertSize(1, c.getPrompts());
-               assertSize(1, c.getResources());
-       }
-
-       @Test
-       void setLists_replacingAndNullClears() {
-               var c = new 
McpServerConfig().addTool(dummyTool("t")).addPrompt(dummyPrompt("p")).addResource(dummyResource("r"));
-               c.setTools(null);
-               c.setPrompts(null);
-               c.setResources(null);
-               assertEmpty(c.getTools());
-               assertEmpty(c.getPrompts());
-               assertEmpty(c.getResources());
-
-               c.setTools(List.of(dummyTool("a")));
-               c.setPrompts(List.of(dummyPrompt("a")));
-               c.setResources(List.of(dummyResource("a")));
-               assertSize(1, c.getTools());
-               assertSize(1, c.getPrompts());
-               assertSize(1, c.getResources());
-       }
-
-       @Test
-       void setCursor_nullResets() {
-               var c = new McpServerConfig().setCursor(McpCursor.fixedSize(2));
-               c.setCursor(null);
-               assertSame(McpCursor.SINGLE_PAGE, c.getCursor());
-       }
-}
diff --git 
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpTypedHandlers_Test.java
 
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpTypedHandlers_Test.java
index 72fcf1da66..aec3ccc06d 100644
--- 
a/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpTypedHandlers_Test.java
+++ 
b/juneau-integration-tests/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpTypedHandlers_Test.java
@@ -115,7 +115,9 @@ class McpTypedHandlers_Test {
                        .setMethod(McpMethods.TOOLS_CALL)
                        .setParams(JsonMap.of("name", "d"));
                var resp = dispatch(req, config);
-               assertSame(ctr, resp.getResult());
+               // The neutral/wire boundary always remaps the result, so only 
value equality survives here.
+               var result = (CallToolResult) resp.getResult();
+               assertString("direct", ((TextContent) 
result.getContent().get(0)).getText());
        }
 
        @Test
@@ -234,7 +236,7 @@ class McpTypedHandlers_Test {
                };
                var raw = McpTypedHandlers.adaptTool(typed);
                var ctr = raw.call(null, ctx);
-               assertString("null", ((TextContent) 
ctr.getContent().get(0)).getText());
+               assertString("null", ctr.getContent().get(0).text());
        }
 
        @Test
diff --git 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/main/java/org/apache/juneau/rest/server/mcp/v20250618/Mcp20250618Revision.java
 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/main/java/org/apache/juneau/rest/server/mcp/v20250618/Mcp20250618Revision.java
index 09da0a545c..128e7a0f6e 100644
--- 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/main/java/org/apache/juneau/rest/server/mcp/v20250618/Mcp20250618Revision.java
+++ 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/main/java/org/apache/juneau/rest/server/mcp/v20250618/Mcp20250618Revision.java
@@ -152,7 +152,7 @@ public final class Mcp20250618Revision implements 
McpRevision {
        }
 
        private InitializeResult initialize(McpServerConfig config) {
-               var caps = config.getCapabilities();
+               var caps = this.capabilities;
                if (caps == null) {
                        caps = new ServerCapabilities();
                        if (! config.getTools().isEmpty())
@@ -162,20 +162,19 @@ public final class Mcp20250618Revision implements 
McpRevision {
                        if (! config.getResources().isEmpty())
                                caps.setResources(new ResourceCapability());
                }
-               var info = config.getServerInfo();
-               if (info == null)
-                       info = new 
Implementation().setName(DEFAULT_SERVER_NAME).setVersion("unknown");
                return new InitializeResult()
-                       .setProtocolVersion(config.getProtocolVersion())
+                       .setProtocolVersion(protocolVersion())
                        .setCapabilities(caps)
-                       .setServerInfo(info)
+                       .setServerInfo(Mcp20250618Wire.serverInfo(config))
                        .setInstructions(config.getInstructions());
        }
 
        private static ListToolsResult listTools(McpServerConfig config, Object 
params, BeanStore ctx) {
                var descriptors = 
config.getTools().stream().map(McpToolHandler::descriptor).toList();
                var page = config.getCursor().page(descriptors, 
McpCursor.cursorOf(params), ctx);
-               return new 
ListToolsResult().setTools(page.items()).setNextCursor(page.nextCursor());
+               return new ListToolsResult()
+                       
.setTools(page.items().stream().map(Mcp20250618Wire::toWire).toList())
+                       .setNextCursor(page.nextCursor());
        }
 
        private CallToolResult callTool(McpServerConfig config, Object params, 
BeanStore ctx) {
@@ -188,13 +187,15 @@ public final class Mcp20250618Revision implements 
McpRevision {
                        .findFirst()
                        .orElseThrow(() -> new 
McpException(errorCode(McpErrorKind.TOOL_NOT_FOUND), "Tool not found: " + 
name));
                var args = McpParamUtils.mapParam(p, "arguments");
-               return handler.call(args, ctx);
+               return Mcp20250618Wire.toWire(handler.call(args, ctx));
        }
 
        private static ListPromptsResult listPrompts(McpServerConfig config, 
Object params, BeanStore ctx) {
                var descriptors = 
config.getPrompts().stream().map(McpPromptHandler::descriptor).toList();
                var page = config.getCursor().page(descriptors, 
McpCursor.cursorOf(params), ctx);
-               return new 
ListPromptsResult().setPrompts(page.items()).setNextCursor(page.nextCursor());
+               return new ListPromptsResult()
+                       
.setPrompts(page.items().stream().map(Mcp20250618Wire::toWire).toList())
+                       .setNextCursor(page.nextCursor());
        }
 
        private GetPromptResult getPrompt(McpServerConfig config, Object 
params, BeanStore ctx) {
@@ -207,13 +208,15 @@ public final class Mcp20250618Revision implements 
McpRevision {
                        .findFirst()
                        .orElseThrow(() -> new 
McpException(errorCode(McpErrorKind.PROMPT_NOT_FOUND), "Prompt not found: " + 
name));
                var args = McpParamUtils.mapParam(p, "arguments");
-               return handler.get(args, ctx);
+               return Mcp20250618Wire.toWire(handler.get(args, ctx));
        }
 
        private static ListResourcesResult listResources(McpServerConfig 
config, Object params, BeanStore ctx) {
                var descriptors = 
config.getResources().stream().map(McpResourceHandler::descriptor).toList();
                var page = config.getCursor().page(descriptors, 
McpCursor.cursorOf(params), ctx);
-               return new 
ListResourcesResult().setResources(page.items()).setNextCursor(page.nextCursor());
+               return new ListResourcesResult()
+                       
.setResources(page.items().stream().map(Mcp20250618Wire::toWire).toList())
+                       .setNextCursor(page.nextCursor());
        }
 
        private ReadResourceResult readResource(McpServerConfig config, Object 
params, BeanStore ctx) {
@@ -225,6 +228,6 @@ public final class Mcp20250618Revision implements 
McpRevision {
                        .filter(h -> uri.equals(h.descriptor().getUri()))
                        .findFirst()
                        .orElseThrow(() -> new 
McpException(errorCode(McpErrorKind.RESOURCE_NOT_FOUND), "Resource not found: " 
+ uri));
-               return handler.read(uri, ctx);
+               return Mcp20250618Wire.toWire(handler.read(uri, ctx));
        }
 }
diff --git 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/main/java/org/apache/juneau/rest/server/mcp/v20250618/Mcp20250618Wire.java
 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/main/java/org/apache/juneau/rest/server/mcp/v20250618/Mcp20250618Wire.java
new file mode 100644
index 0000000000..9b7b4aac4e
--- /dev/null
+++ 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/main/java/org/apache/juneau/rest/server/mcp/v20250618/Mcp20250618Wire.java
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.juneau.rest.server.mcp.v20250618;
+
+import java.util.*;
+
+import org.apache.juneau.bean.jsonrpc.*;
+import org.apache.juneau.bean.mcp.v20250618.*;
+import org.apache.juneau.marshall.collections.*;
+import org.apache.juneau.marshall.marshaller.*;
+import org.apache.juneau.rest.server.mcp.*;
+
+/**
+ * Mapping between the revision-neutral model and the {@code 2025-06-18} wire 
beans.
+ *
+ * <p>
+ * The mapping runs in both directions. Neutral-to-wire is the request path: 
what a handler returns
+ * becomes what a client receives. Wire-to-neutral is needed because {@link 
McpTypedHandlers} accepts
+ * user handlers written against this revision's wire beans and must adapt 
them to the neutral
+ * handler interfaces the core registry holds.
+ *
+ * <p>
+ * <b>{@code null} is preserved as {@code null} throughout.</b> Juneau omits 
null bean properties, so
+ * normalizing a null collection to an empty one would add a property to the 
wire output. An empty
+ * {@code CallToolResult} must keep serializing as <c>{}</c>.
+ */
+final class Mcp20250618Wire {
+
+       private Mcp20250618Wire() {}
+
+       // --- neutral -> wire 
-------------------------------------------------------------------
+
+       static Tool toWire(McpToolSpec x) {
+               if (x == null)
+                       return null;
+               return new Tool()
+                       .setName(x.getName())
+                       .setDescription(x.getDescription())
+                       .setInputSchema(toWire(x.getInputSchema()));
+       }
+
+       static JsonSchema toWire(McpSchema x) {
+               return x == null ? null : Json.to(Json.of(x.toJsonMap()), 
JsonSchema.class);
+       }
+
+       static CallToolResult toWire(McpToolOutcome x) {
+               if (x == null)
+                       return null;
+               var r = new CallToolResult().setIsError(x.getError());
+               if (x.getContent() != null)
+                       
r.setContent(x.getContent().stream().map(Mcp20250618Wire::toWire).toList());
+               return r;
+       }
+
+       static Content toWire(McpContentBlock x) {
+               if (x == null)
+                       return null;
+               return switch (x.kind()) {
+                       case TEXT -> new TextContent().setText(x.text());
+                       case IMAGE -> new 
ImageContent().setData(x.data()).setMimeType(x.mimeType());
+                       case RESOURCE -> new 
EmbeddedResourceContent().setResource(toWire(x.resource()));
+               };
+       }
+
+       static ResourceContents toWire(McpResourceContents x) {
+               if (x == null)
+                       return null;
+               return switch (x.kind()) {
+                       case TEXT -> new 
TextResourceContents().setUri(x.uri()).setMimeType(x.mimeType()).setText(x.text());
+                       case BLOB -> new 
BlobResourceContents().setUri(x.uri()).setMimeType(x.mimeType()).setBlob(x.blob());
+               };
+       }
+
+       static Prompt toWire(McpPromptSpec x) {
+               if (x == null)
+                       return null;
+               var r = new 
Prompt().setName(x.getName()).setDescription(x.getDescription());
+               if (x.getArguments() != null)
+                       
r.setArguments(x.getArguments().stream().map(Mcp20250618Wire::toWire).toList());
+               return r;
+       }
+
+       static PromptArgument toWire(McpPromptArgument x) {
+               if (x == null)
+                       return null;
+               return new 
PromptArgument().setName(x.getName()).setDescription(x.getDescription()).setRequired(x.getRequired());
+       }
+
+       static GetPromptResult toWire(McpPromptOutcome x) {
+               if (x == null)
+                       return null;
+               var r = new 
GetPromptResult().setDescription(x.getDescription());
+               if (x.getMessages() != null)
+                       
r.setMessages(x.getMessages().stream().map(Mcp20250618Wire::toWire).toList());
+               return r;
+       }
+
+       static PromptMessage toWire(McpPromptMessage x) {
+               if (x == null)
+                       return null;
+               return new 
PromptMessage().setRole(toWire(x.getRole())).setContent(toWire(x.getContent()));
+       }
+
+       static Role toWire(McpRole x) {
+               if (x == null)
+                       return null;
+               return switch (x) {
+                       case USER -> Role.USER;
+                       case ASSISTANT -> Role.ASSISTANT;
+                       case SYSTEM -> Role.SYSTEM;
+                       case TOOL -> Role.TOOL;
+               };
+       }
+
+       static Resource toWire(McpResourceSpec x) {
+               if (x == null)
+                       return null;
+               return new Resource()
+                       .setUri(x.getUri())
+                       .setName(x.getName())
+                       .setTitle(x.getTitle())
+                       .setDescription(x.getDescription())
+                       .setMimeType(x.getMimeType())
+                       .setSize(x.getSize());
+       }
+
+       static ReadResourceResult toWire(McpResourceOutcome x) {
+               if (x == null)
+                       return null;
+               var r = new ReadResourceResult();
+               if (x.getContents() != null)
+                       
r.setContents(x.getContents().stream().map(Mcp20250618Wire::toWire).toList());
+               return r;
+       }
+
+       static Implementation serverInfo(McpServerConfig config) {
+               if (config.getName() == null && config.getVersion() == null)
+                       return new Implementation()
+                               
.setName(Mcp20250618Revision.DEFAULT_SERVER_NAME)
+                               .setVersion("unknown");
+               return new 
Implementation().setName(config.getName()).setVersion(config.getVersion());
+       }
+
+       // --- wire -> neutral 
-------------------------------------------------------------------
+
+       static McpToolSpec toNeutral(Tool x) {
+               if (x == null)
+                       return null;
+               return new McpToolSpec()
+                       .setName(x.getName())
+                       .setDescription(x.getDescription())
+                       .setInputSchema(toNeutral(x.getInputSchema()));
+       }
+
+       static McpSchema toNeutral(JsonSchema x) {
+               return x == null ? null : McpSchema.of(Json.to(Json.of(x), 
JsonMap.class));
+       }
+
+       static McpToolOutcome toNeutral(CallToolResult x) {
+               if (x == null)
+                       return null;
+               var r = new McpToolOutcome().setError(x.getIsError());
+               if (x.getContent() != null)
+                       
r.setContent(x.getContent().stream().map(Mcp20250618Wire::toNeutral).toList());
+               return r;
+       }
+
+       static McpContentBlock toNeutral(Content x) {
+               if (x == null)
+                       return null;
+               if (x instanceof TextContent x2)
+                       return McpContentBlock.text(x2.getText());
+               if (x instanceof ImageContent x2)
+                       return McpContentBlock.image(x2.getData(), 
x2.getMimeType());
+               if (x instanceof EmbeddedResourceContent x2)
+                       return 
McpContentBlock.resource(toNeutral(x2.getResource()));
+               throw new McpException(Mcp20250618Revision.CODE_INTERNAL_ERROR, 
"Unsupported content type: " + x.getClass().getName());
+       }
+
+       static McpResourceContents toNeutral(ResourceContents x) {
+               if (x == null)
+                       return null;
+               if (x instanceof TextResourceContents x2)
+                       return McpResourceContents.text(x2.getUri(), 
x2.getMimeType(), x2.getText());
+               if (x instanceof BlobResourceContents x2)
+                       return McpResourceContents.blob(x2.getUri(), 
x2.getMimeType(), x2.getBlob());
+               throw new McpException(Mcp20250618Revision.CODE_INTERNAL_ERROR, 
"Unsupported resource contents type: " + x.getClass().getName());
+       }
+
+       static McpPromptSpec toNeutral(Prompt x) {
+               if (x == null)
+                       return null;
+               var r = new 
McpPromptSpec().setName(x.getName()).setDescription(x.getDescription());
+               if (x.getArguments() != null)
+                       
r.setArguments(x.getArguments().stream().map(Mcp20250618Wire::toNeutral).toList());
+               return r;
+       }
+
+       static McpPromptArgument toNeutral(PromptArgument x) {
+               if (x == null)
+                       return null;
+               return new 
McpPromptArgument().setName(x.getName()).setDescription(x.getDescription()).setRequired(x.getRequired());
+       }
+
+       static McpPromptOutcome toNeutral(GetPromptResult x) {
+               if (x == null)
+                       return null;
+               var r = new 
McpPromptOutcome().setDescription(x.getDescription());
+               if (x.getMessages() != null)
+                       
r.setMessages(x.getMessages().stream().map(Mcp20250618Wire::toNeutral).toList());
+               return r;
+       }
+
+       static McpPromptMessage toNeutral(PromptMessage x) {
+               if (x == null)
+                       return null;
+               return new 
McpPromptMessage().setRole(toNeutral(x.getRole())).setContent(toNeutral(x.getContent()));
+       }
+
+       static McpRole toNeutral(Role x) {
+               if (x == null)
+                       return null;
+               return switch (x) {
+                       case USER -> McpRole.USER;
+                       case ASSISTANT -> McpRole.ASSISTANT;
+                       case SYSTEM -> McpRole.SYSTEM;
+                       case TOOL -> McpRole.TOOL;
+               };
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/main/java/org/apache/juneau/rest/server/mcp/v20250618/McpTypedHandlers.java
 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/main/java/org/apache/juneau/rest/server/mcp/v20250618/McpTypedHandlers.java
index 1d24b73a35..e043dd5eff 100644
--- 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/main/java/org/apache/juneau/rest/server/mcp/v20250618/McpTypedHandlers.java
+++ 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/main/java/org/apache/juneau/rest/server/mcp/v20250618/McpTypedHandlers.java
@@ -56,15 +56,15 @@ public final class McpTypedHandlers {
                assertArgNotNull("typed", typed);
                return new McpToolHandler() {
                        @Override
-                       public Tool descriptor() {
-                               return typed.descriptor();
+                       public McpToolSpec descriptor() {
+                               return 
Mcp20250618Wire.toNeutral(typed.descriptor());
                        }
 
                        @Override
-                       public CallToolResult call(Map<String,Object> 
arguments, BeanStore ctx) {
+                       public McpToolOutcome call(Map<String,Object> 
arguments, BeanStore ctx) {
                                A bound = bindArguments(arguments, 
typed.argumentType());
                                R result = typed.call(bound, ctx);
-                               return wrapToolResult(result);
+                               return 
Mcp20250618Wire.toNeutral(wrapToolResult(result));
                        }
                };
        }
@@ -84,14 +84,14 @@ public final class McpTypedHandlers {
                assertArgNotNull("typed", typed);
                return new McpPromptHandler() {
                        @Override
-                       public Prompt descriptor() {
-                               return typed.descriptor();
+                       public McpPromptSpec descriptor() {
+                               return 
Mcp20250618Wire.toNeutral(typed.descriptor());
                        }
 
                        @Override
-                       public GetPromptResult get(Map<String,Object> 
arguments, BeanStore ctx) {
+                       public McpPromptOutcome get(Map<String,Object> 
arguments, BeanStore ctx) {
                                A bound = bindArguments(arguments, 
typed.argumentType());
-                               return typed.get(bound, ctx);
+                               return 
Mcp20250618Wire.toNeutral(typed.get(bound, ctx));
                        }
                };
        }
diff --git 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/Characterization_Test.java
 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/Characterization_Test.java
index 207f4ed696..af924b5aa0 100644
--- 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/Characterization_Test.java
+++ 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/Characterization_Test.java
@@ -68,21 +68,18 @@ class Characterization_Test {
                private static final long serialVersionUID = 1L;
                @Override protected McpServerConfig createMcpConfig() {
                        return new McpServerConfig()
-                               .setServerInfo(new 
Implementation().setName("characterization").setVersion("1.0.0"))
+                               .setName("characterization").setVersion("1.0.0")
                                .setInstructions("Be concise.")
-                               .addTool(tool("echo", new 
JsonSchema().setType("object").setRequired("text"), a -> new CallToolResult()
-                                       .setContent(List.of(new 
TextContent().setText(String.valueOf(a.get("text")))))))
-                               .addTool(tool("mixed", null, a -> new 
CallToolResult().setContent(List.of(
-                                       new TextContent().setText("t"),
-                                       new 
ImageContent().setData("AAA=").setMimeType("image/png"),
-                                       new 
EmbeddedResourceContent().setResource(
-                                               new 
TextResourceContents().setUri("file:///e").setMimeType("text/plain").setText("emb"))))))
-                               .addTool(tool("failing", null, a -> new 
CallToolResult().setIsError(true)
-                                       .setContent(List.of(new 
TextContent().setText("nope")))))
-                               .addPrompt(prompt("greet", a -> new 
GetPromptResult().setDescription("d").setMessages(List.of(
-                                       new 
PromptMessage().setRole(Role.USER).setContent(new TextContent().setText("hi " + 
a.get("who")))))))
-                               .addResource(resource("file:///a", u -> new 
ReadResourceResult().setContents(List.of(
-                                       new 
TextResourceContents().setUri(u).setMimeType("text/plain").setText("body")))));
+                               .addTool(tool("echo", 
McpSchema.of(JsonMap.of("type", "object", "required", List.of("text"))), a -> 
McpToolOutcome.text(String.valueOf(a.get("text")))))
+                               .addTool(tool("mixed", null, a -> 
McpToolOutcome.of(
+                                       McpContentBlock.text("t"),
+                                       McpContentBlock.image("AAA=", 
"image/png"),
+                                       
McpContentBlock.resource(McpResourceContents.text("file:///e", "text/plain", 
"emb")))))
+                               .addTool(tool("failing", null, a -> 
McpToolOutcome.text("nope").setError(true)))
+                               .addPrompt(prompt("greet", a -> new 
McpPromptOutcome().setDescription("d").setMessages(List.of(
+                                       new 
McpPromptMessage().setRole(McpRole.USER).setContent(McpContentBlock.text("hi " 
+ a.get("who")))))))
+                               .addResource(resource("file:///a", u -> new 
McpResourceOutcome().setContents(List.of(
+                                       McpResourceContents.text(u, 
"text/plain", "body")))));
                }
        }
 
@@ -90,11 +87,15 @@ class Characterization_Test {
        public static class F_Caps extends McpRestServlet20250618 {
                private static final long serialVersionUID = 1L;
                @Override protected McpServerConfig createMcpConfig() {
-                       return new McpServerConfig()
-                               .setCapabilities(new ServerCapabilities()
-                                       .setLogging(new 
LoggingCapability().setLevel("info"))
-                                       .setResources(new 
ResourceCapability().setSubscribe(true).setListChanged(true))
-                                       .setExperimental(JsonMap.of("flag", 
1)));
+                       return new McpServerConfig();
+               }
+
+               @Override
+               protected ServerCapabilities capabilities() {
+                       return new ServerCapabilities()
+                               .setLogging(new 
LoggingCapability().setLevel("info"))
+                               .setResources(new 
ResourceCapability().setSubscribe(true).setListChanged(true))
+                               .setExperimental(JsonMap.of("flag", 1));
                }
        }
 
@@ -104,8 +105,8 @@ class Characterization_Test {
                @Override protected McpServerConfig createMcpConfig() {
                        return new McpServerConfig()
                                .setCursor(McpCursor.fixedSize(1))
-                               .addTool(tool("t1", null, a -> new 
CallToolResult()))
-                               .addTool(tool("t2", null, a -> new 
CallToolResult()));
+                               .addTool(tool("t1", null, a -> new 
McpToolOutcome()))
+                               .addTool(tool("t2", null, a -> new 
McpToolOutcome()));
                }
        }
 
@@ -122,24 +123,24 @@ class Characterization_Test {
 
        // --- fixture handler factories 
---------------------------------------------------------
 
-       private static McpToolHandler tool(String name, JsonSchema schema, 
Function<Map<String,Object>,CallToolResult> fn) {
+       private static McpToolHandler tool(String name, McpSchema schema, 
Function<Map<String,Object>,McpToolOutcome> fn) {
                return new McpToolHandler() {
-                       @Override public Tool descriptor() { return new 
Tool().setName(name).setDescription("desc:" + name).setInputSchema(schema); }
-                       @Override public CallToolResult call(Map<String,Object> 
arguments, BeanStore ctx) { return fn.apply(arguments); }
+                       @Override public McpToolSpec descriptor() { return new 
McpToolSpec().setName(name).setDescription("desc:" + 
name).setInputSchema(schema); }
+                       @Override public McpToolOutcome call(Map<String,Object> 
arguments, BeanStore ctx) { return fn.apply(arguments); }
                };
        }
 
-       private static McpPromptHandler prompt(String name, 
Function<Map<String,Object>,GetPromptResult> fn) {
+       private static McpPromptHandler prompt(String name, 
Function<Map<String,Object>,McpPromptOutcome> fn) {
                return new McpPromptHandler() {
-                       @Override public Prompt descriptor() { return new 
Prompt().setName(name).setDescription("pd"); }
-                       @Override public GetPromptResult get(Map<String,Object> 
arguments, BeanStore ctx) { return fn.apply(arguments); }
+                       @Override public McpPromptSpec descriptor() { return 
new McpPromptSpec().setName(name).setDescription("pd"); }
+                       @Override public McpPromptOutcome 
get(Map<String,Object> arguments, BeanStore ctx) { return fn.apply(arguments); }
                };
        }
 
-       private static McpResourceHandler resource(String uri, 
Function<String,ReadResourceResult> fn) {
+       private static McpResourceHandler resource(String uri, 
Function<String,McpResourceOutcome> fn) {
                return new McpResourceHandler() {
-                       @Override public Resource descriptor() { return new 
Resource().setUri(uri).setName("a").setMimeType("text/plain"); }
-                       @Override public ReadResourceResult read(String u, 
BeanStore ctx) { return fn.apply(u); }
+                       @Override public McpResourceSpec descriptor() { return 
new McpResourceSpec().setUri(uri).setName("a").setMimeType("text/plain"); }
+                       @Override public McpResourceOutcome read(String u, 
BeanStore ctx) { return fn.apply(u); }
                };
        }
 
diff --git 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/Mcp20250618Revision_Test.java
 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/Mcp20250618Revision_Test.java
index fda7de737f..465a15afd8 100644
--- 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/Mcp20250618Revision_Test.java
+++ 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/Mcp20250618Revision_Test.java
@@ -35,43 +35,43 @@ class Mcp20250618Revision_Test {
 
        private final BeanStore ctx = new BasicBeanStore();
 
-       private static McpToolHandler tool(String name, 
java.util.function.Function<Map<String,Object>,CallToolResult> fn) {
+       private static McpToolHandler tool(String name, 
java.util.function.Function<Map<String,Object>,McpToolOutcome> fn) {
                return new McpToolHandler() {
                        @Override
-                       public Tool descriptor() {
-                               return new 
Tool().setName(name).setDescription("desc:" + name);
+                       public McpToolSpec descriptor() {
+                               return new 
McpToolSpec().setName(name).setDescription("desc:" + name);
                        }
 
                        @Override
-                       public CallToolResult call(Map<String,Object> 
arguments, BeanStore ctx) {
+                       public McpToolOutcome call(Map<String,Object> 
arguments, BeanStore ctx) {
                                return fn.apply(arguments);
                        }
                };
        }
 
-       private static McpPromptHandler prompt(String name, 
java.util.function.Function<Map<String,Object>,GetPromptResult> fn) {
+       private static McpPromptHandler prompt(String name, 
java.util.function.Function<Map<String,Object>,McpPromptOutcome> fn) {
                return new McpPromptHandler() {
                        @Override
-                       public Prompt descriptor() {
-                               return new Prompt().setName(name);
+                       public McpPromptSpec descriptor() {
+                               return new McpPromptSpec().setName(name);
                        }
 
                        @Override
-                       public GetPromptResult get(Map<String,Object> 
arguments, BeanStore ctx) {
+                       public McpPromptOutcome get(Map<String,Object> 
arguments, BeanStore ctx) {
                                return fn.apply(arguments);
                        }
                };
        }
 
-       private static McpResourceHandler resource(String uri, 
java.util.function.Function<String,ReadResourceResult> fn) {
+       private static McpResourceHandler resource(String uri, 
java.util.function.Function<String,McpResourceOutcome> fn) {
                return new McpResourceHandler() {
                        @Override
-                       public Resource descriptor() {
-                               return new 
Resource().setUri(uri).setName("res");
+                       public McpResourceSpec descriptor() {
+                               return new 
McpResourceSpec().setUri(uri).setName("res");
                        }
 
                        @Override
-                       public ReadResourceResult read(String u, BeanStore ctx) 
{
+                       public McpResourceOutcome read(String u, BeanStore ctx) 
{
                                return fn.apply(u);
                        }
                };
@@ -88,9 +88,9 @@ class Mcp20250618Revision_Test {
        @Test
        void a01_initialize_default_capabilities() {
                var config = new McpServerConfig()
-                       .addTool(tool("a", a -> new CallToolResult()))
-                       .addPrompt(prompt("p", a -> new GetPromptResult()))
-                       .addResource(resource("r://x", u -> new 
ReadResourceResult()));
+                       .addTool(tool("a", a -> new McpToolOutcome()))
+                       .addPrompt(prompt("p", a -> new McpPromptOutcome()))
+                       .addResource(resource("r://x", u -> new 
McpResourceOutcome()));
 
                var resp = send(config, req(1, McpMethods.INITIALIZE, null));
                assertNotNull(resp);
@@ -103,14 +103,11 @@ class Mcp20250618Revision_Test {
        }
 
        @Test
-       void a02_initialize_explicit_capabilitiesAndServerInfo() {
-               var caps = new ServerCapabilities().setLogging(new 
LoggingCapability());
-               var info = new 
Implementation().setName("custom").setVersion("9.9");
-               var config = new 
McpServerConfig().setCapabilities(caps).setServerInfo(info).setInstructions("hi");
+       void a02_initialize_explicitServerInfoAndInstructions() {
+               var config = new 
McpServerConfig().setName("custom").setVersion("9.9").setInstructions("hi");
                var resp = send(config, req(1, McpMethods.INITIALIZE, null));
                var result = (InitializeResult) resp.getResult();
-               assertSame(caps, result.getCapabilities());
-               assertSame(info, result.getServerInfo());
+               assertBean(result.getServerInfo(), "name,version", 
"custom,9.9");
                assertString("hi", result.getInstructions());
        }
 
@@ -166,7 +163,7 @@ class Mcp20250618Revision_Test {
 
        @Test
        void b03_notification_returnsNullResponse() {
-               var config = new McpServerConfig().addTool(tool("a", args -> 
new CallToolResult()));
+               var config = new McpServerConfig().addTool(tool("a", args -> 
new McpToolOutcome()));
                var notif = req(null, McpMethods.TOOLS_CALL, JsonMap.of("name", 
"a"));
                assertNull(send(config, notif));
        }
@@ -192,8 +189,8 @@ class Mcp20250618Revision_Test {
        @Test
        void c01_tools_list_singlePage() {
                var config = new McpServerConfig()
-                       .addTool(tool("a", args -> new CallToolResult()))
-                       .addTool(tool("b", args -> new CallToolResult()));
+                       .addTool(tool("a", args -> new McpToolOutcome()))
+                       .addTool(tool("b", args -> new McpToolOutcome()));
                var resp = send(config, req(1, McpMethods.TOOLS_LIST, null));
                var result = (ListToolsResult) resp.getResult();
                assertSize(2, result.getTools());
@@ -203,8 +200,8 @@ class Mcp20250618Revision_Test {
        @Test
        void c02_tools_list_paged() {
                var config = new 
McpServerConfig().setCursor(McpCursor.fixedSize(1))
-                       .addTool(tool("a", args -> new CallToolResult()))
-                       .addTool(tool("b", args -> new CallToolResult()));
+                       .addTool(tool("a", args -> new McpToolOutcome()))
+                       .addTool(tool("b", args -> new McpToolOutcome()));
                var first = (ListToolsResult) send(config, req(1, 
McpMethods.TOOLS_LIST, null)).getResult();
                assertSize(1, first.getTools());
                assertString("1", first.getNextCursor());
@@ -218,9 +215,9 @@ class Mcp20250618Revision_Test {
        @Test
        void d01_tools_call_routes_byName() {
                var config = new McpServerConfig().addTool(tool("echo", args -> 
{
-                       var ctr = new CallToolResult();
-                       ctr.setContent(List.of(new 
TextContent().setText(String.valueOf(args.get("text")))));
-                       return ctr;
+                       var outcome = new McpToolOutcome();
+                       
outcome.setContent(List.of(McpContentBlock.text(String.valueOf(args.get("text")))));
+                       return outcome;
                }));
                var resp = send(config, req(1, McpMethods.TOOLS_CALL, 
JsonMap.of("name", "echo", "arguments", JsonMap.of("text", "hi"))));
                var ctr = (CallToolResult) resp.getResult();
@@ -241,14 +238,14 @@ class Mcp20250618Revision_Test {
 
        @Test
        void d04_tools_call_argumentsNotObject_throwsInvalidParams() {
-               var config = new McpServerConfig().addTool(tool("e", a -> new 
CallToolResult()));
+               var config = new McpServerConfig().addTool(tool("e", a -> new 
McpToolOutcome()));
                var resp = send(config, req(1, McpMethods.TOOLS_CALL, 
JsonMap.of("name", "e", "arguments", "string-not-map")));
                assertEquals(Mcp20250618Revision.CODE_INVALID_PARAMS, 
resp.getError().getCode());
        }
 
        @Test
        void d05_tools_call_paramsNotMap_invalidParams() {
-               var config = new McpServerConfig().addTool(tool("e", a -> new 
CallToolResult()));
+               var config = new McpServerConfig().addTool(tool("e", a -> new 
McpToolOutcome()));
                var resp = send(config, req(1, McpMethods.TOOLS_CALL, 
"not-a-map"));
                assertEquals(Mcp20250618Revision.CODE_INVALID_PARAMS, 
resp.getError().getCode());
        }
@@ -288,7 +285,7 @@ class Mcp20250618Revision_Test {
 
        @Test
        void e01_prompts_list_and_get() {
-               var config = new McpServerConfig().addPrompt(prompt("p", args 
-> new GetPromptResult().setDescription("ok")));
+               var config = new McpServerConfig().addPrompt(prompt("p", args 
-> new McpPromptOutcome().setDescription("ok")));
                var list = (ListPromptsResult) send(config, req(1, 
McpMethods.PROMPTS_LIST, null)).getResult();
                assertSize(1, list.getPrompts());
                var get = (GetPromptResult) send(config, req(1, 
McpMethods.PROMPTS_GET, JsonMap.of("name", "p"))).getResult();
@@ -311,7 +308,7 @@ class Mcp20250618Revision_Test {
 
        @Test
        void f01_resources_list_and_read() {
-               var config = new 
McpServerConfig().addResource(resource("file://a", uri -> new 
ReadResourceResult().setContents(List.of(new 
TextResourceContents().setUri(uri).setText("ok")))));
+               var config = new 
McpServerConfig().addResource(resource("file://a", uri -> new 
McpResourceOutcome().setContents(List.of(McpResourceContents.text(uri, null, 
"ok")))));
                var list = (ListResourcesResult) send(config, req(1, 
McpMethods.RESOURCES_LIST, null)).getResult();
                assertSize(1, list.getResources());
                var read = (ReadResourceResult) send(config, req(1, 
McpMethods.RESOURCES_READ, JsonMap.of("uri", "file://a"))).getResult();
@@ -334,7 +331,7 @@ class Mcp20250618Revision_Test {
 
        @Test
        void g01_cursor_paramsAreOptional() {
-               var config = new 
McpServerConfig().setCursor(McpCursor.fixedSize(1)).addPrompt(prompt("a", args 
-> new GetPromptResult())).addPrompt(prompt("b", args -> new 
GetPromptResult()));
+               var config = new 
McpServerConfig().setCursor(McpCursor.fixedSize(1)).addPrompt(prompt("a", args 
-> new McpPromptOutcome())).addPrompt(prompt("b", args -> new 
McpPromptOutcome()));
                // params null
                var resp = (ListPromptsResult) send(config, req(1, 
McpMethods.PROMPTS_LIST, null)).getResult();
                assertSize(1, resp.getPrompts());
diff --git 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpHandlerDefaults_Test.java
 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpHandlerDefaults_Test.java
index dbbb8e883e..9540afec35 100644
--- 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpHandlerDefaults_Test.java
+++ 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpHandlerDefaults_Test.java
@@ -19,7 +19,6 @@ package org.apache.juneau.rest.server.mcp.v20250618;
 import static org.apache.juneau.test.bct.BctAssertions.*;
 import static org.junit.jupiter.api.Assertions.*;
 
-import org.apache.juneau.bean.mcp.v20250618.*;
 import org.apache.juneau.commons.inject.*;
 import org.apache.juneau.rest.server.mcp.*;
 import org.junit.jupiter.api.*;
@@ -32,19 +31,19 @@ class McpHandlerDefaults_Test {
 
        @Test
        void a01_toolHandler_defaultDescriptor_throws() {
-               McpToolHandler h = (args, ctx) -> new CallToolResult();
+               McpToolHandler h = (args, ctx) -> new McpToolOutcome();
                assertThrows(UnsupportedOperationException.class, 
h::descriptor);
        }
 
        @Test
        void a02_promptHandler_defaultDescriptor_throws() {
-               McpPromptHandler h = (args, ctx) -> new GetPromptResult();
+               McpPromptHandler h = (args, ctx) -> new McpPromptOutcome();
                assertThrows(UnsupportedOperationException.class, 
h::descriptor);
        }
 
        @Test
        void a03_resourceHandler_defaultDescriptor_throws() {
-               McpResourceHandler h = (uri, ctx) -> new ReadResourceResult();
+               McpResourceHandler h = (uri, ctx) -> new McpResourceOutcome();
                assertThrows(UnsupportedOperationException.class, 
h::descriptor);
        }
 
diff --git 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpRestServlet20250618_Test.java
 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpRestServlet20250618_Test.java
index 53dd178d03..d452ecdb16 100644
--- 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpRestServlet20250618_Test.java
+++ 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpRestServlet20250618_Test.java
@@ -51,18 +51,16 @@ class McpRestServlet20250618_Test extends TestBase {
                @Override
                protected McpServerConfig createMcpConfig() {
                        return new McpServerConfig()
-                               .setServerInfo(new 
Implementation().setName("test").setVersion("1.0.0"))
+                               .setName("test").setVersion("1.0.0")
                                .addTool(new McpToolHandler() {
                                        @Override
-                                       public Tool descriptor() {
-                                               return new 
Tool().setName("echo").setDescription("Echoes back");
+                                       public McpToolSpec descriptor() {
+                                               return new 
McpToolSpec().setName("echo").setDescription("Echoes back");
                                        }
 
                                        @Override
-                                       public CallToolResult 
call(Map<String,Object> arguments, BeanStore ctx) {
-                                               var ctr = new CallToolResult();
-                                               ctr.setContent(List.of(new 
TextContent().setText(String.valueOf(arguments.get("text")))));
-                                               return ctr;
+                                       public McpToolOutcome 
call(Map<String,Object> arguments, BeanStore ctx) {
+                                               return 
McpToolOutcome.text(String.valueOf(arguments.get("text")));
                                        }
                                });
                }
@@ -123,11 +121,11 @@ class McpRestServlet20250618_Test extends TestBase {
                public McpServerConfig getMcpConfig() {
                        return new McpServerConfig().addTool(new 
McpToolHandler() {
                                @Override
-                               public Tool descriptor() { return new 
Tool().setName("ping"); }
+                               public McpToolSpec descriptor() { return new 
McpToolSpec().setName("ping"); }
 
                                @Override
-                               public CallToolResult call(Map<String,Object> 
arguments, BeanStore ctx) {
-                                       return new 
CallToolResult().setContent(List.of(new TextContent().setText("pong")));
+                               public McpToolOutcome call(Map<String,Object> 
arguments, BeanStore ctx) {
+                                       return McpToolOutcome.text("pong");
                                }
                        });
                }
diff --git 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpServerConfig_Test.java
 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpServerConfig_Test.java
deleted file mode 100644
index 6ec4f9fbd6..0000000000
--- 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpServerConfig_Test.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.juneau.rest.server.mcp.v20250618;
-
-import static org.apache.juneau.test.bct.BctAssertions.*;
-import static org.junit.jupiter.api.Assertions.*;
-
-import java.util.*;
-
-import org.apache.juneau.bean.mcp.v20250618.*;
-import org.apache.juneau.commons.inject.*;
-import org.apache.juneau.rest.server.mcp.*;
-import org.junit.jupiter.api.*;
-
-/**
- * Coverage for {@link McpServerConfig}.
- */
-class McpServerConfig_Test {
-
-       private static McpToolHandler dummyTool(String name) {
-               return new McpToolHandler() {
-                       @Override
-                       public Tool descriptor() {
-                               return new Tool().setName(name);
-                       }
-
-                       @Override
-                       public CallToolResult call(Map<String,Object> 
arguments, BeanStore ctx) {
-                               return new CallToolResult();
-                       }
-               };
-       }
-
-       private static McpPromptHandler dummyPrompt(String name) {
-               return new McpPromptHandler() {
-                       @Override
-                       public Prompt descriptor() {
-                               return new Prompt().setName(name);
-                       }
-
-                       @Override
-                       public GetPromptResult get(Map<String,Object> 
arguments, BeanStore ctx) {
-                               return new GetPromptResult();
-                       }
-               };
-       }
-
-       private static McpResourceHandler dummyResource(String uri) {
-               return new McpResourceHandler() {
-                       @Override
-                       public Resource descriptor() {
-                               return new Resource().setUri(uri);
-                       }
-
-                       @Override
-                       public ReadResourceResult read(String u, BeanStore ctx) 
{
-                               return new ReadResourceResult();
-                       }
-               };
-       }
-
-       @Test
-       void a01_defaults() {
-               var c = new McpServerConfig();
-               assertNull(c.getServerInfo());
-               assertString(McpProtocol.VERSION_2025_06_18, 
c.getProtocolVersion());
-               assertNull(c.getInstructions());
-               assertNotNull(c.getTools());
-               assertNotNull(c.getPrompts());
-               assertNotNull(c.getResources());
-               assertNull(c.getCapabilities());
-               assertSame(McpCursor.SINGLE_PAGE, c.getCursor());
-       }
-
-       @Test
-       void a02_setters_and_addCalls() {
-               var info = new Implementation().setName("x").setVersion("1");
-               var caps = new ServerCapabilities().setLogging(new 
LoggingCapability());
-               var c = new McpServerConfig()
-                       .setServerInfo(info)
-                       .setProtocolVersion("2024-11-05")
-                       .setInstructions("hello")
-                       .setCapabilities(caps)
-                       .setCursor(McpCursor.fixedSize(5))
-                       .addTool(dummyTool("t1"), dummyTool("t2"))
-                       .addPrompt(dummyPrompt("p1"))
-                       .addResource(dummyResource("r://a"));
-
-               assertSame(info, c.getServerInfo());
-               assertString("2024-11-05", c.getProtocolVersion());
-               assertString("hello", c.getInstructions());
-               assertSame(caps, c.getCapabilities());
-               assertNotSame(McpCursor.SINGLE_PAGE, c.getCursor());
-               assertSize(2, c.getTools());
-               assertSize(1, c.getPrompts());
-               assertSize(1, c.getResources());
-       }
-
-       @Test
-       void a03_setLists_replacingAndNullClears() {
-               var c = new 
McpServerConfig().addTool(dummyTool("t")).addPrompt(dummyPrompt("p")).addResource(dummyResource("r"));
-               c.setTools(null);
-               c.setPrompts(null);
-               c.setResources(null);
-               assertEmpty(c.getTools());
-               assertEmpty(c.getPrompts());
-               assertEmpty(c.getResources());
-
-               c.setTools(List.of(dummyTool("a")));
-               c.setPrompts(List.of(dummyPrompt("a")));
-               c.setResources(List.of(dummyResource("a")));
-               assertSize(1, c.getTools());
-               assertSize(1, c.getPrompts());
-               assertSize(1, c.getResources());
-       }
-
-       @Test
-       void a04_setCursor_nullResets() {
-               var c = new McpServerConfig().setCursor(McpCursor.fixedSize(2));
-               c.setCursor(null);
-               assertSame(McpCursor.SINGLE_PAGE, c.getCursor());
-       }
-}
diff --git 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpTypedHandlers_Test.java
 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpTypedHandlers_Test.java
index 7c5f2c2157..a01ba476c6 100644
--- 
a/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpTypedHandlers_Test.java
+++ 
b/juneau-rest/juneau-rest-server-mcp-2025-06-18/src/test/java/org/apache/juneau/rest/server/mcp/v20250618/McpTypedHandlers_Test.java
@@ -115,7 +115,9 @@ class McpTypedHandlers_Test {
                        .setMethod(McpMethods.TOOLS_CALL)
                        .setParams(JsonMap.of("name", "d"));
                var resp = dispatch(req, config);
-               assertSame(ctr, resp.getResult());
+               // The neutral/wire boundary always remaps the result, so only 
value equality survives here.
+               var result = (CallToolResult) resp.getResult();
+               assertString("direct", ((TextContent) 
result.getContent().get(0)).getText());
        }
 
        @Test
@@ -234,7 +236,7 @@ class McpTypedHandlers_Test {
                };
                var raw = McpTypedHandlers.adaptTool(typed);
                var ctr = raw.call(null, ctx);
-               assertString("null", ((TextContent) 
ctr.getContent().get(0)).getText());
+               assertString("null", ctr.getContent().get(0).text());
        }
 
        @Test
diff --git a/juneau-rest/juneau-rest-server-mcp/pom.xml 
b/juneau-rest/juneau-rest-server-mcp/pom.xml
index f3ec6d2046..dff22f2baa 100644
--- a/juneau-rest/juneau-rest-server-mcp/pom.xml
+++ b/juneau-rest/juneau-rest-server-mcp/pom.xml
@@ -40,11 +40,6 @@
                        <artifactId>juneau-rest-server</artifactId>
                        <version>${project.version}</version>
                </dependency>
-               <dependency>
-                       <groupId>org.apache.juneau</groupId>
-                       <artifactId>juneau-bean-mcp-2025-06-18</artifactId>
-                       <version>${project.version}</version>
-               </dependency>
                <dependency>
                        <groupId>org.apache.juneau</groupId>
                        <artifactId>juneau-bean-jsonrpc</artifactId>
diff --git 
a/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpPromptHandler.java
 
b/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpPromptHandler.java
index e8612f8d8a..3e571f554b 100644
--- 
a/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpPromptHandler.java
+++ 
b/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpPromptHandler.java
@@ -18,15 +18,15 @@ package org.apache.juneau.rest.server.mcp;
 
 import java.util.*;
 
-import org.apache.juneau.bean.mcp.v20250618.*;
 import org.apache.juneau.commons.inject.*;
 
 /**
  * Handler for a single MCP prompt.
  *
  * <p>
- * Implementations declare a {@link #descriptor() descriptor} (the {@link 
Prompt} returned by {@code prompts/list})
- * and a {@link #get(Map, BeanStore) get} body invoked when the matching 
{@code prompts/get} method runs.
+ * Implementations declare a {@link #descriptor() descriptor} (the {@link 
McpPromptSpec} returned by
+ * {@code prompts/list}) and a {@link #get(Map, BeanStore) get} body invoked 
when the matching
+ * {@code prompts/get} method runs.
  */
 @FunctionalInterface
 public interface McpPromptHandler {
@@ -35,13 +35,13 @@ public interface McpPromptHandler {
         * Returns the static descriptor for this prompt.
         *
         * <p>
-        * The {@link Prompt#getName() name} value is used by the bound {@link 
McpRevision} to route
+        * The {@link McpPromptSpec#getName() name} value is used by the bound 
{@link McpRevision} to route
         * incoming {@code prompts/get} requests, so each handler in an {@link 
McpServerConfig} must use a
         * unique name.
         *
         * @return The prompt descriptor. Never {@code null}.
         */
-       default Prompt descriptor() {
+       default McpPromptSpec descriptor() {
                throw new UnsupportedOperationException("descriptor() must be 
implemented by McpPromptHandler subclasses.");
        }
 
@@ -52,5 +52,5 @@ public interface McpPromptHandler {
         * @param ctx Per-request bean store. Never {@code null}.
         * @return The rendered prompt. Never {@code null}.
         */
-       GetPromptResult get(Map<String,Object> arguments, BeanStore ctx);
+       McpPromptOutcome get(Map<String,Object> arguments, BeanStore ctx);
 }
diff --git 
a/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpResourceHandler.java
 
b/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpResourceHandler.java
index db02fe3e77..f79a91b87f 100644
--- 
a/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpResourceHandler.java
+++ 
b/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpResourceHandler.java
@@ -16,15 +16,15 @@
  */
 package org.apache.juneau.rest.server.mcp;
 
-import org.apache.juneau.bean.mcp.v20250618.*;
 import org.apache.juneau.commons.inject.*;
 
 /**
  * Handler for a single MCP resource.
  *
  * <p>
- * Implementations declare a {@link #descriptor() descriptor} (the {@link 
Resource} returned by {@code resources/list})
- * and a {@link #read(String, BeanStore) read} body invoked when the matching 
{@code resources/read} method runs.
+ * Implementations declare a {@link #descriptor() descriptor} (the {@link 
McpResourceSpec} returned by
+ * {@code resources/list}) and a {@link #read(String, BeanStore) read} body 
invoked when the matching
+ * {@code resources/read} method runs.
  */
 @FunctionalInterface
 public interface McpResourceHandler {
@@ -33,13 +33,13 @@ public interface McpResourceHandler {
         * Returns the static descriptor for this resource.
         *
         * <p>
-        * The {@link Resource#getUri() uri} value is used by the bound {@link 
McpRevision} to route
+        * The {@link McpResourceSpec#getUri() uri} value is used by the bound 
{@link McpRevision} to route
         * incoming {@code resources/read} requests, so each handler in an 
{@link McpServerConfig} must use
         * a unique URI.
         *
         * @return The resource descriptor. Never {@code null}.
         */
-       default Resource descriptor() {
+       default McpResourceSpec descriptor() {
                throw new UnsupportedOperationException("descriptor() must be 
implemented by McpResourceHandler subclasses.");
        }
 
@@ -50,5 +50,5 @@ public interface McpResourceHandler {
         * @param ctx Per-request bean store. Never {@code null}.
         * @return The resource contents. Never {@code null}.
         */
-       ReadResourceResult read(String uri, BeanStore ctx);
+       McpResourceOutcome read(String uri, BeanStore ctx);
 }
diff --git 
a/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpRestServlet.java
 
b/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpRestServlet.java
index 3475544b92..b51302eee3 100644
--- 
a/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpRestServlet.java
+++ 
b/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpRestServlet.java
@@ -19,7 +19,6 @@ package org.apache.juneau.rest.server.mcp;
 import java.util.concurrent.atomic.*;
 
 import org.apache.juneau.bean.jsonrpc.*;
-import org.apache.juneau.bean.mcp.v20250618.*;
 import org.apache.juneau.commons.inject.*;
 import org.apache.juneau.http.Content;
 import org.apache.juneau.marshall.serializer.*;
diff --git 
a/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpServerConfig.java
 
b/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpServerConfig.java
index da8fd2ac99..ae301961d7 100644
--- 
a/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpServerConfig.java
+++ 
b/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpServerConfig.java
@@ -20,8 +20,6 @@ import static org.apache.juneau.commons.utils.Shorts.*;
 
 import java.util.*;
 
-import org.apache.juneau.bean.mcp.v20250618.*;
-
 /**
  * Aggregate configuration consumed by the bound {@link McpRevision}.
  *
@@ -29,58 +27,64 @@ import org.apache.juneau.bean.mcp.v20250618.*;
  * Applications register a single {@link McpServerConfig} (typically as a bean 
in their {@code RestContext}
  * bean store) listing the tools, prompts, and resources to expose, plus 
optional server metadata and a
  * pagination strategy.
+ *
+ * <p>
+ * This type is revision-neutral: it holds no field typed with any protocol 
revision's wire beans, and
+ * in particular holds no capabilities field in any form. The protocol version 
is owned by
+ * {@link McpRevision#protocolVersion()}, and an explicit capabilities 
advertisement is owned by a
+ * revision-specific hook on that revision's servlet or endpoint mixin.
  */
 public class McpServerConfig {
 
-       private Implementation serverInfo;
-       private String protocolVersion = McpProtocol.VERSION_2025_06_18;
+       private String name;
+       private String version;
        private String instructions;
        private List<McpToolHandler> tools = l();
        private List<McpPromptHandler> prompts = l();
        private List<McpResourceHandler> resources = l();
-       private ServerCapabilities capabilities;
        private McpCursor cursor = McpCursor.SINGLE_PAGE;
 
        /**
-        * Server identity reported in {@code initialize}.
+        * Server name reported in {@code initialize}.
         *
         * <p>
-        * If {@code null}, the bound {@link McpRevision} fills in a default 
identity.
+        * When both this and {@link #getVersion()} are {@code null}, the bound 
revision substitutes its
+        * own default server identity.
         *
-        * @return The server info, or {@code null} if not set.
+        * @return The name, or {@code null} if not set.
         */
-       public Implementation getServerInfo() {
-               return serverInfo;
+       public String getName() {
+               return name;
        }
 
        /**
-        * Sets the server identity.
+        * Sets the server name.
         *
-        * @param serverInfo The new value.
-        * @return This object (for method chaining).
+        * @param value The new value. Can be <jk>null</jk> to unset the 
property.
+        * @return This object.
         */
-       public McpServerConfig setServerInfo(Implementation serverInfo) {
-               this.serverInfo = serverInfo;
+       public McpServerConfig setName(String value) {
+               name = value;
                return this;
        }
 
        /**
-        * MCP protocol revision returned by {@code initialize}.
+        * Server version reported in {@code initialize}.
         *
-        * @return The protocol version, or <jk>null</jk> if not set.
+        * @return The version, or {@code null} if not set.
         */
-       public String getProtocolVersion() {
-               return protocolVersion;
+       public String getVersion() {
+               return version;
        }
 
        /**
-        * Sets the protocol revision.
+        * Sets the server version.
         *
-        * @param protocolVersion The new value. Can be <jk>null</jk> to unset 
it.
-        * @return This object (for method chaining).
+        * @param value The new value. Can be <jk>null</jk> to unset the 
property.
+        * @return This object.
         */
-       public McpServerConfig setProtocolVersion(String protocolVersion) {
-               this.protocolVersion = protocolVersion;
+       public McpServerConfig setVersion(String value) {
+               version = value;
                return this;
        }
 
@@ -197,29 +201,6 @@ public class McpServerConfig {
                return this;
        }
 
-       /**
-        * Optional explicit capabilities advertisement.
-        *
-        * <p>
-        * When {@code null}, the bound {@link McpRevision} synthesizes one 
from the registered handler lists.
-        *
-        * @return The override, or {@code null} if auto-derived.
-        */
-       public ServerCapabilities getCapabilities() {
-               return capabilities;
-       }
-
-       /**
-        * Sets the explicit capabilities advertisement.
-        *
-        * @param capabilities The new value.
-        * @return This object (for method chaining).
-        */
-       public McpServerConfig setCapabilities(ServerCapabilities capabilities) 
{
-               this.capabilities = capabilities;
-               return this;
-       }
-
        /**
         * Pagination strategy for {@code list} dispatchers (tools / prompts / 
resources).
         *
diff --git 
a/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpToolHandler.java
 
b/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpToolHandler.java
index 6d0169d020..0c88a0bd20 100644
--- 
a/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpToolHandler.java
+++ 
b/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/McpToolHandler.java
@@ -18,19 +18,20 @@ package org.apache.juneau.rest.server.mcp;
 
 import java.util.*;
 
-import org.apache.juneau.bean.mcp.v20250618.*;
 import org.apache.juneau.commons.inject.*;
 
 /**
  * Handler for a single MCP tool.
  *
  * <p>
- * Implementations declare a {@link #descriptor() descriptor} (the {@link 
Tool} returned by {@code tools/list})
- * and a {@link #call(Map, BeanStore) call} body invoked when the matching 
{@code tools/call} method runs.
+ * Implementations declare a {@link #descriptor() descriptor} (returned from 
{@code tools/list}) and
+ * a {@link #call(Map, BeanStore) call} body invoked when a matching {@code 
tools/call} arrives. Both
+ * use the revision-neutral model, so a handler compiles against exactly one 
protocol revision's
+ * worth of assumptions: none.
  *
  * <p>
- * The {@link BeanStore} argument is the per-request bean store, allowing 
handlers to look up additional
- * services (or the underlying {@code RestRequest}) without making this 
interface depend on REST runtime types.
+ * The {@link BeanStore} argument is the per-request bean store, letting 
handlers look up additional
+ * services (or the underlying {@code RestRequest}) without this interface 
depending on REST runtime types.
  */
 @FunctionalInterface
 public interface McpToolHandler {
@@ -39,13 +40,13 @@ public interface McpToolHandler {
         * Returns the static descriptor for this tool.
         *
         * <p>
-        * The {@link Tool#getName() name} value is used by the bound {@link 
McpRevision} to route
+        * The {@link McpToolSpec#getName() name} value is used by the bound 
{@link McpRevision} to route
         * incoming {@code tools/call} requests, so each handler in an {@link 
McpServerConfig} must use a
         * unique name.
         *
         * @return The tool descriptor. Never {@code null}.
         */
-       default Tool descriptor() {
+       default McpToolSpec descriptor() {
                throw new UnsupportedOperationException("descriptor() must be 
implemented by McpToolHandler subclasses.");
        }
 
@@ -56,5 +57,5 @@ public interface McpToolHandler {
         * @param ctx Per-request bean store. Never {@code null}.
         * @return The call result. Never {@code null}.
         */
-       CallToolResult call(Map<String,Object> arguments, BeanStore ctx);
+       McpToolOutcome call(Map<String,Object> arguments, BeanStore ctx);
 }
diff --git 
a/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/package-info.java
 
b/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/package-info.java
index 4799b0818a..ce41ce58fc 100644
--- 
a/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/package-info.java
+++ 
b/juneau-rest/juneau-rest-server-mcp/src/main/java/org/apache/juneau/rest/server/mcp/package-info.java
@@ -16,7 +16,18 @@
  */
 
 /**
- * Stateless Model Context Protocol (MCP) endpoint built on {@code 
juneau-rest-server} using the
- * {@code juneau-bean-mcp} wire types.
+ * Revision-neutral core for MCP endpoints built on {@code juneau-rest-server}.
+ *
+ * <p>
+ * This package knows the shape of an MCP server — tools, prompts, resources, 
pagination, the
+ * JSON-RPC dispatch contract, and the two HTTP entry points — without knowing 
any MCP protocol
+ * revision. It has no compile dependency on any revision's wire beans, and 
that is enforced at
+ * build time. A protocol revision is supplied by an implementation of {@link 
McpRevision} living in
+ * its own module (for example {@code juneau-rest-server-mcp-2025-06-18}), and 
a consumer binds one
+ * at compile time by extending that revision's abstract servlet or composing 
its endpoint mixin.
+ *
+ * <h5 class='section'>See Also:</h5><ul>
+ *     <li class='link'><a class="doclink" 
href="https://juneau.apache.org/docs/topics/JuneauRestServerMcp";>juneau-rest-server-mcp</a>
+ * </ul>
  */
 package org.apache.juneau.rest.server.mcp;
diff --git 
a/juneau-rest/juneau-rest-server-mcp/src/test/java/org/apache/juneau/rest/server/mcp/FakeMcpRevision_Test.java
 
b/juneau-rest/juneau-rest-server-mcp/src/test/java/org/apache/juneau/rest/server/mcp/FakeMcpRevision_Test.java
index 80ec9c80de..5b7658aa02 100644
--- 
a/juneau-rest/juneau-rest-server-mcp/src/test/java/org/apache/juneau/rest/server/mcp/FakeMcpRevision_Test.java
+++ 
b/juneau-rest/juneau-rest-server-mcp/src/test/java/org/apache/juneau/rest/server/mcp/FakeMcpRevision_Test.java
@@ -1,3 +1,19 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.apache.juneau.rest.server.mcp;
 
 import static org.junit.jupiter.api.Assertions.*;
@@ -103,7 +119,6 @@ class FakeMcpRevision_Test extends TestBase {
        }
 
        @Test
-       @org.junit.jupiter.api.Disabled("Enabled by the task that drops core's 
dependency on juneau-bean-mcp-2025-06-18.")
        void a04_coreTestTreeSeesNoRevisionModule() {
                assertThrows(ClassNotFoundException.class,
                        () -> 
Class.forName("org.apache.juneau.rest.server.mcp.v20250618.Mcp20250618Revision"),
diff --git 
a/juneau-rest/juneau-rest-server-mcp/src/test/java/org/apache/juneau/rest/server/mcp/McpConfigCore_Test.java
 
b/juneau-rest/juneau-rest-server-mcp/src/test/java/org/apache/juneau/rest/server/mcp/McpConfigCore_Test.java
new file mode 100644
index 0000000000..83d5c67dde
--- /dev/null
+++ 
b/juneau-rest/juneau-rest-server-mcp/src/test/java/org/apache/juneau/rest/server/mcp/McpConfigCore_Test.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.juneau.rest.server.mcp;
+
+import static org.apache.juneau.test.bct.BctAssertions.*;
+import static org.junit.jupiter.api.Assertions.*;
+
+import java.util.*;
+
+import org.apache.juneau.commons.inject.*;
+import org.junit.jupiter.api.*;
+
+/**
+ * Coverage for the revision-neutral {@link McpServerConfig}.
+ */
+class McpConfigCore_Test {
+
+       private static McpToolHandler dummyTool(String name) {
+               return new McpToolHandler() {
+                       @Override public McpToolSpec descriptor() { return new 
McpToolSpec().setName(name); }
+                       @Override public McpToolOutcome call(Map<String,Object> 
arguments, BeanStore ctx) { return new McpToolOutcome(); }
+               };
+       }
+
+       private static McpPromptHandler dummyPrompt(String name) {
+               return new McpPromptHandler() {
+                       @Override public McpPromptSpec descriptor() { return 
new McpPromptSpec().setName(name); }
+                       @Override public McpPromptOutcome 
get(Map<String,Object> arguments, BeanStore ctx) { return new 
McpPromptOutcome(); }
+               };
+       }
+
+       private static McpResourceHandler dummyResource(String uri) {
+               return new McpResourceHandler() {
+                       @Override public McpResourceSpec descriptor() { return 
new McpResourceSpec().setUri(uri); }
+                       @Override public McpResourceOutcome read(String u, 
BeanStore ctx) { return new McpResourceOutcome(); }
+               };
+       }
+
+       @Test
+       void a01_defaults() {
+               var a = new McpServerConfig();
+               assertNull(a.getName());
+               assertNull(a.getVersion());
+               assertNull(a.getInstructions());
+               assertNotNull(a.getTools());
+               assertNotNull(a.getPrompts());
+               assertNotNull(a.getResources());
+               assertSame(McpCursor.SINGLE_PAGE, a.getCursor());
+       }
+
+       @Test
+       void a02_setters_and_addCalls() {
+               var a = new McpServerConfig()
+                       .setName("x")
+                       .setVersion("1")
+                       .setInstructions("hello")
+                       .setCursor(McpCursor.fixedSize(5))
+                       .addTool(dummyTool("t1"), dummyTool("t2"))
+                       .addPrompt(dummyPrompt("p1"))
+                       .addResource(dummyResource("r://a"));
+
+               assertString("x", a.getName());
+               assertString("1", a.getVersion());
+               assertString("hello", a.getInstructions());
+               assertNotSame(McpCursor.SINGLE_PAGE, a.getCursor());
+               assertSize(2, a.getTools());
+               assertSize(1, a.getPrompts());
+               assertSize(1, a.getResources());
+       }
+
+       @Test
+       void a03_setLists_replacingAndNullClears() {
+               var a = new 
McpServerConfig().addTool(dummyTool("t")).addPrompt(dummyPrompt("p")).addResource(dummyResource("r"));
+               a.setTools(null);
+               a.setPrompts(null);
+               a.setResources(null);
+               assertEmpty(a.getTools());
+               assertEmpty(a.getPrompts());
+               assertEmpty(a.getResources());
+
+               a.setTools(List.of(dummyTool("a")));
+               a.setPrompts(List.of(dummyPrompt("a")));
+               a.setResources(List.of(dummyResource("a")));
+               assertSize(1, a.getTools());
+               assertSize(1, a.getPrompts());
+               assertSize(1, a.getResources());
+       }
+
+       @Test
+       void a04_setCursor_nullResets() {
+               var a = new McpServerConfig().setCursor(McpCursor.fixedSize(2));
+               a.setCursor(null);
+               assertSame(McpCursor.SINGLE_PAGE, a.getCursor());
+       }
+
+       @Test
+       void a05_noRevisionSpecificSurfaceRemains() {
+               var m = 
Arrays.stream(McpServerConfig.class.getMethods()).map(java.lang.reflect.Method::getName).toList();
+               assertFalse(m.contains("getCapabilities"), "capabilities are 
revision-owned; core must hold none");
+               assertFalse(m.contains("setCapabilities"), "capabilities are 
revision-owned; core must hold none");
+               assertFalse(m.contains("getProtocolVersion"), "the protocol 
version is owned by McpRevision.protocolVersion()");
+               assertFalse(m.contains("setProtocolVersion"), "the protocol 
version is owned by McpRevision.protocolVersion()");
+               assertFalse(m.contains("getServerInfo"), "server identity is 
plain name/version on the neutral config");
+       }
+
+       @Test
+       void a06_nullListElementsAreDistinctFromEmpty() {
+               assertNull(new McpToolOutcome().getContent());
+               assertNull(new McpPromptOutcome().getMessages());
+               assertNull(new McpResourceOutcome().getContents());
+       }
+}

Reply via email to