MCP Source Relation Server
by owayo
Verified
import json
import sys
from pathlib import Path
from typing import Dict, List, Set
from mcp.server.fastmcp import FastMCP
from src.source_analyzer import SourceAnalyzer
# Initialize MCP server
mcp = FastMCP("source-relation")
def analyze_dependencies_recursively(
analyzer: SourceAnalyzer, file_path: str, analyzed_files: Set[str]
) -> Dict[str, List[str]]:
"""ファイルの依存関係を再帰的に解析する
Args:
analyzer (SourceAnalyzer): 解析を行うアナライザーインスタンス
file_path (str): 解析対象のファイルパス
analyzed_files (Set[str]): 解析済みファイルのセット
Returns:
Dict[str, List[str]]: 解析されたすべての依存関係の辞書
"""
if file_path in analyzed_files:
return {}
analyzed_files.add(file_path)
dependencies: Dict[str, List[str]] = {}
# ファイルを解析
try:
current_deps = analyzer.analyze_single_file(Path(file_path))
direct_dependencies = current_deps.get(file_path, [])
dependencies[file_path] = direct_dependencies
# 各依存ファイルについても再帰的に解析
for dependency in direct_dependencies:
if dependency not in analyzed_files:
nested_deps = analyze_dependencies_recursively(
analyzer, dependency, analyzed_files
)
dependencies.update(nested_deps)
except Exception:
pass
return dependencies
@mcp.prompt()
def source_relation(path: str) -> str:
"""Return a prompt"""
path_obj = Path(path)
base_dir = str(path_obj.parent if path_obj.is_file() else path_obj)
analyzer = SourceAnalyzer(base_dir)
# ソースコードを解析
if path_obj.is_file():
analyzed_files: Set[str] = set()
file_path = str(path_obj.absolute())
dependencies = analyze_dependencies_recursively(
analyzer, file_path, analyzed_files
)
else:
dependencies = analyzer.analyze_directory()
# 結果をまとめる
result = {"dependencies": dependencies}
return json.dumps(result, indent=2, ensure_ascii=False)
@mcp.tool()
def get_source_relation(path: str) -> str:
"""Analyze dependencies between source files"""
path_obj = Path(path)
base_dir = str(path_obj.parent if path_obj.is_file() else path_obj)
analyzer = SourceAnalyzer(base_dir)
# ソースコードを解析
if path_obj.is_file():
analyzed_files: Set[str] = set()
file_path = str(path_obj.absolute())
dependencies = analyze_dependencies_recursively(
analyzer, file_path, analyzed_files
)
else:
dependencies = analyzer.analyze_directory()
# 結果をまとめる
result = {"dependencies": dependencies}
return json.dumps(result, indent=2, ensure_ascii=False)
if __name__ == "__main__":
args = sys.argv[1:]
if not args:
mcp.run(transport="stdio")
elif args[0] == "test" and len(args) == 2:
print(get_source_relation(args[1]))
else:
print("""使用方法:
1. MCPサーバーとして実行:
uv run source_relation.py
2. コマンドラインツールとして実行:
uv run source_relation.py test /path/to/project または
uv run source_relation.py test /path/to/file
""")