filesystem-mcp-server
Resume Matcher — MCP Edition
Агент сопоставления резюме, использующий прямые инструменты файловой системы, заменён на автономный MCP-сервер, плюс агент LangGraph, рефакторизованный для общения с ним (и со вторым MCP-сервером) через реальный MCP-клиент вместо локальных вызовов функций.
Учебные цели → что в этом репозитории
Цель | Где |
Понять Model Context Protocol |
|
Заменить пользовательские инструменты MCP-серверами | Каждая операция файловой системы из Milestone 1 теперь является |
Реализовать стандартизированные интерфейсы инструментов | Единая обёртка |
Развернуть 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.pyWindows 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:
Переменная | По умолчанию |
|
|
|
|
|
|
|
|
|
|
|
|
Тестирование
pytest tests/ -v14 тестов, два уровня:
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)This server cannot be installed
Maintenance
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
Generate tailored, ATS-optimized resume PDFs and cover letters from a job description, over MCP.
Hosted MCP tools for FFmpeg-style video and audio processing through FFMPEG API.
Resume builder with native MCP — create and edit resumes from your AI assistant.
Public MCP server for discovering open jobs. Search, filter, and get application links.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables file system operations (read, write, list, search, watch, batch process) via MCP over JSON-RPC 2.0, used by a resume matching agent.
- FlicenseNot gradedqualityCmaintenanceEnables 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.
- FlicenseNot gradedqualityCmaintenanceProvides file system tools for resume matching agents, enabling reading, writing, searching, listing, watching, and batch processing of files via the Model Context Protocol.
- FlicenseNot gradedqualityCmaintenanceProvides MCP tools for reading, listing, writing, searching, watching, and batch-processing files, enabling automated file management and resume matching workflows.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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