Skip to main content
Glama
jobboard

jobboard

README.md
# jobboard

jobboard is a small keyless bridge to JobYap's hosted
job search. JobYap aggregates job postings and the
community discussion around them; this package exposes
that search as nine MCP tools (and matching CLI
subcommands) by forwarding every call to the hosted
JobYap MCP endpoint. Read-only, no account, no API
key.

Two of the tools do the heavy lifting. `search_jobs`
browses the postings with structured filters (title
text, companies, locations, remote/hybrid, freshness,
discussion activity) and answers in under a second.
`match_jobs` ranks postings for one specific candidate
— a resume, or described experience, skills and visa
needs — by reading each posting's full description, so
it can take 10 to 15 seconds. Around them: `get_job`
reads one posting in full, `get_job_comments` reads
its discussion thread, `search_locations` resolves a
place name to the location identifiers the filters
accept, `list_companies` lists every tracked company
with its active job count, `get_job_stats` reports
aggregate counts, and `search` / `fetch` are the
deep-research pair (natural-language search, then the
full document for a result id).

## Tools

- `search_jobs` — browse, list, count or page through
  postings with structured filters. Optional: `query`
  (substring matched against job titles only),
  `companies` (exact names from `list_companies`),
  `locations` (identifiers from `search_locations`),
  `work_mode` (`remote` or `hybrid`), `posted_within`
  (`24h`, `7d`, `30d`), `has_comments`, `sort`
  (`recent` default, or `popular`), `page_size`,
  `cursor`, `include_total`.
- `match_jobs` — rank the best live postings for one
  candidate. `titles` (title terms; required unless
  `companies` is given), `exclude_titles`, `companies`,
  `exclude_companies`, `locations`, `include_anywhere`
  (default true), `work_mode`, `posted_within`
  (default `7d`), `candidate_years`,
  `needs_sponsorship`, `skills` (rank, never filter),
  `limit` (default 15).
- `get_job` — one posting in full: markdown
  description, salary ranges, locations with work
  mode, apply URL, posting dates and the canonical
  discussion URL. Required: `id` (numeric job id, a
  jobyap.com job URL, or a page slug).
- `get_job_comments` — the discussion thread for a
  job, chronological and threaded, with like counts.
  Required: `id`, as above. Comments are
  user-generated content.
- `search_locations` — resolve a free-text place name
  to location identifiers (`country-XX`,
  `state-XX-YY`, `city-XX-YY-name`). Required:
  `query` (minimum 2 characters); optional `limit`.
- `list_companies` — every company JobYap tracks,
  with its active job count and company-page URL.
- `get_job_stats` — companies tracked, active job
  count, newest posting date.
- `search` — natural-language search over postings;
  returns result ids, titles and citable URLs for
  `fetch`. Required: `query`.
- `fetch` — the full JobYap document for a search
  result id: the complete posting as markdown plus
  top community comments. Required: `id`.

The MCP layer validates each call locally before
forwarding: an unknown tool name, arguments that are
not a JSON object, or a missing required argument are
rejected as invalid params. Well-formed arguments are
forwarded exactly as given, and the upstream result
comes back verbatim — content, structuredContent and
any `isError` flag.

## Configuration

- `JOBYAP_MCP_URL` (optional) — override the hosted
  endpoint. Defaults to `https://mcp.jobyap.com/mcp`.

Failures are reported as error results whose text
starts with `jobboard error: ` (this rebuild's own
rendering): transport failures, non-2xx HTTP answers,
JSON-RPC errors and unparseable responses from the
upstream all take that shape, with the upstream's
message or status after the prefix.

### Forwarding mechanics

The bridge internals are a labelled reconstruction
(the Streamable HTTP session pattern): on the first
call the client POSTs an `initialize` request
(protocolVersion `2025-03-26`, empty capabilities,
clientInfo name `jobboard`), captures the
`mcp-session-id` response header when one is
returned, POSTs `notifications/initialized`, then
POSTs the `tools/call` request with the session
header attached when captured. The session is reused
for the life of the process. Every POST carries
`Content-Type: application/json` and
`Accept: application/json, text/event-stream`, and
responses may be plain JSON or SSE. tools/list is
served locally from the tool definitions captured
from the hosted endpoint, so listing tools never
touches the network.

## CLI

Each tool is a subcommand taking one JSON argument
string:

```bash
npx @reneturcios/jobboard search_jobs '{"query":"engineer","work_mode":"remote"}'
npx @reneturcios/jobboard match_jobs '{"titles":["software engineer"],"skills":["typescript","node"]}'
npx @reneturcios/jobboard get_job '{"id":42}'
npx @reneturcios/jobboard --version
```

Output is the forwarded result content as JSON. Exit
codes: `0` on success, `1` on an `isError` result, `2`
on a usage error.

## MCP server

```bash
npx -y @reneturcios/jobboard mcp
```

MCP client config:

```json
{
  "mcpServers": {
    "jobboard": {
      "command": "npx",
      "args": ["-y", "@reneturcios/jobboard", "mcp"]
    }
  }
}
```

## Docker

```bash
docker run -i ghcr.io/cloudcorprecords/jobboard
docker run --rm ghcr.io/cloudcorprecords/jobboard get_job '{"id":42}'
```

## Development

```bash
npm install
npm run build   # tsc -> dist/
npm test        # tsx --test test/*.test.ts (fake fetch only, no network)
npm run dev     # run the CLI from source
```

## License

MIT — Copyright (c) 2026 Rene Turcios