MCP server (Claude Desktop / Claude Code)

automation_file ships a Model Context Protocol (MCP) server that exposes every entry of the shared ActionRegistry as an MCP tool. Hosts such as Claude Desktop, Claude Code, and other MCP-aware clients can then call FA_* actions exactly like any other MCP tool — no plugin code, no extra packaging.

Transport is stdio (one JSON-RPC 2.0 message per line on stdin / stdout), matching the protocol that current MCP hosts consume.

What you get

  • initialize handshake reporting protocol version 2024-11-05 and serverInfo.name / serverInfo.version.

  • tools/list returns one MCP tool per registered FA_* action, with an auto-derived JSON Schema for its arguments (built from the Python signature: str "string", int "integer", etc.).

  • tools/call dispatches through the registry and returns the result as a JSON-encoded text content block.

  • --allowed-actions allow-list flag to surface only a subset of the registry to the host.

  • Every internal failure surfaces as a JSON-RPC error object — the host can render it without parsing exception strings.

Starting the server

CLI:

python -m automation_file mcp
python -m automation_file mcp --name automation_file --version 1.0.0
python -m automation_file mcp --allowed-actions FA_list_dir,FA_file_checksum

The process runs in the foreground, reading newline-delimited JSON from stdin and writing responses to stdout. MCP hosts spawn this process for you — you rarely run it by hand.

From Python (e.g. when embedding into another stdio bridge):

from automation_file import MCPServer

server = MCPServer(name="automation_file", version="1.0.0")
server.serve_stdio()        # blocks until stdin closes

Filter to a smaller surface area by passing your own registry:

from automation_file import MCPServer
from automation_file.core.action_registry import ActionRegistry
from automation_file import executor

safe = ActionRegistry()
for name in ("FA_list_dir", "FA_file_checksum", "FA_fast_find"):
    safe.register(name, executor.registry.resolve(name))

MCPServer(safe).serve_stdio()

Claude Desktop configuration

Add an entry under mcpServers in ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "automation_file": {
      "command": "python",
      "args": ["-m", "automation_file", "mcp"]
    }
  }
}

Restart Claude Desktop. The automation_file server appears in the tools panel; every FA_* action is callable.

Lock the surface area down to a curated allow-list — recommended for hosts that operate on sensitive paths:

{
  "mcpServers": {
    "automation_file": {
      "command": "python",
      "args": [
        "-m", "automation_file", "mcp",
        "--allowed-actions",
        "FA_list_dir,FA_fast_find,FA_file_checksum,FA_verify_checksum"
      ]
    }
  }
}

Use a virtualenv interpreter explicitly (avoids picking up the system Python):

{
  "mcpServers": {
    "automation_file": {
      "command": "C:\\envs\\fa\\Scripts\\python.exe",
      "args": ["-m", "automation_file", "mcp"]
    }
  }
}

Claude Code configuration

Claude Code consumes the same MCP definition. Register the server with the claude mcp add CLI:

claude mcp add automation_file -- python -m automation_file mcp

Or commit a .mcp.json to the repo root:

{
  "mcpServers": {
    "automation_file": {
      "command": "python",
      "args": ["-m", "automation_file", "mcp"]
    }
  }
}

After it loads, ask Claude Code to use mcp__automation_file__FA_* tools — for example "use FA_fast_find to locate every *.log under ./var".

Inspecting the catalogue

Render the same descriptors a host would see — useful for tests, GUI debugging, or generating documentation:

from automation_file import tools_from_registry, executor

for tool in tools_from_registry(executor.registry):
    print(tool["name"], "->", tool["description"])

Each descriptor is shaped as:

{
  "name": "FA_fast_find",
  "description": "First docstring line of the underlying callable.",
  "inputSchema": {
    "type": "object",
    "properties": {"root": {"type": "string"}, "pattern": {"type": "string"}},
    "required": ["root", "pattern"],
    "additionalProperties": true,
  },
}

Manual smoke test

Pipe JSON-RPC frames straight at the server to confirm it loads:

printf '%s\n%s\n%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
  '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"FA_fast_find","arguments":{"root":".","pattern":"*.py","limit":3}}}' \
  | python -m automation_file mcp

Each input line gets exactly one JSON-RPC reply on stdout (notifications have no reply).

Security considerations

  • The MCP server runs with the same privileges as the Python process that starts it. Every tool call lands in your shell’s user account.

  • By default the server exposes every registered FA_* action, including ones that delete files, write to the filesystem, or upload to remote backends. Use --allowed-actions to whitelist a tight surface for any host you don’t fully trust.

  • Do not call add_package_to_executor() (or expose its action) before starting an MCP server intended for a third-party host. That helper registers every top-level function / class / builtin of an arbitrary package and is eval-grade power.

  • The server logs at the INFO level via file_automation_logger when it starts, including the number of exposed tools and the configured server name. Tool-call payloads are never logged.

  • Outbound HTTP-bearing actions (FA_download_file, the cloud backends) keep their SSRF guard; the MCP layer does not loosen any per-action check.