Content
# fastworks-mcp
[](https://github.com/igun997/fastworks-mcp/actions/workflows/ci.yml)
[](https://github.com/igun997/fastworks-mcp/releases/latest)
Go CLI and MCP server for Fastwork freelancers. Log in once, keep the session on disk, then manage orders, services, chat, jobboard bids, rewards, withdrawals, stats, and online presence from a terminal or from an AI agent.
Two binaries:
| Binary | Purpose |
| --- | --- |
| `fastworks` | CLI for humans and scripts |
| `fastworks-mcp` | Model Context Protocol server on stdio for AI agents |
## Requirements
- Go 1.23 or newer
- A Fastwork seller account (this talks to the same endpoints as the seller web app)
## Install
Prebuilt binaries (linux and darwin on amd64/arm64, windows amd64) ship with every release:
```bash
VERSION=$(curl -fsSL https://api.github.com/repos/igun997/fastworks-mcp/releases/latest | grep -m1 '"tag_name"' | cut -d'"' -f4)
curl -fsSL "https://github.com/igun997/fastworks-mcp/releases/download/${VERSION}/fastworks-mcp_${VERSION}_linux_amd64.tar.gz" | tar -xz
cd "fastworks-mcp_${VERSION}_linux_amd64"
./fastworks version
```
Each release also carries `checksums.txt`; verify with `sha256sum -c checksums.txt`.
With the Go toolchain:
```bash
go install github.com/igun997/fastworks-mcp/cmd/fastworks@latest
go install github.com/igun997/fastworks-mcp/cmd/fastworks-mcp@latest
```
From source:
```bash
git clone git@github.com:igun997/fastworks-mcp.git
cd fastworks-mcp
make build # bin/fastworks and bin/fastworks-mcp, version stamped from git
make check # gofmt + vet + tests
```
## Quick start
```bash
bin/fastworks login --email you@example.com # prompts for the password
bin/fastworks whoami # confirm the session
bin/fastworks orders --status selling # today's work
bin/fastworks chat rooms --unread # who is waiting
bin/fastworks presence # daily online check-in
```
Then point an AI agent at the same session:
```bash
bin/fastworks-mcp # stdio MCP server, 59 tools
```
## Log in
```bash
fastworks login --email you@example.com # prompts for the password
fastworks login --email you@example.com --password-stdin < pass.txt
fastworks whoami
```
The login chain mirrors the seller web app:
1. `POST api.fastwork.id/auth/v2/login` returns a one-time `authorization_code`.
2. `GET seller.fastwork.id/callback?code=…` sets the `accessToken` cookie (a ~1 year JWT).
3. `POST seller.fastwork.id/api/user` confirms the session and returns the profile.
Session state (token, expiry, cookies, device id) lands in `~/.config/fastworks/session-<profile>.json`, directory `0700`, file `0600`. Use `--profile NAME` for multiple accounts.
`--save-credentials` stores email and password in that file so the CLI and MCP server can re-login automatically when a token is rejected. The password is written in plain text; anyone who can read the file or a backup of it can log in as you. Remove it with `fastworks session forget-credentials`.
## CLI
```bash
fastworks orders --status selling # active orders (status 2)
fastworks orders --status approval # awaiting buyer approval (status 4)
fastworks notifications --orders-only --limit 10
fastworks services # list services
fastworks service get --id ID --section basic|packages|media|metadata|detail
fastworks service create # draft, holds one product slot
fastworks service upload --id ID --file cover.jpg
fastworks service update --id ID --file payload.json
fastworks service submit --id ID
fastworks service visible --id ID --show=false
fastworks service delete --id ID --yes # irreversible
fastworks service auto-message --id ID --message "Hi, thanks for reaching out"
fastworks service categories
fastworks service schema # exact writable fields, limits, workflow
fastworks chat rooms --unread
fastworks chat messages --room ROOM_ID --limit 30
fastworks chat send --room ROOM_ID --message "On it, sending a draft tonight"
fastworks chat send --room ROOM_ID --image progress.png --message "Update hari ini"
fastworks chat send --room ROOM_ID --file build.zip
fastworks chat media --room ROOM_ID [--files]
fastworks chat read --room ROOM_ID
fastworks chat unread
fastworks order get --code SOD105EI # order in chat: status, buyer, quotation
fastworks order works --order ORDER_ID # deliverables already sent
fastworks order submit-work --code SOD105EI --room ROOM_ID --file build.zip --link https://drive…
fastworks order quotation create --order ORDER_ID --file quotation.json
fastworks order quotation cancel --order ORDER_ID
fastworks order templates # saved quotation templates
fastworks order milestones --master ORDER_ID
fastworks order review --order ORDER_ID --rating 5 --comment "Brief jelas"
fastworks withdrawals --balance
fastworks withdrawals --month 7 --year 2026
fastworks withdrawals --detail WITHDRAWAL_ID
fastworks jobboard quota # bids used / allowed
fastworks jobboard jobs --search website --open
fastworks jobboard job --id JOB_ID
fastworks jobboard bid --job JOB_ID --product SERVICE_ID \
--description-file pitch.txt --budget 4000000 --days 21 --brief-url https://example.com
fastworks jobboard my-bids
fastworks jobboard withdraw --offer BID_ID --yes
fastworks rewards points
fastworks rewards missions --open
fastworks rewards claim # claims every open mission
fastworks rewards catalog --affordable
fastworks rewards redeem --reward REWARD_ID --yes
fastworks stats # rating, response time, check-ins
fastworks stats --monthly # income series
fastworks stats --products # per-product performance
fastworks stats --product PRODUCT_ID
fastworks presence # daily online check-in
fastworks presence --every 30m # keep checking in
fastworks watch # realtime events as JSON lines
fastworks watch --webhook https://example.com/hook --events new_message_received,order_updated
fastworks session show --check
fastworks logout
```
Escape hatch for endpoints without a dedicated command:
```bash
fastworks api POST /api/v4/product.getMyServices --data '{}'
fastworks api GET /order/v2/orders --query limit=10 --include
fastworks graphql --query 'query { user { credits, pending_withdrawal_credits } }'
```
Global flags work before or after the subcommand: `--profile`, `--json`.
### Service update payloads
`service update` sends a partial patch; only the keys you include change.
```json
{
"title": "Android app development",
"description": "React Native app plus Play Store upload",
"category_id": "0856f9bb-…",
"subcategory_id": "…",
"base_price": 1500000,
"images": [{ "url": "https://…", "thumbnail_url": "https://…", "caption": null }],
"packages": [
{
"name": "Basic",
"price": 1500000,
"active": true,
"description": "APK and source code",
"delivery_times": 30,
"revision_times": 1,
"is_revision_times_unlimited": false,
"deliverables": []
}
]
}
```
Typical new-service flow: `service create` → `service upload` (returns `url` and `thumbnail_url`) → `service update` with title, description, category, price, images, packages → `service submit`.
Full field reference, limits, and validation rules: [docs/service-fields.md](docs/service-fields.md), or `fastworks service schema` / the `fastwork_service_schema` MCP tool at runtime.
## MCP server
```bash
fastworks-mcp # stdio, realtime chat socket on by default
fastworks-mcp --profile work --presence 30m
```
### Client configuration
Use an absolute path to the binary. Every client below takes the same server block.
Claude Desktop — `~/.config/Claude/claude_desktop_config.json` on Linux, `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS:
```json
{
"mcpServers": {
"fastwork": {
"command": "/home/you/bin/fastworks-mcp",
"args": ["--presence", "30m"]
}
}
}
```
Cursor — `~/.cursor/mcp.json` (or `.cursor/mcp.json` inside a project):
```json
{
"mcpServers": {
"fastwork": {
"command": "/home/you/bin/fastworks-mcp",
"args": []
}
}
}
```
pi — `~/.pi/agent/mcp.json`, `directTools` exposes the tools without the gateway wrapper:
```json
{
"mcpServers": {
"fastwork": {
"command": "/home/you/bin/fastworks-mcp",
"args": ["--presence", "30m"],
"directTools": true
}
}
}
```
VS Code (GitHub Copilot agent mode) — `.vscode/mcp.json`:
```json
{
"servers": {
"fastwork": {
"type": "stdio",
"command": "/home/you/bin/fastworks-mcp",
"args": []
}
}
}
```
Separate accounts get separate profiles, one server entry each:
```json
{
"mcpServers": {
"fastwork-main": { "command": "/home/you/bin/fastworks-mcp", "args": ["--profile", "main"] },
"fastwork-agency": { "command": "/home/you/bin/fastworks-mcp", "args": ["--profile", "agency"] }
}
}
```
Flags: `--profile NAME` picks the session profile, `--realtime=false` disables the chat websocket, `--presence 30m` keeps the seller online streak alive, `--version` prints the build version.
Run `fastworks login` once before starting the server; the MCP server reads the same session file and refuses tools that need auth when no valid token exists.
Tools:
| Area | Tools |
| --- | --- |
| Session | `fastwork_whoami` |
| Orders | `fastwork_orders_list`, `fastwork_notifications` |
| Services | `fastwork_service_schema`, `fastwork_services_list`, `fastwork_service_get`, `fastwork_service_create_draft`, `fastwork_service_update`, `fastwork_service_submit`, `fastwork_service_set_visible`, `fastwork_service_delete`, `fastwork_service_auto_message`, `fastwork_service_upload_media`, `fastwork_categories_list` |
| Chat | `fastwork_chat_rooms`, `fastwork_chat_room`, `fastwork_chat_messages`, `fastwork_chat_send`, `fastwork_chat_send_image`, `fastwork_chat_send_file`, `fastwork_chat_media_list`, `fastwork_chat_mark_read`, `fastwork_chat_unsend`, `fastwork_chat_unread`, `fastwork_chat_events` |
| Orders in chat | `fastwork_order_get`, `fastwork_order_list`, `fastwork_order_works`, `fastwork_order_submit_work`, `fastwork_order_milestones`, `fastwork_order_review_buyer` |
| Proposals | `fastwork_quotation_schema`, `fastwork_quotation_create`, `fastwork_quotation_cancel`, `fastwork_quotation_templates` |
| Money | `fastwork_wallet`, `fastwork_withdrawals_list`, `fastwork_withdrawal_details` |
| Stats | `fastwork_seller_stats`, `fastwork_income_monthly`, `fastwork_product_performance`, `fastwork_service_stats` |
| Jobboard | `fastwork_jobboard_jobs`, `fastwork_jobboard_job`, `fastwork_jobboard_job_offers`, `fastwork_jobboard_quota`, `fastwork_jobboard_tags`, `fastwork_jobboard_bid_schema`, `fastwork_jobboard_bid`, `fastwork_jobboard_my_bids`, `fastwork_jobboard_bid_withdraw` |
| Rewards | `fastwork_rewards_points`, `fastwork_rewards_missions`, `fastwork_rewards_claim`, `fastwork_rewards_history`, `fastwork_rewards_catalog`, `fastwork_rewards_redeem` |
| Presence | `fastwork_presence_ping` |
| Anything else | `fastwork_api_call` |
Notes for agent use:
- `fastwork_chat_send`, `fastwork_chat_send_image`, `fastwork_chat_send_file`, and `fastwork_chat_events` need the realtime socket, which runs unless you pass `--realtime=false`.
- Attachment tools take `file_path` or `content_base64`; uploading stores the file, and the message is posted in the same call.
- `fastwork_quotation_schema` documents the proposal payload; read it before `fastwork_quotation_create`.
- `fastwork_chat_events` drains a buffer of the last 500 events; pass `wait_seconds` to block until something arrives.
- `fastwork_service_delete` refuses to run without `confirm: true`.
- `fastwork_service_upload_media` accepts `file_path` or `content_base64`.
## Realtime chat
Chat runs on a Phoenix channel: `wss://chat-api.fastwork.id/socket/websocket?vsn=2.0.0&token=<accessToken>`, topic `user:<userId>`. Sending is a `send_message` push; the server pushes `new_message_received`, `message_updated`, `room_updated`, `read_receive_updated`, `unread_messages_count_updated`, and `order_updated`. `fastworks watch` prints those as JSON lines and can forward each one to a webhook.
Attachments, work submissions, quotations, and buyer reviews go through the chat web app backend (`chat.fastwork.id/api`), which uses cookie auth and a same-origin `Origin` header. Details and payload shapes: [docs/chat-and-orders.md](docs/chat-and-orders.md).
## Actions that change your account
These write to the live Fastwork account. The CLI asks for an explicit flag and the MCP tools require confirmation where the action cannot be undone.
| Action | Effect | Guard |
| --- | --- | --- |
| `chat send` / `fastwork_chat_send*` | buyer sees the message or attachment immediately | none, treat as sending a real reply |
| `order submit-work` / `fastwork_order_submit_work` | sends deliverables and notifies the buyer for approval | none |
| `order quotation create` / `fastwork_quotation_create` | posts a priced proposal into the buyer's chat | none |
| `order quotation cancel` / `fastwork_quotation_cancel` | withdraws the pending proposal | only before payment |
| `order review` / `fastwork_order_review_buyer` | publishes your rating of the buyer | one-way |
| `service submit` / `fastwork_service_submit` | service goes to review, often published straight away | none |
| `service visible --show=false` | hides the service from search | reversible |
| `service delete` / `fastwork_service_delete` | permanently removes the service | `--yes` flag / `confirm: true` |
| `service update` on a live service | lands as a pending revision on the listing | none |
| `jobboard bid` / `fastwork_jobboard_bid` | sends a real proposal to the job owner and uses one bid from the quota | `--dry-run` / `dry_run` previews the payload |
| `jobboard withdraw` / `fastwork_jobboard_bid_withdraw` | deletes your bid, the owner loses the proposal | `--yes` / `confirm: true` |
| `rewards claim` / `fastwork_rewards_claim` | claims mission points; unmet missions fail harmlessly | none |
| `rewards redeem` / `fastwork_rewards_redeem` | spends points, no refunds | `--yes` / `confirm: true` |
| `presence` | records the daily online check-in | none |
## Environment
| Variable | Purpose |
| --- | --- |
| `FASTWORK_EMAIL`, `FASTWORK_PASSWORD` | login credentials |
| `FASTWORKS_PROFILE` | default profile name |
| `FASTWORKS_SESSION_DIR` | session directory (default `~/.config/fastworks`) |
| `FASTWORK_API_BASE`, `FASTWORK_SELLER_BASE`, `FASTWORK_AUTH_BASE` | endpoint overrides |
| `FASTWORK_CHAT_API_BASE`, `FASTWORK_CHAT_SOCKET_BASE`, `FASTWORK_CHAT_BFF_BASE` | chat endpoint overrides |
| `FASTWORK_JOBBOARD_API_BASE`, `FASTWORK_JOBBOARD_ORIGIN` | jobboard endpoint overrides |
| `FASTWORK_REWARDS_API_BASE`, `FASTWORK_REWARDS_ORIGIN` | rewards endpoint overrides |
| `FASTWORK_CLIENT_ID`, `FASTWORK_CALLBACK_URL` | OAuth-style client settings |
| `FASTWORK_USER_AGENT`, `FASTWORK_LANGUAGE`, `FASTWORK_LOCALE` | request identity |
| `FASTWORK_TIMEOUT` | HTTP timeout, e.g. `45s` |
## Tests
```bash
make check # gofmt check, go vet, go test ./...
go test -race ./...
```
Tests run against `httptest` fakes, including a Phoenix websocket stub, so no live Fastwork account is needed.
## CI and releases
| Workflow | Trigger | What it does |
| --- | --- | --- |
| `ci.yml` | push to `main`/`feat/**`/`fix/**`, PRs to `main` | gofmt check, `go vet`, `go test -race`, builds both binaries, smoke-tests `tools/list` |
| `autotag.yml` | push to `main`, manual | reads Conventional Commits since the last tag, picks the next semver, pushes the tag, then calls the release workflow |
| `release.yml` | tag `v*`, manual, or called by `autotag.yml` | cross-compiles five targets, packages archives with README and docs, writes `checksums.txt`, publishes the GitHub release |
Tagging rules used by `autotag.yml`:
| Commit subject | Bump |
| --- | --- |
| `feat!: …` or a `BREAKING CHANGE` footer | major |
| `feat: …` | minor |
| `fix: …`, `perf: …`, `refactor: …`, `revert: …` | patch |
| only `chore: …`, `docs: …`, `test: …`, `ci: …` | no release |
Manual override: run the "Auto tag and release" workflow and pick `patch`, `minor`, or `major`. To publish an existing tag again, run "Release" with that tag. Version strings are stamped into both binaries, so `fastworks version` and `fastworks-mcp --version` report the released tag.
## Layout
```
cmd/fastworks/ CLI entry point
cmd/fastworks-mcp/ MCP stdio server entry point
internal/fastwork/ REST + GraphQL client, auth, orders, products, seller data
internal/chat/ chat REST client and Phoenix socket
internal/jobboard/ jobboard browsing and bidding
internal/rewards/ points, missions, redemption catalog
internal/session/ session store, persistent cookie jar, JWT decoding
internal/cliapp/ CLI commands
internal/mcpserver/ JSON-RPC/MCP plumbing and tool definitions
docs/ endpoint and field reference
.github/workflows/ CI, auto tagging, release
```
## Docs
- [docs/service-fields.md](docs/service-fields.md) — every writable service field, limits, validation rules, create-to-submit order
- [docs/chat-and-orders.md](docs/chat-and-orders.md) — chat attachments, work submission, proposals, buyer reviews
- [docs/jobboard-and-rewards.md](docs/jobboard-and-rewards.md) — jobboard browsing and bidding, rewards points and missions
- [docs/fastwork-endpoints.md](docs/fastwork-endpoints.md) — full observed endpoint catalog per host
## Notes and limits
- Fastwork publishes no public API. Endpoints were observed from the seller and chat web apps and can change without notice.
- Session files hold a long-lived token; treat `~/.config/fastworks` like an SSH key directory. Never commit it.
- `go.work` is intentionally ignored: this is a single module, so a workspace file is local dev config only.
- Commit messages follow Conventional Commits; the release tag is derived from them.
- Order payloads are returned as raw JSON because the shape is undocumented; the account used for development had no active orders to model against.
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
No recommendations available