在 Feat Cloud 中暴露 MCP 服务
MCP 这页最容易写成“大量注解参数说明”,但那样其实帮不了你真正落地。
更实际的问题是:如果你已经有一个 Feat Cloud 应用,现在想把它变成一个 MCP 服务,应该从哪种方式开始。
先判断:你需要哪一种 MCP 暴露方式
Section titled “先判断:你需要哪一种 MCP 暴露方式”在 Feat Cloud 里,MCP 大体有两种用法:
默认 MCP 服务器
Section titled “默认 MCP 服务器”当你的 Controller 里出现 @Tool、@Prompt、@Resource 这些注解时,Feat Cloud 可以在编译期帮你生成默认 MCP 服务。
适合:
- 你只是想把少量工具或资源先暴露出去
- 你不打算自定义一整套 MCP 路径
- 你希望先用最少的配置打通能力
自定义 MCP 端点
Section titled “自定义 MCP 端点”如果你需要明确指定 MCP 服务名、SSE 端点、消息端点和流式端点,就用 @McpEndpoint。
适合:
- 你已经把 MCP 当成一个明确的服务能力来设计
- 你希望自己控制端点路径和服务边界
- 你不想完全依赖默认端点行为
从默认方式开始
Section titled “从默认方式开始”如果你只是想先把一个工具暴露给 MCP 客户端,不一定需要自定义服务端点。
下面这种 Controller 已经足够表达一个最小用例:
import tech.smartboot.feat.cloud.annotation.Controller;import tech.smartboot.feat.cloud.annotation.mcp.Tool;import tech.smartboot.feat.cloud.annotation.mcp.Param;
@Controllerpublic class DefaultMcpController {
@Tool(description = "简单的问候工具") public String greeting(@Param(required = true, description = "用户姓名") String name) { return "你好," + name + "!"; }}这类写法的重点不是“看起来像注解示例”,而是它已经足够让编译期生成 MCP 对应服务能力。
什么时候切到自定义端点
Section titled “什么时候切到自定义端点”一旦你开始真正管理一个 MCP 服务,而不是单独抛几个工具,就应该考虑 @McpEndpoint。
仓库里的真实示例是:
import tech.smartboot.feat.ai.mcp.enums.PromptType;import tech.smartboot.feat.ai.mcp.model.ToolResult;import tech.smartboot.feat.cloud.annotation.Controller;import tech.smartboot.feat.cloud.annotation.mcp.McpEndpoint;import tech.smartboot.feat.cloud.annotation.mcp.Prompt;import tech.smartboot.feat.cloud.annotation.mcp.Resource;import tech.smartboot.feat.cloud.annotation.mcp.Tool;import tech.smartboot.feat.cloud.annotation.mcp.Param;
@Controller@McpEndpoint( name = "demo-mcp-service", title = "Demo MCP Service", sseEndpoint = "/mcp/demo/sse", sseMessageEndpoint = "/mcp/demo/sse/message", streamableEndpoint = "/mcp/demo/stream")public class McpDemoController {
@Tool(name = "getUserInfo", description = "根据用户ID获取用户信息") public UserInfo getUserInfo( @Param(required = true, description = "用户ID") Long userId, @Param(required = false, description = "是否包含详细信息") Boolean detailed ) { UserInfo user = new UserInfo(); user.setId(userId); user.setName("User " + userId); user.setEmail(userId + "@example.com"); return user; }
@Prompt( name = "codeReviewPrompt", description = "代码审查提示词", type = PromptType.TEXT ) public String codeReviewPrompt( @Param(required = true, description = "编程语言") String language, @Param(required = true, description = "代码片段") String codeSnippet ) { return String.format("请审查以下%s代码并提供改进建议:%s", language, codeSnippet); }
@Resource( uri = "/resources/coding-standards.md", name = "编码规范", description = "团队编码规范文档", mimeType = "text/markdown", isText = true ) public String codingStandards() { return "# 编码规范"; }
@Tool(description = "获取文本信息") public ToolResult.TextContent getTextInfo() { return ToolResult.ofText("这是文本内容"); }}这段示例已经很能说明问题了:
@Tool暴露可调用能力@Prompt暴露提示模板@Resource暴露文本或二进制资源@McpEndpoint负责把这整组能力挂到一组明确端点上
怎么理解这些注解
Section titled “怎么理解这些注解”把一个方法暴露成 MCP 可调用工具。
如果你的目标是“让模型调用这段业务逻辑”,从这里开始最自然。
@Prompt
Section titled “@Prompt”把一段模板化提示词暴露出去。
更适合“把一套提示结构交给外部 MCP 客户端使用”,而不是普通 Controller 里直接返回文本。
@Resource
Section titled “@Resource”暴露一段文本资源或二进制资源。
适合团队规范、说明文档、静态内容、图片等可被外部读取的材料。
@Param
Section titled “@Param”描述 MCP 工具或提示词参数。
这里的 @Param 不是普通 Controller 查询参数的同一层概念,而是 MCP 参数元信息的一部分。
一个更实用的建议
Section titled “一个更实用的建议”如果你是第一次做 MCP,不要一上来就把 Tool、Prompt、Resource 全部堆在一个大 Controller 里。
更稳的做法通常是:
- 先暴露一个最小 Tool
- 再加一个 Prompt
- 最后再考虑是否需要 Resource
也就是说,先确认“服务能被 MCP 客户端发现和调用”,再扩能力。
什么时候需要 McpServer
Section titled “什么时候需要 McpServer”仓库里也有直接注入 McpServer 的例子,例如 McpToolMainController。
这类写法更适合你在代码里动态管理工具,而不是完全依赖注解生成。
如果你当前只是想把业务能力暴露出去,优先用注解方式。
当你开始需要更精细的控制时,再考虑直接操作 McpServer。
我已经加了注解,但外部看不到 MCP 能力
Section titled “我已经加了注解,但外部看不到 MCP 能力”优先检查:
- 当前类是否真的被 Feat Cloud 扫描到
- 你是否走的是默认 MCP 服务,还是自定义端点
- 相关编译期生成代码是否真的已经产生
@Tool 和普通 Controller 方法是什么关系
Section titled “@Tool 和普通 Controller 方法是什么关系”它们不是二选一的关系。
一个类可以既是普通 Controller,又暴露 MCP 能力,但这时你最好明确它的职责边界,不要把所有事情混在一个超大类里。
我什么时候才应该用 MCP
Section titled “我什么时候才应该用 MCP”当你的目标不只是“做一个 HTTP 接口”,而是“让模型或 MCP 客户端以结构化方式理解并调用我的应用能力”时,MCP 才真正有意义。
- 如果你还没把普通控制器写熟,先回去看 Controller 开发实践
- 如果你准备把 AI 能力和服务端能力结合起来看,再去读 Feat AI 简介
- 如果你只想先完成最小 Web 应用,而不是立刻做 MCP,回到 构建第一个 Feat Cloud 应用