Resume Matcher MCP Server

Resume Matcher MCP Server

Provides sandboxed file system tools (read, write, search, list, watch) over the Model Context Protocol, enabling resume matching and analysis workflows via an agent.

Category
访问服务器

README

Resume Matcher — MCP Server & LangGraph Agent (Milestone 4)

A resume-matching system whose file-system tooling is served over the Model Context Protocol (MCP). The custom file tools from Milestone 1 are now a standalone, JSON-RPC 2.0-compliant MCP server; the Milestone 3 LangGraph conversational agent consumes them through an MCP client facade — same functionality, standardized architecture. A second, optional MCP server (DuckDuckGo, stdio) adds web search as a bonus.

Architecture

The system is split across a protocol boundary: the agent process never touches the filesystem directly at runtime — every read/write crosses JSON-RPC 2.0.

graph LR
    subgraph Host["Agent process (agent_cli.py / app.py)"]
        CLI[agent_cli.py<br/>flags: --mcp-url, --local-fs,<br/>--require-mcp, --web-search]
        AG[MatchingAgent<br/>LangGraph StateGraph]
        ENG[Engine<br/>JobMatcher + LLMClient<br/>+ fs: FileStore + web]
        FS[FileStore protocol<br/>mcp_fs_client.py]
        LOCAL[LocalFileStore<br/>delegates to fs_tools]
        MCPC[McpFileStore<br/>sync bridge over asyncio]
        DDGC[McpWebSearch<br/>stdio client]
        CLI --> AG --> ENG --> FS
        FS -.impl.-> LOCAL
        FS -.impl.-> MCPC
        ENG -.optional.-> DDGC
    end

    subgraph Server["filesystem_mcp_server.py (FastMCP)"]
        EP["/mcp — Streamable HTTP<br/>JSON-RPC 2.0"]
        HEALTH["/health — GET"]
        TOOLS["6 tools: read_file, list_files,<br/>write_file, search_in_file,<br/>watch_directory, batch_process"]
        RES["resources: resume://{filename},<br/>resume://index"]
        SANDBOX[fs_tools sandbox<br/>FS_TOOLS_BASE_DIR]
        EP --> TOOLS --> SANDBOX
        EP --> RES --> SANDBOX
    end

    DDG[duckduckgo-mcp-server<br/>subprocess]

    MCPC -- "HTTP POST /mcp" --> EP
    DDGC -- "stdio JSON-RPC" --> DDG
    LOCAL -- "direct calls (offline/test)" --> SANDBOX2[fs_tools sandbox]

Components

Component File Role
MCP file-system server filesystem_mcp_server.py FastMCP (official SDK), Streamable HTTP at /mcp, GET /health. Wraps the sandboxed M1 fs_tools primitives — it does not reimplement them.
M1 tool layer fs_tools.py Sandboxed file primitives: path-escape rejection, .txt/.pdf/.docx text extraction.
Client facade mcp_fs_client.py FileStore protocol; LocalFileStore (offline/tests), McpFileStore (sync bridge over Streamable HTTP), McpWebSearch (DuckDuckGo MCP over stdio).
Matching agent matching_agent.py LangGraph HITL agent (M3 topology unchanged); all runtime file I/O goes through the injected FileStore — no direct fs_tools import.
Entry points agent_cli.py, app.py CLI (--mcp-url, --local-fs, --require-mcp, --web-search) and Streamlit UI, both with graceful MCP fallback.
RAG + matcher resume_rag.py, job_matcher.py, reranker.py ChromaDB retrieval, ranking, reranking (M2).

The two MCP servers

1. Filesystem server (filesystem_mcp_server.py) — Streamable HTTP

Tools (JSON Schemas auto-generated by FastMCP from type hints, discovered via tools/list):

Tool What it does
read_file Read a file inside the sandbox; extracts text from .txt/.pdf/.docx.
list_files List directory contents with metadata.
write_file Write content; returns bytes_written.
search_in_file Keyword search with char offsets + snippets per match.
watch_directory Stateful poll cursor: first call baselines, later polls with the same watch_id report new / modified / deleted files.
batch_process Concurrent multi-file ops with per-file failure isolation — one bad path never fails the batch.

Resources: resume://index plus one resume://{filename} per file in resumes/ — the resource list tracks the live directory, so adding or removing a resume changes what resources/list returns.

Session lifecycle (standard MCP over JSON-RPC 2.0):

initialize → notifications/initialized → tools/list → tools/call …
                                       → resources/list → resources/read …

2. Web-search server (bonus) — duckduckgo-mcp-server over stdio

Spawned as a per-session subprocess by McpWebSearch; no API key needed. Used by the agent's deep-screen step for market context, wrapped in try/except — if search fails, the analysis completes without it.

Why two transports?

Streamable HTTP for the file server: it's a long-lived, independently addressable service — multiple clients can share it, and it gets a real ops surface (GET /health, curl-able). stdio for the search server: a per-session helper with no reuse requirement, so spawning it as a child process is the simpler fit. Details in docs/architecture.md.

Error model (three tiers)

Tier Example Surface
Domain outcome File not found, path escapes sandbox {"success": false, "error": ...} in a normal result — the agent branches on it as data, never an exception
Programmer error Invalid operation enum ValueError → isError: true — loud, signals a caller bug
Protocol error Malformed JSON-RPC JSON-RPC error object, handled by the MCP SDK

Sync bridge

LangGraph nodes are synchronous; the MCP SDK is async. McpFileStore runs a daemon thread hosting a private asyncio loop, and a single coroutine owns the open/close of the HTTP session (anyio cancel scopes must stay on one task). Sync callers submit via run_coroutine_threadsafe with a 30 s timeout, so a hung server can never deadlock a graph node.

Agent workflow — where MCP is called

The LangGraph pipeline (parse_jd → extract_requirements → search_resumes → rank_candidates → summarize_shortlist → generate_report → human_feedback) loops on a HITL interrupt (refine / compare / interview / screen / explain / chat / done). Two states cross the MCP boundary:

  • deep_analyze (fan-out per shortlisted candidate on screen) — tools/call read_file to fetch the full resume body, plus optional DDG search for market context.
  • write_decision_log (on done) — tools/call write_file to persist the decision log JSON.

Retrieval/ranking use the local ChromaDB index directly: RAG indexing is an offline batch pipeline, and routing thousands of embedding reads through a network protocol adds latency for zero interoperability benefit (see the refactor boundary in docs/architecture.md). Sequence + state-machine diagrams: docs/diagrams/agent_mcp_interaction.md.

Resilience

  • Graceful fallback: the CLI and Streamlit UI probe the server at startup; if unreachable they warn and fall back to LocalFileStore (identical interface, no network).
  • --require-mcp: hard-fails with a start hint when the server is down — for demos that must prove MCP is in the loop.
  • Sandbox: every tool and resource resolves paths against FS_TOOLS_BASE_DIR; escape attempts get a structured error. Server binds to loopback by default.
  • Known gaps (out of scope): no auth/TLS on /mcp, single-process server, watch cursors are in-memory.

Setup

python -m venv --system-site-packages .venv
.venv\Scripts\pip install -r requirements.txt
copy .env.example .env   # add ANTHROPIC_API_KEY for live LLM runs

Run

# Terminal 1 — MCP server
.venv\Scripts\python filesystem_mcp_server.py
# health check: http://127.0.0.1:8765/health

# Terminal 2 — agent through MCP
.venv\Scripts\python agent_cli.py "senior python backend engineer" --require-mcp
# optional bonus: add --web-search (DuckDuckGo MCP, no API key)

# Streamlit UI (connects to MCP automatically; web search is a sidebar toggle)
.venv\Scripts\python -m streamlit run app.py

Configuration precedence is CLI > env > default for base dir (FS_TOOLS_BASE_DIR), host/port (MCP_FS_HOST/MCP_FS_PORT), and the client URL (MCP_FS_URL, default http://127.0.0.1:8765/mcp).

Demo & tests

# Narrated end-to-end demo (server + discovery + all 6 tools + watch + batch + agent).
# Asserts every step's expectation — exits 0 only if all hold.
.venv\Scripts\python scripts\demo_m4.py            # full
.venv\Scripts\python scripts\demo_m4.py --skip-agent  # tools only, no API key needed

# Test suite (fully offline — StubLLM, no API calls). Integration tests start a
# real server subprocess and speak real Streamable HTTP — no mocked transport.
.venv\Scripts\python -m pytest -q

Scenario-by-scenario coverage map (each deliverable → the test or demo step that proves it): docs/test_scenarios.md.

Docs

Earlier milestones (M1 file tools, M2 RAG + job matcher, M3 LangGraph agent) are included as the working baseline this milestone builds on.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选