CATS MCP Server
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@CATS MCP Serverfind candidates with Python experience in San Francisco"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
CATS MCP Server
A universal MCP adapter for the CATS (CatsOne) API v3.
Comprehensive, atomic coverage of the CATS API exposed to any MCP-compatible client - Claude, ChatGPT, Codex, Mastra, Google ADK, or your own orchestrator.
For the current inventory see docs/TOOLS.md, generated from the registry.
What a client sees
This server exposes all three MCP primitives, not just tools:
Primitive | What it gives you |
Tools | every CATS endpoint, plus batch reads and a status check |
Resources | what this adapter is, which account it is attached to, and the account-specific ids nothing else works without |
Prompts | how to operate the CATS API correctly - not what to do with the results |
Start with the resource cats://server/capabilities. It states what this server
owns, what it deliberately leaves to the caller, and how it is configured - and
it works even when CATS is unreachable.
Related MCP server: Viterbit MCP Server
What this is, and is not
This is an adapter. It owns CATS authentication, endpoint coverage, tool schemas, discovery metadata, response shaping, pagination, rate-limit handling and safety classification.
It does not own recruiting workflows, agent orchestration, memory, outreach, scheduling, candidate ranking, or a frontend. Those belong to the calling orchestrator. See docs/ARCHITECTURE.md.
Install
uv venv
uv pip install -r requirements.txt -r requirements-dev.txt
uv pip install -e .FastMCP 4 is a prerelease, so every dependency is pinned exactly - a loose specifier lets uv resolve that package to a prerelease too.
Configure
Copy the variables you need into .env (gitignored) or set them in your
deployment environment.
Variable | Default | Purpose |
| - | Required. CATS API key |
|
| API base URL |
| derived from | Override only; e.g. a vanity domain |
|
|
|
| all | e.g. |
|
|
|
|
| HTTP bind |
| - |
|
| - | JWKS endpoint, for |
| - | JWT claims to verify |
|
| results per |
|
| logging verbosity |
Run
python server.py # stdio, for Claude Desktop / Cursor / Claude Code
CATS_TRANSPORT=http python server.py # HTTP (requires auth, see below)Or via the FastMCP CLI:
fastmcp run src/cats_mcp/app.py:mcpDiscovery modes
The catalog is large on purpose - atomic coverage is what makes the adapter reusable. But those schemas must not all land in a model's context.
Mode | The model sees | Use for |
| the full authorized catalog | orchestrators doing their own tool discovery |
|
| direct MCP clients |
| a Code Mode sandbox | multi-step composition without intermediate results |
Every tool stays callable in every mode. Only visibility changes; hidden
tools are reached through call_tool, and authorization is enforced the same
either way.
Mastra and other orchestrators should use raw and run their own tool
search across every connected MCP server. Stacking this server's BM25 transform
under Mastra's means searching an index of an index, and prevents Mastra from
ranking CATS tools against tools from other servers.
code needs an optional extra:
uv pip install -e '.[code-mode]'Authentication
Serving over HTTP requires saying who verifies the caller, via
CATS_AUTH_MODE. There is no default, because guessing wrong is harmful in
both directions: assume a gateway that is not there and destructive tools sit
on an open URL; assume none and a correctly-fronted deployment fails to start.
Mode | Meaning | Use when |
| something in front authenticates first | hosted on Prefect Horizon, or behind a reverse proxy |
| this server verifies bearer tokens itself | self-hosted with nothing in front |
| nobody authenticates | local development only |
On Horizon, use platform. Its gateway "runs before your server code" and
authentication is enabled by default for hosted endpoints, so a rejected caller
never reaches this process.
For jwt:
CATS_AUTH_MODE=jwt
CATS_AUTH_JWKS_URI=https://your-issuer/.well-known/jwks.json
CATS_AUTH_ISSUER=https://your-issuer/
CATS_AUTH_AUDIENCE=cats-mcpstdio needs no mode - the transport is a pipe to a process you started.
Per-tool scopes (cats:read, cats:write, cats:destructive,
cats:bulk, cats:admin) apply in jwt mode, where this server sees verified
claims. Authorization then filters discovery as well as execution: a
read-only caller cannot see destructive tools in a listing, in search results,
or reach them through call_tool. Under platform, the gateway authenticates
but this server sees no claims, so authorization is the gateway's to enforce.
Working with candidate data
List and search tools return compact summaries by default - ids plus a small
field projection, with count, total, has_more and next_page.
Widen deliberately:
Level | Returns |
| a handful of identifying fields |
| the record, including custom fields - certifications, trade qualifications, screening answers |
| the whole record |
| exactly those columns |
Custom fields are where account-specific screening data lives, so reach for
summary_level='standard' rather than fetching each candidate individually -
that is the difference between one request and fifty against a 500/hour budget.
Links back to CATS
Candidate and job records carry a url field pointing at them in the CATS web
UI. Consumers were otherwise building these by hand and getting them wrong -
CATS uses index.php?m=candidates&a=show&candidateID=..., not a REST-style
/candidates/{id} path, so hand-built links look right in a spreadsheet and
404 when clicked.
The domain is derived, not configured. GET /site returns the account's
subdomain, and which account that is follows from the API key, so the adapter
reads it from the same credential it is already using - once per account, cached
for the process, and skipped entirely for the tools that can never emit a link.
That is what keeps links correct if different callers bring different CATS
accounts: a single configured value would hand one of them links into the other
company's CATS. Set CATS_UI_BASE_URL only to override - a vanity domain, or to
avoid the lookup.
A link is only emitted where the id genuinely identifies that record. A tool is
tagged with the resource it belongs to, not the shape of the rows it returns, so
list_candidate_attachments is a candidate tool returning attachments -
building a candidate link from an attachment id yields a working link to an
unrelated real person, which returns 200 and so is never reported as an error.
Saved-list membership rows are the one exception that still links: the row names
its candidate in candidate_id, so the link is built from that, never the row's
own id.
Unset, no link is emitted at all. A missing link is recoverable; a wrong one is not noticed until someone tries to use it.
Resumes, attachments, activities, pipelines and applications are never included
in a list at any level. They are unbounded in size and each has its own tool -
download_attachment returns the actual document for the model to read.
Known gap: attachment uploads are unverified
upload_candidate_attachment sends file_url in a JSON body. Nobody has
confirmed that against a live account, and CATS's documented endpoint
(POST /candidates/{id}/attachments?filename=..., filename as a query
param) reads like a binary upload, not a fetch-this-url request - the same
kind of never-tried spec that create_task and create_candidate_work_history
turned out to be. Fix only after a live attempt produces a real error to fix
against; do not guess the shape. See issue #25.
That issue also tracks the planned use of this tool: a standalone script,
outside this repo, that watches a local downloads folder for LinkedIn
profile PDF exports, extracts the profile URL printed in the document, and
resolves the candidate via lookup_candidate's exact profile_urls match -
never by name. An unresolved or ambiguous match is left for a human; nothing
here guesses which candidate a loose file belongs to. This adapter owns no
filesystem access or scheduling by design (see "What this is, and is not"
above), so that script runs locally on its own schedule and calls this
server, rather than living in src/cats_mcp/.
Rate limits
The CATS standard is 500 requests/hour. Some accounts are raised, so the
real ceiling is read from the response headers rather than assumed;
Retry-After is honoured and backoff is jittered.
Call get_connection_status to see the remaining budget before a large batch.
The composite read primitives exist for this reason - get_candidate_engagement
answers "when was each of these 50 candidates last contacted" in one tool call
instead of 50, and returns a compact table instead of 50 activity lists. See
docs/TOOLS.md.
Development
python -m pytest tests/ -q # test suite
python -m ruff check src/ tests/ # lint
python scripts/generate_tool_docs.py --write # regenerate docs/TOOLS.mdTool counts are generated from the registry and a test fails if the docs drift.
Adding a tool
Tools are declarative. Add a ToolSpec to the right module in
src/cats_mcp/registry/specs/ - name, endpoint, method, parameters and their
locations, safety class, tags and response strategy. One executor turns any spec
into a working tool; there is no per-tool request code to write.
Documentation
Document | Covers |
what this owns and does not, consumers, design decisions | |
running it locally, on Horizon, or self-hosted | |
tool, resource and prompt inventory (generated) | |
why an id is often not the record you think it is | |
| |
CATS web-UI links and how the domain is derived | |
resolving a saved list (Do Not Contact) in three calls | |
finding people in a region without matching the wrong towns | |
secret handling and the pre-commit guard |
Superseded documentation is not kept in the working tree; git history has it.
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
Recruiting tools for candidate sourcing, enrichment, ATS workflows, campaigns, and outreach.
7 recruiting tools over one MCP endpoint: ATS boards, LinkedIn jobs, profiles, companies, Naukri.
CareerProof MCP gives AI agents direct access to a professional-grade career and workforce intelligence platform. Two namespaces: atlas_* for HR/TA teams (candidate evaluation, batch shortlisting, competency scoring, interview generation, JD analysis, custom eval frameworks, research reports) and ceevee_* for professionals (CV optimization, career positioning, salary intelligence, market reports). Backed by RAG knowledge from 50+ premium research sources (McKinsey, BCG, HBR, Gartner, WEF)
# **RChilli MCP Hub** RChilli MCP Hub is a production-grade MCP server that exposes RChilli's full HR data intelligence platform as 17 AI-callable tools across 4 categories. Built on 15+ years of HR data intelligence, it is trusted by ATS vendors, HR technology platforms, staffing agencies, and enterprise recruiting teams worldwide. Every tool is read-only and returns a consistent, structured JSON response — no raw exceptions, no inconsistent formats. <br> --- <br> # **Tools — 17 Total** userkey and subuserid are injected automatically from your Bearer token — you never need to pass them manually. <br> --- <br> # **🔍 Resume & Job Description Parsing — 3 tools** <br> > ### **`extract_resume_data`** > > Extracts and converts resumes, CVs, and candidate documents into structured, searchable profiles with contact details, skills, experience, education, certifications, and taxonomy-enriched data for ATS, HCM, and AI recruiting workflows. When used on a careers page or application form, the same extraction call auto-fills every application field in under 10 seconds — documented to increase candidate conversion by up to 194%. Supports 40+ languages with English-normalized output for global intake, and runs in batch mode to process legacy databases or migration backlogs overnight at scale. Also supports resume reprocessing — re-running previously extracted resumes through the latest extraction logic and taxonomy version to bring older records up to current data quality, without requiring a new document from the candidate. Distinct from bulk import (first-time extraction of a new batch) and from talent data refresh (re-enrichment from a newer submitted resume). <br> > ### **`extract_resume_data_from_url`** > > Accepts a direct URL to a PDF, DOCX, or RTF file and returns the same normalized JSON profile as the Resume Data Extraction tool. Ideal for pipeline automation where resumes are stored in cloud storage, S3, or email attachments. Also supports the same auto-fill, multilingual, and batch-processing capabilities as the core extraction tool for URL-based intake sources. <br> > ### **`extract_job_data`** > > Extracts and converts job descriptions into structured hiring data including job title, required skills, preferred skills, responsibilities, experience, education, and taxonomy-normalized role requirements for recruitment automation and candidate matching. <br> --- <br> # **🧠 Skills & Job Taxonomy — 4 tools** <br> > ### **`lookup_skill`** > > Returns authoritative detail for a known skill including description, all aliases, related skills, proficiency levels, and O*NET/ESCO mappings. Use when you need the complete record rather than a ranked search. <br> > ### **`lookup_job_profile`** > > Returns authoritative detail for a known job profile including canonical title, SOC/O*NET code, job family, typical required and preferred skills, salary bands, and work context. <br> > ### **`autocomplete_skill`** > > Accepts a partial skill string (min 2 chars) and returns up to 10 ranked autocomplete suggestions with canonical names and categories. Prevents free-text entry errors and keeps skill data clean at point of entry. <br> > ### **`autocomplete_job_profile`** > > Accepts a partial job title string and returns ranked autocomplete suggestions with canonical titles and job families. Ensures job titles map to taxonomy profiles from the moment a recruiter starts typing. <br> --- <br> # **🛡️ Redaction, Documents & Utilities — 7 tools** <br> > ### **`redact_resume`** > > Redacts personally identifiable information from candidate profiles to support anonymized review, bias-aware screening, compliance workflows, and audit logs. Configurable redaction scope. Idempotent. <br> > ### **`reformat_resume_with_template`** > > RChilli's Resume Reformatting tool accepts any structured candidate profile and applies one of six branded templates (TM001–TM006) to produce a consistently formatted output document in PDF, DOCX, RTF, or HTML — ensuring every candidate is presented in a standardized, professional layout regardless of how their original resume was structured. Designed for staffing firms, recruitment agencies, and enterprise HR teams who need to control candidate presentation at scale, it eliminates manual reformatting effort and enforces brand consistency across all submissions. <br> > ### **`convert_document_format`** > > Accepts a document as base64 or URL and converts between PDF, DOCX, RTF, HTML, and plain text. Preserves formatting fidelity. Useful as a pre-processing step before data extraction on non-standard file types. <br> > ### **`tag_entities`** > > RChilli's Named Entity Recognition tool takes already-extracted HR text and annotates it by wrapping each recognized entity in a structured XML-style label inline — returning output such as `<job_title>Senior Data Engineer</job_title>`, `<skill>Python</skill>`, `<city>Austin</city>`, `<degree>Bachelor of Science</degree>`, and `<organization>Google</organization>` — covering 10+ HR-specific entity types including person name, state, country, date, and year. Unlike data extraction tools that produce separate field lists, tag_entities preserves the full original text structure with entities labeled in place, making the output immediately consumable by ATS field-mapping pipelines, candidate profile builders, and content annotation workflows without any offset calculation or post-processing. <br> > ### **`extract_contacts`** > > Identifies and structures names, emails, phone numbers, LinkedIn URLs, and addresses with field-level confidence scores from candidate records, emails, or documents. Safe for GDPR/CCPA workflows. <br> > ### **`geolocate`** > > Converts partial or informal location text into structured city, state, country, ISO codes, latitude, and longitude. Enables radius-based candidate and job search and supports workforce planning analytics. <br> > ### **`classify_job_zone`** > > RChilli's Job Zone Classification tool reads the job profile from a resume or job description and returns its O/*NET Job Zone — one of five standardized levels ranging from Zone 1 (little or no preparation required) through Zone 2 (some preparation), Zone 3 (medium preparation), Zone 4 (considerable preparation), to Zone 5 (extensive preparation required) — based on the education, experience, and training criteria defined by O/*NET. The returned Job Zone level enables downstream workflows such as candidate-to-role fit filtering, compensation benchmarking, over/under-qualification flagging, and job architecture standardization without any manual O/*NET lookup. <br> --- <br> # **🎯 Search & Matching — 3 tools** <br> > ### **`score_resume_against_jd`** > > Accepts one resume and one Job Description (no index required) and returns an overall match score, dimension scores, skill gap list, and natural-language explanation. Bias-controlled and audit-ready. <br> > ### **`find_matches_in_index`** > > Accepts a resume or Job Description as input and returns the top-N most similar documents from the indexed corpus ranked by semantic similarity. No index setup required for the input document. <br> > ### **`search_indexed_documents`** > > Accepts a query string and returns ranked document references from the tenant's pre-populated index. Supports Boolean and semantic search modes. Requires documents to be indexed before use.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables interaction with the Loxo recruitment platform API, facilitating tasks such as candidate and job management, activity logging, and call queue management through AI assistants.5MIT
- FlicenseNot gradedqualityDmaintenanceEnables interaction with Viterbit recruitment API for managing candidates, jobs, and applications. Supports searching, updating candidate data, handling job applications, and advanced filtering with subscription and activity status tracking.
- FlicenseNot gradedqualityNot gradedmaintenanceEnables interaction with the PeopleBox Applicant Tracking System (ATS) to manage candidates, positions, and recruitment pipelines. It provides tools for searching candidate profiles, adding notes, and tracking application timelines through natural language interfaces.
- AlicenseNot gradedqualityDmaintenanceProvides comprehensive access to the Kaseya VSAX (VSA 10) REST API v3 through 67 specialized tools. It enables users to manage devices, run workflows, execute scripts, and oversee organizational data using natural language and OData query support.1MIT
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/vanman2024/cats-mcp-server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server