Skip to main content
Glama
gunio-mcp

gunio-mcp

gunio-mcp

A local-only, Docker-packaged MCP server (and a thin read CLI) for gun.io, authenticated with your own browser session — the same host-side cookie-broker + wrapper pattern as claudesync. It lets an MCP client (Claude Code, etc.) read your gun.io freelancer data — interviews, applications, jobs, profile — and perform a small set of gated writes.

Unofficial. No affiliation with gun.io. This talks to gun.io's private, undocumented API using your logged-in session. It is a personal automation tool; use it at your own risk and within gun.io's Terms of Service. No gun.io code is included in this repo.

How it works

Firefox session ──(host-side broker: rookie-cli)──▶ GUNIO_COOKIE ──▶ docker run ──▶ FastMCP server ──▶ app.gun.io/api/v2
  • A cookie broker (scripts/lib/harvest-cookie.sh) reads your gun.io session (sessionid + csrftoken) from the browser, host-side. Nothing leaves your machine.

  • A thin wrapper passes that cookie into a container via the GUNIO_COOKIE env var and docker runs it per invocation.

  • Inside the container, a Python/FastMCP server (gunio_mcp) calls gun.io's /api/v2 through a safety-guarded client (gunio_broker).

Related MCP server: Upwork MCP Server

Security model

  • Reads need only the cookies. Writes echo the csrftoken as X-CSRFToken (Django CSRF), and are double-gated: a call previews unless confirm=true and the server env has GUNIO_MCP_WRITE_SCOPE set.

  • Hard denylist in the client, enforced regardless of tool: auth/logout (a GET that kills your session), the entire /staff/ tree, DELETE on a freelancer (account deletion), complete-screening, and telemetry writes.

  • Cookies are never logged or placed in exceptions.

  • Local only. No data is sent anywhere except gun.io itself.

Install (once Docker image + installer land)

# bootstrap the broker + wrappers, pull the image
scripts/gunio-setup.sh install

# register the MCP server with Claude Code
claude mcp add --scope user gunio ~/.local/share/gunio/gunio-mcp-wrapper.sh

To enable writes, set GUNIO_MCP_WRITE_SCOPE=writes in the server env (see the wrapper). Without it, write tools only ever return a dry-run preview.

Remote mode (--serve)

By default gunio-mcp speaks MCP over stdio for a local client. With --serve it instead runs FastMCP's streamable HTTP transport as a long-lived service:

gunio-mcp --serve                      # http://127.0.0.1:8000/mcp
gunio-mcp --serve --host 0.0.0.0 --port 9000

Configuration (flags win over env vars):

Flag

Env var

Default

Meaning

--host

GUNIO_MCP_HOST

127.0.0.1

bind host

--port

GUNIO_MCP_PORT

8000

bind port

n/a

GUNIO_MCP_AUTH_TOKEN

unset

static bearer token required from clients

n/a

GUNIO_MCP_INSECURE

unset

1 allows a non-loopback bind without a token

Naming convention: GUNIO_MCP_* vars configure the server process itself; GUNIO_* vars (today just GUNIO_COOKIE) configure the gun.io account/session.

Endpoint security

GUNIO_COOKIE authenticates the server TO gun.io; nothing inherent authenticates clients TO this server. Anyone who can reach the HTTP endpoint can act as your gun.io account, including gated writes if the write scope is set. Therefore:

  • Set GUNIO_MCP_AUTH_TOKEN to require Authorization: Bearer <token> on every request (compared in constant time; never logged).

  • Binding a non-loopback host without that token refuses to start, unless you explicitly set GUNIO_MCP_INSECURE=1 because the network layer (e.g. Tailscale or an authenticating proxy) already provides access control.

  • Do NOT set GUNIO_MCP_WRITE_SCOPE on a remote deployment unless GUNIO_MCP_AUTH_TOKEN is configured.

Bearer auth applies only to serve mode; the stdio default ignores these vars.

Docker

docker run -e GUNIO_COOKIE=... -e GUNIO_MCP_AUTH_TOKEN=... -p 8000:8000 \
  gunio-mcp:local --serve --host 0.0.0.0

Inside a container, binding 0.0.0.0 with the token set is the expected pattern.

In remote mode there is no host-side broker refreshing the session: the GUNIO_COOKIE you deploy with is it. When gun.io expires that session, reads start failing until the deployment is updated with a fresh cookie. The auth_status tool (or gunio auth status on the CLI) is how you detect this: it performs one lightweight authenticated read and reports

{"mode": "cookie", "authenticated": false, "checked_at": "...", "error": "gun.io returned HTTP 401"}

without ever raising raw errors or leaking cookie material. Phase 2 will add credential-based login; this release is transport + visibility only.

Develop

uv sync --extra dev
uv run --extra dev pytest -q          # full suite
uv run gunio me                       # thin CLI (needs GUNIO_COOKIE or a logged-in browser)
uv run gunio-mcp                      # run the MCP server over stdio

GUNIO_COOKIE is a sessionid=...; csrftoken=... string; the broker produces it, or set it by hand for local dev.

Layout

Path

Role

src/gunio_broker/client.py

Safety-guarded HTTP client for /api/v2

src/gunio_mcp/tools.py

Pure tool helpers (reads + gated writes), unit-tested

src/gunio_mcp/server.py

FastMCP wrappers + main() (stdio)

src/gunio_cli/main.py

Thin read-only CLI

scripts/

Cookie broker, wrappers, installer (lifted from claudesync)

License

MIT.

Available Tools

24 tools
cancel_interviewB

Cancel an interview. Previews unless confirm=true and writes are enabled.

Inputs: interview_id (required), reason, confirm.

get_applicationB

Get a single job application by id.

Inputs: application_id (required).

get_availabilityB

Freelancer availability / seeking state.

Inputs: no named parameters.

get_freelancer_profileB

Full freelancer profile: bio, experiences, skills, rates.

Inputs: no named parameters.

get_interviewC

Get a single interview by id.

Inputs: interview_id (required).

get_jobA

Get a single job listing by id.

Inputs: job_id (required).

get_meA

Current gun.io user: identity, contact, flags, embedded freelancer summary.

Inputs: no named parameters.

get_subscriptionsB

The user's notification subscription settings.

Inputs: no named parameters.

get_workstyleC

The user's work-style preferences.

Inputs: no named parameters.

job_statsB

Platform job stats (e.g. jobs published last week).

Inputs: no named parameters.

list_applicationsC

List the freelancer's job applications (with status and embedded job info).

Inputs: page.

list_hiresC

List the freelancer's active/past engagements (hires).

Inputs: page.

list_interviewsB

List the freelancer's interviews, optionally filtered by status.

Inputs: status.

list_invitesB

List inbound invites for the freelancer.

Inputs: no named parameters.

list_mission_interviewsB

List the freelancer's mission interviews.

Inputs: no named parameters.

list_presentationsC

List client presentations for the freelancer.

Inputs: no named parameters.

list_reviewsC

List reviews the freelancer has received.

Inputs: page.

reschedule_interviewB

Reschedule an interview. Previews unless confirm=true and writes are enabled.

Inputs: body (required), interview_id (required), confirm.

respond_to_inviteC

Respond to an invite. Previews unless confirm=true and writes are enabled.

Inputs: body (required), invite_id (required), confirm.

schedule_interviewB

Schedule an interview. Previews unless confirm=true and writes are enabled.

Inputs: body (required), interview_id (required), confirm.

search_jobsC

Search open gun.io job listings.

Inputs: q, page.

update_applicationB

Patch a job application. Previews unless confirm=true and writes are enabled.

Inputs: patch (required), application_id (required), confirm.

update_profileA

Patch the freelancer profile. Previews unless confirm=true and writes are enabled.

Inputs: patch (required), confirm.

withdraw_applicationB

Withdraw a job application. Previews unless confirm=true and writes are enabled.

Inputs: application_id (required), reason, confirm.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.2/5.0

    Scored across 24 tools

    Disambiguation4/5

    Most tools target distinct resources (user, profile, interviews, applications, etc.), but 'list_interviews' and 'list_mission_interviews' could cause confusion; descriptions help clarify.

    Naming Consistency4/5

    Predominantly uses verb_noun pattern (list_, get_, update_, etc.), with minor deviations like 'get_me' and 'job_stats' being slightly off-pattern.

    Tool Count4/5

    24 tools is above the typical range but still reasonable for a comprehensive freelance platform client; each tool serves a distinct purpose without being excessive.

    Completeness4/5

    Covers core freelancer workflows (profile, applications, interviews, invites, hires, job search), but lacks tools for messaging or payment tracking which might be relevant.

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      A
      quality
      D
      maintenance
      A local job-hunting MCP server for discovering jobs across pluggable web sources, tracking applications through a status lifecycle, and managing profiles/resumes, with geo/map-region search.
      12
      -
    • A
      license
      Not graded
      quality
      D
      maintenance
      Local-first MCP server for research on AI-assisted browsing of a user-owned professional-network account (e.g., LinkedIn), providing read-focused tools such as profile, company, search, and feed reads.
      MIT