MCP注释服务器

一个基于Spring AI的MCP服务器实现,提供工具、资源、提示和自动补全功能,支持SSE和STDIO传输模式。

  • by Karelgit
  • 本地部署
  • 1 星标
  • 更新于
在 GitHub 查看 Karelgit/mcp-annotations-server

使用说明

Spring AI MCP注释服务器示例

许可证 Java版本

这个示例项目演示了如何使用Spring AI的MCP注释创建MCP服务器。它展示了MCP服务器功能的全面实现,包括使用Java注释的干净、声明性方法的工具、资源、提示和完成。

有关更多信息,请参阅 MCP服务器启动器 参考文件。

目录

概述

该示例展示了一个全面的MCP服务器实现,包括:

  • 与集成 spring-ai-starter-mcp-server-webmvc
  • 支持SSE(服务器发送事件)和STDIO传输
  • 使用注释自动注册MCP功能:
    • @Tool Spring AI工具注册
    • @McpTool 用于MCP特定工具注册
    • @McpResource 用于资源注册
    • @McpPrompt 快速注册
    • @McpComplete 完成注册
  • 每种能力类型的综合示例

特性

此示例演示了:

  1. 天气工具 -使用Spring AI检索天气预报和警报的工具 @Tool 和MCP @McpTool 注释
  2. 用户配置文件资源 -用于访问具有各种URI模式的用户配置文件信息的资源
  3. 快速生成 -针对不同用例的各种提示模板
  4. 自动完成 -用户名和国家的完成建议

依赖项

该项目需要Spring AI MCP服务器WebVC引导启动器和MCP注释:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
</dependency>

这些依赖关系提供:

  • 基于Spring MVC的HTTP传输(WebMvcSseServerTransport)
  • 自动配置的SSE、可流式HTTP或无状态端点,由配置 spring.ai.mcp.server.protocol=... 财产和违约 SSE.
  • 可选STDIO传输,如果 spring.ai.mcp.server.stdio=true 已设置
  • MCP操作的基于注释的方法处理

建设项目

使用Maven构建项目:

./mvnw clean install -DskipTests

运行服务器

服务器支持两种传输模式:

WebVC SSE/流式HTTP/无状态模式

模式取决于 spring.ai.mcp.server.protocol=... 设置。

java -Dspring.ai.mcp.server.protocol=STREAMABLE -jar target/mcp-annotations-server-0.0.1-SNAPSHOT.jar

STDIO模式

要启用STDIO传输,请设置相应的属性:

java -Dspring.ai.mcp.server.stdio=true -Dspring.main.web-application-type=none -jar target/mcp-annotations-server-0.0.1-SNAPSHOT.jar

配置

通过配置服务器 application.properties:

# Server identification
spring.ai.mcp.server.name=my-weather-server
spring.ai.mcp.server.version=0.0.1
spring.ai.mcp.server.protocol=STREAMABLE
# spring.ai.mcp.server.protocol=STATELESS


# Transport configuration (uncomment to enable STDIO)
# spring.ai.mcp.server.stdio=true
# spring.main.web-application-type=none

# Logging (required for STDIO transport)
spring.main.banner-mode=off
# logging.pattern.console=

# Log file location
logging.file.name=./mcp-annotations-server/target/server.log

服务器实现

服务器使用Spring Boot和MCP注释自动注册功能:

@SpringBootApplication
public class McpServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(McpServerApplication.class, args);
    }

    // (Optional) not MCP annotation. Just demostrates how to use the @Tool along with the @McpTool to provision MCP Server Tools.
    @Bean
    public ToolCallbackProvider weatherTools(SpringAiToolProvider weatherService) {
        return MethodToolCallbackProvider.builder().toolObjects(weatherService).build();
    }
}

MCP能力

工具

该项目包括两个不同的工具提供商,展示了不同的注释方法:

SpringAiToolProvider(Spring AI@Tool注释)

使用Spring AI @Tool 天气相关工具的注释:

@Service
public class SpringAiToolProvider {
    @Tool(description = "Get weather forecast for a specific latitude/longitude")
    public String getWeatherForecastByLocation(double latitude, double longitude) {
        // Implementation using weather.gov API
    }

    @Tool(description = "Get weather alerts for a US state. Input is Two-letter US state code (e.g., CA, NY)")
    public String getAlerts(String state) {
        // Implementation using weather.gov API
    }
}

McpToolProvider(MCP@McpTool注释)

使用MCP特定 @McpTool 温度检索注释:

@Service
public class McpToolProvider {
    @McpTool(description = "Get the temperature (in celsius) for a specific location")
    public WeatherResponse getTemperature(McpSyncServerExchange exchange,
            @McpProgressToken String progressToken
            @McpToolParam(description = "The location latitude") double latitude,
            @McpToolParam(description = "The location longitude") double longitude,
            @McpToolParam(description = "The city name") String city) {
        // Implementation using open-meteo.com API
    }
}

可用工具

  1. 天气预报工具 (春天AI)
  • 姓名: getWeatherForecastByLocation
  • 描述:获取特定纬度/经度的天气预报
  • 参数:
    • latitude:双纬度坐标
    • longitude:双经度坐标
  1. 天气警报工具 (春天AI)
  • 姓名: getAlerts
  • 描述:获取美国某个州的天气警报
  • 参数:
    • state:String-两个字母的美国州代码(例如,CA、NY)
  1. 温度工具 (MCP)
  • 姓名: getTemperature
  • 描述:获取特定位置的温度(单位:摄氏度)
  • 参数:
    • latitude:double-位置纬度
    • longitude:double-位置经度
    • city:String-城市名称

资源

这 UserProfileResourceProvider 使用实现资源访问 @McpResource 带综合示例的注释:

@Service
public class UserProfileResourceProvider {
    @McpResource(uri = "user-profile://{username}", 
                name = "User Profile", 
                description = "Provides user profile information for a specific user")
    public ReadResourceResult getUserProfile(ReadResourceRequest request, String username) {
        // Implementation to retrieve user profile
    }
    
    // Additional resource methods...
}

可用资源

  1. 用户档案
  • URI: user-profile://{username}
  • 描述:为特定用户提供用户配置文件信息
  1. 用户详细信息
  • URI: user-profile://{username}
  • 描述:使用URI变量提供用户详细信息
  1. 用户属性
  • URI: user-attribute://{username}/{attribute}
  • 描述:提供用户配置文件中的特定属性
  1. Exchange用户配置文件
  • URI: user-profile-exchange://{username}
  • 描述:提供具有服务器交换上下文的用户配置文件
  1. 用户连接
  • URI: user-connections://{username}
  • 描述:为用户提供连接列表
  1. 用户通知
  • URI: user-notifications://{username}
  • 说明:为用户提供通知
  1. 用户状态
  • URI: user-status://{username}
  • 描述:提供用户的当前状态
  1. 用户位置
  • URI: user-location://{username}
  • 描述:为用户提供当前位置
  1. 用户头像
  • URI: user-avatar://{username}
  • 描述:为用户提供base64编码的头像图像
  • MIME类型: image/png

示例用户数据

提供者为用户提供了示例数据: john, jane, bob,以及 alice 配置文件包含姓名、电子邮件、年龄和位置信息。

提示

这 PromptProvider 使用实现提示生成 @McpPrompt 注释:

@Service
public class PromptProvider {
    @McpPrompt(name = "greeting", description = "A simple greeting prompt")
    public GetPromptResult greetingPrompt(
            @McpArg(name = "name", description = "The name to greet", required = true) String name) {
        // Implementation to generate greeting prompt
    }
    
    // Additional prompt methods...
}

可用提示

  1. 问候
  • 姓名: greeting
  • 描述:一个简单的问候提示
  • 参数:
    • name:String-要问候的名字(必填)
  1. 个性化消息
  • 姓名: personalized-message
  • 描述:根据用户信息生成个性化消息
  • 参数:
    • name:String-用户名(必填)
    • age:Integer-用户的年龄(可选)
    • interests:String-用户的兴趣(可选)
  1. 话题开启者
  • 姓名: conversation-starter
  • 说明:提供与系统的对话启动器
  1. 地图参数
  • 姓名: map-arguments
  • 说明:演示如何使用映射作为参数
  1. 单一消息
  • 姓名: single-message
  • 描述:演示返回单个PromptMessage
  • 参数:
    • name:String-用户名(必填)
  1. 字符串列表
  • 姓名: string-list
  • 说明:演示返回字符串列表
  • 参数:
    • topic:String-提供信息的主题(必填)

补全

这 AutocompleteProvider 使用实现自动完成 @McpComplete 注释:

@Service
public class AutocompleteProvider {
    @McpComplete(uri = "user-status://{username}")
    public List<String> completeUsername(String usernamePrefix) {
        // Implementation to provide username completions
    }
    
    // Additional completion methods...
}

可用完工量

  1. 用户名填写
  • URI: user-status://{username}
  • 根据前缀为用户名提供完成建议
  1. 名称完成
  • 提示: personalized-message
  • 在个性化消息提示中为姓名提供完成建议
  1. 国家名称填写
  • 提示: travel-planner
  • 提供国家名称的填写建议
  • 退货: CompleteResult 附竣工详图

MCP客户端

您可以使用STDIO或SSE传输连接到服务器:

启动启动器客户端

为了获得更好的开发体验,请考虑使用 MCP客户端启动程序 及相关的 MCP客户端注释 支持。

MCP客户端引导启动器提供:

  • MCP客户端连接的自动配置
  • 基于声明性注释的服务器通知处理程序
  • 支持多种传输协议(SSE、流式HTTP、STDIO)
  • 客户端处理程序的自动注册

客户端依赖

将MCP客户端引导启动器添加到您的项目中:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-starter-mcp-client</artifactId>
</dependency>

客户端注释

客户端支持多种注释来处理服务器通知:

  • @McpLogging -处理来自MCP服务器的日志消息通知
  • @McpProgress -处理长时间运行的操作的进度通知
  • @McpSampling -处理来自MCP服务器的LLM完成采样请求
  • @McpElicitation -处理启发请求,从用户那里收集更多信息
  • @McpToolListChanged -处理服务器工具列表更改时的通知
  • @McpResourceListChanged -处理服务器资源列表更改时的通知
  • @McpPromptListChanged -当服务器的提示列表更改时处理通知

重要:所有MCP客户端注释 必须 包含一个 clients 参数,用于将处理程序与特定的MCP客户端连接相关联。

客户端实现示例

@SpringBootApplication
public class McpClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(McpClientApplication.class, args).close();
    }

    @Bean
    public CommandLineRunner predefinedQuestions(List<McpSyncClient> mcpClients) {
        return args -> {
            for (McpSyncClient mcpClient : mcpClients) {
                System.out.println(">>> MCP Client: " + mcpClient.getClientInfo());

               // Call a tool that sends progress notifications
               CallToolRequest toolRequest = CallToolRequest.builder()
                     .name("tool1")
                     .arguments(Map.of("input", "test input"))
                     .progressToken("test-progress-token")
                     .build();

               CallToolResult response = mcpClient.callTool(toolRequest);

               System.out.println("Tool response: " + response);
            }
        };
    }
}

客户端处理程序提供者

@Service
public class McpClientHandlerProviders {

    private static final Logger logger = LoggerFactory.getLogger(McpClientHandlerProviders.class);

    @McpProgress(clients = "server1")
    public void progressHandler(ProgressNotification progressNotification) {
        logger.info("MCP PROGRESS: [{}] progress: {} total: {} message: {}",
                progressNotification.progressToken(), progressNotification.progress(),
                progressNotification.total(), progressNotification.message());
    }

    @McpLogging(clients = "server1")
    public void loggingHandler(LoggingMessageNotification loggingMessage) {
        logger.info("MCP LOGGING: [{}] {}", loggingMessage.level(), loggingMessage.data());
    }

    @McpSampling(clients = "server1")
    public CreateMessageResult samplingHandler(CreateMessageRequest llmRequest) {
        logger.info("MCP SAMPLING: {}", llmRequest);
        String userPrompt = ((McpSchema.TextContent) llmRequest.messages().get(0).content()).text();
        String modelHint = llmRequest.modelPreferences().hints().get(0).name();

        return CreateMessageResult.builder()
                .content(new McpSchema.TextContent("Response " + userPrompt + " with model hint " + modelHint))
                .build();
    }

    @McpElicitation(clients = "server1")
    public ElicitResult elicitationHandler(McpSchema.ElicitRequest request) {
        logger.info("MCP ELICITATION: {}", request);
        return new ElicitResult(ElicitResult.Action.ACCEPT, Map.of("message", request.message()));
    }
}

客户端配置

在中配置客户端连接 application.properties:

spring.application.name=mcp
spring.main.web-application-type=none

# Streamable-HTTP transport configuration
spring.ai.mcp.client.streamable-http.connections.server1.url=http://localhost:8080

# SSE transport configuration (alternative)
# spring.ai.mcp.client.sse.connections.server1.url=http://localhost:8080

# Global client settings
spring.ai.mcp.client.request-timeout=5m

# Logging configuration
logging.level.io.modelcontextprotocol.client=WARN
logging.level.io.modelcontextprotocol.spec=WARN

# Optional: Disable tool callback if not needed
# spring.ai.mcp.client.toolcallback.enabled=false

运行客户端示例

流式HTTP(HttpClient)传输
  1. 启动MCP注释服务器:
java -Dspring.ai.mcp.server.protocol=STREAMABLE -jar mcp-annotations-server-0.0.1-SNAPSHOT.jar
  1. 在另一个控制台中,启动配置了Streamable HTTP传输的客户端:
java -Dspring.ai.mcp.client.streamable-http.connections.server1.url=http://localhost:8080 \
 -jar mcp-annotations-client-0.0.1-SNAPSHOT.jar
苏格兰和南方能源公司运输
  1. 使用SSE协议启动MCP注释服务器:
java -Dspring.ai.mcp.server.protocol=SSE -jar mcp-annotations-server-0.0.1-SNAPSHOT.jar
  1. 启动配置了SSE传输的客户端:
java -Dspring.ai.mcp.client.sse.connections.server1.url=http://localhost:8080 \
 -jar mcp-annotations-client-0.0.1-SNAPSHOT.jar

注: 这 clients="server1" 参数 @McpLogging, @McpSampling, @McpProgress 和 @McpElicitate 注释与您在文档中输入的连接名称相对应 spring.ai.mcp.client.streamable-http.connections.server1.url= 或 spring.ai.mcp.client.sse.connections.server1.url= 配置。

STDIO传输
  1. 创建一个 mcp-servers-config.json 配置文件:
{
  "mcpServers": {
    "annotations-server": {
      "command": "java",
      "args": [
        "-Dspring.ai.mcp.server.stdio=true",
        "-Dspring.main.web-application-type=none",
        "-Dlogging.pattern.console=",
        "-jar",
        "/absolute/path/to/mcp-annotations-server-0.0.1-SNAPSHOT.jar"
      ]
    }
  }
}
  1. 使用配置文件运行客户端:
java -Dspring.ai.mcp.client.stdio.servers-configuration=file:mcp-servers-config.json \
 -Dlogging.pattern.console= \
 -jar mcp-annotations-client-0.0.1-SNAPSHOT.jar

客户端将自动:

  • 连接到已配置的MCP服务器
  • 基于以下内容注册带注释的处理程序 clients 参数
  • 通过带注释的方法处理服务器通知和请求
  • 按配置提供日志记录和进度更新

其他资源

🔗连接mcp方式

{
  "mcpServers": {
    "annotations-server": {
      "command": "java",
      "args": [
        "-Dspring.ai.mcp.server.stdio=true",
        "-Dspring.main.web-application-type=none",
        "-Dlogging.pattern.console=",
        "-jar",
        "/Users/karel/CursorProjects/mcp-annotations-server/target/mcp-annotations-server-0.0.1-SNAPSHOT.jar"
      ]
    }
  }
}

{
  "mcpServers": {
    "annotations-server": {
      "url": "http://localhost:8080/sse"
    }
  }
}

mcp注释服务器