ati-hh-mcp
Click on "Deploy 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., "@ati-hh-mcpsearch for remote Python developer jobs in Moscow"
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.
ati-hh-mcp
Public MCP (Model Context Protocol) server for the hh.ru API: every operation of the public hh.ru OpenAPI specification – all 135 of them – exposed as grouped, switchable toolsets for LLM agents. stdio for personal use, streamable HTTP with API keys and OAuth for teams.
Complete and verified: 135/135 public OpenAPI operations are implemented and locked by a contract metatest (operations and required parameters); responses are checked against the vendored specification with live-recorded fixtures.
Safe by design: mutations require an explicit
confirm=trueargument; GET requests are throttled and retried on 429, mutations never repeat automatically; tokens never appear in logs.Built for LLMs: domain-prefixed snake_case tool names, concise English descriptions, structured errors with hh.ru codes and Russian descriptions.
Contents
Related MCP server: HeadHunter API MCP Server
Requirements
Python 3.10 – 3.14 (CI matrix covers every minor version), or Docker.
uv for the uvx/stdio path.
An hh.ru API token or a registered OAuth application for authorized calls; public dictionaries, suggestions and vacancy search work without a token.
Quick start
uvx from git (stdio)
No clone, no install – the server runs straight from the repository:
uvx --from git+https://github.com/timur-ai/ati-hh-mcp ati-hh-mcp serve --transport stdioThe command starts the server on stdio with the default toolsets. Point an
MCP client at it (see client configuration) and set
HH_TOKEN in the server environment for authorized tools.
Docker Compose (HTTP)
git clone https://github.com/timur-ai/ati-hh-mcp
cd ati-hh-mcp
MCP_API_KEYS="$(openssl rand -hex 32)" docker compose up --buildClients connect to http://localhost:8080/mcp with
Authorization: Bearer <your-api-key>. The container is non-root, has a
/health endpoint for the Compose healthcheck, and keeps OAuth tokens in a
SQLite volume. See the deployment guide
for multi-user setup.
TLS is mandatory for network exposure: the server speaks plain HTTP, so
put a TLS-terminating reverse proxy (Caddy/nginx) in front of it, bind the
container to 127.0.0.1 and run a single worker process – see the
deployment guide for
ready-made proxy snippets.
Client configuration
ZCode (stdio)
.zcode/settings.json in the project (or the user config):
{
"mcpServers": {
"hh": {
"command": "uvx",
"args": [
"--from", "git+https://github.com/timur-ai/ati-hh-mcp",
"ati-hh-mcp", "serve", "--transport", "stdio"
],
"env": {
"HH_TOKEN": "YOUR_HH_TOKEN",
"HH_UA_EMAIL": "you@example.com"
}
}
}
}Claude Desktop (stdio)
claude_desktop_config.json
(macOS: ~/Library/Application Support/Claude/claude_desktop_config.json,
Windows: %APPDATA%\Claude\claude_desktop_config.json):
{
"mcpServers": {
"hh": {
"command": "uvx",
"args": [
"--from", "git+https://github.com/timur-ai/ati-hh-mcp",
"ati-hh-mcp", "serve", "--transport", "stdio"
],
"env": {
"HH_TOKEN": "YOUR_HH_TOKEN",
"HH_UA_EMAIL": "you@example.com"
}
}
}
}Cursor (stdio and HTTP)
.cursor/mcp.json. stdio launch:
{
"mcpServers": {
"hh": {
"command": "uvx",
"args": [
"--from", "git+https://github.com/timur-ai/ati-hh-mcp",
"ati-hh-mcp", "serve", "--transport", "stdio"
],
"env": {
"HH_TOKEN": "YOUR_HH_TOKEN",
"HH_UA_EMAIL": "you@example.com"
}
}
}
}Connection to the Docker/HTTP deployment:
{
"mcpServers": {
"hh": {
"url": "http://localhost:8080/mcp",
"headers": {
"Authorization": "Bearer YOUR_MCP_API_KEY"
}
}
}
}Toolsets
62 tools are enabled by default; six employer toolsets and the undocumented
extended set are opt-in via HH_TOOLSETS. HH_TOOLSETS fully replaces the
default list; the auth toolset is always included regardless.
A generated catalog with every tool, its OpenAPI operation and description
lives in the tool reference.
Toolset | Tools | Default | Domain |
| 5 | always on |
|
| 16 | on | areas, industries, professional roles, languages, locales, metro, skills, universities, vacancy conditions |
| 11 | on | search suggestions: areas, companies, positions, skills, keywords |
| 4 | on | vacancy search, similar and related vacancies |
| 10 | on | responses/invitations: lists, states, messages, tests, invitations |
| 14 | on | chats: messages, participants, files, read counters |
| 2 | on | resume viewing, call-tracking phone numbers |
| 23 | off | employer vacancy CRUD, drafts, publication, statistics |
| 5 | off | employer responses/invitations, mail templates, statistics |
| 11 | off | resume search (52 parameters), saved searches, applicant comments |
| 11 | off | managers, settings, access and limits |
| 25 | off | employers info, addresses, departments, calls, webhooks, salary statistics |
| 4 | off | undocumented: apply to a vacancy, own resumes, artifacts |
Enable extra toolsets with a comma-separated list, for example
HH_TOOLSETS=employer_vacancies,employer_resumes.
Authorization
The server separates access to the MCP server from access to hh.ru:
Authorization: Bearer <key>(HTTP mode) – the MCP API key fromMCP_API_KEYS; protects the server itself in multi-user deployments.X-HH-Token: <hh-token>– the hh.ru token for a single request (HTTP mode).OAuth profile – token pairs stored in SQLite per MCP API key.
An hh.ru token can be provided in three ways.
1. Static token
Set HH_TOKEN in the server environment (the usual stdio path). Applies to
every call of the deployment; in HTTP mode with MCP_API_KEYS set, HH_TOKEN
is deliberately ignored to avoid mixing user profiles.
2. Per-request token header
Send X-HH-Token: <token> with an MCP call (HTTP mode). The token is used
statelessly for that request only and is never stored.
3. OAuth login
With HH_CLIENT_ID, HH_CLIENT_SECRET and HH_REDIRECT_URI configured:
stdio: call
auth_get_login_url, open the URL in a browser, log in on hh.ru, copy thecodeparameter from the redirect address, then callauth_exchange_code(code). Token pairs land in the local SQLite store and refresh automatically.HTTP: same flow, but the redirect goes to
GET /oauth/callbackon the server and the exchange completes automatically. The OAuthstateparameter is bound to the caller's profile, so tokens land in the right SQLite profile.
auth_status shows the current profile state, auth_logout calls
DELETE /token on hh.ru and drops the stored pair.
Registering an hh.ru application
Sign in at dev.hh.ru and open the application admin.
Create an application; you will get
HH_CLIENT_IDandHH_CLIENT_SECRET.Register the redirect URI:
HTTP deployment:
http://<your-host>:8080/oauth/callback(for local testinghttp://localhost:8080/oauth/callback);stdio: any previously registered URI works – you copy the code manually.
Set
HH_CLIENT_ID,HH_CLIENT_SECRET,HH_REDIRECT_URIin the server environment and restart.
Two-level search schema
Heavy search operations (search_vacancies with 45 parameters,
employer_search_resumes with 52) would bury an LLM in flat arguments. Such tools use
a two-level schema: frequent filters are top-level tool parameters, the long
tail lives in a nested advanced object:
{
"text": "python developer",
"area": "1",
"salary": 200000,
"advanced": { "work_format": "remote", "date_from": "2026-01-01" }
}Unset fields – top-level or nested – are simply not sent to hh.ru. The allowed subset is locked in the tool registry and verified by the contract metatest, so no parameter outside the OpenAPI operation can sneak in.
Architecture
flowchart LR
A["MCP client<br/>(ZCode, Claude, Cursor)"] -- "stdio" --> S
A -- "HTTP + Bearer MCP API key" --> S
S["FastMCP server<br/>transports - auth middleware - /health - /oauth/callback"]
S --> R["Registry<br/>tool = operation (135/135)"]
S --> T["13 toolsets / 141 tools<br/>mutating tools require confirm"]
T --> K["toolkit make_tool<br/>path/query/body packing"]
K --> C["HHClient<br/>User-Agent - token bucket - 429 retries (GET only)"]
C -- "HTTPS + Bearer hh.ru token" --> HH["api.hh.ru"]
S -.-> DB[("TokenStore SQLite<br/>OAuth profiles per API key")]
B["browser OAuth"] -.-> STransports: stdio for personal launch (
uvx git+...), streamable HTTP withMCP_API_KEYSfor teams;/healthfor Docker healthchecks.Registry: the single source of truth mapping every tool to its OpenAPI operation; a contract metatest enforces
required params of the operation subset of tool params subset of operation params.HHClient: token-bucket throttling (default 25 req/min), the User-Agent contact policy of hh.ru, automatic 429 retries for GET only – mutations fail loudly instead of repeating.
TokenStore: SQLite, one OAuth profile per MCP API key (keyed by the sha256 hash – raw keys are never stored); automatic refresh on expiry.
Configuration
Environment variable | Default | Purpose |
| – | hh.ru token for all calls (stdio path; ignored in HTTP mode with |
| – | OAuth application client id (dev.hh.ru) |
| – | OAuth application client secret |
| – | OAuth redirect URI registered at dev.hh.ru |
| default set | Comma-separated toolsets to enable; fully replaces the default list ( |
|
| API base URL (tests and experiments) |
| placeholder | Contact email in the User-Agent (hh.ru requirement) |
|
| Requests per minute (token bucket) |
| platform dir | SQLite path for OAuth token pairs (Docker: |
| – | Comma-separated API keys guarding the HTTP endpoint (case-sensitive) |
Limitations
Stated honestly:
No resume CRUD. The public hh.ru OpenAPI has no operations to create or edit resumes; the
resumestoolset is read-only by design.The extended toolset is undocumented API.
apply_to_vacancy,my_resumes,artifacts_list,artifact_deleterely on endpoints outside the public specification; they are disabled by default, marked[UNDOCUMENTED hh.ru API]and may break without notice.Authorization header semantics.
Authorizationcarries the MCP server API key, not the hh.ru token; the hh.ru token travels inX-HH-TokenorHH_TOKEN. This mirrors the two-tenant reality (server access vs hh.ru access) and is an intentional deviation from the hh.ru API convention.Retries are GET-only. A timed-out mutation is reported as an error with a "may have been applied" hint; it is never retried automatically.
The live API drifts from the specification. Responses are validated against the vendored OpenAPI with live-recorded fixtures; the single confirmed deviation (
GET /suggests/companiesreturnsnullin non-nullableurl,area.name,logo_urls) is pinned inKNOWN_DEVIATIONSoftests/contract/test_schemas.py.Search endpoints are geo-blocked for datacenter IPs by hh.ru; the fixture recorder skips them (403
forbidden) when run from such networks. The server itself is unaffected when run from an allowed network.
Documented deviations
From the original design decisions, recorded with reasons:
FastMCP 4.1 instead of "FastMCP 2": the plan fixed the family, the concrete major was chosen in the M1 spike by stability and Python 3.10–3.14 support criteria; pinned in
uv.lock. Details: ADR Z1.__main__coverage floor is 90 %, below the project-wide 95 % – the CLI entrypoint is a thin argument parser around tested components.Distribution is sources-only (git + Docker): no PyPI, no GHCR, per the project decision.
Development
uv sync --dev # environment
uv run pytest -q # 547 tests (+8 live, opt-in): unit + contract + MCP e2e
uv run ruff check src tests # lint
uv run mypy src # strict type checkUseful maintenance scripts:
uv run python scripts/record_fixtures.py # re-record live response fixtures (read-only, sanitized)
uv run python scripts/gen_tool_docs.py # regenerate docs/tools/ from the registry
bash scripts/fetch_openapi.sh # refresh the vendored OpenAPI spec
uv run mkdocs serve # documentation site locallyLive integration tests (tests/integration_live/, marker live) are opt-in
and safe: read-only calls, token from the HH_LIVE_TOKEN secret, masked in
logs. The documentation site builds strictly (mkdocs build --strict) and
deploys to GitHub Pages from main on every push.
License
This server cannot be deployed
Maintenance
Related MCP Connectors
Multi-tenant Telegram gateway for AI agents — HTTP+stdio, 8 tools, MTProto User API
73 public tools: agent handoffs, one-time secrets, semantic search, queues, inboxes and webhooks.
Russian APIs for AI agents: YooKassa, CDEK, Bitrix24 and more. Ready scenarios with code. No key.
ADHD-friendly tasks, notes & projects for LucidNest - 18 tools, scoped tokens, Streamable HTTP.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables AI assistants to search job vacancies, manage resumes, and apply to jobs on HeadHunter (hh.ru), Russia's largest job search platform. Includes OAuth 2.0 integration for secure job applications and an automated vacancy hunter agent with intelligent matching.32MIT
- AlicenseNot gradedqualityFmaintenanceEnables AI assistants to access and manage HeadHunter job platform data, including vacancies, resumes, negotiations, and employer settings via 167+ tools.41 npm5MIT
- AlicenseNot gradedqualityDmaintenanceExposes iiko restaurant management system REST API as 42+ LLM-callable tools over stdio, enabling natural language interaction with products, employees, orders, payments, OLAP reports, and assembly charts.2MIT
- AlicenseAqualityCmaintenanceEnables searching and retrieving job vacancies, resumes, employers, and salary statistics from the hh.ru API (Russia/CIS) via 19 tools, with optional token access for resume search.1958 npm5MIT