Skip to content

MCP: stateless job-seeker tools + streamable HTTP transport - #4

Open
miao4ai wants to merge 1 commit into
mainfrom
recruiter-mcp-http
Open

MCP: stateless job-seeker tools + streamable HTTP transport#4
miao4ai wants to merge 1 commit into
mainfrom
recruiter-mcp-http

Conversation

@miao4ai

@miao4ai miao4ai commented Sep 7, 2026

Copy link
Copy Markdown
Owner

What

Lets a chat app (charbit's recruiter skill) use Open Recruiter as its job search / recommendation engine over MCP.

New job-seeker tools — stateless: the resume arrives as text, nothing is stored or indexed, so one shared instance serves many users without their data landing in this database.

Tool LLM? Returns
search_jobs(query?, location?, top_k=10) no job cards by keywords / location ("remote" matches remote jobs)
recommend_jobs(resume_text, top_k=5) no job cards best-first by vector similarity, fields.score 0–1; [] without a Voyage key
match_resume_to_job(resume_text, job_id) yes score, strengths, gaps, reasoning

The existing six recruiter tools are unchanged.

Streamable HTTP transportRECRUITER_MCP_TRANSPORT=http (RECRUITER_MCP_HOST/PORT, default 127.0.0.1:8765, endpoint /mcp). stdio stays the default, so Claude Desktop / Cursor wiring is untouched.

Two interop decisions worth knowing

  1. Stateless + JSON responses. charbit's connector POSTs one JSON-RPC request at a time, never sends notifications/initialized, and never opens an SSE stream. stateless_http=True is what lets tools/call follow initialize directly; json_response=True avoids SSE framing.
  2. Card tools return a JSON string, not a list. mcp 2.0 splits a list result into one text block per item; the connector reads the first text block as one array of {id, title, subtitle, price, detail, url, fields} cards (fields values are strings — decoded as map[string]string). Same contract as charbit's mcp-suumo partner service.

Also: Candidate.embed_text() ignores raw_resume_text, so the transient candidate carries the resume in resume_summary — otherwise the embedding is empty and search returns nothing.

Verification

  • New tests: product/tests/harness/test_mcp_jobseeker.py — 6 passed. Full harness: 284 passed.
  • HTTP smoke with charbit's exact request shape: initialize → plain application/json; tools/call search_jobs → one text block holding the card array, isError: false; string "top_k":"3" coerced to int; recommend_jobs without a Voyage key → [].

uv.lock intentionally not touched (per CLAUDE.md).

🤖 Generated with Claude Code

Add search_jobs / recommend_jobs / match_resume_to_job so a chat app (charbit's
recruiter skill) can search and recommend jobs for a user from resume text.
Nothing is stored or indexed per call, so one shared instance serves many users.

RECRUITER_MCP_TRANSPORT=http serves streamable HTTP (stateless, JSON responses)
for a server-side caller; stdio stays the default for Claude Desktop / Cursor.

The card tools return a JSON string: the SDK splits a list result into one text
block per item, and the connector reads the first block as one array.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant