qortal-mcp-server

QuickMythril/qortal-mcp-server

3.2

If you are the rightful owner of qortal-mcp-server and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.

Qortal MCP Server is a read-only Model Context Protocol server designed to expose Qortal node and QDN data to AI agents.

Qortal MCP Server (Python)

Overview

This repository contains a read‑only Qortal MCP server implemented in Python.
It exposes a carefully curated subset of the Qortal Core HTTP API (port 12391) as LLM‑friendly tools so that agents (Codex, ChatGPT Agents, etc.) can query on‑chain and QDN data without any ability to sign or broadcast transactions.

The server runs alongside a Qortal Core node and acts as a safe, structured proxy for information such as:

  • Node status and version
  • Account / balance / name information
  • Cross‑chain Trade Portal offers
  • QDN (Qortal Data Network) search metadata
  • Group metadata (group listings, membership, invites/requests/bans)
  • Chat history metadata (messages, counts, active chats)

All write / state‑changing operations are permanently out of scope.

Status

This project is in early development.

  • v1 goal: minimal but useful tool set + stable Python server:

    • Node: get_node_status, get_node_info, get_node_summary, get_node_uptime
    • Accounts/Names: get_account_overview, get_balance, validate_address, get_name_info, get_names_by_address, get_primary_name, search_names, list_names, list_names_for_sale (QORT-only by default; bounded asset balances via include_assets + optional asset_ids)
    • Trades: list_trade_offers (AT address returned as tradeAddress)
    • Hidden trades: list_hidden_trade_offers (failed Trade Portal offers, limited)
    • QDN: search_qdn (metadata only; name/identifier included when present)
    • Chat: get_chat_messages, count_chat_messages, get_chat_message_by_signature, get_active_chats (optional decode_text=true decodes plaintext when safe)
    • Groups: list_groups, get_groups_by_owner, get_groups_by_member, get_group, get_group_members, get_group_invites_by_address, get_group_invites_by_group, get_group_join_requests, get_group_bans
    • Blocks: get_block_at_timestamp, get_block_height, get_block_by_height, get_block_by_signature, get_block_height_by_signature, get_first_block, get_last_block, list_block_summaries, list_block_range
    • Transactions: search_transactions, get_transaction_by_signature, get_transaction_by_reference, list_transactions_by_block, list_transactions_by_address, list_transactions_by_creator

    get_account_overview currently returns QORT balance plus names; the assetBalances field is intentionally left empty in v1 to avoid large payloads. Other omitted or optional endpoints (e.g., block signers, minting info) are listed in DESIGN.md.

    Planned: optional public-node fallback/NodePool (opt-in; defaults to local-only). See DESIGN.md for policy and configuration notes.

The first implementation milestone focuses only on get_node_status and get_account_overview, then expands from there.

For full details, see DESIGN.md.

Security model (short version)

  • Read‑only only – no signing, no broadcasting, no POST/PUT/DELETE calls.
  • Only a whitelisted set of GET endpoints under /admin, /addresses, /names, /crosschain/tradeoffers, /arbitrary/search, and a small subset of /assets will ever be used.
  • Tool inputs are validated (addresses, names, service codes, limits, etc.).
  • Outputs are trimmed and normalized for LLMs (no huge binary blobs, no logs, no sensitive node details).
  • The Qortal Core API key (if required) is kept server-side and never returned to callers.
  • Config is read at process startup; set QORTAL_* env vars before launching the server (restart to apply changes).

The full security model is documented in DESIGN.md and enforced via the rules in AGENTS.md.

Public node fallback (opt-in, experimental)

  • Default behavior remains single-node/local. Fallback to public nodes must be explicitly enabled.
  • Enable via env: QORTAL_ALLOW_PUBLIC_FALLBACK=true plus a comma-separated QORTAL_PUBLIC_NODES list (e.g., https://api.qortal.org). Optional tuning: QORTAL_FALLBACK_COOLDOWN_SECONDS (~30 default), QORTAL_FALLBACK_HEALTH_CHECK_PATH (default /blocks/height), QORTAL_FALLBACK_HEALTH_CHECK_TIMEOUT (default ~2s).
  • Policy: primary-first; retry another node only on network errors (connection/timeout). Any real HTTP response (including 401/4xx/5xx) stops retries. Recently failed nodes are skipped for a short cooldown (~30s default).
  • API key: only sent to the trusted local node; never forwarded to public nodes. Admin endpoints may still fail on fallback due to missing auth.
  • Trust note: public nodes change the trust model for read-only data; enable only if you accept that tradeoff. See DESIGN.md for details.

High-level architecture

  • Python 3.11+

  • HTTP server: FastAPI + Uvicorn (or equivalent ASGI server)

  • HTTP client to Qortal: httpx

  • Internal layout (subject to refinement):

    qortal_mcp/
      __init__.py
      config.py           # base URL, API key path, timeouts, limits
      qortal_api/
        __init__.py
        client.py         # thin wrappers around whitelisted Qortal HTTP endpoints
      tools/
        __init__.py
        node.py           # node status / info tools
        account.py        # account + balance + names tools
        names.py          # name system helpers
        trade.py          # Trade Portal tools
        qdn.py            # QDN / arbitrary search tools
      server.py           # FastAPI app wiring tools to HTTP routes or MCP interface
    

Each tool function is responsible for:

  • Validating inputs
  • Calling one or more qortal_api.client helpers
  • Mapping raw Qortal responses into compact JSON results for LLMs
  • Handling and normalizing errors

See DESIGN.md for specifics on each tool and its underlying Qortal endpoint(s).

Requirements

  • Python 3.11+
  • A running Qortal Core node with the HTTP API enabled (default http://localhost:12391)
  • If your Core requires an API key for /admin/* endpoints, ensure the MCP server can read it (for example from apikey.txt, or environment).

Quick start (once implementation exists)

# 1. Clone the repo
git clone https://github.com/<your-user-or-org>/qortal-mcp-python.git
cd qortal-mcp-python

# 2. Create a virtualenv and install dependencies
python -m venv .venv
source .venv/bin/activate  # Windows: .venv\\Scripts\\activate
pip install -r requirements.txt

# 3. Configure Qortal Core connection (defaults usually OK)
#    e.g. edit config file or set environment variables as described in DESIGN.md

# 4. Run the server (example – adjust module/path once implemented)
uvicorn qortal_mcp.server:app --reload

# (Optional) Quick sanity check against your local Core node
# Override QORTAL_SAMPLE_ADDRESS to another on-chain address if desired.
python scripts/sanity_check.py

# (Optional) Run unit tests
pip install -r requirements-dev.txt
pytest

# (Optional) Live integration tests (require a running Core node)
# Set LIVE_QORTAL=1 and optionally QORTAL_SAMPLE_ADDRESS / QORTAL_SAMPLE_NAME
LIVE_QORTAL=1 pytest tests/test_live_integration.py

## HTTP usage examples

With the server running (default `http://localhost:8000`):

```bash
# Health
curl http://localhost:8000/health

# Metrics snapshot
curl http://localhost:8000/metrics

# Node status
curl http://localhost:8000/tools/node_status

# Account overview
curl http://localhost:8000/tools/account_overview/QgB7zMfujQMLkisp1Lc8PBkVYs75sYB3vV

# Validate address (no Core call)
curl http://localhost:8000/tools/validate_address/QgB7zMfujQMLkisp1Lc8PBkVYs75sYB3vV

# Name info
curl http://localhost:8000/tools/name_info/AGAPE

# Trade offers (limit=3)
curl "http://localhost:8000/tools/trade_offers?limit=3"

# Groups (list first 5)
curl "http://localhost:8000/tools/groups?limit=5"

# Group detail + members
curl "http://localhost:8000/tools/group/1"
curl "http://localhost:8000/tools/group/1/members?limit=10"

# Chat (messages between two addresses)
curl "http://localhost:8000/tools/chat/messages?involving=Qaddress1&involving=Qaddress2&limit=5"

# Chat with decoded plaintext (when not encrypted)
curl "http://localhost:8000/tools/chat/messages?involving=Qaddress1&involving=Qaddress2&limit=5&decode_text=true"

# Hidden trade offers (limit=3)
curl "http://localhost:8000/tools/hidden_trade_offers?limit=3"

# Account overview with bounded assets
curl "http://localhost:8000/tools/account_overview/QgB7zMfujQMLkisp1Lc8PBkVYs75sYB3vV?include_assets=true&asset_ids=1&asset_ids=2"

MCP integration (initialize + tools)

The MCP gateway lives at POST /mcp and supports the MCP initialize handshake plus standard tool methods.

  • Protocol version: 2025-03-26 (echoed back to the client)
  • Supported methods:
    • initialize → returns protocolVersion, serverInfo, capabilities.tools
    • tools/list or list_tools → returns the tool catalog
    • tools/call or call_tool → call a tool by name

Example initialize call for debugging:

curl -sS -X POST http://127.0.0.1:8000/mcp \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-03-26",
      "capabilities": {},
      "clientInfo": {
        "name": "debug-client",
        "version": "0.0.1"
      }
    }
  }'

Tool calls (post-initialize):

{"jsonrpc": "2.0", "id": 2, "method": "tools/list"}
{"jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": {"name": "validate_address", "arguments": {"address": "Q..."}}}

Tool responses include a content array with a text item plus a structuredContent copy of the JSON result. Tool execution errors set isError: true and return the message as text content. Protocol-level failures use the JSON-RPC error field.

Manifest: mcp-manifest.json points at http://localhost:8000/mcp with name qortal-mcp-server and version 0.1.0. Update the endpoint for remote usage.

Notes on rate limits and logging

  • A simple per-tool rate limiter (token bucket) defaults to ~5 requests/second per tool to protect the underlying Qortal node. Adjust via QortalConfig.rate_limit_qps.
  • Logging is minimal and avoids secrets. Adjust log level via QORTAL_MCP_LOG_LEVEL.
  • Responses include an X-Request-ID header for tracing.
  • Log format can be switched to JSON with QORTAL_MCP_LOG_FORMAT=json. Per-tool rate limits can be set in code via per_tool_rate_limits if desired.
  • /metrics returns in-process counters (requests, rate-limited counts, per-tool successes/errors); for multi-worker setups, aggregate externally.

Testing

  • Unit tests: pytest (or pytest --cov=qortal_mcp --cov=tests --cov-report=term-missing after installing requirements-dev.txt which includes pytest-cov).
  • Live integration (requires a running Qortal node): LIVE_QORTAL=1 pytest tests/test_live_integration.py (optionally set QORTAL_SAMPLE_ADDRESS / QORTAL_SAMPLE_NAME).

Deployment notes

  • Run with uvicorn or gunicorn+uvicorn workers, e.g.:
    • uvicorn qortal_mcp.server:app --host 0.0.0.0 --port 8000
    • gunicorn -k uvicorn.workers.UvicornWorker -w 2 qortal_mcp.server:app
  • Rate limits and metrics are per-process; if you run multiple workers or behind a reverse proxy, consider external aggregation and/or adjust per_tool_rate_limits.
  • Terminate TLS at a reverse proxy (nginx/caddy/traefik) and restrict access to trusted clients if exposing beyond localhost.
  • /metrics returns in-process counters (requests, rate-limited counts, per-tool successes/errors).

Once running, the server can be wired into your LLM tooling as an MCP server or
as an HTTP tool host, depending on your integration.

### Available tool routes (v1)

- `GET /health`
- `GET /metrics`
- `GET /tools/node_status`
- `GET /tools/node_info`
- `GET /tools/account_overview/{address}`
- `GET /tools/balance/{address}?assetId=0`
- `GET /tools/validate_address/{address}`
- `GET /tools/name_info/{name}`
- `GET /tools/names_by_address/{address}?limit=...`
- `GET /tools/trade_offers?limit=...`
- `GET /tools/qdn_search?address=...&service=...&limit=...`

## Roadmap (short)

1. **Milestone 1**
   - Project skeleton
   - `qortal_api.client`
   - `get_node_status`, `get_account_overview`
2. **Milestone 2**
   - Remaining v1 tools (`get_node_info`, `get_name_info`, etc.)
   - More robust error handling, logging, and tests
3. **Milestone 3**
   - Example agent / MCP integration configs
   - Optional extended tools (DEX views, QDN convenience tools)

See **`DESIGN.md`** for the current authoritative plan.