exfer-mcp 0.1.0__tar.gz
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.
- exfer_mcp-0.1.0/.gitignore +31 -0
- exfer_mcp-0.1.0/CHANGELOG.md +20 -0
- exfer_mcp-0.1.0/LICENSE +21 -0
- exfer_mcp-0.1.0/PKG-INFO +213 -0
- exfer_mcp-0.1.0/README.md +180 -0
- exfer_mcp-0.1.0/pyproject.toml +113 -0
- exfer_mcp-0.1.0/src/exfer_mcp/__init__.py +24 -0
- exfer_mcp-0.1.0/src/exfer_mcp/_version.py +1 -0
- exfer_mcp-0.1.0/src/exfer_mcp/config.py +102 -0
- exfer_mcp-0.1.0/src/exfer_mcp/server.py +99 -0
- exfer_mcp-0.1.0/src/exfer_mcp/tools/__init__.py +56 -0
- exfer_mcp-0.1.0/src/exfer_mcp/tools/_common.py +92 -0
- exfer_mcp-0.1.0/src/exfer_mcp/tools/address.py +79 -0
- exfer_mcp-0.1.0/src/exfer_mcp/tools/payment_uri.py +104 -0
- exfer_mcp-0.1.0/src/exfer_mcp/tools/transfer.py +145 -0
- exfer_mcp-0.1.0/src/exfer_mcp/tools/wait.py +70 -0
- exfer_mcp-0.1.0/tests/__init__.py +0 -0
- exfer_mcp-0.1.0/tests/conftest.py +60 -0
- exfer_mcp-0.1.0/tests/test_tools.py +257 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Python build artifacts
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
build/
|
|
6
|
+
dist/
|
|
7
|
+
*.egg-info/
|
|
8
|
+
|
|
9
|
+
# venvs
|
|
10
|
+
.venv/
|
|
11
|
+
venv/
|
|
12
|
+
env/
|
|
13
|
+
|
|
14
|
+
# tooling caches
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
.coverage
|
|
19
|
+
htmlcov/
|
|
20
|
+
|
|
21
|
+
# editor
|
|
22
|
+
.vscode/
|
|
23
|
+
.idea/
|
|
24
|
+
*.swp
|
|
25
|
+
|
|
26
|
+
# uv lock — opt-in
|
|
27
|
+
uv.lock
|
|
28
|
+
|
|
29
|
+
# assistant runtime state
|
|
30
|
+
.claude/
|
|
31
|
+
.gstack/
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0
|
|
4
|
+
|
|
5
|
+
Initial release. Seven tools wrapping the `exfer-walletd` v1.9 Read +
|
|
6
|
+
Spend surface (via `exfer-walletd>=0.8.0`):
|
|
7
|
+
|
|
8
|
+
- `exfer_generate_address`
|
|
9
|
+
- `exfer_get_balance`
|
|
10
|
+
- `exfer_simulate_transfer`
|
|
11
|
+
- `exfer_transfer`
|
|
12
|
+
- `exfer_wait_for_tx`
|
|
13
|
+
- `exfer_payment_uri_encode`
|
|
14
|
+
- `exfer_payment_uri_decode`
|
|
15
|
+
|
|
16
|
+
stdio transport. Auth via `WALLETD_URL` + `WALLETD_AUTH_TOKEN` env
|
|
17
|
+
vars; optional TLS pinning via `WALLETD_FINGERPRINT`. Errors from
|
|
18
|
+
walletd (insufficient balance, wait-timeout, indexer-not-configured)
|
|
19
|
+
surface as MCP `isError=true` content with one-line plain-English
|
|
20
|
+
summaries so the agent can react instead of crashing the conversation.
|
exfer_mcp-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Exfer community contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
exfer_mcp-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: exfer-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Model Context Protocol server for the Exfer blockchain — gives an AI agent direct, typed access to an exfer-walletd hot wallet
|
|
5
|
+
Project-URL: Homepage, https://github.com/exfer-stack/exfer-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/exfer-stack/exfer-mcp
|
|
7
|
+
Project-URL: Bug Tracker, https://github.com/exfer-stack/exfer-mcp/issues
|
|
8
|
+
Project-URL: exfer-walletd (Rust daemon), https://github.com/exfer-stack/exfer-walletd
|
|
9
|
+
Project-URL: exfer-walletd (Python SDK), https://github.com/exfer-stack/exfer-py
|
|
10
|
+
Author: exfer-stack
|
|
11
|
+
License: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: agent,crypto,exfer,mcp,wallet
|
|
14
|
+
Classifier: Development Status :: 3 - Alpha
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: <3.14,>=3.10
|
|
24
|
+
Requires-Dist: exfer-walletd<1.0,>=0.8.0
|
|
25
|
+
Requires-Dist: mcp<2.0,>=1.0
|
|
26
|
+
Provides-Extra: dev
|
|
27
|
+
Requires-Dist: mypy<2.0,>=1.10; extra == 'dev'
|
|
28
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
29
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
30
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
31
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
32
|
+
Description-Content-Type: text/markdown
|
|
33
|
+
|
|
34
|
+
# exfer-mcp
|
|
35
|
+
|
|
36
|
+
Model Context Protocol server for the [Exfer](https://github.com/ahuman-exfer/exfer) blockchain. Gives an AI agent (Claude Desktop, Claude Code, any MCP-aware host) typed, direct access to an [`exfer-walletd`](https://github.com/exfer-stack/exfer-walletd) hot wallet.
|
|
37
|
+
|
|
38
|
+
> ⚠️ **This is a hot wallet.** Anything that can talk to this MCP server can spend funds — there are no per-period caps, no human-approval gates, no rate limits beyond walletd's own. Until walletd ships the v1.10 allowance ledger, run `exfer-mcp` only against accounts you would be okay losing in full.
|
|
39
|
+
|
|
40
|
+
## What it exposes
|
|
41
|
+
|
|
42
|
+
Seven v0.1 tools — enough for the "Hello World agent flow" of generating an address, simulating a transfer, sending it, and waiting for confirmation:
|
|
43
|
+
|
|
44
|
+
| Tool | What it does |
|
|
45
|
+
|---|---|
|
|
46
|
+
| `exfer_generate_address` | Create a new managed wallet address |
|
|
47
|
+
| `exfer_get_balance` | Confirmed balance of a managed address |
|
|
48
|
+
| `exfer_simulate_transfer` | Dry-run a payment — exact fee + inputs, no broadcast |
|
|
49
|
+
| `exfer_transfer` | Build, sign, broadcast a payment |
|
|
50
|
+
| `exfer_wait_for_tx` | Block until a tx reaches a confirmation depth |
|
|
51
|
+
| `exfer_payment_uri_encode` | Build a BIP21-style `exfer:` URI |
|
|
52
|
+
| `exfer_payment_uri_decode` | Parse a BIP21-style `exfer:` URI |
|
|
53
|
+
|
|
54
|
+
HTLC swap tools, attestation / reputation lookups, and `htlc_list` are out of v0.1 scope — tracked for v0.2.
|
|
55
|
+
|
|
56
|
+
## Install
|
|
57
|
+
|
|
58
|
+
### Recommended — `uvx` (zero global install)
|
|
59
|
+
|
|
60
|
+
`uvx` runs the server in an isolated, on-demand environment. No `pip install`, no virtual-env management, no PATH wrestling. The host (Claude Desktop / Claude Code / Cursor / …) spawns it on demand and uv handles the rest.
|
|
61
|
+
|
|
62
|
+
Install `uv` once:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
# macOS / Linux
|
|
66
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
67
|
+
|
|
68
|
+
# Windows
|
|
69
|
+
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Then wire `uvx exfer-mcp` into your MCP host config — examples below. The first time the host launches the server, uv fetches the package from PyPI; subsequent runs are cached.
|
|
73
|
+
|
|
74
|
+
### Fallback — `pip install`
|
|
75
|
+
|
|
76
|
+
For developer / CI use, or environments where adding `uv` is awkward:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install exfer-mcp # installs the `exfer-mcp` console script
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Requires Python ≥ 3.10. Pulls `exfer-walletd ≥ 0.8.0` (the JSON-RPC client) and `mcp ≥ 1.0` (the MCP server framework).
|
|
83
|
+
|
|
84
|
+
## Configure (Claude Desktop)
|
|
85
|
+
|
|
86
|
+
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS (or the equivalent path on your OS), then restart Claude Desktop:
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"mcpServers": {
|
|
91
|
+
"exfer": {
|
|
92
|
+
"command": "uvx",
|
|
93
|
+
"args": ["exfer-mcp"],
|
|
94
|
+
"env": {
|
|
95
|
+
"WALLETD_URL": "http://127.0.0.1:7448",
|
|
96
|
+
"WALLETD_AUTH_TOKEN": "<paste your walletd token here>"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The token is whatever `exfer-walletd` was started with — by default it's written to `~/.exfer-walletd/token` on first run (`chmod 0600`).
|
|
104
|
+
|
|
105
|
+
If walletd is running with `--tls` and a self-signed cert, pin its fingerprint:
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"mcpServers": {
|
|
110
|
+
"exfer": {
|
|
111
|
+
"command": "uvx",
|
|
112
|
+
"args": ["exfer-mcp"],
|
|
113
|
+
"env": {
|
|
114
|
+
"WALLETD_URL": "https://127.0.0.1:7448",
|
|
115
|
+
"WALLETD_AUTH_TOKEN": "<token>",
|
|
116
|
+
"WALLETD_FINGERPRINT": "sha256:<paste from cert.fingerprint>"
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
For a publicly-fronted walletd (e.g. behind a reverse proxy with a CA-signed cert), drop the `WALLETD_FINGERPRINT` field — the SDK falls back to the system CA chain.
|
|
124
|
+
|
|
125
|
+
### Pin a specific version
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
"args": ["exfer-mcp@0.1.0"]
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Configure (Claude Code)
|
|
132
|
+
|
|
133
|
+
One-shot via `claude mcp add`:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
claude mcp add exfer \
|
|
137
|
+
-e WALLETD_URL=http://127.0.0.1:7448 \
|
|
138
|
+
-e WALLETD_AUTH_TOKEN=<token> \
|
|
139
|
+
-- uvx exfer-mcp
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Or by editing the project / global Claude Code MCP config directly:
|
|
143
|
+
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"mcpServers": {
|
|
147
|
+
"exfer": {
|
|
148
|
+
"command": "uvx",
|
|
149
|
+
"args": ["exfer-mcp"],
|
|
150
|
+
"env": {
|
|
151
|
+
"WALLETD_URL": "http://127.0.0.1:7448",
|
|
152
|
+
"WALLETD_AUTH_TOKEN": "<token>"
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Configure (other MCP hosts)
|
|
160
|
+
|
|
161
|
+
Cursor, Cline, Continue.dev, and most other MCP-aware hosts accept the same `command` / `args` / `env` shape. Use the `uvx exfer-mcp` invocation above.
|
|
162
|
+
|
|
163
|
+
## Environment
|
|
164
|
+
|
|
165
|
+
| Variable | Required | Default | Meaning |
|
|
166
|
+
|---|---|---|---|
|
|
167
|
+
| `WALLETD_URL` | ✓ | — | walletd base URL |
|
|
168
|
+
| `WALLETD_AUTH_TOKEN` | ✓ | — | walletd bearer token |
|
|
169
|
+
| `WALLETD_FINGERPRINT` | only for `https://` with a self-signed cert | — | SHA-256 of walletd's TLS cert (`sha256:<hex>`) |
|
|
170
|
+
| `EXFER_MCP_DEFAULT_FEE_RATE` | | walletd default | fee_rate (exfers/byte) for spends when the agent didn't specify |
|
|
171
|
+
| `EXFER_MCP_HTTPX_TIMEOUT` | | 30 | per-RPC timeout in seconds |
|
|
172
|
+
|
|
173
|
+
## Recommended agent flow
|
|
174
|
+
|
|
175
|
+
When the user asks the agent to send a payment, the expected sequence is:
|
|
176
|
+
|
|
177
|
+
1. `exfer_simulate_transfer` → compute exact fee
|
|
178
|
+
2. Show the user the fee and ask for confirmation
|
|
179
|
+
3. `exfer_transfer` → broadcast
|
|
180
|
+
4. `exfer_wait_for_tx` → confirm
|
|
181
|
+
|
|
182
|
+
The simulate-first pattern means the agent always knows the cost before committing. The user is the one who decides whether the cost is acceptable.
|
|
183
|
+
|
|
184
|
+
## Safety
|
|
185
|
+
|
|
186
|
+
- `WALLETD_AUTH_TOKEN` is **all-or-nothing access to the wallet**. Treat it like a payment-card number.
|
|
187
|
+
- `exfer-mcp` does no per-call confirmation by itself — that's the host's job. If you need spend caps, configure them on the walletd side (planned for v1.10) or run a walletd that only holds a small float you would be comfortable losing.
|
|
188
|
+
- The MCP transport is stdio. The agent does not see the wire token; only this process does.
|
|
189
|
+
- Errors from walletd surface as MCP `isError=true` content the agent reads and reacts to, including specific cases like `InsufficientBalanceError` (over-spend) and `WaitTimeoutError` (confirmation depth not reached in time).
|
|
190
|
+
|
|
191
|
+
## Coming soon
|
|
192
|
+
|
|
193
|
+
- **`.mcpb` desktop bundle** — Anthropic's one-click `.mcpb` install format for Claude Desktop, with the env vars surfaced as a form at install time.
|
|
194
|
+
- **v0.2 tools** — HTLC trio (`exfer_htlc_lock` / `exfer_htlc_claim` / `exfer_htlc_reclaim`), `exfer_htlc_status`, attestation queries (`exfer_get_attestation_edges`).
|
|
195
|
+
- **MCP directory** — submission to Anthropic's curated MCP directory + community directories.
|
|
196
|
+
|
|
197
|
+
## Development
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
git clone https://github.com/exfer-stack/exfer-mcp
|
|
201
|
+
cd exfer-mcp
|
|
202
|
+
uv venv && source .venv/bin/activate
|
|
203
|
+
uv pip install -e '.[dev]'
|
|
204
|
+
pytest # unit tests
|
|
205
|
+
mypy && ruff check # lint
|
|
206
|
+
python -m scripts.e2e_smoke # end-to-end smoke (needs a live walletd)
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
See [`scripts/e2e_smoke.py`](scripts/e2e_smoke.py) for a runnable example that exercises the full Exfer stack — walletd, indexer, MCP — against a real deployment.
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
MIT
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
# exfer-mcp
|
|
2
|
+
|
|
3
|
+
Model Context Protocol server for the [Exfer](https://github.com/ahuman-exfer/exfer) blockchain. Gives an AI agent (Claude Desktop, Claude Code, any MCP-aware host) typed, direct access to an [`exfer-walletd`](https://github.com/exfer-stack/exfer-walletd) hot wallet.
|
|
4
|
+
|
|
5
|
+
> ⚠️ **This is a hot wallet.** Anything that can talk to this MCP server can spend funds — there are no per-period caps, no human-approval gates, no rate limits beyond walletd's own. Until walletd ships the v1.10 allowance ledger, run `exfer-mcp` only against accounts you would be okay losing in full.
|
|
6
|
+
|
|
7
|
+
## What it exposes
|
|
8
|
+
|
|
9
|
+
Seven v0.1 tools — enough for the "Hello World agent flow" of generating an address, simulating a transfer, sending it, and waiting for confirmation:
|
|
10
|
+
|
|
11
|
+
| Tool | What it does |
|
|
12
|
+
|---|---|
|
|
13
|
+
| `exfer_generate_address` | Create a new managed wallet address |
|
|
14
|
+
| `exfer_get_balance` | Confirmed balance of a managed address |
|
|
15
|
+
| `exfer_simulate_transfer` | Dry-run a payment — exact fee + inputs, no broadcast |
|
|
16
|
+
| `exfer_transfer` | Build, sign, broadcast a payment |
|
|
17
|
+
| `exfer_wait_for_tx` | Block until a tx reaches a confirmation depth |
|
|
18
|
+
| `exfer_payment_uri_encode` | Build a BIP21-style `exfer:` URI |
|
|
19
|
+
| `exfer_payment_uri_decode` | Parse a BIP21-style `exfer:` URI |
|
|
20
|
+
|
|
21
|
+
HTLC swap tools, attestation / reputation lookups, and `htlc_list` are out of v0.1 scope — tracked for v0.2.
|
|
22
|
+
|
|
23
|
+
## Install
|
|
24
|
+
|
|
25
|
+
### Recommended — `uvx` (zero global install)
|
|
26
|
+
|
|
27
|
+
`uvx` runs the server in an isolated, on-demand environment. No `pip install`, no virtual-env management, no PATH wrestling. The host (Claude Desktop / Claude Code / Cursor / …) spawns it on demand and uv handles the rest.
|
|
28
|
+
|
|
29
|
+
Install `uv` once:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# macOS / Linux
|
|
33
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
34
|
+
|
|
35
|
+
# Windows
|
|
36
|
+
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Then wire `uvx exfer-mcp` into your MCP host config — examples below. The first time the host launches the server, uv fetches the package from PyPI; subsequent runs are cached.
|
|
40
|
+
|
|
41
|
+
### Fallback — `pip install`
|
|
42
|
+
|
|
43
|
+
For developer / CI use, or environments where adding `uv` is awkward:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install exfer-mcp # installs the `exfer-mcp` console script
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Requires Python ≥ 3.10. Pulls `exfer-walletd ≥ 0.8.0` (the JSON-RPC client) and `mcp ≥ 1.0` (the MCP server framework).
|
|
50
|
+
|
|
51
|
+
## Configure (Claude Desktop)
|
|
52
|
+
|
|
53
|
+
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS (or the equivalent path on your OS), then restart Claude Desktop:
|
|
54
|
+
|
|
55
|
+
```json
|
|
56
|
+
{
|
|
57
|
+
"mcpServers": {
|
|
58
|
+
"exfer": {
|
|
59
|
+
"command": "uvx",
|
|
60
|
+
"args": ["exfer-mcp"],
|
|
61
|
+
"env": {
|
|
62
|
+
"WALLETD_URL": "http://127.0.0.1:7448",
|
|
63
|
+
"WALLETD_AUTH_TOKEN": "<paste your walletd token here>"
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The token is whatever `exfer-walletd` was started with — by default it's written to `~/.exfer-walletd/token` on first run (`chmod 0600`).
|
|
71
|
+
|
|
72
|
+
If walletd is running with `--tls` and a self-signed cert, pin its fingerprint:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"mcpServers": {
|
|
77
|
+
"exfer": {
|
|
78
|
+
"command": "uvx",
|
|
79
|
+
"args": ["exfer-mcp"],
|
|
80
|
+
"env": {
|
|
81
|
+
"WALLETD_URL": "https://127.0.0.1:7448",
|
|
82
|
+
"WALLETD_AUTH_TOKEN": "<token>",
|
|
83
|
+
"WALLETD_FINGERPRINT": "sha256:<paste from cert.fingerprint>"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
For a publicly-fronted walletd (e.g. behind a reverse proxy with a CA-signed cert), drop the `WALLETD_FINGERPRINT` field — the SDK falls back to the system CA chain.
|
|
91
|
+
|
|
92
|
+
### Pin a specific version
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
"args": ["exfer-mcp@0.1.0"]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Configure (Claude Code)
|
|
99
|
+
|
|
100
|
+
One-shot via `claude mcp add`:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
claude mcp add exfer \
|
|
104
|
+
-e WALLETD_URL=http://127.0.0.1:7448 \
|
|
105
|
+
-e WALLETD_AUTH_TOKEN=<token> \
|
|
106
|
+
-- uvx exfer-mcp
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Or by editing the project / global Claude Code MCP config directly:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"mcpServers": {
|
|
114
|
+
"exfer": {
|
|
115
|
+
"command": "uvx",
|
|
116
|
+
"args": ["exfer-mcp"],
|
|
117
|
+
"env": {
|
|
118
|
+
"WALLETD_URL": "http://127.0.0.1:7448",
|
|
119
|
+
"WALLETD_AUTH_TOKEN": "<token>"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Configure (other MCP hosts)
|
|
127
|
+
|
|
128
|
+
Cursor, Cline, Continue.dev, and most other MCP-aware hosts accept the same `command` / `args` / `env` shape. Use the `uvx exfer-mcp` invocation above.
|
|
129
|
+
|
|
130
|
+
## Environment
|
|
131
|
+
|
|
132
|
+
| Variable | Required | Default | Meaning |
|
|
133
|
+
|---|---|---|---|
|
|
134
|
+
| `WALLETD_URL` | ✓ | — | walletd base URL |
|
|
135
|
+
| `WALLETD_AUTH_TOKEN` | ✓ | — | walletd bearer token |
|
|
136
|
+
| `WALLETD_FINGERPRINT` | only for `https://` with a self-signed cert | — | SHA-256 of walletd's TLS cert (`sha256:<hex>`) |
|
|
137
|
+
| `EXFER_MCP_DEFAULT_FEE_RATE` | | walletd default | fee_rate (exfers/byte) for spends when the agent didn't specify |
|
|
138
|
+
| `EXFER_MCP_HTTPX_TIMEOUT` | | 30 | per-RPC timeout in seconds |
|
|
139
|
+
|
|
140
|
+
## Recommended agent flow
|
|
141
|
+
|
|
142
|
+
When the user asks the agent to send a payment, the expected sequence is:
|
|
143
|
+
|
|
144
|
+
1. `exfer_simulate_transfer` → compute exact fee
|
|
145
|
+
2. Show the user the fee and ask for confirmation
|
|
146
|
+
3. `exfer_transfer` → broadcast
|
|
147
|
+
4. `exfer_wait_for_tx` → confirm
|
|
148
|
+
|
|
149
|
+
The simulate-first pattern means the agent always knows the cost before committing. The user is the one who decides whether the cost is acceptable.
|
|
150
|
+
|
|
151
|
+
## Safety
|
|
152
|
+
|
|
153
|
+
- `WALLETD_AUTH_TOKEN` is **all-or-nothing access to the wallet**. Treat it like a payment-card number.
|
|
154
|
+
- `exfer-mcp` does no per-call confirmation by itself — that's the host's job. If you need spend caps, configure them on the walletd side (planned for v1.10) or run a walletd that only holds a small float you would be comfortable losing.
|
|
155
|
+
- The MCP transport is stdio. The agent does not see the wire token; only this process does.
|
|
156
|
+
- Errors from walletd surface as MCP `isError=true` content the agent reads and reacts to, including specific cases like `InsufficientBalanceError` (over-spend) and `WaitTimeoutError` (confirmation depth not reached in time).
|
|
157
|
+
|
|
158
|
+
## Coming soon
|
|
159
|
+
|
|
160
|
+
- **`.mcpb` desktop bundle** — Anthropic's one-click `.mcpb` install format for Claude Desktop, with the env vars surfaced as a form at install time.
|
|
161
|
+
- **v0.2 tools** — HTLC trio (`exfer_htlc_lock` / `exfer_htlc_claim` / `exfer_htlc_reclaim`), `exfer_htlc_status`, attestation queries (`exfer_get_attestation_edges`).
|
|
162
|
+
- **MCP directory** — submission to Anthropic's curated MCP directory + community directories.
|
|
163
|
+
|
|
164
|
+
## Development
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
git clone https://github.com/exfer-stack/exfer-mcp
|
|
168
|
+
cd exfer-mcp
|
|
169
|
+
uv venv && source .venv/bin/activate
|
|
170
|
+
uv pip install -e '.[dev]'
|
|
171
|
+
pytest # unit tests
|
|
172
|
+
mypy && ruff check # lint
|
|
173
|
+
python -m scripts.e2e_smoke # end-to-end smoke (needs a live walletd)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
See [`scripts/e2e_smoke.py`](scripts/e2e_smoke.py) for a runnable example that exercises the full Exfer stack — walletd, indexer, MCP — against a real deployment.
|
|
177
|
+
|
|
178
|
+
## License
|
|
179
|
+
|
|
180
|
+
MIT
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling>=1.21"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "exfer-mcp"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Model Context Protocol server for the Exfer blockchain — gives an AI agent direct, typed access to an exfer-walletd hot wallet"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.10,<3.14"
|
|
12
|
+
authors = [{ name = "exfer-stack" }]
|
|
13
|
+
keywords = ["exfer", "mcp", "agent", "wallet", "crypto"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Typing :: Typed",
|
|
24
|
+
]
|
|
25
|
+
# Pinned to >=0.8 because the v0.1 tool surface uses simulate_transfer +
|
|
26
|
+
# wait_for_tx + payment_uri_* — all walletd v1.9 methods that landed in
|
|
27
|
+
# exfer-walletd 0.8.0. Drop the lower bound only when the MCP tool
|
|
28
|
+
# surface stops using them.
|
|
29
|
+
dependencies = [
|
|
30
|
+
"exfer-walletd>=0.8.0,<1.0",
|
|
31
|
+
"mcp>=1.0,<2.0",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
[project.scripts]
|
|
35
|
+
# The single entrypoint a Claude Desktop / Claude Code config refers
|
|
36
|
+
# to. The stdio transport is launched here.
|
|
37
|
+
exfer-mcp = "exfer_mcp.server:main"
|
|
38
|
+
|
|
39
|
+
[project.urls]
|
|
40
|
+
Homepage = "https://github.com/exfer-stack/exfer-mcp"
|
|
41
|
+
Repository = "https://github.com/exfer-stack/exfer-mcp"
|
|
42
|
+
"Bug Tracker" = "https://github.com/exfer-stack/exfer-mcp/issues"
|
|
43
|
+
"exfer-walletd (Rust daemon)" = "https://github.com/exfer-stack/exfer-walletd"
|
|
44
|
+
"exfer-walletd (Python SDK)" = "https://github.com/exfer-stack/exfer-py"
|
|
45
|
+
|
|
46
|
+
[project.optional-dependencies]
|
|
47
|
+
dev = [
|
|
48
|
+
"pytest>=8.0",
|
|
49
|
+
"pytest-asyncio>=0.23",
|
|
50
|
+
"respx>=0.21",
|
|
51
|
+
"mypy>=1.10,<2.0",
|
|
52
|
+
"ruff>=0.5",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
[tool.hatch.version]
|
|
56
|
+
path = "src/exfer_mcp/_version.py"
|
|
57
|
+
|
|
58
|
+
[tool.hatch.build.targets.wheel]
|
|
59
|
+
packages = ["src/exfer_mcp"]
|
|
60
|
+
|
|
61
|
+
[tool.hatch.build.targets.sdist]
|
|
62
|
+
include = [
|
|
63
|
+
"src/exfer_mcp",
|
|
64
|
+
"tests",
|
|
65
|
+
"README.md",
|
|
66
|
+
"LICENSE",
|
|
67
|
+
"CHANGELOG.md",
|
|
68
|
+
"pyproject.toml",
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
[tool.ruff]
|
|
72
|
+
line-length = 100
|
|
73
|
+
target-version = "py310"
|
|
74
|
+
src = ["src", "tests"]
|
|
75
|
+
|
|
76
|
+
[tool.ruff.lint]
|
|
77
|
+
select = ["E", "F", "I", "B", "UP", "SIM", "RUF"]
|
|
78
|
+
ignore = [
|
|
79
|
+
"E501",
|
|
80
|
+
]
|
|
81
|
+
|
|
82
|
+
[tool.ruff.lint.per-file-ignores]
|
|
83
|
+
"tests/**" = ["B011"]
|
|
84
|
+
|
|
85
|
+
[tool.mypy]
|
|
86
|
+
python_version = "3.10"
|
|
87
|
+
strict = true
|
|
88
|
+
warn_unreachable = true
|
|
89
|
+
disallow_any_unimported = true
|
|
90
|
+
files = ["src/exfer_mcp"]
|
|
91
|
+
|
|
92
|
+
[[tool.mypy.overrides]]
|
|
93
|
+
module = ["respx"]
|
|
94
|
+
ignore_missing_imports = true
|
|
95
|
+
|
|
96
|
+
# The `mcp` SDK's `Server.list_tools()` / `Server.call_tool()` decorators
|
|
97
|
+
# are not typed in the upstream package. We can't make them strict without
|
|
98
|
+
# stubs; silence the two specific codes they emit so we don't slacken
|
|
99
|
+
# strict-mode elsewhere.
|
|
100
|
+
[[tool.mypy.overrides]]
|
|
101
|
+
module = ["exfer_mcp.server"]
|
|
102
|
+
disable_error_code = ["no-untyped-call", "misc", "untyped-decorator"]
|
|
103
|
+
|
|
104
|
+
[tool.pytest.ini_options]
|
|
105
|
+
testpaths = ["tests"]
|
|
106
|
+
pythonpath = ["src"]
|
|
107
|
+
asyncio_mode = "auto"
|
|
108
|
+
|
|
109
|
+
[tool.uv.sources]
|
|
110
|
+
# Local-checkout override while the matching `exfer-walletd` 0.8.0
|
|
111
|
+
# isn't on PyPI yet. When the wheel ships, drop this section and the
|
|
112
|
+
# normal PyPI resolver will take over.
|
|
113
|
+
exfer-walletd = { path = "../exfer-py", editable = true }
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Model Context Protocol server for the Exfer blockchain.
|
|
2
|
+
|
|
3
|
+
Wraps an ``exfer-walletd`` daemon as a set of MCP tools so an AI agent
|
|
4
|
+
(Claude Desktop, Claude Code, any MCP-aware host) can transact on the
|
|
5
|
+
Exfer chain directly — generate addresses, simulate transfers, send
|
|
6
|
+
payments, wait for confirmation, build payment URIs.
|
|
7
|
+
|
|
8
|
+
The transport is stdio; the agent host spawns this process as a
|
|
9
|
+
subprocess and speaks JSON-RPC over its stdin / stdout. See the README
|
|
10
|
+
for the exact host-config stanza.
|
|
11
|
+
|
|
12
|
+
.. warning::
|
|
13
|
+
|
|
14
|
+
This is a hot wallet. Anything that can talk to this MCP server can
|
|
15
|
+
spend funds from the wired ``WALLETD_AUTH_TOKEN``. Run only against
|
|
16
|
+
accounts you would be okay losing in full until walletd ships
|
|
17
|
+
per-period allowance caps (tracked at exfer-walletd v1.10).
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from __future__ import annotations
|
|
21
|
+
|
|
22
|
+
from ._version import __version__
|
|
23
|
+
|
|
24
|
+
__all__ = ["__version__"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.1.0"
|