- Python 68.4%
- Nix 31.6%
Drop a personal home-directory path from the README config snippet. Co-Authored-By: Eva |
||
|---|---|---|
| nix | ||
| src/ghostswap_mcp | ||
| .env.example | ||
| .gitignore | ||
| flake.lock | ||
| flake.nix | ||
| pyproject.toml | ||
| README.md | ||
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_currencies → validate_address → get_quote →
create_swap → get_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.