{
  "markdown": "# gainium-mcp\n\nAn MCP (Model Context Protocol) server for [Gainium](https://gainium.io) — the crypto trading bot platform. Lets AI assistants manage your bots, deals, balances, and more through a standard MCP interface.\n\nDetailed setup and connection documentation is available in [docs/using-gainium-mcp.md](docs/using-gainium-mcp.md).\n\n## Quick Start\n\n### 1. Get your API keys\n\nGo to [Gainium API Settings](https://app.gainium.io/app/api) and create an API key pair.\n\n### 2. Add to your MCP client\n\nAdd this to your MCP configuration (VS Code, Claude Desktop, etc.):\n\n```json\n{\n  \"gainium-mcp\": {\n    \"command\": \"npx\",\n    \"args\": [\"-y\", \"gainium-mcp\"],\n    \"env\": {\n      \"GAINIUM_API_KEY\": \"<your-api-key>\",\n      \"GAINIUM_API_SECRET\": \"<your-api-secret>\"\n    }\n  }\n}\n```\n\nThat's it. The server starts automatically when your AI assistant needs it.\n\nThis local stdio mode uses `GAINIUM_API_KEY` and `GAINIUM_API_SECRET` from the server process environment.\n\n### Environment Variables\n\n| Variable | Required | Default | Description |\n|---|---|---|---|\n| `GAINIUM_API_KEY` | Yes | — | Your Gainium API public key |\n| `GAINIUM_API_SECRET` | Yes | — | Your Gainium API secret |\n| `GAINIUM_API_BASE_URL` | No | `https://api.gainium.io` | API base URL |\n| `GAINIUM_MCP_TRANSPORT` | No | `stdio` | Transport mode: `stdio`, `http`, `streamable-http`, `sse`, or `http-sse` |\n| `GAINIUM_MCP_HOST` | No | `127.0.0.1` | Bind host for HTTP mode |\n| `GAINIUM_MCP_PORT` | No | `3000` | Bind port for HTTP mode |\n| `GAINIUM_MCP_HTTP_PATH` | No | `/mcp` | Streamable HTTP endpoint path |\n| `GAINIUM_MCP_SSE_PATH` | No | `/sse` | Deprecated SSE GET endpoint path |\n| `GAINIUM_MCP_MESSAGES_PATH` | No | `/messages` | Deprecated SSE POST endpoint path |\n| `GAINIUM_OAUTH_ISSUER` | No | — | Authorization-server base URL. Setting this (with `MCP_INTROSPECTION_SECRET`, in HTTP mode) enables OAuth protected-resource mode |\n| `GAINIUM_INTROSPECTION_URL` | No | `<issuer>/oauth/introspect` | Token introspection endpoint |\n| `MCP_INTROSPECTION_SECRET` | No | — | Shared secret presented to the introspection endpoint (must match the auth server) |\n| `GAINIUM_MCP_PUBLIC_URL` | No | derived from request | Public base URL used in the protected-resource metadata |\n| `OPENAI_APPS_CHALLENGE_TOKEN` | No | — | When set, served as plain text at `/.well-known/openai-apps-challenge` for OpenAI Apps domain verification |\n\n## Authentication Modes\n\n`gainium-mcp` supports three deployment models:\n\n- **Local stdio mode:** the MCP server reads `GAINIUM_API_KEY` and `GAINIUM_API_SECRET` from env vars.\n- **OAuth 2.1 hosted mode (recommended for hosted/public):** the server acts as an OAuth protected resource. Clients (e.g. the Claude connector) obtain an access token from the Gainium authorization server and send it as `Authorization: Bearer <token>`. See [OAuth 2.1 hosted mode](#oauth-21-hosted-mode) below.\n- **Header hosted mode (legacy/self-hosted):** each request sends `X-API-Key` and `X-API-Secret` headers so one shared server can serve many users.\n\nIn header/stdio mode, request headers take priority, falling back to `GAINIUM_API_KEY` / `GAINIUM_API_SECRET`. When OAuth mode is enabled, the Bearer token is required and the `X-API-Key`/`X-API-Secret` headers are ignored.\n\n### OAuth 2.1 hosted mode\n\nThis is the mode used for the public `https://mcp.gainium.io/mcp` endpoint and the Anthropic Claude connector directory (which requires OAuth and forbids API-key headers).\n\nEnable it by setting, in HTTP mode:\n\n```bash\nexport GAINIUM_MCP_TRANSPORT=http\nexport GAINIUM_OAUTH_ISSUER=https://app.gainium.io        # Gainium authorization server\nexport MCP_INTROSPECTION_SECRET=<shared-secret>           # must match the auth server\nexport GAINIUM_MCP_PUBLIC_URL=https://mcp.gainium.io      # this server's public URL\n# optional, defaults to <issuer>/oauth/introspect:\n# export GAINIUM_INTROSPECTION_URL=https://app.gainium.io/oauth/introspect\nnode dist/server.js\n```\n\nWhen enabled, the server:\n\n1. Serves **OAuth Protected Resource Metadata** (RFC 9728) at\n   `/.well-known/oauth-protected-resource` and `/.well-known/oauth-protected-resource/mcp`,\n   advertising the authorization server.\n2. Rejects unauthenticated MCP requests with **`401 Unauthorized`** and a\n   `WWW-Authenticate: Bearer resource_metadata=\"…\"` header, so clients can discover\n   the auth server and run the OAuth flow (Dynamic Client Registration + PKCE).\n3. Validates the Bearer access token on each request via the auth server's\n   **token introspection** endpoint, resolving it to the user's Gainium\n   `(apiKey, apiSecret)` and per-key restrictions (read/write, paper-only, single-bot),\n   which are still enforced server-side. Introspection results are cached briefly.\n\nThe local stdio path is unaffected by these variables.\n\n## HTTP and SSE Mode\n\nBy default, `gainium-mcp` runs over stdio for MCP clients that spawn local processes. To run it as an HTTP server instead:\n\n```bash\nexport GAINIUM_MCP_TRANSPORT=http\nexport GAINIUM_MCP_HOST=127.0.0.1\nexport GAINIUM_MCP_PORT=3000\nnode dist/server.js\n```\n\nWhen HTTP mode is enabled, the server exposes both transport styles:\n\n- `GET|POST|DELETE /mcp` for the current Streamable HTTP transport\n- `GET /sse` plus `POST /messages?sessionId=...` for deprecated HTTP+SSE clients\n\nThis makes one server process compatible with both modern MCP HTTP clients and older SSE-based integrations. In hosted mode, authenticate with OAuth (see [OAuth 2.1 hosted mode](#oauth-21-hosted-mode)) or, for self-hosted/legacy setups, send `X-API-Key` and `X-API-Secret` on each request.\n\n## Available Tools (17)\n\nAs of v3.0.0 the toolset is consolidated: a single tool per operation, with a\n`botType` / `dealType` / `action` discriminator instead of one tool per variant.\nEvery tool carries an MCP safety annotation — read-only tools set `readOnlyHint`,\nwrite tools set `destructiveHint`.\n\n### Bots\n\n| Tool | Access | Description |\n|---|---|---|\n| `list_bots` | read | List bots by type (`dca`, `combo`, `grid`) with filters and field selection |\n| `get_bot` | read | Get a single bot by id and type |\n| `create_bot` | write | Create a bot (`dca`, `combo`, or `grid`) |\n| `update_bot` | write | Update bot settings |\n| `clone_bot` | write | Clone a bot with optional overrides |\n| `manage_bot` | write | Lifecycle action: `start`, `stop`, `archive`, `restore`, `changePairs` |\n\n### Deals\n\n| Tool | Access | Description |\n|---|---|---|\n| `list_deals` | read | List deals by type (`dca`, `combo`, `terminal`) with filters |\n| `get_deal` | read | Get a single deal by id and type |\n| `create_deal` | write | Create a deal |\n| `update_deal` | write | Update an active deal |\n| `manage_deal` | write | Deal action: `close`, `addFunds`, `reduceFunds` |\n\n### Backtest\n\n| Tool | Access | Description |\n|---|---|---|\n| `run_backtest` | write | Run a backtest: `validate`, `estimate`, async, or sync (`request`/`requestSync` submit a job — not read-only) |\n| `backtest_info` | read | List backtest requests or get one by ID |\n\n### Discovery, Account & Market\n\n| Tool | Access | Description |\n|---|---|---|\n| `discover` | read | Schema discovery for bot types and indicators |\n| `get_account` | read | Balances, connected exchanges, supported exchanges, and global variables |\n| `get_screener` | read | Cryptocurrency screener with market metrics |\n| `manage_global_variable` | write | Global variable action: `create`, `update`, `delete` |\n\n## Field Selection\n\nAll GET endpoints support the `fields` parameter for efficient payloads:\n\n- **Presets**: `minimal`, `standard` (default), `extended`, `full`\n- **Custom**: comma-separated dot-notation fields (e.g. `_id,uuid,settings.name,profit.total`)\n\nUsing `minimal` reduces payload size by ~85%.\n\n## API Permissions\n\n- **Read-only key**: read tools only (`list_*`, `get_*`, `discover`, `backtest_info`, `get_screener`, `list_presets`)\n- **Write key**: all tools, including `create_*`, `update_*`, `clone_bot`, `manage_bot`, `manage_deal`, `manage_global_variable`, `apply_preset`, and `run_backtest`\n- **Read-only directory connector** (`/mcp` with `GAINIUM_READONLY=true`, served at `mcp.gainium.io/read`): exposes and allows only the 9 `readOnlyHint` tools — `run_backtest` and all write tools are excluded\n- **Token audience binding (OAuth mode)**: when `GAINIUM_MCP_PUBLIC_URL` is set, the server treats `<public-url><http-path>` as its RFC 8707 resource. An access token whose introspected `aud` is a *different* resource is rejected — a token minted for `mcp.gainium.io/read` can't be replayed against `mcp.gainium.io/mcp`, and vice versa. Tokens with no `aud` (legacy grants) are still accepted.\n\n## Development\n\n```bash\n# Clone and install\ngit clone https://github.com/gainium/gainium-mcp.git\ncd gainium-mcp\nnpm install\n\n# Build\nnpm run build\n\n# Run locally (for testing)\nexport GAINIUM_API_KEY=your_key\nexport GAINIUM_API_SECRET=your_secret\nnode dist/server.js\n\n# Run in HTTP/SSE mode\nexport GAINIUM_MCP_TRANSPORT=http\nexport GAINIUM_MCP_PORT=3000\nnode dist/server.js\n```\n\n## Architecture\n\n```\ngainium-mcp/\n├── src/\n│   ├── server.ts          # MCP server + tool definitions (stdio + HTTP/SSE transports)\n│   └── gainium-client.ts  # HMAC-authenticated HTTP client for Gainium API v2\n├── dist/                  # Compiled output (published to npm)\n├── package.json\n├── tsconfig.json\n└── README.md\n```\n\n## License\n\nMIT\n",
  "bytes": 9349,
  "sha": "04431447181cb8238fc2fba39c3ffbe8dcd18655996562e71b90e2c811282f1d",
  "repo_slug": "gainium/gainium-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_gainium_gainium_mcp_8e8d792f/readme"
}