mcp-local-access
Enables Notion AI to access a designated local folder, providing file operations such as reading, searching, editing, creating, deleting, and running allowed commands.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mcp-local-accesssearch the codebase for all TODO comments and list them"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MCP (Local Access)
MCP-сервер позволяет облачным сервисам с поддержкой MCP, например Notion AI. Предоставлять доступ к одной папке на вашем компьютере: читать файлы, искать по ним, править, создавать и удалять, а также запускать разрешённые команды.
MCP сервер — это «руки», облачный сервис — «мозг». Вместо копирования кода в чат и обратно, MCP позволяет работать с файлами на ПК.
Зачем это нужно
Чат с ИИ видит реальный проект, а не пересказ: точные файлы, точные строки.
Правки применяются сразу в файлы, с диффом в ответе.
Рамки задаёте вы: одна корневая папка, список запрещённых путей, белый список команд, при желании — режим «только чтение».
Статус. Версия разработана для Windows и MacOS, но реально протестирована только на Windows; ветки для macOS/Linux написаны, но не проверены.

Содержание
Related MCP server: Secure Local Workspace MCP
1. Как это работает
Notion AI / claude.ai / chatgpt
│ HTTPS + Bearer-токен
▼
cloudflared-туннель или свой web сервер с TLS
│ HTTP внутри локальной сети
▼
server.py (слушает host:port, отдаёт /mcp)
│ все пути проверяются: песочница + права
▼
rootDir + явно разрешённые внешние папки Read/WriteСтек: Python + MCP SDK для Python (FastMCP) + uvicorn, транспорт Streamable HTTP
на пути /mcp, авторизация Bearer-токеном. Сервер ничего не знает о способе
публикации: он просто слушает host:port, а как этот порт оказался в интернете —
дело туннеля или прокси.
2. Структура проекта
Путь | Что это |
| MCP-сервер: конфиг, песочница путей, права, регистрация инструментов, авторизация |
| диалог Ask me: интерфейс, звук и ожидание ответа пользователя |
| файл настроек, создайте его из |
| шаблон настроек |
| файл хранит токен |
| четыре зависимости: |
| этот файл |
| базовые инструкции для ИИ, чтобы ИИ знал минимальный контекст по вашему проекту |
|
|
3. Требования
Python 3.10 или новее (
python --version).Способ отдать локальный порт наружу по HTTPS — одно из двух:
cloudflared, если своего веб сервера нет:
Windows:
winget install Cloudflare.cloudflaredmacOS:
brew install cloudflared
свой обратный прокси с TLS (на базе Nginx, Caddy, Traefik) перед этим портом.
При первом запуске server.py, сам генерирует токен, установка для cloudflare
для этой задачи не нужна, он сам сам cloudflared.
4. Установка
cd local-access
python -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activate
pip install -r requirements.txt5. Настройка
Все настройки лежат в config.json. Скопируйте шаблон и поправьте:
# Windows
copy config.example.json config.json
# macOS / Linux
cp config.example.json config.json{
"rootDir": "C:/usr/mcp/local-access",
"host": "0.0.0.0",
"port": 8000,
"readOnly": false,
"jsonResponse": false,
"rulesFile": "Rules.md",
"logDir": "logs",
"audit": true,
"maxCommandTimeout": 600,
"permissions": { "...": "см. раздел 11" }
}Ключ | Значение |
| Основная папка файловой песочницы. Всё вне неё закрыто, кроме явно подключённых абсолютными правилами |
| Интерфейс для прослушивания. По умолчанию |
| Локальный порт; туннель или прокси смотрит сюда. По умолчанию 8000. |
|
|
|
|
| Путь к файлу-путеводителю для модели. Необязательный, см. раздел 10. |
| Папка внутри |
|
|
| Верхняя граница |
| Правила по путям и командам, см. раздел 11. |
| Мост к расширению Browser MCP, см. «Браузер (Browser MCP)» в разделе 9. Необязательный. |
Несколько файлов настроек
По умолчанию читается config.json. Другой файл задаётся ключом --config
(короткая форма -c). Путь указывать не нужно: файл всегда ищется в папке, где
лежит server.py.
rem start.cmd
start "MCP Server" cmd /k python C:\usr\mcp\local-access\server.py --config new.jsonПорядок выбора:
--config, затем переменнаяCONFIG_FILE, затемconfig.json.Файл, указанный через
--config, обязан существовать — иначе сервер не стартует с ошибкойConfig file not found. Отсутствиеconfig.jsonпо умолчанию, как и раньше, не ошибка.Активный файл настроек всегда закрыт для модели, как бы он ни назывался: правило
*(**/config.json)не покрыло быnew.json. Неактивные запасные конфиги защищайте сами, например"*(**/new.json)"вdeny.Имя активного файла сервер печатает при старте в строке
config.
В .env — только секретный токен:
# Windows
copy .env.example .env
# macOS / Linux
cp .env.example .envОставьте MCP_TOKEN пустым: при первом запуске сервер сгенерирует токен и
запишет его в эту же строку. Чтобы сменить токен, очистите значение и
перезапустите сервер.
6. Запуск и публикация
Нужны два терминала.
Терминал 1 — сервер:
python server.pyОн печатает эндпоинт, токен и действующие правила:
local-mcp v0.1
root : C:\usr\mcp\my-project
endpoint : http://0.0.0.0:8000/mcp
token : 3f8c1d...
read-only : no
rules : C:\usr\mcp\local-mcp-v0.1\Rules.md
logs : C:\usr\mcp\my-project\logs (audit.log: last 300 lines)
processes : adopted 1, cleaned 4 old log(s)
config : C:\usr\mcp\local-mcp-v0.1\config.json
perms : defaultMode allow
allow : List(**), Read(**), Edit(**), Create(**), Delete(**)
deny : *(**/.env), *(**/.env.*), *(**/config.json), *(**/secrets/**)
run : Run(npm run dev), Run(npm run build), Run(git status)
browser : ws://localhost:9009 - press 'Connect' in the Browser MCP extension
WARNING: the server is listening on the whole local network.
For a tighter setup set "host": "127.0.0.1" in config.json.Вариант A — быстрый туннель cloudflared
Терминал 2:
cloudflared tunnel --url http://localhost:8000 --protocol http2После запуска в терминале можно увидеть публичный адрес:
Requesting new quick Tunnel on trycloudflare.com... +--------------------------------------------------------------------------------------------+ | Your quick Tunnel has been created! Visit it at (it may take some time to be reachable): | | https://verbal-univ-silent-bracelet.trycloudflare.com | +--------------------------------------------------------------------------------------------+
В данном случае это https://verbal-univ-silent-bracelet.trycloudflare.com.
Обратите внимание, что после каждого запуска url адрес меняется.
--protocol http2заставляет туннель работать по TCP вместо QUIC/UDP. Без этого флага соединение может отваливаться сtimeout: no recent network activity, а запросы — падать с ошибкой Cloudflare 1033.Туннель не нужно перезапускать вместе с сервером: он пробрасывает
localhost:8000, и пока порт тот же, публичный адрес продолжает работать. Перезапуск нужен, только если вы поменялиportили туннель сам умер.Адрес быстрого туннеля меняется при каждом старте cloudflared — значит, URL в клиенте придётся обновлять.
Вариант B — использование веб сервер перед сервером (постоянный адрес)
Для этого варианта нужно иметь:
статический внешний IP-адрес
веб сервер с TLS, на котором можно настроить обратный прокси
домен, при этом для mcp можно использовать домен третьего уровня
получить сертификат для работы https
В config.json:
"host": "0.0.0.0"— значение по умолчанию и то, что нужно прокси: на127.0.0.1сервер доступен только с этой машины."port": 8000— или любой свободный порт, на который смотрит прокси.После правки файла перезапустите
server.pyи проверьте строкуendpoint.
На хосте с прокси нужен только location /mcp — публичный путь это дело прокси,
сервер всегда отдаёт /mcp.
Пример настройки обратного прокси на Nginx:
server {
listen 443 ssl;
server_name mcp.example.com;
location /mcp {
proxy_pass http://192.168.1.50:8000/mcp; # машина, где запущен server.py
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_buffering off; # SSE должен стримиться, а не буферизоваться
proxy_request_buffering off;
proxy_read_timeout 3600s;
chunked_transfer_encoding on;
}
}Ключевые строки —
proxy_buffering offиproxy_request_buffering off: транспорт стримит SSE, и буферизующий прокси подвешивает каждый ответ до таймаута.Заголовок
Authorizationпроходит без изменений, токен доезжает как есть.Сервер сам переписывает заголовок
Host, так что защита SDK от DNS-rebinding не требует дополнительных заголовков (ошибки 421 не будет).TLS терминируется на прокси, до сервера идёт обычный HTTP внутри локальной сети.
Адрес после этого постоянный: https://mcp.example.com/mcp вводится в клиент
один раз и переживает перезапуски и сервера, и прокси.
7. Подключение клиента
Notion (Settings → Connections → добавить MCP-сервер):
URL:
https://ваш-адрес/mcp— суффикс/mcpобязателенАутентификация: Bearer-токен, префикс
Bearer, сам токен — из терминала 1
8. Настройка через JSON на примере accio.com
Некоторые сервисы позволяют добавить MCP-сервер не по полям формы, а одним
блоком JSON. Например, в accio.com: Settings → MCP → секция Custom → кнопка
Add custom MCP (или «+ Add») → диалог Add Custom MCP Server. В диалоге
есть четыре вкладки Configuration Mode: JSON | Stdio (Local) | HTTP | SSE.
Откройте вкладку JSON и вставьте этот текст:
{
"mcpServers": {
"Local Access": {
"type": "http",
"url": "https://your-host.example.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_TOKEN"
}
}
}
}Затем замените значения по умолчанию на свои:
url— адрес вашего туннеля или домена, суффикс/mcpобязателенAuthorization— префиксBearerи ваш токен (MCP_TOKENиз.env, сервер печатает его при запуске)
Ключ Local Access — это просто имя подключения в интерфейсе, его можно
поменять. Тот же JSON подходит любому клиенту, который принимает конфигурацию
в формате mcpServers.
9. Инструменты
Пути внутри проекта задаются относительно rootDir. Для явно разрешённых
внешних папок доступны абсолютные пути и ссылки из проекта. Остальные внешние
пути и ссылки блокируются. См. «Внешние папки и сетевые пути» в разделе 11.
Путеводитель
Инструмент | Что делает |
| Возвращает |
Тот же текст автоматически дописывается к первому результату инструмента в диалоге, так что обычно вызывать его не нужно.
Файлы
Инструмент | Что делает |
| Листинг папки; |
| Файл с номерами строк, постранично для больших файлов |
| Поиск по проекту, отдаёт |
| Размер, число строк, время изменения, текст или бинарник |
| Точная замена, возвращает дифф |
| Несколько замен в одном файле, всё или ничего |
| Новый файл или папка |
| Переименование или перемещение |
| Безвозвратное удаление файла или папки |
Шумные папки (
node_modules,.git,dist,build,.venv,venv,__pycache__,.next,.idea) при листинге и поиске пропускаются всегда.У
deleteнет корзины: непустая папка требуетrecursive=true, сам корень удалить нельзя, а папка, внутри которой лежит запрещённый правилами файл, не удаляется целиком.moveтребует правDeleteна источник иCreateна приёмник, поэтому защищённый файл нельзя вынести из-под защиты переносом.Один файл не стоит править двумя вызовами одновременно:
edit_fileиmulti_editчитают и пишут файл целиком, параллельные вызовы затирают друг друга.
Команды
Инструмент | Что делает |
| Запускает команду внутри |
| Всё, что запущено в этой сессии: живое и завершённое |
| Состояние и свежий вывод одного процесса |
| Убивает процесс вместе с детьми |
Команды идут через системный шелл, поэтому
&&,||,|и;работают. Каждое звено цепочки проверяется по правиламRun(...)отдельно, команда без подходящего правила отклоняется.Команда должна быть одной строкой: перевод строки — разделитель команд, так что многострочная строка выполнилась бы лишь частично. Склеивайте шаги через
&&или положите их в скрипт.background=false(по умолчанию) — для команд, которые завершаются: вызов возвращает код выхода и вывод, процесс после этого гарантированно мёртв. По таймауту убивается всё дерево процессов.background=true— для долгоживущих команд вродеnpm run dev. Процесс живёт после вызова; когда вернуть управление, решаютwait_for(регулярное выражение) илиidle_timeout, напримерwait_for: "ready in|listening on".Вывод стримится в
logs/cmd-NNN.log, а не держится в памяти, так что шумная сборка не разорвёт ответ. Длинный вывод возвращается началом и хвостом.Каждый запущенный процесс отслеживается, и короткий блок
[processes]дописывается к любому результату инструмента, пока что-то работает или только что завершилось:
[processes]
#1 running npm run dev (pid 24188, 96s, log logs/cmd-001.log)
#2 exited (exit 0) npm run build (log logs/cmd-002.log)Так модель остаётся в курсе терминала: MCP-сервер не может сам прислать уведомление внутрь хода модели, поэтому состояние заново подкладывается контекстом при следующем вызове.
Запуск команды, которая уже работает, отклоняется со ссылкой на её номер;
restart=trueсначала останавливает старый процесс.Вывод принудительно переводится в UTF-8 (
chcp 65001на Windows,PYTHONIOENCODING,NO_COLOR), чтобы логи не превращались в кракозябры.Процессы убиваются деревом (
taskkill /Tна Windows, целая группа процессов на macOS/Linux, сначалаSIGTERM, потомSIGKILL), потому что порт держит неnpm, а его дочернийnode.При выходе сервера все запущенные процессы останавливаются, так что
Ctrl+Cне оставляет висящих dev-серверов.Реестр процессов дублируется в
logs/processes.json. Жёсткое убийство сервера (закрытая консоль, диспетчер задач) не выполняет очистку и оставляет детей живыми, поэтому при старте каждая запись сверяется с ОС: живой pid подхватывается обратно в реестр и показывается какrunning (adopted), остальное считается завершённым, а ихcmd-NNN.logудаляются. Номера продолжают расти, поэтому имена логов не конфликтуют. Подхваченный процесс можно смотреть и останавливать как обычно — теряется только точный код выхода, потому что сервер больше не владеет его хэндлом.
Диалоговое окно
Инструмент show-dialog-box() открывает диалоговое окно Ask me, которое позволяет входить в зацикленный диалог с агентом.

Сценарий работы
При работе с MCP Local Access в инструкциях агента добавляется правило: после завершения задачи или уточняющего вопроса в чате вызвать
show-dialog-box.Введите следующий запрос в появившемся окне и нажмите OK. Пустой ответ - завершают диалог.
Если пользователь не ответил в течение 50 сек (таймаут можно изменить), то инструмент перезапускает себя, если этого не делать, то инструмент завершится по таймауту.
Настройка
В файле config.json есть параметры, которые настраивают работу с этим инструментом, пример:
"dialog": {
"width": 500,
"height": 300,
"sound": true,
"autoPrompt": true,
"waitTimeoutSeconds": 50
}Настройки задают начальную ширину и высоту окна, время перезапуска инструмента (менять нужно осознанно), включить звук при вызове инструмента, нужно ли вызывать инструмент после ответа.
Автоматическое указание агенту
Инструкция передаётся в MCP-поле instructions и дополнительно с первым
результатом инструмента; повторно — при изменении файла правил или после
длительного перерыва.
Параметр принимает только JSON true/false. Если параметр
отсутствует, указания включены.
Ожидание и таймауты
Когда время одного вызова истекает, инструмент возвращает Call show-dialog-box again to continue waiting for the same window. Агент должен вызвать его снова: продолжится ожидание того же
окна, без дубликата и без потери набранного текста. Если ответ уже отправлен, следующий вызов заберёт сохранённый результат. Одновременно ожидающий второй вызов получает сообщение, что ожидание уже идёт.
Управление браузером (Browser Control)
Инструменты MCP Local Access browser_* управляют вашим браузером, используя расширение Browser Control.
server.py поднимает WebSocket на ws://localhost:9009, к которому подключается расширение.
Браузер могут использовать облачные агенты и работать с сайтами под вашей авторизацией.
Как включить
Установите в Chrome расширение Browser Control.
В браузере откройте нужную вкладку, нажмите на иконку Browser Control и кнопку Connect this tab. Либо агент может сам открыть Chrome и подключить свою вкладку без дополнительных действий со стороны пользователя.
Инструмент | Что делает |
| Показывает, слушает ли сервер порт, подключена ли вкладка и есть ли агентская сессия; выводит расширенную диагностику |
| Запускает Chrome с вашим профилем и подключает вкладку агента без Connect |
| Закрывает вкладку агента; Chrome, запущенный агентом, завершает по PID |
| Открывает URL, возвращает снимок страницы |
| Назад / вперёд по истории |
| ARIA-снимок страницы с |
| Клик по элементу |
| Наведение на элемент |
| Перетаскивание |
| Ввод текста, |
| Выбор в выпадающем списке |
| Нажатие клавиши, например |
| Пауза в секундах, отклоняет отрицательные, бесконечные и превышающие 60 секунд значения |
| Скриншот вкладки (PNG) |
| Возвращает логи и структурированную информацию о состоянии их сбора |
| Одна команда Chrome DevTools Protocol для подключённой вкладки ( |
| JavaScript в странице, как в консоли DevTools; возвращает значение или исключение |
| Подписка на события домена CDP ( |
| Реальная проверка debugger, подписок, ошибок и потерь сбора |
| Console API, исключения и браузерные Log-сообщения; очистка только явно |
|
|
|
|
Сценарий для модели: browser_snapshot → взять ref нужного элемента → browser_click / browser_type. Действия возвращают свежий снимок страницы.
В readOnly у browser_cdp разрешены только читающие методы (get*, describe*, query*, search*, resolve*); browser_evaluate и подписки запрещены. В журнал аудита записываются только имя метода и длина выражения, но не параметры и не код.
Сервер отказывает в методах, которые выходят за пределы вкладки (CDP_DENIED_DOMAINS / CDP_DENIED_METHODS в server.py): Browser.*, Target.*, Network.getAllCookies, Storage.getCookies/setCookies/clearCookies, Network.clearBrowserCookies/clearBrowserCache, Storage.clearDataFor*, Network.loadNetworkResource, Network.getCookies с urls, Page.close/crash, а также Page.navigate на javascript: и, по умолчанию, на file:// (если browser.allowFileUrls не установлен в true). Browser Control дополнительно ограничивает Network.setCookie(s)/deleteCookies и методы с origin/securityOrigin/storageKey сайтом текущей вкладки.
Настройка MCP Local Access (необязательно; ниже приведены значения по умолчанию):
"browser": {
"enabled": true,
"host": "localhost",
"port": 9009,
"timeoutSeconds": 30,
"allowFileUrls": false,
"chromePath": "",
"userDataDir": "",
"profileDirectory": "",
"launchArgs": [],
"launchTimeoutSeconds": 30,
"closeTimeoutSeconds": 10
}Ключ | Значение |
|
|
| Интерфейс WebSocket. |
| Порт, к которому подключается расширение. Browser MCP знает только |
| Сколько ждать ответа расширения на одну команду |
| По умолчанию |
|
|
|
|
|
|
|
|
| Сколько секунд |
| Сколько |
Важно
В режиме
readOnlyдоступны чтение страницы, снимки и чтение диагностики. Действия браузера, очистка журналов и включение/выключение сетевого сбора запрещены.В
logs/audit.logзаписываются переходы, клики и события ввода; сам введённый текст не записывается (это может быть пароль) — только его длина.Браузер не входит в песочницу
rootDir: агент видит всё, что открыто в подключённой вкладке, и действует от вашего имени.Для
browser_navigateиPage.navigateсервер всегда запрещает переходы наjavascript:, а наfile://— только приbrowser.allowFileUrls=false(значение по умолчанию). Разрешение на сервере не отменяет отдельные ограничения Browser Control и Chrome.
Агентский браузер: browser_launch / browser_close
Установить расширение Browser Control может только пользователь.
Агент может сам открыть Chrome и подключить свою вкладку.
Если userDataDir пуст, Chrome запускается с вашим профилем и может открывать сайты под вашей учётной записью.
Варианты запуска Chrome:
Chrome не запущен: агент запускает его, а после работы закрывает свою вкладку. Если других открытых вкладок нет, агент завершает Chrome по PID.
Chrome уже открыт: новая вкладка открывается в последнем активном окне, а по завершении работы агент закрывает только свою вкладку.
Для работы с браузером вкладка агента не обязана быть активной. Агент может получать снимки страницы, нажимать на элементы, переходить по ссылкам и делать скриншоты даже в свёрнутом окне. Страница при этом «спит», и её обновления происходят медленнее.
Сбор ограничен основной CDP-целью выбранной вкладки; дочерние CDP-сессии не агрегируются. Журналы хранятся в памяти и теряются при перезапуске worker, отключении или смене вкладки.
Большие снимки ограничены 20 000 пикселей по стороне и бюджетом 32 млн пикселей с учётом DPR/масштаба; возможны ограничения конкретного Chrome, sticky и lazy loading. Перед выпуском требуется фактическая проверка в Chrome: mock-тесты её не заменяют.
10. Rules.md — краткое описание вашего проекта
Rules.md — (опционально) необязательный файл, кратко опишите свой проект,
или можете указать путь к файлам документации по вашему проекту.
Смысл простой — не объяснять модели детали о проекте в каждом новом диалоге.
Название файла и путь к этому файлу, можно изменить в переменной
rulesFileвconfig.json. Если переменная не задана, то берется файлRules.md, расположенный в папке указанной вrootDir.Файл перечитывается при изменении, перезапуск не нужен: новый текст приходит со следующим результатом инструмента и в следующей сессии клиента.
11. Права доступа
Правила живут в блоке permissions файла config.json и записываются в стиле
Claude Code: Инструмент(glob-путь).
{
"permissions": {
"defaultMode": "allow",
"allow": ["List(**)", "Read(**)", "Edit(**)", "Create(**)", "Delete(**)"],
"deny": [
"*(**/.env)",
"*(**/.env.*)",
"*(**/config.json)",
"*(**/secrets/**)",
"*(**/*.pem)",
"*(**/*.key)",
"Edit(**/.git/**)",
"Create(**/.git/**)",
"Delete(**/.git/**)"
]
}
}Глаголы:
List,Read,Edit,Create,Delete,Run, внешнийWriteили*для всех путевых глаголов. Соответствие инструментам:ListиReadвместе определяют, что показываетlist_files;Readпокрывает ещёsearch_textиfile_info;Editпокрываетmulti_edit;Create—createи приёмникmove;Delete—deleteи источникmove.Runстоит особняком: его аргумент — шаблон команды, а не путь, поэтому*(**)его никогда не выдаёт. См. «Правила для команд» ниже.defaultMode: "allow"— внутриrootDirразрешено всё, что не запрещено (чёрный список). Внешние папки всегда требуют явного абсолютногоRead/Write.defaultMode: "deny"— работают только пути изallow(белый список).denyвсегда сильнееallow.Обычные шаблоны задаются относительно
rootDir, разделитель —/, поддерживаются*(один сегмент),**(любая глубина) и?(один символ).Шаблоны привязаны к корню, поэтому
.envсовпадает только с файлом в корне. Чтобы накрыть все подпапки, нужен префикс**/—**/.env.secrets/**скрывает и саму папкуsecrets.Запрещённые элементы не показываются в
list_files, вместо них выводится число скрытых записей.Если блока
permissionsнет, действуют встроенные значения: разрешено всё, кроме**/.env,**/.env.*,**/secrets/**,**/*.pem,**/*.key, плюс запрет записи и удаления внутри**/.git/**.Правила читаются при старте — после правки перезапустите сервер.
*(**/config.json)доступ к файлу закрыт для модели, чтобы не переписала собственные права.
Внешние папки и сетевые пути
Чтобы подключить конкретную папку вне rootDir, владелец добавляет в
permissions.allow абсолютное правило Read(папка) или Write(папка).
Корень проекта менять не нужно. Это разрешение папки и всего её содержимого,
а не всего диска.
{
"permissions": {
"defaultMode": "allow",
"allow": [
"List(**)", "Read(**)", "Edit(**)", "Create(**)", "Delete(**)",
"Read(J:/src/**)",
"Write(//debian/share/work)"
],
"deny": [
"*(**/.env)", "*(**/.env.*)", "*(**/config.json)",
"*(**/secrets/**)", "*(**/*.pem)", "*(**/*.key)",
"Delete(//debian/share/work/important/**)"
]
}
}Внешнее правило | Листинг, поиск, сведения и чтение | Изменение и создание | Удаление и перемещение |
| Да | Нет | Нет |
| Да | Да | Да, с проверкой прав источника и назначения |
Read(J:/src)иRead(J:/src/**)равнозначны: включают саму папку и любую глубину вложенности. То же дляWrite. Другие шаблоны в разрешении внешней папки запрещены: укажите конкретный абсолютный путь.Поддерживаются дисковые пути Windows (
J:/src,J:/Просто так), UNC (//debian/share/src) и абсолютные пути Linux/macOS (/mnt/share/src). Используйте/; в JSON обратный слеш требует экранирования, например"Read(J:\\src)"в виде JSON должен содержать два обратных слеша. На Linux UNC не подключает Samba автоматически: сначала смонтируйте ресурс средствами ОС и разрешите его локальный путь.Readс относительным шаблоном сохраняет старое значение внутри проекта.Writeвallowиспользуется только с абсолютной внешней папкой.Широкие относительные
Edit(**),*(**)иdefaultMode: "allow"не дают внешних прав и не повышают внешнийReadдоWrite.Можно обращаться через
src/main.py, еслиrootDir/src— ссылка на разрешённую папку, либо напрямую черезJ:/src/main.pyили//debian/share/src/main.py. Абсолютные пути внутри самогоrootDirпо-прежнему не принимаются: используйте относительные.Проверяется конечная цель ссылок. Выход в неразрешённую папку, соседний
src-other, неполный UNC,J:src, device-пути и Windows alternate data streams не разрешаются. Листинг и поиск пропускают запрещённые папки и не зацикливаются на ссылках.denyпроверяется по пути ссылки, конечной цели и пути относительно подключённой папки. Запреты вроде*(**/.env)и*(**/secrets/**)действуют также снаружи; ссылка с невинным именем не открывает запрещённую цель. Запрет папки действует и на её содержимое.Write(...)вdenyблокирует все файловые операции; для запрета только удаления используйтеDelete(...).При вложенных разрешениях наиболее конкретная папка определяет уровень:
Write(J:/src)плюсRead(J:/src/vendor)делаетvendorдоступной только для чтения. На одной и той же папкеWriteповышаетRead.readOnly: trueблокирует все инструменты изменения даже приWrite. СамrootDirи корни подключённых папок нельзя удалить или переместить. Изменение файла через символьную ссылку сохраняет ссылку; удаление обычной символьной ссылки удаляет ссылку, а не её цель.Доступ зависит и от Windows/SMB: учётная запись сервера должна видеть ресурс. UNC обычно надёжнее буквы диска, привязанной к пользовательскому сеансу. При старте реальный путь разрешения фиксируется; подключите ресурс заранее. Если диск переподключён на другой ресурс или изменена цель ссылки-разрешения, перезапустите сервер и перепроверьте настройки.
Read/Writeне выдаютRun. Внешнийcwdкоманды требуетWriteи отдельного разрешенияRun. Однако команда, запущенная даже внутри проекта, не ограничена файловой песочницей и может обращаться к другим путям.Эти проверки не заменяют изоляцию ОС: локальный процесс, одновременно меняющий ссылки, и разрешённые на стороне Samba переходы за пределы share требуют отдельных ограничений ОС/SMB.
После изменения кода или правил перезапустите сервер. config.example.json
по умолчанию не открывает никаких внешних папок; реальные пути добавляет владелец
в свой config.json.
Проверка реализации без чтения рабочего конфига и секретов:
python -m unittest discover -s tests -vТесты используют временные папки; UNC и сопоставление сетевого диска дополнительно проверяются моделированием, без подключения к реальному Samba-ресурсу.
Правила для команд
Команды — всегда белый список. Run(...) принимает шаблон команды, где *
означает любой текст; всё остальное сравнивается буквально, пробелы
сжимаются, регистр игнорируется. Если ни одного правила Run нет,
run_command отказывает во всём.
{
"permissions": {
"allow": [
"Run(npm run dev)",
"Run(npm run build)",
"Run(npm install)",
"Run(git status)",
"Run(git diff*)",
"Run(python *)",
"Run(pytest*)"
],
"deny": ["Run(*rm -rf*)"]
}
}Цепочка разбивается по
&&,||,|,;и переводам строк, и каждый сегмент должен сам совпасть с правилом изallow. Дляnpm run build && git statusнужны оба правила;npm run build && rm -rf /упадёт на втором сегменте.Разбиение учитывает кавычки, поэтому
git commit -m "fix | bug"— один сегмент.denyи здесь сильнее, аdefaultMode: "allow"на команды не распространяется.
Насколько это обеспечивает безопасность. Не сильно, и это осознанный компромисс.
Белый список спасает от случайностей и опечаток, а не от целенаправленной атаки: одного
разрешённого python * или npm run * достаточно, чтобы сделать всё, что может
обычная программа, включая выход за rootDir — песочница путей ограничивает
только файловые инструменты, но никогда не дочерний процесс. Держите список
коротким и конкретным и относитесь к запуску команд как к «я доверяю этому
клиенту свою учётную запись», а не как к песочнице.
Пример белого списка: читать только src и Markdown, писать только в
src/generated:
{
"permissions": {
"defaultMode": "deny",
"allow": ["List(src/**)", "Read(src/**)", "Read(*.md)", "Create(src/generated/**)", "Edit(src/generated/**)"]
}
}12. Лимиты
Зашиты в server.py (константы в начале файла), меняются правкой кода:
Лимит | Значение |
Размер одного ответа | 100 000 символов, дальше обрезка |
Чтение/запись содержимого файла | 1 МБ |
Записей в листинге | 1000 |
Таймаут синхронной команды | 60 с по умолчанию, максимум — |
Ожидание фоновой команды |
|
Одновременно фоновых процессов | 8 |
Вывод команды в одном ответе | 20 000 символов |
Завершённый процесс в реестре | 10 минут |
| последние 300 строк |
| 20 000 символов |
13. Безопасность
Любой, у кого есть публичный URL и токен, может читать, менять и удалять внутри
rootDirи явно подключённых внешних папок — в пределах разрешённых операций и правилdeny.run_command— самая широкая дыра: дочерний процесс не связан песочницей путей, поэтому разрешённыеpython *,node *илиnpm run *могут добраться до всего, до чего дотягивается ваша учётная запись. Держите списокRunкоротким.Останавливайте фоновые процессы, когда закончили (
stop_process(stop_all=true)); остановка сервера поCtrl+Cубивает их тоже. Жёсткое убийство — нет, но при следующем старте живые процессы подхватываются обратно.Выключайте туннель, когда он не нужен.
Токен меняется так: очистить
MCP_TOKENв.envи перезапустить сервер.rootDirдержите настолько узким, насколько позволяет задача: родительская папка втягивает в песочницу и сам этот проект вместе с его.env.
Если нужно строже: включите подтверждение вызовов на стороне клиента, сузьте
rootDir, поставьте "readOnly": true или уберите все правила Run.
14. Диагностика
Симптом | Причина |
| Нет |
| Файла из |
| Порт занят другим Browser MCP ( |
| Во вкладке не нажат Connect в расширении Browser MCP |
| Модель обратилась к активному файлу настроек — он закрыт всегда |
401 от клиента | Токен не совпадает или заголовок называется не |
421 | Старый |
406 Not Acceptable | Клиент не отправил заголовок |
Cloudflare 1033 | Туннель потерял соединение; перезапустите с |
Клиент не видит инструментов | В URL нет суффикса |
Новый инструмент не появился | Клиент закэшировал старый список; переподключите коннектор |
Ответы подвешиваются до таймаута | Прокси буферизует SSE: |
| Путь совпал с правилом |
| Ни одно правило |
| Та же команда ещё жива: посмотрите её, остановите или передайте |
| Долгоживущая команда запущена без |
| Переводы строк разделяют команды; склейте шаги через |
| Для проекта используйте относительный путь |
| Внешняя цель не разрешена абсолютным |
| Для изменения внешней папки нужно явное |
15. FAQ
А что если я хочу несколько rootDir?
Один процесс — один основной корень. Для конкретных внешних папок добавьте
абсолютные Read/Write из раздела 11. Другие варианты:
Указать общую родительскую папку и сузить доступ правами, например
List(project-a/**),Read(project-a/**),Edit(project-a/**)и то же дляproject-b. Просто и работает, но всё лежит в одной песочнице.Запустить второй экземпляр сервера со своим конфигом и портом: конфиг задаётся ключом
--config(файл ищется рядом сserver.py) или переменнойCONFIG_FILE, а порт — в самом конфиге.python server.py --config config-b.json CONFIG_FILE=/path/to/config-b.json python server.py # macOS / Linux set CONFIG_FILE=C:\path\to\config-b.json && python server.py # WindowsМост к браузеру может работать только в одном экземпляре (порт
9009один): в остальных поставьте"browser": { "enabled": false }.Каждому экземпляру нужен свой публичный адрес (второй туннель или второй
locationв Nginx) и своё подключение в клиенте. Токен берётся из.envрядом сserver.py, так что для разных токенов нужны разные копии проекта.
Обязателен ли cloudflared?
Нет. Нужен любой способ отдать порт наружу по HTTPS: свой Nginx/Caddy/Traefik, именованный туннель Cloudflare, любой другой туннель. Сервер о нём ничего не знает.
Можно ли обойтись без публикации наружу?
Notion и claude.ai работают через интернет, им нужен публичный HTTPS-адрес.
Локальные клиенты (Cursor и другие, запущенные на этой же машине) могут
подключаться прямо к http://127.0.0.1:8000/mcp — тогда поставьте
"host": "127.0.0.1".
Может ли модель выйти за пределы rootDir?
По умолчанию файловыми инструментами — нет. Владелец может явно разрешить
конкретные внешние папки абсолютными Read/Write; другие внешние пути
и ссылки остаются закрыты. Через run_command — да: дочерний процесс
песочницей не ограничен. Если это неприемлемо, не давайте правил Run или
включите readOnly.
Как вообще запретить любые изменения?
"readOnly": true — остаются только чтение, поиск и листинг. Промежуточный
вариант: оставить Edit/Create на рабочую папку и запретить остальное через
deny.
Нужен ли Rules.md?
Нет, сервер работает и без него. Но с ним не приходится в каждом новом диалоге объяснять, что это за проект и как в нём принято работать. См. раздел 10.
Работает ли это на macOS и Linux?
Код есть (/bin/sh, start_new_session, убийство группы процессов), но проверен
он только на Windows. Считайте первый запуск на macOS/Linux тестовым.
Модель удалила нужный файл — как откатить?
Никак средствами сервера: корзины нет, удаление безвозвратное. Держите проект под
git, а в logs/audit.log можно посмотреть, что именно произошло.
Рекомендуется настроить запуск бекапа проекта перед каждой новой задачей.
Почему клиент спрашивает подтверждение на каждый вызов?
Это поведение клиента, сервер на него не влияет. В Notion подтверждения настраиваются в свойствах подключения; права сервера работают независимо от того, что вы нажали.
Токен утёк. Что делать?
Очистить значение MCP_TOKEN в .env, перезапустить сервер (он сгенерирует
новый токен), вписать новый токен в клиента. Старый перестаёт работать сразу.
Почему logs/ внутри rootDir, а не рядом с сервером?
Чтобы модель могла сама прочитать вывод команды через read_file. Побочный
эффект: добавьте logs/ в .gitignore.
This server cannot be deployed
Maintenance
Related MCP Connectors
Safe folder access for ChatGPT and Claude: read, write and search files, risky tools opt-in.
Read and search folders on your own computer with explicit consent. Files are never uploaded.
An agent-first office suite Claude & ChatGPT read and write over one MCP URL.
Hosted Notion MCP server for Claude, ChatGPT and Cursor, with each action switched per account.
Related MCP Servers
- FlicenseNot gradedqualityBmaintenanceEnables secure remote access to your computer's filesystem and terminal through MCP, allowing AI assistants to manage files, run commands, and automate tasks from anywhere via a hosted relay.200-
- AlicenseAqualityBmaintenanceEnables ChatGPT and Codex to safely work with explicitly authorized local project folders through MCP, providing constrained file reading, searching, patch editing, Git inspection, and whitelisted tasks without exposing arbitrary shell, deletion, or deployment capabilities.17MIT
- AlicenseAqualityBmaintenanceEnables MCP-compatible AI clients to securely access explicitly authorized local project files and run approved development commands with bounded execution and audit logging.1MIT
- AlicenseNot gradedqualityBmaintenanceEnables a ChatGPT MCP connection to read, create, and modify text files in explicitly shared folders across multiple self-hosted computers, and to run PowerShell or sh terminal commands under separate per-device authorization.MIT