You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/architecture.md
+79Lines changed: 79 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -54,3 +54,82 @@ graph TB
54
54
style Row1 fill:none,stroke:none
55
55
style Row2 fill:none,stroke:none
56
56
```
57
+
58
+
## Where Each Component Runs
59
+
60
+
Understanding where the **client**, **MCP server**, and **target Linux system** run is helpful for deployment and development alike.
61
+
62
+
| Component | Location | Description |
63
+
|-----------|----------|-------------|
64
+
|**Client**| User's machine | The MCP client (Cursor, Claude Desktop, Goose, etc.) runs on the machine where the user works. It spawns the Linux MCP Server as a **subprocess** and communicates over **stdio** (stdin/stdout) using the MCP protocol (JSON-RPC). |
65
+
|**MCP Server**| Same host as client, or in a container | The server process is started by the client (e.g. `linux-mcp-server` or `podman run ... linux-mcp-server`). With a native install it runs on the **same machine as the client**. With a container deploy it runs **inside the container** on that same machine. In both cases the server receives tool calls over stdio and performs command execution. |
66
+
|**Target Linux system**| Same host as client, or any host reachable via SSH | Commands are executed either **locally** on the same host where the MCP server is running (subprocess or container), or **remotely** on another machine. Remote execution is done by the server opening an **SSH connection from the server host to the target host** and running commands there. The client never talks to the target directly. |
67
+
68
+
This means:
69
+
70
+
-**Client ↔ Server**: Communication is **always** over stdio, using the MCP JSON-RPC protocol. The client does not connect to the target directly.
71
+
-**Server ↔ Target**: If `host` is omitted, execution is **local** (same host as the server). If `host` is set, the server **SSHs from its own host** to that host to run commands.
72
+
-**Containers**: When the server runs in a container, “local” means inside the container. Local execution can be disabled via the `disallow_local_execution_in_containers` decorator (tools then require a `host` parameter for remote SSH).
73
+
74
+
## Detailed Tool Call Flow
75
+
76
+
End-to-end flow of a single MCP tool call: from the client request through the server to command execution on the target, and back.
77
+
78
+
```mermaid
79
+
sequenceDiagram
80
+
participant User
81
+
participant Client as MCP Client<br/>(e.g. Cursor)
82
+
participant LLM as LLM Service
83
+
participant Server as MCP Server Process<br/>(same host or container)
84
+
participant FastMCP as FastMCP
85
+
participant Tool as Tool (e.g. get_system_information)
86
+
participant Cmd as CommandSpec / COMMANDS
87
+
participant Exec as execute_command
88
+
participant Target as Target Linux System<br/>(local or remote)
1. User asks a question in the MCP client (e.g. Cursor).
126
+
2. Client sends the prompt to the LLM; the LLM decides to call a tool.
127
+
3. Client sends MCP JSON-RPC `tools/call` (e.g. `get_system_information`) over **stdio** to the MCP server (same host or container).
128
+
4. FastMCP dispatches the call to the tool.
129
+
5. Tool runs decorators (`@log_tool_call`, `@disallow_local_execution_in_containers`), resolves commands via `CommandSpec`/`COMMANDS`, and invokes `cmd.run(host=host)` for each subcommand.
130
+
6.`execute_command` runs on the target: **local** (`asyncio.create_subprocess_exec` when `host` is omitted) or **remote** (SSH via `SSHConnectionManager` when `host` is set).
131
+
7. Target returns return code, stdout, and stderr to `execute_command`.
0 commit comments