之前两篇文章:MCP简介和MCP能做什么阐述了MCP的基本概念和原理。
本文将使用Visual Studio Code写一个MCP服务端和MCP客户端,演示MCP的基本功能。
MCP版本迭代很快,能用把代码顺利跑起来并不是一件容易的事:)
准备运行环境
- Windows 10
- Visual studio code 1.104.3
- python 3.12.3
- mcp 1.16.0
- 创建 venv 虚拟环境
- 安装 mcp
激活虚拟环境(windows):
.venv\Scripts\activate
安装mcp
pip install mcp
MCP代码仓库推荐使用
uv工具管理包。由于我之前一直用pip管理包,觉得再用uv比较麻烦,所以没有安装它。
构建MCP服务端
下面的程序使用 FastMCP 构建了一个带有 工具/tool、资源/resource和提示词模板/prompt 的MCP服务端。
本次的服务使用 标准输入输出/Stdio 方式对客户端提供服务,这样MCP客户端加载这个MCP服务端就能完成它们的通信,调试起来比较方便。当然,MCP服务端也可以使用HTTP(支持流式传输)的方式向远端MCP客户端提供服务。
from mcp.server.fastmcp import FastMCP
# Create an MCP server
mcp = FastMCP("Demo MCP Server")
# Add an addition tool
@mcp.tool()
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
# Add a dynamic greeting resource
@mcp.resource("greeting://{name}")
def get_greeting(name: str) -> str:
"""Get a personalized greeting"""
return f"Hello, {name}!"
# Add a prompt
@mcp.prompt()
def greet_user(name: str, style: str = "friendly") -> str:
"""Generate a greeting prompt"""
styles = {
"friendly": "Please write a warm, friendly greeting",
"formal": "Please write a formal, professional greeting",
"casual": "Please write a casual, relaxed greeting",
}
return f"{styles.get(style, styles['friendly'])} for someone named {name}."
def main():
# Initialize and run the server
mcp.run(transport='stdio')
if __name__ == "__main__":
main()
由于没有安装
nv工具,所以这里我们用mcp.run(transport='stdio')明确启动mcp服务端,传输方式采用stdio。
构建MCP客户端
下面的MCP客户端将调用MCP服务端,测试 工具/tool、资源/resource和提示词模板/prompt 。
import asyncio
import os
from pydantic import AnyUrl
from mcp import ClientSession, StdioServerParameters, types
from mcp.client.stdio import stdio_client
# 获取当前文件所在目录的绝对路径
current_dir = os.path.dirname(os.path.abspath(__file__))
print(current_dir)
server_path = os.path.join(current_dir, "fastmcp_server.py")
# Create server parameters for stdio connection
server_params = StdioServerParameters(
command="python",
args=[server_path],
env=None,
)
async def run():
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# Initialize the connection
await session.initialize()
# List available tools
tools = await session.list_tools()
print(f"Available tools: {[t.name for t in tools.tools]}")
# Call a tool
result = await session.call_tool("add", arguments={"a": 5, "b": 3})
result_unstructured = result.content[0]
if isinstance(result_unstructured, types.TextContent):
print(f"Tool result: {result_unstructured.text}")
result_structured = result.structuredContent
print(f"Structured tool result: {result_structured}")
# List available resources
resources = await session.list_resources() # it doesn't work!
print(f"Available resources: {[r.uri for r in resources.resources]}")
# Read a resource
resource_content = await session.read_resource(AnyUrl("greeting://World"))
content_block = resource_content.contents[0]
if isinstance(content_block, types.TextResourceContents):
print(f"Resource content: {content_block.text}")
# List available prompts
prompts = await session.list_prompts()
print(f"Available prompts: {[p.name for p in prompts.prompts]}")
# Get a prompt
if prompts.prompts:
prompt = await session.get_prompt("greet_user", arguments={"name": "Alice", "style": "friendly"})
print(f"Prompt result: {prompt.messages[0].content}")
def main():
"""Entry point for the client script."""
asyncio.run(run())
if __name__ == "__main__":
main()
由于没有使用nv,运行MCP服务端和MCP客户端要多写一些代码,而客户端看起来更复杂一点。
请注意:
- 使用MCP服务端的准确地址:使用绝对路径是比较稳妥的方法,否则可能因为MCP客户端加载MCP服务端失败。
- session.list_resources返回空:不知道为什么无法返回MCP服务端的资源,而直接调用服务端的资源却没问题。
运行代码
在 Visual Studio Code 中运行MCP客户端代码即可,客户端会在启动时加载MCP服务端。
Available tools: ['add']
Tool result: 8
Structured tool result: {'result': 8}
Available resources: []
Resource content: Hello, World!
Available prompts: ['greet_user']
Prompt result: type='text' text='Please write a warm, friendly greeting for someone named Alice.' annotations=None meta=None
总结
以上演示了MCP服务端和MCP客户端的基本功能。对于实际的项目工程来说,这只是一个小小的开始,但是在绝大部分情况下,这种简单的实战演练对“更深入的理解概念和技术”会大有帮助。
代码
本文涉及的所有代码以及相关资源都已经共享,参见:
为便于找到代码,程序文件名称最前面的编号与本系列文章的文档编号相同。
🪐感谢您观看,祝好运🪐