@agenttrust-sdk/mcp 0.3.1 → 0.3.3
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/README.md +25 -3
- package/dist/chain.js +4 -2
- package/dist/chain.js.map +1 -1
- package/dist/config.d.ts +22 -2
- package/dist/config.js +165 -15
- package/dist/config.js.map +1 -1
- package/dist/embedded-docs/mcp/hosted-endpoint.mdx +1 -1
- package/dist/embedded-docs/mcp/install.mdx +12 -3
- package/dist/embedded-docs/mcp/tools.mdx +2 -2
- package/dist/embedded-docs/quickstart.mdx +83 -0
- package/dist/errors.d.ts +79 -0
- package/dist/errors.js +277 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.js +13 -6
- package/dist/index.js.map +1 -1
- package/dist/server.js +19 -16
- package/dist/server.js.map +1 -1
- package/dist/tools/discovery/docs.d.ts +6 -0
- package/dist/tools/discovery/docs.js +13 -1
- package/dist/tools/discovery/docs.js.map +1 -1
- package/dist/tools/discovery/facilitator-walkthrough.d.ts +5 -0
- package/dist/tools/discovery/facilitator-walkthrough.js +13 -2
- package/dist/tools/discovery/facilitator-walkthrough.js.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/read/get-quantu-reputation.d.ts +23 -3
- package/dist/tools/read/get-quantu-reputation.js +32 -7
- package/dist/tools/read/get-quantu-reputation.js.map +1 -1
- package/dist/tools/read/simulate-payment.js +13 -13
- package/dist/tools/read/simulate-payment.js.map +1 -1
- package/dist/tools/write/emit-feedback.d.ts +4 -4
- package/dist/tools/write/emit-feedback.js +55 -12
- package/dist/tools/write/emit-feedback.js.map +1 -1
- package/dist/tools/write/init-authority.d.ts +43 -0
- package/dist/tools/write/init-authority.js +92 -0
- package/dist/tools/write/init-authority.js.map +1 -0
- package/dist/tools/write/init-policy.d.ts +23 -3
- package/dist/tools/write/init-policy.js +92 -15
- package/dist/tools/write/init-policy.js.map +1 -1
- package/dist/tools/write/request-validation.js +6 -2
- package/dist/tools/write/request-validation.js.map +1 -1
- package/dist/tools/write/respond-to-validation.d.ts +3 -2
- package/dist/tools/write/respond-to-validation.js +10 -7
- package/dist/tools/write/respond-to-validation.js.map +1 -1
- package/dist/tools/write/set-killswitch.d.ts +10 -0
- package/dist/tools/write/set-killswitch.js +63 -14
- package/dist/tools/write/set-killswitch.js.map +1 -1
- package/package.json +15 -16
- package/scripts/install-claude-desktop.sh +0 -0
- package/dist/embedded-docs/getting-started/architecture-overview.mdx +0 -85
- package/dist/embedded-docs/reference/formal-verification.mdx +0 -19
- package/dist/embedded-docs/sdk/atomic-tx-invariant.mdx +0 -37
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ deployed AgentTrust programs through natural language.
|
|
|
24
24
|
| `agenttrust_list_facilitators` | Active facilitator adapters (Pay.sh / Dexter / atxp / MCPay) + ship status. |
|
|
25
25
|
| `agenttrust_demo_state` | Three pre-warmed devnet counterparties used by `examples/pay-sh-demo`. |
|
|
26
26
|
|
|
27
|
-
### Write (require `KEYPAIR_B58`
|
|
27
|
+
### Write (require a signer: `KEYPAIR_B58` / `KEYPAIR_PATH` / Solana CLI default)
|
|
28
28
|
|
|
29
29
|
| Tool | Effect |
|
|
30
30
|
|--|--|
|
|
@@ -105,7 +105,17 @@ The script edits the Claude Desktop config in place. It backs up the
|
|
|
105
105
|
prior config to `claude_desktop_config.json.bak.<timestamp>` so you can
|
|
106
106
|
revert if needed.
|
|
107
107
|
|
|
108
|
-
For write tools,
|
|
108
|
+
For write tools, supply a signer via any one of the four steps in the
|
|
109
|
+
resolution chain (first match wins):
|
|
110
|
+
|
|
111
|
+
1. `KEYPAIR_B58` — base58-encoded 64-byte secret key
|
|
112
|
+
2. `KEYPAIR_PATH` — absolute path to a JSON-array secret-key file (Solana CLI native format)
|
|
113
|
+
3. `~/.config/solana/id.json` — Solana CLI's default keypair location, picked up automatically
|
|
114
|
+
4. `SOLANA_KEYPAIR_PATH` — alt path env some tooling sets
|
|
115
|
+
|
|
116
|
+
If you already use `solana-keygen` locally, no env is needed — the
|
|
117
|
+
default `~/.config/solana/id.json` is detected automatically. To set an
|
|
118
|
+
explicit signer in the Claude Desktop config block:
|
|
109
119
|
|
|
110
120
|
```json
|
|
111
121
|
"env": {
|
|
@@ -115,6 +125,16 @@ For write tools, add `KEYPAIR_B58` to the `env` block:
|
|
|
115
125
|
}
|
|
116
126
|
```
|
|
117
127
|
|
|
128
|
+
Or point at a file instead of inlining the secret:
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
"env": {
|
|
132
|
+
"RPC_URL": "https://api.devnet.solana.com",
|
|
133
|
+
"NETWORK": "solana-devnet",
|
|
134
|
+
"KEYPAIR_PATH": "/Users/you/.config/solana/id.json"
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
118
138
|
### Cursor
|
|
119
139
|
|
|
120
140
|
Cursor's MCP config lives at `~/.cursor/mcp.json` (or per-workspace
|
|
@@ -176,7 +196,9 @@ The server listens on `http://0.0.0.0:8765`. Behind any reverse proxy
|
|
|
176
196
|
|--|--|--|
|
|
177
197
|
| `RPC_URL` | devnet RPC | Solana RPC endpoint. |
|
|
178
198
|
| `NETWORK` | `solana-devnet` | `solana-devnet` or `solana-mainnet`. Drives Quantu program IDs. |
|
|
179
|
-
| `KEYPAIR_B58` | unset | Base58-encoded 64-byte secret key.
|
|
199
|
+
| `KEYPAIR_B58` | unset | Base58-encoded 64-byte secret key. First step in the signer-resolution chain. |
|
|
200
|
+
| `KEYPAIR_PATH` | unset | Path to a JSON-array secret-key file (Solana CLI native format). Second step in the signer-resolution chain. |
|
|
201
|
+
| `SOLANA_KEYPAIR_PATH` | unset | Alt path env some tooling sets. Fourth step in the signer-resolution chain. |
|
|
180
202
|
| `MCP_TRANSPORT` | `stdio` | `stdio` or `http`. |
|
|
181
203
|
| `MCP_HTTP_PORT` | `8765` | Port for HTTP transport. |
|
|
182
204
|
| `POLICY_VAULT_PROGRAM_ID` | devnet ID | Override the policy_vault program ID. |
|
package/dist/chain.js
CHANGED
|
@@ -109,8 +109,10 @@ class ChainClient {
|
|
|
109
109
|
}
|
|
110
110
|
requireSigner() {
|
|
111
111
|
if (!this.cfg.signer) {
|
|
112
|
-
throw new Error("This tool requires KEYPAIR_B58
|
|
113
|
-
"
|
|
112
|
+
throw new Error("This tool requires a signer. Set one of: KEYPAIR_B58 (base58 of a " +
|
|
113
|
+
"64-byte secret key), KEYPAIR_PATH (absolute path to a Solana CLI " +
|
|
114
|
+
"keypair JSON), or run `solana-keygen new` so ~/.config/solana/id.json " +
|
|
115
|
+
"exists. Then restart the MCP server.");
|
|
114
116
|
}
|
|
115
117
|
return this.cfg.signer;
|
|
116
118
|
}
|
package/dist/chain.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chain.js","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmGH,oCAIC;AArGD,0DAA4C;
|
|
1
|
+
{"version":3,"file":"chain.js","sourceRoot":"","sources":["../src/chain.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Env parsing for the AgentTrust MCP server.
|
|
3
3
|
*
|
|
4
|
-
* Read tools work without any env. Write tools require
|
|
4
|
+
* Read tools work without any env. Write tools require a signer
|
|
5
|
+
* keypair, resolved through a four-step fallback chain (see `readSigner`):
|
|
6
|
+
* 1. `KEYPAIR_B58` — base58 of the 64-byte secret key
|
|
7
|
+
* 2. `KEYPAIR_PATH` — JSON-array secret-key file (Solana CLI native)
|
|
8
|
+
* 3. `~/.config/solana/id.json` — Solana CLI's default keypair location
|
|
9
|
+
* 4. `SOLANA_KEYPAIR_PATH` — alt name some tooling sets
|
|
10
|
+
*
|
|
5
11
|
* The HTTP transport requires `MCP_HTTP_PORT` (else stdio is the default).
|
|
6
12
|
*
|
|
7
13
|
* Defaults are biased toward the local-developer / Claude Desktop case:
|
|
@@ -19,15 +25,29 @@ export interface AgentTrustConfig {
|
|
|
19
25
|
* shape rather than a sibling field on AgentTrustConfig. */
|
|
20
26
|
readonly programs: ProgramIds;
|
|
21
27
|
readonly quantu: QuantuProgramIds;
|
|
22
|
-
/** Optional signer keypair.
|
|
28
|
+
/** Optional signer keypair. Resolved via the layered fallback chain
|
|
29
|
+
* documented on `readSigner`. Write tools require this. */
|
|
23
30
|
readonly signer?: Keypair;
|
|
24
31
|
/** Transport selection. */
|
|
25
32
|
readonly transport: "stdio" | "http";
|
|
26
33
|
/** HTTP transport port (only used when transport === "http"). */
|
|
27
34
|
readonly httpPort: number;
|
|
35
|
+
/** HTTP transport bind host (only used when transport === "http").
|
|
36
|
+
* Defaults to 127.0.0.1 so a laptop developer doesn't expose the
|
|
37
|
+
* server on the LAN. Production-style deploys (Fly, Vercel) set
|
|
38
|
+
* `MCP_HTTP_HOST=0.0.0.0` explicitly. */
|
|
39
|
+
readonly httpHost: string;
|
|
28
40
|
/** Optional default facilitator name to surface in tool replies. */
|
|
29
41
|
readonly defaultFacilitator?: string;
|
|
30
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Decode a JSON-array secret-key file (Solana CLI's native format) into
|
|
45
|
+
* a Keypair. Exported for direct testing.
|
|
46
|
+
*
|
|
47
|
+
* Throws with a clear, source-named error when the file is unreadable,
|
|
48
|
+
* not valid JSON, not an array of numbers, or the wrong byte length.
|
|
49
|
+
*/
|
|
50
|
+
export declare function readKeypairFile(filePath: string): Keypair;
|
|
31
51
|
export declare function loadConfig(): AgentTrustConfig;
|
|
32
52
|
/**
|
|
33
53
|
* Build a Solana Explorer URL for a tx signature or account, scoped to
|
package/dist/config.js
CHANGED
|
@@ -2,18 +2,61 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Env parsing for the AgentTrust MCP server.
|
|
4
4
|
*
|
|
5
|
-
* Read tools work without any env. Write tools require
|
|
5
|
+
* Read tools work without any env. Write tools require a signer
|
|
6
|
+
* keypair, resolved through a four-step fallback chain (see `readSigner`):
|
|
7
|
+
* 1. `KEYPAIR_B58` — base58 of the 64-byte secret key
|
|
8
|
+
* 2. `KEYPAIR_PATH` — JSON-array secret-key file (Solana CLI native)
|
|
9
|
+
* 3. `~/.config/solana/id.json` — Solana CLI's default keypair location
|
|
10
|
+
* 4. `SOLANA_KEYPAIR_PATH` — alt name some tooling sets
|
|
11
|
+
*
|
|
6
12
|
* The HTTP transport requires `MCP_HTTP_PORT` (else stdio is the default).
|
|
7
13
|
*
|
|
8
14
|
* Defaults are biased toward the local-developer / Claude Desktop case:
|
|
9
15
|
* devnet RPC, devnet program IDs, no signer required.
|
|
10
16
|
*/
|
|
17
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
20
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
21
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
22
|
+
}
|
|
23
|
+
Object.defineProperty(o, k2, desc);
|
|
24
|
+
}) : (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
o[k2] = m[k];
|
|
27
|
+
}));
|
|
28
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
+
}) : function(o, v) {
|
|
31
|
+
o["default"] = v;
|
|
32
|
+
});
|
|
33
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
34
|
+
var ownKeys = function(o) {
|
|
35
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
36
|
+
var ar = [];
|
|
37
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
38
|
+
return ar;
|
|
39
|
+
};
|
|
40
|
+
return ownKeys(o);
|
|
41
|
+
};
|
|
42
|
+
return function (mod) {
|
|
43
|
+
if (mod && mod.__esModule) return mod;
|
|
44
|
+
var result = {};
|
|
45
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
46
|
+
__setModuleDefault(result, mod);
|
|
47
|
+
return result;
|
|
48
|
+
};
|
|
49
|
+
})();
|
|
11
50
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
51
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
52
|
};
|
|
14
53
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
54
|
+
exports.readKeypairFile = readKeypairFile;
|
|
15
55
|
exports.loadConfig = loadConfig;
|
|
16
56
|
exports.explorerUrl = explorerUrl;
|
|
57
|
+
const fs = __importStar(require("fs"));
|
|
58
|
+
const os = __importStar(require("os"));
|
|
59
|
+
const path = __importStar(require("path"));
|
|
17
60
|
const web3_js_1 = require("@solana/web3.js");
|
|
18
61
|
const bs58_1 = __importDefault(require("bs58"));
|
|
19
62
|
const trustgate_1 = require("@agenttrust-sdk/trustgate");
|
|
@@ -26,34 +69,140 @@ function readNetwork() {
|
|
|
26
69
|
}
|
|
27
70
|
return "solana-devnet";
|
|
28
71
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Decode a JSON-array secret-key file (Solana CLI's native format) into
|
|
74
|
+
* a Keypair. Exported for direct testing.
|
|
75
|
+
*
|
|
76
|
+
* Throws with a clear, source-named error when the file is unreadable,
|
|
77
|
+
* not valid JSON, not an array of numbers, or the wrong byte length.
|
|
78
|
+
*/
|
|
79
|
+
function readKeypairFile(filePath) {
|
|
80
|
+
let raw;
|
|
81
|
+
try {
|
|
82
|
+
raw = fs.readFileSync(filePath, "utf8");
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
throw new Error(`keypair file at ${filePath} is unreadable: ${err.message}`);
|
|
86
|
+
}
|
|
87
|
+
let parsed;
|
|
88
|
+
try {
|
|
89
|
+
parsed = JSON.parse(raw);
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
throw new Error(`keypair file at ${filePath} is not valid JSON: ${err.message}`);
|
|
93
|
+
}
|
|
94
|
+
if (!Array.isArray(parsed) || !parsed.every((n) => typeof n === "number")) {
|
|
95
|
+
throw new Error(`keypair file at ${filePath} must be a JSON array of numbers (Solana CLI format)`);
|
|
96
|
+
}
|
|
97
|
+
const bytes = Uint8Array.from(parsed);
|
|
98
|
+
if (bytes.length !== 64) {
|
|
99
|
+
throw new Error(`keypair file at ${filePath}: expected 64-byte secret key, got ${bytes.length} bytes`);
|
|
100
|
+
}
|
|
33
101
|
try {
|
|
34
|
-
const bytes = bs58_1.default.decode(raw);
|
|
35
102
|
return web3_js_1.Keypair.fromSecretKey(bytes);
|
|
36
103
|
}
|
|
37
104
|
catch (err) {
|
|
38
|
-
throw new Error(`
|
|
39
|
-
|
|
105
|
+
throw new Error(`keypair file at ${filePath} could not be loaded as a Solana keypair: ${err.message}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Layered signer detection. Tries, in order:
|
|
110
|
+
* 1. `KEYPAIR_B58` (base58 of 64-byte secret key)
|
|
111
|
+
* 2. `KEYPAIR_PATH` (JSON-array secret-key file)
|
|
112
|
+
* 3. `~/.config/solana/id.json` (Solana CLI's default keypair location)
|
|
113
|
+
* 4. `SOLANA_KEYPAIR_PATH` (alt name some tooling sets)
|
|
114
|
+
*
|
|
115
|
+
* Explicit env vars win over the well-known default. If an env var is
|
|
116
|
+
* SET but unparseable, we throw a clear error naming the source. If
|
|
117
|
+
* unset, we fall through silently. If none of the four is usable we
|
|
118
|
+
* return undefined — the read-only mode for no-auth read tools.
|
|
119
|
+
*/
|
|
120
|
+
function readSigner() {
|
|
121
|
+
const b58 = process.env.KEYPAIR_B58?.trim();
|
|
122
|
+
if (b58) {
|
|
123
|
+
let bytes;
|
|
124
|
+
try {
|
|
125
|
+
bytes = bs58_1.default.decode(b58);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
throw new Error(`KEYPAIR_B58 is set but failed to decode as base58: ${err.message}. ` +
|
|
129
|
+
`Expected base58-encoded 64-byte secret key.`);
|
|
130
|
+
}
|
|
131
|
+
if (bytes.length !== 64) {
|
|
132
|
+
throw new Error(`KEYPAIR_B58 decoded to ${bytes.length} bytes; expected 64-byte secret key. ` +
|
|
133
|
+
`A 32-byte value is the public-key half only — Solana keypair files contain both halves.`);
|
|
134
|
+
}
|
|
135
|
+
try {
|
|
136
|
+
return web3_js_1.Keypair.fromSecretKey(bytes);
|
|
137
|
+
}
|
|
138
|
+
catch (err) {
|
|
139
|
+
throw new Error(`KEYPAIR_B58 decoded to 64 bytes but Solana rejected it: ${err.message}`);
|
|
140
|
+
}
|
|
40
141
|
}
|
|
142
|
+
const explicitPath = process.env.KEYPAIR_PATH?.trim();
|
|
143
|
+
if (explicitPath) {
|
|
144
|
+
try {
|
|
145
|
+
return readKeypairFile(explicitPath);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
throw new Error(`KEYPAIR_PATH points at ${explicitPath} but the file is unreadable: ${err.message}`);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const altPath = process.env.SOLANA_KEYPAIR_PATH?.trim();
|
|
152
|
+
if (altPath) {
|
|
153
|
+
try {
|
|
154
|
+
return readKeypairFile(altPath);
|
|
155
|
+
}
|
|
156
|
+
catch (err) {
|
|
157
|
+
throw new Error(`SOLANA_KEYPAIR_PATH points at ${altPath} but the file is unreadable: ${err.message}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const defaultPath = path.join(os.homedir(), ".config", "solana", "id.json");
|
|
161
|
+
if (fs.existsSync(defaultPath)) {
|
|
162
|
+
try {
|
|
163
|
+
return readKeypairFile(defaultPath);
|
|
164
|
+
}
|
|
165
|
+
catch (err) {
|
|
166
|
+
throw new Error(`Solana CLI default keypair at ${defaultPath} is unusable: ${err.message}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return undefined;
|
|
41
170
|
}
|
|
42
171
|
function readTransport() {
|
|
43
172
|
const raw = (process.env.MCP_TRANSPORT ?? "stdio").trim().toLowerCase();
|
|
44
173
|
const port = Number.parseInt(process.env.MCP_HTTP_PORT ?? "8765", 10);
|
|
174
|
+
// Default bind 127.0.0.1 — a local-laptop user starting `MCP_TRANSPORT=http`
|
|
175
|
+
// should NOT expose the server on the LAN by accident. Hosted deploys
|
|
176
|
+
// (Fly, Vercel) explicitly set MCP_HTTP_HOST=0.0.0.0.
|
|
177
|
+
const host = (process.env.MCP_HTTP_HOST ?? "127.0.0.1").trim();
|
|
45
178
|
if (raw === "http" || raw === "sse")
|
|
46
|
-
return { transport: "http", httpPort: port };
|
|
47
|
-
return { transport: "stdio", httpPort: port };
|
|
179
|
+
return { transport: "http", httpPort: port, httpHost: host };
|
|
180
|
+
return { transport: "stdio", httpPort: port, httpHost: host };
|
|
48
181
|
}
|
|
49
182
|
function loadConfig() {
|
|
50
183
|
const network = readNetwork();
|
|
51
184
|
const rpcUrl = (process.env.RPC_URL ?? (network === "solana-mainnet" ? MAINNET_RPC : DEVNET_RPC)).trim();
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
185
|
+
try {
|
|
186
|
+
// eslint-disable-next-line no-new
|
|
187
|
+
new URL(rpcUrl);
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
throw new Error(`RPC_URL is not a valid URL: ${err.message}. Got: ${rpcUrl}`);
|
|
191
|
+
}
|
|
192
|
+
const { transport, httpPort, httpHost } = readTransport();
|
|
193
|
+
// AgentTrust programs ship on devnet. Quantu ships on both devnet and
|
|
194
|
+
// mainnet. When mainnet is selected the AgentTrust program IDs must be
|
|
195
|
+
// overridden via env — otherwise we'd silently point at devnet pubkeys
|
|
196
|
+
// on a mainnet RPC (every read returns `exists: false`, every write
|
|
197
|
+
// throws cryptic Anchor errors).
|
|
198
|
+
const policyVaultEnv = process.env.POLICY_VAULT_PROGRAM_ID?.trim();
|
|
199
|
+
const trustGateEnv = process.env.TRUSTGATE_PROGRAM_ID?.trim();
|
|
200
|
+
const validationRegistryEnv = process.env.VALIDATION_REGISTRY_PROGRAM_ID?.trim();
|
|
201
|
+
if (network === "solana-mainnet" && !policyVaultEnv && !trustGateEnv && !validationRegistryEnv) {
|
|
202
|
+
throw new Error("AgentTrust programs are not yet deployed on mainnet. " +
|
|
203
|
+
"Set explicit POLICY_VAULT_PROGRAM_ID, TRUSTGATE_PROGRAM_ID, and " +
|
|
204
|
+
"VALIDATION_REGISTRY_PROGRAM_ID env vars, or use NETWORK=solana-devnet (default).");
|
|
205
|
+
}
|
|
57
206
|
const programs = {
|
|
58
207
|
policyVault: parsePubkeyEnv("POLICY_VAULT_PROGRAM_ID", trustgate_1.DEFAULT_DEVNET_PROGRAM_IDS.policyVault),
|
|
59
208
|
trustGate: parsePubkeyEnv("TRUSTGATE_PROGRAM_ID", trustgate_1.DEFAULT_DEVNET_PROGRAM_IDS.trustGate),
|
|
@@ -71,6 +220,7 @@ function loadConfig() {
|
|
|
71
220
|
signer: readSigner(),
|
|
72
221
|
transport,
|
|
73
222
|
httpPort,
|
|
223
|
+
httpHost,
|
|
74
224
|
defaultFacilitator: process.env.MCP_DEFAULT_FACILITATOR?.trim() || undefined,
|
|
75
225
|
};
|
|
76
226
|
}
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -134,7 +134,7 @@ Phase M flagged this as Bug #4. Fixing it requires restructuring the transport i
|
|
|
134
134
|
|
|
135
135
|
## Auth
|
|
136
136
|
|
|
137
|
-
The hosted endpoint has no authentication for read tools. Write tools require a `KEYPAIR_B58`
|
|
137
|
+
The hosted endpoint has no authentication for read tools. Write tools require a signer on the *server* (resolved via `KEYPAIR_B58` / `KEYPAIR_PATH` / Solana CLI default); the hosted instance has none of these set, so write tools surface the standard `signer required` error.
|
|
138
138
|
|
|
139
139
|
For write-tool access from a hosted MCP context, run your own instance with your own keypair:
|
|
140
140
|
|
|
@@ -96,7 +96,14 @@ Behind any reverse proxy (Caddy, nginx, Vercel, Fly.io) this surfaces as a publi
|
|
|
96
96
|
|
|
97
97
|
## Write tools — adding a keypair
|
|
98
98
|
|
|
99
|
-
The five write tools (`agenttrust_init_policy`, `agenttrust_set_killswitch`, `agenttrust_request_validation`, `agenttrust_respond_to_validation`, `agenttrust_emit_feedback`) require a signing keypair.
|
|
99
|
+
The five write tools (`agenttrust_init_policy`, `agenttrust_set_killswitch`, `agenttrust_request_validation`, `agenttrust_respond_to_validation`, `agenttrust_emit_feedback`) require a signing keypair. The MCP server resolves a signer through a four-step chain (first match wins):
|
|
100
|
+
|
|
101
|
+
1. `KEYPAIR_B58` — base58-encoded 64-byte secret key
|
|
102
|
+
2. `KEYPAIR_PATH` — absolute path to a JSON-array secret-key file (Solana CLI native format)
|
|
103
|
+
3. `~/.config/solana/id.json` — Solana CLI's default keypair location, picked up automatically
|
|
104
|
+
4. `SOLANA_KEYPAIR_PATH` — alt path env some tooling sets
|
|
105
|
+
|
|
106
|
+
If you already use `solana-keygen` locally, no env is needed. To set an explicit signer in the Claude Desktop config, add `KEYPAIR_B58` to the `env` block:
|
|
100
107
|
|
|
101
108
|
```json
|
|
102
109
|
{
|
|
@@ -114,7 +121,7 @@ The five write tools (`agenttrust_init_policy`, `agenttrust_set_killswitch`, `ag
|
|
|
114
121
|
}
|
|
115
122
|
```
|
|
116
123
|
|
|
117
|
-
Without
|
|
124
|
+
Without any usable signer, write tools surface a clear `signer required` error. Read and discovery tools never need one.
|
|
118
125
|
|
|
119
126
|
Convert a Solana CLI keypair to base58:
|
|
120
127
|
|
|
@@ -135,7 +142,9 @@ cat ~/.config/solana/id.json | jq -r '.[0:64]' | npx bs58 encode
|
|
|
135
142
|
|---|---|---|
|
|
136
143
|
| `RPC_URL` | devnet RPC | Solana RPC endpoint |
|
|
137
144
|
| `NETWORK` | `solana-devnet` | `solana-devnet` or `solana-mainnet`. Drives Quantu program IDs. |
|
|
138
|
-
| `KEYPAIR_B58` | unset | Base58-encoded 64-byte secret key.
|
|
145
|
+
| `KEYPAIR_B58` | unset | Base58-encoded 64-byte secret key. First step in the signer-resolution chain. |
|
|
146
|
+
| `KEYPAIR_PATH` | unset | Path to a JSON-array secret-key file (Solana CLI native format). Second step in the signer-resolution chain. |
|
|
147
|
+
| `SOLANA_KEYPAIR_PATH` | unset | Alt path env some tooling sets. Fourth step in the signer-resolution chain. |
|
|
139
148
|
| `MCP_TRANSPORT` | `stdio` | `stdio` or `http` |
|
|
140
149
|
| `MCP_HTTP_PORT` | `8765` | Port for HTTP transport |
|
|
141
150
|
| `POLICY_VAULT_PROGRAM_ID` | devnet ID | Override `policy_vault` program ID |
|
|
@@ -90,7 +90,7 @@ Returns the three pre-warmed devnet counterparties used by `examples/pay-sh-demo
|
|
|
90
90
|
|
|
91
91
|
The demo state is bundled in the tarball as of 0.2.3 — the published package doesn't need a separate state file.
|
|
92
92
|
|
|
93
|
-
## Write (5 tools — require `KEYPAIR_B58`)
|
|
93
|
+
## Write (5 tools — require a signer: `KEYPAIR_B58` / `KEYPAIR_PATH` / Solana CLI default)
|
|
94
94
|
|
|
95
95
|
| Tool | Effect |
|
|
96
96
|
|---|---|
|
|
@@ -114,7 +114,7 @@ Required args: `subject_asset`, `claim_uri_hash_hex`, `deadline_slot`. The capab
|
|
|
114
114
|
|
|
115
115
|
### `agenttrust_respond_to_validation`
|
|
116
116
|
|
|
117
|
-
Required args: `subject_asset`, `claim_payload_hash_hex`, `claim_uri_hash_hex`, `expires_at_slot`. The signer (the
|
|
117
|
+
Required args: `subject_asset`, `claim_payload_hash_hex`, `claim_uri_hash_hex`, `expires_at_slot`. The signer (resolved via the chain `KEYPAIR_B58` / `KEYPAIR_PATH` / Solana CLI default) is the attestor. v1 trust model: tx signature authenticates; v1.1+ adds Ed25519 sysvar verify.
|
|
118
118
|
|
|
119
119
|
### `agenttrust_emit_feedback`
|
|
120
120
|
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Quickstart
|
|
3
|
+
description: AgentTrust in 60 seconds. Install the MCP server into Claude Desktop, create a policy, run a gate-decision simulation. No clone, no Anchor build.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Sixty seconds, three steps, one MCP server. By the end you have a real `PolicyAccount` PDA on devnet and a decoded `gate_payment` decision in your chat client. No clone, no Anchor build, no local validator.
|
|
7
|
+
|
|
8
|
+
## 1. Install the MCP server into Claude Desktop
|
|
9
|
+
|
|
10
|
+
Drop this block into `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS, or `%APPDATA%\Claude\claude_desktop_config.json` on Windows:
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"mcpServers": {
|
|
15
|
+
"agenttrust": {
|
|
16
|
+
"command": "npx",
|
|
17
|
+
"args": ["-y", "@agenttrust-sdk/mcp"],
|
|
18
|
+
"env": {
|
|
19
|
+
"RPC_URL": "https://api.devnet.solana.com",
|
|
20
|
+
"NETWORK": "solana-devnet"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Restart Claude Desktop. Eighteen tools are now wired in. Ten read-only tools work immediately on devnet with zero credentials. The five write tools resolve a signer through the chain `KEYPAIR_B58` then `KEYPAIR_PATH` then `~/.config/solana/id.json` then `SOLANA_KEYPAIR_PATH` and use the first one that parses. If you already use `solana-keygen`, the default `id.json` is picked up automatically and no env var is needed.
|
|
28
|
+
|
|
29
|
+
## 2. Create a policy
|
|
30
|
+
|
|
31
|
+
Ask Claude Desktop, in plain English:
|
|
32
|
+
|
|
33
|
+
> Use agenttrust_init_policy to create policy 1 for my agent. Enable Spending (bitmask 2) with a per-transaction max of 1 USDC.
|
|
34
|
+
|
|
35
|
+
The `agenttrust_init_policy` tool is self-healing. If your agent's `PolicyAuthority` PDA does not yet exist on devnet, the tool prepends an `init_authority` instruction (single member = your signer, threshold = 1) and submits both in one atomic transaction. You never see Anchor error 3012. Spending caps also default sanely: when at least one cap is set, unspecified peer caps default to the max of the specified caps rather than zero, so v1 policies (immutable post-init) cannot accidentally hard-deny every payment.
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
Output:
|
|
39
|
+
txSignature: 4n8…ZxR
|
|
40
|
+
explorerTxUrl: https://explorer.solana.com/tx/4n8…ZxR?cluster=devnet
|
|
41
|
+
policyPda: 9aF…tNm
|
|
42
|
+
effectiveSpending: { perTxMax: "1000000", dailyMax: "1000000", weeklyMax: "1000000" }
|
|
43
|
+
selfHealed: true
|
|
44
|
+
healedSteps: ["init_authority"]
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Open the `explorerTxUrl` to see the on-chain transaction. The `policyPda` is the `PolicyAccount` PDA the gate evaluates against on every payment.
|
|
48
|
+
|
|
49
|
+
## 3. Run a gate-decision simulation
|
|
50
|
+
|
|
51
|
+
Now ask:
|
|
52
|
+
|
|
53
|
+
> Use agenttrust_simulate_payment to gate a 5-USDC payment from the tier-3 demo agent to the tier-0 demo agent against policy 1. What does the gate decide?
|
|
54
|
+
|
|
55
|
+
`agenttrust_simulate_payment` is read-only. It calls the on-chain `gate_payment` instruction in simulate mode and decodes the `GateDecision` return value — `Allow`, `Deny` with a stable reason code (1 through 15), or `RequireValidation` with the 32-byte capability hash. The same call path the Express service's `POST /verify` route uses for the real x402 v2 challenge.
|
|
56
|
+
|
|
57
|
+
```text
|
|
58
|
+
Output:
|
|
59
|
+
kind: "Deny"
|
|
60
|
+
reasonCode: 5
|
|
61
|
+
reasonName: "SpendingPerTxExceeded"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The gate denied the payment because 5 USDC exceeds the 1 USDC per-tx cap you set in step 2. Drop the amount to 0.5 USDC and ask again. The decision flips to `Allow`. You have just exercised the full PolicyVault decision path on devnet from a chat prompt.
|
|
65
|
+
|
|
66
|
+
## Where to next
|
|
67
|
+
|
|
68
|
+
Sixty seconds is enough to feel the shape. The deeper paths:
|
|
69
|
+
|
|
70
|
+
<Cards>
|
|
71
|
+
<Card title="The three live paths" href="/getting-started/quickstart">
|
|
72
|
+
Hit the live x402 demo, mount the SDK middleware on Express, wire the MCP server, all against the hosted devnet build.
|
|
73
|
+
</Card>
|
|
74
|
+
<Card title="MCP server" href="/mcp">
|
|
75
|
+
Eighteen tools, four resources, three guided prompts. Full install reference at /mcp/install.
|
|
76
|
+
</Card>
|
|
77
|
+
<Card title="@agenttrust-sdk/trustgate" href="/sdk">
|
|
78
|
+
The TypeScript SDK every facilitator pulls in. Express middleware, client helpers, the atomicity guard, the full ValidationRegistry instruction builder set.
|
|
79
|
+
</Card>
|
|
80
|
+
<Card title="Architecture" href="/architecture">
|
|
81
|
+
How the three Anchor programs compose into one settlement path. The atomic-tx invariant. The FacilitatorAdapter pattern.
|
|
82
|
+
</Card>
|
|
83
|
+
</Cards>
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured error envelopes for MCP `tools/call` responses (F-013).
|
|
3
|
+
*
|
|
4
|
+
* Before this module, every thrown handler error was flattened to
|
|
5
|
+
* `{ isError: true, content: [{type:"text",text:"tool error: <msg>"}] }`
|
|
6
|
+
* — opaque to LLM agents and useless for automated recovery.
|
|
7
|
+
*
|
|
8
|
+
* Now `classifyError()` inspects the thrown value and produces a
|
|
9
|
+
* `ToolError` with:
|
|
10
|
+
* - `errorCode`: one of a fixed enum so callers can branch on it.
|
|
11
|
+
* - `message`: short human description (truncated original).
|
|
12
|
+
* - `hint`: single sentence of remediation guidance.
|
|
13
|
+
* - `cause`: truncated original message (<=500 chars) for debugging.
|
|
14
|
+
*
|
|
15
|
+
* `renderToolError()` serialises that envelope into the MCP
|
|
16
|
+
* `CallToolResult` shape. The envelope is JSON-encoded into
|
|
17
|
+
* `content[0].text` (so transports that only surface text still get a
|
|
18
|
+
* parseable payload), AND mirrored into `structuredContent` (the MCP
|
|
19
|
+
* spec field for machine-readable tool output, supported by the
|
|
20
|
+
* `@modelcontextprotocol/sdk` schema we already depend on).
|
|
21
|
+
*
|
|
22
|
+
* Tool handlers do NOT need to change. They still:
|
|
23
|
+
* - `throw new Error("...")` for ad-hoc failures
|
|
24
|
+
* - `throw new ZodError(...)` (implicitly, via `schema.parse()`)
|
|
25
|
+
* - throw `AnchorError` / `SendTransactionError` (via `.rpc()` calls)
|
|
26
|
+
* The classifier sniffs the thrown value (name, message prefix,
|
|
27
|
+
* `instanceof` where the constructor is in scope) and maps it.
|
|
28
|
+
*
|
|
29
|
+
* Note for future contributors: callers reading `content[0].text` as a
|
|
30
|
+
* string will see a JSON object now, not a plain sentence. This is
|
|
31
|
+
* intentional — `isError: true` is preserved so existing transports
|
|
32
|
+
* still treat it as a failure. If you add a new tool that throws a
|
|
33
|
+
* specific subclass, extend `classifyError()` here rather than
|
|
34
|
+
* pattern-matching in `server.ts`.
|
|
35
|
+
*/
|
|
36
|
+
/** Stable enum of error categories surfaced to MCP clients. */
|
|
37
|
+
export type ToolErrorCode = "auth_required" | "input_invalid" | "rpc_failure" | "chain_error" | "not_found" | "internal";
|
|
38
|
+
export interface ToolError {
|
|
39
|
+
errorCode: ToolErrorCode;
|
|
40
|
+
message: string;
|
|
41
|
+
hint?: string;
|
|
42
|
+
cause?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Classify an unknown thrown value into a structured `ToolError`.
|
|
46
|
+
*
|
|
47
|
+
* @param err The thrown value from a tool handler (or Zod parse).
|
|
48
|
+
* @param toolName Optional — the MCP tool that was being invoked. When
|
|
49
|
+
* supplied, surfaces in the `auth_required` hint so the
|
|
50
|
+
* LLM agent knows which call to retry.
|
|
51
|
+
*/
|
|
52
|
+
export declare function classifyError(err: unknown, toolName?: string): ToolError;
|
|
53
|
+
/**
|
|
54
|
+
* Build the MCP `CallToolResult` envelope for a classified error.
|
|
55
|
+
*
|
|
56
|
+
* Returns the canonical shape:
|
|
57
|
+
* {
|
|
58
|
+
* isError: true,
|
|
59
|
+
* content: [{ type: "text", text: "<json string>" }],
|
|
60
|
+
* structuredContent: <ToolError as object>
|
|
61
|
+
* }
|
|
62
|
+
*
|
|
63
|
+
* The JSON-in-text duplication is intentional: MCP clients that only
|
|
64
|
+
* surface text content (current Claude Desktop fallback path) still get
|
|
65
|
+
* a parseable payload, while spec-compliant clients pick up the
|
|
66
|
+
* structured field directly.
|
|
67
|
+
*
|
|
68
|
+
* The return type is `unknown` so callers don't need to import the SDK's
|
|
69
|
+
* private `CallToolResult` zod type — the server handler returns
|
|
70
|
+
* `Promise<{ ... }>` and TS infers the shape at the call site.
|
|
71
|
+
*/
|
|
72
|
+
export declare function renderToolError(toolError: ToolError): {
|
|
73
|
+
isError: true;
|
|
74
|
+
content: Array<{
|
|
75
|
+
type: "text";
|
|
76
|
+
text: string;
|
|
77
|
+
}>;
|
|
78
|
+
structuredContent: Record<string, unknown>;
|
|
79
|
+
};
|