从 mcp-sdk(java) 的角度，是没法实现动态输出 tools 的。mcp-sdk 的机制是先注册 tool，然后内部处理 "tools/list" 响应（而且特别内部）。要实现动态输出 tools ，一般有两种方案

* 修改 mcp-sdk 代码，扩展 "tools/list" 处理，由外部代理（不利于 mcp-sdk 的未来维护与升级）
* 先定义好 tools 组，然后在 http 接入处进行切换（这个是目前可以做的）


下面使用 http 接入处进行切换的方案，进行演示（v3.9.6 后支持）

### 1、容器风格

以下以 solon 容器为例。其它容器需要自己转下。

```java
import io.modelcontextprotocol.server.transport.WebRxStatelessServerTransport;
import org.noear.solon.Solon;
import org.noear.solon.ai.annotation.PromptMapping;
import org.noear.solon.ai.annotation.ResourceMapping;
import org.noear.solon.ai.annotation.ToolMapping;
import org.noear.solon.ai.chat.message.ChatMessage;
import org.noear.solon.ai.chat.prompt.MethodPromptProvider;
import org.noear.solon.ai.chat.resource.MethodResourceProvider;
import org.noear.solon.ai.chat.tool.MethodToolProvider;
import org.noear.solon.ai.mcp.McpChannel;
import org.noear.solon.ai.mcp.server.McpServerEndpointProvider;
import org.noear.solon.annotation.Component;
import org.noear.solon.annotation.Param;
import org.noear.solon.core.handle.Context;

import java.util.Arrays;
import java.util.Collection;

public class App {
    public static void main(String[] args) {
        Solon.start(App.class, args);

        WebRxStatelessServerTransport serverTransport1 = buildMcpServerTransport("group1");
        WebRxStatelessServerTransport serverTransport2 = buildMcpServerTransport("group2");

        //接入时进行路由分发（不同的 ServerTransport，需要代理不同的方法。可以看它的 toHttpHandler 方法里有哪些处理）
        Solon.app().router().get("/mcp", ctx -> {
            int role = ctx.paramAsInt("role");

            if (role == 1) {
                serverTransport1.handleGet(ctx);
            } else {
                serverTransport2.handleGet(ctx);
            }
        });

        Solon.app().router().post("/mcp", ctx -> {
            int role = ctx.paramAsInt("role");

            if (role == 1) {
                serverTransport1.handlePost(ctx);
            } else {
                serverTransport2.handlePost(ctx);
            }
        });
    }

    public static WebRxStatelessServerTransport buildMcpServerTransport(String group) {
        Object mcpBean = Solon.context().getBean(group);

        if (mcpBean == null) {
            return null;
        }

        McpServerEndpointProvider endpointProvider = McpServerEndpointProvider.builder()
                .name(group)
                .channel(McpChannel.STREAMABLE_STATELESS)
                .sseEndpoint("/mcp")
                .build();

        //不同的 group ，用不同的 tools
        endpointProvider.addTool(new MethodToolProvider(mcpBean));
        endpointProvider.addResource(new MethodResourceProvider(mcpBean));
        endpointProvider.addPrompt(new MethodPromptProvider(mcpBean));

        //这里用 build（不用 start，否则会自动注册到路由器）
        //(WebRxStatelessServerTransport) 要与 .channel(McpChannel.STREAMABLE_STATELESS) 对应起来
        return (WebRxStatelessServerTransport) endpointProvider.getServer().build();
    }

    @Component("group1")
    public static class McpServerTool {
        //@Inject //容器形态可以注入（否则，要自己组件需要的服务）
        //UserService userService;

        @ToolMapping(description = "查询天气预报")
        public String getWeather(@Param(description = "城市位置") String location, Context ctx) {
            return "晴，14度";
        }

        @ResourceMapping(uri = "config://app-version", description = "获取应用版本号", mimeType = "text/config")
        public String getAppVersion() {
            return "v3.2.0";
        }

        @PromptMapping(description = "生成关于某个主题的提问")
        public Collection<ChatMessage> askQuestion(@Param(description = "主题") String topic) {
            return Arrays.asList(
                    ChatMessage.ofUser("请解释一下'" + topic + "'的概念？")
            );
        }
    }
}
```


### 2、Java 原生风格

```java
import io.modelcontextprotocol.server.transport.WebRxStatelessServerTransport;
import org.noear.solon.Solon;
import org.noear.solon.ai.annotation.PromptMapping;
import org.noear.solon.ai.annotation.ResourceMapping;
import org.noear.solon.ai.annotation.ToolMapping;
import org.noear.solon.ai.chat.message.ChatMessage;
import org.noear.solon.ai.chat.prompt.MethodPromptProvider;
import org.noear.solon.ai.chat.resource.MethodResourceProvider;
import org.noear.solon.ai.chat.tool.MethodToolProvider;
import org.noear.solon.ai.mcp.McpChannel;
import org.noear.solon.ai.mcp.server.McpServerEndpointProvider;
import org.noear.solon.annotation.Param;
import org.noear.solon.core.handle.Context;

import java.util.Arrays;
import java.util.Collection;

public class App {
    public static void main(String[] args) {
        Solon.start(App.class, args);

        WebRxStatelessServerTransport serverTransport1 = buildMcpServerTransport("group1");
        WebRxStatelessServerTransport serverTransport2 = buildMcpServerTransport("group2");

        //接入时进行路由分发（不同的 ServerTransport，需要代理不同的方法。可以看它的 toHttpHandler 方法里有哪些处理）
        Solon.app().router().get("/mcp", ctx -> {
            int role = ctx.paramAsInt("role");

            if (role == 1) {
                serverTransport1.handleGet(ctx);
            } else {
                serverTransport2.handleGet(ctx);
            }
        });

        Solon.app().router().post("/mcp", ctx -> {
            int role = ctx.paramAsInt("role");

            if (role == 1) {
                serverTransport1.handlePost(ctx);
            } else {
                serverTransport2.handlePost(ctx);
            }
        });
    }

    private static WebRxStatelessServerTransport buildMcpServerTransport(String group) {
        McpServerEndpointProvider endpointProvider = McpServerEndpointProvider.builder()
                .name(group)
                .channel(McpChannel.STREAMABLE_STATELESS)
                .sseEndpoint("/mcp")
                .build();

        //不同的 group ，用不同的 tools
        endpointProvider.addTool(new MethodToolProvider(new McpServerTool()));
        endpointProvider.addResource(new MethodResourceProvider(new McpServerTool()));
        endpointProvider.addPrompt(new MethodPromptProvider(new McpServerTool()));

        //这里用 build（不用 start，否则会自动注册到路由器）
        //(WebRxStatelessServerTransport) 要与 .channel(McpChannel.STREAMABLE_STATELESS) 对应起来
        return (WebRxStatelessServerTransport) endpointProvider.getServer().build();
    }

    private static class McpServerTool {
        @ToolMapping(description = "查询天气预报")
        public String getWeather(@Param(description = "城市位置") String location, Context ctx) {
            return "晴，14度";
        }

        @ResourceMapping(uri = "config://app-version", description = "获取应用版本号", mimeType = "text/config")
        public String getAppVersion() {
            return "v3.2.0";
        }

        @PromptMapping(description = "生成关于某个主题的提问")
        public Collection<ChatMessage> askQuestion(@Param(description = "主题") String topic) {
            return Arrays.asList(
                    ChatMessage.ofUser("请解释一下'" + topic + "'的概念？")
            );
        }
    }
}
```



