← Back to SKILL.md1from __future__ import annotations2 3from pathlib import Path4from typing import Any5 6from fastmcp import FastMCP7 8 9mcp = FastMCP("__SERVER_NAME__")10 11 12def _read_text(path: str) -> str:13 file_path = Path(path).expanduser()14 try:15 return file_path.read_text(encoding="utf-8")16 except FileNotFoundError as exc:17 raise ValueError(f"File not found: {file_path}") from exc18 except UnicodeDecodeError as exc:19 raise ValueError(f"File is not valid UTF-8 text: {file_path}") from exc20 21 22@mcp.tool23def summarize_text_file(path: str, preview_chars: int = 1200) -> dict[str, int | str]:24 """Return basic metadata and a preview for a UTF-8 text file."""25 file_path = Path(path).expanduser()26 text = _read_text(path)27 return {28 "path": str(file_path),29 "characters": len(text),30 "lines": len(text.splitlines()),31 "preview": text[:preview_chars],32 }33 34 35@mcp.tool36def search_text_file(path: str, needle: str, max_matches: int = 20) -> dict[str, Any]:37 """Find matching lines in a UTF-8 text file."""38 file_path = Path(path).expanduser()39 matches: list[dict[str, Any]] = []40 for line_number, line in enumerate(_read_text(path).splitlines(), start=1):41 if needle.lower() in line.lower():42 matches.append({"line_number": line_number, "line": line})43 if len(matches) >= max_matches:44 break45 return {"path": str(file_path), "needle": needle, "matches": matches}46 47 48@mcp.resource("file://{path}")49def read_file_resource(path: str) -> str:50 """Expose a text file as a resource."""51 return _read_text(path)52 53 54if __name__ == "__main__":55 mcp.run()56