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-mcp find 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.
Inputs: limit, sources, keywords, language, +1 more.
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.
Inputs: limit, keywords, language, min_amount_usd.
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.
Inputs: limit, keywords, min_amount_usd.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
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.
Discover verified deep-tech engineering bounties from any AI agent.
Bounty-feed search 386 rows across 9 sources (Bountycaster/Dework/Sherlock/Algora/GitHub/Reddit).
Finds real, maintained open-source repos that fit your project. MCP grounding for coding agents.
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
- AlicenseBqualityBmaintenanceMarketplace 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.27211 npm1MIT
- AlicenseAqualityDmaintenanceEnables AI agents to search and discover verified deep-tech engineering bounties with real funding, using a single search_bounties tool.191 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.462 npmApache 2.0