RecrutAuto MCP server
The Model Context Protocol (MCP) is an open standard that lets AI assistants like Claude securely access your tools and data. Recrut'Auto exposes an MCP server that gives your AI assistant access to your campaigns, candidates, messages, and templates.
In practice: you talk to Claude in natural language, and it performs the actions in Recrut'Auto for you.
Why use MCP?
- Speed — "List the candidates who replied this week on the Python Dev campaign" instead of filtering in the UI.
- Analysis — Claude can cross-reference multiple campaigns, identify patterns, suggest priorities.
- Drafting — generate personalized follow-up messages from the candidate profile.
- Quick creation — create a campaign by describing your need in one sentence.
Which token should I use?
The MCP server authenticates with a Personal Access Token (ra_…) generated from Access tokens. Claude then acts on your behalf: it sees exactly the same campaigns, candidates, and messages as you, with your permissions.
Organization API keys (ra_live_…, created under Organization › Developers) are meant for server-to-server integrations (CI/CD, ATS sync, SCIM) via the REST API. They are not accepted by the MCP server, which requires acting as an identified member. For Claude, always use a personal token.
Endpoint
| SSE endpoint (current environment) | https://mcp.recrutauto.fr/sse |
All requests require the Authorization: Bearer ra_<token> header. A request without a valid token receives a 401.
Prerequisites
- A Personal Access Token in the
ra_…format — see Access tokens. - Node.js ≥ 20 — required by the
mcp-remotebridge that graphical apps (Claude Desktop) use. - One of the following clients: Claude Desktop, Claude Code (CLI), Cursor, or VS Code (Claude extension).
Configuration per client
Claude Desktop (Mac / Windows)
This is the simplest way to use RecrutAuto with Claude in a graphical application.
Claude Desktop's Settings › Connectors › Add custom connector button only accepts a URL (or an OAuth connector): it doesn't let you provide a static Authorization header. For a Bearer-token-protected server like RecrutAuto, you therefore go through the config file and the mcp-remote bridge (which requires Node.js ≥ 20).
- Open Settings › Developer › Edit Config.
- Add the server to
claude_desktop_config.json:
{
"mcpServers": {
"recrutauto": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://mcp.recrutauto.fr/sse",
"--header",
"Authorization:${RECRUTAUTO_MCP_TOKEN}"
],
"env": {
"RECRUTAUTO_MCP_TOKEN": "Bearer ra_YOUR_TOKEN"
}
}
}
}
env, not in argsPut "Bearer ra_…" in the environment variable and Authorization:${RECRUTAUTO_MCP_TOKEN} in args. This works around a known Claude Desktop / Cursor bug (notably on Windows) where the space in "Bearer ra_…" is mis-escaped when written directly in args.
- Quit Claude Desktop completely (menu → Quit, not just Cmd/Ctrl+W) then relaunch it. The RecrutAuto tools appear in the tool selector.
claude.ai (web app)
claude.ai supports RecrutAuto as a custom connector over OAuth 2.0 — no token to paste: you authenticate with your usual RecrutAuto account.
- In claude.ai: Settings › Connectors › Add custom connector.
- Enter the MCP server URL:
https://mcp.recrutauto.fr/sse. - Confirm: claude.ai redirects you to the RecrutAuto sign-in page (Keycloak). Log in and authorize access. The RecrutAuto tools then appear in claude.ai.
You must already have a RecrutAuto account — sign in at least once on console.recrutauto.fr first. The OAuth authorization acts on your behalf, with exactly your permissions (like a personal token). No organization key is used here.
Claude Code (CLI)
The URL is a positional argument (Claude Code ≥ 2.1), not a --url flag:
claude mcp add recrutauto \
--transport sse \
https://mcp.recrutauto.fr/sse \
--header "Authorization: Bearer ra_YOUR_TOKEN" \
--scope user
The --scope user flag writes the config to ~/.claude.json → available in all your projects. The other scope values are project (committed to ./.claude/settings.json — avoid for a token) and local (default, limited to the current directory).
Verification:
claude mcp list
# → recrutauto: https://mcp.recrutauto.fr/sse (SSE) - ✓ Connected
In a Claude Code session, the tools appear under mcp__recrutauto__* (e.g. mcp__recrutauto__list_campaigns).
Older versions of the docs mentioned --url <URL> — this is incorrect. The CLI returns error: unknown option '--url'. Use the URL as a positional argument.
Cursor / VS Code (Claude extension)
Settings → MCP Servers → Add → type SSE:
| Field | Value |
|---|---|
| Name | recrutauto |
| URL | https://mcp.recrutauto.fr/sse |
| Header | Authorization: Bearer ra_YOUR_TOKEN |
Available tools
The MCP server exposes 18 tools and 5 prompts, grouped by domain.
Search
| Tool | Description |
|---|---|
search_candidates | Search the whole enriched vivier (global sourcing base, like campaign creation). Structured filters: skills (resolved to canonical IDs; require_all_skills for AND), location/geo_urn, seniority_min/max (total career; an explicit threshold is a hard filter), plus intent filters company, past_company, excluded_company, industry, languages, school, contract_types, keywords_title, has_email/has_phone, query (relevance). interpret_only=true = dry-run: returns only interpreted (resolved filters incl. skill_ids/skills_unmatched), total and facets (top skills/locations) — to validate interpretation before the real search. Response: {results, total, facets, interpreted}. |
suggest_locations | Location autocomplete (global geo dictionary) → typed options {geo_urn, name, type: city/region/country}. Use it to disambiguate city/department/region before search_candidates (pass the chosen geo_urn). |
search_companies | Search companies by name. Requires authentication (global catalog). |
Candidates
| Tool | Description |
|---|---|
get_candidate | Full profile of a candidate with experiences, education, skills, and campaign status. |
get_messages | Full history of LinkedIn messages with a candidate. |
get_conversations | Recent conversations (last message per candidate), sorted by date. |
Campaigns
| Tool | Description |
|---|---|
list_campaigns | List campaigns with candidate count and workflow-step breakdown. Optional status filter. |
list_projects | B2B alias of list_campaigns ("Project" is the public B2B name of campaigns). Same filters. |
get_campaign | Full details of a campaign (filters, tags, configuration, offer). |
create_campaign | Create a new campaign (draft status by default — never an automatic n8n execution). |
update_campaign | Modify the settings of an existing campaign (partial merge). |
Pipeline
| Tool | Description |
|---|---|
get_campaign_candidates | Candidates of a campaign with workflow status, score, and notes. Paginated. |
get_pipeline_stats | Statistics: connection rate, reply rate, conversion rate, breakdown by step. |
add_candidate | Add a candidate to a campaign by their LinkedIn URL (uniqueness per subscription). |
update_candidate_notes | Update a candidate's notes and tags within a campaign. |
evaluate_candidates | Run evaluation and scoring (11 filters + score 0-10). preview: bool parameter — if true, computes the projected changes and reverts them without persisting. Useful to preview the impact before applying. |
Templates
| Tool | Description |
|---|---|
list_message_templates | List a campaign's message templates. |
update_message_template | Modify a template's content or key (Jinja2 syntax). |
- Campaigns created via MCP are in draft status: activate them manually from the interface to start the n8n execution.
- A candidate can only be in one campaign per subscription.
- Each write emits a structured audit event (
recrutauto.mcp.audit.*) with the invoked tool and modified fields. - Templates use Jinja2 with the variables:
{{candidate.firstname}},{{candidate.lastname}},{{candidate.title}},{{candidate.company}},{{recruiter.firstname}},{{offer.title}},{{booking_url}},{{politeness}},{{period}}.
Pre-configured prompts
5 ready-to-use MCP prompts — invoke them via / in Claude Desktop or Cursor, or ask for them explicitly in Claude Code.
find_candidates
Search the vivier from a natural-language request, clarifying ambiguities before searching: vague seniority ("experienced" → ask the year threshold, noting only total career seniority is filterable, not per-skill years), ambiguous place (Paris city/department/region → suggest_locations then geo_urn). Chains suggest_locations + search_candidates.
Parameter: request (the natural-language request).
campaign_summary
Full summary of a campaign with stats and key candidates. Chains get_campaign + get_pipeline_stats + get_campaign_candidates.
Parameter: campaign_id
candidate_profile
Analysis of a candidate's full profile and interaction history. Chains get_candidate + get_messages.
Parameter: candidate_id
pipeline_review
Global review of all active campaigns and identification of priority actions. Chains list_campaigns + get_pipeline_stats for each.
No parameters.
draft_message
Drafting of a personalized message for a candidate. Chains get_candidate + get_messages + contextual drafting.
Parameters:
candidate_idmessage_type—reconnect(follow-up),hunt(first approach),meet(appointment proposal),not_interested(polite reply to a rejection).
Conversation examples
You: "List my 3 latest active campaigns and give me their reply rates"
Claude calls list_campaigns(status="en cours") then get_pipeline_stats(campaign_id=X) for each.
You: "Create a Senior Go Dev campaign, 5 to 10 years of experience, in Paris or Remote, with informal tone"
Claude calls:
create_campaign(
name="Dev Go Senior",
tags="Go,Backend,Senior",
experience_min=5,
experience_max=10,
locations="Paris,Remote",
politeness="cool"
)
You: "Simulate the scoring of campaign 42 without changing anything to see the impact"
Claude calls evaluate_candidates(campaign_id=42, preview=True) — returns a before/after diff per candidate without touching the database.
You: "For candidate 42, draft a follow-up message that references their experience at Datadog"
Claude calls get_candidate(42) then get_messages(42), then drafts a personalized message.
Quick validation
After configuration, two tests to confirm everything works:
1. Network connectivity (should return 401 with a clean JSON error)
curl -s -o - -w "\nHTTP %{http_code}\n" https://mcp.recrutauto.fr/sse
# → {"error":"unauthorized","detail":"missing Bearer token"}
# HTTP 401
2. Authentication (SSE stream open, Ctrl+C to stop)
curl -N -H "Authorization: Bearer ra_YOUR_TOKEN" https://mcp.recrutauto.fr/sse
# → event: endpoint
# data: /messages/?session_id=...
If you see event: endpoint, your token is valid and the stream is open. From Claude Code, claude mcp list should show recrutauto … ✓ Connected.
Security
Authentication model
The server exposes the MCP protocol over an SSE (Server-Sent Events) transport. Every incoming request must carry an Authorization: Bearer ra_… header; the token is validated on every call (SHA-256 hash, expiration and active-state check). Any request without a valid token is rejected with an HTTP 401 before reaching the MCP engine. There is no "no-auth" mode: the instance is strictly multi-tenant.
Guarantees
- Scope isolation — your token only accesses your campaigns, candidates, and messages. Each service explicitly filters on your scope: it is impossible to access another tenant's data, even by forging an object's ID.
- Audit trail — each write (campaign create/update, candidate add/update, evaluation, template update) emits a structured event under the
recrutauto.mcp.auditlogger. Thepreview=Truemode onevaluate_candidatesemits a distinct event. - Instant revocation — revoking a token immediately cuts off the corresponding MCP client's access. An already-open
GET /ssestream stays connected but can no longer invoke tools. - Rate-limit — calls are capped at 30 req/s per IP at the ingress level.
- Encryption in transit — TLS on all public endpoints.
- Dry-run available —
evaluate_candidates(preview=True)returns the projection without persisting any change.
Troubleshooting
| Symptom | Likely cause | Remedy |
|---|---|---|
error: unknown option '--url' | Obsolete CLI syntax | The URL is a positional argument: claude mcp add <name> --transport sse <URL> --header "..." |
HTTP 401 invalid or expired token | Token revoked, expired, or mispasted | Regenerate via console.recrutauto.fr → My Account → Access tokens |
HTTP 401 missing Bearer token | Malformed header | Check the case of Bearer and the single space after it |
Timeout or HTTP 000 on curl | DNS or outbound firewall blocked | Check your DNS resolution and any corporate proxy |
HTTP 502 / 503 | Service temporarily unavailable | Retry in a few moments; if it persists, contact support |
claude mcp list doesn't show recrutauto | Wrong scope or config not reloaded | claude mcp list --scope user / --scope project; restart Claude Code |
| Tools respond but everything is empty | Scope with no data | Check that you're using the right token (My Account → Access tokens) |
| Claude doesn't suggest the MCP tools | Permissions not granted | Approve the recrutauto server or restart the session |
| Token leaked in a conversation | Security incident | Revoke immediately (My Account → Tokens → trash) and regenerate |
Diagnostic commands
# Claude Code CLI version
claude --version
# Effective config (lists all scopes)
claude mcp list
# Remove a problematic entry
claude mcp remove recrutauto --scope user
# Test raw connectivity (401 expected without a token)
curl -i https://mcp.recrutauto.fr/sse
# Test with token
curl -N -H "Authorization: Bearer ra_YOUR_TOKEN" https://mcp.recrutauto.fr/sse
External resources
- MCP specification — the open standard.
- Anthropic MCP documentation — official client-side guide.
mcp-remote— stdio ↔ SSE/HTTP bridge for Claude Desktop.