QuickMythril/qortal-mcp-server
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 viainclude_assets+ optionalasset_ids) - Trades:
list_trade_offers(AT address returned astradeAddress) - 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(optionaldecode_text=truedecodes 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_overviewcurrently returns QORT balance plus names; theassetBalancesfield is intentionally left empty in v1 to avoid large payloads. Other omitted or optional endpoints (e.g., block signers, minting info) are listed inDESIGN.md.Planned: optional public-node fallback/NodePool (opt-in; defaults to local-only). See
DESIGN.mdfor policy and configuration notes. - Node:
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/assetswill 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=trueplus a comma-separatedQORTAL_PUBLIC_NODESlist (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.mdfor 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.clienthelpers - 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 fromapikey.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→ returnsprotocolVersion,serverInfo,capabilities.toolstools/listorlist_tools→ returns the tool catalogtools/callorcall_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-IDheader for tracing. - Log format can be switched to JSON with
QORTAL_MCP_LOG_FORMAT=json. Per-tool rate limits can be set in code viaper_tool_rate_limitsif desired. /metricsreturns in-process counters (requests, rate-limited counts, per-tool successes/errors); for multi-worker setups, aggregate externally.
Testing
- Unit tests:
pytest(orpytest --cov=qortal_mcp --cov=tests --cov-report=term-missingafter installingrequirements-dev.txtwhich includespytest-cov). - Live integration (requires a running Qortal node):
LIVE_QORTAL=1 pytest tests/test_live_integration.py(optionally setQORTAL_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 8000gunicorn -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.
/metricsreturns 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.