20 KiB
MCP for CRM — 工具说明文档
服务对象:汽车零部件(小型阀体外壳)智能报价智能体 服务定位:CRM 侧客户/询价/报价/商机数据服务(业务写入 + 只读回读 + 受限清理) 版本:v1.1(2026-08-09)
1 服务概览
| 项 | 值 |
|---|---|
| 服务名 | mcp-for-crm-auto |
| 框架 | MCPServer(mcp 2.0.0 内置高级框架),@app.tool() 装饰器注册 |
| 传输协议 | Streamable HTTP(JSON-RPC 2.0) |
| 远程端点 | https://crm-data.dongsk.top/mcp |
| 本地端点 | http://0.0.0.0:8002/mcp(cd src && python3 server.py) |
| 数据库 | PostgreSQL 15+,库 smart_quotation_auto(仅服务层内部经 db.py 连接池访问) |
| 工具数 | 10 个 = 6 个业务工具 + 4 个验证/管理工具 |
工具一览
| # | 工具 | 功能 | 类型 | 报价环节 |
|---|---|---|---|---|
| 1 | get_customer_info |
查询客户信用/折扣/账期 | 只读 | Step 2 客户查询 |
| 2 | create_inquiry |
创建询价单 | 写入 | Step 7 存档 |
| 3 | save_quotation |
保存报价单(自动版本+1) | 写入(事务) | Step 7 存档 |
| 4 | get_quotation_history |
历史报价/版本链查询 | 只读 | Step 7 前置检查 |
| 5 | update_opportunity |
创建/更新商机 | 写入 | Step 7 存档 |
| 6 | get_inquiry_info |
询价单整行回读 | 只读 | 存档后验证 |
| 7 | get_opportunity_info |
商机回读 | 只读 | 存档后验证 |
| 8 | get_record_counts |
三表行数统计 | 只读 | 数据卫生检查 |
| 9 | purge_test_records |
受限测试数据清理 | 写入(带防护) | 回归测试清理 |
| 10 | save_quotation_mock |
报价写入 CRM(Mock 模拟) | 写入(独立 mock 表) | 模拟报价写入 CRM |
单号与状态约定
| 实体 | 单号规则 | 状态机 |
|---|---|---|
| 询价单 | INQ-2026-NNNN(自增) |
pending → quoted(首次报价自动推进) |
| 报价单 | QUO-2026-NNNN(自增) |
draft → superseded(被新版替代);won / lost 为终态,受保护 |
| 商机 | OPP-2026-NNNN(自增) |
lead → quoted → won / lost |
2 调用约定
2.1 客户端注册(mcpServers)
{
"mcpServers": {
"crm": { "url": "https://crm-data.dongsk.top/mcp" }
}
}
2.2 兜底命令行客户端(纯标准库)
python3 scripts/mcp_http_client.py crm <工具名> '<JSON参数>'
# 示例
python3 scripts/mcp_http_client.py crm get_customer_info '{"customer_code":"OEM-2024-003"}'
2.3 返回通用约定
- 所有工具返回 JSON 字符串(
ensure_ascii=False,中文不转义)。 - 查询类:
{"total": N, "<集合名>": [...]};写入/操作类:{"success": true|false, ...}。 - 失败统一形态:
{"success": false, "message": "<原因>"}。 - 金额字段(decimal 列)在 JSON 中为字符串,如
"180000.00";日期YYYY-MM-DD。 - 日期入参格式必须为
YYYY-MM-DD,否则返回格式错误。
3 业务工具详解(6 个)
3.1 get_customer_info — 查询客户信息
功能:按客户编码精确查询,或按名称、OEM 层级模糊搜索。返回信用等级、折扣率、账期、历史订单统计,用于报价前的客户校验与商务条款确定。
入参(全部可选;全部不传 = 返回全表):
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
customer_code |
string | 否 | — | 客户编码,精确匹配,如 OEM-2024-003 |
name |
string | 否 | — | 客户名称,%模糊% 匹配 |
oem_tier |
string | 否 | — | 层级精确匹配:OEM / Tier1 / Tier2 |
返回字段:
| 字段 | 类型 | 说明 |
|---|---|---|
total |
int | 命中条数 |
customers[].customer_code |
string | 客户编码 |
customers[].name |
string | 客户名称 |
customers[].oem_tier |
string | OEM / Tier1 / Tier2 |
customers[].credit_level |
string | 信用等级 A/B/C/D 或「无评级」 |
customers[].discount_rate |
decimal | 折扣率(字符串,如 "0.040" = 4%) |
customers[].payment_days |
int | 账期天数(月结 N 天) |
customers[].contact_person / phone / email |
string | 联系人信息 |
customers[].industry / region |
string | 行业 / 区域 |
customers[].total_orders |
int | 历史订单数 |
customers[].total_amount |
decimal | 历史订单总额 |
customers[].notes |
string | 备注 |
返回示例:
{
"total": 1,
"customers": [
{
"customer_code": "OEM-2024-003",
"name": "某新能源主机厂",
"oem_tier": "OEM",
"credit_level": "A",
"discount_rate": "0.040",
"payment_days": 60,
"contact_person": "刘工",
"phone": "0551-2222-0005",
"email": "liu@oem-nev.example.com",
"industry": "汽车",
"region": "合肥",
"total_orders": 22,
"total_amount": "9800000.00",
"notes": "新能源三电系统配套,增长快",
"created_at": "2026-08-07 17:31:56.244396"
}
]
}
3.2 create_inquiry — 创建询价记录
功能:客户提交询价后建档。校验客户存在性,自动生成 INQ-2026-NNNN 单号,初始状态 pending。
入参:
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
customer_code |
string | 是 | — | 客户编码(不存在则失败) |
drawing_number |
string | 否 | null | 图纸号 |
part_number |
string | 否 | null | 零件号 |
annual_volume |
int | 否 | null | 年用量(件/年) |
target_price |
float | 否 | null | 客户目标价 ¥ |
notes |
string | 否 | null | 备注 |
返回字段:
| 字段 | 类型 | 说明 |
|---|---|---|
success |
bool | 成功标记 |
inquiry_id |
string | 生成的询价单号 |
customer_name |
string | 客户名称 |
status |
string | 固定 pending |
message |
string | 提示信息 |
失败返回:{"success": false, "message": "未找到客户 XXX"}
返回示例:
{
"success": true,
"inquiry_id": "INQ-2026-0028",
"customer_name": "某新能源主机厂",
"status": "pending",
"message": "询价记录 INQ-2026-0028 已创建"
}
业务规则:同一询价单可多次创建(每次生成新单号);「同一询价单多次报价」通过 3.3 save_quotation 的版本机制实现,不重复建档。
3.3 save_quotation — 保存报价单(多版本核心)
功能:报价存档核心工具。同一询价单不限报价次数,版本号自动 MAX+1;旧版非终态自动置 superseded;首报自动推询价单 pending → quoted;won 终态保护(仍存档但带 warning)。事务内完成:作废旧版 → 推询价状态 → 写报价主表 → 写成本明细表。
入参:
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
inquiry_id |
string | 是 | — | 询价单号(不存在则失败并提示先建档) |
customer_code |
string | 是 | — | 客户编码(不存在则失败) |
mold_cost |
float | 是 | — | 模具费 ¥(一次性) |
unit_price |
float | 是 | — | 单价 ¥ |
annual_volume |
int | 是 | — | 年用量 |
material_cost |
float | 是 | — | 材料成本 ¥/件 |
casting_cost |
float | 是 | — | 压铸成本 ¥/件 |
machining_cost |
float | 是 | — | 机加工成本 ¥/件 |
post_process_cost |
float | 是 | — | 后处理成本 ¥/件 |
overhead_rate |
float | 否 | 0.12 | 管理费率 |
profit_rate |
float | 否 | 0.15 | 利润率 |
tax_rate |
float | 否 | 0.13 | 税率 |
payment_terms |
string | 否 | 月结30天 |
付款条款 |
delivery_terms |
string | 否 | 含税含运 |
交付条款 |
valid_days |
int | 否 | 30 | 报价有效天数(自当日起) |
remarks |
string | 否 | null | 备注 |
返回字段:
| 字段 | 类型 | 说明 |
|---|---|---|
success |
bool | 成功标记 |
quotation_id |
string | 生成的报价单号 |
status |
string | 固定 draft(草稿,待人工审核后发出) |
version |
int | 本次版本号(自动递增) |
previous_quotation_id |
string|null | 上一版报价单号(首报为 null) |
price_change_pct |
float|null | 较上版价差百分比(首报为 null) |
summary.mold_cost / unit_price / annual_volume |
float/int | 回显 |
summary.total_annual |
float | 年总额 = 单价×年用量 |
summary.tax_rate |
string | 税率百分比字符串,如 "13%" |
summary.tax_amount |
float | 税额 |
summary.total_amount |
float | 含税总额 |
summary.currency |
string | 固定 CNY |
valid_until |
string | 有效期至 YYYY-MM-DD |
warning |
string(可选) | 存在中标旧版时的提示 |
message |
string | 提示信息 |
返回示例(第 2 版议价):
{
"success": true,
"quotation_id": "QUO-2026-0029",
"status": "draft",
"version": 2,
"previous_quotation_id": "QUO-2026-0028",
"price_change_pct": -3.0,
"summary": {
"mold_cost": 180000,
"unit_price": 42.7,
"annual_volume": 80000,
"total_annual": 3416000.0,
"tax_rate": "13%",
"tax_amount": 444080.0,
"total_amount": 3860080.0,
"currency": "CNY"
},
"valid_until": "2026-09-08",
"message": "报价单 QUO-2026-0029(第 2 版)已保存为草稿,待人工审核后发出"
}
业务规则:
- 版本链查询用 3.4;
won/lost终态永不被 superseded 覆盖。 - 并发安全由数据库
(inquiry_id, version)唯一约束兜底。 - 草稿态报价单在 HTML 上带「草稿·待人工审核」水印,人工审核后才可发出。
3.4 get_quotation_history — 查询历史报价
功能:历史报价与版本链查询,用于再报价前置检查(有没有报过、上一版多少钱)与价格一致性校验。同一询价单按版本号降序返回,并逐行标记 is_latest。
入参(全部可选):
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
customer_code |
string | 否 | — | 按客户筛选 |
inquiry_id |
string | 否 | — | 按询价单筛选 |
start_date |
string | 否 | — | 报价日期起,YYYY-MM-DD |
end_date |
string | 否 | — | 报价日期止,YYYY-MM-DD |
status |
string | 否 | — | 状态筛选:draft/superseded/won/lost |
latest_only |
bool | 否 | false | true 时每个询价单仅返回最新一版 |
返回字段:
| 字段 | 类型 | 说明 |
|---|---|---|
total |
int | 命中条数 |
quotations[] |
array | 报价行(quotation 全字段 + customer_name) |
quotations[].version |
int | 版本号 |
quotations[].status |
string | 状态 |
quotations[].is_latest |
bool | 是否为该询价单最新版本(全表口径,不受筛选影响) |
quotations[].cost_detail |
object | 成本明细(四项成本 + 费率 + total_cost + unit_price) |
返回示例(INQ-2026-0019 三版议价链,latest_only=true):
{
"total": 1,
"quotations": [
{
"quotation_id": "QUO-2026-0018",
"inquiry_id": "INQ-2026-0019",
"customer_code": "OEM-2024-002",
"quotation_date": "2026-08-07",
"valid_until": "2026-09-06",
"version": 3,
"status": "draft",
"mold_cost": "180000.00",
"unit_price": "41.50",
"annual_volume": 80000,
"customer_name": "某商用车主机厂",
"is_latest": true,
"cost_detail": { "...": "四项成本与费率" }
}
]
}
注意:日期参数格式错误(非 YYYY-MM-DD)会抛出解析异常,调用方应保证格式。
3.5 update_opportunity — 创建/更新商机
功能:双模式。传 opportunity_id = 更新已有商机的阶段/金额/概率等字段(仅更新非 null 字段);不传 opportunity_id = 按 customer_code + title 新建商机(默认 stage=lead、probability=20、expected_amount=0,source=智能报价自动生成)。
入参:
| 参数 | 类型 | 必填 | 默认 | 说明 |
|---|---|---|---|---|
opportunity_id |
string | 否 | — | 商机号(传入则走更新模式) |
customer_code |
string | 新建时必填 | — | 客户编码 |
title |
string | 新建时必填 | — | 商机标题 |
stage |
string | 否 | 新建时 lead |
阶段:lead/quoted/won/lost |
expected_amount |
float | 否 | 新建时 0 | 预期金额 ¥ |
probability |
int | 否 | 新建时 20 | 成交概率 % |
oem_program |
string | 否 | — | OEM 项目/平台 |
expected_close_date |
string | 否 | — | 预期关单日期 YYYY-MM-DD |
notes |
string | 否 | — | 备注(保留参数) |
返回字段:
| 字段 | 类型 | 说明 |
|---|---|---|
success |
bool | 成功标记 |
opportunity_id |
string | 商机号(更新时为传入值,新建时为生成值) |
message |
string | 「已更新」或「已创建」 |
失败返回:
{"success": false, "message": "expected_close_date 格式错误:...,应为 YYYY-MM-DD"}{"success": false, "message": "未找到商机 OPP-2026-XXXX"}{"success": false, "message": "新建商机需要提供 customer_code 和 title"}{"success": false, "message": "未找到客户 XXX"}
返回示例(新建):
{
"success": true,
"opportunity_id": "OPP-2026-0019",
"message": "商机 OPP-2026-0019 已创建"
}
3.6 save_quotation_mock — 报价写入 CRM(Mock 模拟)
用途:模拟「报价写入 CRM」动作。写入独立 mock 表 quotation_mock,不校验客户/询价单/商机,与其他工具无任何关联,适合演示与联调场景单独调用。
入参:
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
part_name |
string | ✅ | — | 零件名称 |
unit_price |
number | ✅ | — | 报价单价 |
customer_name |
string | — | null | 客户名称(自由文本,不做存在性校验) |
part_number |
string | — | null | 零件号 |
material_grade |
string | — | null | 材质牌号 |
mold_cost |
number | — | 0.0 | 模具费 |
annual_volume |
integer | — | null | 年用量(提供时自动计算 total_annual = unit_price × annual_volume) |
currency |
string | — | CNY | 币种 |
remarks |
string | — | null | 备注 |
返回示例:
{
"success": true,
"quotation_id": "QUO-MOCK-0001",
"status": "draft",
"summary": {
"part_name": "变速箱阀体外壳", "unit_price": 41.66, "mold_cost": 180000.0,
"annual_volume": 300000, "total_annual": 12498000.0, "currency": "CNY"
},
"message": "报价单 QUO-MOCK-0001 已写入 CRM mock 表(quotation_mock)"
}
关键说明:
- 单号
QUO-MOCK-####自增,独立于正式QUO-2026-####序列。 quotation_mock表无外键,写入不影响正式三表(inquiry/quotation/opportunity),get_record_counts也不统计该表。- 无版本管理、无状态流转:每次调用新增一行,状态固定
draft。
4 验证/管理工具详解(4 个)
用途:MCP 读写分离交叉验证——写工具的返回值与只读回读工具交叉核对;测试数据清理经受限工具完成。 原则:验证/清理环节禁止直连数据库;
db.py仅为服务层内部连接池。
4.1 get_inquiry_info — 询价单回读(只读)
功能:按询价单号回读询价单整行,用于存档后验证(状态、图号、零件号、年用量、目标价、创建时间)。
入参:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
inquiry_id |
string | 是 | 询价单号 |
返回:命中 {"success": true, "inquiry": {<整行字段>}};未命中 {"success": false, "message": "未找到询价单 XXX"}。
示例:
{
"success": true,
"inquiry": {
"inquiry_id": "INQ-2026-0025",
"customer_code": "T1-2025-002",
"inquiry_date": "2026-08-08",
"drawing_number": "DWG-VHB-MN-Rev1",
"part_number": "P-VHB-009",
"annual_volume": 5000,
"target_price": "30.00",
"status": "quoted",
"notes": "TC-05生产报价:微型泵阀体壳 ADC12 96.3cc 160T一模两腔...",
"created_at": "2026-08-08 13:34:11.945841"
}
}
4.2 get_opportunity_info — 商机回读(只读)
功能:按商机号或客户编码回读商机,用于存档后验证(stage/probability/expected_amount/更新时间)。两参数二选一,opportunity_id 优先。
入参:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
opportunity_id |
string | 二选一 | 商机号(精确单条) |
customer_code |
string | 二选一 | 客户编码(该客户全部商机,按创建时间倒序) |
返回:{"total": N, "opportunities": [<整行字段>]};两参数都未提供时 {"success": false, "message": "需提供 opportunity_id 或 customer_code"}。
示例:
{
"total": 1,
"opportunities": [
{
"opportunity_id": "OPP-2026-0018",
"customer_code": "T1-2025-002",
"title": "微型泵阀体壳 ADC12(P-VHB-009)首单",
"stage": "quoted",
"expected_amount": "40300.00",
"probability": 50,
"oem_program": "大陆制动系统配套",
"expected_close_date": "2026-09-30",
"source": "智能报价自动生成",
"created_by": "AI智能报价",
"updated_at": "2026-08-08"
}
]
}
4.3 get_record_counts — 三表行数统计(只读)
功能:返回 inquiry/quotation/opportunity 三表行数,用于数据卫生检查(如回归前后行数一致性核对)。
入参:无。
返回示例:
{
"success": true,
"counts": { "inquiry": 24, "quotation": 27, "opportunity": 18 }
}
4.4 purge_test_records — 受限测试数据清理(管理)
功能:清理 TC-03 回归测试写入的数据。带硬性防护:仅当报价单 remarks、询价单 notes 含「TC-03回归测试」,或商机 title 以「TC-03」开头时才允许删除;其余一律进入 rejected 列表,防止误删演示/生产数据。级联删除子表(quotation_cost_detail / inquiry_item)。
入参(至少传一组;均为 ID 数组):
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
quotation_ids |
array[string] | 否 | 待清理报价单号列表 |
inquiry_ids |
array[string] | 否 | 待清理询价单号列表 |
opportunity_ids |
array[string] | 否 | 待清理商机号列表 |
返回字段:
| 字段 | 类型 | 说明 |
|---|---|---|
success |
bool | 固定 true(单条拒绝不影响整体) |
deleted.quotations / deleted.inquiries / deleted.opportunities |
int | 实际删除条数 |
deleted.rejected |
array[string] | 被防护拒绝的 ID 列表(非测试标记或不存在) |
示例一:正常清理(回归测试自动调用)
{
"success": true,
"deleted": { "quotations": 3, "inquiries": 3, "opportunities": 1, "rejected": [] }
}
示例二:防护生效(对生产数据调用)
{
"success": true,
"deleted": {
"quotations": 0, "inquiries": 0, "opportunities": 0,
"rejected": ["QUO-2026-0027", "INQ-2026-0025", "OPP-2026-0018"]
}
}
5 附录
5.1 依赖数据表
| 表 | 用途 |
|---|---|
customer |
客户主数据(信用/折扣/账期/历史统计) |
inquiry |
询价单(pending→quoted) |
quotation |
报价单主表(版本链/状态机/金额) |
quotation_cost_detail |
报价成本明细(四项成本+费率) |
opportunity |
商机(阶段/金额/概率/关单日期) |
5.2 标准存档链路(智能体 Step 7)
get_quotation_history(inquiry_id) ← 前置:查有无历史版本
├─ 无 → create_inquiry(...) ← 建询价单
└─ 有 → 复用原 inquiry_id
save_quotation(...) ← 存报价(版本自动+1,事务)
update_opportunity(...) ← 商机同步最新版年总额(stage=quoted)
get_inquiry_info / get_opportunity_info ← 可选:存档后交叉验证
5.3 与 ERP 服务的协作
核价计算(材质对照/压铸参数/机加工工时/汇总核价)由 mcp-for-erp 承担,见《MCP for ERP — 工具说明文档》;CRM 服务不做核价计算,只做客户与商务数据管理。