mcp-adzuna
This server provides an MCP interface for Adzuna's job search and salary analytics APIs, enabling AI agents to query live job market data.
search_jobs: Search job listings by keywords, location, salary range, category, employment type (full-time, part-time, contract, permanent), company, and more, with flexible keyword matching (AND, OR, exact phrase, exclude, title-only).
list_categories: Retrieve available job category tags (e.g.,
it-jobs,sales-jobs) for a given country, used to filter other tools.salary_histogram: Get a salary distribution histogram for a search, showing vacancy counts per salary band.
top_companies: Get the top 5 employers by number of vacancies for a search.
regional_data: Get vacancy counts per sub-region, helping discover valid location strings for other tools.
historical_salary: Get average salary by month over time for a category and/or location.
api_version: Retrieve the current Adzuna API version (useful for debugging connectivity/auth).
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., "@mcp-adzuna search for python developer jobs in Berlin and show salary trends"
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.
mcp-adzuna
An MCP (Model Context Protocol) server that exposes Adzuna's job search and salary analytics APIs as tools.
This repo is server-only, by design: it's meant to be pulled into other AI systems/repos as a reusable
dependency, not run standalone. The client half of MCP — connecting to a server, listing its tools, and dispatching
tool calls from an LLM — is generic and already provided by whatever is hosting your agent (Claude Code, Claude
Desktop, or the MCP client library inside your own agent stack). Point that host at this server (see
below) rather than writing a bespoke client per project. A minimal demo client is
included under example/ purely to show the protocol working end-to-end — not as a reusable client
library for production use.
Architecture
MCP defines three roles: a host app that embeds an LLM (Claude Code, Claude Desktop, or your own agent stack),
an MCP client living inside that host which speaks the MCP wire protocol (tool discovery, tools/call, JSON-RPC
framing), and an MCP server that exposes tools and responds to protocol messages without knowing who's calling
it. This repo is only the last one — the host and its MCP client are supplied by whoever consumes this server (see
Using from another repo).
Internally, the server is split into two layers with no knowledge of each other's domain:
LLM decides to call a tool
│
▼
Host app (Claude Code / Claude Desktop / your agent stack)
│ spawns `mcp-adzuna` as a subprocess, speaks MCP over stdio
▼
MCP Client (built into the host — see example/ for a minimal standalone one)
│ tools/call { name: "search_jobs", arguments: {...} }
▼
┌─────────────────────────── this repo ───────────────────────────┐
│ MCP Server (server.py: the `mcp` object) │
│ - owns the stdio loop, tool registry, JSON schemas │
│ - dispatches to the matching @mcp.tool() function │
│ │ │
│ ▼ │
│ search_jobs(country=..., what=...) │
│ │ plain Python function call, no protocol involved │
│ ▼ │
│ AdzunaAPI.search(...) (client.py) │
│ - builds query params, calls httpx, strips __CLASS__ noise │
└────────────────────────────┼─────────────────────────────────────┘
▼
Adzuna's REST API (api.adzuna.com)server.pyis the only file that speaks MCP: tool names, docstrings-as-descriptions, type hints-as-JSON-schema.client.py'sAdzunaAPIis a plain REST wrapper around Adzuna's HTTP API — it has no knowledge that MCP exists. It's deliberately not namedAdzunaClient, to avoid confusion with the "MCP client" role above; it's a client of Adzuna's API in the ordinary SDK sense (likehttpx.Clientorboto3.client(...)), not an MCP client.
This split means AdzunaAPI is independently testable (tests/test_client.py runs against a mocked HTTP transport
with zero MCP runtime involved) and independently reusable (importable in a plain script with no MCP dependency
dragged in).
Related MCP server: trackly-cli
Tools
Tool | Adzuna endpoint | What it does |
|
| Search job listings by keyword, location, salary, category, etc. |
|
| List job category tags (e.g. |
|
| Distribution of salaries for a search as a histogram. |
|
| Top 5 employers by vacancy count for a search. |
|
| Vacancy counts per sub-region of a location. |
|
| Average salary by month, over time. |
|
| Current Adzuna API version (useful for checking connectivity/auth). |
Setup
Get a free
app_id/app_keyat developer.adzuna.com/signup.Install the package:
pip install -e .Set your credentials:
cp .env.example .env # edit .env and fill in ADZUNA_APP_ID / ADZUNA_APP_KEY
Running standalone
export ADZUNA_APP_ID=... ADZUNA_APP_KEY=...
mcp-adzunaThis starts the server on stdio, the standard transport for local MCP clients.
Using from another repo
Since this package isn't published to PyPI, other repos can run it straight from GitHub with
uv's uvx — no local clone or install step needed in the consuming repo:
{
"mcpServers": {
"adzuna": {
"command": "uvx",
"args": ["--from", "git+https://github.com/fabioba/mcp-adzuna.git", "mcp-adzuna"],
"env": {
"ADZUNA_APP_ID": "your-app-id",
"ADZUNA_APP_KEY": "your-app-key"
}
}
}
}Or, with Claude Code's CLI:
claude mcp add adzuna --env ADZUNA_APP_ID=your-app-id --env ADZUNA_APP_KEY=your-app-key \
-- uvx --from git+https://github.com/fabioba/mcp-adzuna.git mcp-adzunauv/uvx will fetch and cache the package from the git repo on first run, and re-fetch when the pinned ref
changes — pin to a tag or commit (git+https://...@v0.1.0) once you cut a release, so consuming repos don't pick up
breaking changes silently.
If a consuming repo already manages its own Python environment, adding mcp-adzuna @ git+https://github.com/fabioba/mcp-adzuna.git
to its pyproject.toml/requirements.txt dependencies works the same way, and mcp-adzuna becomes an installed
console-script entry point in that environment's mcpServers config instead.
Using locally with Claude Code / Claude Desktop
For local development on this repo itself, add it to your MCP config using the local install (see Setup) instead:
{
"mcpServers": {
"adzuna": {
"command": "mcp-adzuna",
"env": {
"ADZUNA_APP_ID": "your-app-id",
"ADZUNA_APP_KEY": "your-app-key"
}
}
}
}Example client
example/ contains a minimal MCP client that spawns this server and calls a tool, to see the protocol
work end-to-end without setting up a full MCP host first:
pip install -e ".[dev]"
python example/client.pySee example/README.md for what it demonstrates.
Development
pip install -e ".[dev]"
pytestTests run against a mocked HTTP transport (httpx.MockTransport) and don't require real Adzuna credentials.
Available Tools
7 toolsapi_versionA
Get the current Adzuna API version - useful for debugging connectivity/auth.
Inputs: no named parameters.
historical_salaryA
Get average salary by month for a category and/or location, over time.
Returned keys are "YYYY-MM" strings; order is not guaranteed by the API.
country: ISO country code, e.g. "gb", "us", "de". category: a category tag as returned by list_categories. months: how many months of history to return. location: a hierarchical place, most general first, e.g. ["UK", "London"]. See regional_data for how to discover valid values.
Inputs: country (required), months, category, location.
list_categoriesA
List Adzuna's job category tags for a country (e.g. "it-jobs", "sales-jobs").
country: ISO country code, e.g. "gb", "us", "de".
Category tags returned here can be passed as the category param to
search_jobs, salary_histogram, top_companies, regional_data, and
historical_salary.
Inputs: country (required).
regional_dataA
Get vacancy counts for each sub-region of a given location.
Also useful for discovering the exact area strings Adzuna expects for
the location param on other tools - each returned location includes
an area array you can reuse verbatim.
country: ISO country code, e.g. "gb", "us", "de". category: a category tag as returned by list_categories. location: a hierarchical place, most general first, e.g. ["UK", "West Midlands"]. Omit to get the country's top-level regions.
Inputs: country (required), category, location.
salary_histogramA
Get the current distribution of salaries for a job search as a histogram.
Each key in the returned histogram is the lower bound of a salary band; the value is the number of vacancies whose salary falls in that band.
country: ISO country code, e.g. "gb", "us", "de". what: keywords to filter jobs by (AND semantics, all words must match). category: a category tag as returned by list_categories. location: a hierarchical place, most general first, e.g. ["UK", "London"]. See regional_data for how to discover valid values.
Inputs: country (required), what, category, location.
search_jobsA
Search Adzuna's job listings.
country: ISO country code Adzuna covers, e.g. "gb", "us", "de", "fr", "it".
what: keywords where ALL words must match (AND). For multi-word roles like
"Senior Lead Data Engineer" this can silently return zero results;
use what_or instead to match ANY of the words.
what_or: keywords where ANY word may match (OR) - higher recall than what.
what_and: same as what (all words must match), explicit alternate name.
what_phrase: an exact phrase that must appear in the title or description.
what_exclude: keywords to exclude from results.
title_only: keywords to match, restricted to the job title only.
where: geographic centre of the search - a city, region, or postal code
(NOT a country name; combine with country for that). A bad value
here silently returns no results rather than erroring.
distance: search radius in km around where. Defaults to 5km if omitted.
location: a hierarchical place, most general first, e.g.
["UK", "South East England", "Buckinghamshire"]. See regional_data
for how to discover valid values.
category: a category tag as returned by list_categories.
sort_by / sort_dir: how to order results (e.g. sort_by="salary").
salary_min / salary_max: salary bounds to filter on.
salary_include_unknown: also include jobs with no listed salary.
full_time / part_time / contract / permanent: filter by employment type.
results_per_page: number of results per page (page size), default is
set server-side by Adzuna if omitted.
Inputs: country (required), page, what, where, +20 more.
top_companiesA
Get a leaderboard of the top 5 employers by number of vacancies.
country: ISO country code, e.g. "gb", "us", "de". what: keywords to filter jobs by (AND semantics, all words must match). category: a category tag as returned by list_categories. location: a hierarchical place, most general first, e.g. ["UK", "London"]. See regional_data for how to discover valid values.
Inputs: country (required), what, category, location.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 7 tools
Each tool targets a distinct aspect: job search, category listing, salary distribution, top companies, regional breakdown, historical salary, and API version. There is no overlap, and descriptions clearly differentiate each tool's purpose.
Tool names follow a mix of verb_noun (search_jobs, list_categories) and noun_phrase (salary_histogram, top_companies, regional_data, historical_salary, api_version) patterns. All are lowercase with underscores, but the lack of a consistent verb prefix makes the naming pattern inconsistent.
With 7 tools, the server is well-scoped for a job search and analytics domain. Each tool serves a distinct purpose without redundancy or bloat.
The server covers the core job search workflow, including filtering, category discovery, salary analysis, and regional breakdowns. However, there is no explicit tool for fetching a single job's full details or for paginating beyond setting a page size, leaving minor gaps in the lifecycle.
Related MCP Connectors
Public MCP server for discovering open jobs. Search, filter, and get application links.
A jobs data API and MCP server. Every listing comes from the employer's own career site, an ATS feed or a government employment service, never resold from another board. Each row names its source and when we last confirmed the vacancy existed, and a role that disappears keeps a closure date and a reason. Six tools: search_jobs, get_job, company_hiring, market_signals, coverage, changes_since.
GetJobzi MCP server for job search, application tracking, and career forecasting.
Pay-per-use tool marketplace for AI agents. Search, price-check, and call APIs via MCP.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceMCP server that exposes job search data from multiple boards, enabling clients to query and manage job listings via natural language.7MIT

trackly-cliofficial
AlicenseNot gradedqualityBmaintenanceMCP server for job search and application tracking, enabling AI agents to search jobs, get details, manage applications, and find contacts across 128K+ jobs and 1,900+ companies.1,041 npm3MIT- AlicenseAqualityDmaintenanceMCP server that scours job openings from public, ToS-clean sources (Greenhouse, Lever, Ashby, HN, RemoteOK, Adzuna, USAJobs) and provides tools for job search, company listings, and salary context.4MIT
- AlicenseAqualityCmaintenanceMCP server for interacting with the CleanJobData Job API, enabling job searches, company lookups, location suggestions, and candidate profile prompts.5MIT