用MCP实现一个简单的Client + Server计算工具

你是不是经常有这种想法:我写了个Python脚本,能不能让另一个脚本来远程调用它?又或者,我想写一个可以随时调用的小工具,别老每次都跑一堆代码……那你真的可以试试 MCP(Modular Communication Protocol)。它让你不用搞复杂的网络协议、服务部署啥的,就能让多个Python程序之间愉快“对话”。

而且我跟你说,真的超简单,连我这种不搞后端的都能一次性跑起来。这篇教程我就按最小白的方式,手把手带你从0到1,把一个“计算器服务”搭出来。你只要照着一步步来,肯定能搞定!

一、准备环境:安装MCP

只要你电脑上有 Python(建议版本 3.8+),第一步就是打开终端(Windows用CMD或者PowerShell,Mac/Linux直接Terminal)运行:

    
bash
pip install mcp

这行命令会自动帮你把 MCP 所有需要的依赖装好。

ai_tutorial_mcp_case_Client_Server_1

装完以后,就可以开始写代码啦!

二、先写 MCP 服务端(Server)

我们先来做一个“服务端”,功能很简单:你告诉它一个数学表达式,它给你返回答案。

步骤1:新建一个文件,命名为 server_demo.py

用你喜欢的编辑器打开这个文件,比如 VSCode、PyCharm,或者直接用记事本也行。

ai_tutorial_mcp_case_Client_Server_2

然后复制下面这段代码进去:

    
python
# server_demo.py 修改版
import math
import re
from typing import Dict, List, Union, Optional
from mcp.server.fastmcp import FastMCP

# 创建一个 MCP 服务实例
mcp = FastMCP("高级计算器服务")

# 存储计算历史
calculation_history = []

@mcp.tool()
def calculate(expression: str) -> float:
    """
    输入一个数学表达式,返回计算结果
    例如:'1 + 2 * 3' => 7
    """
    # 安全检查:只允许合法的数学表达式
    if not is_safe_expression(expression):
        return f"错误:不安全的表达式 '{expression}'"
    
    try:
        # 使用更安全的方式计算表达式
        result = safe_eval(expression)
        
        # 记录历史
        calculation_history.append({"expression": expression, "result": result})
        
        return float(result)
    except Exception as e:
        return f"计算错误: {str(e)}"

@mcp.tool()
def advanced_math(operation: str, value: float, second_value: Optional[float] = None) -> float:
    """
    执行高级数学运算
    
    参数:
    - operation: 运算类型,可选值: 'sqrt'(平方根), 'pow'(幂), 'sin', 'cos', 'log'
    - value: 要计算的数值
    - second_value: 某些运算需要的第二个值(例如幂运算)
    
    例如: advanced_math('sqrt', 16) => 4.0
    """
    try:
        if operation == 'sqrt':
            if value < 0:
                return "错误: 不能计算负数的平方根"
            result = math.sqrt(value)
        elif operation == 'pow':
            if second_value is None:
                return "错误: 幂运算需要提供第二个参数"
            result = math.pow(value, second_value)
        elif operation == 'sin':
            result = math.sin(value)
        elif operation == 'cos':
            result = math.cos(value)
        elif operation == 'log':
            if value <= 0:
                return "错误: 对数运算的值必须为正数"
            if second_value is not None and second_value > 0:
                result = math.log(value, second_value)  # 自定义底数
            else:
                result = math.log(value)  # 自然对数
        else:
            return f"错误: 不支持的运算 '{operation}'"
        
        # 记录历史
        calculation_history.append({
            "operation": operation, 
            "value": value,
            "second_value": second_value,
            "result": result
        })
        
        return float(result)
    except Exception as e:
        return f"计算错误: {str(e)}"

@mcp.tool()
def get_calculation_history() -> List[Dict[str, Union[str, float]]]:
    """
    获取计算历史记录
    
    返回最近的计算历史列表
    """
    return calculation_history[-10:] if calculation_history else []

@mcp.tool()
def clear_history() -> str:
    """
    清除计算历史记录
    """
    global calculation_history
    calculation_history = []
    return "历史记录已清除"

def is_safe_expression(expr: str) -> bool:
    """检查表达式是否安全,只允许基本数学运算"""
    # 只允许数字、基本运算符和一些数学函数
    allowed_pattern = r'^[\d\s\+\-\*\/\(\)\.\,\^\%]+$'
    return bool(re.match(allowed_pattern, expr))

def safe_eval(expr: str) -> float:
    """更安全的表达式求值方法"""
    # 替换幂运算符号为Python语法
    expr = expr.replace('^', '**')
    
    # 定义允许的数学函数和常量
    safe_dict = {
        'abs': abs,
        'round': round,
        'min': min,
        'max': max,
        'pi': math.pi,
        'e': math.e
    }
    
    # 使用限制的命名空间计算表达式
    return eval(expr, {"__builtins__": {}}, safe_dict)

# 启动 MCP Server - 修改为支持HTTP/WebSocket传输
if __name__ == "__main__":
    import sys
    if len(sys.argv) > 1 and sys.argv[1] == "--inspector":
        # 当通过Inspector启动时,使用HTTP传输
        mcp.run(transport='http', port=6275)
    else:
        # 默认使用stdio传输
        mcp.run(transport='stdio')

是不是很简单?重点在 @mcp.tool() 这句,它会自动把 calculate 方法注册成 MCP 能识别的工具。客户端就可以远程调用这个函数了!

三、再写 MCP 客户端(Client)

客户端就是你启动去调用“服务端”的部分。

步骤2:新建另一个文件,叫 client_demo.py

ai_tutorial_mcp_case_Client_Server_3

复制下面的内容进去:

    
python
# client_demo.py
from mcp.client.stdio import stdio_client
from mcp import ClientSession, StdioServerParameters
import asyncio
import os

# 设置 Server 启动参数
server_params = StdioServerParameters(
    command="python",
    args=["./server_demo.py"],  # 注意这里的路径要根据你自己保存的位置来改
    env=None
)

async def main():
    print("=== MCP 高级计算器客户端 ===")
    print("正在连接到计算器服务...")
    
    try:
        async with stdio_client(server_params) as (read, write):
            async with ClientSession(read, write) as session:
                await session.initialize()
                print("连接成功!\n")
                
                while True:
                    print("\n选择功能:")
                    print("1. 基本计算")
                    print("2. 高级数学运算")
                    print("3. 查看历史记录")
                    print("4. 清除历史记录")
                    print("0. 退出程序")
                    
                    choice = input("\n请选择 (0-4): ")
                    
                    if choice == '0':
                        print("谢谢使用,再见!")
                        break
                    
                    elif choice == '1':
                        expression = input("\n请输入数学表达式 (例如: 2 + 3 * 4): ")
                        print(f"计算: {expression}")
                        try:
                            result = await session.call_tool("calculate", {"expression": expression})
                            print(f"结果: {result.content}")
                        except Exception as e:
                            print(f"调用出错: {e}")
                    
                    elif choice == '2':
                        print("\n高级数学运算")
                        print("可用操作: sqrt(平方根), pow(幂), sin, cos, log")
                        operation = input("请输入操作类型: ")
                        
                        try:
                            value = float(input("请输入第一个值: "))
                            second_value = None
                            
                            if operation == 'pow' or operation == 'log':
                                second_value = float(input("请输入第二个值: "))
                                result = await session.call_tool(
                                    "advanced_math", 
                                    {
                                        "operation": operation, 
                                        "value": value,
                                        "second_value": second_value
                                    }
                                )
                            else:
                                result = await session.call_tool(
                                    "advanced_math", 
                                    {
                                        "operation": operation, 
                                        "value": value
                                    }
                                )
                            
                            print(f"结果: {result.content}")
                        except ValueError:
                            print("错误: 请输入有效的数字")
                        except Exception as e:
                            print(f"调用出错: {e}")
                    
                    elif choice == '3':
                        try:
                            result = await session.call_tool("get_calculation_history", {})
                            history = result.content
                            
                            if not history:
                                print("\n历史记录为空")
                            else:
                                print("\n=== 计算历史记录 ===")
                                for i, entry in enumerate(history, 1):
                                    if "expression" in entry:
                                        print(f"{i}. 表达式: {entry['expression']} = {entry['result']}")
                                    else:
                                        op_str = f"{entry['operation']}({entry['value']}"
                                        if entry['second_value'] is not None:
                                            op_str += f", {entry['second_value']}"
                                        op_str += ")"
                                        print(f"{i}. 高级运算: {op_str} = {entry['result']}")
                        except Exception as e:
                            print(f"获取历史记录失败: {e}")
                    
                    elif choice == '4':
                        try:
                            result = await session.call_tool("clear_history", {})
                            print(result.content)
                        except Exception as e:
                            print(f"清除历史记录失败: {e}")
                    
                    else:
                        print("无效的选择,请重试")
                    
                    input("\n按回车键继续...")
                    # 清屏
                    os.system('cls' if os.name == 'nt' else 'clear')
                    
    except Exception as e:
        print(f"连接服务器失败: {e}")
        print("请确保 server_demo.py 文件路径正确,且已安装所有依赖")

# 运行主函数
if __name__ == "__main__":
    asyncio.run(main())

这个脚本会自动调用 Server 并传一个表达式进去,然后返回结果。

四、开始运行:验证是否通了!

确保你现在这两个文件都写好了:

  • server_demo.py
  • client_demo.py

ai_tutorial_mcp_case_Client_Server_4

然后,直接在终端运行:

    
bash
python client_demo.py

ai_tutorial_mcp_case_Client_Server_5

是不是很神奇?你就会看到它打印:

    
发送表达式:188 * 23 - 34
结果是:4300.0

搞定!现在你已经成功用 MCP 连接了一个服务端和客户端,而且还完成了一次远程调用!

五、可视化调试 MCP Server(推荐!)

有时候你写完 Server 想先测试一下,不想写 Client,这时候 MCP 提供了一个调试神器:MCP Inspector

首先我们先要先安装一下uv:

    
pip install uv

然后你在命令行里运行:

    
bash
mcp dev server_demo.py

ai_tutorial_mcp_case_Client_Server_6

如果报错了:

    
Error: typer is required. Install with 'pip install mcp[cli]'

ai_tutorial_mcp_case_Client_Server_7

那么就先运行:

    
pip install mcp[cli]

然后浏览器打开:

    
http://localhost:6274

ai_tutorial_mcp_case_Client_Server_8

你就会进入一个超好用的界面,你可以直接点工具、填参数、点调用,看返回结果。

ai_tutorial_mcp_case_Client_Server_9

开发调试都超方便!

最后

我一开始以为搞客户端和服务端通讯会特别麻烦,得写 socket、搞接口、处理协议啥的,但用了 MCP 才发现,原来都帮你封装好了,连 transport 都默认支持 stdio。写起来像写普通 Python 脚本一样轻松,最适合做一些自动化工具、AI插件,甚至插件市场那种轻服务都可以搞一搞。

MCP 真的是一个小而美的协议框架,你动手写一遍就懂了。而且文档和调试工具都还挺友好的,不会让人踩坑。

阅读全文
RPA
八爪鱼RPA
支持一键抓取公众号/小红书/抖音/淘宝数据
立即查看
流程自动化
付费
AI爆文训练营
图文变现友好赛道,低门槛、高上限,教你从0到1做个赚钱的公众号!
立即查看
躺着赚钱
¥149/年
何老师陪你做副业
这里聚焦AI副业、个人IP、自媒体运营、写作、赚钱案例。不哔哔,只分享有价值的副业项目。
立即查看
AI赚钱案例
限免
DeepSeek进阶教程
带你全面掌握DeepSeek应用技巧。提升工作、学习效率
立即查看
100万人学过
付费
网盘拉新实战教程
每周花费一小时,手把手教你赚网盘平台佣金
立即查看
500人学过
限时优惠
AiPPT
结合最新AI技术,为用户提供一键生成高质量PPT的解决方案。
立即查看
一键生成 PPT
免费
豆包MarsCode
一款免费的AI编程助手,全新支持DeepSeek R1/V3、豆包大模型1.5自由切换,免部署、更准确、更强大!
立即查看
AI编程助手
免费
Monica AI
Monica AI满血复活DeepSeek【免费】,提升您的聊天、搜索、写作和编程体验。
立即查看
一站式 AI 助手
云服务
腾讯云
综合性的云计算服务平台,现已接入DeepSeek,提供多样化的云解决方案
立即查看
高效可靠
云服务
阿里云
全球领先的云计算与数据服务平台,提供云服务器、存储、数据库、安全等多种服务
立即查看
多样化
DeepSeek企业微信码
免费领取DeepSeek资料