Skip to main content
Glama
GAVTIN

filesystem-mcp-server

by GAVTIN

Resume Matcher — MCP Edition

Die direkten Dateisystem-Tools des Resume-Matching-Agenten wurden durch einen eigenständigen MCP-Server ersetzt, plus ein LangGraph-Agent, der so umgestaltet wurde, dass er über einen echten MCP-Client mit ihm (und einem zweiten MCP-Server) kommuniziert, anstatt über lokale Funktionsaufrufe.

Lernziele → was in diesem Repo ist

Ziel

Wo

Model Context Protocol verstehen

filesystem_mcp_server.py implementiert Tools und Ressourcen; getestet gegen das echte JSON-RPC-2.0-Wire-Protokoll in tests/ (nicht gemockt)

Eigene Tools durch MCP-Server ersetzen

Jede Dateisystemoperation aus Meilenstein 1 ist jetzt ein @mcp.tool(); nichts in matching_agent.py importiert Dateisystemcode direkt

Standardisierte Tool-Schnittstellen implementieren

Einheitlicher {"success": bool, ...}-Envelope für jedes Tool; strukturierte JSON-RPC-ähnliche Fehlercodes (siehe unten)

Produktionsreife Systeme bereitstellen

Umgebungsbasierte Konfiguration, begrenzte Nebenläufigkeit, Behandlung von Teilfehlern, ein getesteter Fix für die Umgebungsweitergabe, 14 bestandene Tests über Unit- und Protokollebenen

Related MCP server: Filesystem MCP Server

Architektur

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")]

Zwei unabhängige MCP-Server, jeweils ein eigener OS-Prozess, ohne Kenntnis voneinander oder von LangGraph. Der Agent entdeckt ihre Tools beim Start (client.get_tools()) und ruft sie beim Namen auf – das ist der ganze Sinn des Refactorings: filesystem_mcp_server.py könnte morgen ein neues Tool bekommen und matching_agent.py bräuchte keine Codeänderung.

Zustandsmaschine (Agent ↔ MCP-Interaktion)

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

Dass check_new_resumes zuerst watch_directory aufruft – bevor irgendetwas anderes angefasst wird – ist beabsichtigt: Ein Lauf ohne Neues führt direkt zu [*], ohne einen LLM-Aufruf zu verbrauchen, und der --watch-Modus (siehe unten) verarbeitet nur das, was sich tatsächlich geändert hat, statt jedes Mal das gesamte Verzeichnis.

Lokal ausführen

Erstellen Sie vom Repo-Root aus die virtuelle Umgebung und installieren Sie die Abhängigkeiten.

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

Wenn Sie den Posteingang von Grund auf neu scannen möchten

Der Watcher führt eine kleine Statusdatei, sodass er nur neu hinzugefügte Lebensläufe bewertet. Wenn Sie den aktuellen Ordner erneut verarbeiten möchten, löschen Sie zuerst den Watcher-Status:

python matching_agent.py --reset-watch

Häufige Verwendungsmuster

# 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

Verwenden Sie beim Ausführen des Agenten das Python der Projekt-Venv, nicht das System-Python. In diesem Repo lautet der funktionierende Befehl typischerweise ./.venv/Scripts/python.exe matching_agent.py unter Windows oder source .venv/bin/activate && python matching_agent.py unter Unix-ähnlichen Shells.

Führen Sie einen der Server eigenständig aus, um direkt daran herumzutesten (praktisch mit dem MCP Inspector):

python filesystem_mcp_server.py
python notifications_mcp_server.py

Die Konfiguration erfolgt über Umgebungsvariablen – siehe ServerConfig.from_env() in filesystem_mcp_server.py:

Variable

Standard

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

Testen

pytest tests/ -v

14 Tests, zwei Ebenen:

  • Unit (test_filesystem_mcp_server.py, größtenteils): Ruft Tool-Funktionen direkt gegen eine tmp_path-Fixture auf – schnell, ohne Subprozess. Abgedeckt werden Erfolgspfade, die Fehlercodes RESUME_NOT_FOUND / INVALID_PARAMS und die Teilfehlerberichterstattung von batch_process.

  • Protokoll (test_server_speaks_mcp_protocol_over_stdio): Startet den echten Server als Subprozess und steuert ihn mit dem offiziellen mcp-Client-SDK – tools/list, tools/call, resources/read – über echtes JSON-RPC 2.0, beweist also die Protokollebene, nicht nur das darunterliegende Python.

  • Agent (test_matching_agent.py): Der LLM-Aufruf wird durch einen deterministischen Fake (FakeStructuredModel) ersetzt, sodass diese keinen API-Schlüssel benötigen – sie prüfen die Graph-Verdrahtung, die Tool-Erkennung über mehrere Server, den Kurzschluss-Pfad bei keinen neuen Dateien und dass ein zweiter Durchlauf im --watch-Stil nur die neu eingetroffene Datei erneut verarbeitet, nicht das gesamte Verzeichnis.

Designentscheidungen

MCP-SDK auf mcp>=1.28,<2.0 festgelegt. Die v2-Linie des Python-SDKs wurde zusammen mit der MCP-Spezifikationsrevision vom 2026-07-28 veröffentlicht und benennt FastMCP in MCPServer um (jetzt unter mcp.server.mcpserver). v1.x ist das, wofür das aktuelle LangChain/LangGraph-MCP-Ökosystem gebaut und dokumentiert ist, daher pinnt dieses Projekt bewusst darauf – nicht zufällig. Es lohnt sich, dies zu überdenken, sobald langchain-mcp-adapters und die breitere Tutorial-Basis auf v2 aufholen.

stdio statt HTTP. Keine Netzwerkoberfläche, die abgesichert werden muss, keine Authentifizierung einzurichten, und es ist das, was MultiServerMCPClient für einen lokalen „Command"-Server erwartet. Der Kompromiss, der beim Bau bestätigt wurde: Jeder Tool-Aufruf öffnet eine neue Subprozess-Sitzung, anstatt eine wiederzuverwenden – in Ordnung für einen Demo-/CLI-Agenten, und der ehrliche Grund, warum eine latenzempfindliche Produktionsversion stattdessen auf einen langlebigen streamable-http-Server umsteigen würde.

Fehler sind strukturiertes JSON, kein Prosa. Jeder Fehler wirft ToolError mit einem JSON-Payload, das einen code im JSON-RPC-„Serverfehler"-Bereich (-32000..-32099) sowie ein maschinenlesbares error-Label trägt (RESUME_NOT_FOUND, DIRECTORY_NOT_FOUND, UNSUPPORTED_FILE_TYPE, EXTRACTION_FAILED, INVALID_PARAMS). Ende-zu-Ende gegen eine Live-Client-Sitzung bestätigt: Es erscheint als CallToolResult(isError=True, ...), und _call_tool() von matching_agent.py wirft es als MCPToolCallError mit intaktem Code erneut, anstatt dass ein Aufrufer eine Nachricht per String-Vergleich abgleichen muss.

watch_directory pollt; es pusht nicht. MCP-Tools sind Request/Response, daher ist dies ein Poll (eine JSON-Statusdatei mit Dateiname→mtime, die bei jedem Aufruf verglichen wird) und kein inotify/watchdog-Listener. Der --watch-Modus von matching_agent.py macht daraus etwas, das sich live anfühlt – ein Hintergrund-Listener, der über MCP-Ressourcen-Abonnements pusht, wäre der natürliche nächste Schritt und wird vom Protokoll unterstützt, ist hier aber außerhalb des Rahmens.

batch_process nimmt eine explizite Dateiliste, nicht nur ein Verzeichnis. Dadurch kann check_new_resumes → batch_extract nur das erneut verarbeiten, was watch_directory gerade gemeldet hat, statt jedes Mal den gesamten Ordner – die Nebenläufigkeit (asyncio.Semaphore(MAX_BATCH_CONCURRENCY)) macht „effizient" aus der Spezifikation tatsächlich wahr, wenn die Liste lang ist.

Die Umgebungsweitergabe ist explizit und kein Standard, den man überspringen kann. Ein echter Stolperstein beim Bau: Der stdio-Client von mcp erbt nicht die Umgebung des Elternprozesses – er startet Kind-Server mit einer minimalen Standardumgebung (nur PATH/HOME/TERM), direkt bestätigt gegen mcp.client.stdio.get_default_environment(). Ohne explizites env=dict(os.environ) in der Serverkonfiguration von matching_agent.py erreichen RESUME_DIRECTORY und Co. stillschweigend nie filesystem_mcp_server.py – der Agent läuft, findet die Tools problemlos und arbeitet einfach leise im falschen Verzeichnis. Wissenswert, bevor es Sie eine Debugging-Sitzung kostet.

Repo-Struktur

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