Skip to main content
Glama
Crayz129

hn-hiring-mcp

by Crayz129

hn-hiring-mcp

CI npm

An MCP server that turns the monthly Hacker News "Ask HN: Who is hiring?" threads into a typed, searchable job API.

Every month hundreds of companies post jobs there as free-form comments. HN's own API can only return items by id, so there is no way to ask "remote Python roles in Europe that state a salary" or "is Rust demand growing?". This server parses each post into structured fields (company, roles, location, remote/hybrid/onsite, salary, visa, technologies) and exposes four read-only tools to any MCP client.

Tools

Tool

What it does

list_hiring_threads

Latest monthly threads with ids and comment counts.

search_jobs

Search one month: free text, location, work_mode, technologies, has_salary, visa_sponsorship, sort, limit/offset. Returns compact summaries.

get_job

Full text and parsed fields of one post by id.

hiring_trends

Per month: share of posts mentioning each technology, and remote/hybrid/onsite counts.

All tools declare JSON Schemas for input and output (structuredContent), are annotated readOnlyHint, and fail with a clear, model-readable error:

INVALID_INPUT: Unknown technology "cobol". Known technologies: Python, TypeScript, … For anything else use the free-text "query".
NOT_FOUND: HN item 49922569 is not a top-level job post in a "Who is hiring?" thread.
UPSTREAM_ERROR: HN API answered 503 while loading thread list. Try again later.

Related MCP server: hn-mcp

Install

Requires Node.js 22+.

Claude Code

claude mcp add hn-hiring -- npx -y hn-hiring-mcp

Claude Desktop: add to claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "hn-hiring": {
      "command": "npx",
      "args": ["-y", "hn-hiring-mcp"]
    }
  }
}

Any other MCP client: run npx -y hn-hiring-mcp as a stdio server.

Example

An abridged session in Claude Desktop (October 2026 data):

You: Find remote Python jobs from this month's Who is hiring that state a salary.

Claude calls search_jobs({ "technologies": ["Python"], "work_mode": "remote", "has_salary": true })

Claude: The October 2026 thread has 37 remote posts mentioning Python; 22 of them state a salary:

  1. NeuralFrame: Senior Backend Engineer, Medical Data Pipeline (Python + Rust). REMOTE (US only, no visa sponsorship), $170k–$210k + equity. HN post

  2. …

You: Has demand for MCP experience changed this year?

Claude calls hiring_trends({ "technologies": ["MCP", "Python", "TypeScript"], "months": 6 })

Claude: Yes. Posts mentioning MCP went from 2.5% in May to 4.5% in October (1.3% at the June low), while Python (22–27%) and TypeScript (20–24%) stayed flat.

How it works

  • Data source: the public HN Algolia API. One request returns a whole thread (~250 job posts), instead of ~400 item requests to the Firebase API.

  • Politeness: requests are serialised with at least 1 s between them, send an identifying User-Agent, and retry once on 429/5xx.

  • Cache: responses are cached in memory and on disk (~/.cache/hn-hiring-mcp, override with HN_HIRING_MCP_CACHE_DIR, or off). Threads older than 45 days never change and are kept; the current month is refreshed hourly. Replies to job posts are dropped before caching.

  • Parsing (src/parse.ts) follows the thread's own convention, Company | Role | Location | REMOTE | Salary, and also handles — separators, the location in parentheses and salary ranges written with -. Technology detection (src/technologies.ts) leans conservative: "Go ahead and apply" is not Go. Posts are free text, so the fields are best-effort; headline and hn_url are always there to check.

Privacy and scope

  • Read-only. No accounts, no logins, no applying on anyone's behalf.

  • E-mail addresses in posts (including name [at] company [dot] com and puzzle-style ones) are replaced with [email on HN]; the user follows hn_url to the original post to apply.

  • HN usernames of posters are not returned.

Development

npm install
npm test            # vitest, against recorded fixtures only; no network
npm run typecheck
npm run build
node scripts/smoke.ts search_jobs '{"query":"rust","limit":3}'   # live call through a real MCP client
node scripts/record-fixtures.ts                                   # refresh fixtures (anonymised, trimmed)

The server tests connect a real MCP Client to the server over an in-memory transport, so they exercise schemas, validation and error mapping the way Claude does.

License

MIT

Available Tools

4 tools
get_jobGet job postA
Read-onlyIdempotent

Returns the full text and parsed fields of one job post by its HN id (from search_jobs).

ParametersJSON Schema
NameRequiredDescriptionDefault
idYesHN comment id of the job post

Output Schema

ParametersJSON Schema
NameRequiredDescription
idYesHN comment id; pass to get_job for the full post
textYesFull post text; e-mail addresses are replaced with [email on HN]
linksYes
monthYes
rolesYes
hn_urlYesLink to the original post; apply via the instructions there
salaryYesAs written by the poster
companyYes
excerptYes
headlineYes
locationYes
posted_atYes
thread_idYes
work_modesYes
technologiesYes
employment_typesYes
visa_sponsorshipYesnull when the post does not mention it

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint and openWorldHint, so the safety and repeat-call profile is covered without the description. The description adds only that the return contains 'full text and parsed fields', which is modest extra context beyond the structured fields; no error or rate-limit behavior is disclosed.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

One sentence, front-loaded with the verb and result shape, with the id-provenance hint in a compact parenthetical. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present, the description need not explain return values, and annotations carry the safety profile, so the short description is close to sufficient. The only real gap is behavioral/edge-case guidance (missing or nonexistent id), which is not required but would complete the picture.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single 'id' parameter is already documented as the HN comment id of the job post, so the baseline is 3. The description adds provenance ('from search_jobs'), telling the agent where a valid id comes from, which is genuinely useful beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (Returns) plus resource and scope: 'full text and parsed fields of one job post by its HN id'. It distinguishes itself from the list/search siblings implicitly by being a single-item fetch, though it never names a sibling as an alternative the way an ideal routing hint would.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The parenthetical '(from search_jobs)' implies the workflow: obtain the id from search_jobs first, then call this tool. That is useful implied usage, but there is no explicit when-to-use vs. when-not, and no mention of what happens if the id is invalid or the post is gone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_hiring_threadsList hiring threadsB
Read-onlyIdempotent

Lists the most recent monthly "Ask HN: Who is hiring?" threads, newest first.

ParametersJSON Schema
NameRequiredDescriptionDefault
limitNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
threadsYes

TDQS

B3/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint and openWorldHint, so the safety profile is covered. The description adds the useful 'newest first' ordering and monthly cadence context, but says nothing about how many threads are returned or what the default limit behavior is. Modest added value over the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single tight sentence with the key ordering constraint front-loaded after the resource. No wasted words, though it is arguably a touch thin given the unaddressed limit parameter.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no explanation, and the tool is simple with one optional param. Still, the description omits the limit semantics and any routing guidance among the three siblings, leaving gaps an agent would benefit from having closed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The single 'limit' parameter has 0% schema description coverage and is never mentioned in the description, so its purpose, default (6), and maximum (24) are invisible to the agent. With coverage this low the description needed to compensate and does not, though the omission is small given only one param.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Lists the most recent monthly "Ask HN: Who is hiring?" threads') plus ordering ('newest first'), so the agent knows exactly what comes back. It is distinguishable from siblings like search_jobs and get_job by the fact that it returns threads rather than individual postings, though it never names those siblings explicitly.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no when-to-use or when-not-to-use guidance and no mention of the alternative tools (search_jobs, get_job, hiring_trends). The agent must infer that this is a discovery/browsing entry point versus a search endpoint. Only implied usage is conveyed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

search_jobsSearch job postsA
Read-onlyIdempotent

Searches one month of "Who is hiring?" posts. All filters are optional and combined with AND. Returns compact summaries; call get_job for the full text of a post.

ParametersJSON Schema
NameRequiredDescriptionDefault
sortNoDefault: relevance when query is set, otherwise newest
limitNo
monthNoThread month as YYYY-MM. Defaults to the latest thread.
queryNoFree-text terms, all must appear, e.g. 'machine learning Berlin'
offsetNo
locationNoSubstring of the location, e.g. 'Europe', 'London', 'US'
work_modeNo
has_salaryNoOnly posts that state compensation
technologiesNoAll must be mentioned, e.g. ['Python', 'PostgreSQL']
visa_sponsorshipNotrue: offers sponsorship/relocation; false: explicitly does not

Output Schema

ParametersJSON Schema
NameRequiredDescription
jobsYes
monthYes
offsetYes
thread_idYes
next_offsetYes
total_matchesYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly/openWorld/idempotent, so the safety profile is covered; the description adds real value by disclosing the return shape ('compact summaries') and the filter-combination semantics ('AND'). It omits pagination behavior of limit/offset and doesn't explain the relationship between month and list_hiring_threads.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences: what it searches, how filters behave, and where to go for more. The scope constraint and routing hint are front-loaded with zero filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 10-param search tool with an output schema, the description covers purpose, filter logic, and the get_job handoff, so return values need no explanation. It is slightly incomplete on pagination and on how the month parameter relates to list_hiring_threads, but nothing critical for a correct call is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 70% schema coverage, the schema already documents most parameters (defaults, patterns, enum hints). The description contributes the key cross-parameter semantics the schema cannot express: filters are optional and combined with AND. It adds nothing for individual params like sort or offset, but the combination rule is meaningful.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Searches ... "Who is hiring?" posts') and pins the scope to 'one month,' which no sibling covers. It also distinguishes itself from get_job by noting it returns compact summaries rather than full text, so an agent can route correctly without opening schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives clear usage context: all filters are optional and AND-combined, and it explicitly routes to get_job for full post text. It stops short of stating when *not* to use it (e.g. vs. hiring_trends for aggregate trends, or list_hiring_threads to discover valid months).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv0.1.0
    • First observedget_job
    • First observedhiring_trends
    • First observedlist_hiring_threads
    • First observedsearch_jobs

TDQS

A3.8/5.0

Scored across 4 tools

Disambiguation5/5

Each tool has a clearly distinct purpose: listing threads, searching across posts, retrieving a single post, and aggregating trends. Their boundaries are explicit and the descriptions cross-reference each other (search returns summaries, get_job fetches full text), so misselection is unlikely.

Naming Consistency4/5

Three tools follow a verb_noun pattern (list_hiring_threads, search_jobs, get_job), but hiring_trends breaks the pattern as a noun phrase. The deviation is minor and the intent remains clear.

Tool Count5/5

Four tools map cleanly onto the read-only domain of listing, searching, retrieving, and analyzing HN hiring posts. Each tool earns its place without redundancy or padding.

Completeness4/5

The set covers discovery (list/search), retrieval (get_job), and analytics (hiring_trends), which is solid for a read-only surface. Minor gaps like company- or role-level aggregation are absent, but agents can work around these via search.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    MCP 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.
    4
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server for Hacker News research. Enables AI agents to search stories and comments, browse listings, read discussion threads, and look up users via structured tools.
    27 npm
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to search Hacker News 'Who is hiring?' job postings with filters for role, level, location, remote, visa, salary, and company type, returning enriched results with direct apply links.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables searching and retrieving standardized Hacker News 'Who is hiring?' job postings, and checking candidate fit against them via MCP tools.
    MIT