Skip to content

Commit 8dd83cd

Browse files
authored
build: publish mcp server as mcp-jobspy (#425)
1 parent 7a8952a commit 8dd83cd

7 files changed

Lines changed: 166 additions & 30 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ jobs:
2727
- run: "python -m pip install --only-binary :all: dist/*.whl"
2828
- run: cd /tmp && python -c "from jobspy import scrape_jobs"
2929
- run: cd /tmp && jobspy --help && python -m jobspy --version
30+
- run: python -m build --wheel mcp
31+
- run: "python -m pip install --only-binary :all: dist/*.whl mcp/dist/*.whl"
32+
- run: cd /tmp && mcp-jobspy < /dev/null
3033

3134
lint:
3235
runs-on: ubuntu-latest

‎.github/workflows/publish-to-pypi.yml‎

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,68 @@ permissions:
88
contents: read
99

1010
jobs:
11-
publish:
11+
build:
1212
runs-on: ubuntu-latest
1313
steps:
1414
- uses: actions/checkout@v7
15-
- run: |
16-
version=${GITHUB_REF_NAME#v}
17-
test "$(jq -r .version server.json)" = "$version"
18-
test "$(jq -r '.packages[0].version' server.json)" = "$version"
19-
test "$(jq -r '.packages[0].runtimeArguments[0].value' server.json)" = "python-jobspy[mcp]==$version"
2015
- uses: actions/setup-python@v7
2116
with:
2217
python-version: "3.x"
23-
- run: python -m pip install build
18+
- run: |
19+
version=${GITHUB_REF_NAME#v}
20+
grep -qxF "version = \"$version\"" pyproject.toml
21+
grep -qxF "version = \"$version\"" mcp/pyproject.toml
22+
grep -qxF "dependencies = [\"python-jobspy[mcp]==$version\"]" mcp/pyproject.toml
23+
test "$(jq -r .version mcp/server.json)" = "$version"
24+
test "$(jq -r '.packages[0].version' mcp/server.json)" = "$version"
25+
- run: python -m pip install build twine
2426
- run: python -m build
27+
- run: python -m build mcp
28+
- run: twine check --strict dist/* mcp/dist/*
29+
- uses: actions/upload-artifact@v7
30+
with:
31+
name: dist
32+
path: |
33+
dist/
34+
mcp/dist/
35+
36+
publish:
37+
needs: build
38+
runs-on: ubuntu-latest
39+
steps:
40+
- uses: actions/download-artifact@v8
41+
with:
42+
name: dist
2543
- uses: pypa/gh-action-pypi-publish@release/v1
2644
with:
2745
password: ${{ secrets.PYPI_API_TOKEN }}
46+
skip-existing: true
2847

29-
mcp-registry:
48+
mcp-jobspy:
3049
needs: publish
3150
runs-on: ubuntu-latest
51+
environment: pypi
52+
permissions:
53+
id-token: write
54+
steps:
55+
- uses: actions/download-artifact@v8
56+
with:
57+
name: dist
58+
- uses: pypa/gh-action-pypi-publish@release/v1
59+
with:
60+
packages-dir: mcp/dist/
61+
skip-existing: true
62+
63+
mcp-registry:
64+
needs: mcp-jobspy
65+
runs-on: ubuntu-latest
3266
permissions:
3367
contents: read
3468
id-token: write
3569
steps:
3670
- uses: actions/checkout@v7
3771
- timeout-minutes: 10
38-
run: until curl -sf "https://pypi.org/pypi/python-jobspy/${GITHUB_REF_NAME#v}/json" > /dev/null; do sleep 10; done
72+
run: until curl -sf "https://pypi.org/pypi/mcp-jobspy/${GITHUB_REF_NAME#v}/json" > /dev/null; do sleep 10; done
3973
- run: curl -sL https://github.com/modelcontextprotocol/registry/releases/download/v1.8.1/mcp-publisher_linux_amd64.tar.gz | tar xz mcp-publisher
4074
- run: ./mcp-publisher login github-oidc
41-
- run: ./mcp-publisher publish
75+
- run: ./mcp-publisher publish mcp/server.json

‎README.md‎

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,7 @@ Each job is one line of JSON on stdout; errors and warnings go to stderr. `--pro
7676

7777
## MCP server
7878

79-
`mcp-jobspy` is an MCP server with two tools: `search_jobs` returns a preview of each job, `get_job_details` the full records of chosen ones. It installs with `pip install "python-jobspy[mcp]"` or runs through `uvx` as below.
80-
81-
For proxies, give them to the agent, or set `HTTPS_PROXY` in the server's `env`.
79+
`mcp-jobspy` is an MCP server that runs with `uvx mcp-jobspy@latest` or installs with `pip install "python-jobspy[mcp]"`. See [mcp/README.md](https://github.com/speedyapply/JobSpy/blob/main/mcp/README.md) for setup, tools and proxies.
8280

8381
**Standard config** works for most clients:
8482

@@ -87,7 +85,7 @@ For proxies, give them to the agent, or set `HTTPS_PROXY` in the server's `env`.
8785
"mcpServers": {
8886
"jobspy": {
8987
"command": "uvx",
90-
"args": ["--from", "python-jobspy[mcp]", "mcp-jobspy"]
88+
"args": ["mcp-jobspy@latest"]
9189
}
9290
}
9391
}
@@ -307,5 +305,3 @@ JobPost
307305
```
308306

309307
A column is empty when the job board doesn't provide it.
310-
311-
<!-- mcp-name: io.github.speedyapply/jobspy -->

‎mcp/LICENSE‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023 Cullen Watson
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

‎mcp/README.md‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# mcp-jobspy
2+
3+
<p align="center">
4+
<a href="https://pypi.org/project/mcp-jobspy/"><img src="https://img.shields.io/pypi/v/mcp-jobspy" alt="PyPI version"></a>
5+
<a href="https://github.com/speedyapply/JobSpy/actions/workflows/ci.yml"><img src="https://github.com/speedyapply/JobSpy/actions/workflows/ci.yml/badge.svg?branch=main" alt="CI"></a>
6+
<a href="https://github.com/speedyapply/JobSpy/blob/main/mcp/LICENSE"><img src="https://img.shields.io/pypi/l/mcp-jobspy" alt="License: MIT"></a>
7+
<a href="https://discord.gg/v7WdHnrNcN"><img src="https://img.shields.io/discord/1227411661221269565?label=discord&logo=discord&logoColor=white" alt="Discord"></a>
8+
</p>
9+
10+
[JobSpy](https://github.com/speedyapply/JobSpy)'s MCP server lets AI agents search LinkedIn, Indeed, Glassdoor, ZipRecruiter, Bayt, Naukri, BDJobs and HelloWork. It installs [`python-jobspy[mcp]`](https://pypi.org/project/python-jobspy/) at the same version and runs its `mcp-jobspy` command.
11+
12+
## Setup
13+
14+
Most clients take this config:
15+
16+
```json
17+
{
18+
"mcpServers": {
19+
"jobspy": {
20+
"command": "uvx",
21+
"args": ["mcp-jobspy@latest"]
22+
}
23+
}
24+
}
25+
```
26+
27+
For Claude Code:
28+
29+
```
30+
claude mcp add jobspy -- uvx mcp-jobspy@latest
31+
```
32+
33+
## Tools
34+
35+
- `search_jobs` searches the boards and returns a preview of each job with a search id. It takes JobSpy's search options (keywords, location, boards, number per board, posting age, remote, job type and more) and can save every record to a `.csv`, `.json` or `.jsonl` file.
36+
- `get_job_details` returns the full records of chosen jobs from a search, without searching again.
37+
38+
## Proxies
39+
40+
Job boards block repeated searches. Give the agent a proxy or a list of them, or set `HTTPS_PROXY` in the server's environment to keep credentials out of the chat:
41+
42+
```json
43+
{
44+
"mcpServers": {
45+
"jobspy": {
46+
"command": "uvx",
47+
"args": ["mcp-jobspy@latest"],
48+
"env": {"HTTPS_PROXY": "http://user:pass@host:port"}
49+
}
50+
}
51+
}
52+
```
53+
54+
<!-- mcp-name: io.github.speedyapply/jobspy -->

‎mcp/pyproject.toml‎

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
[project]
2+
name = "mcp-jobspy"
3+
version = "1.4.0"
4+
description = "JobSpy MCP Server: job scraper for LinkedIn, Indeed, Glassdoor, ZipRecruiter, Bayt, Naukri, BDJobs & HelloWork"
5+
readme = "README.md"
6+
maintainers = [
7+
{ name = "Kirk Watson", email = "kirk@klwindustries.com" },
8+
]
9+
license = "MIT"
10+
keywords = ["jobs-scraper", "linkedin", "indeed", "glassdoor", "ziprecruiter", "bayt", "naukri", "bdjobs", "hellowork", "cli", "mcp", "mcp-server"]
11+
classifiers = [
12+
"Development Status :: 5 - Production/Stable",
13+
"Environment :: Console",
14+
"Intended Audience :: Developers",
15+
"Intended Audience :: End Users/Desktop",
16+
"Operating System :: OS Independent",
17+
"Programming Language :: Python :: 3",
18+
"Topic :: Internet :: WWW/HTTP",
19+
"Topic :: Internet :: WWW/HTTP :: Indexing/Search",
20+
"Topic :: Office/Business",
21+
]
22+
requires-python = ">=3.10"
23+
dependencies = ["python-jobspy[mcp]==1.4.0"]
24+
25+
[project.urls]
26+
Homepage = "https://github.com/speedyapply/JobSpy"
27+
Issues = "https://github.com/speedyapply/JobSpy/issues"
28+
"Release notes" = "https://github.com/speedyapply/JobSpy/releases"
29+
Documentation = "https://github.com/speedyapply/JobSpy/tree/main/mcp"
30+
31+
[project.scripts]
32+
mcp-jobspy = "jobspy.mcp:main"
33+
34+
[build-system]
35+
requires = ["hatchling"]
36+
build-backend = "hatchling.build"
37+
38+
[tool.hatch.build.targets.wheel]
39+
bypass-selection = true

server.json renamed to mcp/server.json

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,20 @@
44
"title": "JobSpy",
55
"description": "Search LinkedIn, Indeed, ZipRecruiter, Glassdoor and regional job boards",
66
"version": "1.4.0",
7-
"websiteUrl": "https://github.com/speedyapply/JobSpy#mcp-server",
7+
"websiteUrl": "https://github.com/speedyapply/JobSpy/tree/main/mcp",
88
"repository": {
99
"url": "https://github.com/speedyapply/JobSpy",
1010
"source": "github"
1111
},
1212
"packages": [
1313
{
1414
"registryType": "pypi",
15-
"identifier": "python-jobspy",
15+
"identifier": "mcp-jobspy",
1616
"version": "1.4.0",
1717
"runtimeHint": "uvx",
1818
"transport": {
1919
"type": "stdio"
20-
},
21-
"runtimeArguments": [
22-
{
23-
"type": "named",
24-
"name": "--from",
25-
"value": "python-jobspy[mcp]==1.4.0"
26-
},
27-
{
28-
"type": "positional",
29-
"value": "mcp-jobspy"
30-
}
31-
]
20+
}
3221
}
3322
]
3423
}

0 commit comments

Comments
 (0)