write_file
Write file contents after policy validation, with automatic logging and backup. Ensures agent actions stay within defined boundaries.
Instructions
Write full file content with policy checks, logging, and backup support.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | ||
| content | Yes | ||
| ctx | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- src/tools/file_tools.py:48-109 (handler)The actual implementation of write_file. It enforces path policy, creates backups of existing files, writes content, runs Script Sentinel scan, and returns a result message.
def write_file(path: str, content: str, ctx: Context | None = None) -> str: """Write full file content with policy checks, logging, and backup support.""" 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="write_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) log_entry = build_log_entry("write_file", result, path=path) append_log_entry(log_entry) if not result.allowed: return f"[POLICY BLOCK] {result.reason}" backup_location = None backup_enabled = bool(POLICY.get("audit", {}).get("backup_enabled", True)) if backup_enabled and os.path.exists(path): backup_location = backup_paths([path]) if backup_location: append_log_entry( { **log_entry, "source": "mcp-server", "backup_location": backup_location, "event": "backup_created", } ) try: with open(path, "w") as f: f.write(content) except OSError as e: return f"Error writing file: {e}" sentinel_scan = script_sentinel.scan_and_record_write(path, content, writer_agent_id=AGENT_ID) if sentinel_scan.get("flagged"): append_log_entry( { **log_entry, "source": "mcp-server", "event": "script_sentinel_flagged", "content_hash": sentinel_scan.get("content_hash", ""), "matched_signatures": sentinel_scan.get("matched_signatures", []), "script_sentinel_mode": POLICY.get("script_sentinel", {}).get("mode", "match_original"), "script_sentinel_scan_mode": sentinel_scan.get("scan_mode", POLICY.get("script_sentinel", {}).get("scan_mode", "exec_context")), } ) msg = f"Successfully wrote {len(content)} characters to {path}" if backup_location: msg += f" (previous version backed up to {backup_location})" else: msg += " (no content-change backup needed)" if sentinel_scan.get("flagged"): msg += " (Script Sentinel flagged content)" return msg finally: reset_runtime_context(context_tokens) - src/server.py:6-17 (schema)Import of write_file from tools module (no dedicated schema file; the function signature itself defines the schema via MCP tool decorator).
from tools import ( delete_file, edit_file, execute_command, list_directory, read_file, restore_backup, server_info, write_file, ) approvals.init_approval_store() - src/server.py:21-31 (registration)Registration of write_file as an MCP tool via FastMCP's tool() decorator.
for tool in [ server_info, restore_backup, execute_command, read_file, write_file, edit_file, delete_file, list_directory, ]: mcp.tool()(tool) - src/mcp_config_manager.py:30-39 (registration)Tool name list used by the MCP config manager to write config files for different IDEs.
AIRG_MCP_TOOLS = [ "server_info", "restore_backup", "execute_command", "read_file", "write_file", "edit_file", "delete_file", "list_directory", ] - src/airg_hook.py:11-14 (registration)AIRG hook redirects 'Write' tool calls to the write_file MCP handler.
REDIRECTS = { "Bash": "mcp__ai-runtime-guard__execute_command", "Shell": "mcp__ai-runtime-guard__execute_command", "Write": "mcp__ai-runtime-guard__write_file",