Is your feature request related to a problem?
Yes. dbt-mcp invokes the dbt CLI by executing DBT_PATH directly as a subprocess. On Windows with Smart App Control (SAC) enabled, the unsigned dbt console-script launcher (.venv/Scripts/dbt.exe) is blocked with WinError 4551 - An Application Control policy has blocked this file. The server crashes on startup during binary detection, and the MCP client only sees a generic -32000.
Startup path: load_config() calls detect_binary_type(settings.dbt_path), which runs subprocess.run([dbt_path, "--help"]) and raises:
OSError: [WinError 4551] An Application Control policy has blocked this file
File ".../dbt_mcp/dbt_cli/binary_type.py", line 30, in detect_binary_type
File ".../dbt_mcp/config/config.py", line 200, in load_config
Root cause: SAC blocks execution of unsigned PE launchers. The dbt.exe console-script shim is unsigned with no cloud reputation, so it is blocked. The signed python.exe in the same venv is trusted, and python -m dbt.cli.main ... runs fine. This also breaks plain uv run dbt, so it is not MCP-specific, but dbt-mcp offers no way to route around it.
Why the usual escapes do not apply:
- SAC has no per-app whitelist, and its Microsoft-signed base policy does not accept WDAC supplemental (hash-allow)
policies, so dbt.exe cannot be individually
- Signing is not a fix dbt-labs can ship: the blocked dbt.exe is a launcher stub generated locally by uv/pip, not an
artifact you distribute, and SAC gates on si signature presence alone.
- A local .cmd/.bat shim does not work: dbt-mcp calls subprocess with shell=False, and Python 3.12 refuses to launch .cmd/.bat that way (WinError 2). Any replacement .exe is unsigned and blocked in turn.
Microsoft's own guidance for this case is to refactor so that only signed binaries execute, i.e. invoke via python -m through the trusted interpreter.
Environment:
- OS: Windows 11 10.0.26200 / 25H2, SAC On/enforcing (VerifiedAndReputablePolicyState = 1)
- dbt-mcp: 1.21.1 (latest)
- dbt-mcp runtime Python: 3.12.10
- dbt-core: 1.11.11 (dbt Core local, CLI tools enabled), uv-managed venv
- Launched via uvx dbt-mcp (also repros with
- Config: DBT_PROJECT_DIR + DBT_PATH=.../.venv/Scripts/dbt.exe
Describe the solution you'd like
Let the dbt invocation be a command list, not a single executable path. Either shape works:
- A new DBT_COMMAND env var parsed with shlex.split, e.g. DBT_COMMAND="python -m dbt.cli.main" (or an absolute .../python.exe -m dbt.cli.main). Everywhere the code currently does [dbt_path, ...], use [*dbt_command, ...].
- Or a boolean DBT_INVOKE_AS_MODULE=true that internally builds [sys.executable, "-m", "dbt.cli.main", ...] from the venv resolved via DBT_PROJECT_DIR.
The three call sites to change:
- dbt_cli/binary_type.py:30 - subprocess.run([file_path, "--help"])
- dbt_cli/binary_type.py:75 - subprocess.run([dbt_path, "--version"])
- dbt_cli/tools.py:134 - subprocess.Popen([config.dbt_path, color_flag, *full_command])
All three keep detect_binary_type and every CLI tool working, just routed through the signed interpreter.
Describe alternatives you've considered
- Whitelist dbt.exe in SAC: not possible (no per-app exception; SAC base policy rejects WDAC supplementals). Would require replacing SAC with a custom WDAC base policy, and the hash rule breaks on every dbt upgrade.
- Turn SAC off: works, but a system-wide security downgrade to run one MCP server; unacceptable on many managed/dev machines.
- Point DBT_PATH at python.exe: fails, because dbt-mcp appends dbt subcommands, so python.exe --help / python.exe run do not behave as dbt.
- A .cmd/.exe shim at DBT_PATH: fails, because subprocess(shell=False) refuses .cmd/.bat on Python 3.12, and any new .exe is itself unsigned and blocked.
Confirmed working local workaround (evidence the upstream fix is a few lines): a launcher that monkeypatches subprocess.run/Popen to rewrite any spawn of the blocked dbt.exe into the equivalent invocation through the venv's signed python.exe as python -m dbt.cli.main, then calls dbt_mcp.main.main(). With this in place all CLI tools register and run under SAC with no 4551. It patches only stdlib rather than dbt-mcp, which is exactly what native command-list support would make unnecessary.
Additional context
SAC is increasingly default-on for new Windows 11 machines and blocks the entire unsigned-console-script pattern (uvx, venv entry-point .exes, etc.), so this will affect more users over time. Microsoft SAC Q&A on the signed-binaries-only remediation: https://learn.microsoft.com/en-us/answers/questions/5791210/application-signed-and-blocked-by-smart-app-contro
Is your feature request related to a problem?
Yes. dbt-mcp invokes the dbt CLI by executing DBT_PATH directly as a subprocess. On Windows with Smart App Control (SAC) enabled, the unsigned dbt console-script launcher (.venv/Scripts/dbt.exe) is blocked with WinError 4551 - An Application Control policy has blocked this file. The server crashes on startup during binary detection, and the MCP client only sees a generic -32000.
Startup path: load_config() calls detect_binary_type(settings.dbt_path), which runs subprocess.run([dbt_path, "--help"]) and raises:
OSError: [WinError 4551] An Application Control policy has blocked this file
File ".../dbt_mcp/dbt_cli/binary_type.py", line 30, in detect_binary_type
File ".../dbt_mcp/config/config.py", line 200, in load_config
Root cause: SAC blocks execution of unsigned PE launchers. The dbt.exe console-script shim is unsigned with no cloud reputation, so it is blocked. The signed python.exe in the same venv is trusted, and python -m dbt.cli.main ... runs fine. This also breaks plain uv run dbt, so it is not MCP-specific, but dbt-mcp offers no way to route around it.
Why the usual escapes do not apply:
policies, so dbt.exe cannot be individually
artifact you distribute, and SAC gates on si signature presence alone.
Microsoft's own guidance for this case is to refactor so that only signed binaries execute, i.e. invoke via python -m through the trusted interpreter.
Environment:
Describe the solution you'd like
Let the dbt invocation be a command list, not a single executable path. Either shape works:
The three call sites to change:
All three keep detect_binary_type and every CLI tool working, just routed through the signed interpreter.
Describe alternatives you've considered
Confirmed working local workaround (evidence the upstream fix is a few lines): a launcher that monkeypatches subprocess.run/Popen to rewrite any spawn of the blocked dbt.exe into the equivalent invocation through the venv's signed python.exe as python -m dbt.cli.main, then calls dbt_mcp.main.main(). With this in place all CLI tools register and run under SAC with no 4551. It patches only stdlib rather than dbt-mcp, which is exactly what native command-list support would make unnecessary.
Additional context
SAC is increasingly default-on for new Windows 11 machines and blocks the entire unsigned-console-script pattern (uvx, venv entry-point .exes, etc.), so this will affect more users over time. Microsoft SAC Q&A on the signed-binaries-only remediation: https://learn.microsoft.com/en-us/answers/questions/5791210/application-signed-and-blocked-by-smart-app-contro