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: mcp-local-files
1. Как это работает
Notion AI / claude.ai / chatgpt
│ HTTPS + Bearer-токен
▼
cloudflared-туннель или свой web сервер с TLS
│ HTTP внутри локальной сети
▼
server.py (слушает host:port, отдаёт /mcp)
│ все пути проверяются: песочница + права
▼
rootDir — единственная папка, к которой есть доступСтек: Python + MCP SDK для Python (FastMCP) + uvicorn, транспорт Streamable HTTP
на пути /mcp, авторизация Bearer-токеном. Сервер ничего не знает о способе
публикации: он просто слушает host:port, а как этот порт оказался в интернете —
дело туннеля или прокси.
2. Структура проекта
Путь | Что это |
| весь сервер: конфиг, песочница путей, права, инструменты, авторизация |
| файл настроек, создайте его из |
| шаблон настроек |
| файл хранит токен |
| три зависимости: |
| этот файл |
| базовые инструкции для ИИ, чтобы ИИ знал минимальный контекст по вашему проекту |
|
|
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. |
В .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)
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. Инструменты
Все пути в аргументах — относительные, от rootDir. Абсолютные пути
отклоняются, как и симлинки, ведущие за пределы корня.
Путеводитель
Инструмент | Что делает |
| Возвращает |
Тот же текст автоматически дописывается к первому результату инструмента в диалоге, так что обычно вызывать его не нужно.
Файлы
Инструмент | Что делает |
| Листинг папки; |
| Файл с номерами строк, постранично для больших файлов |
| Поиск по проекту, отдаёт |
| Размер, число строк, время изменения, текст или бинарник |
| Точная замена, возвращает дифф |
| Несколько замен в одном файле, всё или ничего |
| Новый файл или папка |
| Переименование или перемещение |
| Безвозвратное удаление файла или папки |
Шумные папки (
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удаляются. Номера продолжают расти, поэтому имена логов не конфликтуют. Подхваченный процесс можно смотреть и останавливать как обычно — теряется только точный код выхода, потому что сервер больше не владеет его хэндлом.
Журнал действий
При "audit": true каждая команда, перемещение и multi_edit дописываются в
logs/audit.log:
2026-09-15 03:40:12 ok run_command: #1 npm run dev (cwd .)
2026-09-15 03:41:02 ok move: src/old.ts -> src/new.tsЭто ответ на вопрос «что модель на самом деле сделала» — полезно после долгой
сессии или когда что-то сломалось, а диффа недостаточно. Добавьте logs/ в
.gitignore.
Журнал — скользящий хвост, а не архив: он обрезается до последних 300 строк
(AUDIT_KEEP_LINES в server.py) при старте и каждые 100 записей, поэтому расти
бесконечно не может. Логи команд чистятся отдельно: при старте удаляется каждый
logs/cmd-NNN.log, чей процесс не жив и не подхвачен.
9. 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или*для всех путевых глаголов. Соответствие инструментам:ListиReadвместе определяют, что показываетlist_files;Readпокрывает ещёsearch_textиfile_info;Editпокрываетmulti_edit;Create—createи приёмникmove;Delete—deleteи источникmove.Runстоит особняком: его аргумент — шаблон команды, а не путь, поэтому*(**)его никогда не выдаёт. См. «Правила для команд» ниже.defaultMode: "allow"— разрешено всё, что не запрещено (чёрный список).defaultMode: "deny"— работают только пути изallow(белый список).denyвсегда сильнееallow.Шаблоны задаются относительно
rootDir, разделитель —/, поддерживаются*(один сегмент),**(любая глубина) и?(один символ).Шаблоны привязаны к корню, поэтому
.envсовпадает только с файлом в корне. Чтобы накрыть все подпапки, нужен префикс**/—**/.env.secrets/**скрывает и саму папкуsecrets.Запрещённые элементы не показываются в
list_files, вместо них выводится число скрытых записей.Если блока
permissionsнет, действуют встроенные значения: разрешено всё, кроме**/.env,**/.env.*,**/secrets/**,**/*.pem,**/*.key, плюс запрет записи и удаления внутри**/.git/**.Правила читаются при старте — после правки перезапустите сервер.
*(**/config.json)доступ к файлу закрыт для модели, чтобы не переписала собственные права.
Правила для команд
Команды — всегда белый список. 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/**)"]
}
}11. Лимиты
Зашиты в server.py (константы в начале файла), меняются правкой кода:
Лимит | Значение |
Размер одного ответа | 100 000 символов, дальше обрезка |
Чтение/запись содержимого файла | 1 МБ |
Записей в листинге | 1000 |
Таймаут синхронной команды | 60 с по умолчанию, максимум — |
Ожидание фоновой команды |
|
Одновременно фоновых процессов | 8 |
Вывод команды в одном ответе | 20 000 символов |
Завершённый процесс в реестре | 10 минут |
| последние 300 строк |
| 20 000 символов |
12. Безопасность
Любой, у кого есть публичный 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.
13. Диагностика
Симптом | Причина |
| Нет |
401 от клиента | Токен не совпадает или заголовок называется не |
421 | Старый |
406 Not Acceptable | Клиент не отправил заголовок |
Cloudflare 1033 | Туннель потерял соединение; перезапустите с |
Клиент не видит инструментов | В URL нет суффикса |
Новый инструмент не появился | Клиент закэшировал старый список; переподключите коннектор |
Ответы подвешиваются до таймаута | Прокси буферизует SSE: |
| Путь совпал с правилом |
| Ни одно правило |
| Та же команда ещё жива: посмотрите её, остановите или передайте |
| Долгоживущая команда запущена без |
| Переводы строк разделяют команды; склейте шаги через |
| Так и задумано: пути относительны |
14. FAQ
А что если я хочу несколько rootDir?
Один процесс — один корень, это основа песочницы. Варианты:
Указать общую родительскую папку и сузить доступ правами, например
List(project-a/**),Read(project-a/**),Edit(project-a/**)и то же дляproject-b. Просто и работает, но всё лежит в одной песочнице.Запустить второй экземпляр сервера со своим конфигом и портом: путь к конфигу берётся из переменной
CONFIG_FILE, а порт — из самого конфига.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Каждому экземпляру нужен свой публичный адрес (второй туннель или второй
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?
Файловыми инструментами — нет: абсолютные пути отклоняются, .. разворачивается,
симлинки наружу отбрасываются. Через run_command — да: дочерний процесс
песочницей не ограничен. Если это неприемлемо, не давайте правил Run или
включите readOnly.
Как вообще запретить любые изменения?
"readOnly": true — остаются только чтение, поиск и листинг. Промежуточный
вариант: оставить Edit/Create на рабочую папку и запретить остальное через
deny.
Нужен ли Rules.md?
Нет, сервер работает и без него. Но с ним не приходится в каждом новом диалоге объяснять, что это за проект и как в нём принято работать. См. раздел 9.
Работает ли это на 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
An agent-first office suite Claude & ChatGPT read and write over one MCP URL.
MCP server connecting AI agents to 100+ apps (Gmail, Slack, Notion, GitHub) via one-click OAuth.
Publish and share access-controlled Markdown documents from any MCP-enabled AI tool.
Egnyte's remote MCP server for secure AI access, search, upload and file management in your account.
Related MCP Servers
- AlicenseAqualityBmaintenanceAllows Claude desktop app to execute terminal commands and edit files on your computer through MCP, with features including command execution, process management, and diff-based file editing.26156,453 npm9,596MIT
- AlicenseNot gradedqualityFmaintenanceEnables ChatGPT/Codex to read, search, and edit files in a single allowed folder on Windows through OpenAI Secure MCP Tunnel.ISC
- FlicenseNot gradedqualityCmaintenanceEnables 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.37-
- FlicenseNot gradedqualityBmaintenanceEnables Claude Desktop or other MCP clients to execute shell commands, read/write files, and list directories on the local machine. Includes basic safety guardrails to block obviously destructive operations.-