在"Hello, MCP",我们采用HTTP传输协议搭建了一个简单FastMCP服务器,并直接采用HTTP请求的形式完整MCP的基本操作,包括读取组件列表、调用工具、读取资源和渲染提示词等操作。接下来我们来演示其他两种交互方法,一是使用fastmcp命令行,而是以编程的方式是客户端SDK。
1. 搭建MCP服务器
我们直接使用"Hello, MCP"中搭建的服务器,相关代码如下:
python
from fastmcp import FastMCP
mcp = FastMCP("Greeting")
@mcp.tool()
async def greet(name: str) -> str:
"""Get a greeting message for the given name"""
return f"Hi, {name}!"
@mcp.resource("greeting://everyone")
async def greet_everyone() -> str:
"""Get a greeting message for everyone"""
return f"Hey, everyone!"
@mcp.resource("greeting://{name}")
async def greet_to_name(name: str) -> str:
"""Get a greeting message for the given name"""
return f"Hello, {name}!"
@mcp.prompt()
async def greet_prompt(name: str) -> str:
"""Get a greeting message for the given name"""
return f"Hi, {name}!"
mcp.run(transport="http", host="0.0.0.0", port=3721)
在根据名称Greeting创建了代表MCP服务器的FastMCP对象之后,我们利用该对象的三种装饰器方法注册了四种典型的组件:
- greet:利用
@mcp.tool装饰器注册的工具; - greet_everyone: 利用
@mcp.resource装饰器注册的静态文本资源,表示绑定于固定URI的单个资源; - greet_to_name:利用
@mcp.resource装饰器注册的动态资源模板,表示绑定于URI模板的一组资源; - greet_prompt:利用
@mcp.prompt装饰器注册的提示词(模板);
然后我们调用FastMCP的run方法启动服务器。为了方便后面的演示,我们设置了如下四个参数:
- transport:将传输协议设置为HTTP,那么我们就可以单纯地发送HTTP请求的方式与MCP服务交互了;
- host: 设置成"0.0.0.0",那么我们可以利用localhost、127.0.0.1以及绑定的主机名和真实IP地址访问MCP服务器;
- port:显式指定的端口号3721,默认为8000;
2 以命令行的方法与MCP服务器交互
FastMCP提供了同名的CLI,所以我们可以以命令行的形式与MCP服务器交互。比如我们通过如下的方式读取工具列表。
shell
PS C:\Users\jinnan> fastmcp list http://localhost:3721/mcp
Tools (1)
greet(name: str) -> dict
Get a greeting message for the given name
可以进一步添加命令行开关--input-schema和--output-schema显式工具输入和输出Schema。
shell
PS C:\Users\jinnan> fastmcp list http://localhost:3721/mcp --input-schema --output-schema
Tools (1)
greet(name: str) -> dict
Get a greeting message for the given name
Input: {"additionalProperties": false, "properties": {"name": {"type": "string"}}, "required": ["name"], "type": "object"}
Output: {"properties": {"result": {"type": "string"}}, "required": ["result"], "type": "object", "x-fastmcp-wrap-result": true}
如果希望看到工具更多细节,可以添加--json开关以JSON格式输出工具信息。
shell
PS C:\Users\jinnan> fastmcp list http://localhost:3721/mcp --json
{
"tools": [
{
"name": "greet",
"description": "Get a greeting message for the given name",
"inputSchema": {
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"outputSchema": {
"properties": {
"result": {
"type": "string"
}
},
"required": [
"result"
],
"type": "object",
"x-fastmcp-wrap-result": true
}
}
]
}
如果进一步添加命令行开关--resources --prompts,可以列出资源和提示词,不过貌似只能显式静态资源。
shell
PS C:\Users\jinnan> fastmcp list http://localhost:3721/mcp --json --resources --prompts
{
"tools": [
{
"name": "greet",
"description": "Get a greeting message for the given name",
"inputSchema": {
"additionalProperties": false,
"properties": {
"name": {
"type": "string"
}
},
"required": [
"name"
],
"type": "object"
},
"outputSchema": {
"properties": {
"result": {
"type": "string"
}
},
"required": [
"result"
],
"type": "object",
"x-fastmcp-wrap-result": true
}
}
],
"resources": [
{
"uri": "greeting://everyone",
"name": "greet_everyone",
"description": "Get a greeting message for everyone",
"mimeType": "text/plain"
}
],
"prompts": [
{
"name": "greet_prompt",
"description": "Get a greeting message for the given name",
"arguments": [
{
"name": "name",
"description": null,
"required": true
}
]
}
]
}
我们还可以执行按照如下的方式执行fastmcp call命令调用工具greet,并将参数name指定为MCP。关于fastmcp cli的详细用法,可以参考官方文档。
shell
PS C:\Users\jinnan> fastmcp call http://localhost:3721/mcp greet name=MCP --json
{
"content": [
{
"type": "text",
"text": "Hi, MCP!"
}
],
"is_error": false,
"structured_content": {
"result": "Hi, MCP!"
}
}
3 利用FastMCP客户端SDK
fastmcp库还提供了客户端SDK,我们利用它不仅仅可以采用单纯的请求-响应模式完成诸如读取组件和调用工具这样的操作,还能提供接收并处理来自服务端的请求和通知。MCP是一个涉及服务端和客户端双边协议,fastmcp客户端SDK是MCP客户端协议的实现。
对于上面构建的MCP服务器,我们可以根据其URL(http://localhost:3721/mcp)创建一个`Client`对象,并调用其`list_tools`、`list_resources`、`list_resource_templates`和`list_prompts`方法读取工具、静态资源、动态资源模板和提示词(模板)列表。
python
import asyncio
from fastmcp import Client
client = Client("http://localhost:3721/mcp")
async def main():
async with client:
tools = await client.list_tools()
print(f"Tools ({len(tools)}):",end="")
for tool in tools:
print(f"""
name: {tool.name}
description: {tool.description}
input_schema: {tool.inputSchema}
output_schema: {tool.outputSchema}""")
resources = await client.list_resources()
print(f"\nResources ({len(resources)}):",end="")
for resource in resources:
print(f"""
name: {resource.name}
description: {resource.description}
mimeType: {resource.mimeType}""")
resource_templates = await client.list_resource_templates()
print(f"\nResource Templates ({len(resource_templates)}):",end="")
for template in resource_templates:
print(f"""
name: {template.name}
description: {template.description}
mimeType: {template.mimeType}""")
prompts = await client.list_prompts()
print(f"\nPrompts ({len(prompts)}):",end="")
for prompt in prompts:
print(f"""
name: {prompt.name}
description: {prompt.description}
arguments: {prompt.arguments}""")
if __name__ == "__main__":
asyncio.run(main())
输出:
Tools (1):
name: greet
description: Get a greeting message for the given name
input_schema: {'additionalProperties': False, 'properties': {'name': {'type': 'string'}}, 'required': ['name'], 'type': 'object'}
output_schema: {'properties': {'result': {'type': 'string'}}, 'required': ['result'], 'type': 'object', 'x-fastmcp-wrap-result': True}
Resources (1):
name: greet_everyone
description: Get a greeting message for everyone
mimeType: text/plain
Resource Templates (1):
name: greet_to_name
description: Get a greeting message for the given name
mimeType: text/plain
Prompts (1):
name: greet_prompt
description: Get a greeting message for the given name
arguments: [PromptArgument(name='name', description=None, required=True)]
我们还可以按照如下的方式调用Client对象的call_tool方法调用工具,调用read_resource方法读取指定URI的资源,以及调用get_prompt方法完整指定提示词的渲染。
python
import asyncio
from typing import cast
from fastmcp import Client
from mcp.types import TextResourceContents
client = Client("http://localhost:3721/mcp")
async def main():
async with client:
result = await client.call_tool("greet", {"name": "MCP"})
print("Tool call result:",end="")
print(f"""
content: {result.content}
data: {result.data}
structured_content: {result.structured_content}
is_error: {result.is_error}
""")
resource = cast(list[TextResourceContents], await client.read_resource("greeting://MCP"))[0]
print("Resource:", end="")
print(f"""
uri: {resource.uri}
mimeType: {resource.mimeType}
text: {resource.text}
""")
propmpt = await client.get_prompt(name ="greet_prompt",arguments= {"name": "MCP"})
print("Prompt:", end="")
print(f"""
description: {propmpt.description}
messages: {propmpt.messages}
""")
if __name__ == "__main__":
asyncio.run(main())
输出:
Tool call result:
content: [TextContent(type='text', text='Hi, MCP!', annotations=None, meta=None)]
data: Hi, MCP!
structured_content: {'result': 'Hi, MCP!'}
is_error: False
Resource:
uri: greeting://MCP
mimeType: text/plain
text: Hello, MCP!
Prompt:
description: Get a greeting message for the given name
messages: [PromptMessage(role='user', content=TextContent(type='text', text='Hi, MCP! This is a prompt response.', annotations=None, meta=None))]