netexec-mcp 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (30) hide show
  1. netexec_mcp-1.0.0/.github/workflows/publish.yml +57 -0
  2. netexec_mcp-1.0.0/.gitignore +21 -0
  3. netexec_mcp-1.0.0/.mcp.json.example +20 -0
  4. netexec_mcp-1.0.0/LICENSE +23 -0
  5. netexec_mcp-1.0.0/PKG-INFO +206 -0
  6. netexec_mcp-1.0.0/README.md +185 -0
  7. netexec_mcp-1.0.0/pyproject.toml +43 -0
  8. netexec_mcp-1.0.0/src/netexec_mcp/__init__.py +3 -0
  9. netexec_mcp-1.0.0/src/netexec_mcp/auth.py +156 -0
  10. netexec_mcp-1.0.0/src/netexec_mcp/config.py +219 -0
  11. netexec_mcp-1.0.0/src/netexec_mcp/dynamic.py +595 -0
  12. netexec_mcp-1.0.0/src/netexec_mcp/executor.py +388 -0
  13. netexec_mcp-1.0.0/src/netexec_mcp/guardrails.py +228 -0
  14. netexec_mcp-1.0.0/src/netexec_mcp/meta.py +212 -0
  15. netexec_mcp-1.0.0/src/netexec_mcp/modules/__init__.py +39 -0
  16. netexec_mcp-1.0.0/src/netexec_mcp/modules/ftp.py +133 -0
  17. netexec_mcp-1.0.0/src/netexec_mcp/modules/ldap.py +910 -0
  18. netexec_mcp-1.0.0/src/netexec_mcp/modules/mssql.py +619 -0
  19. netexec_mcp-1.0.0/src/netexec_mcp/modules/nfs.py +174 -0
  20. netexec_mcp-1.0.0/src/netexec_mcp/modules/rdp.py +251 -0
  21. netexec_mcp-1.0.0/src/netexec_mcp/modules/smb.py +1687 -0
  22. netexec_mcp-1.0.0/src/netexec_mcp/modules/ssh.py +209 -0
  23. netexec_mcp-1.0.0/src/netexec_mcp/modules/vnc.py +96 -0
  24. netexec_mcp-1.0.0/src/netexec_mcp/modules/winrm.py +329 -0
  25. netexec_mcp-1.0.0/src/netexec_mcp/modules/wmi.py +259 -0
  26. netexec_mcp-1.0.0/src/netexec_mcp/modules/workspace.py +431 -0
  27. netexec_mcp-1.0.0/src/netexec_mcp/resources.py +319 -0
  28. netexec_mcp-1.0.0/src/netexec_mcp/results.py +829 -0
  29. netexec_mcp-1.0.0/src/netexec_mcp/server.py +242 -0
  30. netexec_mcp-1.0.0/uv.lock +1779 -0
@@ -0,0 +1,57 @@
1
+ name: Publish to PyPI
2
+
3
+ # Publishes netexec-mcp to PyPI when a GitHub Release is published.
4
+ # Uses PyPI Trusted Publishing (OIDC) — no API token is stored in the repo.
5
+ #
6
+ # One-time setup on PyPI (https://pypi.org/manage/account/publishing/):
7
+ # PyPI project name : netexec-mcp
8
+ # Owner : mpgn
9
+ # Repository : netexec-mcp
10
+ # Workflow filename : publish.yml
11
+ # Environment name : pypi
12
+ # For a brand-new project name, add it as a "pending publisher" before the first run.
13
+
14
+ on:
15
+ release:
16
+ types: [published]
17
+
18
+ jobs:
19
+ build:
20
+ name: Build distribution
21
+ runs-on: ubuntu-latest
22
+ steps:
23
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
24
+
25
+ - name: Install uv
26
+ uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0
27
+
28
+ - name: Build sdist and wheel
29
+ run: uv build
30
+
31
+ - name: Check distribution metadata
32
+ run: uvx twine check dist/*
33
+
34
+ - name: Upload build artifacts
35
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
36
+ with:
37
+ name: dist
38
+ path: dist/
39
+
40
+ publish:
41
+ name: Publish to PyPI
42
+ needs: build
43
+ runs-on: ubuntu-latest
44
+ environment:
45
+ name: pypi
46
+ url: https://pypi.org/p/netexec-mcp
47
+ permissions:
48
+ id-token: write # required for Trusted Publishing (OIDC)
49
+ steps:
50
+ - name: Download build artifacts
51
+ uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
52
+ with:
53
+ name: dist
54
+ path: dist/
55
+
56
+ - name: Publish to PyPI
57
+ uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
@@ -0,0 +1,21 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .pytest_cache/
6
+
7
+ # uv / venv
8
+ .venv/
9
+
10
+ # local secrets / audit artifacts
11
+ *.jsonl
12
+ .env
13
+ audit_out/ # parser_audit.py output: raw nxc stdout incl. real NTDS/LSA/gMSA secrets
14
+ tests/*
15
+ .mcp.json
16
+ PLAN.md
17
+ runtest.txt
18
+ audit_out/*
19
+ docs/*
20
+ scripts/*
21
+ .python-version
@@ -0,0 +1,20 @@
1
+ {
2
+ "mcpServers": {
3
+ "netexec": {
4
+ "command": "netexec-mcp", // with uv "command": "uv"
5
+ "args": [], // with uv ["run", "--directory", "/path/", "netexec-mcp"],
6
+ "env": {
7
+ "NXC_COMMAND": "netexec", // with uv "NXC_COMMAND": "uv run --directory /home/bonclay/NetExec netexec",
8
+ "NXC_PROTOCOLS": "smb,ldap,rdp,winrm,wmi,mssql",
9
+ "NXC_SCOPE": "10.0.0.0/24,192.168.56.0/24",
10
+ "NXC_MODE": "recon", // suggest, recon, loot, full
11
+ "NXC_TIMEOUT": "300",
12
+ "NXC_MAX_TARGETS": "256",
13
+ "NXC_AUDIT_LOG": "/home/bonclay/.netexec-mcp/audit.jsonl",
14
+ "NXC_WORKSPACE": "default",
15
+ "NXC_TOOL_MODE": "dynamic", // recommended
16
+ "NXC_PATH": "~/.nxc"
17
+ }
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2026, Martial Puygrenier (mpgn)
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,206 @@
1
+ Metadata-Version: 2.4
2
+ Name: netexec-mcp
3
+ Version: 1.0.0
4
+ Summary: MCP server that drives NetExec (nxc) for authorized security testing.
5
+ Project-URL: Homepage, https://github.com/mpgn/netexec-mcp
6
+ Project-URL: Repository, https://github.com/mpgn/netexec-mcp
7
+ Project-URL: Issues, https://github.com/mpgn/netexec-mcp/issues
8
+ Author-email: Martial Puygrenier <mpgn@pm.me>
9
+ License-Expression: BSD-2-Clause
10
+ License-File: LICENSE
11
+ Keywords: active-directory,ldap,mcp,netexec,nxc,pentest,security,smb
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Information Technology
14
+ Classifier: License :: OSI Approved :: BSD License
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Topic :: Security
18
+ Requires-Python: >=3.10
19
+ Requires-Dist: fastmcp>=2.0
20
+ Description-Content-Type: text/markdown
21
+
22
+ # netexec-mcp
23
+
24
+ An [MCP](https://modelcontextprotocol.io) server that lets an AI agent drive
25
+ **[NetExec](https://github.com/Pennyw0rth/NetExec)** (`nxc`) for **authorized**
26
+ security testing only.
27
+
28
+ It is a **pure subprocess wrapper**: it shells out to the `nxc` CLI as an argv list
29
+ (never `shell=True`, never importing NetExec as a library) and declares **no** nxc
30
+ dependency. How nxc itself is installed (PATH / uv / pipx / docker) is entirely up to you.
31
+
32
+ <img width="1417" height="581" alt="image" src="https://github.com/user-attachments/assets/8c72cd0d-77bf-4ccf-a553-7c5ccce55513" />
33
+ <img width="1479" height="618" alt="image" src="https://github.com/user-attachments/assets/ae30ebcc-c613-47ec-a565-8a1247a67509" />
34
+
35
+ ## Status
36
+
37
+ **v1 — all 10 nxc protocols, 131 tools** (117 protocol tools + 9 discovery/meta-tools +
38
+ 5 offline workspace-DB readers). SMB, LDAP, WinRM, MSSQL, SSH, RDP, WMI, FTP, NFS, and VNC
39
+ are built out (native flags, credential dumping/gathering, command exec, file transfer, promoted
40
+ high-value `-M` modules, and structured output). The first seven are validated end-to-end against a
41
+ live AD lab; FTP/NFS/VNC are source-verified + unit-tested (no lab yet). A 3-level safety model gates
42
+ everything; the long tail of nxc `-M` modules is reachable via meta-tools.
43
+
44
+ ## Built for small / local models
45
+
46
+ With 131 tools, listing every one to the model would spend ~46k tokens of context
47
+ before any work starts enough to overflow a small-context (≤8B / 32k) model and to
48
+ make every call on a large one needlessly expensive. So the default `NXC_TOOL_MODE`
49
+ is **`dynamic`**: only a handful of meta-tools are exposed (`nxc_catalog`,
50
+ `nxc_find_tool`, `nxc_describe_tool`, `nxc_call`, `nxc_health`), and the model
51
+ discovers and dispatches the real tools on demand. This keeps the tool surface out
52
+ of the context window required to run on small local models, and cheaper (same
53
+ quality) on large ones. Set `NXC_TOOL_MODE=static` to opt out and list every tool. See
54
+ the `NXC_TOOL_MODE` row under [Configuration](#configuration-env-vars) and the
55
+ step-budget note beneath it.
56
+
57
+ ## Requirements
58
+
59
+ - Python ≥ 3.10, [`uv`](https://docs.astral.sh/uv/) or [`pipx`](https://pipx.pypa.io/)
60
+ - **NetExec installed separately** — it is not a pip dependency and is not on PyPI.
61
+ See the [official install guide](https://www.netexec.wiki/getting-started/installation).
62
+ Any install works as long as `nxc` / `netexec` is reachable on `PATH` or via
63
+ `NXC_COMMAND`; the server runs `nxc --version` on boot and refuses to start if it
64
+ can't find it.
65
+
66
+ ## Quick start
67
+
68
+ ### Option A: uv (run from a source checkout)
69
+
70
+ ```bash
71
+ uv sync
72
+
73
+ # Point at your nxc install (example: a uv-managed source checkout)
74
+ export NXC_COMMAND="uv run --directory ~/NetExec netexec"
75
+ export NXC_SCOPE="10.0.0.0/24" # required to target anything (fail-closed)
76
+
77
+ uv run netexec-mcp
78
+ ```
79
+
80
+ MCP client config (`command`/`args` launch the server itself):
81
+
82
+ ```json
83
+ {
84
+ "command": "uv",
85
+ "args": ["run", "--directory", "/path/to/netexec-mcp", "netexec-mcp"]
86
+ }
87
+ ```
88
+
89
+ ### Option B: install from PyPI (standalone `netexec-mcp` CLI)
90
+
91
+ ```bash
92
+ # Pick one installer — all put `netexec-mcp` on PATH:
93
+ pipx install netexec-mcp # pipx
94
+ uv tool install netexec-mcp # uv
95
+ # or run without installing:
96
+ uvx netexec-mcp # uv, one-shot
97
+
98
+ export NXC_COMMAND="nxc" # or however your nxc install is invoked
99
+ export NXC_SCOPE="10.0.0.0/24"
100
+
101
+ netexec-mcp
102
+ ```
103
+
104
+ MCP client config — `netexec-mcp` is on `PATH`, so no `uv`/`--directory` wrapper:
105
+
106
+ ```json
107
+ {
108
+ "command": "netexec-mcp",
109
+ "args": []
110
+ }
111
+ ```
112
+
113
+ On boot the server runs `<base> --version` and **refuses to start** if it fails
114
+ (unless mode `suggest`, which downgrades that to a warning). See `.mcp.json.example`
115
+ for a ready-to-edit MCP client config (uv variant).
116
+
117
+ ## Operating modes (`NXC_MODE`)
118
+
119
+ Four escalating levels of how much the server is allowed to *do*:
120
+
121
+ | Mode | What runs | Use when |
122
+ | --- | --- | --- |
123
+ | `suggest` | **Nothing executes.** Tools return the resolved nxc command for a human (the auditor) to run. Scope still enforced; offensive commands *can* be previewed. | You want the agent to plan commands you run yourself. |
124
+ | `recon` _(default)_ | Read-only enumeration; executes, credential-dumping and state-changing actions are refused. | Day-to-day authorized recon. |
125
+ | `loot` | Recon **plus** read-only credential-dumping (sam/lsa/ntds/gpp/roasting) — no state change on the target, but it harvests credential material. | Authorized credential-harvesting. |
126
+ | `full` | Everything executes, including state-changing / privilege-escalation actions (exec, write, spray, coercion-with-listener, exploits). | Authorized active testing. |
127
+
128
+ `NXC_MODE` is the canonical control; it defaults to `recon` when unset.
129
+
130
+ ## Configuration (env vars)
131
+
132
+ | Var | Purpose | Default |
133
+ | --- | --- | --- |
134
+ | `NXC_COMMAND` | Base command (shlex-parsed). Falls back to `nxc`/`netexec` on `PATH`. | autodetect |
135
+ | `NXC_PROTOCOLS` | Comma-separated protocols to enable (e.g. `smb,ldap`). | all implemented |
136
+ | `NXC_TOOL_MODE` | Tool-surface presentation — `dynamic` (**default**: expose only meta-tools; the ~100-tool surface is discovered via `nxc_find_tool`/`nxc_catalog` and run via `nxc_call`) or `static` (list every tool). Dynamic keeps the ~46k-token surface out of the context window — required for small-context models, ~8× cheaper (same quality) on large ones. Set `static` to opt out (best for a decisive model, or to avoid discovery round-trips on a big-context model). | `dynamic` |
137
+ | `NXC_SCOPE` | Comma-separated target allowlist (IP/CIDR/range/hostname). **Fail-closed**: targets with no scope are rejected. | _(none)_ |
138
+ | `NXC_MODE` | Operating level — `suggest` / `recon` / `loot` / `full`. | `recon` |
139
+ | `NXC_TIMEOUT` | Per-call timeout (seconds). | `300` |
140
+ | `NXC_MAX_TARGETS` | Max target tokens per call. | `256` |
141
+ | `NXC_AUDIT_LOG` | Path to an append-only JSONL audit log. | _(none)_ |
142
+ | `NXC_WORKSPACE` | nxc workspace to read for richer results. | _(none — reads nxc.conf's `workspace`, else `default`)_ |
143
+ | `NXC_PATH` | Override nxc's home dir (mirrors nxc's own `NXC_PATH`); where `nxc.conf` and `workspaces/` are read from. | `~/.nxc` |
144
+
145
+ > **Dynamic mode needs a bigger client-side step budget.** `max_steps` (how many tool
146
+ > calls the agent may make) is **not** an MCP setting — the server can't see or set it.
147
+ > It lives in your client's agent loop. In `dynamic` mode each action costs ~2 calls
148
+ > (`nxc_find_tool` → `nxc_call`), so a chain that needs 4 calls in `full` needs ~10 in
149
+ > `dynamic`. Set the budget high enough there, e.g. mcp-use:
150
+ > ```python
151
+ > MCPAgent(llm=ChatOllama(model="qwen3:14b"), client=client, max_steps=30) # default is 5 — too low
152
+ > ```
153
+ > Other clients (Claude Desktop, Cursor, Cline, …) have their own max-iterations
154
+ > setting. The MCP can only *hint* this via its startup `instructions`; it can't enforce it.
155
+
156
+ ## Resources
157
+
158
+ The server publishes cheatsheets as MCP resources so an agent can ground itself:
159
+
160
+ - `netexec://guide/operating-modes`
161
+ - `netexec://guide/auth`
162
+ - `netexec://guide/workflows` (incl. the cross-protocol gMSA chain)
163
+ - `netexec://guide/workspace` (cached recall vs. live — when to use which)
164
+ - `netexec://guide/safety`
165
+ - `netexec://catalog/tools` (live, auto-generated tool inventory)
166
+ - `netexec://workspace/credentials`, `/admins`, `/loggedin`, `/hosts` (workspace DB data,
167
+ same source as the `workspace_*` tools, filterless)
168
+
169
+ ## Safety & guardrails
170
+
171
+ Enforced at a single choke point before any command runs:
172
+
173
+ - **Scope allowlist** (`NXC_SCOPE`) — every target checked; **fail-closed**.
174
+ - **Mode gating** (`NXC_MODE`) — offensive actions refused outside `full`.
175
+ - **Target cap** + per-call **timeout**.
176
+ - **Audit log** — every command (executed / dry-run / rejected) appended as JSON.
177
+ - **No shell** — nxc is invoked as an argv list; nothing is shell-interpreted.
178
+
179
+ ## Example: the gMSA credential chain
180
+
181
+ ```
182
+ smb_lsa (full) -> secrets[] incl. { type: "gmsa_id", gmsa_id, ntlm }
183
+ ldap_gmsa_convert_id -> resolves the gmsa_id to an account name (gmsa-robin$)
184
+ <any tool> -> replay with username="gmsa-robin$", ntlm_hash=<nt>
185
+ ```
186
+
187
+ ## Development
188
+
189
+ ```bash
190
+ uv run pytest -q # mocked-subprocess unit tests (no nxc/network needed)
191
+ ```
192
+
193
+ Architecture and milestone history live in `PLAN.md`. Tools/flags are verified against
194
+ the nxc source (`nxc/protocols/<proto>/proto_args.py`) — `--help` lists args the
195
+ handlers reject.
196
+
197
+ ### nxc version
198
+
199
+ This MCP is a subprocess wrapper and pins no nxc dependency, but its tools/flags are
200
+ verified against a specific nxc build:
201
+
202
+ > **nxc 1.5.1 "Yippie-Ki-Yay", commit `738b842a`** (`738b842a…`, 2026-07-31, build 595)
203
+
204
+ Check your local build with `nxc --version` (it prints `version - codename - commit - build`).
205
+ nxc moves fast and occasionally moves/removes flags, so when you bump nxc, re-verify the
206
+ affected protocol's `proto_args.py` + handler and re-run the tests.
@@ -0,0 +1,185 @@
1
+ # netexec-mcp
2
+
3
+ An [MCP](https://modelcontextprotocol.io) server that lets an AI agent drive
4
+ **[NetExec](https://github.com/Pennyw0rth/NetExec)** (`nxc`) for **authorized**
5
+ security testing only.
6
+
7
+ It is a **pure subprocess wrapper**: it shells out to the `nxc` CLI as an argv list
8
+ (never `shell=True`, never importing NetExec as a library) and declares **no** nxc
9
+ dependency. How nxc itself is installed (PATH / uv / pipx / docker) is entirely up to you.
10
+
11
+ <img width="1417" height="581" alt="image" src="https://github.com/user-attachments/assets/8c72cd0d-77bf-4ccf-a553-7c5ccce55513" />
12
+ <img width="1479" height="618" alt="image" src="https://github.com/user-attachments/assets/ae30ebcc-c613-47ec-a565-8a1247a67509" />
13
+
14
+ ## Status
15
+
16
+ **v1 — all 10 nxc protocols, 131 tools** (117 protocol tools + 9 discovery/meta-tools +
17
+ 5 offline workspace-DB readers). SMB, LDAP, WinRM, MSSQL, SSH, RDP, WMI, FTP, NFS, and VNC
18
+ are built out (native flags, credential dumping/gathering, command exec, file transfer, promoted
19
+ high-value `-M` modules, and structured output). The first seven are validated end-to-end against a
20
+ live AD lab; FTP/NFS/VNC are source-verified + unit-tested (no lab yet). A 3-level safety model gates
21
+ everything; the long tail of nxc `-M` modules is reachable via meta-tools.
22
+
23
+ ## Built for small / local models
24
+
25
+ With 131 tools, listing every one to the model would spend ~46k tokens of context
26
+ before any work starts enough to overflow a small-context (≤8B / 32k) model and to
27
+ make every call on a large one needlessly expensive. So the default `NXC_TOOL_MODE`
28
+ is **`dynamic`**: only a handful of meta-tools are exposed (`nxc_catalog`,
29
+ `nxc_find_tool`, `nxc_describe_tool`, `nxc_call`, `nxc_health`), and the model
30
+ discovers and dispatches the real tools on demand. This keeps the tool surface out
31
+ of the context window required to run on small local models, and cheaper (same
32
+ quality) on large ones. Set `NXC_TOOL_MODE=static` to opt out and list every tool. See
33
+ the `NXC_TOOL_MODE` row under [Configuration](#configuration-env-vars) and the
34
+ step-budget note beneath it.
35
+
36
+ ## Requirements
37
+
38
+ - Python ≥ 3.10, [`uv`](https://docs.astral.sh/uv/) or [`pipx`](https://pipx.pypa.io/)
39
+ - **NetExec installed separately** — it is not a pip dependency and is not on PyPI.
40
+ See the [official install guide](https://www.netexec.wiki/getting-started/installation).
41
+ Any install works as long as `nxc` / `netexec` is reachable on `PATH` or via
42
+ `NXC_COMMAND`; the server runs `nxc --version` on boot and refuses to start if it
43
+ can't find it.
44
+
45
+ ## Quick start
46
+
47
+ ### Option A: uv (run from a source checkout)
48
+
49
+ ```bash
50
+ uv sync
51
+
52
+ # Point at your nxc install (example: a uv-managed source checkout)
53
+ export NXC_COMMAND="uv run --directory ~/NetExec netexec"
54
+ export NXC_SCOPE="10.0.0.0/24" # required to target anything (fail-closed)
55
+
56
+ uv run netexec-mcp
57
+ ```
58
+
59
+ MCP client config (`command`/`args` launch the server itself):
60
+
61
+ ```json
62
+ {
63
+ "command": "uv",
64
+ "args": ["run", "--directory", "/path/to/netexec-mcp", "netexec-mcp"]
65
+ }
66
+ ```
67
+
68
+ ### Option B: install from PyPI (standalone `netexec-mcp` CLI)
69
+
70
+ ```bash
71
+ # Pick one installer — all put `netexec-mcp` on PATH:
72
+ pipx install netexec-mcp # pipx
73
+ uv tool install netexec-mcp # uv
74
+ # or run without installing:
75
+ uvx netexec-mcp # uv, one-shot
76
+
77
+ export NXC_COMMAND="nxc" # or however your nxc install is invoked
78
+ export NXC_SCOPE="10.0.0.0/24"
79
+
80
+ netexec-mcp
81
+ ```
82
+
83
+ MCP client config — `netexec-mcp` is on `PATH`, so no `uv`/`--directory` wrapper:
84
+
85
+ ```json
86
+ {
87
+ "command": "netexec-mcp",
88
+ "args": []
89
+ }
90
+ ```
91
+
92
+ On boot the server runs `<base> --version` and **refuses to start** if it fails
93
+ (unless mode `suggest`, which downgrades that to a warning). See `.mcp.json.example`
94
+ for a ready-to-edit MCP client config (uv variant).
95
+
96
+ ## Operating modes (`NXC_MODE`)
97
+
98
+ Four escalating levels of how much the server is allowed to *do*:
99
+
100
+ | Mode | What runs | Use when |
101
+ | --- | --- | --- |
102
+ | `suggest` | **Nothing executes.** Tools return the resolved nxc command for a human (the auditor) to run. Scope still enforced; offensive commands *can* be previewed. | You want the agent to plan commands you run yourself. |
103
+ | `recon` _(default)_ | Read-only enumeration; executes, credential-dumping and state-changing actions are refused. | Day-to-day authorized recon. |
104
+ | `loot` | Recon **plus** read-only credential-dumping (sam/lsa/ntds/gpp/roasting) — no state change on the target, but it harvests credential material. | Authorized credential-harvesting. |
105
+ | `full` | Everything executes, including state-changing / privilege-escalation actions (exec, write, spray, coercion-with-listener, exploits). | Authorized active testing. |
106
+
107
+ `NXC_MODE` is the canonical control; it defaults to `recon` when unset.
108
+
109
+ ## Configuration (env vars)
110
+
111
+ | Var | Purpose | Default |
112
+ | --- | --- | --- |
113
+ | `NXC_COMMAND` | Base command (shlex-parsed). Falls back to `nxc`/`netexec` on `PATH`. | autodetect |
114
+ | `NXC_PROTOCOLS` | Comma-separated protocols to enable (e.g. `smb,ldap`). | all implemented |
115
+ | `NXC_TOOL_MODE` | Tool-surface presentation — `dynamic` (**default**: expose only meta-tools; the ~100-tool surface is discovered via `nxc_find_tool`/`nxc_catalog` and run via `nxc_call`) or `static` (list every tool). Dynamic keeps the ~46k-token surface out of the context window — required for small-context models, ~8× cheaper (same quality) on large ones. Set `static` to opt out (best for a decisive model, or to avoid discovery round-trips on a big-context model). | `dynamic` |
116
+ | `NXC_SCOPE` | Comma-separated target allowlist (IP/CIDR/range/hostname). **Fail-closed**: targets with no scope are rejected. | _(none)_ |
117
+ | `NXC_MODE` | Operating level — `suggest` / `recon` / `loot` / `full`. | `recon` |
118
+ | `NXC_TIMEOUT` | Per-call timeout (seconds). | `300` |
119
+ | `NXC_MAX_TARGETS` | Max target tokens per call. | `256` |
120
+ | `NXC_AUDIT_LOG` | Path to an append-only JSONL audit log. | _(none)_ |
121
+ | `NXC_WORKSPACE` | nxc workspace to read for richer results. | _(none — reads nxc.conf's `workspace`, else `default`)_ |
122
+ | `NXC_PATH` | Override nxc's home dir (mirrors nxc's own `NXC_PATH`); where `nxc.conf` and `workspaces/` are read from. | `~/.nxc` |
123
+
124
+ > **Dynamic mode needs a bigger client-side step budget.** `max_steps` (how many tool
125
+ > calls the agent may make) is **not** an MCP setting — the server can't see or set it.
126
+ > It lives in your client's agent loop. In `dynamic` mode each action costs ~2 calls
127
+ > (`nxc_find_tool` → `nxc_call`), so a chain that needs 4 calls in `full` needs ~10 in
128
+ > `dynamic`. Set the budget high enough there, e.g. mcp-use:
129
+ > ```python
130
+ > MCPAgent(llm=ChatOllama(model="qwen3:14b"), client=client, max_steps=30) # default is 5 — too low
131
+ > ```
132
+ > Other clients (Claude Desktop, Cursor, Cline, …) have their own max-iterations
133
+ > setting. The MCP can only *hint* this via its startup `instructions`; it can't enforce it.
134
+
135
+ ## Resources
136
+
137
+ The server publishes cheatsheets as MCP resources so an agent can ground itself:
138
+
139
+ - `netexec://guide/operating-modes`
140
+ - `netexec://guide/auth`
141
+ - `netexec://guide/workflows` (incl. the cross-protocol gMSA chain)
142
+ - `netexec://guide/workspace` (cached recall vs. live — when to use which)
143
+ - `netexec://guide/safety`
144
+ - `netexec://catalog/tools` (live, auto-generated tool inventory)
145
+ - `netexec://workspace/credentials`, `/admins`, `/loggedin`, `/hosts` (workspace DB data,
146
+ same source as the `workspace_*` tools, filterless)
147
+
148
+ ## Safety & guardrails
149
+
150
+ Enforced at a single choke point before any command runs:
151
+
152
+ - **Scope allowlist** (`NXC_SCOPE`) — every target checked; **fail-closed**.
153
+ - **Mode gating** (`NXC_MODE`) — offensive actions refused outside `full`.
154
+ - **Target cap** + per-call **timeout**.
155
+ - **Audit log** — every command (executed / dry-run / rejected) appended as JSON.
156
+ - **No shell** — nxc is invoked as an argv list; nothing is shell-interpreted.
157
+
158
+ ## Example: the gMSA credential chain
159
+
160
+ ```
161
+ smb_lsa (full) -> secrets[] incl. { type: "gmsa_id", gmsa_id, ntlm }
162
+ ldap_gmsa_convert_id -> resolves the gmsa_id to an account name (gmsa-robin$)
163
+ <any tool> -> replay with username="gmsa-robin$", ntlm_hash=<nt>
164
+ ```
165
+
166
+ ## Development
167
+
168
+ ```bash
169
+ uv run pytest -q # mocked-subprocess unit tests (no nxc/network needed)
170
+ ```
171
+
172
+ Architecture and milestone history live in `PLAN.md`. Tools/flags are verified against
173
+ the nxc source (`nxc/protocols/<proto>/proto_args.py`) — `--help` lists args the
174
+ handlers reject.
175
+
176
+ ### nxc version
177
+
178
+ This MCP is a subprocess wrapper and pins no nxc dependency, but its tools/flags are
179
+ verified against a specific nxc build:
180
+
181
+ > **nxc 1.5.1 "Yippie-Ki-Yay", commit `738b842a`** (`738b842a…`, 2026-07-31, build 595)
182
+
183
+ Check your local build with `nxc --version` (it prints `version - codename - commit - build`).
184
+ nxc moves fast and occasionally moves/removes flags, so when you bump nxc, re-verify the
185
+ affected protocol's `proto_args.py` + handler and re-run the tests.
@@ -0,0 +1,43 @@
1
+ [project]
2
+ name = "netexec-mcp"
3
+ version = "1.0.0"
4
+ description = "MCP server that drives NetExec (nxc) for authorized security testing."
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ license = "BSD-2-Clause"
8
+ license-files = ["LICENSE"]
9
+ authors = [
10
+ { name = "Martial Puygrenier", email = "mpgn@pm.me" },
11
+ ]
12
+ keywords = ["mcp", "netexec", "nxc", "pentest", "security", "active-directory", "smb", "ldap"]
13
+ classifiers = [
14
+ "Development Status :: 4 - Beta",
15
+ "Intended Audience :: Information Technology",
16
+ "License :: OSI Approved :: BSD License",
17
+ "Topic :: Security",
18
+ "Programming Language :: Python :: 3",
19
+ "Operating System :: OS Independent",
20
+ ]
21
+ dependencies = [
22
+ "fastmcp>=2.0",
23
+ ]
24
+
25
+ [project.urls]
26
+ Homepage = "https://github.com/mpgn/netexec-mcp"
27
+ Repository = "https://github.com/mpgn/netexec-mcp"
28
+ Issues = "https://github.com/mpgn/netexec-mcp/issues"
29
+
30
+ [project.scripts]
31
+ netexec-mcp = "netexec_mcp.server:main"
32
+
33
+ [build-system]
34
+ requires = ["hatchling"]
35
+ build-backend = "hatchling.build"
36
+
37
+ [tool.hatch.build.targets.wheel]
38
+ packages = ["src/netexec_mcp"]
39
+
40
+ [dependency-groups]
41
+ dev = [
42
+ "pytest>=8.0",
43
+ ]
@@ -0,0 +1,3 @@
1
+ """netexec-mcp: an MCP server that drives NetExec (nxc) for authorized security testing."""
2
+
3
+ __version__ = "0.1.0"