Skip to main content
Glama
iliyalazarevwork-art

freelancehunt-mcp

README.md
# freelancehunt-mcp

[![npm](https://img.shields.io/npm/v/freelancehunt-mcp.svg)](https://www.npmjs.com/package/freelancehunt-mcp)
[![license](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)

An [MCP](https://modelcontextprotocol.io) server for the [Freelancehunt](https://freelancehunt.com) API 2.0 — the freelance marketplace used across Ukraine and neighbouring markets.

Point Claude, Cursor or any MCP client at it and ask things like *"find PHP projects under 40 bids where the employer actually pays on time"*. 31 tools cover the whole documented API: projects, bids, profiles, reviews, threads and workspaces.

## Why this exists

Freelancehunt's API has no official MCP server. The one adapter that does exist (inside a multi-board aggregator) flattens every project into a generic "job" record — dropping `bid_count` and the employer block, which are exactly the fields that tell you whether a project is worth one of your finite monthly bids.

This server keeps the API's own shapes and adds the filtering the API cannot do:

- **`find_projects`** walks several feed pages and filters locally by keywords, budget floor, bid-count ceiling and employer quality. The API itself offers none of this.
- **`get_reviews`** surfaces the per-axis grades Freelancehunt collects — communication, brief definition, **payment**, scope stability — averaged across reviews. A low payment score predicts a painful project far better than the budget does.
- Every response keeps `bid_count`, the employer's rating, completed-project count and review balance, so an agent can judge competition and counterparty in one call.

## Install

Requires Node.js 18+.

```bash
npx -y freelancehunt-mcp
```

### Get a token

Generate one on the [**Apps and API**](https://freelancehunt.com/my/api2) page of your Freelancehunt profile (`https://freelancehunt.com/my/api2`). The token acts on behalf of your account — treat it like a password, and revoke it on that same page if it leaks.

### Claude Code

```bash
claude mcp add freelancehunt --env FREELANCEHUNT_TOKEN=your_token -- npx -y freelancehunt-mcp
```

### Claude Desktop / Cursor

Add to the MCP config (`claude_desktop_config.json`, or `.cursor/mcp.json`):

```json
{
  "mcpServers": {
    "freelancehunt": {
      "command": "npx",
      "args": ["-y", "freelancehunt-mcp"],
      "env": {
        "FREELANCEHUNT_TOKEN": "your_token",
        "FREELANCEHUNT_LANG": "uk"
      }
    }
  }
}
```

### Run from a local checkout

`bin/mcp-stdio.sh` builds nothing and holds no secret: it reads the token from a `.env` file
and execs the built server, so the client config stays free of credentials.

```bash
git clone https://github.com/iliyalazarevwork-art/freelancehunt-mcp.git
cd freelancehunt-mcp
npm install && npm run build
cp .env.example .env    # then fill in FREELANCEHUNT_TOKEN
```

Point any client at the wrapper — no `env` block needed:

```json
{
  "mcpServers": {
    "freelancehunt": {
      "command": "/abs/path/to/freelancehunt-mcp/bin/mcp-stdio.sh"
    }
  }
}
```

For Codex CLI, the same command goes into `~/.codex/config.toml`:

```toml
[mcp_servers.freelancehunt]
command = "/abs/path/to/freelancehunt-mcp/bin/mcp-stdio.sh"
args = []
```

The wrapper takes the token from `FREELANCEHUNT_TOKEN` in the environment, else from
`$FREELANCEHUNT_ENV_FILE`, else from `.env` beside the repository — and accepts `FH_TOKEN`
as an alias, so a `.env` shared with another project works as-is.

### Configuration

| Variable | Default | Meaning |
|---|---|---|
| `FREELANCEHUNT_TOKEN` | — | **Required.** API token. `FH_TOKEN` also works. |
| `FREELANCEHUNT_LANG` | `en` | Response language: `uk`, `ru` or `en`. Affects skill and status names. |
| `FREELANCEHUNT_TIMEOUT_MS` | `30000` | Per-request timeout. |

## Tools

### Projects
| Tool | What it does |
|---|---|
| `find_projects` | Multi-page scan with local filters: keywords, budget range, `max_bids`, employer rating and history. **Start here.** |
| `list_projects` | Raw feed page, 10 projects per page. |
| `get_project` | Full details of one project. |
| `list_my_projects` | Projects you published (employer accounts only). |
| `create_project` · `update_project` · `project_action` | Publish, edit, amend, extend, close, reopen. |

### Bids
| Tool | What it does |
|---|---|
| `list_my_bids` | Your bids with status and winner flag. |
| `list_project_bids` | Bids on a project — sizing up competition. |
| `add_bid` | Place a bid: `days`, `budget {amount, currency}`, `comment`, `safe_type`, `is_hidden`. |
| `bid_action` | `revoke`, `restore`, `reject`, `choose` (pick winner). |

### Profiles and reviews
`get_my_profile` · `get_freelancer` · `get_employer` · `get_reviews` · `list_profiles`

### Messaging
`get_feed` · `mark_feed_read` · `list_threads` · `get_thread` · `send_message` · `thread_action`

### Workspaces
`list_workspaces` · `get_workspace` · `workspace_action` (negotiate conditions, extend, complete, close, review, request arbitration) · `complete_contest_workspace`

### Reference
`list_skills` · `list_locations` · `list_contests` · `get_contest` · `contest_action`

> **Skill ids are the only feed filter the API enforces.** Call `list_skills` first and pass `skill_ids` — `only_my_skills` and `only_for_plus` are documented but silently ignored by the server.

## Endpoint availability (measured, not documented)

The published API documentation lists 57 endpoints. Fewer than half answer for a regular freelancer token. Measured against the live API in September 2026:

| Works | Returns 404 / 400 |
|---|---|
| `/projects`, `/projects/{id}` | `/countries`, `/cities/{id}` |
| `/skills` | `/freelancers`, `/employers` (list form) |
| `/my/profile`, `/my/bids`, `/my/feed` | `/my/reviews`, `/contests`, `/my/contests` |
| `/freelancers/{id}`, `/employers/{id}` | `/my/workspaces/*` |
| `/freelancers/{id}/reviews`, `/employers/{id}/reviews` | `/projects/{id}/bids` (unless you own the project) |
| `/threads` | `/my/projects` → 400 for freelancer-only accounts |

Tools for the unavailable endpoints are still registered — access may differ by account type or Plus status, and a clear API error is more useful than a missing tool.

Two more things the documentation gets wrong:

- **Rate-limit headers do not exist.** The docs promise `X-Ratelimit-Limit` and `X-Ratelimit-Remaining`; no response carries them. Assume an undocumented limit, back off on HTTP 429.
- **Every response carries `deprecation: true`.** There is no successor version — `/v1`, `/v3` and `/v4` all 404, and the docs still describe 2.0 as current. No `Sunset` date is published, so the flag is informational for now, but plan for the API to change.

## Safety

Some tools write to a real account under the token owner's name. The platform's rules on automation are strict, and bids are a finite monthly resource — a wasted bid cannot be recovered.

- `add_bid`, `bid_action`, `send_message`, `thread_action`, `workspace_action`, `create_project`, `project_action` and `contest_action` are annotated as non-read-only, and the destructive ones (`choose` a winner, close a workspace, delete a thread, request arbitration) additionally carry `destructiveHint`. MCP clients surface these as confirmation prompts.
- The server instructions tell the model to confirm with the user before any of them.
- Unsolicited messages to employers who never contacted you are spam under the platform rules. `send_message` says so in its own description.

If you want a strictly read-only deployment, run the server with a token generated for a throwaway account, or fork and drop the write registrations — they are isolated in `src/tools/`.

## Development

```bash
npm install
npm run build
npm run typecheck

# live smoke test against the API — read-only, writes nothing
FREELANCEHUNT_TOKEN=your_token node scripts/smoke.mjs

# interactive tool explorer
npm run inspect
```

Layout: `src/client.ts` is the HTTP layer (query building, error mapping, pagination), `src/tools/*.ts` register tools by domain, `src/index.ts` wires everything to stdio.

Contributions welcome — particularly measurements of endpoint availability from **employer** and **Plus** accounts, which would fill in the gaps in the table above.

## License

MIT © Iliya Lazarev

Not affiliated with or endorsed by Freelancehunt.

TDQS

B3.4/5.0

Scored across 31 tools

Disambiguation4/5

Most tools map cleanly to a distinct resource and action, and the generic *_action tools are separated by their target resource. There is minor overlap between workspace_action and complete_contest_workspace, and a few stubbed 404 tools add noise, but the descriptions generally resolve ambiguity.

Naming Consistency4/5

The set is predominantly snake_case verb_noun: list_*, get_*, create_project, update_project, add_bid, send_message. The *_action batch tools are a recognizable pattern, though they are noun_noun rather than verb_noun, and complete_contest_workspace / mark_feed_read deviate slightly.

Tool Count2/5

With 31 tools the surface is too large for the rubric's 25+ threshold. Several tools are documented but return 404 for normal tokens, so they inflate the count without adding usable capability.

Completeness4/5

Core lifecycles are well covered: projects support list/find/get/create/update/actions, bids support add/list/action, workspaces have list/get/action, and threads have list/get/send/action. Missing contest creation, working profile search, and the 404 stubs keep it from a perfect score.

Maintenance

ActivityMaintained
ResponsivenessNo issues