Skip to main content
Glama
inflearner0

systeminformer-mcp

by inflearner0
README.md
# systeminformer-mcp

An MCP server that exposes [System Informer](https://github.com/winsiderss/systeminformer)'s
capabilities as tools: processes, threads, modules, handles, memory, services,
network endpoints, drivers, windows and file signatures — plus process launching
and control.

54 tools, verified end-to-end on Windows 11 (build 26200).

## How it works

Modern System Informer builds have **no headless command mode** — the old
`-ctype` / `-cobject` / `-caction` switches were removed, and the remaining
command line switches only configure the GUI. Scraping a GUI would be both
fragile and lossy.

So this server does what System Informer itself does: it calls the same native
NT APIs directly (`NtQuerySystemInformation`, `NtQueryInformationProcess`,
`NtDuplicateObject`, the SCM APIs, `iphlpapi`, `WinVerifyTrust`, …) through
`ctypes`. Results come back as structured JSON rather than table rows.

The installed System Informer application is still used for two things:

- **GUI hand-off** — `launch_systeminformer_gui`, `launch_peview` for the live
  graphs and interactive views that do not translate to tool output.
- **`dbghelp.dll`** — the copy shipped with System Informer writes process dumps.

Neither is required. If System Informer is not installed, every inspection and
control tool still works; only those two hand-off tools become unavailable.

## Install

```bash
pip install mcp
```

Then register the server with your MCP client. For Claude Code — note the
`PYTHONPATH`, which is what lets `python -m si_mcp` find the package from any
working directory:

```bash
claude mcp add systeminformer --scope user -e PYTHONIOENCODING=utf-8 -e "PYTHONPATH=C:\path\to\systeminformer-mcp" -- python -m si_mcp
```

Or add it to your client's config file directly:

```json
{
  "mcpServers": {
    "systeminformer": {
      "command": "python",
      "args": ["-m", "si_mcp"],
      "env": {
        "PYTHONIOENCODING": "utf-8",
        "PYTHONPATH": "C:\\path\\to\\systeminformer-mcp"
      }
    }
  }
}
```

Alternatively `pip install -e .` from the project root, which puts a
`systeminformer-mcp` console script on PATH and makes `PYTHONPATH` unnecessary.

Set `SYSTEMINFORMER_PATH` if System Informer is installed somewhere other than
`C:\Program Files\SystemInformer`.

## Privileges

Windows, not this server, decides what is visible. Run the server **elevated**
for full coverage — call `server_status` at any time to see exactly what is and
is not available:

| Running as | What you get |
|---|---|
| Standard user | Your own processes in full; other users' processes are limited |
| Elevated | Nearly everything: all processes, kernel addresses, service control |
| Elevated + KSystemInformer driver | Protected processes (PPL, antimalware) too |

Unelevated, Windows withholds kernel addresses (driver base addresses read back
as `0x0`) and thread start addresses for processes you do not own. The server
works around the latter by re-querying through a thread handle where it can.

## Tools

**System** — `system_overview`, `system_cpu_usage`, `system_memory`, `system_uptime`

**Processes** — `list_processes`, `process_tree`, `process_details`,
`process_token`, `process_modules`, `process_threads`, `thread_details`

**Process control** — `launch_process`, `launch_process_elevated`,
`terminate_process`, `terminate_process_tree`, `suspend_process`,
`resume_process`, `set_process_priority`, `set_process_affinity`,
`set_process_critical`, `empty_working_set`, `create_process_dump`

**Threads** — `suspend_thread`, `resume_thread`, `terminate_thread`,
`set_thread_priority`, `set_thread_affinity`

**Memory** — `process_memory_regions`, `process_memory_summary`,
`read_process_memory`, `write_process_memory`, `protect_process_memory`,
`search_process_memory`, `process_memory_strings`

**Handles** — `list_handles`, `handle_type_summary`, `find_handles_by_name`,
`close_handle`

**Services** — `list_services`, `service_details`, `control_service`,
`set_service_start_type`, `create_service`, `delete_service`

**Network** — `network_connections`, `port_owner`

**Drivers & windows** — `list_drivers`, `list_windows`, `window_action`

**Files** — `file_details`, `verify_file_signature`

**System Informer** — `server_status`, `launch_systeminformer_gui`, `launch_peview`

### Examples

```
"What's using port 3000?"                  -> port_owner
"Which process has this DLL locked?"       -> find_handles_by_name
"Why is my machine at 100% CPU?"           -> list_processes sort_by=cpu
"Start notepad minimized, then suspend it" -> launch_process, suspend_process
"Is this binary signed?"                   -> verify_file_signature
```

## Safety

Tools that cannot be undone, or that can destabilise a running process, require
an explicit `confirm=true`:

- `write_process_memory` — can corrupt or crash the target
- `close_handle` — the owning process is not told its handle vanished
- `terminate_process_tree` — kills every descendant
- `delete_service` — service registration cannot be restored by this server
- `set_process_critical` — **terminating a critical process bugchecks Windows**

`launch_process_elevated` routes through the standard Windows UAC consent
prompt. This server never accepts, stores or transmits credentials; to run a
process as a *different* user, use the System Informer GUI's Run As dialog.

## Notes on correctness

A few details that are easy to get wrong and are handled here:

- **Object names can hang.** Naming a handle means duplicating it and calling
  `NtQueryObject`, which blocks forever on a synchronous named pipe whose peer
  never answers. Like System Informer, this runs on a worker thread with a
  timeout; a wedged worker is retired rather than reused, and the handle is
  deliberately leaked instead of being closed out from under the blocked call.
- **Process names are not NUL-terminated.** `SYSTEM_PROCESS_INFORMATION`
  carries an explicit `Length`; decoding by scanning for a terminator reads
  past the string into adjacent data and yields unpaired UTF-16 surrogates.
  All tool output is additionally sanitized so no malformed name from another
  process can fail a response.
- **Token structures embed pointers into their own buffer.** `TOKEN_USER` and
  friends must be read from a live allocation, not a copied `bytes`.
- **Fixed-size info classes reject over-sized buffers.** `SystemBasicInformation`
  and the per-processor tables want exactly the size the running kernel expects,
  which differs across Windows versions, so the size is queried first.
- **PID reuse breaks process trees.** A "parent" created after its child is
  treated as recycled, and the child is reported at the root.

## Tests

```bash
python tests/test_e2e.py
```

Starts the server over real MCP stdio transport, calls a tool from every group,
and round-trips a live process: launch → inspect → suspend → resume → dump →
terminate. It also asserts that each guarded tool refuses to act without
`confirm=true`. 44 checks.