spring-ai mcp server实战

本文主要研究一下如何使用spring-ai-starter-mcp-server进行自定义mcp server

步骤

pom.xml

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

定义prompts/list方法

    /**
     * 必须是list的形式注入才能识别到
     * @return
     */
    @Bean
    public List<McpServerFeatures.SyncPromptSpecification> syncPromptSpecList() {
        return Arrays.asList(demoPromptSpec());
    }

    public McpServerFeatures.SyncPromptSpecification demoPromptSpec() {
        var syncPromptSpecification = new McpServerFeatures.SyncPromptSpecification(
                new McpSchema.Prompt("greeting", "description", List.of(
                        new McpSchema.PromptArgument("name", "description", true)
                )),
                (exchange, request) -> {
                    // Prompt implementation
                    return new McpSchema.GetPromptResult("description", Collections.emptyList());
                }
        );
        return syncPromptSpecification;
    }

定义resources/list方法

    /**
     * 必须是list的形式注入才能识别到,自动识别然后实现resources/list接口
     * @return
     */
    @Bean
    public List<McpServerFeatures.SyncResourceSpecification> resourceSpecList() {
        return listResource();
    }

定义resources/read方法

    public List<McpServerFeatures.SyncResourceSpecification> resourceSpecList() {
        return Arrays.asList(new McpServerFeatures.SyncResourceSpecification(new McpSchema.Resource("mysql://table1/meta", "table1", "meta data", "text/plain", null), (exchange, request) -> {
            // Resource read implementation
            McpSchema.ResourceContents contents = new McpSchema.TextResourceContents(
                    "meta1", "text/plain", "meta"
            );
            return new McpSchema.ReadResourceResult(Arrays.asList(contents));
        }));
    }

定义tools/list方法

    @Bean
    public ToolCallbackProvider dbTools(DemoService demoService) {
        return MethodToolCallbackProvider.builder().toolObjects(demoService).build();
    }

定义tool/call方法

@Service
public class DemoService {
	
	@Tool(description = "demo tool query")
	public String query(String param1) {
		return "hello" + param1;
	}
}

源码

syncTools

org/springframework/ai/mcp/server/autoconfigure/McpServerAutoConfiguration.java

	@Bean
	@ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC",
			matchIfMissing = true)
	public List<McpServerFeatures.SyncToolSpecification> syncTools(ObjectProvider<List<ToolCallback>> toolCalls,
			List<ToolCallback> toolCallbacksList, McpServerProperties serverProperties) {

		List<ToolCallback> tools = new ArrayList<>(toolCalls.stream().flatMap(List::stream).toList());

		if (!CollectionUtils.isEmpty(toolCallbacksList)) {
			tools.addAll(toolCallbacksList);
		}

		return this.toSyncToolSpecifications(tools, serverProperties);
	}

syncTools这一部分把ToolCallback转为SyncToolSpecifications注册到spring中

mcpSyncServer

org/springframework/ai/mcp/server/autoconfigure/McpServerAutoConfiguration.java

	@Bean
	@ConditionalOnProperty(prefix = McpServerProperties.CONFIG_PREFIX, name = "type", havingValue = "SYNC",
			matchIfMissing = true)
	public McpSyncServer mcpSyncServer(McpServerTransportProvider transportProvider,
			McpSchema.ServerCapabilities.Builder capabilitiesBuilder, McpServerProperties serverProperties,
			ObjectProvider<List<SyncToolSpecification>> tools,
			ObjectProvider<List<SyncResourceSpecification>> resources,
			ObjectProvider<List<SyncPromptSpecification>> prompts,
			ObjectProvider<BiConsumer<McpSyncServerExchange, List<McpSchema.Root>>> rootsChangeConsumers,
			List<ToolCallbackProvider> toolCallbackProvider) {

		McpSchema.Implementation serverInfo = new Implementation(serverProperties.getName(),
				serverProperties.getVersion());

		// Create the server with both tool and resource capabilities
		SyncSpecification serverBuilder = McpServer.sync(transportProvider).serverInfo(serverInfo);

		List<SyncToolSpecification> toolSpecifications = new ArrayList<>(tools.stream().flatMap(List::stream).toList());

		List<ToolCallback> providerToolCallbacks = toolCallbackProvider.stream()
			.map(pr -> List.of(pr.getToolCallbacks()))
			.flatMap(List::stream)
			.filter(fc -> fc instanceof ToolCallback)
			.map(fc -> (ToolCallback) fc)
			.toList();

		toolSpecifications.addAll(this.toSyncToolSpecifications(providerToolCallbacks, serverProperties));

		if (!CollectionUtils.isEmpty(toolSpecifications)) {
			serverBuilder.tools(toolSpecifications);
			capabilitiesBuilder.tools(serverProperties.isToolChangeNotification());
			logger.info("Registered tools: " + toolSpecifications.size() + ", notification: "
					+ serverProperties.isToolChangeNotification());
		}

		List<SyncResourceSpecification> resourceSpecifications = resources.stream().flatMap(List::stream).toList();
		if (!CollectionUtils.isEmpty(resourceSpecifications)) {
			serverBuilder.resources(resourceSpecifications);
			capabilitiesBuilder.resources(false, serverProperties.isResourceChangeNotification());
			logger.info("Registered resources: " + resourceSpecifications.size() + ", notification: "
					+ serverProperties.isResourceChangeNotification());
		}

		List<SyncPromptSpecification> promptSpecifications = prompts.stream().flatMap(List::stream).toList();
		if (!CollectionUtils.isEmpty(promptSpecifications)) {
			serverBuilder.prompts(promptSpecifications);
			capabilitiesBuilder.prompts(serverProperties.isPromptChangeNotification());
			logger.info("Registered prompts: " + promptSpecifications.size() + ", notification: "
					+ serverProperties.isPromptChangeNotification());
		}

		rootsChangeConsumers.ifAvailable(consumer -> {
			serverBuilder.rootsChangeHandler((exchange, roots) -> {
				consumer.accept(exchange, roots);
			});
			logger.info("Registered roots change consumer");
		});

		serverBuilder.capabilities(capabilitiesBuilder.build());

		return serverBuilder.build();
	}

mcpSyncServer会把注入的List、List、List、List设置到serverBuilder的tools、resources、prompts中

小结

spring ai mcp server通过McpServerAutoConfiguration把托管给spring的List、List、List、List设置到serverBuilder的tools、resources、prompts中。如果代码要自定义resources、prompts,直接注入List、List即可。tools的话,在托管bean的方法中注解@Tool就可以。

doc

### MCP MySQL Server Configuration and Management #### Overview of MCP MySQL Server Setup For configuring an MCP (Multi-Cloud Platform) environment with a MySQL server, the setup involves ensuring that all necessary configurations are correctly applied to integrate MySQL as part of the data storage solution. In scenarios where applications like Nacos need to connect to a MySQL database, it is crucial to ensure proper initialization and configuration. #### Initialization of MySQL Database for Application Integration When initializing a MySQL database specifically for application integration such as switching from default settings to using MySQL, one can modify `application.properties` or configure during Docker startup[^1]. This ensures that the application connects to the correct MySQL instance configured within the MCP environment. #### Schema Creation for Application Data Persistence To avoid issues related to no datasource exceptions when deploying services on platforms like Nacos via Docker while aiming at persisting data into MySQL, creating databases and tables beforehand is essential. The SQL script located at `D:\software\nacos\nacos-server-2.3.1\conf\mysql-schema.sql` serves this purpose by providing commands needed for setting up schemas required by Nacos[^2]. #### Troubleshooting Common Issues During Deployment In cases similar to those described in experiences involving deployment challenges—such as encountering errors due to missing database creation steps—it becomes evident how critical these preparatory actions are before attempting service deployments. Ensuring that both the database exists along with its schema helps prevent common pitfalls associated with connectivity problems between containers running inside Docker environments and external databases[^3]. ```sql -- Example command to create a new database named 'mcp_db' CREATE DATABASE mcp_db; USE mcp_db; SOURCE D:/software/nacos/nacos-server-2.3.1/conf/mysql-schema.sql; ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值