hn-hiring-mcp
Uses the public HN Algolia API as its data source to fetch Hacker News "Ask HN: Who is hiring?" threads and job posts, enabling tools for listing monthly threads, searching structured job posts, retrieving individual jobs, and analyzing hiring trends.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@hn-hiring-mcpFind remote Python jobs with salary in this month's Who is hiring?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
hn-hiring-mcp
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 |
| Latest monthly threads with ids and comment counts. |
| Search one month: free text, |
| Full text and parsed fields of one post by id. |
| 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-mcpClaude 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:
NeuralFrame: Senior Backend Engineer, Medical Data Pipeline (Python + Rust). REMOTE (US only, no visa sponsorship), $170k–$210k + equity. HN post
…
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 withHN_HIRING_MCP_CACHE_DIR, oroff). 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;headlineandhn_urlare 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] comand puzzle-style ones) are replaced with[email on HN]; the user followshn_urlto 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 toolsget_jobGet job postARead-onlyIdempotent
Returns the full text and parsed fields of one job post by its HN id (from search_jobs).
| Name | Required | Description | Default |
|---|---|---|---|
| id | Yes | HN comment id of the job post |
Output Schema
| Name | Required | Description |
|---|---|---|
| id | Yes | HN comment id; pass to get_job for the full post |
| text | Yes | Full post text; e-mail addresses are replaced with [email on HN] |
| links | Yes | |
| month | Yes | |
| roles | Yes | |
| hn_url | Yes | Link to the original post; apply via the instructions there |
| salary | Yes | As written by the poster |
| company | Yes | |
| excerpt | Yes | |
| headline | Yes | |
| location | Yes | |
| posted_at | Yes | |
| thread_id | Yes | |
| work_modes | Yes | |
| technologies | Yes | |
| employment_types | Yes | |
| visa_sponsorship | Yes | null when the post does not mention it |
TDQS
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.
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.
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.
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.
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.
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.
hiring_trendsHiring trendsARead-onlyIdempotent
For each of the last N monthly threads, counts how many posts mention each technology and how many offer remote/hybrid/onsite. Good for questions like 'is demand for Rust growing?'. The first call for many months can take ~1 s per uncached month.
| Name | Required | Description | Default |
|---|---|---|---|
| months | No | ||
| technologies | Yes | e.g. ['Python', 'TypeScript', 'Rust'] |
Output Schema
| Name | Required | Description |
|---|---|---|
| months | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, idempotentHint=true, and openWorldHint=true. The description adds valuable latency context ('The first call for many months can take ~1 s per uncached month'), which is behavioral information not captured by annotations. It does not mention output structure, but with an output schema present, that is less critical.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core computation, followed by an example and a performance caveat. No wasted words.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has an output schema, so the description needn't explain return values. It covers the computation, an example use case, and latency. It could be slightly more complete by clarifying the 'months' parameter or noting any data freshness limits, but it is largely sufficient for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 50%: the 'technologies' parameter is well documented with an example, but 'months' has no description. The description states 'the last N monthly threads', implying the 'months' parameter controls the window but doesn't clarify the default (6) or maximum (12) beyond what the schema already provides. Baseline 3 is appropriate given partial schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a precise computation: 'For each of the last N monthly threads, counts how many posts mention each technology and how many offer remote/hybrid/onsite.' This is a specific verb (counts) applied to specific resources (posts, technologies, work modes), and it is clearly distinguishable from siblings like list_hiring_threads (enumeration) and search_jobs (search).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives a concrete example use case ('is demand for Rust growing?'), which tells the agent when this tool is appropriate. However, it does not explicitly state when not to use it or name the sibling alternatives, so it stops short of full routing guidance.
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 threadsBRead-onlyIdempotent
Lists the most recent monthly "Ask HN: Who is hiring?" threads, newest first.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| threads | Yes |
TDQS
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.
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.
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.
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.
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.
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 postsARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| sort | No | Default: relevance when query is set, otherwise newest | |
| limit | No | ||
| month | No | Thread month as YYYY-MM. Defaults to the latest thread. | |
| query | No | Free-text terms, all must appear, e.g. 'machine learning Berlin' | |
| offset | No | ||
| location | No | Substring of the location, e.g. 'Europe', 'London', 'US' | |
| work_mode | No | ||
| has_salary | No | Only posts that state compensation | |
| technologies | No | All must be mentioned, e.g. ['Python', 'PostgreSQL'] | |
| visa_sponsorship | No | true: offers sponsorship/relocation; false: explicitly does not |
Output Schema
| Name | Required | Description |
|---|---|---|
| jobs | Yes | |
| month | Yes | |
| offset | Yes | |
| thread_id | Yes | |
| next_offset | Yes | |
| total_matches | Yes |
TDQS
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.
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.
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.
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.
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.
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.
4 tool updates
v0.1.0- First observed
get_job - First observed
hiring_trends - First observed
list_hiring_threads - First observed
search_jobs
TDQS
Scored across 4 tools
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.
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.
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.
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
Related MCP Connectors
Hacker News MCP — search and retrieve stories from Hacker News
JobsPipe — data pipeline of every job posting on the web. Search live, normalized job postings from 30+ ATS feeds and job boards for AI agents via MCP.
Public MCP server for discovering open jobs. Search, filter, and get application links.
Deterministic Hacker News developer sentiment, themes & feature requests via MCP. No API key.
Related MCP Servers
- AlicenseAqualityDmaintenanceMCP 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.4MIT
- AlicenseNot gradedqualityCmaintenanceMCP 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 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables 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
- AlicenseNot gradedqualityBmaintenanceEnables searching and retrieving standardized Hacker News 'Who is hiring?' job postings, and checking candidate fit against them via MCP tools.MIT