Skip to main content
Glama
JobStreet MCP Server

JobStreet MCP Server

by emansih
README.md
# jobstreet-mcp

A [Model Context Protocol](https://modelcontextprotocol.io) server (stdio transport) for searching
[JobStreet Singapore](https://sg.jobstreet.com) jobs, written in TypeScript. All tools are read-only and
need no sign-in.

> **Unofficial / undocumented API.** This server calls the same public JSON endpoints the JobStreet
> website uses (SEEK platform: REST `/api/jobsearch/v5/*` and GraphQL `/graphql`). They are not a
> supported public API and can change or break without notice; the server validates responses and fails
> with a clear error on schema drift. Please respect JobStreet/SEEK's terms of use and rate limits: the
> client throttles to at most 2 requests/second and caches results for 5 minutes. Not affiliated with
> SEEK or JobStreet.

## Tools

| Tool | Inputs | Description |
|---|---|---|
| `search_jobs` | `keywords`, `location`, `workTypes`, `workArrangements`, `classificationIds`, `subclassificationIds`, `salaryType`, `salaryMin`, `salaryMax`, `listedWithinDays`, `sortBy`, `page` (default 1), `pageSize` (default 30, max 100) | Search jobs. Returns `totalCount`, `page`, `pageSize`, `hasMore`, `searchUrl` and trimmed `jobs`. |
| `get_job_details` | `jobId` | Full job details with the description converted to plain text. |
| `get_search_counts` | same filters as `search_jobs` (no paging) | Facet counts by classification, work type and location without fetching jobs. |
| `suggest_keywords` | `query`, `count` (default 10) | Keyword autocomplete. |
| `suggest_locations` | `query`, `count` (default 10) | Location autocomplete; use the text as `location`. |
| `list_classifications` | none | The 30 top-level classification IDs. Subclassification IDs come from `search_jobs` results. |

Filter values:

- `workTypes`: `full_time`, `part_time`, `contract_temp`, `casual_vacation`
- `workArrangements`: `on_site`, `hybrid`, `remote`
- `salaryType`: `annual`, `monthly`, `hourly`. Salary bounds are SGD integers. If `salaryMin` or
  `salaryMax` is given without `salaryType`, `monthly` is used. With only `salaryMax`, the minimum is 0;
  with only `salaryMin`, there is no upper bound. `salaryType` alone (no bounds) is ignored.
- `listedWithinDays`: `1`, `3`, `7`, `14`, `31`
- `sortBy`: `relevance` (default), `date`

Resources: `jobstreet://classifications`, `jobstreet://about`.

API details are in [docs/jobstreet-sg-api-handover.md](./docs/jobstreet-sg-api-handover.md).

## Install

Requires Node.js >= 20.

```sh
npx -y jobstreet-mcp
# or install globally
npm install -g jobstreet-mcp
```

## Usage

### Claude Desktop

Add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "jobstreet": {
      "command": "npx",
      "args": ["-y", "jobstreet-mcp"]
    }
  }
}
```

### Claude Code

```sh
claude mcp add jobstreet -- npx -y jobstreet-mcp
```

## Development

Uses [pnpm](https://pnpm.io) (version pinned via `packageManager`).

```sh
pnpm install
pnpm dev         # run from source with tsx (watch mode)
pnpm typecheck
pnpm test
pnpm build       # outputs to dist/
pnpm start       # run the built server
```

Code layout: `src/server.ts` registers the tools (`createServer({ fetch })` takes an injectable `fetch`
for tests); `src/jobstreet/` holds the HTTP client (throttle, cache, timeout), parameter mapping, response
validation and the HTML-to-text converter. The stdio entry point is `src/index.ts`; never write to stdout
there other than MCP messages (log to stderr).

## Releasing

CI (`.github/workflows/ci.yml`) typechecks, tests and builds on every push to `main` and on pull requests.

Publishing (`.github/workflows/publish.yml`) runs when a tag matching `v*` is pushed:

1. Add an npm automation/granular access token with publish rights as the repository secret `NPM_TOKEN`
   (GitHub repo -> Settings -> Secrets and variables -> Actions).
2. Make sure `package.json` has a `repository` field pointing at the GitHub repo
   (required for npm provenance).
3. Bump the version and tag it; the tag must equal `v<package.json version>`:

   ```sh
   pnpm version patch   # or minor / major (creates the commit and the vX.Y.Z tag)
   git push --follow-tags
   ```

The workflow installs, typechecks, tests, builds and runs
`pnpm publish --access public --provenance --no-git-checks`.

## License

[Apache-2.0](./LICENSE)