swedish-jobs-mcp
An MCP server that lets AI assistants (Claude, Codex, Cursor, …) search all current job ads in Sweden — the ads in Arbetsförmedlingen's Platsbanken.
It talks to Arbetsförmedlingen's open JobTech APIs. It is not affiliated with or endorsed by Arbetsförmedlingen.
mcp-name: io.github.kizouker/swedish-jobs-mcp
Tools
| Tool | What it does |
|---|---|
search_jobs |
Free-text search ("python malmö"), remote filter, last N days, sorting, paging |
get_job |
One ad in full: description, salary, skills, apply link |
suggest_search_terms |
Autocomplete ("utve" → "utvecklare") |
changes_since |
Ads added/removed in all of Sweden in the last N hours |
How it works
The MCP client starts the server as a local process and talks to it over stdio. The server then calls Arbetsförmedlingen's JobTech APIs over HTTPS. No port is opened on your machine.
flowchart LR
User([User]) --> Client["MCP client<br/>(Claude Code, Claude Desktop, Codex)"]
subgraph Local machine
Client <-->|"stdio: JSON-RPC over stdin/stdout"| Server["swedish-jobs-mcp process<br/>(started by uvx)"]
end
Server -->|"HTTPS: /search, /ad/{id}, /complete"| JobSearch["JobSearch API<br/>jobsearch.api.jobtechdev.se"]
Server -->|"HTTPS: /stream"| JobStream["JobStream API<br/>jobstream.api.jobtechdev.se"]
Install
Needs uv.
Claude Desktop — add to claude_desktop_config.json:
{
"mcpServers": {
"swedish-jobs": {
"command": "uvx",
"args": ["swedish-jobs-mcp"],
}
}
}
Claude Code: claude mcp add swedish-jobs -- uvx swedish-jobs-mcp
Codex — add to ~/.codex/config.toml:
[mcp_servers.swedish-jobs]
command = "uvx"
args = ["swedish-jobs-mcp"]
Paging
search_jobs and changes_since return at most 25 ads per call, so one answer
never floods the AI's context. Each result has a next_offset: call the tool
again with offset=next_offset to get the next page. When next_offset is
null, there are no more ads.
Configuration
Everything is optional. Set these as environment variables (in the env block
of your MCP client config) to change the defaults:
| Variable | Default | What it does |
|---|---|---|
SWEDISH_JOBS_MAX_PAGE_SIZE |
25 |
Most ads returned per call |
SWEDISH_JOBS_DEFAULT_PAGE_SIZE |
25 |
Ads returned when no limit is given |
SWEDISH_JOBS_TIMEOUT |
30 |
Seconds to wait for JobSearch |
SWEDISH_JOBS_STREAM_TIMEOUT |
120 |
Seconds to wait for JobStream |
JOBTECH_SEARCH_URL / JOBTECH_STREAM_URL |
JobTech's public URLs | Point at another host, e.g. a test server |
Fair use
JobSearch is meant for searching, not bulk downloading. For a full copy of all ads, JobTech points to the JobStream API instead. Job ad texts may contain contact people's names and emails; don't store them longer than you need.
Data
Job ads come from Arbetsförmedlingen's open JobSearch and JobStream APIs, originally published under the name JobTech Development (JobTech). This repository's MIT license covers only the code, not the data.
- Licence: Arbetsförmedlingen publishes the job ads under Creative Commons CC0 (public domain). No attribution is required, but we credit Arbetsförmedlingen / JobTech as the source. See the dataset page: https://data.arbetsformedlingen.se/dataset/job-ads/
- Status: The JobTech Development brand is being retired. Open
data and APIs are moving to Arbetsförmedlingen's own site and to the data
catalogue at https://data.arbetsformedlingen.se/. Read more in
Vad händer nu med Arbetsförmedlingens JobTech?
(Swedish JobTech, 18 Oct 2024). The old
jobtechdev.sepages may no longer work. - API key: The old JobTech pages asked developers to apply for an API key.
We looked for one and could not find it: the page that should issue it
(
apirequest.jobtechdev.se) was not working when we checked. The new catalogue says no key or registration is needed, and the server works without one today. - As-is: We use the APIs as they are, for as long as they keep working. If
the API addresses or terms change, set
JOBTECH_SEARCH_URLandJOBTECH_STREAM_URL(see Configuration) and check the catalogue above. - Questions about the data: opendata@arbetsformedlingen.se
Development
uv run --extra dev pytest # offline tests: unit tests + end-to-end over MCP (API is faked)
uv run --extra dev pytest -m live # live tests against the real JobTech API
The end-to-end tests (tests/test_e2e.py) start the server as a real process
and call its tools over MCP, against a small fake JobTech server on localhost.
GitHub Actions runs the lint and the offline tests (Python 3.10-3.13) on every push and pull request. The live tests run every Monday and can be started by hand (Actions tab -> CI -> Run workflow), so a change in the JobTech API shows up as a failed run without blocking pull requests.
Try it locally with MCP Inspector
MCP Inspector is a web page where you can call the tools yourself. Needs Node.js.
npx @modelcontextprotocol/inspector uv run swedish-jobs-mcp
Open the address printed in the terminal, click Connect, then Tools → List Tools.
Debug in VS Code
Start the server through Inspector with debugpy listening on port 5678:
npx @modelcontextprotocol/inspector uv run --with debugpy python -X frozen_modules=off -m debugpy --listen 127.0.0.1:5678 -m swedish_jobs_mcp.server
.vscode/launch.json already has an attach configuration:
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to MCP server",
"type": "debugpy",
"request": "attach",
"connect": { "host": "127.0.0.1", "port": 5678 },
"justMyCode": false
}
]
}
- Set a breakpoint in
src/swedish_jobs_mcp/server.py. - In Inspector, click Connect.
- In VS Code, open Run and Debug, pick Attach to MCP server and press play.
- In Inspector, run a tool (for example
search_jobs). VS Code stops at the breakpoint.
Tips:
- Don't use
print()in the server. It writes to stdout, which is the MCP channel, and breaks the connection. Useloggingor write to stderr. Address already in usemeans an old process still holds port 5678. Find it withlsof -i :5678and stop it withkill <PID>.-X frozen_modules=offstops the debugger from missing breakpoints.
License
MIT
Metadata
Release files for swedish-jobs-mcp 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| swedish_jobs_mcp-0.1.0.tar.gz | 91.6 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| swedish_jobs_mcp-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 100.5 kB
Release files / swedish_jobs_mcp-0.1.0.tar.gz
| Download URL | swedish_jobs_mcp-0.1.0.tar.gz |
|---|---|
| Size | 91.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fd34e66d0a5434701e73ff43bbea83e7123b73de1418fdc933dc6caabd91c973
|
|
BLAKE2b-256 checksum How to use checksums |
ea405f8e2bd3063d6d866e7875efb0d0b352086417da99eb5a68aeff2ce53782
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / swedish_jobs_mcp-0.1.0-py3-none-any.whl
| Download URL | swedish_jobs_mcp-0.1.0-py3-none-any.whl |
|---|---|
| Size | 8.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
52a62c9553d2af287dc79f7a537b58a8f4cc3738da967e99080bc79d251efc1c
|
|
BLAKE2b-256 checksum How to use checksums |
0efeddba3d525ed87c80b237140dab67dc6c48e9a9dc5d7c38402bff445662a9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for swedish-jobs-mcp 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.