MCP server for ghostswap.io
  • Python 68.4%
  • Nix 31.6%
Find a file
Aleksandr 2651c3a232 docs: use a generic path in the MCP client example
Drop a personal home-directory path from the README config snippet.

Co-Authored-By: Eva
2026-07-22 16:50:54 +03:00
nix Initial commit: GhostSwap Partners API MCP server 2026-07-22 16:48:35 +03:00
src/ghostswap_mcp Initial commit: GhostSwap Partners API MCP server 2026-07-22 16:48:35 +03:00
.env.example Initial commit: GhostSwap Partners API MCP server 2026-07-22 16:48:35 +03:00
.gitignore Initial commit: GhostSwap Partners API MCP server 2026-07-22 16:48:35 +03:00
flake.lock Initial commit: GhostSwap Partners API MCP server 2026-07-22 16:48:35 +03:00
flake.nix Initial commit: GhostSwap Partners API MCP server 2026-07-22 16:48:35 +03:00
pyproject.toml Initial commit: GhostSwap Partners API MCP server 2026-07-22 16:48:35 +03:00
README.md docs: use a generic path in the MCP client example 2026-07-22 16:50:54 +03:00

ghostswap-mcp

An MCP server for the GhostSwap Partners API — no-KYC crypto-to-crypto swaps across 1,600+ coins, exposed as MCP tools.

Packaged for Nix: run it with uv, install it as a flake package, or enable it as a NixOS service (services.ghostswap-mcp).

Tools

Tool Endpoint Auth Notes
health GET /health no Liveness probe.
public_quote GET /v1/public/quote no Indicative rate, no key needed.
list_currencies GET /v1/currencies yes lite=true → just tickers.
get_pair GET /v1/pairs yes Min/max for a pair.
validate_address POST /v1/addresses/validate yes Check a payout/refund wallet.
get_quote POST /v1/quotes yes Live quote; mode=fixed locks a rate.
create_swap POST /v1/swaps yes Moves real funds. Idempotent.
list_swaps GET /v1/swaps yes Paginated, org-scoped.
get_swap GET /v1/swaps/{id} yes Status source of truth — poll this.

Standard flow: list_currenciesvalidate_addressget_quotecreate_swapget_swap (poll until a terminal status: finished, failed, refunded, overdue, expired).

Credentials

Partner endpoints need a bearer built from two env vars:

GHOSTSWAP_PUBLIC_KEY=gspk_live_...
GHOSTSWAP_SECRET=gssk_live_...

Get them from the partner dashboard after your application is approved. public_quote and health work without them. The secret is never sent anywhere except in the Authorization header to partners-api.ghostswap.io.

Running

With uv (development)

git clone ssh://forgejo@git.desu.church:61488/eva/ghostswap-mcp.git
cd ghostswap-mcp
cp .env.example .env      # fill in your keys
set -a; . ./.env; set +a  # export them into the shell
uv run ghostswap-mcp                       # stdio (default)
uv run ghostswap-mcp --transport streamable-http --host 127.0.0.1 --port 8080

As a Claude Code / MCP client (stdio)

{
  "mcpServers": {
    "ghostswap": {
      "command": "uv",
      "args": ["run", "ghostswap-mcp"],
      "cwd": "/path/to/ghostswap-mcp",
      "env": {
        "GHOSTSWAP_PUBLIC_KEY": "gspk_live_...",
        "GHOSTSWAP_SECRET": "gssk_live_..."
      }
    }
  }
}

Or point command at the Nix-built binary: nix run .# / result/bin/ghostswap-mcp.

Nix flake

nix run git+ssh://forgejo@git.desu.church:61488/eva/ghostswap-mcp.git   # or: nix run .
nix build .                               # -> ./result/bin/ghostswap-mcp
nix develop                               # dev shell with python+mcp, uv, ruff

NixOS module

The flake exposes nixosModules.default (aka nixosModules.ghostswap-mcp), which runs the server under systemd as streamable-http.

{
  inputs.ghostswap-mcp.url = "git+ssh://forgejo@git.desu.church:61488/eva/ghostswap-mcp.git";

  # in your configuration.nix / flake nixosConfigurations:
  imports = [ inputs.ghostswap-mcp.nixosModules.default ];

  services.ghostswap-mcp = {
    enable = true;
    host = "127.0.0.1";
    port = 8080;
    # Credentials via an EnvironmentFile kept out of the store
    # (e.g. sops-nix / agenix). Omit for public-only tools.
    environmentFile = "/run/secrets/ghostswap-mcp.env";
  };
}

Options: transport (streamable-http | sse | stdio), host, port, apiBase, openFirewall, environmentFile, extraEnvironment, package. The service is hardened (DynamicUser, ProtectSystem=strict, no capabilities) — it is a pure network client with no state.

License

MIT.