bounty-mcp
Searches open public GitHub issues labeled bounty or 💎 Bounty via the GitHub issue search API, with optional filtering by language, keywords, and minimum USD amount, returning bounty results with title, repo, URL, labels, creation date, and parsed amount.
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., "@bounty-mcpfind open paid Rust bounties over $50 and compare GitHub with Opire"
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.
bounty-mcp
An MCP server, over stdio, that gives agents tools to search paid open-source bounties:
GitHub: open issues labelled
bountyor💎 Bounty(the label Algora uses), found through the GitHub issue search API.Opire: open rewards from the public Opire API (
https://api.opire.dev/rewards).
Every tool returns the same result shape, so agents can compare bounties across sources.
No API keys are required. A GitHub token is optional: it raises the GitHub rate limit, and since it
is sent with every search it could also let GitHub return issues from private repositories the token
can read. To prevent that, every GitHub query includes is:public, and any returned item whose
repository is flagged private (private: true or a non-public visibility) is dropped.
Not affiliated with GitHub, Algora or Opire.
Requirements
Node.js 18 or newer (uses the built-in
fetch)
Related MCP server: taskbounty-mcp-server
Install from source
git clone <this repository> bounty-mcp
cd bounty-mcp
npm install
npm run buildThis creates dist/index.js. Start the server with:
node /absolute/path/to/bounty-mcp/dist/index.jsMCP clients start the server themselves, so you normally only put this command in the client config
(see below). If you install the package from a registry, npx bounty-mcp would start the
same server.
Client configuration
Claude Desktop
Add the server to claude_desktop_config.json:
{
"mcpServers": {
"bounty": {
"command": "node",
"args": ["/absolute/path/to/bounty-mcp/dist/index.js"],
"env": {
"GITHUB_TOKEN": "ghp_optional_token"
}
}
}
}Cursor
Add it to .cursor/mcp.json in your project (or ~/.cursor/mcp.json for all projects):
{
"mcpServers": {
"bounty": {
"command": "node",
"args": ["/absolute/path/to/bounty-mcp/dist/index.js"],
"env": {
"GITHUB_TOKEN": "ghp_optional_token"
}
}
}
}The env block is optional. Leave it out to use GitHub without a token.
Environment
Variable | Required | Effect |
| no | Sent as |
A classic or fine-grained token with no extra scopes is enough to search public issues. Results are
limited to public repositories whatever the token can access (see is:public below).
Result shape
Every tool returns a text block with JSON (pretty-printed) and the same object as
structuredContent:
{
"count": 1,
"results": [
{
"title": "research implementation for Windows",
"repo": "radumarias/rencfs",
"url": "https://github.com/radumarias/rencfs/issues/3",
"labels": ["opire", "Rust"],
"created_at": "2024-07-30T17:46:26.532Z",
"amount_usd": 42,
"source": "opire",
"languages": ["Rust"]
}
]
}Field | Type | Notes |
| string | Issue / reward title |
| string |
|
| string | Issue URL |
| string[] | GitHub label names; for Opire |
| string | ISO 8601 timestamp |
| number | null | USD amount, |
|
| Where the item came from (for merged duplicates: the entry that was kept) |
| string (optional) | Raw Opire amount when its unit is not |
| string[] (optional) | Opire: reported languages. GitHub: the |
| string[] (optional) |
|
On failure a tool returns isError: true with a text message explaining what went wrong.
Invalid arguments (for example limit: 500) are rejected the same way.
Tools
search_github_bounties
Searches open GitHub issues with the bounty or 💎 Bounty label, newest first.
Parameter | Type | Default | Description |
| string | none | Adds |
| string | none | Free text added to the GitHub query (GitHub search syntax applies) |
| number | none | Keep only issues with a parsed amount of at least this many USD (when > 0, issues without a parsed amount are dropped) |
| integer | 20 | 1–50 |
The query sent to GET https://api.github.com/search/issues is:
is:issue is:open is:public label:bounty,"💎 Bounty" [language:<x>] [keywords]with sort=created&order=desc. is:public is always present, so private repositories never show up
even when GITHUB_TOKEN can read them; items flagged private in the response are dropped as well.
Comma-separated values in one label: qualifier are ORed. Only the value containing a space is
quoted: quoting the whole list (label:"bounty,💎 Bounty") makes GitHub look for one label with that
literal name, and it returns nothing.
per_page equals limit. When min_amount_usd is set, it fetches min(100, limit × 2) issues,
filters them locally and returns up to limit. So you can get fewer than limit results even when
more matching issues exist further back. (search_bounties always fetches 100; see below.)
Example result item:
{
"title": "USDC-quoted pairs not having the correct marketcap displayed in tools",
"repo": "blake-guthrie/GLASS",
"url": "https://github.com/blake-guthrie/GLASS/issues/1",
"labels": ["bounty"],
"created_at": "2026-10-23T19:03:20Z",
"amount_usd": 100,
"source": "github"
}search_opire_rewards
Lists open rewards from Opire, sorted by amount_usd descending (unknown amounts last), then newest
first. The sort happens before limit is applied, so a small limit returns the largest rewards.
Parameter | Type | Default | Description |
| string | none | Every whitespace-separated term must appear (case-insensitive) in title, repo or labels |
| number | none | Keep only rewards worth at least this many USD |
| integer | 20 | 1–50 |
The Opire endpoint is public. It returns a small list and ignores query parameters, so all filtering
happens locally. The amount comes from Opire's pendingPrice: USD_CENT values are divided by
100. Any other unit gives amount_usd: null and the raw value in currency_raw. Malformed items
in the response are skipped.
search_bounties
Queries the selected sources concurrently and merges the results.
Parameter | Type | Default | Description |
| string | none | GitHub: |
| string | none | GitHub: added to the search query. Opire: all terms must match locally |
| number | none | Minimum USD amount, applied after dedupe |
| integer | 20 | 1–50, applied after merging |
| array of |
| Sources to query |
Candidates: each source returns its full candidate set, not cut to
limitand not filtered by amount. GitHub fetches one page of 100 issues (itsper_pagemaximum) whateverlimitis; Opire returns every reward matchingkeywordsandlanguage. Dedupe, the amount minimum, the sort andlimitthen run on the combined set, in that order. So an older, larger GitHub bounty is not lost because newer ones filled the firstlimitslots, and an item whose amount only one source knows keeps the labels andsourcesfrom both.Dedupe: items are matched by normalized URL. The scheme,
www., letter case, trailing slashes, query string and fragment are ignored. That way the samehttps://github.com/o/r/issues/Nfound by both sources becomes one item. The entry with a known amount wins (Opire's reported amount over an amount parsed from GitHub text; otherwise the first one seen), labels are combined, andsourceslists every source it came from.Sort:
amount_usddescending, unknown amounts last, thencreated_atnewest first.Partial failure: if one source fails, the other's results are still returned and the response gets a
warningsarray, e.g.["github: GitHub rate limit hit; resets at …"]. The tool returnsisErroronly when every selected source fails.
Rate limits and errors
The GitHub search API allows 10 requests/minute without a token and 30/minute with one. To
stay under that, the server runs its own sliding-window limiter (per process). It allows 10 GitHub
searches per 60s without GITHUB_TOKEN and 25 per 60s with it. When the window is full, the call
fails right away (it does not wait) with:
rate limit: retry in 23sEach GitHub search sent counts toward the limiter, including ones that GitHub then rejects.
search_bounties uses one GitHub search per call when GitHub is selected. Opire is not rate-limited
locally.
When GitHub itself answers with a rate limit (429, or a rate-limit 403) and says when it resets, the client records that time and fails every GitHub search locally until then, without sending a request or using a limiter slot:
GitHub rate limit hit; resets at <ISO time>; set GITHUB_TOKEN to raise the limit (cooling down, request not sent)The cooldown is per process. If the response has no usable reset time, no cooldown is set.
GitHub error responses are turned into these messages:
Response | Message |
429, or 403 with |
|
other 403 |
|
401 |
|
422 |
|
other non-2xx |
|
The reset time comes from retry-after if present (either delta-seconds, e.g. 30, or an HTTP-date,
e.g. Sat, 24 Oct 2026 12:01:30 GMT), otherwise x-ratelimit-reset (epoch seconds). Timeouts are 15s
for GitHub and 20s for Opire (… request timed out after Ns). Network failures and invalid JSON are
reported too.
Amount parsing (GitHub)
GitHub issues have no amount field, so amount_usd is a heuristic and may be wrong or missing.
It looks in this order:
Title: the largest amount found (so
$100–$200gives 200).Labels: the largest amount found in any label (e.g.
$50,bounty: $500).Body: the first amount within a short distance after the words bounty, reward, prize, paid or payout. Otherwise, the first amount in the body.
Only two forms count as amounts:
a dollar sign next to a number:
$100,US$100,$1,500,$2.5k,$1.5K,💰 $250,[$50],100$a number next to a currency word:
100 USD,USD 100,100 USDC,100 USDT,100 dollars
Bare numbers (💰 500, reward-100-usd) are not guessed. $ followed by a non-digit is ignored.
Space-separated thousands ($1 500, 1 500 USD, USD 1 500, 1 500$) are rejected rather than
misread as 1 or 500. Dollar signs with a letter prefix other than US (CA$500, AU$500, NZ$,
HK$, SG$, C$, A$, …) are other currencies and give no amount; US$ counts as USD. Crypto
amounts are taken at face value (100 USDC = 100).
Self-test
node dist/index.js --selftestRuns one live query per source (5 results each) and prints, for example:
github: OK 5 results (first: <title> <url>)
opire: OK 3 results (first: <title> <url>)
selftest: 2/2 sources OKA failed source prints github: FAILED: <message>. The exit code is 0 if at least one source
succeeded, otherwise 1.
Other flags: --help (usage, including GITHUB_TOKEN) and --version. Without flags the MCP
server runs on stdin/stdout. Logs go to stderr only, because stdout carries the MCP protocol.
Development
npm install
npm run build # compiles src/ to dist/
npm test # vitest; no network access, fetch is mocked with recorded fixtures
npm run typecheck # type-checks src/ and test/Layout:
src/index.ts CLI entry (--selftest, --help, --version, or start the stdio server)
src/server.ts createServer(): tool registration and search_bounties orchestration
src/github.ts GitHub search client, query building, error mapping
src/opire.ts Opire client, lenient parsing, local filtering
src/merge.ts URL normalization, dedupe, sorting, amount filter
src/parse.ts amount parsing heuristics
src/ratelimit.ts sliding-window rate limiter
src/selftest.ts --selftest
test/ vitest suites and recorded API fixturesLicense
MIT © 2026 synthalorian
Available Tools
3 toolssearch_bountiesSearch all bounty sourcesARead-only
Search GitHub and Opire concurrently, dedupe by URL, and sort by amount (unknown amounts last), then newest first. If a source fails, results from the others are still returned with a warning.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results (1-50, default 20) | |
| sources | No | Sources to query (default: ["github", "opire"]) | |
| keywords | No | Free-text keywords | |
| language | No | Repository / project programming language, e.g. "TypeScript" | |
| min_amount_usd | No | Only return bounties worth at least this many USD (items with unknown amounts are excluded) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well past the readOnlyHint/openWorldHint annotations: discloses concurrent fan-out, URL-based dedupe, sort precedence (amount descending, unknown amounts last, then newest first), and degraded-mode behavior with a warning when one source fails. This is exactly the operational context an agent needs before calling.
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, no filler. Merge/sort semantics come first, failure handling second — both front-loaded and each clause carries information.
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 no output schema, the description carries the burden of return semantics and does well on ordering and partial results, but it doesn't characterize the result shape (what identifies a bounty, how amounts/currency are represented, whether the warning is a field or a separate channel).
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%, so limit, sources, keywords, language and min_amount_usd are already documented, including the unknown-amount exclusion rule. The description adds only the sort ordering that interacts with amount, which is baseline-appropriate but not compensating value.
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 (Search) and resource (bounties) plus the exact scope: GitHub and Opire concurrently, merged and sorted. The aggregation framing distinguishes it from the per-source siblings search_github_bounties and search_opire_rewards without needing to name them.
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?
Implied clearly by title and body: use this for a combined multi-source search. It does not explicitly say when to prefer a single-source sibling (e.g., source-specific keywords or pagination), 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.
search_github_bountiesSearch GitHub bounty issuesARead-only
Search open GitHub issues labelled "bounty" or Algora's "💎 Bounty", newest first. Amounts are parsed heuristically from the title, labels and body and may be missing or wrong.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results (1-50, default 20) | |
| keywords | No | Free-text keywords | |
| language | No | Repository / project programming language, e.g. "TypeScript" | |
| min_amount_usd | No | Only return bounties worth at least this many USD (items with unknown amounts are excluded) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint and openWorldHint, so the safety profile is covered. The description adds genuinely useful behavioral context beyond that: results are newest-first and bounty amounts are heuristically parsed and may be missing or wrong — a data-quality caveat the agent cannot infer from structured fields.
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 tight sentences: the first gives scope and ordering, the second gives the caveat. Nothing is wasted and the most important scoping information is front-loaded.
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 search tool with no output schema, the description never says what a result contains (title, repo, URL, parsed amount, labels) or how ordering/limit interact with pagination. The core scope and the amount-reliability caveat are present, but return-shape information 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?
Schema coverage is 100%, so parameters are already documented (including the min_amount_usd note that unknown-amount items are excluded). The description reinforces this by explaining why amounts can be unreliable, which directly affects how much to trust amount-based filtering.
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 (search open GitHub issues labelled 'bounty' or Algora's '💎 Bounty') and adds ordering (newest first), so the agent knows exactly what corpus is covered. It does not name the sibling tools (search_bounties, search_opire_rewards), so platform differentiation is left implicit rather than stated.
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 scope constraint (open issues, specific bounty labels) implies when the tool applies, but there is no explicit guidance on when to prefer it over search_bounties or search_opire_rewards. No exclusions or prerequisites are stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_opire_rewardsSearch Opire rewardsARead-only
List open rewards from Opire (api.opire.dev), sorted by amount (unknown amounts last), then newest first. The API returns a small list and ignores query parameters, so keyword and amount filtering is done locally.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Max results (1-50, default 20) | |
| keywords | No | Free-text keywords | |
| min_amount_usd | No | Only return bounties worth at least this many USD (items with unknown amounts are excluded) |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the read-only/open-world profile, and the description adds real behavioral context: sort order (amount descending, unknown amounts last, then newest first) and the important disclosure that the upstream API ignores query parameters so keyword and amount filtering happen locally. It does not say whether 'limit' is applied upstream or locally, which is the main remaining ambiguity.
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, zero filler, and the most decision-relevant facts (source and ordering) are front-loaded before the local-filtering caveat.
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?
No output schema exists, so the description carries the burden of return-value context, and it only says the API returns 'a small list' without describing a reward's fields. Everything else an agent needs to call it correctly — source, ordering, local filtering — is present.
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%, so the baseline is 3; each parameter is already documented in the schema. The description adds only the general statement that keyword and amount filtering is local, plus the ordering rule that explains why unknown-amount items fall last, without per-parameter detail.
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 ('List open rewards from Opire') with scope and ordering, and names the upstream source (api.opire.dev), which implicitly separates it from the GitHub-oriented siblings. It never explicitly contrasts itself with search_bounties or search_github_bounties, so sibling differentiation is by implication only.
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?
Usage is implied by the named source: use this to search Opire rewards. There is no explicit when-to-use/when-not statement nor any pointer to the sibling tools that cover other sources, leaving the agent to infer routing.
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.
3 tool updates
v0.1.0- First observed
search_bounties - First observed
search_github_bounties - First observed
search_opire_rewards
TDQS
Scored across 3 tools
The two source-specific tools (search_github_bounties, search_opire_rewards) are clearly distinct, but search_bounties is an aggregator that overlaps functionally with both. Descriptions do explain the difference (combined dedupe vs. per-source), which saves it from being truly confusing, but an agent must read carefully to decide whether to call the aggregate or the individual sources.
All three names are snake_case with the same verb 'search_', forming a predictable pattern. The minor deviation is that search_bounties lacks a source qualifier even though it is a superset of the other two, which makes it slightly ambiguous against search_github_bounties.
Three tools for a narrowly scoped bounty-discovery server is reasonable and each has a defensible role. The only inefficiency is that the aggregate tool largely subsumes the two source-specific ones, so the effective surface is closer to one-and-a-half tools.
The server covers discovery/search only: no detail lookup for a specific bounty, no filtering parameters exposed (keyword/amount filtering is done internally for Opire), and no pagination or repo-scoped search. Agents can work around this by using the returned URLs, but the surface stops at listing.
Maintenance
Related MCP Connectors
Search agent-ready open source repos by task, interface, ecosystem and OG score.
71Search GitHub, npm, PyPI, StackOverflow, ArXiv from one MCP — built for coding agents.
Discover verified deep-tech engineering bounties from any AI agent.
Bounty-feed search 386 rows across 9 sources (Bountycaster/Dework/Sherlock/Algora/GitHub/Reddit).
Related MCP Servers
- AlicenseNot gradedqualityFmaintenanceIntegrates with the Market.dev API to search for open source experts and projects. It enables users to find contributors and developers based on skills, location, or specific library and framework involvement.3MIT
- AlicenseBqualityAmaintenanceMarketplace where AI coding agents fix GitHub bugs for cash bounties. Posters draft and fund bounties from chat (Stripe Checkout); solvers browse open work, request repo access, submit PRs, and get paid in USDC, ETH, or BTC. 11 tools.2736 npm1MIT
- AlicenseAqualityDmaintenanceEnables AI agents to search and discover verified deep-tech engineering bounties with real funding, using a single search_bounties tool.116 npmMIT
- AlicenseAqualityDmaintenanceEnables AI agents to find and query real-time GitHub coding bounties with built-in scam filtering, supporting listing, matching, and detailed bounty retrieval.417 npmApache 2.0