105 lines
3.8 KiB
Python
105 lines
3.8 KiB
Python
import uvicorn
|
||
import logging
|
||
from mcp.server.fastmcp import FastMCP
|
||
from typing import List, Dict, Any
|
||
import threading
|
||
|
||
# --- 配置 ---
|
||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
||
logger = logging.getLogger(__name__)
|
||
|
||
# --- MCP Server 定义 ---
|
||
mcp = FastMCP()
|
||
|
||
# 使用一个简单的字典和线程锁来安全地管理状态
|
||
test_state: Dict[str, Any] = {}
|
||
state_lock = threading.Lock()
|
||
|
||
def _reset_state():
|
||
"""重置测试状态,不加锁,供内部调用"""
|
||
global test_state
|
||
test_state = {
|
||
"results": {}, # e.g., {"api_id_1": [{"task_name": "...", "status": "...", "details": "..."}]}
|
||
"apis_pending_init": [],
|
||
}
|
||
|
||
_reset_state() # 初始化状态
|
||
|
||
@mcp.tool()
|
||
def initialize_test_plan(api_ids: List[str]) -> Dict[str, Any]:
|
||
"""
|
||
根据提供的API ID列表,初始化测试计划。
|
||
这会重置所有测试状态,并为每个API准备好存储多次任务结果的列表。
|
||
"""
|
||
with state_lock:
|
||
_reset_state()
|
||
for api_id in api_ids:
|
||
test_state["results"][api_id] = []
|
||
|
||
test_state["apis_pending_init"] = list(api_ids)
|
||
logger.info(f"TestManager: Initialized test plan with {len(api_ids)} APIs.")
|
||
return {
|
||
"status": "success",
|
||
"message": f"Test plan initialized for {len(api_ids)} APIs.",
|
||
"apis_pending": list(api_ids)
|
||
}
|
||
|
||
@mcp.tool()
|
||
def record_test_result(api_id: str, task_name: str, status: str, details: str) -> Dict[str, Any]:
|
||
"""
|
||
记录一个API在一个特定任务上的测试结果。
|
||
|
||
Args:
|
||
api_id (str): 被测试的API的ID。
|
||
task_name (str): 执行的任务的名称。
|
||
status (str): 测试状态,例如 'passed' 或 'failed'。
|
||
details (str): 关于测试结果的详细描述或摘要。
|
||
"""
|
||
with state_lock:
|
||
if api_id not in test_state["results"]:
|
||
# 如果由于某种原因API ID不存在,先创建它
|
||
test_state["results"][api_id] = []
|
||
|
||
# 将本次任务的结果追加到列表中
|
||
test_state["results"][api_id].append({
|
||
"task_name": task_name,
|
||
"status": status,
|
||
"details": details
|
||
})
|
||
|
||
logger.info(f"TestManager: Recorded result for {api_id} on task '{task_name}': {status}")
|
||
return {"status": "success", "message": f"Result for {api_id} on task '{task_name}' recorded."}
|
||
|
||
@mcp.tool()
|
||
def get_test_summary() -> Dict[str, Any]:
|
||
"""
|
||
获取整个测试活动的最终摘要。
|
||
"""
|
||
with state_lock:
|
||
total_apis = len(test_state["results"])
|
||
tasks_completed_count = sum(len(tasks) for tasks in test_state["results"].values())
|
||
|
||
summary = {
|
||
"total_apis": total_apis,
|
||
"total_tasks_completed": tasks_completed_count,
|
||
"results": test_state["results"]
|
||
}
|
||
logger.info("TestManager: Providing test summary.")
|
||
return summary
|
||
|
||
# --- 启动服务器 ---
|
||
if __name__ == "__main__":
|
||
import uvicorn
|
||
|
||
# 移除get_next_api_to_test工具,因为它在M*N模型中不再需要。
|
||
# 我们使用 try...except 来确保即使工具不存在或属性名不正确,程序也不会崩溃。
|
||
try:
|
||
# 基于之前的观察,我们尝试使用 _tools 属性
|
||
if "get_next_api_to_test" in mcp._tools:
|
||
del mcp._tools["get_next_api_to_test"]
|
||
logger.info("Successfully removed deprecated tool: get_next_api_to_test")
|
||
except (AttributeError, KeyError):
|
||
logger.warning("Could not remove 'get_next_api_to_test' tool (it may not exist or the tools attribute name is different). Continuing...")
|
||
pass
|
||
|
||
uvicorn.run(mcp.streamable_http_app(), host="127.0.0.1", port=8004) |