from pydantic import Field
from typing import Dict, Any, Optional
from mcp.server.fastmcp import FastMCP
import subprocess
import json
import re
import os
import argparse
from pathlib import Path
mcp = FastMCP("memoryAnalyzerMcp")
@mcp.tool()
def valgrind_memcheck(
program: str = Field(..., description="要检测的程序路径"),
args: Optional[str] = Field(default="", description="程序参数"),
options: Optional[str] = Field(default="", description="valgrind额外选项")
) -> Dict[str, Any]:
"""使用valgrind检测内存问题"""
try:
cmd = ['valgrind']
if options:
cmd.extend(options.split())
cmd.append(program)
if args:
cmd.extend(args.split())
output = subprocess.check_output(
cmd,
stderr=subprocess.STDOUT,
universal_newlines=True
)
return {
"status": "success",
"report": output
}
except subprocess.CalledProcessError as e:
return {
"status": "error",
"report": e.output
}
except Exception as e:
return {"error": str(e)}
@mcp.tool()
def asan_analyze(
program: str = Field(..., description="要分析的程序路径"),
args: Optional[str] = Field(default="", description="程序参数")
) -> Dict[str, Any]:
"""使用address-sanitizer分析内存错误"""
try:
env = os.environ.copy()
env["ASAN_OPTIONS"] = "detect_leaks=1"
cmd = [program]
if args:
cmd.extend(args.split())
output = subprocess.check_output(
cmd,
stderr=subprocess.STDOUT,
universal_newlines=True,
env=env
)
return {
"status": "success",
"report": output
}
except subprocess.CalledProcessError as e:
return {
"status": "error",
"report": e.output
}
except Exception as e:
return {"error": str(e)}
@mcp.tool()
def report_analyzer(
report_file: str = Field(..., description="内存报告文件路径"),
output_format: str = Field(default="text", description="输出格式(json/text)")
) -> Dict[str, Any]:
"""分析内存报告"""
try:
with open(report_file, 'r') as f:
content = f.read()
if output_format == "json":
leaks = re.findall(r"definitely lost: (\d+) bytes", content)
errors = re.findall(r"ERROR: AddressSanitizer: (\w+)", content)
return {
"status": "success",
"report": {
"leaks": {
"count": len(leaks),
"total_bytes": sum(map(int, leaks)) if leaks else 0
},
"errors": errors
}
}
else:
return {
"status": "success",
"report": content
}
except Exception as e:
return {"error": str(e)}
def init_config():
parser = argparse.ArgumentParser()
parser.add_argument('--VALGRIND_PATH', required=True, help="valgrind安装路径")
parser.add_argument('--ASAN_OPTIONS', default="detect_leaks=1", help="ASAN配置选项")
parser.add_argument('--REPORT_DIR',
default=str(Path.home() / ".local/share/memory_analyzer/reports"),
help="报告存储目录,默认为~/.local/share/memory_analyzer/reports")
args = parser.parse_args()
print(f"报告目录设置为: {args.REPORT_DIR} (不实际创建目录)")
if __name__ == "__main__":
init_config()
mcp.run()