read_file
Read a text file securely from the workspace after applying path-policy enforcement to restrict access.
Instructions
Read a text file from the workspace after path-policy enforcement.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| ctx | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- src/tools/file_tools.py:20-45 (handler)The read_file handler function. Resolves the path relative to WORKSPACE_ROOT, enforces path policy via check_path_policy, logs the result, reads and returns file content with error handling.
def read_file(path: str, ctx: Context | None = None) -> str: """Read a text file from the workspace after path-policy enforcement.""" context_tokens = activate_runtime_context(ctx) path = str(pathlib.Path(WORKSPACE_ROOT) / path) if not os.path.isabs(path) else path try: refresh_policy_if_changed() path_check = check_path_policy(path, tool="read_file") if path_check: result = PolicyResult(allowed=False, reason=path_check[0], decision_tier="blocked", matched_rule=path_check[1]) else: result = PolicyResult(allowed=True, reason="allowed", decision_tier="allowed", matched_rule=None) append_log_entry(build_log_entry("read_file", result, path=path)) if not result.allowed: return f"[POLICY BLOCK] {result.reason}" try: with open(path, "r", errors="replace") as f: return f.read() except FileNotFoundError: return f"Error: file not found: {path}" except OSError as e: return f"Error reading file: {e}" finally: reset_runtime_context(context_tokens) - src/tools/file_tools.py:1-17 (helper)Imports used by read_file: check_path_policy, PolicyResult, activate_runtime_context, append_log_entry, build_log_entry, etc.
import datetime import os import pathlib from typing import Any, TYPE_CHECKING if TYPE_CHECKING: from mcp.server.fastmcp import Context else: Context = Any from audit import append_log_entry, build_log_entry from backup import backup_paths from config import AGENT_ID, POLICY, WORKSPACE_ROOT, refresh_policy_if_changed from models import PolicyResult from policy_engine import check_path_policy, relative_depth from runtime_context import activate_runtime_context, reset_runtime_context import script_sentinel - src/server.py:19-31 (registration)The read_file function is registered as an MCP tool via mcp.tool()(read_file) in the FastMCP server setup.
mcp = FastMCP("ai-runtime-guard") for tool in [ server_info, restore_backup, execute_command, read_file, write_file, edit_file, delete_file, list_directory, ]: mcp.tool()(tool) - src/tools/__init__.py:1-14 (registration)read_file is exported from the tools package in __all__ and imported from file_tools.
from .command_tools import execute_command, server_info from .file_tools import delete_file, edit_file, list_directory, read_file, write_file from .restore_tools import restore_backup __all__ = [ "server_info", "execute_command", "read_file", "write_file", "edit_file", "delete_file", "list_directory", "restore_backup", ] - src/policy_engine.py:884-924 (helper)The check_path_policy function used by read_file to enforce path policy (blocked paths, extensions, runtime paths, workspace boundary, backup access).
def check_path_policy(path: str, tool: str | None = None) -> tuple[str, str] | None: blocked = POLICY.get("blocked", {}) lower_path = str(path).lower() try: resolved = pathlib.Path(path).resolve() except Exception: resolved = pathlib.Path(path) for blocked_path in blocked.get("paths", []): if _blocked_path_matches(resolved, str(blocked_path)): return ( f"Sensitive path access not permitted: '{blocked_path}' may contain secrets or critical system configuration", blocked_path, ) for ext in blocked.get("extensions", []): if re.search(rf"{re.escape(ext)}\b", lower_path): return ( f"Sensitive file extension not permitted: '{ext}' files may contain private keys or certificates", ext, ) if is_protected_runtime_path(path): return ( f"Path '{path}' is protected runtime state and is not accessible via {tool or 'this tool'}", "runtime_protected_path", ) if not is_within_workspace(path): return (f"Path '{path}' is outside the allowed workspace", "workspace_boundary") backup_access = POLICY.get("backup_access", {}) if backup_access.get("block_agent_tools", True) and is_backup_path(path): tool_name = (tool or "").lower() if tool_name != "restore_backup": return ( f"Path '{path}' is inside protected backup storage and is not accessible via {tool or 'this tool'}", "backup_storage_protected", ) return None