@blurt-blockchain/blurt-mcp-server 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +118 -0
- package/LICENSE +682 -0
- package/README.md +117 -0
- package/SECURITY.md +107 -0
- package/dist/app.js +88 -0
- package/dist/buildServer.js +146 -0
- package/dist/contracts/registerBlurtTool.js +53 -0
- package/dist/contracts/toolRegistry.js +384 -0
- package/dist/resources/blurtResource.js +82 -0
- package/dist/server-stdio.js +37 -0
- package/dist/server.js +35 -0
- package/dist/tools/claimRewards.js +48 -0
- package/dist/tools/comment.js +58 -0
- package/dist/tools/compareAccounts.js +50 -0
- package/dist/tools/fetch.js +91 -0
- package/dist/tools/follow.js +39 -0
- package/dist/tools/getAccount.js +80 -0
- package/dist/tools/getAccountHistory.js +109 -0
- package/dist/tools/getAccountNotifications.js +40 -0
- package/dist/tools/getAccountPosts.js +130 -0
- package/dist/tools/getAccountRelationships.js +34 -0
- package/dist/tools/getAccountSubscriptions.js +50 -0
- package/dist/tools/getAccountWitnessVotes.js +46 -0
- package/dist/tools/getBlurtPrice.js +43 -0
- package/dist/tools/getChainStatus.js +94 -0
- package/dist/tools/getCommunity.js +75 -0
- package/dist/tools/getDelegations.js +37 -0
- package/dist/tools/getPendingRewards.js +53 -0
- package/dist/tools/getPost.js +88 -0
- package/dist/tools/getPostReblogs.js +29 -0
- package/dist/tools/getPostVotes.js +78 -0
- package/dist/tools/getPublications.js +109 -0
- package/dist/tools/getReferrals.js +39 -0
- package/dist/tools/getVoteValue.js +67 -0
- package/dist/tools/getWitness.js +46 -0
- package/dist/tools/listCommunities.js +90 -0
- package/dist/tools/listWitnesses.js +48 -0
- package/dist/tools/lookupAccounts.js +30 -0
- package/dist/tools/mute.js +39 -0
- package/dist/tools/post.js +42 -0
- package/dist/tools/readNotifications.js +35 -0
- package/dist/tools/reblog.js +39 -0
- package/dist/tools/search.js +189 -0
- package/dist/tools/subscribeCommunity.js +39 -0
- package/dist/tools/upvote.js +48 -0
- package/dist/utils/blurtUri.js +61 -0
- package/dist/utils/loadEnv.js +21 -0
- package/dist/utils/logger.js +63 -0
- package/dist/utils/price.js +21 -0
- package/dist/utils/rpc.js +126 -0
- package/dist/utils/signer.js +350 -0
- package/docs/adr/0001-neutral-infrastructure.md +50 -0
- package/docs/architecture.md +62 -0
- package/docs/cache-policy.md +42 -0
- package/docs/clients.md +78 -0
- package/docs/deployment.md +102 -0
- package/docs/development.md +51 -0
- package/docs/install-snippets.md +236 -0
- package/docs/load-testing.md +51 -0
- package/docs/operations.md +56 -0
- package/docs/release-provenance.md +63 -0
- package/docs/tools.generated.md +89 -0
- package/docs/tools.md +102 -0
- package/docs/usage.md +157 -0
- package/docs/write-operations.md +223 -0
- package/package.json +77 -0
package/docs/tools.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# Tools & resources
|
|
2
|
+
|
|
3
|
+
The server exposes **25 read-only tools** (always available) plus **opt-in write tools** (local stdio
|
|
4
|
+
by default; HTTP signing requires an explicit unsafe trusted-deployment override — see
|
|
5
|
+
[write operations](./write-operations.md)).
|
|
6
|
+
|
|
7
|
+
## Tools
|
|
8
|
+
|
|
9
|
+
| Tool | Description |
|
|
10
|
+
| --- | --- |
|
|
11
|
+
| `get-account` | Full account info: profile, wallet balances, Blurt Power, delegations, witness votes, rewards. |
|
|
12
|
+
| `get-account-history` | Account operation history, optionally filtered by operation type (vote, transfer, comment, …). |
|
|
13
|
+
| `get-account-posts` | Posts related to an account (blog, feed, posts, comments, replies, payout) via the Nexus L2 API. |
|
|
14
|
+
| `get-post` | A single post, or the full discussion tree (`with_comments=true`). |
|
|
15
|
+
| `get-publications` | Ranked posts (trending, hot, created, promoted, payout, …) via Nexus `getRankedPosts`. |
|
|
16
|
+
| `get-blurt-price` | Current BLURT price in USD and BTC from the public price feed. |
|
|
17
|
+
| `get-chain-status` | Network + market overview: head block, supply, reward fund, participation, price, market cap. |
|
|
18
|
+
| `list-communities` | Directory of Blurt communities (rank / new / subscribers), with search and pagination. |
|
|
19
|
+
| `get-community` | Details of a single community (subscribers, moderators, pending payout, …). |
|
|
20
|
+
| `get-post-votes` | Votes on a post/comment ranked by weight (rshares), for curation analysis. |
|
|
21
|
+
| `get-vote-value` | Estimated value of an account's upvote, in BLURT and USD, at a given weight. |
|
|
22
|
+
| `list-witnesses` | Top witnesses (block producers) ranked by vote weight, with missed blocks and version. |
|
|
23
|
+
| `get-witness` | Single witness details + a health read (vote weight, blocks behind head, enabled). |
|
|
24
|
+
| `get-account-witness-votes` | Which witnesses an account supports (and its proxy, if any). |
|
|
25
|
+
| `get-account-relationships` | Follower/following counts and a sample of each (social graph). |
|
|
26
|
+
| `get-pending-rewards` | Unclaimed author/curation rewards (claimable now), in BLURT and USD. |
|
|
27
|
+
| `get-account-subscriptions` | Communities an account is subscribed to, with its role in each. |
|
|
28
|
+
| `compare-accounts` | Side-by-side metrics for 2–5 accounts (BP, reach, output, earnings) in one call. |
|
|
29
|
+
| `get-referrals` | Accounts a referrer brought to Blurt (beBlurt referral system), with the total count. |
|
|
30
|
+
| `get-account-notifications` | An account's recent notifications (mentions, replies, votes, follows, reblogs) + unread count. |
|
|
31
|
+
| `get-post-reblogs` | The accounts that reblogged a post, and how many (reach signal beyond votes). |
|
|
32
|
+
| `get-delegations` | Outgoing Blurt Power delegations of an account (per delegatee), converted to BLURT. |
|
|
33
|
+
| `lookup-accounts` | Autocomplete Blurt account names by prefix (alphabetical). |
|
|
34
|
+
| `search` | Resolve a free-form query into Blurt resource links (account, history, posts, single post). |
|
|
35
|
+
| `fetch` | Retrieve the raw JSON of a Blurt resource from a `blurt://…` URI or shorthand id. |
|
|
36
|
+
|
|
37
|
+
`search` and `fetch` follow the connector convention used by ChatGPT-style clients.
|
|
38
|
+
|
|
39
|
+
Each tool ships with a verbose, LLM-oriented description (visible in the client) explaining when to
|
|
40
|
+
use it, its parameters and its output — for an AI client, the description *is* the interface.
|
|
41
|
+
|
|
42
|
+
The v1-candidate contract index is generated from source-of-truth registry metadata in
|
|
43
|
+
[`tools.generated.md`](./tools.generated.md). Regenerate it with `npm run docs:tools` and verify it
|
|
44
|
+
with `npm run docs:check`.
|
|
45
|
+
|
|
46
|
+
## Write tools (opt-in, local stdio by default)
|
|
47
|
+
|
|
48
|
+
| Tool | Description |
|
|
49
|
+
| --- | --- |
|
|
50
|
+
| `blurt-claim-rewards` | Claim the configured account's pending rewards (`claim_reward_balance`). Supports `dry_run`. |
|
|
51
|
+
| `blurt-upvote` | Upvote a post/comment as the configured account (`vote`), at a given weight. Supports `dry_run`. |
|
|
52
|
+
| `blurt-comment` | Reply to a post/comment as the configured account (`comment`). Stamps `json_metadata.app = blurt-mcp/<version>` and appends a `via Blurt-MCP` footer. Supports `dry_run`. |
|
|
53
|
+
| `blurt-post` | Publish a new top-level post (title, body, tags). Same `blurt-mcp` app stamp + footer as `blurt-comment`. Supports `dry_run`. |
|
|
54
|
+
| `blurt-follow` | Follow or unfollow an account (`custom_json` follow). Supports `dry_run`. |
|
|
55
|
+
| `blurt-mute` | Mute (ignore) or unmute an account (`custom_json` follow/ignore). Supports `dry_run`. |
|
|
56
|
+
| `blurt-subscribe-community` | Subscribe to or leave a community (`custom_json` community). Supports `dry_run`. |
|
|
57
|
+
| `blurt-reblog` | Reblog (re-share) a post to the account's blog (`custom_json` reblog), or undo it. Supports `dry_run`. |
|
|
58
|
+
| `blurt-read-notifications` | Mark the account's notifications as read up to now (`custom_json` notify). Supports `dry_run`. |
|
|
59
|
+
|
|
60
|
+
All write tools are signed locally with the posting key, **off by default**, and exposed through stdio
|
|
61
|
+
by default. `BLURT_DRY_RUN_DEFAULT=true` can make omitted `dry_run` parameters preview-first without
|
|
62
|
+
blocking explicit execution. HTTP signing is only for explicit unsafe trusted-deployment override mode.
|
|
63
|
+
See [write operations](./write-operations.md).
|
|
64
|
+
|
|
65
|
+
## Resources
|
|
66
|
+
|
|
67
|
+
Resource templates resolvable via the `fetch` tool or a resource-aware client:
|
|
68
|
+
|
|
69
|
+
- `blurt://account/{username}`
|
|
70
|
+
- `blurt://history/{username}?limit=&ops=vote,comment`
|
|
71
|
+
- `blurt://posts/{by}/{tag}?limit=` — `by` ∈ `trending|hot|created|promoted|payout|payout_comments|muted`
|
|
72
|
+
- `blurt://account-posts/{sort}/{account}?limit=` — `sort` ∈ `blog|feed|posts|comments|replies|payout`
|
|
73
|
+
- `blurt://post/{author}/{permlink}?with_comments=true`
|
|
74
|
+
|
|
75
|
+
## Example prompts
|
|
76
|
+
|
|
77
|
+
You never tell the AI which tool to use — it picks and chains them. Start simple, then push.
|
|
78
|
+
|
|
79
|
+
**Market & network**
|
|
80
|
+
- "What is the current BLURT price in USD?"
|
|
81
|
+
- "What is Blurt's market cap and how many BLURT are in circulation?"
|
|
82
|
+
- "Is the Blurt chain healthy right now?"
|
|
83
|
+
|
|
84
|
+
**Accounts & wallets**
|
|
85
|
+
- "Show me the account `nalexadre` and convert its BLURT balance to USD."
|
|
86
|
+
- "How much Blurt Power does `nalexadre` have?"
|
|
87
|
+
|
|
88
|
+
**Curation**
|
|
89
|
+
- "How much is a 100% upvote from `nalexadre` worth, in BLURT and USD?"
|
|
90
|
+
- "Who are the top 5 curators on the post `nalexadre/how-ai-can-help-curation-on-blurt-1759501073717`?"
|
|
91
|
+
|
|
92
|
+
**Communities**
|
|
93
|
+
- "What are the most popular Blurt communities?"
|
|
94
|
+
- "Find a community about photography and show me its details."
|
|
95
|
+
|
|
96
|
+
**Governance**
|
|
97
|
+
- "List the top 10 Blurt witnesses and flag any that look inactive or behind on version."
|
|
98
|
+
- "Which witnesses does `nalexadre` vote for — and are they all healthy?"
|
|
99
|
+
|
|
100
|
+
**Multi-step**
|
|
101
|
+
- "Give me a profile of `nalexadre`: bio, the USD value of their vote, and their latest post with its vote count."
|
|
102
|
+
- "Compare `nalexadre`, `megadrive` and `khrom` — stake, reach and earnings — as a table."
|
package/docs/usage.md
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Installation & usage
|
|
2
|
+
|
|
3
|
+
For connecting a specific client (Claude, ChatGPT, Cursor, …) see the
|
|
4
|
+
[client compatibility matrix](./clients.md). For local signing, see
|
|
5
|
+
[write operations](./write-operations.md).
|
|
6
|
+
|
|
7
|
+
## Requirements
|
|
8
|
+
|
|
9
|
+
- Node.js **>= 18** to run the server (uses native `fetch`/`AbortController`).
|
|
10
|
+
- Node.js **>= 20.6** for development and tests (the test runner uses `node --import tsx`).
|
|
11
|
+
- npm
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
For package-based local use, run the official npm package:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx -y -p @blurt-blockchain/blurt-mcp-server blurt-mcp-stdio
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
For source development:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
For copy-paste client configs, see [install snippets](./install-snippets.md).
|
|
28
|
+
|
|
29
|
+
## Configuration
|
|
30
|
+
|
|
31
|
+
Copy the example env file and adjust as needed:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
cp .env.example .env
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
| Variable | Default | Description |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| `PORT` | `3000` | HTTP port Express listens on. |
|
|
40
|
+
| `BLURT_RPC_URLS` | a list of public Blurt nodes | Comma-separated Blurt RPC endpoints. **Provide several**: the server scores them continuously (via [`@beblurt/blurt-nodes-checker`](https://gitlab.com/beblurt/blurt-nodes-checker)) and keeps the client on the healthiest ones; offline/stale/forked nodes are dropped. |
|
|
41
|
+
| `BLURT_PRICE_URL` | `https://api.blurt.blog/price_info` | Price feed used by the price/market tools. |
|
|
42
|
+
| `LOG_LEVEL` | `info` | `debug` \| `info` \| `warn` \| `error`. |
|
|
43
|
+
| `NODE_ENV` | `development` | `production` switches logs to JSON output. |
|
|
44
|
+
| `BLURT_CHAIN_ID` | _(mainnet)_ | Optional. Target a **testnet**: set this **and** `BLURT_ADDRESS_PREFIX`. Unset = Blurt main network (dblurt default). |
|
|
45
|
+
| `BLURT_ADDRESS_PREFIX` | _(mainnet `BLT`)_ | Optional. Testnet address prefix; set together with `BLURT_CHAIN_ID`. |
|
|
46
|
+
|
|
47
|
+
Write-related variables (`BLURT_ACCOUNT`, `BLURT_POSTING_KEY`, `BLURT_WRITE_PROFILE`,
|
|
48
|
+
`BLURT_WRITE_TOOLS_BANNED`, `BLURT_DRY_RUN_DEFAULT`, `BLURT_ENV_FILE`) are documented in
|
|
49
|
+
[write operations](./write-operations.md). The intentionally unsafe HTTP-signing override is also
|
|
50
|
+
documented there because it changes deployment posture and should be reviewed before use.
|
|
51
|
+
|
|
52
|
+
> The `/mcp` endpoint has **no built-in authentication** and is **read-only** by default — no private
|
|
53
|
+
> keys required for normal HTTP operation. Authentication is planned for a future version.
|
|
54
|
+
|
|
55
|
+
## Running the HTTP server
|
|
56
|
+
|
|
57
|
+
Development (hot reload):
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npm run dev
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Production:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm run build
|
|
67
|
+
npm start
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The server then listens on `http://localhost:<PORT>/mcp` (HTTP `POST`); `GET` and `DELETE` return
|
|
71
|
+
`405` (stateless mode). It also exposes cheap operational probes outside MCP:
|
|
72
|
+
|
|
73
|
+
- `GET /healthz` — process liveness;
|
|
74
|
+
- `GET /readyz` — readiness with non-sensitive RPC readiness counters.
|
|
75
|
+
|
|
76
|
+
> **Deploy behind a reverse proxy** (nginx, Caddy, Traefik, …). Let the proxy terminate TLS and handle
|
|
77
|
+
> rate limiting and `Host`/origin filtering. The public hosted endpoint intentionally remains anonymous
|
|
78
|
+
> and read-only. Do not expose write/signing over HTTP unless you have deliberately enabled the unsafe
|
|
79
|
+
> trusted-deployment override described in [write operations](./write-operations.md#advanced-unsafe-http-signing-for-trusted-deployments).
|
|
80
|
+
> See [SECURITY.md](../SECURITY.md) for the rationale.
|
|
81
|
+
|
|
82
|
+
### Inspecting
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm run inspector
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Launches the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) against the built server.
|
|
89
|
+
|
|
90
|
+
## Connecting an MCP client
|
|
91
|
+
|
|
92
|
+
The server speaks MCP over **Streamable HTTP** at `POST /mcp` (stateless: no session id). Use the
|
|
93
|
+
hosted instance (`https://mcp.blurt-blockchain.com/mcp`) or your own (`http://localhost:<PORT>/mcp`).
|
|
94
|
+
|
|
95
|
+
**Apps with native remote-MCP support (Claude, ChatGPT, Grok, Mistral, …):** add a custom/remote
|
|
96
|
+
connector and paste the URL — that's it.
|
|
97
|
+
|
|
98
|
+
**Desktop apps configured via a JSON file (e.g. Claude Desktop's `claude_desktop_config.json`)** speak
|
|
99
|
+
**stdio**, so bridge to the HTTP server with [`mcp-remote`](https://www.npmjs.com/package/mcp-remote)
|
|
100
|
+
— `npx` fetches it on first run:
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"mcpServers": {
|
|
105
|
+
"blurt": {
|
|
106
|
+
"command": "npx",
|
|
107
|
+
"args": ["-y", "mcp-remote", "https://mcp.blurt-blockchain.com/mcp"]
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Swap the URL for `http://localhost:<PORT>/mcp` to point at a server you run yourself.
|
|
114
|
+
|
|
115
|
+
## Run locally as a stdio server
|
|
116
|
+
|
|
117
|
+
Prefer a fully local server — no HTTP, no bridge, no hosted dependency? Use the package bin:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
npx -y -p @blurt-blockchain/blurt-mcp-server blurt-mcp-stdio
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Desktop config example:
|
|
124
|
+
|
|
125
|
+
```json
|
|
126
|
+
{
|
|
127
|
+
"mcpServers": {
|
|
128
|
+
"blurt": {
|
|
129
|
+
"command": "npx",
|
|
130
|
+
"args": ["-y", "-p", "@blurt-blockchain/blurt-mcp-server", "blurt-mcp-stdio"]
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
When developing from a source checkout instead, build once and point your client at the compiled file:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
npm install && npm run build
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
{
|
|
144
|
+
"mcpServers": {
|
|
145
|
+
"blurt": {
|
|
146
|
+
"command": "node",
|
|
147
|
+
"args": ["/absolute/path/to/blurt-mcp-server/dist/server-stdio.js"]
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
It registers the same 25 read tools and uses the same RPC node selection as the HTTP server; logs go to
|
|
154
|
+
`stderr` so they never interfere with the protocol on `stdout`. (For development: `npm run dev:stdio`.)
|
|
155
|
+
|
|
156
|
+
To enable **local signing** (claim rewards, …) on this stdio server, see
|
|
157
|
+
[write operations](./write-operations.md).
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# Write operations (signing) — opt-in, local by default
|
|
2
|
+
|
|
3
|
+
Write tools (`blurt-claim-rewards`, `blurt-upvote`, `blurt-comment`, `blurt-post`, `blurt-follow`,
|
|
4
|
+
`blurt-mute`, `blurt-subscribe-community`, `blurt-reblog`, `blurt-read-notifications`) are **off by
|
|
5
|
+
default**. They are registered **only** on the stdio server by default, and **only** when a valid
|
|
6
|
+
**posting** authority is configured. The normal HTTP server refuses to start if a posting key is
|
|
7
|
+
present; an explicitly unsafe HTTP override exists only for trusted operator-controlled deployments
|
|
8
|
+
(see [Advanced: unsafe HTTP signing for trusted deployments](#advanced-unsafe-http-signing-for-trusted-deployments)).
|
|
9
|
+
|
|
10
|
+
Read [SECURITY.md](../SECURITY.md) for the full threat model and the principles every write tool follows.
|
|
11
|
+
|
|
12
|
+
## Which key — delegated posting authority (recommended)
|
|
13
|
+
|
|
14
|
+
`BLURT_ACCOUNT` is the account you act *as*. `BLURT_POSTING_KEY` may be **either**:
|
|
15
|
+
|
|
16
|
+
1. **A delegated account's posting key (recommended).** Create/own a separate account, grant it
|
|
17
|
+
**posting authority** over `BLURT_ACCOUNT` (add it to your posting `account_auths` — most wallets
|
|
18
|
+
call this "posting authority"), and configure the MCP with **that account's** posting key. Your own
|
|
19
|
+
key is never shared, and you can **revoke** access in one operation (remove the authority) without
|
|
20
|
+
rotating any key.
|
|
21
|
+
2. **Your account's own posting key.** Simpler, but to revoke it you must change your posting key.
|
|
22
|
+
|
|
23
|
+
On startup the server validates that the key has posting authority over `BLURT_ACCOUNT` — directly, or
|
|
24
|
+
through a delegated account — and **refuses owner/active keys**. The posting authority cannot move funds.
|
|
25
|
+
|
|
26
|
+
## Recommended setup — key in a file you control, outside the repo
|
|
27
|
+
|
|
28
|
+
Put the secret in a file outside the project (e.g. `~/.config/blurt-mcp/secret.env`, `chmod 600`), and
|
|
29
|
+
point the stdio launcher at it with `BLURT_ENV_FILE` — the launcher itself carries **no secret**:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"mcpServers": {
|
|
34
|
+
"blurt": {
|
|
35
|
+
"command": "node",
|
|
36
|
+
"args": ["/absolute/path/to/blurt-mcp-server/dist/server-stdio.js"],
|
|
37
|
+
"env": { "BLURT_ENV_FILE": "/home/you/.config/blurt-mcp/secret.env" }
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# ~/.config/blurt-mcp/secret.env (chmod 600)
|
|
45
|
+
BLURT_ACCOUNT=youraccount
|
|
46
|
+
BLURT_POSTING_KEY=5J...
|
|
47
|
+
# recommended for new users — claim rewards + upvote only:
|
|
48
|
+
BLURT_WRITE_PROFILE=curator
|
|
49
|
+
# optional — subtract individual tools from the selected profile:
|
|
50
|
+
# BLURT_WRITE_TOOLS_BANNED=upvote
|
|
51
|
+
# optional neutral safety default — omitted dry_run parameters preview first:
|
|
52
|
+
# BLURT_DRY_RUN_DEFAULT=true
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The server loads `BLURT_ENV_FILE` (or, if unset, the project's `.env`) regardless of the working
|
|
56
|
+
directory the desktop app launches it from. Variables already set in the launcher's `env` block take
|
|
57
|
+
precedence over the file, so you can also place the values directly in `env` if you prefer.
|
|
58
|
+
|
|
59
|
+
> Do **not** put the posting key in the project's `.env`: the HTTP server would then refuse to start,
|
|
60
|
+
> and the secret would live inside the working tree. Keep it in a file outside the repo.
|
|
61
|
+
|
|
62
|
+
## Guarantees
|
|
63
|
+
|
|
64
|
+
- Only the **posting** key is accepted (active/owner are refused; it cannot move funds). The key is
|
|
65
|
+
used solely for local signing — never sent to the network, logs, or other dependencies.
|
|
66
|
+
- Write tools are registered **only** on the stdio server by default, gated by the validated key and
|
|
67
|
+
the `BLURT_WRITE_TOOLS_BANNED` denylist. The HTTP server refuses to start with a key unless the
|
|
68
|
+
operator explicitly enables the unsafe trusted-deployment override below.
|
|
69
|
+
- Calls are rate-limited (per tool).
|
|
70
|
+
|
|
71
|
+
Every write tool supports `dry_run: true` to preview **without** broadcasting, and your AI client also
|
|
72
|
+
prompts you to approve each tool call before it runs. Operators who prefer preview-first behavior can
|
|
73
|
+
set `BLURT_DRY_RUN_DEFAULT=true`; omitted `dry_run` parameters then default to preview mode, while an
|
|
74
|
+
explicit `dry_run: false` still executes the operation.
|
|
75
|
+
|
|
76
|
+
### Neutral infrastructure boundary
|
|
77
|
+
|
|
78
|
+
The official server intentionally does **not** enforce content, account, tag, community or social-usage
|
|
79
|
+
policy. It validates signing authority, protects unsafe transports by default, lets operators choose
|
|
80
|
+
which write tools are registered, and can default calls to dry-run mode. It does not implement allow/block
|
|
81
|
+
lists for accounts or communities, posting quotas, or moderation policy files; those belong in clients,
|
|
82
|
+
wrappers, gateways, external signers, custom deployments, or forks when an operator needs them. See
|
|
83
|
+
[ADR 0001](./adr/0001-neutral-infrastructure.md).
|
|
84
|
+
|
|
85
|
+
### Enabling tools with capability profiles
|
|
86
|
+
|
|
87
|
+
`BLURT_WRITE_PROFILE` is the recommended control for new deployments. It enables a semantic set of
|
|
88
|
+
capabilities, so operators do not need to maintain a long comma-separated list of every tool and do not
|
|
89
|
+
need to edit config just because a future release adds a tool that clearly belongs to the same profile.
|
|
90
|
+
|
|
91
|
+
If `BLURT_WRITE_PROFILE` is **unset**, the server preserves the historical behavior for backward
|
|
92
|
+
compatibility: all current write tools are enabled, and `BLURT_WRITE_TOOLS_BANNED` subtracts specific
|
|
93
|
+
ones.
|
|
94
|
+
|
|
95
|
+
Recommended starting point:
|
|
96
|
+
|
|
97
|
+
```dotenv
|
|
98
|
+
BLURT_WRITE_PROFILE=curator
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Profiles:
|
|
102
|
+
|
|
103
|
+
| Profile | Enables | Intended operator posture |
|
|
104
|
+
| --- | --- | --- |
|
|
105
|
+
| `none` | no write tools | Keep a key configured but temporarily expose no write surface. |
|
|
106
|
+
| `curator` | `claim-rewards`, `upvote` | Safer new-user default: rewards + voting only. |
|
|
107
|
+
| `social` | `curator` plus `follow`, `mute`, `subscribe-community`, `read-notifications`, `reblog` | Social/community actions, but no original text publishing. |
|
|
108
|
+
| `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. |
|
|
109
|
+
| `full` | every write tool in this release | Explicit full-access mode; equivalent to legacy unset-profile behavior for current tools. |
|
|
110
|
+
|
|
111
|
+
`BLURT_WRITE_TOOLS_BANNED` remains supported as a backward-compatible subtractive control. It always
|
|
112
|
+
removes individual tools from whichever profile is active (or from legacy `full` mode when no profile
|
|
113
|
+
is set). For example, a social operator that wants to allow follows/community/reblogs but not upvotes:
|
|
114
|
+
|
|
115
|
+
```dotenv
|
|
116
|
+
BLURT_WRITE_PROFILE=social
|
|
117
|
+
BLURT_WRITE_TOOLS_BANNED=upvote
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Use the **tool name** column below for denylist entries. Unknown denylist names are ignored so old
|
|
121
|
+
configuration remains forward-compatible across releases; an unknown `BLURT_WRITE_PROFILE` fails
|
|
122
|
+
closed at startup.
|
|
123
|
+
|
|
124
|
+
| Tool | Tool name | Operation | Rate cap | Profiles |
|
|
125
|
+
| --- | --- | --- | ---: | --- |
|
|
126
|
+
| `blurt-claim-rewards` | `claim-rewards` | `claim_reward_balance` | 6 / hour | `curator`, `social`, `publisher`, `full` |
|
|
127
|
+
| `blurt-upvote` | `upvote` | `vote` | 30 / hour | `curator`, `social`, `publisher`, `full` |
|
|
128
|
+
| `blurt-comment` | `comment` | `comment` (reply) | 10 / hour | `publisher`, `full` |
|
|
129
|
+
| `blurt-post` | `post` | `comment` (top-level) | 10 / hour | `publisher`, `full` |
|
|
130
|
+
| `blurt-follow` | `follow` | `custom_json` follow | 30 / hour | `social`, `publisher`, `full` |
|
|
131
|
+
| `blurt-mute` | `mute` | `custom_json` follow/ignore | 30 / hour | `social`, `publisher`, `full` |
|
|
132
|
+
| `blurt-subscribe-community` | `subscribe-community` | `custom_json` community | 30 / hour | `social`, `publisher`, `full` |
|
|
133
|
+
| `blurt-reblog` | `reblog` | `custom_json` reblog | 30 / hour | `social`, `publisher`, `full` |
|
|
134
|
+
| `blurt-read-notifications` | `read-notifications` | `custom_json` notify | 30 / hour | `social`, `publisher`, `full` |
|
|
135
|
+
|
|
136
|
+
### Advanced: unsafe HTTP signing for trusted deployments
|
|
137
|
+
|
|
138
|
+
The default and recommended signing mode is still **local stdio**. However, experienced operators who
|
|
139
|
+
run a private, authenticated, access-controlled deployment may deliberately opt in to exposing the same
|
|
140
|
+
write tools over the HTTP MCP endpoint.
|
|
141
|
+
|
|
142
|
+
This is intentionally hard to enable. You must configure a valid write context (`BLURT_ACCOUNT` and
|
|
143
|
+
`BLURT_POSTING_KEY`) and set this exact environment variable/value on the HTTP server process:
|
|
144
|
+
|
|
145
|
+
```dotenv
|
|
146
|
+
BLURT_UNSAFE_ALLOW_HTTP_SIGNING_WITH_POSTING_KEY=I_ACCEPT_FULL_RESPONSIBILITY_FOR_EXPOSING_BLURT_WRITE_TOOLS_OVER_HTTP
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Any other value is ignored and the HTTP server still refuses to start with `BLURT_POSTING_KEY` set.
|
|
150
|
+
When the override is active, startup prints a large `UNSAFE HTTP SIGNING ENABLED` warning to `stderr`.
|
|
151
|
+
The override does **not** weaken the other write policies: active/owner keys are still refused, posting
|
|
152
|
+
authority is still validated, `BLURT_WRITE_TOOLS_BANNED` still applies, and rate caps still apply.
|
|
153
|
+
|
|
154
|
+
Use this only when the HTTP endpoint is protected by your own authentication, TLS, network isolation,
|
|
155
|
+
reverse-proxy controls, monitoring, and operational procedures. Do **not** use it for the public hosted
|
|
156
|
+
endpoint, an anonymous service, or an unauthenticated LAN/WAN deployment. The operator accepts full
|
|
157
|
+
responsibility for every on-chain operation signed by that process. See [SECURITY.md](../SECURITY.md)
|
|
158
|
+
for the full rationale and threat model.
|
|
159
|
+
|
|
160
|
+
## `blurt-claim-rewards`
|
|
161
|
+
|
|
162
|
+
Claims the configured account's pending author/curation rewards (`claim_reward_balance`), moving them
|
|
163
|
+
into the account's balance and Blurt Power. Acts only on the configured account; no parameter targets
|
|
164
|
+
another account. Returns the pending amounts and, when executed, the transaction id.
|
|
165
|
+
|
|
166
|
+
## `blurt-upvote`
|
|
167
|
+
|
|
168
|
+
Upvotes a post or comment (`vote`) as the configured account.
|
|
169
|
+
|
|
170
|
+
- Parameters: `author`, `permlink`, `weight` (percent, 1-100, default 100), `dry_run`.
|
|
171
|
+
- Only the configured account votes; on chain, weight 100% = 10000.
|
|
172
|
+
|
|
173
|
+
## `blurt-comment`
|
|
174
|
+
|
|
175
|
+
Posts a reply (`comment`) to a post or comment as the configured account.
|
|
176
|
+
|
|
177
|
+
- Parameters: `parent_author`, `parent_permlink`, `body` (markdown), `dry_run`.
|
|
178
|
+
- A unique permlink is generated automatically. The body gets a `via Blurt-MCP` footer (linking back
|
|
179
|
+
to this repository) appended after a blank line, and `json_metadata.app` is set to `blurt-mcp/<version>`.
|
|
180
|
+
- Posts are **public and permanent** — use `dry_run: true` first to review the exact final body.
|
|
181
|
+
|
|
182
|
+
## `blurt-post`
|
|
183
|
+
|
|
184
|
+
Publishes a **new top-level post** (`comment` with an empty parent) as the configured account.
|
|
185
|
+
|
|
186
|
+
- Parameters: `title`, `body` (markdown), `tags` (1–8 lowercase tags; the first is the main category),
|
|
187
|
+
`dry_run`.
|
|
188
|
+
- A unique permlink is generated from the title. Same `via Blurt-MCP` footer and `json_metadata.app =
|
|
189
|
+
blurt-mcp/<version>` stamping as `blurt-comment`; the tags are stored in `json_metadata.tags`.
|
|
190
|
+
- Posts are **public and permanent** — use `dry_run: true` first to review the exact final post.
|
|
191
|
+
|
|
192
|
+
## `blurt-follow`
|
|
193
|
+
|
|
194
|
+
Follows or unfollows another account (`custom_json` id `follow`).
|
|
195
|
+
|
|
196
|
+
- Parameters: `account`, `action` (`follow` | `unfollow`, default `follow`), `dry_run`.
|
|
197
|
+
|
|
198
|
+
## `blurt-mute`
|
|
199
|
+
|
|
200
|
+
Mutes (ignores) or unmutes another account (`custom_json` id `follow`, `what: ['ignore']`), hiding its
|
|
201
|
+
content in compatible frontends.
|
|
202
|
+
|
|
203
|
+
- Parameters: `account`, `action` (`mute` | `unmute`, default `mute`), `dry_run`.
|
|
204
|
+
|
|
205
|
+
## `blurt-subscribe-community`
|
|
206
|
+
|
|
207
|
+
Subscribes the account to a community, or unsubscribes from it (`custom_json` id `community`).
|
|
208
|
+
|
|
209
|
+
- Parameters: `community` (name/id, e.g. `blurt-192372`), `action` (`subscribe` | `unsubscribe`,
|
|
210
|
+
default `subscribe`), `dry_run`.
|
|
211
|
+
|
|
212
|
+
## `blurt-reblog`
|
|
213
|
+
|
|
214
|
+
Reblogs (re-shares) a post to the account's blog (`custom_json` id `reblog`), or removes a prior reblog.
|
|
215
|
+
|
|
216
|
+
- Parameters: `author`, `permlink`, `undo` (default `false`), `dry_run`.
|
|
217
|
+
|
|
218
|
+
## `blurt-read-notifications`
|
|
219
|
+
|
|
220
|
+
Marks the account's notifications as read up to now (`custom_json` id `notify`, `setLastRead`). Acts
|
|
221
|
+
only on the configured account; no parameter targets another account.
|
|
222
|
+
|
|
223
|
+
- Parameter: `dry_run`. Pair with `get-account-notifications` to read them first.
|
package/package.json
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@blurt-blockchain/blurt-mcp-server",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Model Context Protocol (MCP) server exposing the Blurt blockchain (accounts, history, posts) over Streamable HTTP.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"author": "nalexadre - Blurt blockchain",
|
|
7
|
+
"license": "GPL-3.0-or-later",
|
|
8
|
+
"homepage": "https://gitlab.com/blurt-blockchain/blurt-mcp-server",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://gitlab.com/blurt-blockchain/blurt-mcp-server.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://gitlab.com/blurt-blockchain/blurt-mcp-server/-/issues"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"blurt",
|
|
18
|
+
"blockchain",
|
|
19
|
+
"mcp",
|
|
20
|
+
"model-context-protocol",
|
|
21
|
+
"dblurt"
|
|
22
|
+
],
|
|
23
|
+
"engines": {
|
|
24
|
+
"node": ">=18"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"dev": "tsx watch src/server.ts",
|
|
28
|
+
"start": "node dist/server.js",
|
|
29
|
+
"start:stdio": "node dist/server-stdio.js",
|
|
30
|
+
"dev:stdio": "tsx src/server-stdio.ts",
|
|
31
|
+
"inspector": "npx @modelcontextprotocol/inspector dist/server.js",
|
|
32
|
+
"build": "tsc -p tsconfig.json",
|
|
33
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
34
|
+
"check:secrets": "node scripts/check-secrets.mjs",
|
|
35
|
+
"docs:tools": "tsx scripts/generate-tool-docs.ts",
|
|
36
|
+
"docs:check": "npm run docs:tools && git diff --exit-code docs/tools.generated.md",
|
|
37
|
+
"test": "node --import tsx --test test/uri.test.ts test/search.test.ts test/contract.test.ts test/resilience.test.ts test/write.test.ts test/ops.test.ts test/package.test.ts test/stdio.test.ts test/network.test.ts",
|
|
38
|
+
"test:live": "node --import tsx --test test/live.test.ts",
|
|
39
|
+
"test:http": "node --import tsx --test test/http.test.ts",
|
|
40
|
+
"smoke:http": "node scripts/smoke-http.mjs",
|
|
41
|
+
"test:all": "node --import tsx --test test/*.test.ts",
|
|
42
|
+
"release": "commit-and-tag-version",
|
|
43
|
+
"release:minor": "commit-and-tag-version --release-as minor",
|
|
44
|
+
"release:major": "commit-and-tag-version --release-as major",
|
|
45
|
+
"release:dry": "commit-and-tag-version --dry-run",
|
|
46
|
+
"pack:check": "npm run build && npm pack --dry-run",
|
|
47
|
+
"smoke:package": "node scripts/smoke-package.mjs"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@beblurt/blurt-nodes-checker": "^2.2.0",
|
|
51
|
+
"@beblurt/dblurt": "^0.15.0",
|
|
52
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
53
|
+
"dotenv": "^17.4.2",
|
|
54
|
+
"express": "^5.2.1",
|
|
55
|
+
"zod": "^4.4.3"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@types/express": "^5.0.6",
|
|
59
|
+
"@types/node": "^26.0.1",
|
|
60
|
+
"commit-and-tag-version": "^12.7.3",
|
|
61
|
+
"tsx": "^4.22.4",
|
|
62
|
+
"typescript": "^5.9.3"
|
|
63
|
+
},
|
|
64
|
+
"main": "dist/server.js",
|
|
65
|
+
"bin": {
|
|
66
|
+
"blurt-mcp-server": "dist/server.js",
|
|
67
|
+
"blurt-mcp-stdio": "dist/server-stdio.js"
|
|
68
|
+
},
|
|
69
|
+
"files": [
|
|
70
|
+
"dist/",
|
|
71
|
+
"docs/",
|
|
72
|
+
"README.md",
|
|
73
|
+
"LICENSE",
|
|
74
|
+
"CHANGELOG.md",
|
|
75
|
+
"SECURITY.md"
|
|
76
|
+
]
|
|
77
|
+
}
|