# Blurt MCP Server β full LLM context
Generated from repository source. Do not edit by hand.
This file is generated from canonical repository Markdown sources. Do not edit it by hand.
Primary public documentation: https://mcp.blurt-blockchain.com/
MCP endpoint: https://mcp.blurt-blockchain.com/mcp
Source repository: https://gitlab.com/blurt-blockchain/blurt-mcp-server
## Source index
- README: README.md (https://mcp.blurt-blockchain.com/)
- Site overview: docs/index.md (https://mcp.blurt-blockchain.com/)
- Installation and usage: docs/usage.md (https://mcp.blurt-blockchain.com/usage.html)
- Install snippets: docs/install-snippets.md (https://mcp.blurt-blockchain.com/install-snippets.html)
- Compatible clients: docs/clients.md (https://mcp.blurt-blockchain.com/clients.html)
- Tools and resources: docs/tools.md (https://mcp.blurt-blockchain.com/tools.html)
- Generated tool reference: docs/tools.generated.md (https://mcp.blurt-blockchain.com/tools.generated.html)
- Write operations: docs/write-operations.md (https://mcp.blurt-blockchain.com/write-operations.html)
- Security guide: docs/security.md (https://mcp.blurt-blockchain.com/security.html)
- Deployment overview: docs/deployment.md (https://mcp.blurt-blockchain.com/deployment.html)
- PM2 deployment: docs/deployment-pm2.md (https://mcp.blurt-blockchain.com/deployment-pm2.html)
- Operations: docs/operations.md (https://mcp.blurt-blockchain.com/operations.html)
- Cache policy: docs/cache-policy.md (https://mcp.blurt-blockchain.com/cache-policy.html)
- Load checks: docs/load-testing.md (https://mcp.blurt-blockchain.com/load-testing.html)
- Architecture: docs/architecture.md (https://mcp.blurt-blockchain.com/architecture.html)
- MCP compatibility register: docs/mcp-compatibility-register.md (https://mcp.blurt-blockchain.com/mcp-compatibility-register.html)
- Neutral infrastructure ADR: docs/adr/0001-neutral-infrastructure.md (https://mcp.blurt-blockchain.com/adr/0001-neutral-infrastructure.html)
- Development: docs/development.md (https://mcp.blurt-blockchain.com/development.html)
- Release/provenance: docs/release-provenance.md (https://mcp.blurt-blockchain.com/release-provenance.html)
- Final engineering review baseline: architecture/FINAL_REVIEW.md (https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/blob/main/architecture/FINAL_REVIEW.md)
- Security policy: SECURITY.md (https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/blob/main/SECURITY.md)
- Contributing: CONTRIBUTING.md (https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/blob/main/CONTRIBUTING.md)
---
# README
Source: README.md
Canonical URL: https://mcp.blurt-blockchain.com/
# blurt-mcp-server
[](https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/pipelines)
[](https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/blob/main/LICENSE)
[](https://mcp.blurt-blockchain.com/usage.html#requirements)
**Talk to the [Blurt blockchain](https://blurt.blog) from an AI assistant.**
`blurt-mcp-server` is a [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server for the Blurt blockchain. It gives MCP-capable assistants such as Claude, ChatGPT, Cursor, Codex and other tools a safe way to read public Blurt blockchain data: accounts, posts, communities, witnesses, curation data, notifications and market information.
The public hosted endpoint is **read-only by default**. It holds no private keys and cannot post, vote, transfer, or change on-chain state.
> π’ **Try it in 30 seconds β nothing to install.** Add this hosted endpoint as a custom/remote MCP connector in your AI app:
>
> ```text
> https://mcp.blurt-blockchain.com/mcp
> ```
## Who is this for?
- **Blurt blockchain users and community members** who want to ask natural-language questions about accounts, posts, communities, witnesses and rewards.
- **Witnesses and ecosystem maintainers** who want a quick read-only view of network health, witness status, curation and public activity.
- **AI-assistant users** who want their assistant to understand Blurt blockchain data without copying URLs or JSON by hand.
- **Developers and operators** who want to self-host, inspect, extend or integrate an MCP server for the Blurt blockchain.
If you already know MCP, this package gives you a ready-to-use Blurt blockchain connector. If you are new to MCP, think of it as a standard way for an AI assistant to call well-described tools instead of scraping webpages or guessing API calls.
## What you can ask
You never need to name a tool. Ask a normal question and let the AI assistant choose the right tool or chain of tools:
- *"What is the Blurt blockchain's market cap and how many BLURT are in circulation?"*
- *"Analyze the account `nalexadre`: profile, vote value in USD, followers and latest posts."*
- *"Find a community about cats and show me its details."*
- *"List the top 10 Blurt blockchain witnesses and flag any that look inactive or behind on version."*
- *"Who are the biggest curators on this post, and how much is each of their upvotes worth?"*
β More examples and the read-tool reference: **[Tools & resources](https://mcp.blurt-blockchain.com/tools.html)**.
## What it can do
| Area | Examples |
| --- | --- |
| π€ **Accounts & wallets** | profiles, balances, Blurt Power, operation history, rewards, pending rewards, relationships, delegations, account lookup |
| βοΈ **Content** | individual posts, full discussion trees, account posts, trending/ranked publications |
| π **Communities** | discovery, details, subscriptions and roles |
| π± **Onboarding** | referrals from the beBlurt referral system |
| π
**Curation** | post voters and rebloggers, vote-value estimates in BLURT and USD |
| π **Notifications** | recent notifications and unread counts |
| ποΈ **Governance** | witness ranking, witness health and account witness votes |
| π° **Market & network** | BLURT price, market cap, supply, reward pool and chain status |
| π **Search / fetch** | `blurt://` resource discovery for connector-style clients |
| βοΈ **Write** *(opt-in, local by default)* | claim, vote, comment, post and social actions signed locally with a posting key; see [write operations](https://mcp.blurt-blockchain.com/write-operations.html) |
## Quick start
### 1. Hosted endpoint
Use this when your AI app supports remote MCP / Streamable HTTP connectors:
```text
https://mcp.blurt-blockchain.com/mcp
```
### 2. Desktop app through a bridge
Some desktop apps only launch local commands. In that case, bridge the hosted endpoint with `mcp-remote`:
```json
{
"mcpServers": {
"blurt": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.blurt-blockchain.com/mcp"]
}
}
}
```
### 3. Fully local stdio server
Use this when your client launches a local MCP server process:
```bash
npx -y -p @blurt-blockchain/blurt-mcp-server blurt-mcp-stdio
```
For client configuration, prefer the same environment-file layout used by write mode, even for read-only usage:
```json
{
"mcpServers": {
"blurt": {
"command": "npx",
"args": ["-y", "-p", "@blurt-blockchain/blurt-mcp-server", "blurt-mcp-stdio"],
"env": { "BLURT_ENV_FILE": "/home/you/.config/blurt-mcp/secret.env" }
}
}
}
```
The file can start empty or contain read-only configuration such as `BLURT_RPC_URLS` and `BLURT_PRICE_URL`. Add a posting key only if you deliberately enable local write tools.
β Full setup guide: **[Installation & usage](https://mcp.blurt-blockchain.com/usage.html)**
β Copy-paste client configs: **[Install snippets](https://mcp.blurt-blockchain.com/install-snippets.html)**.
## Compatible clients
Remote-capable clients can use the hosted endpoint directly. Stdio-only clients can either bridge the hosted endpoint with `mcp-remote` or run the package locally.
| Client | Type | Local stdio | Remote HTTP | Config file | Open source |
| --- | --- | ---: | ---: | --- | ---: |
| ChatGPT web β Apps / Connectors | Web | No | Yes | UI only | No |
| Claude Desktop | Desktop | Yes | Yes | `claude_desktop_config.json` | No |
| Claude Code | CLI | Yes | Yes | `~/.claude.json`, `.mcp.json` | No |
| OpenAI Codex (CLI / IDE) | CLI / IDE | Yes | Yes | `~/.codex/config.toml` | Yes |
| VS Code β Copilot agent | IDE | Yes | Yes | `.vscode/mcp.json` | Partial |
| Cursor | IDE | Yes | Yes | `.cursor/mcp.json` | No |
| Windsurf / Cascade | IDE | Yes | Yes | `mcp_config.json` | No |
| Gemini CLI | CLI | Yes | Yes | `~/.gemini/settings.json` | Yes |
| JetBrains AI Assistant | IDE | Yes | Yes | Settings UI | No |
| Cline | IDE ext. / CLI | Yes | Yes | `~/.cline/mcp.json` | Yes |
β Full compatibility matrix: **[Compatible clients](https://mcp.blurt-blockchain.com/clients.html)**. *(Community-maintained; as of 2026-06-28.)*
## Documentation
- [Overview](https://mcp.blurt-blockchain.com/) β start here if you are new to the project
- [Installation & usage](https://mcp.blurt-blockchain.com/usage.html) β requirements, configuration and connection modes
- [Install snippets](https://mcp.blurt-blockchain.com/install-snippets.html) β copy-paste hosted, package, stdio and client configs
- [Tools & resources](https://mcp.blurt-blockchain.com/tools.html) β readable tool categories and example prompts
- [Generated tool reference](https://mcp.blurt-blockchain.com/tools.generated.html) β generated contract index from the tool registry
- [Write operations](https://mcp.blurt-blockchain.com/write-operations.html) β opt-in local signing with a posting key
- [Compatible clients](https://mcp.blurt-blockchain.com/clients.html) β client compatibility notes
- [Architecture](https://mcp.blurt-blockchain.com/architecture.html), [MCP compatibility register](https://mcp.blurt-blockchain.com/mcp-compatibility-register.html), [Deployment](https://mcp.blurt-blockchain.com/deployment.html), [Operations](https://mcp.blurt-blockchain.com/operations.html)
- [Security](https://mcp.blurt-blockchain.com/security.html) Β· [Contributing](https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/blob/main/CONTRIBUTING.md)
## Security
The server is **read-only by default** and holds **no private keys**. Optional write tools are **opt-in and local by default**, use a **posting key only** and are not exposed over HTTP unless an operator deliberately enables an unsafe trusted-deployment override.
New write deployments should start with a small capability profile such as `BLURT_WRITE_PROFILE=curator`. See the [security guide](https://mcp.blurt-blockchain.com/security.html) and [write operations](https://mcp.blurt-blockchain.com/write-operations.html).
## Support
You can contact the maintainer in the `dev` channel of the Blurt Discord server: .
Useful Blurt blockchain development posts can also be found in the [Dev on Blurt community](https://beblurt.com/community/blurt-101010).
## Contributing
Pull requests for new features, bug fixes and documentation improvements are welcome.
Before opening a pull request, run the checks that match your change. For most code changes:
```bash
npm ci
npm run docs:check
npm run build
npm test
npm run typecheck
```
See [CONTRIBUTING.md](https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/blob/main/CONTRIBUTING.md) for the development workflow.
## Author
[@nalexadre](https://beblurt.com/@nalexadre) β Blurt blockchain witness.
## License
This package currently declares `GPL-3.0-or-later` in `package.json`.
See the [LICENSE file](https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/blob/main/LICENSE) for the full license text.
---
# Site overview
Source: docs/index.md
Canonical URL: https://mcp.blurt-blockchain.com/
# Blurt MCP Server
The Blurt MCP server connects AI assistants to public Blurt blockchain data.
It uses the Model Context Protocol TypeScript SDK and supports MCP clients negotiating protocol version
`2025-06-18` for its implemented tools and resource-template features. See the
[MCP compatibility register](./mcp-compatibility-register.md) for the maintained compatibility decisions.
If you are new to MCP, think of it as a standard bridge between an AI assistant and a set of well-described tools. Instead of asking the assistant to guess where data lives, MCP tells the assistant which tools are available, what each one does, and what information it needs.
For the Blurt blockchain, that means an assistant can answer questions about accounts, posts, communities, witnesses, rewards, curation and market data without you manually copying API responses or blockchain explorer pages.
## Who is this for?
- **People discovering the Blurt blockchain** who want a conversational way to explore public activity.
- **Blurt blockchain users and community members** who want quick answers about posts, communities, rewards or witnesses.
- **Witnesses and operators** who want a readable view of network status and public endpoint behavior.
- **Developers and maintainers** who want to self-host, inspect or extend the MCP server.
- **AI assistant users** who want their assistant to use Blurt blockchain data safely and predictably.
## Why it exists
Public blockchain data is useful, but it is not always convenient for humans or AI assistants to navigate directly. This project gives the Blurt blockchain ecosystem a focused MCP interface that is:
- **read-only by default** for the hosted public endpoint;
- **plain-language friendly**, because users ask questions instead of choosing tools by hand;
- **transparent**, because the tools, safety posture and configuration are documented;
- **self-hostable**, because operators can run the same package locally or behind their own HTTP endpoint;
- **neutral infrastructure**, because it does not enforce content, account, community or social policy.
## Fastest path
Use the hosted public endpoint when your client supports remote MCP / Streamable HTTP:
```text
https://mcp.blurt-blockchain.com/mcp
```
Use the npm package when your client launches a local stdio server:
```bash
npx -y -p @blurt-blockchain/blurt-mcp-server blurt-mcp-stdio
```
## Documentation map
### Start
- [Installation & usage](./usage.md) β concepts first, then setup choices
- [Install snippets](./install-snippets.md) β copy-paste client configuration
- [Compatible clients](./clients.md) β client support and known config locations
### Reference
- [Tools & resources](./tools.md) β readable tool categories and examples
- [Generated tool reference](./tools.generated.md) β generated contract index from the tool registry
- [Write operations](./write-operations.md) β optional local signing with a posting key
- [Security](./security.md) β security model and threat posture
### Operate
- [Deployment overview](./deployment.md) β HTTP surface, topology, reverse proxy guidance and deployment method choices
- [PM2 deployment](./deployment-pm2.md) β process-manager setup using `BLURT_ENV_FILE`
- [Operations](./operations.md)
- [Cache policy](./cache-policy.md)
- [Load checks](./load-testing.md)
### Maintain
- [Architecture](./architecture.md)
- [MCP compatibility register](./mcp-compatibility-register.md)
- [ADR 0001 β neutral infrastructure](./adr/0001-neutral-infrastructure.md)
- [Development](./development.md)
- [Release/provenance](./release-provenance.md)
## Source and package
- GitLab source:
- npm package:
---
# Installation and usage
Source: docs/usage.md
Canonical URL: https://mcp.blurt-blockchain.com/usage.html
# Installation & usage
This page explains the main ways to connect an AI assistant to the Blurt blockchain through MCP.
If you are new to MCP, there are two common connection styles:
- **Remote HTTP** β your AI app connects to an MCP URL such as `https://mcp.blurt-blockchain.com/mcp`.
- **Local stdio** β your AI app launches a command on your computer. The command speaks MCP through standard input/output.
Use the hosted endpoint when you want the quickest read-only setup. Use the local package when your client requires stdio, when you want to choose your own Blurt blockchain RPC nodes, or when you later want opt-in local signing.
## Requirements
- Node.js **>= 18** to run the server or package.
- Node.js **>= 20.6** for development and tests.
- npm.
## Installation choices
### Hosted endpoint β no install
Use this when your AI client supports remote MCP / Streamable HTTP:
```text
https://mcp.blurt-blockchain.com/mcp
```
The hosted endpoint is anonymous and read-only. It does not need a private key.
### Local stdio package
Use this when your client launches a local MCP server process:
```bash
npx -y -p @blurt-blockchain/blurt-mcp-server blurt-mcp-stdio
```
For client configuration, prefer using an environment file from the beginning. It gives read-only and write-capable setups the same layout, while keeping secrets out of JSON configs:
```json
{
"mcpServers": {
"blurt": {
"command": "npx",
"args": ["-y", "-p", "@blurt-blockchain/blurt-mcp-server", "blurt-mcp-stdio"],
"env": { "BLURT_ENV_FILE": "/home/you/.config/blurt-mcp/secret.env" }
}
}
}
```
The file may be empty for default read-only usage. Add read-only options such as `BLURT_RPC_URLS` if you want custom RPC nodes. Add a posting key only when you deliberately enable local write tools.
### Source checkout
Use this when you want to develop or inspect the project from source:
```bash
npm install
npm run build
```
Then point your client at the compiled stdio entrypoint:
```json
{
"mcpServers": {
"blurt": {
"command": "node",
"args": ["/absolute/path/to/blurt-mcp-server/dist/server-stdio.js"],
"env": { "BLURT_ENV_FILE": "/home/you/.config/blurt-mcp/secret.env" }
}
}
}
```
For per-client examples, see [install snippets](./install-snippets.md).
## Configuration
Configuration is read from environment variables. Local stdio users should normally put them in a file outside the repository and point the launcher at it with `BLURT_ENV_FILE`.
Example read-only file:
```dotenv
# /home/you/.config/blurt-mcp/secret.env
# Optional: choose several Blurt blockchain RPC nodes.
BLURT_RPC_URLS=https://rpc.blurt.world,https://blurt-rpc.saboin.com
# Optional: enable price-dependent tools.
BLURT_PRICE_URL=https://api.blurt.blog/price_info
```
| Variable | Default / behavior when unset | Description |
| --- | --- | --- |
| `PORT` | `3000` | HTTP port Express listens on. |
| `BLURT_RPC_URLS` | unset; RPC-backed tools unavailable | Comma-separated Blurt blockchain RPC endpoints. The MCP server does not hardcode a maintained node list. Provide several when self-hosting: the server scores them with [`@beblurt/blurt-nodes-checker`](https://gitlab.com/beblurt/blurt-nodes-checker) and keeps the client on healthy nodes. |
| `BLURT_RPC_TIMEOUT_MS` | inherited from `@beblurt/dblurt` | Optional RPC call timeout for the dblurt client. |
| `BLURT_RPC_FAILOVER_THRESHOLD` | inherited from `@beblurt/dblurt` | Optional number of failover rounds for the dblurt client. |
| `BLURT_NODE_CHECKER_*` | inherited from `@beblurt/blurt-nodes-checker` | Optional node-checker timeout, interval, retry, stale-block and history settings. See `.env.example` for exact names and units. |
| `BLURT_PRICE_URL` | unset; price tools unavailable | Price feed used by price and market tools. Configure it explicitly for deployments that expose those tools. |
| `BLURT_PRICE_CACHE_TTL_MS` | no MCP-layer cache | Optional in-memory cache duration for the configured price feed. |
| `BLURT_PRICE_TIMEOUT_MS` | no MCP-layer fetch timeout | Optional timeout for the configured price feed request. |
| `BLURT_HTTP_JSON_BODY_LIMIT` | Express default | Optional JSON request-body limit for HTTP deployments. |
| `HOST` | Node/OS default bind behavior | Optional HTTP bind host. Use `127.0.0.1` when the MCP server runs behind a local reverse proxy; use `0.0.0.0` only when the platform network boundary is trusted. |
| `LOG_LEVEL` | `info` | `debug` \| `info` \| `warn` \| `error`. |
| `NODE_ENV` | `development` | `production` switches logs to JSON output. |
| `BLURT_CHAIN_ID` | Blurt blockchain mainnet | Optional testnet chain id; set together with `BLURT_ADDRESS_PREFIX`. |
| `BLURT_ADDRESS_PREFIX` | mainnet `BLT` | Optional testnet address prefix; set together with `BLURT_CHAIN_ID`. |
Write-related variables (`BLURT_ACCOUNT`, `BLURT_POSTING_KEY`, `BLURT_WRITE_PROFILE`, `BLURT_WRITE_TOOLS_BANNED`, `BLURT_DRY_RUN_DEFAULT`, `BLURT_WRITE_RATE_LIMITS`) are explained in [write operations](./write-operations.md).
## Running your own HTTP server
Use this when you want to self-host a remote MCP endpoint:
```bash
npm run build
npm start
```
The server listens on:
```text
http://localhost:/mcp
```
It also exposes simple operational probes outside MCP:
- `GET /healthz` β process liveness;
- `GET /readyz` β readiness with non-sensitive RPC readiness counters.
Deploy HTTP behind a reverse proxy such as nginx, Caddy or Traefik. Let the proxy handle TLS, rate limiting and host/origin filtering. Do not expose signing over HTTP unless you have deliberately enabled the unsafe trusted-deployment override described in [write operations](./write-operations.md#advanced-unsafe-http-signing-for-trusted-deployments).
## Connecting an MCP client
Remote-capable clients can use the hosted endpoint or your own `/mcp` URL directly.
Desktop clients that only support local commands can bridge the hosted endpoint with [`mcp-remote`](https://www.npmjs.com/package/mcp-remote):
```json
{
"mcpServers": {
"blurt": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.blurt-blockchain.com/mcp"]
}
}
}
```
For local stdio, use the package-bin example above. Logs go to `stderr` so they do not interfere with the MCP protocol on `stdout`.
## Optional local signing
Local signing lets an AI assistant ask to claim rewards, vote, comment or perform other posting-key actions. It is off by default and uses a Blurt blockchain posting key only. Start with [write operations](./write-operations.md) before adding any key.
---
# Install snippets
Source: docs/install-snippets.md
Canonical URL: https://mcp.blurt-blockchain.com/install-snippets.html
# Install snippets
This page is for copy-paste configuration after you have chosen a connection style in [Installation & usage](./usage.md).
## Client snippets
### Claude Desktop
Hosted endpoint through `mcp-remote`:
```json
{
"mcpServers": {
"blurt": {
"command": "npx",
"args": ["-y", "mcp-remote", "https://mcp.blurt-blockchain.com/mcp"]
}
}
}
```
Fully local stdio package:
```json
{
"mcpServers": {
"blurt": {
"command": "npx",
"args": ["-y", "-p", "@blurt-blockchain/blurt-mcp-server", "blurt-mcp-stdio"],
"env": { "BLURT_ENV_FILE": "/home/you/.config/blurt-mcp/secret.env" }
}
}
}
```
### Claude Code
Remote HTTP:
```bash
claude mcp add --transport http blurt https://mcp.blurt-blockchain.com/mcp
```
Local stdio in `.mcp.json`:
```json
{
"mcpServers": {
"blurt": {
"command": "npx",
"args": ["-y", "-p", "@blurt-blockchain/blurt-mcp-server", "blurt-mcp-stdio"],
"env": { "BLURT_ENV_FILE": "/home/you/.config/blurt-mcp/secret.env" }
}
}
}
```
### OpenAI Codex
Remote HTTP in `~/.codex/config.toml`:
```toml
[mcp_servers.blurt]
url = "https://mcp.blurt-blockchain.com/mcp"
```
Local stdio:
```toml
[mcp_servers.blurt]
command = "npx"
args = ["-y", "-p", "@blurt-blockchain/blurt-mcp-server", "blurt-mcp-stdio"]
[mcp_servers.blurt.env]
BLURT_ENV_FILE = "/home/you/.config/blurt-mcp/secret.env"
```
### VS Code / GitHub Copilot agent
`.vscode/mcp.json` using hosted HTTP:
```json
{
"servers": {
"blurt": {
"type": "http",
"url": "https://mcp.blurt-blockchain.com/mcp"
}
}
}
```
Local stdio:
```json
{
"servers": {
"blurt": {
"type": "stdio",
"command": "npx",
"args": ["-y", "-p", "@blurt-blockchain/blurt-mcp-server", "blurt-mcp-stdio"],
"env": { "BLURT_ENV_FILE": "/home/you/.config/blurt-mcp/secret.env" }
}
}
}
```
### Cursor
`.cursor/mcp.json` using hosted HTTP:
```json
{
"mcpServers": {
"blurt": {
"url": "https://mcp.blurt-blockchain.com/mcp"
}
}
}
```
Local stdio:
```json
{
"mcpServers": {
"blurt": {
"command": "npx",
"args": ["-y", "-p", "@blurt-blockchain/blurt-mcp-server", "blurt-mcp-stdio"],
"env": { "BLURT_ENV_FILE": "/home/you/.config/blurt-mcp/secret.env" }
}
}
}
```
### Gemini CLI
Hosted HTTP:
```bash
gemini mcp add blurt https://mcp.blurt-blockchain.com/mcp
```
Local stdio in `~/.gemini/settings.json`:
```json
{
"mcpServers": {
"blurt": {
"command": "npx",
"args": ["-y", "-p", "@blurt-blockchain/blurt-mcp-server", "blurt-mcp-stdio"],
"env": { "BLURT_ENV_FILE": "/home/you/.config/blurt-mcp/secret.env" }
}
}
}
```
### Hermes Agent
`~/.hermes/config.yaml` example for hosted HTTP:
```yaml
mcp_servers:
blurt:
url: https://mcp.blurt-blockchain.com/mcp
```
Local stdio:
```yaml
mcp_servers:
blurt:
command: npx
args: ["-y", "-p", "@blurt-blockchain/blurt-mcp-server", "blurt-mcp-stdio"]
env:
BLURT_ENV_FILE: /home/you/.config/blurt-mcp/secret.env
```
### Open WebUI / LibreChat
Use the hosted Streamable HTTP endpoint where the admin UI or configuration accepts remote MCP servers:
```text
https://mcp.blurt-blockchain.com/mcp
```
For LibreChat-style YAML configurations, the exact schema depends on the deployed version. Prefer the client's current MCP documentation and use the hosted URL above or a self-hosted `/mcp` URL.
## Write tools
Write tools are not exposed by the public hosted endpoint. For local signing, configure the stdio package entrypoint and follow [write operations](./write-operations.md). Use a posting key only.
---
# Compatible clients
Source: docs/clients.md
Canonical URL: https://mcp.blurt-blockchain.com/clients.html
# MCP client compatibility
How to connect AI clients to this server. **"Remote HTTP"** means native MCP Streamable HTTP or legacy
HTTP+SSE β those clients can use the hosted endpoint `https://mcp.blurt-blockchain.com/mcp` directly.
Clients that only speak **stdio** can still reach a remote server through the
[`mcp-remote`](https://www.npmjs.com/package/mcp-remote) bridge, or run the local stdio build.
> The 10 most relevant clients are summarised in the [README](https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/blob/main/README.md#compatible-clients). This
> page lists the additional clients, full config-file paths, and the sources for **both** tables.
> For copy-paste hosted/package snippets, see [install snippets](./install-snippets.md).
>
> This matrix is community-maintained and clients evolve fast β corrections welcome. **Information
> current as of 2026-06-28.**
## Highlighted clients (top 10) β full detail
| Client | Type | Local (stdio) | Remote (HTTP) | Config file | Open source | Notes |
| --- | --- | ---: | ---: | --- | ---: | --- |
| ChatGPT web β Apps / Connectors | Web | No | Yes | UI only; no config file documented | No | Remote MCP over HTTPS; local dev requires a tunnel; Developer Mode / workspace limits. [1] |
| Claude Desktop | Desktop app | Yes | Yes | `claude_desktop_config.json` (macOS `~/Library/Application Support/Claude/`, Windows `%APPDATA%\Claude\`) | No | Local stdio via config; remote via custom connectors. [2] |
| Claude Code | CLI | Yes | Yes | `~/.claude.json`; project `.mcp.json` | No | Supports `stdio`, `http`, `sse`; project config can be shared. [3] |
| OpenAI Codex β CLI / IDE extension | CLI / IDE | Yes | Yes | `~/.codex/config.toml`; project `.codex/config.toml` | Yes | MCP in CLI and IDE extension; local stdio + Streamable HTTP. [4] |
| VS Code β GitHub Copilot agent mode | IDE | Yes | Yes | `.vscode/mcp.json`; user profile MCP config | Partial | Tries HTTP-stream first, falls back to SSE; Copilot/agent policies may restrict. [5] |
| Cursor | IDE | Yes | Yes | `.cursor/mcp.json`; `~/.cursor/mcp.json` | No | Supports `stdio`, SSE, Streamable HTTP; Team/Enterprise admin controls. [6] |
| Windsurf / Cascade / Devin Desktop | IDE | Yes | Yes | `mcp_config.json` (Codeium/Windsurf paths) | No | Supports stdio, Streamable HTTP, SSE; enterprise policy may restrict. [7] |
| Gemini CLI | CLI | Yes | Yes | `~/.gemini/settings.json`; project `.gemini/settings.json` | Yes | Supports stdio, SSE, Streamable HTTP; `gemini mcp add`. [8] |
| JetBrains AI Assistant | IDE | Yes | Yes | Settings β Tools β AI Assistant β MCP (file path Unknown) | No | MCP in JetBrains IDEs; large user base. [9] |
| Cline | IDE extension / CLI | Yes | Yes | CLI `~/.cline/mcp.json`; extension MCP settings JSON | Yes | VS Code ecosystem client. [10] |
## Other compatible clients
| Client | Type | Local (stdio) | Remote (HTTP) | Config file | Open source | Notes |
| --- | --- | ---: | ---: | --- | ---: | --- |
| GitHub Copilot CLI | CLI | Yes | Yes | `~/.copilot/mcp-config.json` | Unknown | Local and remote HTTP examples documented; Copilot subscription/policies apply. [11] |
| Visual Studio β GitHub Copilot agent mode | IDE | Yes | Yes | `.mcp.json`, `.vs/mcp.json`, `.vscode/mcp.json` (by scope) | Partial | Separate from VS Code; Windows/.NET audience. [12] |
| ChatGPT Desktop app | Desktop app | Unknown | Unknown | Unknown | No | "Work with Apps" docs are not MCP client config; document separately from ChatGPT web connectors. [13] |
| Mistral Vibe Work / former Le Chat | Web / mobile | No | Yes | UI only; no config file documented | No | "Le Chat is now Vibe"; Work custom MCP connectors require an admin and a server URL. [14] |
| Mistral Vibe Code CLI | CLI / IDE / Web | Yes | Yes | `config.toml`; project `./.vibe/config.toml`; user `~/.vibe/config.toml` | Yes | Supports `stdio`, `http`, `streamable-http`; no OAuth MCP in CLI yet. [15] |
| Hermes Agent β Nous Research | CLI / local web UI | Yes | Yes | `~/.hermes/config.yaml` | Yes | Agent runtime by Nous Research; local/self-hosted workflows. [16] |
| Google Antigravity | IDE | Yes | Yes | `~/.gemini/config/mcp_config.json` | Unknown | Agentic IDE; docs show local and remote MCP config. [17] |
| OpenClaw | CLI / Web gateway | Yes | Yes | `~/.openclaw/openclaw.json` | Yes | Personal AI assistant/gateway; MCP client registry and server. [18] |
| Zed Agent | IDE | Yes | Yes | Zed `settings.json` / `context_servers` (path varies) | Yes | MCP context servers; good dev audience. [19] |
| Roo Code | IDE extension | Yes | Yes | Global `mcp_settings.json`; project `.roo/mcp.json` | Yes | Supports STDIO, Streamable HTTP, SSE; Cline ecosystem. [20] |
| Continue | IDE extension / CLI | Yes | Yes | `.continue/mcpServers/*.yaml` or `.../mcp.json` | Yes | Agent-mode only; `stdio`, `sse`, `streamable-http`. [21] |
| LM Studio | Desktop app | Yes | Yes | `mcp.json` | No | Strong local-LLM audience; local and remote MCP since 0.3.17. [22] |
| Open WebUI | Web | No | Yes | Admin Settings β External Tools | Yes | Native MCP is Streamable HTTP only; admin-only; stdio needs a proxy. [23] |
| LibreChat | Web | Yes | Yes | `librechat.yaml` | Yes | `stdio`, `websocket`, `streamable-http`, `sse`; restart after config change. [24] |
| OpenCode | CLI / TUI | Yes | Yes | `opencode.json` / `opencode.jsonc` | Yes | Local and remote MCP under `mcp`; OAuth for remote servers. [25] |
## Sources
Covering both the README top-10 table and the tables above.
1. https://developers.openai.com/api/docs/guides/developer-mode β ChatGPT Developer mode
2. https://modelcontextprotocol.io/docs/develop/connect-local-servers β Connect to local MCP servers
3. https://code.claude.com/docs/en/mcp β Connect Claude Code to tools via MCP
4. https://developers.openai.com/codex/mcp β Model Context Protocol β Codex
5. https://code.visualstudio.com/docs/copilot/customization/mcp-servers β Add and manage MCP servers in VS Code
6. https://cursor.com/docs/mcp.md β Cursor MCP docs
7. https://docs.windsurf.com/windsurf/cascade/mcp β Cascade MCP Integration
8. https://geminicli.com/docs/tools/mcp-server/ β MCP servers with Gemini CLI
9. https://www.jetbrains.com/help/ai-assistant/mcp.html β Model Context Protocol (MCP) | AI Assistant
10. https://docs.cline.bot/mcp/mcp-overview β Cline MCP
11. https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers β Adding MCP servers for GitHub Copilot CLI
12. https://learn.microsoft.com/en-us/visualstudio/ide/mcp-servers β Use MCP Servers to Extend GitHub Copilot (Visual Studio)
13. https://help.openai.com/en/articles/12584461-developer-mode-and-mcp-apps-in-chatgpt β Developer mode and MCP apps in ChatGPT
14. https://docs.mistral.ai/vibe/overview β Vibe | Mistral Docs
15. https://docs.mistral.ai/vibe/code/cli/mcp-servers β MCP servers | Mistral Docs
16. https://hermes-agent.nousresearch.com/docs/user-guide/features/mcp β MCP | Hermes Agent
17. https://codelabs.developers.google.com/getting-started-google-antigravity β Getting Started with Google Antigravity
18. https://docs.openclaw.ai/cli/mcp β MCP - OpenClaw
19. https://zed.dev/docs/assistant/model-context-protocol β Model Context Protocol (MCP) in Zed
20. https://roocodeinc.github.io/Roo-Code/features/mcp/using-mcp-in-roo β Using MCP in Roo Code
21. https://docs.continue.dev/customize/deep-dives/mcp β Set Up MCP in Continue
22. https://lmstudio.ai/docs/app/mcp β Use MCP Servers (LM Studio)
23. https://docs.openwebui.com/features/extensibility/mcp/ β MCP | Open WebUI
24. https://www.librechat.ai/docs/configuration/librechat_yaml/object_structure/mcp_servers β MCP Servers (LibreChat)
25. https://opencode.ai/docs/mcp-servers/ β MCP servers | OpenCode
---
# Tools and resources
Source: docs/tools.md
Canonical URL: https://mcp.blurt-blockchain.com/tools.html
# Tools & resources
The server exposes **25 read-only tools** (always available) plus **opt-in write tools** (local stdio
by default; HTTP signing requires an explicit unsafe trusted-deployment override β see
[write operations](./write-operations.md)).
## Tools
| Tool | Description |
| --- | --- |
| `get-account` | Full account info: profile, wallet balances, Blurt Power, delegations, witness votes, rewards. |
| `get-account-history` | Account operation history, optionally filtered by operation type (vote, transfer, comment, β¦). |
| `get-account-posts` | Posts related to an account (blog, feed, posts, comments, replies, payout) via the Nexus L2 API. |
| `get-post` | A single post, or the full discussion tree (`with_comments=true`). |
| `get-publications` | Ranked posts (trending, hot, created, promoted, payout, β¦) via Nexus `getRankedPosts`. |
| `get-blurt-price` | Current BLURT price in USD and BTC from the public price feed. |
| `get-chain-status` | Network + market overview: head block, supply, reward fund, participation, price, market cap. |
| `list-communities` | Directory of Blurt blockchain communities (rank / new / subscribers), with search and pagination. |
| `get-community` | Details of a single community (subscribers, moderators, pending payout, β¦). |
| `get-post-votes` | Votes on a post/comment ranked by weight (rshares), for curation analysis. |
| `get-vote-value` | Estimated value of an account's upvote, in BLURT and USD, at a given weight. |
| `list-witnesses` | Top witnesses (block producers) ranked by vote weight, with missed blocks and version. |
| `get-witness` | Single witness details + a health read (vote weight, blocks behind head, enabled). |
| `get-account-witness-votes` | Which witnesses an account supports (and its proxy, if any). |
| `get-account-relationships` | Follower/following counts and a sample of each (social graph). |
| `get-pending-rewards` | Unclaimed author/curation rewards (claimable now), in BLURT and USD. |
| `get-account-subscriptions` | Communities an account is subscribed to, with its role in each. |
| `compare-accounts` | Side-by-side metrics for 2β5 accounts (BP, reach, output, earnings) in one call. |
| `get-referrals` | Accounts a referrer brought to the Blurt blockchain (beBlurt referral system), with the total count. |
| `get-account-notifications` | An account's recent notifications (mentions, replies, votes, follows, reblogs) + unread count. |
| `get-post-reblogs` | The accounts that reblogged a post, and how many (reach signal beyond votes). |
| `get-delegations` | Outgoing Blurt Power delegations of an account (per delegatee), converted to BLURT. |
| `lookup-accounts` | Autocomplete Blurt blockchain account names by prefix (alphabetical). |
| `search` | Resolve a free-form query into Blurt blockchain resource links (account, history, posts, single post). |
| `fetch` | Retrieve the raw JSON of a Blurt blockchain resource from a `blurt://β¦` URI or shorthand id. |
`search` and `fetch` follow the connector convention used by ChatGPT-style clients.
Each tool ships with a verbose, LLM-oriented description (visible in the client) explaining when to
use it, its parameters and its output β for an AI client, the description *is* the interface.
The v1-candidate contract index is generated from source-of-truth registry metadata in
[`tools.generated.md`](./tools.generated.md). Regenerate it with `npm run docs:tools` and verify it
with `npm run docs:check`.
## Write tools (opt-in, local stdio by default)
Write tools are documented in one canonical place: [write operations](./write-operations.md#canonical-write-tool-list).
That page explains which tools exist, which capability profiles expose them, what each tool broadcasts, and how `dry_run`, optional `BLURT_WRITE_RATE_LIMITS` and the unsafe HTTP override work. Keeping the detailed list in one place avoids drift between the readable overview and the security-sensitive signing guide.
## Resources
Resource templates resolvable via the `fetch` tool or a resource-aware client:
- `blurt://account/{username}`
- `blurt://history/{username}?limit=&ops=vote,comment`
- `blurt://posts/{by}/{tag}?limit=` β `by` β `trending|hot|created|promoted|payout|payout_comments|muted`
- `blurt://account-posts/{sort}/{account}?limit=` β `sort` β `blog|feed|posts|comments|replies|payout`
- `blurt://post/{author}/{permlink}?with_comments=true`
## Example prompts
You never tell the AI which tool to use β it picks and chains them. Start simple, then push.
**Market & network**
- "What is the current BLURT price in USD?"
- "What is the Blurt blockchain's market cap and how many BLURT are in circulation?"
- "Is the Blurt blockchain healthy right now?"
**Accounts & wallets**
- "Show me the account `nalexadre` and convert its BLURT balance to USD."
- "How much Blurt Power does `nalexadre` have?"
**Curation**
- "How much is a 100% upvote from `nalexadre` worth, in BLURT and USD?"
- "Who are the top 5 curators on the post `nalexadre/how-ai-can-help-curation-on-blurt-1759501073717`?"
**Communities**
- "What are the most popular Blurt blockchain communities?"
- "Find a community about photography and show me its details."
**Governance**
- "List the top 10 Blurt blockchain witnesses and flag any that look inactive or behind on version."
- "Which witnesses does `nalexadre` vote for β and are they all healthy?"
**Multi-step**
- "Give me a profile of `nalexadre`: bio, the USD value of their vote, and their latest post with its vote count."
- "Compare `nalexadre`, `megadrive` and `khrom` β stake, reach and earnings β as a table."
---
# Generated tool reference
Source: docs/tools.generated.md
Canonical URL: https://mcp.blurt-blockchain.com/tools.generated.html
# Generated tool contract reference
This file is generated from the Blurt MCP tool registry. It is the contract index for v1-candidate tool metadata: tool name, safety class, data source, cache hint, stability and short description.
Every tool result follows the standard structured-content envelope:
```ts
{
data: unknown,
meta: {
contract: "blurt-mcp.tool-result.v1",
tool: string,
sources: Array<"layer1" | "nexus" | "external" | "mixed" | "mcp">,
retrieved_at: string,
freshness: { cache: "none" | "short" | "medium" | "external", ttl_seconds: number | null },
confidence: "high" | "medium" | "low",
caveats: string[]
}
}
```
Tool-specific `data` schemas are intentionally broad in the current v1-candidate contract. They should be tightened only when the project is ready to make stronger compatibility promises.
| Tool | Title | Safety | Source | Cache | Stability | Description |
| --- | --- | --- | --- | --- | --- | --- |
| `blurt-claim-rewards` | Claim rewards locally | write-local | layer1 | none | v1-candidate | Claim pending rewards using the configured local posting key. |
| `blurt-comment` | Comment locally | write-local | layer1 | none | v1-candidate | Broadcast a local posting-key comment/reply operation. |
| `blurt-follow` | Follow locally | write-local | layer1 | none | v1-candidate | Broadcast a local posting-key follow/unfollow custom_json. |
| `blurt-mute` | Mute locally | write-local | layer1 | none | v1-candidate | Broadcast a local posting-key mute/unmute custom_json. |
| `blurt-post` | Post locally | write-local | layer1 | none | v1-candidate | Broadcast a local posting-key top-level post operation. |
| `blurt-read-notifications` | Mark notifications read locally | write-local | layer1 | none | v1-candidate | Broadcast a local posting-key notification read marker. |
| `blurt-reblog` | Reblog locally | write-local | layer1 | none | v1-candidate | Broadcast a local posting-key reblog/undo custom_json. |
| `blurt-subscribe-community` | Subscribe to community locally | write-local | layer1 | none | v1-candidate | Broadcast a local posting-key community subscription custom_json. |
| `blurt-upvote` | Upvote locally | write-local | layer1 | none | v1-candidate | Broadcast a local posting-key vote operation. |
| `compare-accounts` | Compare accounts | read | mixed | short | v1-candidate | Side-by-side account metrics for stake, reach, output and rewards. |
| `fetch` | Fetch Blurt blockchain resource | read | mixed | short | v1-candidate | Resolve a blurt:// URI or shorthand id to raw JSON. |
| `get-account` | Get account profile and wallet summary | read | mixed | short | v1-candidate | Structured account identity, wallet, stake, witness vote count and rewards summary. |
| `get-account-history` | Get raw account operation history | read | layer1 | none | v1-candidate | Recent Layer 1 operations for an account, optionally filtered by operation type. |
| `get-account-notifications` | Get notifications | read | nexus | short | v1-candidate | Nexus notifications and unread count for an account. |
| `get-account-posts` | Get account-related posts | read | nexus | short | v1-candidate | Nexus account posts, blog, comments, replies, feed or payout items. |
| `get-account-relationships` | Get social relationship counts | read | layer1 | short | v1-candidate | Follower/following counts and samples for an account. |
| `get-account-subscriptions` | Get community subscriptions | read | nexus | medium | v1-candidate | Communities an account is subscribed to and its role in them. |
| `get-account-witness-votes` | Get account witness votes | read | layer1 | short | v1-candidate | Witnesses supported by an account and any witness proxy. |
| `get-blurt-price` | Get BLURT market price | read | external | external | v1-candidate | Current BLURT USD/BTC price from the configured public price feed. |
| `get-chain-status` | Get chain and market status | read | mixed | short | v1-candidate | Network, supply, reward and market dashboard for the Blurt blockchain. |
| `get-community` | Get community details | read | nexus | medium | v1-candidate | Nexus details for a single Blurt blockchain community. |
| `get-delegations` | Get outgoing delegations | read | layer1 | short | v1-candidate | Outgoing Blurt Power delegations for an account. |
| `get-pending-rewards` | Get unclaimed rewards | read | mixed | short | v1-candidate | Pending reward balances currently claimable by an account. |
| `get-post` | Get post or discussion | read | nexus | short | v1-candidate | Nexus post summary or full discussion tree for an author/permlink. |
| `get-post-reblogs` | Get post reblogs | read | layer1 | short | v1-candidate | Accounts that reblogged a post. |
| `get-post-votes` | Get post votes | read | layer1 | short | v1-candidate | Layer 1 active votes on a post/comment ranked by rshares. |
| `get-publications` | Get ranked publications | read | nexus | short | v1-candidate | Nexus ranked posts for discovery by sort/tag. |
| `get-referrals` | Get referred accounts | read | nexus | medium | v1-candidate | beBlurt referral accounts and total count for a referrer. |
| `get-vote-value` | Estimate account vote value | read | mixed | short | v1-candidate | Estimated current upvote value for an account at a given weight. |
| `get-witness` | Get witness health | read | layer1 | short | v1-candidate | Layer 1 witness details and health summary for one account. |
| `list-communities` | List communities | read | nexus | medium | v1-candidate | Nexus community discovery by rank, newness or subscribers. |
| `list-witnesses` | List witnesses | read | layer1 | short | v1-candidate | Layer 1 witness ranking and production metadata. |
| `lookup-accounts` | Lookup account names | read | layer1 | medium | v1-candidate | Alphabetical account-name autocomplete by prefix. |
| `search` | Search Blurt blockchain resources | read | mcp | none | v1-candidate | Map a free-form query to blurt:// resource links. |
---
# Write operations
Source: docs/write-operations.md
Canonical URL: https://mcp.blurt-blockchain.com/write-operations.html
# Write operations (signing) β opt-in, local by default
Write operations are **off by default**. They are registered **only** on the stdio server by default, and **only** when a valid **posting** authority is configured. The normal HTTP server refuses to start if a posting key is present; an explicitly unsafe HTTP override exists only for trusted operator-controlled deployments
(see [Advanced: unsafe HTTP signing for trusted deployments](#advanced-unsafe-http-signing-for-trusted-deployments)).
Read [security guide](./security.md) for the full threat model and the principles every write tool follows.
## Which key β delegated posting authority (recommended)
`BLURT_ACCOUNT` is the account you act *as*. `BLURT_POSTING_KEY` may be **either**:
1. **A delegated account's posting key (recommended).** Create/own a separate account, grant it
**posting authority** over `BLURT_ACCOUNT` (add it to your posting `account_auths` β most wallets
call this "posting authority"), and configure the MCP with **that account's** posting key. Your own
key is never shared, and you can **revoke** access in one operation (remove the authority) without
rotating any key.
2. **Your account's own posting key.** Simpler, but to revoke it you must change your posting key.
On startup the server validates that the key has posting authority over `BLURT_ACCOUNT` β directly, or
through a delegated account β and **refuses owner/active keys**. The posting authority cannot move funds.
## Recommended setup β key in a file you control, outside the repo
Put the secret in a file outside the project (e.g. `~/.config/blurt-mcp/secret.env`, `chmod 600`), and
point the stdio launcher at it with `BLURT_ENV_FILE` β the launcher itself carries **no secret**:
```json
{
"mcpServers": {
"blurt": {
"command": "node",
"args": ["/absolute/path/to/blurt-mcp-server/dist/server-stdio.js"],
"env": { "BLURT_ENV_FILE": "/home/you/.config/blurt-mcp/secret.env" }
}
}
}
```
```bash
# ~/.config/blurt-mcp/secret.env (chmod 600)
BLURT_ACCOUNT=youraccount
BLURT_POSTING_KEY=5J...
# recommended for new users β claim rewards + upvote only:
BLURT_WRITE_PROFILE=curator
# optional β subtract individual tools from the selected profile:
# BLURT_WRITE_TOOLS_BANNED=upvote
# optional neutral safety default β omitted dry_run parameters preview first:
# BLURT_DRY_RUN_DEFAULT=true
# optional local brake against accidental loops, disabled when unset:
# BLURT_WRITE_RATE_LIMITS=claim-rewards=6/3600,upvote=30/3600
```
The server loads `BLURT_ENV_FILE` (or, if unset, the project's `.env`) regardless of the working
directory the desktop app launches it from. Variables already set in the launcher's `env` block take
precedence over the file, so you can also place the values directly in `env` if you prefer.
> Do **not** put the posting key in the project's `.env`: the HTTP server would then refuse to start,
> and the secret would live inside the working tree. Keep it in a file outside the repo.
## Guarantees
- Only the **posting** key is accepted (active/owner are refused; it cannot move funds). The key is
used solely for local signing β never sent to the network, logs, or other dependencies.
- Write tools are registered **only** on the stdio server by default, gated by the validated key and
the `BLURT_WRITE_TOOLS_BANNED` denylist. The HTTP server refuses to start with a key unless the
operator explicitly enables the unsafe trusted-deployment override below.
- The MCP server does **not** add write rate limits by default. Operators may opt in to
process-local per-tool caps with `BLURT_WRITE_RATE_LIMITS` when they want an extra brake against
accidental loops or a misconfigured agent. These caps are not moderation rules and do not decide
which accounts, tags or communities are allowed.
Every write tool supports `dry_run: true` to preview **without** broadcasting, and your AI client also
prompts you to approve each tool call before it runs. Operators who prefer preview-first behavior can
set `BLURT_DRY_RUN_DEFAULT=true`; omitted `dry_run` parameters then default to preview mode, while an
explicit `dry_run: false` still executes the operation.
### Neutral infrastructure boundary
The Blurt MCP server is neutral infrastructure. It validates signing safety and transport boundaries, but it does not add default write throttling. Optional operator controls such as `BLURT_WRITE_RATE_LIMITS`, `BLURT_WRITE_TOOLS_BANNED` and `BLURT_DRY_RUN_DEFAULT` are deployment controls for a specific server process; they are not Blurt blockchain protocol rules. Blurt blockchain Layer 1 and RPC operators keep their own protections. See [ADR 0001](./adr/0001-neutral-infrastructure.md).
### Enabling tools with capability profiles
`BLURT_WRITE_PROFILE` is the recommended control for new deployments. It enables a semantic set of
capabilities, so operators do not need to maintain a long comma-separated list of every tool and do not
need to edit config just because a future release adds a tool that clearly belongs to the same profile.
If `BLURT_WRITE_PROFILE` is **unset**, the server preserves the historical behavior for backward
compatibility: all current write tools are enabled, and `BLURT_WRITE_TOOLS_BANNED` subtracts specific
ones.
Recommended starting point:
```dotenv
BLURT_WRITE_PROFILE=curator
```
Profiles:
| Profile | Enables | Intended operator posture |
| --- | --- | --- |
| `none` | no write tools | Keep a key configured but temporarily expose no write surface. |
| `curator` | `claim-rewards`, `upvote` | Safer new-user default: rewards + voting only. |
| `social` | `curator` plus `follow`, `mute`, `subscribe-community`, `read-notifications`, `reblog` | Social/community actions, but no original text publishing. |
| `publisher` | all current publishing/social/reward tools | Trusted local assistant that may comment and publish posts. Future high-risk tools should be classified deliberately before joining this profile. |
| `full` | every write tool in this release | Explicit full-access mode; equivalent to legacy unset-profile behavior for current tools. |
`BLURT_WRITE_TOOLS_BANNED` remains supported as a backward-compatible subtractive control. It always
removes individual tools from whichever profile is active (or from legacy `full` mode when no profile
is set). For example, a social operator that wants to allow follows/community/reblogs but not upvotes:
```dotenv
BLURT_WRITE_PROFILE=social
BLURT_WRITE_TOOLS_BANNED=upvote
```
### Local write rate limits are optional
`BLURT_WRITE_RATE_LIMITS` is the only MCP-server write throttling mechanism. It is disabled when unset.
The format is a comma-separated list of `tool=max/windowSeconds` entries:
```dotenv
BLURT_WRITE_RATE_LIMITS=claim-rewards=6/3600,upvote=30/3600,post=10/3600
```
This limit is process-local and in-memory. It resets when the process restarts and does not coordinate
across replicas. Use it only as a local safety brake for a particular deployment.
Layer distinction:
- **Blurt blockchain Layer 1** still enforces its own protocol rules: signature authority, transaction
validity, voting mana/economics, duplicate/conflicting operations where applicable, and irreversible
public history.
- **Public RPC nodes** may enforce their own traffic limits, quotas, connection limits or abuse controls.
Those limits depend on the node operator and are outside this MCP server.
- **This MCP server** only enforces posting-key validation, transport gating, selected write-tool
registration, optional dry-run defaults, and optional `BLURT_WRITE_RATE_LIMITS` when the operator sets
them.
### Canonical write tool list
Use the **tool name** column below for denylist entries. Unknown denylist names are ignored so old
configuration remains forward-compatible across releases; an unknown `BLURT_WRITE_PROFILE` fails
closed at startup.
| Tool | Tool name | Operation | Optional cap example | Profiles |
| --- | --- | --- | ---: | --- |
| `blurt-claim-rewards` | `claim-rewards` | `claim_reward_balance` | `claim-rewards=6/3600` | `curator`, `social`, `publisher`, `full` |
| `blurt-upvote` | `upvote` | `vote` | `upvote=30/3600` | `curator`, `social`, `publisher`, `full` |
| `blurt-comment` | `comment` | `comment` (reply) | `comment=10/3600` | `publisher`, `full` |
| `blurt-post` | `post` | `comment` (top-level) | `post=10/3600` | `publisher`, `full` |
| `blurt-follow` | `follow` | `custom_json` follow | `follow=30/3600` | `social`, `publisher`, `full` |
| `blurt-mute` | `mute` | `custom_json` follow/ignore | `mute=30/3600` | `social`, `publisher`, `full` |
| `blurt-subscribe-community` | `subscribe-community` | `custom_json` community | `subscribe-community=30/3600` | `social`, `publisher`, `full` |
| `blurt-reblog` | `reblog` | `custom_json` reblog | `reblog=30/3600` | `social`, `publisher`, `full` |
| `blurt-read-notifications` | `read-notifications` | `custom_json` notify | `read-notifications=30/3600` | `social`, `publisher`, `full` |
### Advanced: unsafe HTTP signing for trusted deployments
The default and recommended signing mode is still **local stdio**. However, experienced operators who
run a private, authenticated, access-controlled deployment may deliberately opt in to exposing the same
write tools over the HTTP MCP endpoint.
This is intentionally hard to enable. You must configure a valid write context (`BLURT_ACCOUNT` and
`BLURT_POSTING_KEY`) and set this exact environment variable/value on the HTTP server process:
```dotenv
BLURT_UNSAFE_ALLOW_HTTP_SIGNING_WITH_POSTING_KEY=I_ACCEPT_FULL_RESPONSIBILITY_FOR_EXPOSING_BLURT_WRITE_TOOLS_OVER_HTTP
```
Any other value is ignored and the HTTP server still refuses to start with `BLURT_POSTING_KEY` set.
When the override is active, startup prints a large `UNSAFE HTTP SIGNING ENABLED` warning to `stderr`.
The override does **not** weaken the other write policies: active/owner keys are still refused, posting
authority is still validated, `BLURT_WRITE_TOOLS_BANNED` still applies, and any configured
`BLURT_WRITE_RATE_LIMITS` still apply.
Use this only when the HTTP endpoint is protected by your own authentication, TLS, network isolation,
reverse-proxy controls, monitoring, and operational procedures. Do **not** use it for the public hosted
endpoint, an anonymous service, or an unauthenticated LAN/WAN deployment. The operator accepts full
responsibility for every on-chain operation signed by that process. See [security guide](./security.md)
for the full rationale and threat model.
## `blurt-claim-rewards`
Claims the configured account's pending author/curation rewards (`claim_reward_balance`), moving them
into the account's balance and Blurt Power. Acts only on the configured account; no parameter targets
another account. Returns the pending amounts and, when executed, the transaction id.
## `blurt-upvote`
Upvotes a post or comment (`vote`) as the configured account.
- Parameters: `author`, `permlink`, `weight` (percent, 1-100, default 100), `dry_run`.
- Only the configured account votes; on chain, weight 100% = 10000.
## `blurt-comment`
Posts a reply (`comment`) to a post or comment as the configured account.
- Parameters: `parent_author`, `parent_permlink`, `body` (markdown), `dry_run`.
- A unique permlink is generated automatically. The body gets a `via Blurt-MCP` footer (linking back
to this repository) appended after a blank line, and `json_metadata.app` is set to `blurt-mcp/`.
- Posts are **public and permanent** β use `dry_run: true` first to review the exact final body.
## `blurt-post`
Publishes a **new top-level post** (`comment` with an empty parent) as the configured account.
- Parameters: `title`, `body` (markdown), `tags` (1β8 lowercase tags; the first is the main category),
`dry_run`.
- A unique permlink is generated from the title. Same `via Blurt-MCP` footer and `json_metadata.app =
blurt-mcp/` stamping as `blurt-comment`; the tags are stored in `json_metadata.tags`.
- Posts are **public and permanent** β use `dry_run: true` first to review the exact final post.
## `blurt-follow`
Follows or unfollows another account (`custom_json` id `follow`).
- Parameters: `account`, `action` (`follow` | `unfollow`, default `follow`), `dry_run`.
## `blurt-mute`
Mutes (ignores) or unmutes another account (`custom_json` id `follow`, `what: ['ignore']`), hiding its
content in compatible frontends.
- Parameters: `account`, `action` (`mute` | `unmute`, default `mute`), `dry_run`.
## `blurt-subscribe-community`
Subscribes the account to a community, or unsubscribes from it (`custom_json` id `community`).
- Parameters: `community` (name/id, e.g. `blurt-192372`), `action` (`subscribe` | `unsubscribe`,
default `subscribe`), `dry_run`.
## `blurt-reblog`
Reblogs (re-shares) a post to the account's blog (`custom_json` id `reblog`), or removes a prior reblog.
- Parameters: `author`, `permlink`, `undo` (default `false`), `dry_run`.
## `blurt-read-notifications`
Marks the account's notifications as read up to now (`custom_json` id `notify`, `setLastRead`). Acts
only on the configured account; no parameter targets another account.
- Parameter: `dry_run`. Pair with `get-account-notifications` to read them first.
---
# Security guide
Source: docs/security.md
Canonical URL: https://mcp.blurt-blockchain.com/security.html
# Security
The Blurt MCP server is **read-only by default** and holds **no private keys** in its normal HTTP mode.
Optional write tools are opt-in and local-first:
- local stdio signing uses a posting key only;
- posting keys cannot move funds;
- owner and active keys are refused;
- public HTTP remains read-only by default;
- HTTP signing requires an explicit unsafe trusted-deployment override.
For the full repository security policy and threat model, see [`SECURITY.md`](https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/blob/main/SECURITY.md).
For operator instructions, see [write operations](./write-operations.md).
For HTTP deployments, `/mcp` intentionally does not maintain an AI-product `Origin` allow-list. The
public endpoint is safe by design only while it remains read-only and has no browser ambient authority:
no posting key, no cookies, no credentialed CORS and no user-specific private data. JSON-RPC batch
arrays are rejected because MCP `2025-06-18` removed batching support.
---
# Deployment overview
Source: docs/deployment.md
Canonical URL: https://mcp.blurt-blockchain.com/deployment.html
# Deployment guide
This guide covers deployment concerns that belong around the Blurt MCP server, not inside it.
The application stays a small neutral MCP component: it exposes `/mcp`, `/healthz`, and `/readyz`; TLS,
public rate limiting, bot protection, and global abuse controls should normally live in infrastructure.
## HTTP surface
| Path | Method | Purpose |
| --- | --- | --- |
| `/mcp` | `POST` | Streamable HTTP MCP endpoint. Stateless; no session id. |
| `/mcp` | `GET`, `DELETE` | Returns `405`; not supported in stateless mode. |
| `/healthz` | `GET` | Cheap process liveness check. Does not touch upstream RPC. |
| `/readyz` | `GET` | Cheap readiness check with non-sensitive RPC configuration/readiness counters. |
The app uses Express' JSON parser default request-body limit unless `BLURT_HTTP_JSON_BODY_LIMIT` is set.
For public HTTP deployments, prefer enforcing body size in the reverse proxy or ingress layer where it
can be monitored and changed without rebuilding the MCP server.
The public `/mcp` route intentionally does not maintain an AI-product `Origin` allow-list. This
endpoint's security boundary is instead a public read-only, no-ambient-authority deployment model: no
posting key on public HTTP, no cookies, no credentialed CORS, no user-specific private data, and TLS /
host routing at the reverse proxy. This avoids turning interoperability with current and future MCP
clients into an operator-maintained list of browser origins.
JSON-RPC batch arrays are rejected before the request reaches the MCP SDK transport because MCP
`2025-06-18` removed batching support.
## Recommended topology
```text
Internet / client
-> reverse proxy / ingress / CDN
-> blurt-mcp-server HTTP process
-> Blurt blockchain RPC nodes, Nexus/Bridge API, price feed
```
The public hosted endpoint should stay anonymous and read-only. Do not configure `BLURT_POSTING_KEY` on
a public HTTP deployment. HTTP signing is available only through the deliberately unsafe trusted-deployment
override documented in [write operations](./write-operations.md#advanced-unsafe-http-signing-for-trusted-deployments).
## Caddy example
```txt
mcp.example.org {
encode zstd gzip
@mcp method POST
@mcp path /mcp
reverse_proxy @mcp 127.0.0.1:3000
@health path /healthz /readyz
reverse_proxy @health 127.0.0.1:3000
# Keep request bodies small; MCP JSON-RPC requests are tiny.
request_body {
max_size 256KB
}
# Caddy rate limits require a plugin/module. If unavailable, apply rate limits
# at your CDN, load balancer, firewall, or hosting platform instead.
}
```
## nginx example
```nginx
limit_req_zone $binary_remote_addr zone=blurt_mcp:10m rate=60r/m;
server {
listen 443 ssl http2;
server_name mcp.example.org;
client_max_body_size 256k;
location = /mcp {
limit_req zone=blurt_mcp burst=30 nodelay;
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location = /healthz {
proxy_pass http://127.0.0.1:3000;
}
location = /readyz {
proxy_pass http://127.0.0.1:3000;
}
}
```
Tune the rate-limit numbers for your own traffic and abuse profile. The example is intentionally coarse;
production limits should be validated against real usage.
## Deployment methods
| Method | Use when | Guide |
| --- | --- | --- |
| PM2 | You deploy from a normal Node.js host or VPS and want process restart, boot integration, logs and `pm2 monit`. | [PM2 deployment](./deployment-pm2.md) |
The deployment method should not change the server architecture: keep runtime configuration in
`BLURT_ENV_FILE`, keep TLS/rate limits/body limits at the infrastructure boundary, and keep posting keys
out of public HTTP deployments.
## Production environment checklist
- `NODE_ENV=production` for JSON logs.
- `LOG_LEVEL=info` unless actively debugging.
- Explicit `BLURT_RPC_URLS` for maintained deployments; provide multiple nodes so the node checker can avoid unhealthy nodes.
- Explicit `BLURT_PRICE_URL` if price-dependent tools should be available.
- Optional transport/cache/body settings (`BLURT_RPC_TIMEOUT_MS`, `BLURT_PRICE_CACHE_TTL_MS`, `BLURT_HTTP_JSON_BODY_LIMIT`, etc.) are set by deployment configuration, not by source edits.
- Reverse proxy terminates TLS and applies public rate limits.
- `/healthz` and `/readyz` are routed to monitoring.
- No posting key on public HTTP deployments.
- Secrets for stdio/private deployments are kept outside the repository.
## What is intentionally deferred
The app does not ship a full OpenTelemetry stack, built-in distributed rate limiter, WAF, dashboard,
alerting setup, or generic response cache. Those belong to deployment infrastructure until concrete
hosting requirements justify pulling a small part into the server itself.
---
# PM2 deployment
Source: docs/deployment-pm2.md
Canonical URL: https://mcp.blurt-blockchain.com/deployment-pm2.html
# PM2 deployment
Use this guide when you want to run the Blurt MCP server as a long-lived Node.js process on a VPS or
plain Linux host. PM2 manages the process lifecycle; the server still expects TLS, public rate limits,
request body limits and host routing to live in a reverse proxy such as Caddy, nginx, a CDN or your
hosting platform.
PM2 is a good choice when you want:
- a small Node.js process manager with restart and boot integration;
- simple log streaming with `pm2 logs` and `pm2 monit`;
- deployment from a normal source checkout.
## Configuration model
The PM2 ecosystem file is intentionally not the runtime configuration source. It exposes only
`BLURT_ENV_FILE`, and the server loads all application settings from that file.
Repository example:
```text
ecosystem.config.cjs
```
Runtime configuration file used by the example:
```text
/home/you/.config/blurt-mcp/secret.env
```
Create the directory and environment file on the host:
```bash
mkdir -p /home/you/.config/blurt-mcp
chmod 700 /home/you/.config/blurt-mcp
$EDITOR /home/you/.config/blurt-mcp/secret.env
chmod 600 /home/you/.config/blurt-mcp/secret.env
```
Minimal public HTTP configuration:
```dotenv
NODE_ENV=production
LOG_LEVEL=info
HOST=127.0.0.1
PORT=3000
BLURT_HTTP_JSON_BODY_LIMIT=256kb
BLURT_RPC_URLS=https://rpc.beblurt.com,https://rpc.blurt.world
BLURT_PRICE_URL=https://api.blurt.blog/price_info
```
Keep `BLURT_POSTING_KEY` out of public HTTP deployments. If you need signing, use local stdio or a
private trusted deployment with explicit external controls.
## Install and build
From the checkout:
```bash
npm ci
npm run build
npm install -g pm2
```
Review the `BLURT_ENV_FILE` path in
[`ecosystem.config.cjs`](https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/blob/main/ecosystem.config.cjs)
before starting the service.
## First start
```bash
pm2 start ecosystem.config.cjs
pm2 status blurt-mcp-server
```
Then configure the reverse proxy to send `/mcp`, `/healthz` and `/readyz` to the local process, for
example `127.0.0.1:3000` when using the environment file above.
Validate the process and endpoint:
```bash
curl http://127.0.0.1:3000/healthz
curl http://127.0.0.1:3000/readyz
MCP_URL=https://mcp.example.org/mcp npm run smoke:http
```
## Reload vs restart
Use `reload` for normal deployments after changing code or environment configuration:
```bash
git pull --ff-only
npm ci
npm run build
pm2 reload blurt-mcp-server --update-env
npm run smoke:http
```
Use `restart` when you explicitly want a full stop/start cycle or when troubleshooting a stuck process:
```bash
pm2 restart blurt-mcp-server --update-env
```
`--update-env` matters when `BLURT_ENV_FILE` itself changes in the PM2 process environment. Changes inside
the referenced `secret.env` are picked up by the next process start because the server loads that file at
startup.
## Logs and monitoring
Stream logs:
```bash
pm2 logs blurt-mcp-server
```
Show recent lines only:
```bash
pm2 logs blurt-mcp-server --lines 100
```
Open PM2's terminal monitor:
```bash
pm2 monit
```
In production, the Blurt MCP logger writes JSON lines to `stderr` with its own timestamp. The PM2 example
therefore does not add PM2 timestamp formatting or custom output files. Use OS log rotation or
[`pm2-logrotate`](https://pm2.keymetrics.io/docs/usage/log-management/) for long-lived hosts.
## Save and startup
After the process list is correct:
```bash
pm2 save
pm2 startup
```
`pm2 startup` prints a platform-specific command. Run that command if you want PM2 to restore saved
processes after a reboot.
## Stop or remove
Stop without deleting the PM2 process definition:
```bash
pm2 stop blurt-mcp-server
```
Remove it from PM2 entirely:
```bash
pm2 delete blurt-mcp-server
```
If you delete the process and want the saved boot state to match, run:
```bash
pm2 save
```
## Ecosystem options used
| Option | Value | Why it is used |
| --- | --- | --- |
| `script` | `dist/server.js` | Runs the compiled HTTP entrypoint. Build before starting PM2. |
| `cwd` | `__dirname` | Makes script and fallback `.env` resolution independent of the shell directory. |
| `exec_mode` / `instances` | `fork` / `1` | Avoids premature local clustering; scale at the reverse proxy/platform after measuring real traffic. |
| `autorestart` | `true` | Makes the process manager restart the server after crashes. |
| `watch` | `false` | Keeps production deployments from restarting on generated file or log changes. |
| `max_restarts` / `min_uptime` | `10` / `10s` | Limits rapid crash loops caused by bad builds or invalid configuration. |
| `kill_timeout` | `5000` | Gives Node a short grace period during restarts. |
| `env.BLURT_ENV_FILE` | `/home/you/.config/blurt-mcp/secret.env` | Points the server at the single runtime configuration file. |
## Options intentionally omitted
| Option | Why it is omitted |
| --- | --- |
| `interpreter` | PM2 already uses Node for `.js` scripts. |
| `time` / `log_date_format` | Production logs already contain JSON timestamps from the application logger. |
| `out_file` / `error_file` | Log paths and rotation are host policy; PM2 defaults plus log rotation are sufficient for the example. |
| `merge_logs` | Useful mainly with multiple instances or cluster mode; this example runs one process. |
| `restart_delay` | `max_restarts` and `min_uptime` already cover crash loops without adding another timing policy. |
| `max_memory_restart` | Memory limits are host- and traffic-specific. Add one after observing baseline memory usage. |
For advanced PM2 behavior, see the PM2 documentation for
[ecosystem files](https://pm2.io/docs/runtime/reference/ecosystem-file/),
[restart strategies](https://pm2.keymetrics.io/docs/usage/restart-strategies/) and
[log management](https://pm2.keymetrics.io/docs/usage/log-management/).
---
# Operations
Source: docs/operations.md
Canonical URL: https://mcp.blurt-blockchain.com/operations.html
# Public endpoint operations notes
These notes describe how to operate a public read-only Blurt MCP endpoint. They are not a hard SLO or an
on-call contract; those should be finalized only when hosting ownership, alerting, and maintenance
responsibilities are explicit.
## Service posture
The public endpoint is a best-effort, anonymous, read-only MCP service for public Blurt blockchain data. It should
not hold private keys and should not expose write tools. Write/signing deployments are private operator
responsibility.
## Dependencies
| Dependency | Used for | Degradation behavior |
| --- | --- | --- |
| Blurt blockchain Layer 1 RPC nodes | accounts, balances, history, witnesses, votes, broadcasts in private write mode | Read tools depending on L1 may fail or become slow. Node checker keeps the client on healthy configured nodes when possible. |
| Nexus / Bridge API | ranked posts, account posts, communities, discussions and social L2 views | Nexus-backed tools may fail while L1 tools continue. |
| Price feed (`BLURT_PRICE_URL`) | BLURT/USD and BTC values | Price fields are best-effort; on-chain fields should still be returned where possible. |
| Reverse proxy / ingress | TLS, public rate limiting, body-size enforcement, host/origin filtering | Misconfiguration can expose the app directly or amplify abuse. |
## Health checks
- `/healthz`: process liveness. Use for container/process checks.
- `/readyz`: cheap readiness. Use for load balancers and monitoring. It reports non-sensitive RPC
counters and does not perform a heavy live RPC call on every request.
## Logging
In production (`NODE_ENV=production`) logs are JSON lines on `stderr`. The HTTP app logs method, path,
status and duration for requests, without request bodies or secrets. Collect logs at the process manager,
container runtime, or platform layer.
## Incident examples
| Symptom | Likely area | First checks |
| --- | --- | --- |
| `/healthz` fails | process/container | process manager, container status, recent deploy logs |
| `/healthz` passes but `/readyz` fails | app readiness/config | env vars, configured RPC URL count, startup logs |
| MCP read tools slow/failing | upstream RPC or Nexus | node checker logs, configured RPC nodes, Nexus status |
| Price fields null | price feed | `BLURT_PRICE_URL`, external feed availability |
| High 4xx/429 at proxy | client misuse/abuse | reverse-proxy logs and rate-limit settings |
| High 5xx from app | app/runtime/upstream errors | app logs, recent commits, dependency status |
## Rollback and maintenance
- Keep deployments reproducible from a Git commit and package lockfile.
- Prefer blue/green or rolling deployment where the platform supports it.
- Validate `/healthz`, `/readyz`, and `npm run smoke:http` after deployment.
- Roll back to the previous known-good commit if the MCP transport or core read tools regress.
## SLO candidate, not a guarantee
A future production service may define uptime and latency SLOs. Until monitoring, alerting,
incident ownership, and hosting budget are formalized, treat this document as operational guidance rather
than a public availability guarantee.
---
# Cache policy
Source: docs/cache-policy.md
Canonical URL: https://mcp.blurt-blockchain.com/cache-policy.html
# Cache and freshness policy
The MCP server should avoid broad response caching until result contracts consistently carry
source/freshness metadata. Incorrectly cached blockchain data can mislead AI summaries and users.
## Current cache
The only intentional application cache is the BLURT price helper cache. It is narrow and short-lived:
- external price feed only;
- approximately 60 seconds;
- best-effort;
- failures do not invalidate on-chain data;
- USD/BTC values may be `null` when unavailable.
## No generic response cache yet
Do not add a generic cache layer for account, wallet, history, witness, vote, post, community or pending
reward tools in Phase 4. These values have different freshness expectations and source layers:
- Layer 1 account/wallet/reward/vote/witness state changes with blocks and account activity;
- Nexus/Bridge ranked posts and community views have their own indexing freshness;
- external market prices have separate freshness and failure modes;
- mixed dashboard-style tools combine several sources.
## Requirement before broader caching
Before introducing per-tool TTLs, structured results should expose provenance/freshness metadata such as:
- source layer (`layer1`, `nexus`, `external`, `mixed`);
- retrieval timestamp;
- head block or index/version when available;
- cache hit/miss or freshness age;
- caveats for best-effort external data.
Until then, prefer correctness and transparent latency over silent stale responses.
## Deployment-level caching
Reverse proxies and CDNs should not cache `/mcp` responses by default. MCP requests are JSON-RPC POSTs
whose results depend on tool arguments and upstream state. If an operator experiments with caching, it
should be explicit, endpoint-specific, and validated against stale-data risk.
---
# Load checks
Source: docs/load-testing.md
Canonical URL: https://mcp.blurt-blockchain.com/load-testing.html
# HTTP smoke and lightweight load checks
The repository includes a small HTTP smoke script for deployment validation. It is intentionally light:
it checks MCP connectivity and repeated `tools/list` calls without turning normal CI into a public-load
test against upstream Blurt blockchain services.
## Run against a local server
Start the server:
```bash
npm run build
npm start
```
In another shell:
```bash
npm run smoke:http
```
By default this targets `http://localhost:3000/mcp` and runs five `tools/list` iterations.
## Run against a hosted endpoint
```bash
MCP_URL=https://mcp.example.org/mcp MCP_SMOKE_ITERATIONS=10 npm run smoke:http
```
## Include one representative read
```bash
MCP_URL=https://mcp.example.org/mcp MCP_SMOKE_READ=1 npm run smoke:http
```
This calls `get-chain-status` once after the `tools/list` loop. Use it sparingly on public endpoints;
it may touch upstream RPC/price dependencies.
## Output
The script emits JSON lines, for example:
```json
{"event":"tools_list","iteration":1,"tool_count":25,"duration_ms":42}
{"event":"done","url":"http://localhost:3000/mcp","iterations":5,"include_read":false,"total_duration_ms":260}
```
## What this is not
This is not a full benchmark, distributed load test, or SLO proof. Heavy load testing should be run from
a controlled staging environment with permission and with upstream RPC impact in mind.
---
# Architecture
Source: docs/architecture.md
Canonical URL: https://mcp.blurt-blockchain.com/architecture.html
# Architecture β how it works
- **Two entrypoints, one server.** `server.ts` exposes the tools over **Streamable HTTP** β a single
Express route, `POST /mcp`, in **stateless** mode (no session id), with a fresh `McpServer` built
per request via `buildServer()` (`GET`/`DELETE` return `405`). The HTTP boundary rejects JSON-RPC
batch arrays; public endpoint safety comes from a read-only, no-ambient-authority deployment model
rather than client `Origin` allow-lists. It also exposes cheap operational
probes outside MCP: `GET /healthz` and `GET /readyz`. `server-stdio.ts` exposes the same tools over
**stdio** for local desktop use. Both call `buildServer()`. HTTP deployments can set `HOST` and `PORT`
through the configured `BLURT_ENV_FILE`; process-manager examples should expose only that env-file pointer,
bind to `127.0.0.1` behind a reverse proxy, and avoid becoming a second runtime configuration surface.
- **Shared Blurt blockchain client.** One `@beblurt/dblurt` `Client` is created on first use and reused so RPC
connections stay warm (only the first call pays the cold-connection cost). It is configured with
`rpcTransport: "core"` β the default "legacy" transport aborts each attempt after `(tries+1)*500ms`
and then crashes (`error.code.includes is not a function`) on slow requests under the HTTP server
context. The choice is guarded by `test/resilience.test.ts`.
- **RPC node selection.** A background checker
([`@beblurt/blurt-nodes-checker`](https://gitlab.com/beblurt/blurt-nodes-checker)) continuously
scores the configured nodes (latency, chain lag, version, reliability) and repoints the shared
client at the healthy ones, best-first β so a slow, stale, forked or offline node is avoided rather
than failing a request (`src/utils/rpc.ts`). dblurt's own failover then covers transient blips
within that healthy set.
- **Two data layers.** Account, wallet, history and raw votes come from the **condenser API**
(Layer 1); profiles, ranked posts, account posts, discussions and communities come from the
**Nexus / Bridge API** (Layer 2).
- **Market price.** `get-blurt-price`, `get-chain-status` and `get-vote-value` read the external price
feed (`BLURT_PRICE_URL`) through a shared helper. The feed URL, optional cache TTL and optional timeout are
deployment configuration; if no feed URL is configured, price-dependent fields fail or become `null` rather
than using a hardcoded infrastructure URL. Price is best-effort: if
the feed is down, on-chain data is still returned and USD fields are `null`.
- **`search` / `fetch`.** `search` maps a free-form query to `blurt://β¦` resource links without any
network call; `fetch` resolves such a URI (or a shorthand id) to the raw JSON. This mirrors the
search/fetch connector convention used by ChatGPT-style clients.
- **Write path (opt-in).** When a posting key is present, write tools are registered through a guarded
write context (`src/utils/signer.ts`); the key is validated as the account's posting authority, used
only for local signing, and never logged or sent to the network. New deployments should use semantic
`BLURT_WRITE_PROFILE` capability profiles; the historical `BLURT_WRITE_TOOLS_BANNED` denylist still
works as a subtractive compatibility control. `BLURT_DRY_RUN_DEFAULT=true` is a neutral preview-first
execution-mode default: omitted `dry_run` parameters preview without broadcasting, but explicit
`dry_run: false` still executes. HTTP stays read-only by default and exposes signing only behind the
explicit unsafe trusted-deployment override. The server does not enforce content/account/
community policy files; see [ADR 0001](./adr/0001-neutral-infrastructure.md),
[write operations](./write-operations.md), and [security guide](./security.md).
- **Errors.** Tool failures return `isError: true` with a short message rather than throwing, so the
model can react instead of seeing a transport error.
- **Documentation site UX.** VitePress keeps Markdown as the source of truth. The site uses a minimal
custom theme (`docs/.vitepress/theme/custom.css`) for global readability: wider desktop content,
stronger table headers and more legible wide tables. Large tables remain Markdown because they are
mostly reference material and generated content; Vue components should be reserved for truly
interactive or reused semantic views.
## Project layout
```
src/
server.ts # HTTP entrypoint: builds the app and listens
server-stdio.ts # stdio entrypoint: same tools as a local child process
app.ts # Builds the Express app + /mcp route (no side effects, testable)
buildServer.ts # Registers all tools/resources on an McpServer; BLURT_CLIENT_OPTIONS
tools/ # One file per MCP tool
resources/ # blurt:// resource templates
utils/
logger.ts # Leveled logger (human / JSON), writes to stderr
loadEnv.ts # Loads BLURT_ENV_FILE / project .env regardless of cwd
rpc.ts # Shared client + RPC node selection (blurt-nodes-checker)
signer.ts # Write context: posting-key validation, optional local rate limits, signing
price.ts # Cached BLURT price feed helper
blurtUri.ts # blurt:// URI parsing / shorthand mapping (used by search/fetch)
test/
uri / search / resilience / write # offline (no external network)
live # live, in-memory MCP client
http # live, real Streamable HTTP transport (E2E)
```
---
# MCP compatibility register
Source: docs/mcp-compatibility-register.md
Canonical URL: https://mcp.blurt-blockchain.com/mcp-compatibility-register.html
# MCP compatibility register
This is the living architectural compatibility register for the Blurt MCP server and the upstream Model
Context Protocol (MCP) specification.
It is not a one-time audit and it is not a checklist for implementing every optional MCP feature.
Its purpose is governance: every meaningful compatibility decision should be explicit, easy to review and
revisited when the specification, SDK or product direction changes.
## Principle
The goal is not maximum MCP feature coverage. The goal is clear compatibility ownership.
A missing optional feature is acceptable when it is intentional and documented. An undocumented protocol,
transport or capability difference is not acceptable.
Review this document whenever:
- the MCP specification changes;
- `@modelcontextprotocol/sdk` is upgraded;
- this server adds or removes MCP capabilities, transports, tools, resources, signing modes or authentication;
- public documentation claims support for a specific MCP specification version.
## Current baseline
| Item | Current value |
| --- | --- |
| Last reviewed against MCP spec | `2025-06-18` |
| Upstream spec source | |
| MCP SDK package | `@modelcontextprotocol/sdk` |
| SDK version at review | `1.29.0` |
| SDK latest protocol version at review | `2025-11-25` |
| SDK supported versions at review | `2025-11-25`, `2025-06-18`, `2025-03-26`, `2024-11-05`, `2024-10-07` |
| Project transports | stdio; stateless Streamable HTTP `POST /mcp` |
| Project capabilities | tools; resource templates |
| Project non-goal | full MCP feature coverage |
## Status meanings
| Status | Meaning |
| --- | --- |
| Implemented | Project code intentionally implements the relevant behavior. |
| Implemented by SDK | The behavior is inherited from the MCP TypeScript SDK and currently needs no project code. |
| Intentional divergence | The project deliberately differs from a strict or common reading of the spec and documents why. |
| Stateless compatibility mode | The behavior follows from the public stateless HTTP design and limits stricter transport claims. |
| Optional deferred | Valid optional MCP feature, deferred until it provides project value. |
| Out of scope | Not part of this server's product role unless product direction changes. |
| Monitor | Accepted current behavior that should be rechecked on SDK/spec/product changes. |
## Priority meanings
| Priority | Meaning |
| --- | --- |
| Now | Should be fixed before making stronger MCP-version or transport-conformance claims. Usually a mandatory spec/security requirement or a low-cost correction. |
| Next | Should be addressed in the next protocol/transport hardening pass, but does not block current public documentation if accurately disclosed. |
| Later | Valid optional feature or polish; implement only when it provides project value. |
| Won't implement | Deliberately out of scope for this project unless the product direction changes. |
| Monitor | Inherited SDK behavior or spec/SDK drift that should be rechecked on upgrades. |
## Implementation scope statement
The precise public wording for the current state is:
> This server uses the Model Context Protocol TypeScript SDK and supports MCP clients negotiating protocol
> version `2025-06-18` for its implemented tools and resource-template features.
Do not claim full MCP conformance, certification or complete Streamable HTTP support unless every material
item in this register has been resolved or explicitly accepted for that stronger claim.
## Register
### Streamable HTTP security
- **Status:** Intentional divergence
- **Priority:** Monitor
- **Spec point:** Servers implementing Streamable HTTP **MUST validate the `Origin` header** to mitigate DNS rebinding.
- **Current behavior:** The public HTTP endpoint does not maintain a client `Origin` allow-list. Requests with `Origin` are treated as non-authoritative and accepted by the public endpoint.
- **Decision:** Keep the public endpoint no-ambient-authority; do not add an AI-product Origin registry.
- **Why:** An Origin allow-list is not maintainable for an open public MCP endpoint and would turn client compatibility into operator-maintained policy. DNS rebinding risk is addressed by removing privileged HTTP authority from the public endpoint: no posting key on public HTTP, no cookies, no credentialed CORS, no user-specific private data, and deployment-owned TLS/host routing.
- **Revisit when:** Adding HTTP signing, cookies, credentialed CORS, private/user-specific data, authenticated sessions or private-network access.
### JSON-RPC batching
- **Status:** Implemented
- **Priority:** Monitor
- **Spec point:** MCP `2025-06-18` removed support for JSON-RPC batching.
- **Current behavior:** JSON array request bodies are rejected at the Express `/mcp` boundary before reaching the SDK transport.
- **Decision:** Keep batching unsupported.
- **Why:** The project has no batching use case, and accepting SDK-inherited batches would conflict with `2025-06-18`.
- **Revisit when:** A future MCP version reintroduces batching. Keep regression tests for batch-array rejection.
### HTTP lifecycle
- **Status:** Stateless compatibility mode
- **Priority:** Next
- **Spec point:** Initialization **MUST** be the first interaction.
- **Current behavior:** In stateless HTTP mode, a direct request such as `tools/list` can succeed without prior `initialize` because each POST builds a fresh server/transport and no session state is kept.
- **Decision:** Decide between stateful Streamable HTTP sessions and accurately documented stateless compatibility mode.
- **Why:** Enforcing lifecycle strictly may require server-side session state or a different transport construction pattern. This needs a design pass to avoid breaking common clients.
- **Revisit when:** Evaluating `StreamableHTTPServerTransport` stateful mode, session storage, `/readyz` behavior, client compatibility and deployment cost.
### HTTP protocol-version header
- **Status:** Stateless compatibility mode
- **Priority:** Next
- **Spec point:** For HTTP after initialization, clients must include `MCP-Protocol-Version`; unsupported values should be rejected.
- **Current behavior:** The SDK rejects unsupported explicit values but accepts missing headers. In this app's stateless mode, post-initialization state is not tracked, so the server cannot know whether a request is subsequent to initialization.
- **Decision:** Revisit together with HTTP lifecycle/session design.
- **Why:** This is difficult to enforce meaningfully without session state. It is also primarily a client MUST, but server acceptance weakens strict transport-conformance claims.
- **Revisit when:** If stateful HTTP is adopted, test missing/invalid protocol headers after initialization. If stateless remains, document this as an intentional compatibility mode.
### Protocol version target
- **Status:** Monitor
- **Priority:** Monitor
- **Spec point:** Server response should negotiate a supported protocol version.
- **Current behavior:** SDK `1.29.0` has latest protocol `2025-11-25`; it returns `2025-06-18` when requested, `2025-11-25` when requested, and `2025-11-25` for unknown versions.
- **Decision:** Do not say the server exclusively targets `2025-06-18`. Say it supports clients negotiating `2025-06-18` for implemented features.
- **Why:** The dependency may support newer protocol versions before this project has audited their full behavior.
- **Revisit when:** On SDK upgrades, record SDK latest/supported versions and rerun raw initialize probes for `2025-06-18`, SDK latest and an unknown version.
### Streamable HTTP GET/SSE standalone stream
- **Status:** Optional deferred
- **Priority:** Later
- **Spec point:** Streamable HTTP supports POST and GET with optional SSE for server-to-client messages.
- **Current behavior:** `GET /mcp` returns `405`; POST responses may use SSE per request.
- **Decision:** Keep unsupported until the server has server-initiated requests/notifications that require standalone GET/SSE.
- **Why:** Current public endpoint is request/response oriented and does not need server-initiated sampling, roots, elicitation or live notifications. Supporting GET streams would add operational complexity.
- **Revisit when:** Server-initiated notifications or subscriptions are introduced.
### Authorization for HTTP
- **Status:** Optional deferred
- **Priority:** Later
- **Spec point:** MCP HTTP authorization is optional, but protected HTTP servers that support MCP authorization should follow the authorization spec and Protected Resource Metadata requirements.
- **Current behavior:** Public HTTP endpoint is unauthenticated; write signing over HTTP is refused unless an explicit unsafe trusted-deployment override is set. No OAuth resource-server metadata is implemented.
- **Decision:** Do not implement MCP OAuth until user-specific/private capabilities or protected hosted deployments exist.
- **Why:** Current public endpoint exposes public Blurt blockchain data only. Deployment-specific auth can live at the reverse proxy/gateway layer for now.
- **Revisit when:** The hosted service becomes protected or user-specific.
### Tools capability
- **Status:** Implemented
- **Priority:** Monitor
- **Spec point:** Servers that support tools must declare `tools`; `tools/list` and `tools/call` define tool metadata, inputs and results.
- **Current behavior:** Implemented via `McpServer.registerTool`; initialize advertises `tools: { listChanged: true }`; tools include `name`, `title`, `description`, `inputSchema`, `outputSchema`, annotations and structured results.
- **Decision:** Keep as the core supported feature.
- **Why:** Tools are the main product surface.
- **Revisit when:** The SDK is upgraded or generated tool contracts change.
### Tool list pagination
- **Status:** Optional deferred
- **Priority:** Later
- **Spec point:** `tools/list` supports cursor pagination.
- **Current behavior:** The SDK returns all registered tools in one response with no `nextCursor`. The list is small and static.
- **Decision:** Do not implement custom pagination unless the tool list becomes large or SDK behavior changes.
- **Why:** Pagination adds no value for the current tool set.
- **Revisit when:** Tool count grows substantially.
### Tool list change notifications
- **Status:** Monitor
- **Priority:** Monitor
- **Spec point:** If `listChanged` is declared, servers should notify when the tool list changes.
- **Current behavior:** SDK high-level API advertises `tools: { listChanged: true }`; this server's tool list is fixed at server construction and does not change at runtime.
- **Decision:** Accept as harmless for static tool lists.
- **Why:** No runtime change occurs, so no notification is needed. If future runtime changes are added, notifications become important.
- **Revisit when:** Dynamic tool enable/disable is added after initialization; add list-changed notifications or stop advertising the capability if the SDK allows.
### Structured tool output
- **Status:** Implemented
- **Priority:** Monitor
- **Spec point:** MCP `2025-06-18` supports `structuredContent` and optional `outputSchema`.
- **Current behavior:** Successful tool results use `withStandardStructuredContent`; errors return `isError` with text.
- **Decision:** Keep structured output.
- **Why:** Structured output is valuable for agents and generated contract docs.
- **Revisit when:** The project is ready to make stronger per-tool schema compatibility promises.
### Resources and resource templates
- **Status:** Implemented
- **Priority:** Monitor
- **Spec point:** Servers that support resources must declare `resources`; templates are exposed via `resources/templates/list`; resources are read with `resources/read`.
- **Current behavior:** Four `blurt://` resource templates are implemented. Initialize advertises `resources: { listChanged: true }`.
- **Decision:** Keep as a supported feature.
- **Why:** Resource templates are useful for connector-style `search`/`fetch` workflows.
- **Revisit when:** SDK upgrades affect resource URI templates or reads.
### Resource listing behavior
- **Status:** Optional deferred
- **Priority:** Later
- **Spec point:** Resource list/template list supports pagination and may list concrete resources.
- **Current behavior:** Templates are listed; concrete resource listing is effectively empty because templates use `{ list: undefined }`. No cursor pagination is provided.
- **Decision:** Keep a template-first model; do not list all possible Blurt blockchain resources.
- **Why:** Blurt blockchain resources are unbounded. Concrete listing would be artificial or expensive.
- **Revisit when:** Curated resource lists are added; define stable pagination and freshness rules first.
### Resource subscriptions
- **Status:** Out of scope
- **Priority:** Won't implement
- **Spec point:** Resource capability may support `subscribe`; servers that support it send `notifications/resources/updated`.
- **Current behavior:** Not advertised and not implemented.
- **Decision:** Do not implement until there is a concrete live-update product need.
- **Why:** Public Blurt blockchain queries are request/response; subscriptions would require state, polling and operational commitments.
- **Revisit when:** Live notifications or watch-style features become a product goal.
### Prompts
- **Status:** Out of scope
- **Priority:** Won't implement
- **Spec point:** Servers may expose user-controlled prompt templates.
- **Current behavior:** Not advertised and not implemented.
- **Decision:** Do not implement for now.
- **Why:** This server's role is data/tools, not prompt-template distribution. Human examples live in docs, not MCP prompt objects.
- **Revisit when:** The project needs curated Blurt analysis workflows as selectable client prompts.
### Completion
- **Status:** Optional deferred
- **Priority:** Later
- **Spec point:** Servers may support argument completion for prompts/resources.
- **Current behavior:** Not advertised and not implemented.
- **Decision:** Defer.
- **Why:** Completion would be useful only after prompts or richer resource browsing need it.
- **Revisit when:** Prompts or curated resources are introduced.
### MCP logging
- **Status:** Optional deferred
- **Priority:** Later
- **Spec point:** Servers may advertise `logging` and send `notifications/message`; logs must avoid secrets.
- **Current behavior:** Not advertised. Server logs go to stderr / process logs, not MCP client logging notifications.
- **Decision:** Keep operational logs outside MCP for now.
- **Why:** MCP logging is not required for current clients and may expose implementation details if done casually.
- **Revisit when:** Designing MCP-visible logging with explicit redaction and log-level behavior.
### Ping
- **Status:** Implemented by SDK
- **Priority:** Monitor
- **Spec point:** Either party may send `ping`; receiver must respond promptly.
- **Current behavior:** Implemented by the SDK default handler.
- **Decision:** Keep inherited SDK behavior.
- **Why:** No custom project code is required.
- **Revisit when:** Lifecycle or transport code changes; include ping in future raw protocol smoke tests.
### Cancellation
- **Status:** Optional deferred
- **Priority:** Later
- **Spec point:** Cancellation notifications are optional; receivers should stop processing where possible and may ignore non-cancellable work.
- **Current behavior:** SDK handles notification plumbing; Blurt RPC calls are not actively aborted by project handlers.
- **Decision:** Defer active cancellation until long-running tools or abortable RPC wrappers justify it.
- **Why:** Most calls are short RPC queries; adding cancellation plumbing now would add complexity with limited value.
- **Revisit when:** Long-running tools are added; pass abort signals to RPC/fetch layers and test cancellation.
### Progress notifications
- **Status:** Out of scope
- **Priority:** Won't implement
- **Spec point:** Progress is optional for long-running operations.
- **Current behavior:** Not emitted by tools.
- **Decision:** Do not implement for current short request/response tools.
- **Why:** Current operations do not have meaningful progress stages.
- **Revisit when:** Long-running scans, exports or batch workflows are introduced.
### Sampling, roots and elicitation
- **Status:** Out of scope
- **Priority:** Won't implement
- **Spec point:** Server-initiated client features are optional and require negotiated client capabilities.
- **Current behavior:** Not used.
- **Decision:** Keep out of scope.
- **Why:** The server does not need model calls, filesystem roots or interactive elicitation to expose public Blurt blockchain data.
- **Revisit when:** A new feature explicitly needs client-provided roots, sampling or user elicitation.
### Error style for tool failures
- **Status:** Implemented
- **Priority:** Monitor
- **Spec point:** Tool calls may return tool-level `isError` results; transport errors should be reserved for protocol failures.
- **Current behavior:** Most tool failures return `isError: true` with text; protocol/schema failures are handled by the SDK.
- **Decision:** Keep this behavior.
- **Why:** AI clients can recover from data/API failures without treating the MCP session as broken.
- **Revisit when:** Error formatting changes; continue avoiding secret leakage in error text.
## Maintenance procedure
When reviewing this register:
1. Fetch the exact MCP specification version under review.
2. Record the installed `@modelcontextprotocol/sdk` version, `LATEST_PROTOCOL_VERSION` and supported versions.
3. Probe the live app with raw protocol requests for:
- `initialize` with the target version;
- `initialize` with SDK latest;
- unknown protocol version;
- direct operation before initialize;
- batch request body;
- HTTP `Origin` behavior;
- missing/invalid `MCP-Protocol-Version` header where applicable.
4. Compare advertised capabilities with implemented handlers.
5. Update every affected record with a status, decision and priority.
6. Update public wording if the support/conformance statement changes.
## Current publication wording
Use this wording until a stricter audit proves broader conformance:
> This server uses the Model Context Protocol TypeScript SDK and supports MCP clients negotiating protocol
> version `2025-06-18` for its implemented tools and resource-template features.
---
# Neutral infrastructure ADR
Source: docs/adr/0001-neutral-infrastructure.md
Canonical URL: https://mcp.blurt-blockchain.com/adr/0001-neutral-infrastructure.html
# ADR 0001 β The server remains neutral infrastructure
## Status
Accepted.
## Context
The Blurt MCP server exposes public Blurt blockchain data and optional posting-authority write tools to AI clients.
During the Phase 3 write-security review, an earlier roadmap considered richer operator policy files: allowed or blocked accounts, blocked communities or tags, posting quotas, and a separate preview engine. That direction risked turning the shared MCP layer into a moderation or social-policy engine.
The project should not do that because:
- the Blurt blockchain is designed around freedom of expression;
- Layer 1 already validates operation authority and protocol rules;
- posting authority cannot move funds;
- deployment-specific policy belongs outside the shared server when an operator needs it.
## Decision
The Blurt MCP server remains neutral infrastructure.
It may enforce security and transport boundaries, such as:
- refusing active and owner keys;
- requiring posting authority for write tools;
- keeping public HTTP read-only by default;
- requiring an explicit unsafe override for HTTP signing;
- letting operators choose which write tools are registered;
- supporting preview-first defaults such as `BLURT_DRY_RUN_DEFAULT=true`;
- supporting optional process-local write limits when an operator explicitly configures `BLURT_WRITE_RATE_LIMITS`; the shared server does not impose default MCP write caps.
It should not become a policy engine for:
- allowed or blocked accounts;
- allowed or blocked communities or tags;
- content moderation rules;
- social-usage scoring;
- posting quotas intended to shape speech or community behavior.
Those concerns belong in clients, wrappers, gateways, external signers, custom deployments, or forks.
## Consequences
- Phase 3 keeps neutral safety controls and removes policy-file/moderation enforcement from the roadmap.
- The server can still support deployment ergonomics, previews and capability profiles.
- Operators remain responsible for local policy if they run custom deployments.
- Future signing architecture work should keep this boundary unless a maintainer explicitly opens a new ADR.
---
# Development
Source: docs/development.md
Canonical URL: https://mcp.blurt-blockchain.com/development.html
# Development
See [CONTRIBUTING.md](https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/blob/main/CONTRIBUTING.md) for how to propose changes, and
[architecture.md](./architecture.md) for the design and project layout.
## Testing
Tests use the built-in Node test runner (`node:test`) executed through `tsx`.
```bash
npm test # offline: URI/search routing, RPC resilience, write gating, operational endpoints
npm run test:live # live (in-memory): every tool against a real Blurt RPC node
npm run test:http # live (HTTP E2E): every tool over the real Streamable HTTP transport
npm run docs:check # regenerate tool docs, validate links/npm README policy, build the docs site
npm run docs:site # build the default VitePress documentation site
npm run smoke:http # optional deployment smoke against MCP_URL or localhost:3000/mcp
npm run smoke:package # optional npm package/tarball smoke after build
npm run pack:check # build + npm pack --dry-run
npm run test:all # everything
```
Three layers, by design:
- **Offline** (`test/uri`, `test/search`, `test/resilience`, `test/write`, `test/ops`) β deterministic, no
external network. Includes a resilience test that points the client at an unresponsive local mock to
assert the RPC transport degrades gracefully (guards against the dblurt transport regression),
write-gating tests (no write tools without a write context, capability profile resolution, default HTTP
read-only behavior and the explicit unsafe HTTP override), and operational endpoint tests (`/healthz`,
`/readyz`, request logging), and package-readiness assertions (scoped name, license, bins, files). Runs in CI on every push.
- **Live, in-memory** (`test/live`) β connects an in-memory MCP client to the server and calls every
tool against `BLURT_RPC_URLS`. Validates tool logic and `@beblurt/dblurt` integration.
- **Live, HTTP E2E** (`test/http`) β boots the real Express app on an ephemeral port and drives it
through the actual Streamable HTTP transport + shared client. This is the path the in-memory client
does not exercise, where transport/client bugs surface. Run after dependency or transport changes.
## Documentation policy
- `docs/` is the canonical Markdown source for the documentation website builds.
- `npm run docs:site` builds the project-pages artifact with its project-pages base.
- `npm run docs:siteweb` builds the independent public website artifact for `https://mcp.blurt-blockchain.com/` with base `/`, plus `llms.txt`, `llms-full.txt`, `robots.txt` and `sitemap.xml`.
- The npm/GitLab README is a landing page and must use absolute links for non-anchor documentation links so navigation works from npm.
- `docs/tools.generated.md` is generated from the tool registry; do not edit it by hand.
- `docs/llms.txt` and `docs/llms-full.txt` are generated from canonical documentation sources; regenerate them with `npm run docs:llms` and do not edit them by hand.
- Run `npm run docs:check` after changing README/docs/tool descriptions. It regenerates tool docs, validates LLM retrieval files, validates local Markdown links and npm-safe README links, builds both documentation targets, then checks that generated docs are committed.
- The repository publishes the project-pages VitePress site from `docs/` on `main`.
## Releasing
Versioning follows [Semantic Versioning](https://semver.org) and the changelog is generated from
[Conventional Commits](https://www.conventionalcommits.org) using
[`commit-and-tag-version`](https://github.com/absolute-version/commit-and-tag-version).
```bash
npm run release:dry # preview the bump + changelog without writing anything
npm run release # auto-bump from commits, update CHANGELOG.md, create an annotated tag
npm run release:minor # or force a specific bump
npm run release:major
git push --follow-tags origin main
```
`feat:` bumps the minor, `fix:`/`perf:` bump the patch, and a `BREAKING CHANGE:` footer bumps the major.
The package is prepared for npm as `@blurt-blockchain/blurt-mcp-server`, but publication remains a
separate maintainer-authorized action. See [release/provenance notes](./release-provenance.md).
---
# Release/provenance
Source: docs/release-provenance.md
Canonical URL: https://mcp.blurt-blockchain.com/release-provenance.html
# Release and provenance notes
This project can be prepared for npm publication from the repository, but publication remains a separate
maintainer-authorized action. Do not publish, tag, or bump versions as part of ordinary feature work unless
the maintainer explicitly requests a release.
## Package identity
npm package name:
```text
@blurt-blockchain/blurt-mcp-server
```
Runtime bins after installation:
```text
blurt-mcp-server
blurt-mcp-stdio
```
## Pre-publish checks
Run the normal validation suite first:
```bash
npm run check:secrets
npm run docs:check
npm run typecheck
npm test
npm run build
npm run test:http
npm run test:live
```
Then verify package contents and bin metadata:
```bash
npm run pack:check
npm run smoke:package
```
`pack:check` is dry-run only. `smoke:package` creates a temporary tarball, verifies expected runtime/docs
files and bin shebangs, then removes the tarball.
## Publication
Publication is intentionally not automated in package scripts. When a maintainer approves a release, decide
first:
- version bump and changelog impact;
- Git tag timing;
- npm account / organization access;
- OTP requirements;
- whether npm provenance is supported by the chosen CI path.
Then publish from a clean, validated commit using the selected release process.
## Provenance / signing
npm provenance or signing should be enabled only when the real release pipeline supports it end-to-end.
The repository currently prepares package metadata and pack validation, but does not pretend to produce a
provenance attestation. This avoids false security claims.
---
# Final engineering review baseline
Source: architecture/FINAL_REVIEW.md
Canonical URL: https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/blob/main/architecture/FINAL_REVIEW.md
# Final engineering review β Blurt MCP Server
Review timestamp: `2026-07-06T13:39:39Z`
Repository state reviewed:
- Local HEAD: `42bab40` (`chore(release): 0.4.2`)
- Remote `origin/main`: `42bab40`
- Published npm package: `@blurt-blockchain/blurt-mcp-server@0.4.2`
- Published tarball: `https://registry.npmjs.org/@blurt-blockchain/blurt-mcp-server/-/blurt-mcp-server-0.4.2.tgz`
- GitLab pipeline for published commit: success, pipeline `2655436452`
- Working tree at review start: one intentional uncommitted documentation change, `docs/mcp-compatibility-register.md`
- This file is a review artifact. It should be updated by future major engineering reviews instead of replaced by a new one-off audit.
## Scope and method
This review evaluates whether the repository is ready to enter a normal maintenance and evolution cycle after the major architecture and documentation work completed through `0.4.2` plus the current MCP Compatibility Register redesign.
This is not an implementation plan and does not request new feature work. Findings are classified as:
- **Critical** β blocks safe operation or release; must be fixed immediately.
- **High** β serious product, security or release risk; should be fixed before the next important release.
- **Medium** β real debt or ambiguity; should be scheduled deliberately, but does not block maintenance mode.
- **Low** β small cleanup or polish; do opportunistically.
- **No action required** β reviewed area is consistent or the remaining behavior is intentionally accepted.
Validation evidence gathered for this review:
```bash
npm run check:secrets
npm run docs:check
npm run typecheck
npm test
npm run build
npm run smoke:package
npm run pack:check
npm run test:http
npm run test:live
git diff --check
npm audit --omit=dev --json
npm audit --json
```
Observed validation result:
- secret scan passed;
- documentation links and VitePress build passed;
- TypeScript typecheck passed;
- offline/unit suite passed: `64/64`;
- HTTP E2E suite passed: `24/24`;
- live MCP suite passed: `26/26`;
- package smoke passed: `file_count=73`, status `ok`;
- package dry run produced `@blurt-blockchain/blurt-mcp-server@0.4.2`;
- `git diff --check` passed;
- production and full `npm audit` reported `0` vulnerabilities.
---
# Pass 1 β Software Architect
This pass reviewed implementation, repository organization, README, VitePress documentation, MCP Compatibility Register, ADRs, architecture documents, project philosophy and project-operational guidance as if starting from the current checkout without relying on other passes.
## Findings
### P1-A1 β Deployment process-manager documentation is now narrowed to PM2
**Classification:** No action required
`docs/deployment-pm2.md` presents PM2 as the documented process-manager path. The deployment overview now lists only PM2 as the concrete documented deployment method, while the surrounding architecture language stays tool-neutral where the exact process manager is not important.
This resolves the earlier documentation ambiguity where the overview suggested additional concrete deployment paths that did not have guides.
**Evidence:**
- `docs/deployment-pm2.md` contains the concrete PM2 guide.
- `docs/deployment.md` lists PM2 as the documented process-manager method.
- `docs/architecture.md` uses generic process-manager wording for the `BLURT_ENV_FILE` architecture rule.
- `docs/usage.md` explains the `HOST=127.0.0.1` scenario in terms of running behind a local reverse proxy rather than naming process managers.
**Recommended action:** Keep deployment-tool mentions tied to actual documented guides. When the tool is not architecturally important, describe the deployment concept instead.
### P1-A2 β Stateless HTTP compatibility remains the main architectural debt
**Classification:** Medium
The project intentionally uses stateless Streamable HTTP: one fresh `McpServer`/transport per `POST /mcp`, no session id, `GET`/`DELETE` return `405`, and JSON-RPC batch arrays are rejected. This is coherent for the public endpoint and documented in `docs/architecture.md` and the Compatibility Register.
The architectural trade-off is that strict MCP HTTP lifecycle semantics are not fully enforced: a request such as `tools/list` can succeed without a prior `initialize`, and missing post-initialization `MCP-Protocol-Version` headers cannot be interpreted without session state.
This is not a newly discovered bug. It is already captured in the Compatibility Register as `Stateless compatibility mode` with `Next` priority. It does, however, remain the central reason the project should avoid stronger claims such as full Streamable HTTP conformance or MCP certification.
**Evidence:**
- `docs/mcp-compatibility-register.md` entries: `HTTP lifecycle`, `HTTP protocol-version header`.
- `src/app.ts` builds a fresh server/transport per POST and sets `sessionIdGenerator: undefined`.
- Validation confirms the currently documented behavior passes.
**Recommended action:** Treat this as a future protocol-hardening design decision, not an urgent feature. Before v1.0, either accept and document stateless compatibility mode as the permanent public endpoint model, or design stateful HTTP sessions deliberately.
### P1-A3 β Architecture and implementation are broadly aligned
**Classification:** No action required
The implementation matches the documented architecture:
- two entrypoints (`server.ts`, `server-stdio.ts`) share `buildServer()`;
- HTTP exposes `/mcp`, `/healthz`, `/readyz`;
- stdio keeps MCP protocol on stdout and logs on stderr;
- `BLURT_ENV_FILE` is the single application-runtime configuration pointer for launcher/process-manager examples;
- RPC selection is configuration-first and uses `@beblurt/blurt-nodes-checker` plus dblurt `rpcTransport: "core"`;
- Layer 1 / Nexus / external price-feed boundaries are documented;
- `search`/`fetch` and `blurt://` resource templates match the connector-style architecture;
- write tools are opt-in, local-first, posting-key-only and capability-profile gated;
- ADR 0001 accurately preserves the neutral-infrastructure boundary.
No architectural drift was found in these core areas.
### P1-A4 β Project philosophy remains internally consistent
**Classification:** No action required
The current repository consistently expresses the same philosophy across README, security docs, architecture docs, ADR and implementation:
- neutral infrastructure, not moderation policy;
- configuration-first, no hardcoded infrastructure URLs for price/RPC behavior;
- public HTTP endpoint safe by no ambient authority rather than an AI-product Origin registry;
- local-first signing with posting-key validation;
- optional operator controls rather than built-in social policy;
- deployment infrastructure owns TLS, rate limits, WAF/bot protection and host routing.
The philosophy is not merely documented; tests enforce several important pieces: JSON-RPC batch rejection, non-authoritative `Origin`, HTTP key refusal, posting-authority validation, stdio startup cleanliness and package metadata.
### P1-A5 β Compatibility Register redesign improves long-term governance but is not yet published
**Classification:** Low
The redesigned `docs/mcp-compatibility-register.md` is a better long-term architectural register than the prior wide βgapβ table. It reduces width, removes the confusing βDifference intentional?β column, and gives every item an explicit status, decision, rationale and revisit trigger.
At review time, this change is still uncommitted and therefore not present in the published npm package or the successful GitLab pipeline for `42bab40`. This is normal for work in progress, but future release/status reports should not imply that npm `0.4.2` already contains the redesigned register.
**Recommended action:** When the maintainer is ready, commit the Compatibility Register redesign and this final review together or in separate documentation commits. No source change is needed.
### P1-A6 β Repository has no in-repo agent instruction file; external Hermes skills are operational, not product architecture
**Classification:** No action required
No `AGENTS.md` / `CLAUDE.md` style file is present in the repository. That is acceptable: this project already has README, CONTRIBUTING, SECURITY, VitePress docs and architecture/ADR material. The Hermes skills used during maintenance are external operator memory, not part of the package contract.
If future contributors need agent-specific guidance, it should be a thin routing file pointing to canonical docs, not a second source of architectural truth.
---
# Pass 2 β Security Engineer
This pass reviewed MCP transport implementation, JSON-RPC handling, Streamable HTTP, stdio, signing, authority validation, posting-key restrictions, HTTP exposure, deployment model, dependencies, supply chain, configuration safety and error handling from the current checkout, independent of the architecture conclusions above.
## Findings
### P2-S1 β Public HTTP security depends on the no-ambient-authority model being preserved
**Classification:** Medium
The public endpoint intentionally does not validate `Origin` with an allow-list, despite the Streamable HTTP specification language. This is a documented divergence, tested behavior and a reasonable security posture only under the current public endpoint constraints:
- no posting key on public HTTP;
- no cookies;
- no credentialed CORS;
- no user-specific private data;
- no authenticated private resources;
- TLS/host routing/rate limits at reverse proxy or hosting infrastructure.
This is realistic and maintainable for an open public connector. The risk is not current exposure; the risk is future drift. If HTTP signing, cookies, private data, authenticated sessions or private-network capabilities are added later, the current Origin posture would need a new security design.
**Evidence:**
- `SECURITY.md`, `docs/security.md`, `docs/deployment.md` and Compatibility Register all document the model.
- `test/ops.test.ts` verifies `Origin` is treated as non-authoritative.
- `src/server.ts` refuses HTTP startup with `BLURT_POSTING_KEY` unless the explicit unsafe override is set.
**Recommended action:** No immediate change. Keep this as a hard review gate for any future privileged HTTP feature.
### P2-S2 β HTTP signing override is dangerous by design but properly gated
**Classification:** No action required
The HTTP signing override is intentionally alarming and requires an exact environment variable value:
```text
BLURT_UNSAFE_ALLOW_HTTP_SIGNING_WITH_POSTING_KEY=I_ACCEPT_FULL_RESPONSIBILITY_FOR_EXPOSING_BLURT_WRITE_TOOLS_OVER_HTTP
```
The guard does not weaken posting-key-only validation, profile gating or optional rate caps. The warning text is loud, and documentation repeatedly states not to use this on public/unauthenticated HTTP.
This is an acceptable escape hatch for private, authenticated operator deployments. Removing it is not necessary, because it is explicit and operationally useful.
**Evidence:**
- `src/utils/signer.ts` implements exact-value override and warning.
- `test/write.test.ts` covers HTTP key refusal and exact unsafe override behavior.
- `docs/write-operations.md` and `SECURITY.md` document the responsibility boundary.
### P2-S3 β Posting-key validation and write isolation are mature for current scope
**Classification:** No action required
The signing model is appropriate for a posting-authority MCP connector:
- active/owner keys are refused;
- delegated posting authority is supported;
- write context is created only after WIF parsing and Layer 1 authority validation through dblurt;
- write tools are not registered unless a validated write context is passed;
- normal HTTP refuses to start with a posting key;
- stdio logs to stderr, avoiding protocol corruption;
- dry-run defaults and capability profiles are operator controls, not hidden policy.
The write surface still depends on the security of in-process dependencies, but this is clearly documented as supply-chain trust rather than concealed.
### P2-S4 β Error handling avoids protocol crashes, but raw stack logging is acceptable only if request bodies stay out of logs
**Classification:** Low
`src/app.ts` logs internal MCP errors as stack traces and returns a generic JSON-RPC internal error when headers have not been sent. This is reasonable for operator debugging and avoids leaking stack traces to clients.
The realistic secret-leak concern is whether request bodies or private keys can appear in thrown error stacks. The current request logger never logs bodies, the signing path should not log keys, and normal public HTTP has no key. For unsafe private HTTP signing deployments, operators should still avoid `LOG_LEVEL=debug` and protect logs.
**Evidence:**
- `app.ts` logs `MCP error: stack` server-side, returns generic client error.
- `SECURITY.md` explicitly says production should use `LOG_LEVEL=info` and that signing must never log keys/raw signed transactions.
- Validation includes tests that cover signing safety behavior.
**Recommended action:** Optional future hardening: keep error logging generic around signing paths if new write tools introduce errors that include serialized operation details. No urgent action.
### P2-S5 β Dependency and supply-chain posture is acceptable for current maturity
**Classification:** No action required
The project uses a small production dependency set for its role: MCP SDK, Express, dotenv, zod, dblurt and node checker. A lockfile is present, package smoke validates tarball contents, and `npm audit` reported no known vulnerabilities in both production and full dependency trees at review time.
The release process does not claim npm provenance, which is honest. Provenance/signing can be added later when the CI release path actually supports it end-to-end.
### P2-S6 β Deployment security is deliberately externalized and documented
**Classification:** No action required
The application does not implement built-in public authentication, distributed rate limiting, WAF behavior or TLS. That is acceptable because the docs make the reverse proxy/platform boundary explicit and the public endpoint is anonymous/public-data only.
The project should resist pulling broad infrastructure policy into the server unless a concrete hosted-service requirement appears.
---
# Pass 3 β Release / Quality Engineer
This pass reviewed the repository as if approving a production open-source release: public API, MCP capabilities, documentation quality, generated documentation, VitePress site, Compatibility Register, examples, validation pipeline, tests, npm package, release process and consistency between implementation, docs, package and release flow.
## Findings
### P3-Q1 β Release validation is strong locally, but CI does not run the full release gate
**Classification:** Medium
The local validation pipeline is strong and covers docs, typecheck, offline tests, live HTTP transport, live MCP calls, package smoke and package dry-run. However, `.gitlab-ci.yml` currently runs only:
- `check:secrets`;
- `docs:check`;
- `typecheck`;
- `npm test`;
- `build`;
- Pages build/deploy.
It does not run `test:http`, `test:live`, `smoke:package` or `pack:check` in CI. This is understandable because live tests depend on public RPC/network availability and package dry-run is not always necessary on every commit. Still, from a release/quality perspective, the full release gate is currently a maintainer-local discipline rather than an enforced CI release job.
**Evidence:**
- `.gitlab-ci.yml` has no `test:http`, `test:live`, `smoke:package` or `pack:check` job.
- `docs/release-provenance.md` correctly tells maintainers to run those commands before publishing.
- The commands passed locally during this review.
**Recommended action:** Before v1.0, add a CI-safe release-check job or manual pipeline job for `pack:check` and `smoke:package`. Consider keeping live network tests manual/scheduled/non-blocking to avoid flaky merge gates.
### P3-Q2 β Published npm package is coherent and minimal
**Classification:** No action required
The package exposes exactly the intended runtime bins:
- `blurt-mcp-server` β `dist/server.js`;
- `blurt-mcp-stdio` β `dist/server-stdio.js`.
The package includes runtime `dist/`, Markdown docs, PM2 ecosystem example, README, LICENSE, CHANGELOG, SECURITY and CONTRIBUTING. It excludes local audit files, `.env` and dependencies. The smoke script verifies bin shebangs and required files.
The package does not pretend to expose a library API. That is appropriate for an MCP server package.
### P3-Q3 β Public claims are mostly delivered by implementation and tests
**Classification:** No action required
The project publicly claims:
- hosted/public HTTP endpoint for public Blurt blockchain data;
- local stdio server;
- 25 query/read tools plus opt-in write tools;
- resource templates and `search`/`fetch`;
- JSON-RPC batch rejection for MCP `2025-06-18`;
- local-first posting-key signing;
- PM2 deployment guide;
- VitePress documentation site.
Current code and validation support those claims. Live tests exercised the read tool surface through both real HTTP transport and live in-memory MCP client. Package tests assert metadata and bin behavior. Contract tests assert generated tool docs are derived from registry metadata.
### P3-Q4 β Documentation quality is high and deployment-method scope is clear
**Classification:** No action required
README, docs site, generated tool reference, security guide, write operations, architecture docs, ADR and Compatibility Register are generally consistent and mature. Deployment-method wording now reflects the current documentation strategy: PM2 is the only concrete supported process-manager guide, while generic deployment concepts are described without implying unsupported tool-specific guides.
Before v1.0, keep this boundary: add a new process-manager guide only when the project intends to maintain it.
### P3-Q5 β Compatibility Register gives honest compatibility claims
**Classification:** No action required
The restructured Compatibility Register is more useful as a release-quality artifact than the old gap table. It clearly prevents overclaiming full MCP conformance and separates implemented features, SDK-inherited behavior, intentional divergence, stateless compatibility mode, optional deferred features and out-of-scope features.
This is exactly the sort of document future release reviews should update when the MCP SDK or specification changes.
### P3-Q6 β Release process is honest but still human-centered
**Classification:** Low
The repository uses `commit-and-tag-version`, changelog generation, manual npm publish and explicit pre-publish checks. It avoids false claims about automated provenance. That is acceptable for the current project size.
The cost is that release safety depends on the maintainer actually running the documented local release gate. A future v1.0 process could add a manual GitLab release pipeline that runs package smoke/dry-run and maybe publishes with provenance, but this is not required for normal maintenance today.
### P3-Q7 β Current checkout and published package are intentionally not identical
**Classification:** Low
At review time, `npm latest` and `origin/main` both point to `0.4.2` / `42bab40`, while the local checkout contains an uncommitted redesign of `docs/mcp-compatibility-register.md` and this new review file. Therefore, the current working tree is ahead of the published package at the documentation level.
This is normal during review work. It only matters for release reporting: do not describe the current local documentation baseline as already published until it is committed, pushed and released or Pages-published.
---
# Cross-pass synthesis
## Areas of agreement
All three passes agree that the project is broadly ready for normal maintenance:
- core implementation and architecture are aligned;
- security model is explicit and coherent;
- write/signing behavior is appropriately constrained for current scope;
- documentation is unusually strong for a pre-v1 MCP server;
- validation evidence is real and recent;
- package contents match the intended product shape;
- no Critical or High findings were identified.
## Areas where the passes expose debt
The independent passes converge on three meaningful debts:
1. **MCP HTTP strictness:** stateless mode remains a documented compatibility trade-off, not full Streamable HTTP conformance.
2. **Deployment documentation boundary:** PM2 is the only concrete documented process-manager guide; generic deployment concepts should stay tool-neutral unless another guide is intentionally added.
3. **Release automation:** the full local release gate is stronger than CI, especially package smoke/dry-run and live transport checks.
These are real, but they are not blockers for maintenance mode.
---
# Final conclusion
## Overall project maturity
**Mature pre-v1 / maintenance-ready.**
The project has moved beyond prototype quality. It has a coherent product boundary, public package identity, tested HTTP and stdio transports, strong operator/security docs, generated tool contracts, packaging checks, a published docs site, and an explicit compatibility-governance register.
It should still avoid calling itself fully MCP-conformant or v1-stable until the stateless HTTP trade-off and v1 public contract questions are deliberately resolved.
## Remaining architectural debt
- **Medium:** Decide the long-term MCP HTTP posture: permanent stateless compatibility mode vs stateful Streamable HTTP sessions.
- **No action required:** Deployment-method ownership is now clear: PM2 is the only documented concrete process-manager path.
- **Low:** Keep the Compatibility Register synchronized with SDK/spec upgrades and ensure its redesigned form is committed before treating it as the baseline.
## Remaining documentation debt
- **No action required:** Deployment-method wording has been narrowed so unsupported process-manager paths are not implied.
- **Low:** After committing this review, ensure future release/status language distinguishes committed/published docs from local review artifacts.
- **Low:** Continue using the Compatibility Register as the canonical place for MCP feature/transport decisions.
## Remaining security debt
- **Medium:** The public HTTP security model remains safe only while no-ambient-authority assumptions hold. Any future privileged HTTP feature must trigger a fresh security design.
- **Low:** Error logging should remain conservative as write tools evolve, especially around unsafe HTTP signing deployments.
- **No action required:** Current posting-key validation, HTTP refusal, stdio signing model, dependency audit and package contents are acceptable.
## Remaining quality debt
- **Medium:** CI does not run the full release gate (`test:http`, `test:live`, `smoke:package`, `pack:check`). Consider CI/manual release jobs before v1.0.
- **Low:** Release process is still manual and lacks npm provenance; this is honest and acceptable today, but v1.0 may justify a more formal release pipeline.
## What should realistically be done before v1.0
1. Decide and document the final HTTP transport claim:
- permanent stateless compatibility mode, or
- stateful Streamable HTTP lifecycle/header enforcement.
2. Preserve the current deployment documentation boundary: PM2 is the concrete guide; generic deployment concepts remain tool-neutral.
3. Add a CI/manual release gate for package smoke and dry-run at minimum.
4. Keep Compatibility Register review tied to MCP SDK upgrades.
5. Define what βv1β stabilizes: tool names, resource URI forms, structured result contract, package bins and signing policy.
## What can safely wait until after v1.0
- MCP OAuth / Protected Resource Metadata for hosted protected resources.
- Streamable HTTP standalone GET/SSE support.
- Tool-list pagination.
- Resource subscriptions.
- MCP logging notifications.
- Active cancellation plumbing for short RPC calls.
- npm provenance, if release infrastructure is not ready before v1.0.
- Additional process-manager guides, unless operators specifically need them and the project intends to maintain them.
## What should probably never be implemented
- A generic moderation/social-policy engine inside the shared MCP server.
- Default account/community/tag allow/block policy files in the core server.
- A broad generic transaction-broadcast tool that bypasses per-tool schemas and client approval clarity.
- Public unauthenticated HTTP signing.
- AI-product `Origin` allow-list maintenance for the open public endpoint while the endpoint remains no-ambient-authority.
- Built-in WAF/CDN/global-abuse infrastructure inside the application.
- Full MCP feature coverage for its own sake.
## Approval answer
**Yes, with reservations.**
I would approve this repository as a mature open-source MCP server entering its normal maintenance phase.
The reservations are narrow and explicit: the project must continue to avoid overclaiming full MCP/Streamable HTTP conformance while it uses stateless HTTP compatibility mode; it should tighten deployment-method wording before v1.0; and it should improve release automation if v1.0 is meant to represent a stable public contract. None of those reservations indicate unsafe current operation or architectural incoherence. They are the right kind of remaining work for a project entering maintenance and deliberate evolution.
---
# Security policy
Source: SECURITY.md
Canonical URL: https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/blob/main/SECURITY.md
# Security Policy
## Reporting a vulnerability
Please report security issues privately via a
[GitLab issue](https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/issues) marked confidential,
or by contacting the maintainer (`@nalexadre` on the Blurt blockchain). Please do not disclose publicly until a fix
is available.
## Security model
This connector is **read-only by default**. The public HTTP server reads public Blurt blockchain data and serves it over MCP. It holds **no private keys**, performs **no signing**, and can **not** post, vote, transfer, or otherwise modify on-chain state.
Optional write tools exist for the local stdio server when the user explicitly configures a posting key. HTTP stays read-only by default and refuses to start if a posting key is present. An intentionally dangerous override exists for experienced operators of private, authenticated deployments, but it is disabled by default and must never be used for the public hosted endpoint. As long as the HTTP deployment remains read-only, its attack surface is limited to availability/abuse and to the correctness of the data returned.
## Deployment hardening (HTTP)
The HTTP endpoint (`POST /mcp`) has **no built-in authentication** and runs in stateless mode.
- **Run it behind a reverse proxy** (nginx, Caddy, Traefik, β¦). The proxy should terminate **TLS**
and handle **rate limiting** and **`Host`/origin filtering** (this also covers DNS-rebinding
concerns). The application assumes a trusted proxy in front of it. See [deployment guidance](docs/deployment.md).
- Keep the request body limit small (MCP requests are tiny; large payloads are responses, not
requests).
- The public hosted endpoint intentionally remains anonymous and **read-only**. OAuth is deferred until user-specific capabilities, quotas, preferences or private resources become real requirements.
## Private keys & write operations
The connector exposes a set of opt-in write tools β claim rewards, upvote, comment, post, follow, mute,
subscribe to a community, reblog, and mark notifications read β each signed locally. Because this
introduces a private key into the system, the following principles are **mandatory** and define how
every write tool is built.
### 1. Least privilege β posting key only
Only a Blurt blockchain **posting key** is ever used. The posting key authorizes social operations
(`vote`, `comment`, `claim_reward_balance`, and posting `custom_json` such as follow / community /
reblog / notify) but **cannot move funds** (transfers require the `active` key). Active and owner keys are **never** accepted; on startup the server verifies the key has
**posting authority** over the account β either its own posting key, or a **delegated** posting
authority (an account granted access via `account_auths`) β and refuses otherwise. Delegation is the
recommended setup: it can be revoked in one operation without rotating your key (see
[docs/write-operations.md](docs/write-operations.md)).
### 2. Write is stdio-only by default; HTTP signing requires an unsafe override
Write/signing tools are **only** registered on the local **stdio** server by default, and **only** when a valid key is present. The normal HTTP instance is public and unauthenticated; if a key is detected while running over HTTP, the server **refuses to start**.
Experienced operators may override this guard only for private, trusted, access-controlled deployments by setting the intentionally alarming environment variable below to the exact value shown:
```bash
BLURT_UNSAFE_ALLOW_HTTP_SIGNING_WITH_POSTING_KEY=I_ACCEPT_FULL_RESPONSIBILITY_FOR_EXPOSING_BLURT_WRITE_TOOLS_OVER_HTTP
```
This opt-in is disabled by default. Any other value is ignored and startup still fails. When enabled, startup prints a large warning to `stderr`. The operator is solely responsible for authentication, network isolation, reverse-proxy configuration, client behavior, monitoring and every on-chain operation signed by the process. **Do not use this mode for the public hosted endpoint or any unauthenticated LAN/WAN service.** This override does not relax posting-key-only validation, owner/active-key refusal, write-tool gating, or rate caps.
### 3. Human-in-the-loop at the signing layer
The human approval that gates a write happens **in the AI client app** (it prompts before sending a
tool call) β but this is a **client feature, not guaranteed by MCP**: some agent runners execute
tools autonomously. Therefore the connector does **not** rely on the client alone:
- **Server-side defense-in-depth**: semantic capability profiles (`BLURT_WRITE_PROFILE`, recommended
for new deployments), the backward-compatible denylist (`BLURT_WRITE_TOOLS_BANNED`, which removes
specific write tools so they are never registered), the neutral preview-first default
(`BLURT_DRY_RUN_DEFAULT=true`, which changes omitted `dry_run` parameters without restricting what
users may do), and optional **operator-configured write rate limits** (`BLURT_WRITE_RATE_LIMITS`) that
apply equally to any client when enabled. These local limits are disabled by default and are only an
extra process-local brake against accidental loops; see
[`docs/write-operations.md`](docs/write-operations.md).
- **Client-agnostic human gate (target)**: delegate signing to an external keystore/wallet that
prompts the human for each signature β **WhaleVault** (browser flows) or, ideally, the Blurt blockchain's
roadmapped **SSM Wallet** (incl. headless server mode). The connector sends an **unsigned**
operation and receives a **signed** transaction, **never touching the key**.
### 4. Compartmentalized, validated tools
Each operation is its own tool (`blurt-vote`, `blurt-comment`, `blurt-post`, `blurt-claim-rewards`),
not a single multi-purpose `broadcast` tool β so each has a tight, validated schema and a clear name
in the client's approval dialog. Parameters are **never auto-derived from fetched on-chain content**:
all content read from the chain is treated as **data, never instructions** (indirect prompt-injection
defense).
### 5. Key handling
- The key never appears in the repository. Prefer keeping it in a file **outside** the repo and
pointing the stdio launcher at it with `BLURT_ENV_FILE` (so the launcher config holds no secret and
the key is not in the working tree). The launcher's own `env` block, or a secrets mechanism, are
also acceptable; the project `.env` is not (the HTTP server refuses to start when a key is present).
- On a desktop, an **OS keychain** may be used. On a **headless server**, prefer **systemd
credentials** (`LoadCredential` / `systemd-creds`, encrypted at rest) or a **secrets manager**
(Vault, cloud KMS); a `chmod 600` env file owned by the service user is the minimum baseline.
- The key flows **only** into dblurt's local signing function β **never** to the network (only the
signed transaction is broadcast), **never** to logs, error messages, or any other dependency.
### 6. Logging
Logs go to `stderr`. The signing path must **never** log the key or a raw signed transaction. Run
production with `LOG_LEVEL=info` (not `debug`). A test asserts the signing tool does not emit the key.
## Supply chain
The signing path runs in the same process as its dependencies (dblurt, the SDK, the node checker), so
dependency trust matters once a key is present:
- A committed lockfile pins the dependency tree; `npm audit` runs in CI.
- Updates to libraries on the signing path (especially `@beblurt/dblurt`) are reviewed before
merging.
- The write path keeps its dependencies minimal.
---
# Contributing
Source: CONTRIBUTING.md
Canonical URL: https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/blob/main/CONTRIBUTING.md
# Contributing
Contributions are very welcome β this connector is meant to grow with the community, and it is the
prototype behind the Blurt blockchain's planned **public MCP**. Good first contributions: a new read-only
tool, a better tool description, or a fix.
## Workflow
1. Open an [issue](https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/issues) to discuss non-trivial changes.
2. `npm install`, make your change, and keep it green:
```bash
npm run typecheck
npm test # offline, deterministic
npm run test:all # live + HTTP E2E (hit a real RPC node)
```
3. Use [Conventional Commits](https://www.conventionalcommits.org) (`feat:`, `fix:`, `docs:`, β¦) and
open a merge request.
See [docs/development.md](docs/development.md) for the test layers and the release flow, and
[docs/architecture.md](docs/architecture.md) for the design and project layout.
## Guidelines
- **English everywhere** in code, comments and docs.
- New tools should stay **read-only** (no private keys) and ship with a verbose, LLM-oriented
description β for an AI client, the tool description *is* the interface.
- Any write/signing work must follow [SECURITY.md](SECURITY.md) (posting-key only, stdio by
default, no HTTP signing unless the explicit unsafe trusted-deployment override is in scope, no
secrets in logs).