Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

powershell-mcp

Локальный MCP-сервер, который даёт Claude Code (и другим MCP-клиентам) инструмент для нативного запуска PowerShell — в обход bash-экранирования.


Зачем это

Встроенный инструмент Bash в Claude Code на Windows исполняет команды через Git Bash (POSIX-шелл). Когда ассистент отдаёт PowerShell-скрипт «на запуск» или собирает команду через bash, по дороге теряются/ломаются спецсимволы: кавычки, скобки ()/{}, $, бэктики `, &, |, <, >. В сложных скриптах это приводит к ошибкам, потере времени и сожжённым токенам на отладку «почему не запустилось».

powershell-mcp убирает прослойку bash полностью: скрипт передаётся как строковый аргумент инструмента, сохраняется во временный .ps1 (UTF-8 + BOM) и исполняется напрямую через pwsh. Ничего не экранируется руками — что отдал, то и выполнилось.

Как работает

Claude Code ──(MCP, stdio, JSON-RPC)──► index.js ──► временный .ps1 (UTF-8+BOM) ──► pwsh -NoProfile -NonInteractive -File
                                            │
                                            └─ проверка денлиста ДО запуска
  • Транспорт: stdio (как у большинства локальных MCP-серверов).
  • Один инструмент: run.
  • Stateless: каждый вызов — свежий процесс pwsh. Между вызовами ничего не сохраняется (ни переменные, ни cwd, ни импорты). Нужен контекст — передавай всё одним скриптом.
  • Кодировка: временный файл пишется в UTF-8 с BOM (гарантия, что PowerShell прочитает кириллицу правильно), а в начало скрипта подставляется бутстрап, выставляющий UTF-8 на вывод/ввод/пайпы. Профиль не грузится (-NoProfile) — поведение предсказуемо.
  • Без зависаний: -NonInteractive (никаких интерактивных промптов) + таймаут с принудительным kill.

Требования

  • Node.js ≥ 18
  • PowerShell 7 (pwsh). Проверить: pwsh -v. Если нет — поставить:
    winget install --id Microsoft.PowerShell --source winget
    Windows PowerShell 5.1 (powershell.exe) тоже запустится через PATH-фолбэк, но 7-я версия предпочтительнее (UTF-8 по умолчанию).

Установка

git clone <repo-url> powershell-mcp
cd powershell-mcp
npm install

Проверить, что всё работает:

npm test

Тест поднимает сервер, прогоняет реальные сценарии (математика, кириллица, спецсимволы, stderr, exit code, денлист, cwd, таймаут) и печатает результат.

Регистрация в Claude Code

Способ 1 — через CLI

claude mcp add powershell --scope user -- node "C:\\Users\\<ты>\\.claude\\mcp\\powershell-mcp\\index.js"

Способ 2 — вручную в ~/.claude.json

В секцию mcpServers добавить:

"powershell": {
  "command": "node",
  "args": ["C:\\Users\\<ты>\\.claude\\mcp\\powershell-mcp\\index.js"]
}

⚠️ Перезапусти Claude Code — MCP-соединения фиксируются при старте сессии, новый сервер появится только после рестарта.

Permission-правило

Чтобы инструмент не спрашивал разрешение на каждый вызов, добавь в allowsettings.json):

"mcp__powershell__run"

или шире — "mcp__powershell__*".

Использование

После регистрации и перезапуска у ассистента появляется инструмент mcp__powershell__run.

Параметры:

Параметр Тип Обяз. Описание
script string да Тело PowerShell-скрипта. Многострочный, с любыми спецсимволами.
cwd string нет Рабочая директория. По умолчанию — директория сервера.
timeout_ms number нет Таймаут в мс (по умолчанию 120000). По истечении процесс убивается.

Возврат: текст с exit code, блоком --- stdout --- и блоком --- stderr --- (раздельно). Вывод длиннее 100 000 символов обрезается.

Пример вызова (аргументы инструмента):

{
  "script": "Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 Name, CPU",
  "timeout_ms": 30000
}

Денлист (встроенные ограничения)

До запуска скрипт проверяется регэкспами из denylist.json (без учёта регистра). При совпадении — отказ без выполнения с указанием причины.

Покрывает по умолчанию: reg add/delete/..., изменение реестра через *-Item(Property) в HKLM/HKCU, icacls, takeown, Remove-Item -Recurse, rmdir /s, del /f, Format-Volume, Clear-Disk, format <буква>:, Stop/Restart-Computer, shutdown /... и т.п.

  • Редактируется свободно — это обычный JSON со списком { "pattern": "<regex>", "reason": "<текст>" }.
  • Перечитывается на каждый вызов — правки применяются без перезапуска сервера.
  • Если файл удалён/сломан — используется встроенный минимальный дефолт из index.js.

⚠️ Денлист — это «растяжка-проволока», а НЕ граница безопасности. PowerShell тривиально обходит любой текстовый фильтр (Invoke-Expression, -EncodedCommand, склейка строк). Реальный контроль доступа — это permission-правила mcp__powershell__* в Claude Code и авто-классификатор. Денлист лишь страхует от случайных деструктивных команд.

Кодировки

  • Скрипт сохраняется в UTF-8 с BOM → кириллица в самом скрипте читается корректно.
  • Бутстрап в начале каждого запуска: $OutputEncoding=[Console]::OutputEncoding=[Console]::InputEncoding=[System.Text.UTF8Encoding]::new() → вывод приходит в UTF-8, без cp866-кракозябр.

Переменные окружения

Переменная Назначение
PWSH_PATH Явный путь к pwsh.exe. Если задан и файл существует — используется он.

Порядок поиска pwsh: PWSH_PATHC:\Program Files\PowerShell\7\pwsh.exe%LOCALAPPDATA%\Microsoft\WindowsApps\pwsh.exe (App Execution Alias) → pwsh из PATH.

Структура проекта

powershell-mcp/
├── index.js        — сервер (резолв pwsh, денлист, запуск, форматирование)
├── denylist.json   — паттерны запретов (правится руками)
├── test.mjs        — сквозной тест по MCP-протоколу
├── package.json
└── README.md

Траблшутинг

  • pwsh не найден — поставь PowerShell 7 (см. «Требования») или задай PWSH_PATH.
  • Кракозябры в выводе — убедись, что в скрипте нет своего переопределения кодировки, ломающего бутстрап.
  • Инструмент не появился — перезапустил Claude Code? Проверь claude mcp list — сервер должен быть ✔ Connected.
  • Сервер не стартует — выполни node index.js вручную: в stderr будет строка [powershell-mcp] запущен. pwsh: <путь>.

Лицензия

MIT