Mcp server和Client开发以及使用方法
·
本文档以实现一个贷款利息计算器为示例说明mcp的用法。
server 代码
#!/usr/bin/env python3
"""MCP Server implementation for Loan Calculator."""
import asyncio
import math
from typing import Any
from mcp.server.models import InitializationOptions
from mcp.server import NotificationOptions, Server
from mcp.server.stdio import stdio_server
from mcp.types import (
Tool,
TextContent,
)
# 创建MCP Server实例
server = Server("loan-calculator-server")
def calculate_loan_equal_principal_interest(principal: float, years: int, annual_rate: float) -> dict[str, Any]:
"""
计算等额本息贷款的月供、总利息和本息合计。
等额本息:每月还款额固定,前期利息多、本金少,后期逐渐反转。
Args:
principal: 贷款本金(元)
years: 贷款期限(年)
annual_rate: 年利率(百分比,如 4.5 表示 4.5%)
Returns:
包含计算结果的字典
"""
# 将年利率转换为月利率(小数形式)
monthly_rate = annual_rate / 100 / 12
# 贷款总月数
months = years * 12
# 计算月供(等额本息公式)
# 月供 = [本金 × 月利率 × (1 + 月利率)^还款月数] / [(1 + 月利率)^还款月数 - 1]
if monthly_rate == 0:
monthly_payment = principal / months
else:
monthly_payment = (principal * monthly_rate * (1 + monthly_rate) ** months) / \
((1 + monthly_rate) ** months - 1)
# 计算总还款额
total_payment = monthly_payment * months
# 计算总利息
total_interest = total_payment - principal
return {
"monthly_payment": round(monthly_payment, 2),
"monthly_payment_first": round(monthly_payment, 2),
"monthly_payment_last": round(monthly_payment, 2),
"monthly_payment_decline": 0,
"total_interest": round(total_interest, 2),
"total_payment": round(total_payment, 2),
"principal": principal,
"years": years,
"annual_rate": annual_rate,
"method": "等额本息"
}
def calculate_loan_equal_principal(principal: float, years: int, annual_rate: float) -> dict[str, Any]:
"""
计算等额本金贷款的月供、总利息和本息合计。
等额本金:每月还本金固定,利息逐月递减,首月还款最高。
Args:
principal: 贷款本金(元)
years: 贷款期限(年)
annual_rate: 年利率(百分比,如 4.5 表示 4.5%)
Returns:
包含计算结果的字典
"""
# 将年利率转换为月利率(小数形式)
monthly_rate = annual_rate / 100 / 12
# 贷款总月数
months = years * 12
# 每月偿还本金
monthly_principal = principal / months
# 首月利息 = 全部本金 × 月利率
first_month_interest = principal * monthly_rate
# 末月利息 = 剩余本金 × 月利率 = (每月本金) × 月利率
last_month_interest = monthly_principal * monthly_rate
# 首月还款 = 每月本金 + 首月利息
first_month_payment = monthly_principal + first_month_interest
# 末月还款 = 每月本金 + 末月利息
last_month_payment = monthly_principal + last_month_interest
# 每月还款递减额 = 每月本金 × 月利率
monthly_decline = monthly_principal * monthly_rate
# 总利息 = (首月利息 + 末月利息) × 月数 / 2
total_interest = (first_month_interest + last_month_interest) * months / 2
# 总还款额 = 本金 + 总利息
total_payment = principal + total_interest
return {
"monthly_payment": round((first_month_payment + last_month_payment) / 2, 2),
"monthly_payment_first": round(first_month_payment, 2),
"monthly_payment_last": round(last_month_payment, 2),
"monthly_payment_decline": round(monthly_decline, 2),
"total_interest": round(total_interest, 2),
"total_payment": round(total_payment, 2),
"principal": principal,
"years": years,
"annual_rate": annual_rate,
"method": "等额本金"
}
def calculate_loan(principal: float, years: int, annual_rate: float,
repayment_method: str = "等额本息") -> dict[str, Any]:
"""
计算贷款月供、总利息和本息合计。
Args:
principal: 贷款本金(元)
years: 贷款期限(年)
annual_rate: 年利率(百分比,如 4.5 表示 4.5%)
repayment_method: 还款方式,"等额本息" 或 "等额本金"
Returns:
包含计算结果的字典
"""
if repayment_method == "等额本金":
return calculate_loan_equal_principal(principal, years, annual_rate)
else:
return calculate_loan_equal_principal_interest(principal, years, annual_rate)
def format_result(result: dict[str, Any]) -> str:
"""格式化计算结果为易读的字符串。"""
method = result['method']
if method == "等额本金":
return f"""贷款计算结果({method})
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
贷款本金:¥{result['principal']:,.2f} 元
贷款期限:{result['years']} 年 ({result['years'] * 12} 个月)
年利率:{result['annual_rate']}%
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
首月还款:¥{result['monthly_payment_first']:,.2f} 元
末月还款:¥{result['monthly_payment_last']:,.2f} 元
每月递减:¥{result['monthly_payment_decline']:,.2f} 元
总利息:¥{result['total_interest']:,.2f} 元
本息合计:¥{result['total_payment']:,.2f} 元
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"""
else:
return f"""贷款计算结果({method})
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
贷款本金:¥{result['principal']:,.2f} 元
贷款期限:{result['years']} 年 ({result['years'] * 12} 个月)
年利率:{result['annual_rate']}%
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
每月还款:¥{result['monthly_payment']:,.2f} 元(固定)
总利息:¥{result['total_interest']:,.2f} 元
本息合计:¥{result['total_payment']:,.2f} 元
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"""
@server.list_tools()
async def list_tools() -> list[Tool]:
"""列出可用的工具。"""
return [
Tool(
name="calculate_loan",
description="计算贷款的月供、总利息和本息合计。支持等额本息(每月还款固定)和等额本金(首月最高,逐月递减)两种还款方式。",
inputSchema={
"type": "object",
"properties": {
"principal": {
"type": "number",
"description": "贷款本金,单位:元(例如:100000 表示10万元)"
},
"years": {
"type": "integer",
"description": "贷款期限,单位:年(例如:30 表示30年)"
},
"annual_rate": {
"type": "number",
"description": "年利率,单位:%(例如:4.5 表示4.5%)"
},
"repayment_method": {
"type": "string",
"description": "还款方式:等额本息(每月还款固定)或等额本金(首月最高,逐月递减),默认为等额本息",
"enum": ["等额本息", "等额本金"],
"default": "等额本息"
}
},
"required": ["principal", "years", "annual_rate"]
}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict[str, Any]) -> list[TextContent]:
"""处理工具调用。"""
if name == "calculate_loan":
try:
principal = float(arguments["principal"])
years = int(arguments["years"])
annual_rate = float(arguments["annual_rate"])
repayment_method = arguments.get("repayment_method", "等额本息")
# 参数验证
if principal <= 0:
return [TextContent(
type="text",
text="错误:贷款本金必须大于0"
)]
if years <= 0:
return [TextContent(
type="text",
text="错误:贷款期限必须大于0"
)]
if annual_rate < 0:
return [TextContent(
type="text",
text="错误:年利率不能为负数"
)]
if repayment_method not in ["等额本息", "等额本金"]:
return [TextContent(
type="text",
text="错误:还款方式必须是'等额本息'或'等额本金'"
)]
result = calculate_loan(principal, years, annual_rate, repayment_method)
return [TextContent(
type="text",
text=format_result(result)
)]
except KeyError as e:
return [TextContent(
type="text",
text=f"错误:缺少必需参数 {e}"
)]
except (ValueError, TypeError) as e:
return [TextContent(
type="text",
text=f"错误:参数类型不正确 - {e}"
)]
except Exception as e:
return [TextContent(
type="text",
text=f"计算错误:{e}"
)]
return [TextContent(
type="text",
text=f"未知工具: {name}"
)]
async def main():
"""启动MCP Server。"""
async with stdio_server() as (read_stream, write_stream):
await server.run(
read_stream,
write_stream,
InitializationOptions(
server_name="loan-calculator-server",
server_version="0.1.0",
capabilities=server.get_capabilities(
notification_options=NotificationOptions(),
experimental_capabilities={}
)
)
)
if __name__ == "__main__":
asyncio.run(main())
client-1.py 代码 (直接调用)
"""MCP Client for Loan Calculator - 直接调用MCP工具"""
import asyncio
import os
from dotenv import load_dotenv
from mcp.client.session import ClientSession
from mcp.client.stdio import stdio_client, StdioServerParameters
# 加载环境变量
load_dotenv()
async def main():
"""直接调用MCP Server的贷款计算工具"""
# 连接到MCP Server(通过stdio)
server_params = StdioServerParameters(
command="uv",
args=[
"run",
"python",
"-m",
"mcp_server_client.server"
],
env=os.environ.copy()
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# 初始化
await session.initialize()
# 列出可用工具
tools = await session.list_tools()
print("=" * 50)
print("可用的工具:")
for tool in tools.tools:
print(f" - {tool.name}: {tool.description}")
print("=" * 50)
print()
# 示例1: 计算100万贷款,30年,4.5%利率
print("示例1: 贷款100万,30年,年利率4.5%")
print("-" * 50)
result = await session.call_tool(
"calculate_loan",
arguments={
"principal": 1000000,
"years": 30,
"annual_rate": 4.5
}
)
for content in result.content:
print(content.text)
print()
# 示例2: 计算50万贷款,20年,3.8%利率
print("示例2: 贷款50万,20年,年利率3.8%")
print("-" * 50)
result = await session.call_tool(
"calculate_loan",
arguments={
"principal": 500000,
"years": 20,
"annual_rate": 3.8
}
)
for content in result.content:
print(content.text)
print()
# 示例3: 计算200万贷款,25年,4.2%利率
print("示例3: 贷款200万,25年,年利率4.2%")
print("-" * 50)
result = await session.call_tool(
"calculate_loan",
arguments={
"principal": 2000000,
"years": 25,
"annual_rate": 4.2
}
)
for content in result.content:
print(content.text)
if __name__ == "__main__":
asyncio.run(main())
client-2 代码 (LLM调用mcp工具)
#!/usr/bin/env python3
"""MCP Client for Loan Calculator - 结合DeepSeek大模型调用"""
import asyncio
import json
import os
from dotenv import load_dotenv
from mcp.client.session import ClientSession
from mcp.client.stdio import stdio_client, StdioServerParameters
from openai import AsyncOpenAI
# 加载环境变量
load_dotenv()
DEEPSEEK_API_KEY = os.getenv("DEEPSEEK_API_KEY")
DEEPSEEK_BASE_URL = "https://api.deepseek.com"
async def main():
"""使用DeepSeek大模型结合MCP Server进行智能贷款计算咨询"""
# 初始化DeepSeek客户端
client = AsyncOpenAI(
api_key=DEEPSEEK_API_KEY,
base_url=DEEPSEEK_BASE_URL
)
# 连接到MCP Server
server_params = StdioServerParameters(
command="uv",
args=[
"run",
"python",
"-m",
"mcp_server_client.server"
],
env=os.environ.copy()
)
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
# 初始化MCP会话
await session.initialize()
# 获取可用工具
tools = await session.list_tools()
print("=" * 50)
print("MCP Server 工具列表:")
for tool in tools.tools:
print(f" - {tool.name}: {tool.description}")
print("=" * 50)
print()
# 将MCP工具转换为OpenAI函数格式
mcp_tools = [
{
"type": "function",
"function": {
"name": "calculate_loan",
"description": "计算贷款的月供、总利息和本息合计(等额本息还款方式)",
"parameters": {
"type": "object",
"properties": {
"principal": {
"type": "number",
"description": "贷款本金,单位:元(例如:100000 表示10万元)"
},
"years": {
"type": "integer",
"description": "贷款期限,单位:年(例如:30 表示30年)"
},
"annual_rate": {
"type": "number",
"description": "年利率,单位:%(例如:4.5 表示4.5%)"
}
},
"required": ["principal", "years", "annual_rate"]
}
}
}
]
# 示例对话
questions = [
"我想贷款100万元买房,贷款30年,年利率4.5%,请帮我计算每月需要还款多少钱?总共利息是多少?",
"如果我有50万预算,贷款20年,年利率3.8%,月供多少?和30年贷款相比有什么区别?",
]
for i, question in enumerate(questions, 1):
print(f"问题 {i}: {question}")
print("-" * 50)
# 调用DeepSeek
response = await client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": "你是一个专业的贷款计算助手。当用户询问贷款相关问题时,使用calculate_loan工具来计算准确的数字。计算完成后,用友好的方式解释结果给用户。"},
{"role": "user", "content": question}
],
tools=mcp_tools,
tool_choice="auto"
)
# 处理响应
message = response.choices[0].message
# 如果需要调用工具
if message.tool_calls:
for tool_call in message.tool_calls:
if tool_call.function.name == "calculate_loan":
# 解析参数
function_args = json.loads(tool_call.function.arguments)
# 调用MCP工具
result = await session.call_tool(
"calculate_loan",
arguments=function_args
)
# 获取工具结果
tool_result = result.content[0].text
print(tool_result)
print()
# 让DeepSeek解释结果
explanation_response = await client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": "你是一个专业的贷款计算助手。请用友好的方式解释贷款计算结果。"},
{"role": "user", "content": question},
{"role": "assistant", "content": None, "tool_calls": [tool_call]},
{"role": "tool", "content": tool_result, "tool_call_id": tool_call.id}
]
)
print("AI 解释:")
print(explanation_response.choices[0].message.content)
else:
print(message.content)
print("\n" + "=" * 50 + "\n")
# 交互式问答
print("进入交互模式(输入 'quit' 退出):")
print("=" * 50)
while True:
user_input = input("\n请输入您的问题: ").strip()
if user_input.lower() in ['quit', 'exit', '退出']:
print("再见!")
break
if not user_input:
continue
response = await client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": "你是一个专业的贷款计算助手。当用户询问贷款相关问题时,使用calculate_loan工具来计算准确的数字。计算完成后,用友好的方式解释结果给用户。"},
{"role": "user", "content": user_input}
],
tools=mcp_tools,
tool_choice="auto"
)
message = response.choices[0].message
if message.tool_calls:
for tool_call in message.tool_calls:
if tool_call.function.name == "calculate_loan":
function_args = json.loads(tool_call.function.arguments)
result = await session.call_tool(
"calculate_loan",
arguments=function_args
)
tool_result = result.content[0].text
print("\n计算结果:")
print(tool_result)
print()
explanation_response = await client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": "你是一个专业的贷款计算助手。请用友好的方式解释贷款计算结果。"},
{"role": "user", "content": user_input},
{"role": "assistant", "content": None, "tool_calls": [tool_call]},
{"role": "tool", "content": tool_result, "tool_call_id": tool_call.id}
]
)
print("AI 解释:")
print(explanation_response.choices[0].message.content)
else:
print(f"\n回答: {message.content}")
if __name__ == "__main__":
asyncio.run(main())
更多推荐



所有评论(0)