Skip to main content
Glama
GAVTIN

filesystem-mcp-server

by GAVTIN

Resume Matcher — MCP Edition

Агент сопоставления резюме, использующий прямые инструменты файловой системы, заменён на автономный MCP-сервер, плюс агент LangGraph, рефакторизованный для общения с ним (и со вторым MCP-сервером) через реальный MCP-клиент вместо локальных вызовов функций.

Учебные цели → что в этом репозитории

Цель

Где

Понять Model Context Protocol

filesystem_mcp_server.py реализует инструменты и ресурсы; протестирован против реального протокола JSON-RPC 2.0 в tests/ (не мокается)

Заменить пользовательские инструменты MCP-серверами

Каждая операция файловой системы из Milestone 1 теперь является @mcp.tool(); ничто в matching_agent.py не импортирует код файловой системы напрямую

Реализовать стандартизированные интерфейсы инструментов

Единая обёртка {"success": bool, ...} для каждого инструмента; структурированные коды ошибок в стиле JSON-RPC (см. ниже)

Развернуть production-ready системы

Конфигурация на основе env, ограниченная конкурентность, обработка частичных сбоев, протестированное исправление передачи env, 14 проходящих тестов на уровнях unit и протокола

Related MCP server: Filesystem MCP Server

Архитектура

flowchart LR
    subgraph "Agent process (matching_agent.py)"
        A["LangGraph StateGraph"] --> B["MultiServerMCPClient"]
        A --> L["Claude (LLM)\nstructured scoring"]
    end
    B <-->|"JSON-RPC 2.0 / stdio"| C["filesystem_mcp_server.py"]
    B <-->|"JSON-RPC 2.0 / stdio"| D["notifications_mcp_server.py"]
    C --> E[("sample_data/resumes/\nresults/")]
    D --> F[("results/notifications.log")]

Два независимых MCP-сервера, каждый в отдельном процессе ОС, каждый не знает о другом или о LangGraph. Агент обнаруживает их инструменты при запуске (client.get_tools()) и вызывает их по имени — в этом и заключается суть рефакторинга: filesystem_mcp_server.py может завтра получить новый инструмент, и matching_agent.py не потребует изменения кода.

Конечный автомат (взаимодействие агента и MCP)

stateDiagram-v2
    [*] --> check_new_resumes
    check_new_resumes --> batch_extract: new files found
    check_new_resumes --> [*]: nothing new — short-circuit
    batch_extract --> match: text extracted
    match --> rank_and_save: LLM structured scoring
    rank_and_save --> notify: results persisted
    notify --> [*]: done

    note right of check_new_resumes
        filesystem server
        tool: watch_directory
    end note
    note right of batch_extract
        filesystem server
        tool: batch_process
    end note
    note right of rank_and_save
        filesystem server
        tool: save_match_result (per match)
    end note
    note right of notify
        notifications server
        tool: send_match_notification
        (only matches scoring >= 70)
    end note

То, что check_new_resumes вызывает watch_directory первым — до любых других действий — намеренно: запуск без новых данных сразу переходит к [*], не тратя вызов LLM, а режим --watch (см. ниже) повторно обрабатывает только то, что действительно изменилось, а не весь каталог каждый раз.

Запуск локально

Из корня репозитория создайте виртуальное окружение и установите зависимости.

Bash / Git Bash / Linux / macOS

cd [Path To Files]
python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r requirements.txt
export ANTHROPIC_API_KEY="<your-anthropic-api-key>"
python matching_agent.py

Windows PowerShell

cd [Path To Files]
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txt
$env:ANTHROPIC_API_KEY = "<your-anthropic-api-key>"
python .\matching_agent.py

Если нужно заново просканировать входящие с нуля

Наблюдатель хранит небольшой файл состояния, поэтому он оценивает только недавно добавленные резюме. Если нужно обработать текущую папку снова, сначала очистите состояние наблюдателя:

python matching_agent.py --reset-watch

Типичные сценарии использования

# one pass over the bundled sample data
python matching_agent.py

# run against your own job description and resume folder
python matching_agent.py --job-description path/to/jd.txt --resume-dir path/to/resumes

# keep polling for newly added resumes every 15s (Ctrl+C to stop)
python matching_agent.py --watch --interval 15

Используйте Python из виртуального окружения проекта, а не системный Python, при запуске агента. В этом репозитории рабочая команда обычно ./.venv/Scripts/python.exe matching_agent.py на Windows или source .venv/bin/activate && python matching_agent.py на Unix-подобных оболочках.

Запустите любой сервер отдельно, чтобы проверить его напрямую (удобно с MCP Inspector):

python filesystem_mcp_server.py
python notifications_mcp_server.py

Конфигурация управляется через env — см. ServerConfig.from_env() в filesystem_mcp_server.py:

Переменная

По умолчанию

RESUME_DIRECTORY

./sample_data/resumes

RESULTS_DIRECTORY

./results

ALLOWED_EXTENSIONS

.txt,.pdf,.docx

MAX_BATCH_CONCURRENCY

5

NOTIFY_SCORE_THRESHOLD

70 (matching_agent.py)

MATCHING_AGENT_MODEL

anthropic:claude-sonnet-5

Тестирование

pytest tests/ -v

14 тестов, два уровня:

  • Unit (test_filesystem_mcp_server.py, большая часть): вызов функций инструментов напрямую с фикстурой tmp_path — быстро, без подпроцессов. Покрывает успешные пути, коды ошибок RESUME_NOT_FOUND / INVALID_PARAMS и отчёт о частичных сбоях batch_process.

  • Protocol (test_server_speaks_mcp_protocol_over_stdio): запускает реальный сервер как подпроцесс и управляет им через официальный mcp клиентский SDK — tools/list, tools/call, resources/read — по реальному JSON-RPC 2.0, так что проверяется именно протокольный слой, а не только Python под ним.

  • Agent (test_matching_agent.py): вызов LLM заменён на детерминированный фейк (FakeStructuredModel), поэтому этим тестам не нужен API-ключ — они проверяют связку графа, обнаружение инструментов на нескольких серверах, путь короткого замыкания при отсутствии новых файлов и то, что второй проход в стиле --watch обрабатывает только вновь поступивший файл, а не весь каталог.

Проектные решения

MCP SDK закреплён на mcp>=1.28,<2.0. Линейка v2 Python SDK вышла вместе с ревизией спецификации MCP от 2026-07-28 и переименовывает FastMCP в MCPServer (теперь в mcp.server.mcpserver). v1.x — это то, на чём построена и документирована текущая экосистема LangChain/LangGraph MCP, поэтому проект намеренно закрепляется на ней, а не случайно — стоит пересмотреть, когда langchain-mcp-adapters и более широкая база учебных материалов догонят v2.

stdio вместо HTTP. Нет сетевой поверхности для защиты, не нужно настраивать аутентификацию, и это то, что MultiServerMCPClient ожидает для локального "command" сервера. Компромисс, подтверждённый при создании: каждый вызов инструмента открывает новый сеанс подпроцесса, а не переиспользует существующий — нормально для демо/CLI-агента, и это честная причина, по которой чувствительная к задержкам production-версия перешла бы на долгоживущий streamable-http сервер.

Ошибки — это структурированный JSON, а не проза. Каждый сбой вызывает ToolError с JSON-нагрузкой, содержащей code в диапазоне "server error" JSON-RPC (-32000..-32099) плюс машиночитаемую метку error (RESUME_NOT_FOUND, DIRECTORY_NOT_FOUND, UNSUPPORTED_FILE_TYPE, EXTRACTION_FAILED, INVALID_PARAMS). Подтверждено сквозным тестом с живой клиентской сессией: это проявляется как CallToolResult(isError=True, ...), а _call_tool() в matching_agent.py повторно поднимает его как MCPToolCallError с сохранённым кодом, вместо того чтобы вызывающему приходилось сопоставлять строки сообщения.

watch_directory опрашивает, а не отправляет. Инструменты MCP — это запрос/ответ, поэтому это опрос (JSON-файл состояния имя_файла→mtime, сравниваемый при каждом вызове), а не слушатель inotify/watchdog. Режим --watch в matching_agent.py превращает это в нечто, ощущаемое как живое — фоновый слушатель, отправляющий через MCP подписки на ресурсы, был бы естественным следующим шагом и поддерживается протоколом, но выходит за рамки этого проекта.

batch_process принимает явный список файлов, а не только каталог. Именно это позволяет check_new_resumes → batch_extract повторно обрабатывать только то, что только что сообщил watch_directory, а не всю папку каждый раз — конкурентность (asyncio.Semaphore(MAX_BATCH_CONCURRENCY)) делает "эффективность" из спецификации реальной, когда список длинный.

Передача env явная, и это не опция по умолчанию, которую можно пропустить. Реальная ловушка, обнаруженная при создании: stdio-клиент mcp не наследует окружение родительского процесса — он запускает дочерние серверы с минимальным окружением по умолчанию (только PATH/HOME/TERM), что подтверждено напрямую через mcp.client.stdio.get_default_environment(). Без явной передачи env=dict(os.environ) в конфигурации сервера в matching_agent.py, RESUME_DIRECTORY и другие переменные молча никогда не достигают filesystem_mcp_server.py — агент запускается, отлично обнаруживает инструменты и просто тихо работает с неправильным каталогом. Стоит знать, прежде чем это обойдётся вам в сеанс отладки.

Структура репозитория

resume-matcher-mcp/
├── filesystem_mcp_server.py      # Part A
├── notifications_mcp_server.py   # Part B bonus: 2nd MCP server
├── matching_agent.py             # Part B
├── requirements.txt
├── pytest.ini
├── tests/
│   ├── test_filesystem_mcp_server.py
│   └── test_matching_agent.py
├── sample_data/
│   ├── job_description.txt
│   └── resumes/                  # 21 resumes, deliberately strong/partial/weak fit
└── results/                      # match_results.jsonl + notifications.log (gitignored)

Maintenance

ActivityMaintained
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables file system operations (read, write, list, search, watch, batch process) via MCP over JSON-RPC 2.0, used by a resume matching agent.
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables AI agents to interact with a sandboxed filesystem via MCP tools for reading, writing, searching, and monitoring files, including batch processing and resource discovery for resume management.
  • F
    license
    Not graded
    quality
    C
    maintenance
    Provides file system tools for resume matching agents, enabling reading, writing, searching, listing, watching, and batch processing of files via the Model Context Protocol.
  • F
    license
    Not graded
    quality
    C
    maintenance
    Provides MCP tools for reading, listing, writing, searching, watching, and batch-processing files, enabling automated file management and resume matching workflows.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/GAVTIN/Resume-Matcher-MCP-Edition'

If you have feedback or need assistance with the MCP directory API, please join our Discord server