Skip to main content
Glama

bounty-mcp

An MCP server, over stdio, that gives agents tools to search paid open-source bounties:

  • GitHub: open issues labelled bounty or 💎 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 build

This creates dist/index.js. Start the server with:

node /absolute/path/to/bounty-mcp/dist/index.js

MCP 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

GITHUB_TOKEN

no

Sent as Authorization: Bearer … to GitHub. Raises the search limit from 10 to 30 requests/min.

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

title

string

Issue / reward title

repo

string

owner/name

url

string

Issue URL

labels

string[]

GitHub label names; for Opire "opire" plus the reported programming languages

created_at

string

ISO 8601 timestamp

amount_usd

number | null

USD amount, null if unknown

source

"github" | "opire"

Where the item came from (for merged duplicates: the entry that was kept)

currency_raw

string (optional)

Raw Opire amount when its unit is not USD_CENT, e.g. "500 EUR_CENT"

languages

string[] (optional)

Opire: reported languages. GitHub: the language you searched for, if any

sources

string[] (optional)

search_bounties only: every source the item was found in

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

language

string

none

Adds language:<x>. In issue search this matches the repository language.

keywords

string

none

Free text added to the GitHub query (GitHub search syntax applies)

min_amount_usd

number

none

Keep only issues with a parsed amount of at least this many USD (when > 0, issues without a parsed amount are dropped)

limit

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

keywords

string

none

Every whitespace-separated term must appear (case-insensitive) in title, repo or labels

min_amount_usd

number

none

Keep only rewards worth at least this many USD

limit

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

language

string

none

GitHub: language: qualifier. Opire: case-insensitive exact match on the reported languages (rewards with no languages are excluded)

keywords

string

none

GitHub: added to the search query. Opire: all terms must match locally

min_amount_usd

number

none

Minimum USD amount, applied after dedupe

limit

integer

20

1–50, applied after merging

sources

array of "github" | "opire"

["github","opire"]

Sources to query

  • Candidates: each source returns its full candidate set, not cut to limit and not filtered by amount. GitHub fetches one page of 100 issues (its per_page maximum) whatever limit is; Opire returns every reward matching keywords and language. Dedupe, the amount minimum, the sort and limit then run on the combined set, in that order. So an older, larger GitHub bounty is not lost because newer ones filled the first limit slots, and an item whose amount only one source knows keeps the labels and sources from both.

  • Dedupe: items are matched by normalized URL. The scheme, www., letter case, trailing slashes, query string and fragment are ignored. That way the same https://github.com/o/r/issues/N found 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, and sources lists every source it came from.

  • Sort: amount_usd descending, unknown amounts last, then created_at newest first.

  • Partial failure: if one source fails, the other's results are still returned and the response gets a warnings array, e.g. ["github: GitHub rate limit hit; resets at …"]. The tool returns isError only 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 23s

Each 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 x-ratelimit-remaining: 0 / retry-after / a rate-limit message

GitHub rate limit hit; resets at <ISO time>; set GITHUB_TOKEN to raise the limit (with a token: …; authenticated limit reached, wait before retrying)

other 403

GitHub refused the request (403): <message> (with a token, it also asks you to check GITHUB_TOKEN)

401

GitHub rejected the credentials (401): <message>; GITHUB_TOKEN is invalid or expired

422

GitHub rejected the search query (422): <message>; check the language and keywords

other non-2xx

GitHub API error <status>: <message>

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:

  1. Title: the largest amount found (so $100–$200 gives 200).

  2. Labels: the largest amount found in any label (e.g. $50, bounty: $500).

  3. 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 --selftest

Runs 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 OK

A 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 fixtures

License

MIT © 2026 synthalorian

Available Tools

3 tools
search_bountiesSearch all bounty sourcesA
Read-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.

NameRequiredDescriptionDefault
limitNoMax results (1-50, default 20)
sourcesNoSources to query (default: ["github", "opire"])
keywordsNoFree-text keywords
languageNoRepository / project programming language, e.g. "TypeScript"
min_amount_usdNoOnly return bounties worth at least this many USD (items with unknown amounts are excluded)

TDQS

A4.4/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 issuesA
Read-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.

NameRequiredDescriptionDefault
limitNoMax results (1-50, default 20)
keywordsNoFree-text keywords
languageNoRepository / project programming language, e.g. "TypeScript"
min_amount_usdNoOnly return bounties worth at least this many USD (items with unknown amounts are excluded)

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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 rewardsA
Read-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.

NameRequiredDescriptionDefault
limitNoMax results (1-50, default 20)
keywordsNoFree-text keywords
min_amount_usdNoOnly return bounties worth at least this many USD (items with unknown amounts are excluded)

TDQS

A3.8/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

  1. 3 tool updatesv0.1.0
    • First observedsearch_bounties
    • First observedsearch_github_bounties
    • First observedsearch_opire_rewards

TDQS

A3.8/5.0

Scored across 3 tools

Disambiguation3/5

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.

Naming Consistency4/5

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.

Tool Count4/5

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.

Completeness3/5

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

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    F
    maintenance
    Integrates 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.
    3
    MIT
  • A
    license
    B
    quality
    A
    maintenance
    Marketplace 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.
    27
    36 npm
    1
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Enables AI agents to find and query real-time GitHub coding bounties with built-in scam filtering, supporting listing, matching, and detailed bounty retrieval.
    4
    17 npm
    Apache 2.0