远程MCP
申明
-
python语言请使用fastmcp,蓝心九问mcp客户端主要适配了fastmcp,其他sdk可能会出现不兼容。
-
java语言建议使用蓝心九问自研transport(stateless-http),适用于java8,java17可以使用官方sdk。
streamable-http(Python语言推荐)
streamable-http是mcp官方推出的最新远程mcp transport,用于取代sse transport。
streamable-http transport支持有状态和无状态两种模式,蓝心九问只支持无状态模式。
配置
{
"url": "http://127.0.0.1:8000/mcp",
"transport": "streamable-http",
"includeTools":[
"get_weather"
],
"excludeTools":[
"get_weather"
],
"headers":{
"auth": "app-T2zO4lHcuaykPcyICIUBJwkd"
}
}配置说明
| 参数 | 说明 |
|---|---|
| url | 远程服务地址 |
| transport | mcp transport,写死streamable-http |
| headers | 请求头,按需要设置 |
| includeTools | 只引入某些工具 |
| excludeTools | 排除某些工具 |
includeTools与excludeTools可以都不设置,但是不能同时设置。
服务端示例代码
下面是使用FastMCP构建streamable-http mcp服务,stateless_http、json_response均设置为true。
from pydantic import Field
from fastmcp.server import FastMCP
mcp = FastMCP(stateless_http=True, json_response=True, port=8000)
@mcp.tool(description="获取指定城市,指定时间的天气信息")
async def get_weather(
city: str = Field(description="需要查询天气的城市"),
date: str = Field(description="需要查询天气的日期")
) -> dict:
return {"city": city, "date": date}
if __name__ == '__main__':
mcp.run(transport="streamable-http")建议: mcp工具方法需要返回一个dict
stateless_http说明
streamable-http是否使用无状态,默认为False(有状态),有状态模式下,如果mcp服务部署了多台实例,那么需要自行解决session复制问题
所以,建议将FastMCP的stateless_http设置为True,采用无状态模式
json_response说明
mcp接口是流式返回还是json返回,默认为流式返回,建议将FastMCP的json_response参数设置为True。
但是,1.11.0之后的mcp存在问题(Streamable_ ttp. py shows warning · Issue #1294 · modelcontextprotocol/python-sdk · GitHub)。
所以mcp版本建议安装1.11.0或者之前的版本,1.11.0之后的版本可以将json_response设置为False。
如何获取header参数
from mcp.server.fastmcp.server import Context
@mcp.tool(description="获取指定城市,指定时间的天气信息")
async def get_weather(context:Context) -> dict:
auth = context.request_context.request.headers.get("auth")
return {"auth": auth}mcp方法上存在Context类型参数时,在运行时mcp会自动注入改参数
如何获取系统参数
系统参数指的是蓝心九问平台参数,例如用户工号、登录态信息等,详情如下:
| 系统参数 | 类型 | 说明 |
|---|---|---|
| sys_openid | str | 工号,只有需要登录的场景才有 |
| sys_uuc_info | dict | 登录态信息, 包含token、uucToken、uuid |
| sys_from_debug | bool | 是否来自调试 |
蓝心九问系统参数采用申明注入的方式(只要申明的参数名与系统参数名一致就会自动注入改参数),如下:
@mcp.tool(description="获取指定城市,指定时间的天气信息")
async def get_weather(
sys_openid:str,
sys_uuc_info:dict,
sys_from_debug:bool,
) -> dict:
return {}stateless-http(Java语言推荐)
mcp官方提供的mcp sdk需要Java17。
stateless-http是蓝心九问开发的基于spring mvc的mcp transport。
pom依赖
<dependency>
<groupId>com.vivo.internet</groupId>
<artifactId>mcp-service-sdk</artifactId>
<version>1.0.1-SNAPSHOT</version>
</dependency>启动配置
import mcp.configuration.McpServerConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import(McpServerConfiguration.class)
public class McpConfiguration {
}McpConfiguration不是sdk提供的类,需要自己创建。
服务开发
基于FastMCP注解快速构建mcp服务。
@Component
@FastMCP("test")
public class SdkMcpService {
@McpTool(desc = "天气查询工具")
public Map<String, Object> getWeather(@ToolParam(desc = "城市") String city,
@ToolParam(desc = "查询开始日期") String start,
@ToolParam(desc = "查询结束日期") String end) {
return new HashMap<String, Object>() {{
put("city", city);
put("start", start);
put("end", end);
}};
}
@McpTool(desc = "保存用户")
public Map<String, Object> saveUser(@ToolParam(desc = "用户") User user) {
return new HashMap<String, Object>() {{
put("user", user);
}};
}
@McpTool(desc = "批量保存用户")
public Map<String, Object> saveUsers(@ToolParam(desc = "用户列表") List<User> users) {
return new HashMap<String, Object>() {{
put("users", users);
}};
}
}注解说明
| 参数 | 说明 |
|---|---|
| FastMCP | 将spring bean申明为一个mcp服务,参数为mcp服务请求路径 |
| McpTool | 将spring bean中的public方法申明为mcp工具 |
| ToolParam | 辅助定义参数 |
| HeaderParam | 注入header |
| SysParam | 注入系统参数,系统参数与streamable-http transport一致 |
参数类型
mcp工具方法参数支持下面类型及其java.util.List类型。
| 类型 | 说明 |
|---|---|
| Short(short) | 数值类型 |
| Integer(int) | 数值类型 |
| Long(long) | 数值类型 |
| Float(float) | 浮点型 |
| Double(double) | 浮点型 |
| Boolean(boolean) | 布尔型 |
| Enum | 枚举类型 |
| Map | 字典类型 |
| mcp.registry.ToolParamDefinition | 自定义类型 |
自定义类型
在mcp中自定义类型需要实现mcp.registry.ToolParamDefinition接口,如下:
public class User implements ToolParamDefinition {
@ToolParam(desc = "id")
private Integer id;
@ToolParam(desc = "name")
private String name;
@ToolParam(desc = "爱好", defaultProvider = DefaultProviders.HobbyProvider.class)
private List<String> hobbies;
}同样,可以使用@ToolParam注解来辅助申明类属性。
类之间的依赖不能成环,不然服务启动时会栈溢出。
参数默认值
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ToolParam {
String name() default "";
String desc() default "";
String defaultValue() default "@$@";
String[] _enums() default {};
Class<? extends DefaultProvider> defaultProvider() default NullDefaultProvider.class;
}ToolParam注解提供了两种为参数提供默认值的方式。
-
defaultValue: 该属性值作为默认值,适用于int、boolean等简单类型。
-
defaultProvider: 实现DefaultProvider接口,接口get的返回值作为属性默认值,适用于复杂默认值的构建。
-
_enums: 定义该参数的取值范围,提供_enums时,该参数类型只能为数值类型或者字符串。
返回申明
mcp工具方法返回支持下面几种类型:
-
void: 方法不返回任何数据。
-
java.util.Map: mcp工具方法返回java.util.Map实现。
-
自定义类型: mcp工具方法返回自定义类型,该类型可以通过序列化+反序列化转化为java.util.Map。
调试
以上述@FastMCP("test")为例。
工具列表
直接访问 http://127.0.0.1:8080/mcp-sdk/test/tool-list, 能够正常返回mcp列表则表示mcp已通。
{
"success": true,
"toolList": [
{
"name": "test_tool",
"description": "测试工具",
"inputSchema": {
"type": "object",
"properties": {
"id": {
"type": "integer",
"description": "id"
}
},
"required": [
"id"
]
},
"outputSchema": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "name"
}
},
"required": [
"name"
]
}
}
]
}stateless-http通过在spring mvc上增加接口实现,路径为:mcp-sdk/xxx/xxx 拦截器、过滤器需要对该路径放行
工具调用
调用下面接口
url: http://127.0.0.1:8080/mcp-sdk/test/tool-call
method: POST
arguments:
{
"name":"test_tool",
"arguments":{
"id": 10086
}
}配置
{
"url": "http://127.0.0.1:8080/mcp-sdk/test",
"transport": "stateless-http",
"includeTools":[
"get_weather"
],
"excludeTools":[
"get_weather"
],
"headers":{
"auth":"app-T2zO4lHcuaykPcyICIUBJwkd"
}
}配置说明
| 参数 | 说明 |
|---|---|
| url | 服务地址 + mcp-sdk + @FastMCP参数 |
| transport | mcp transport,写死stateless-http |
| headers | 请求头,按需要设置 |
| includeTools | 只引入某些工具 |
| excludeTools | 排除某些工具 |
includeTools与excludeTools可以都不设置,但是不能同时设置。
sse(不推荐)
sse transport是mcp官方最早发布的远程mcp transport,长连接、有状态。因为有状态,服务端在集群部署时需要解决会话问题。
配置
{
"url": "http://127.0.0.1:8000/sse",
"transport": "sse",
"includeTools":[
"get_weather"
],
"excludeTools":[
"get_weather"
],
"headers":{
"auth":"app-T2zO4lHcuaykPcyICIUBJwkd"
}
}配置说明
| 参数 | 说明 |
|---|---|
| url | 远程服务地址 |
| transport | mcp transport,写死sse |
| headers | 请求头,按需要设置 |
| includeTools | 只引入某些工具 |
| excludeTools | 排除某些工具 |
includeTools与excludeTools可以都不设置,但是不能同时设置。
有状态
sse transport是有状态协议,如果服务部署了多台实例需要自己解决session复制问题。
服务端示例代码
from pydantic import Field
from fastmcp.server import FastMCP
mcp = FastMCP(port=8000)
@mcp.tool(description="获取指定城市,指定时间的天气信息")
async def get_weather(
city: str = Field(description="需要查询天气的城市"),
date: str = Field(description="需要查询天气的日期")
) -> dict:
return {"city": city, "date": date}
if __name__ == '__main__':
mcp.run(transport="sse")建议: mcp工具方法需要返回一个dict 系统参数、header参数使用方式与streamable-http transport一样。