打造专属 MCP Server:测试自动化的私有化解决方案
一、为什么要自建 MCP Server
MCP Server 生态虽然丰富,但组织内部的私有系统------如测试管理系统、性能测试库、接口测试库、UI 自动化测试库等------仍需自行封装。这些内部系统无法通过开源方案解决,必须针对特定业务场景开发专属的 MCP Server,才能真正释放大模型在测试领域的潜力。
本文将介绍两个实战案例:Allure 测试报告读取服务和 JaCoCo 代码覆盖率分析服务,展示如何将内部测试资源转化为大模型可调用的标准化工具。
二、案例一:Allure 测试报告读取服务
业务痛点
某团队每天运行逾 10 万条接口测试脚本进行回归测试。虽然测试执行已自动化,但报告分析环节成为瓶颈:
- 手动翻阅大量 Allure 报告,逐一分析失败用例
- 人为错误风险高,且耗时严重
- 在快节奏的 DevOps 环境中,低效分析延缓反馈循环
Allure 报告数据结构
Allure 报告的 data 目录包含以下关键文件:
| 文件 | 用途 |
|---|---|
| categories.json | 测试结果分类和筛选配置 |
| suites.json | 测试套件层级树(包 → 模块 → 类/方法) |
| behaviors.json | 按 Epic/Feature/Story 叙事层分组 |
| package.json | 按包/模块组织用例 |
| test-cases/*.json | 单个用例的详细记录 |
核心实现逻辑
为什么不直接将 HTML 报告给大模型?HTML 包含大量标签和样式信息,占用上下文却无语义价值。因此需要一个"翻译官",将 Allure 报告转为大模型友好的 JSON 格式。
python
class AllureSuiteParser:
def __init__(self, allure_report_dir: str):
self.report_dir = allure_report_dir
self.data_dir = os.path.join(allure_report_dir, 'data')
self.suites_file = os.path.join(self.data_dir, 'suites.json')
self.test_cases_dir = os.path.join(self.data_dir, 'test-cases')
def parse(self) -> Dict[str, Any]:
with open(self.suites_file, 'r', encoding='utf-8') as f:
suites_data = json.load(f)
return {"test-suites": self._parse_suites(suites_data.get('children', []))}
def _parse_test_case(self, case: Dict) -> Dict[str, Any]:
case_uid = case.get('uid', '')
case_file = os.path.join(self.test_cases_dir, f"{case_uid}.json")
# 提取用例详情:名称、状态、步骤、附件等
解析流程采用递归设计:
parse()读取 suites.json 作为入口_parse_suites()递归遍历 children 分支_parse_test_case()用 uid 从 test-cases 目录提取详情_parse_steps()递归拆解步骤树
MCP Server 封装
python
from mcp.server import FastMCP
from allure_html import AllureSuiteParser
MCP_SERVER_NAME = "mcp-allure-server"
mcp = FastMCP(MCP_SERVER_NAME)
@mcp.tool()
async def get_allure_report(results_dir: str) -> str:
parser = AllureSuiteParser(results_dir)
return json.dumps(parser.parse(), indent=2, ensure_ascii=False)
if __name__ == '__main__':
mcp.run(transport='stdio')
配置方式(STDIO 模式):
json
{
"mcpServers": {
"mcp-allure-server": {
"command": "uv",
"args": [
"run", "--with", "mcp[cli]", "mcp", "run",
"/mcp-allure/mcp-allure-server.py"
]
}
}
}
三、案例二:JaCoCo 代码覆盖率读取服务
业务痛点
接口测试完成后,常发现增量代码未被覆盖。传统流程中,测试工程师需与开发工程师预约会议讨论未覆盖原因,导致:
- 从"即时聊天"变为"会议预约剧场"
- 邮件、拉群、调日历,耗时严重
- 接口测试流水线卡在半道,影响 DevOps 效率
解决方案
让大模型直接读取 JaCoCo 覆盖率报告,自动识别"漏网之鱼",给出补充修复建议。
技术选型
选择 XML 格式而非 HTML,因为:
- XML 结构严谨,受 DTD 管辖,易于解析
- HTML 标签冗余,长报告会导致 token 爆表
- 大模型有上下文窗口限制,需精简输入
核心实现
python
from mcp.server import FastMCP
from jacoco_reporter import JaCoCoReport
MCP_SERVER_NAME = "mcp-jacoco-reporter-server"
mcp = FastMCP(MCP_SERVER_NAME)
# 环境变量控制过滤类型:nocovered / partiallycovered / fullcovered
COVERED_TYPES = os.environ.get("COVERED_TYPES", "no").split(",")
@mcp.tool()
async def jacoco_reporter_server(jacoco_xmlreport_path: str,
covered_types=COVERED_TYPES) -> json:
jac = JaCoCoReport(jacoco_xmlreport_path, covered_types)
return jac.jacoco_to_json()
if __name__ == '__main__':
mcp.run(transport='stdio')
配置示例:
json
{
"mcpServers": {
"mcp-jacoco-reporter-server": {
"command": "uv",
"args": [
"run", "--with", "mcp[cli]", "mcp", "run",
"/path/to/mcp-jacoco-reporter-server.py"
],
"env": {
"COVERED_TYPES": "nocovered,partiallycovered,fullcovered"
}
}
}
}
四、设计要点总结
数据转换原则
| 原始格式 | 问题 | 转换目标 |
|---|---|---|
| HTML 报告 | 标签冗余,token 浪费 | 结构化 JSON |
| XML 报告 | 结构完整但冗长 | 按需过滤的精简 JSON |
MCP Server 开发模式
- 解析层:读取原始数据,提取关键信息
- 过滤层:根据业务需求筛选数据,控制输出大小
- 封装层:用 FastMCP 装饰器注册为可调用的 Tool
- 配置层:STDIO 模式适合本地集成,HTTP 模式适合远程访问
五、结语
MCP Server 为大模型提供延伸能力的趋势已成熟,但针对组织内部私有系统的定制化开发仍是刚需。通过 Allure 报告解析和 JaCoCo 覆盖率分析两个案例,可以看到 MCP Server 在测试自动化中的"解题"魅力:
- 从繁琐手动到 AI 驱动闭环
- 显著提升效率与准确性
- 测试工程师从"执行者"转变为"策略设计者"
这种范式转变不仅解决了具体的技术痛点,更重要的是重新定义了测试工程师在 DevOps 流程中的角色定位。