mrmainspring 0.3.0 → 0.3.1
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 +49 -49
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +107 -279
- package/dist/client-setup.js +16 -103
- package/dist/mcp/grimoireTools.js +0 -10
- package/dist/mcp/memoryTools.js +0 -8
- package/dist/mcp/paymentTools.js +0 -8
- package/package.json +63 -63
package/README.md
CHANGED
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
# Mr Mainspring
|
|
2
|
-
|
|
3
|
-
Installable MCP backend for local agent demos. It exposes memory, Grimoire
|
|
4
|
-
policy/secret storage, payment intent tools, audit trail tools, Casper anchoring
|
|
5
|
-
boundaries, and x402 settlement-provider wiring.
|
|
6
|
-
|
|
7
|
-
## Install
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install -g mrmainspring
|
|
11
|
-
mainspring setup cursor
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
Run the stdio MCP server:
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
mainspring
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
For local development from this repository:
|
|
21
|
-
|
|
22
|
-
```bash
|
|
23
|
-
npm run build
|
|
24
|
-
npm run mcp:stdio
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## Environment
|
|
28
|
-
|
|
29
|
-
No environment variables are required for local memory, Grimoire, audit, or
|
|
30
|
-
payment preflight tools. `mainspring setup` creates the local config, data, and
|
|
31
|
-
logs directories under the user's standard app config folder. Use
|
|
32
|
-
`SIGIL_ENV_FILE` to point at a specific env file for advanced setups.
|
|
33
|
-
|
|
34
|
-
Important package boundaries:
|
|
35
|
-
|
|
36
|
-
- Keep `.env`, local keys, and generated demo data outside the npm package.
|
|
37
|
-
- Real Casper submission remains gated by `CASPER_ENABLE_REAL_SUBMISSION=true`.
|
|
38
|
-
- Real x402 settlement remains gated by `X402_ENABLE_REAL_SETTLEMENT=true` and
|
|
39
|
-
a configured `X402_SIGNER_URL`.
|
|
40
|
-
- The signer private key must live outside the repository workspace.
|
|
41
|
-
|
|
42
|
-
## Library Entry
|
|
43
|
-
|
|
44
|
-
```ts
|
|
45
|
-
import { createSigilServer } from "mrmainspring";
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
The CLI entry is also exported as `mrmainspring/mcp`, but importing it starts
|
|
49
|
-
the stdio server; use the package bin for normal MCP client configuration.
|
|
1
|
+
# Mr Mainspring
|
|
2
|
+
|
|
3
|
+
Installable MCP backend for local agent demos. It exposes memory, Grimoire
|
|
4
|
+
policy/secret storage, payment intent tools, audit trail tools, Casper anchoring
|
|
5
|
+
boundaries, and x402 settlement-provider wiring.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g mrmainspring
|
|
11
|
+
mainspring setup cursor
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Run the stdio MCP server:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
mainspring
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
For local development from this repository:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm run build
|
|
24
|
+
npm run mcp:stdio
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Environment
|
|
28
|
+
|
|
29
|
+
No environment variables are required for local memory, Grimoire, audit, or
|
|
30
|
+
payment preflight tools. `mainspring setup` creates the local config, data, and
|
|
31
|
+
logs directories under the user's standard app config folder. Use
|
|
32
|
+
`SIGIL_ENV_FILE` to point at a specific env file for advanced setups.
|
|
33
|
+
|
|
34
|
+
Important package boundaries:
|
|
35
|
+
|
|
36
|
+
- Keep `.env`, local keys, and generated demo data outside the npm package.
|
|
37
|
+
- Real Casper submission remains gated by `CASPER_ENABLE_REAL_SUBMISSION=true`.
|
|
38
|
+
- Real x402 settlement remains gated by `X402_ENABLE_REAL_SETTLEMENT=true` and
|
|
39
|
+
a configured `X402_SIGNER_URL`.
|
|
40
|
+
- The signer private key must live outside the repository workspace.
|
|
41
|
+
|
|
42
|
+
## Library Entry
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { createSigilServer } from "mrmainspring";
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The CLI entry is also exported as `mrmainspring/mcp`, but importing it starts
|
|
49
|
+
the stdio server; use the package bin for normal MCP client configuration.
|
package/dist/cli.d.ts
CHANGED
|
@@ -5,5 +5,5 @@ type InitResult = {
|
|
|
5
5
|
};
|
|
6
6
|
export declare function runCliCommand(args: string[]): Promise<boolean>;
|
|
7
7
|
export declare function initializeLocalSetup(env?: NodeJS.ProcessEnv): InitResult;
|
|
8
|
-
export declare function formatMcpConfig(): string;
|
|
8
|
+
export declare function formatMcpConfig(target?: string): string;
|
|
9
9
|
export {};
|
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { spawnSync } from "node:child_process";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
@@ -9,42 +9,32 @@ import { ensureGrimoireMasterKey, loadLocalEnvFile, resolveEnvPath } from "./env
|
|
|
9
9
|
import { getDefaultMainspringPaths } from "./paths.js";
|
|
10
10
|
const _pkgRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
11
11
|
const VERSION = JSON.parse(readFileSync(join(_pkgRoot, "package.json"), "utf8")).version;
|
|
12
|
-
const HELP = `Mr Mainspring MCP server
|
|
13
|
-
|
|
14
|
-
Usage:
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
or payment preflight tools.
|
|
12
|
+
const HELP = `Mr Mainspring MCP server
|
|
13
|
+
|
|
14
|
+
Usage:
|
|
15
|
+
mainspring Start the MCP stdio server
|
|
16
|
+
mainspring --help Show this help
|
|
17
|
+
mainspring --version Show the installed version
|
|
18
|
+
mainspring init Create local config, data, and logs directories
|
|
19
|
+
mainspring config [client] Print MCP client config for codex/cursor/claude
|
|
20
|
+
mainspring setup Initialize local files and print MCP config
|
|
21
|
+
mainspring doctor Check the local setup
|
|
22
|
+
mainspring update Show how to update to the latest version
|
|
23
|
+
|
|
24
|
+
MCP client config:
|
|
25
|
+
{
|
|
26
|
+
"mcpServers": {
|
|
27
|
+
"mainspring": {
|
|
28
|
+
"command": "npx",
|
|
29
|
+
"args": ["-y", "mrmainspring"]
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
Advanced users can still set SIGIL_ENV_FILE, SIGIL_DATA_DIR, Supabase, Casper,
|
|
35
|
+
and x402 env vars. No env vars are required for local memory, Grimoire, audit,
|
|
36
|
+
or payment preflight tools.
|
|
38
37
|
`;
|
|
39
|
-
function appendEnvVars(envFile, vars) {
|
|
40
|
-
const existing = existsSync(envFile) ? readFileSync(envFile, "utf8") : "";
|
|
41
|
-
const toWrite = Object.entries(vars).filter(([k]) => !existing.includes(`${k}=`));
|
|
42
|
-
if (toWrite.length === 0)
|
|
43
|
-
return [];
|
|
44
|
-
const block = "\n# Mainspring setup\n" + toWrite.map(([k, v]) => `${k}=${v}`).join("\n") + "\n";
|
|
45
|
-
appendFileSync(envFile, block, "utf8");
|
|
46
|
-
return toWrite.map(([k]) => k);
|
|
47
|
-
}
|
|
48
38
|
export async function runCliCommand(args) {
|
|
49
39
|
const [command, target] = args;
|
|
50
40
|
if (!command || command === "stdio" || command === "server" || command === "mcp") {
|
|
@@ -64,12 +54,11 @@ export async function runCliCommand(args) {
|
|
|
64
54
|
return true;
|
|
65
55
|
}
|
|
66
56
|
if (command === "config") {
|
|
67
|
-
process.stdout.write(`${formatMcpConfig()}\n`);
|
|
57
|
+
process.stdout.write(`${formatMcpConfig(target)}\n`);
|
|
68
58
|
return true;
|
|
69
59
|
}
|
|
70
60
|
if (command === "setup") {
|
|
71
|
-
|
|
72
|
-
if (forceInteractive || (process.stdin.isTTY ?? process.stdout.isTTY)) {
|
|
61
|
+
if (process.stdin.isTTY) {
|
|
73
62
|
await runInteractiveSetup();
|
|
74
63
|
}
|
|
75
64
|
else {
|
|
@@ -82,23 +71,14 @@ export async function runCliCommand(args) {
|
|
|
82
71
|
}
|
|
83
72
|
else {
|
|
84
73
|
process.stdout.write("\nNo MCP clients detected automatically.\n" +
|
|
85
|
-
"Add this to your MCP client config:\n\n");
|
|
74
|
+
"Add this to your MCP client config (Claude Desktop, Cursor, Windsurf, Zed, VS Code, Continue, or any MCP host):\n\n");
|
|
86
75
|
process.stdout.write(`${formatMcpConfig()}\n`);
|
|
87
76
|
process.stdout.write("\nConfig file locations:\n" +
|
|
88
|
-
" Claude Desktop
|
|
89
|
-
"
|
|
90
|
-
"
|
|
91
|
-
"
|
|
92
|
-
"
|
|
93
|
-
" VS Code ~/.vscode/mcp.json\n" +
|
|
94
|
-
" Cline ~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json\n" +
|
|
95
|
-
" Roo Code ~/Library/Application Support/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/cline_mcp_settings.json\n" +
|
|
96
|
-
" Kilo Code ~/Library/Application Support/Code/User/globalStorage/kilocode.kilo-code/settings/cline_mcp_settings.json\n" +
|
|
97
|
-
" OpenCode ~/.config/opencode/config.json\n" +
|
|
98
|
-
" Amazon Q ~/.aws/amazonq/mcp.json\n" +
|
|
99
|
-
" Gemini CLI ~/.gemini/settings.json\n" +
|
|
100
|
-
" Codex CLI ~/.codex/config.json\n" +
|
|
101
|
-
" Continue.dev ~/.continue/config.json (array format)\n\n");
|
|
77
|
+
" Claude Desktop ~/Library/Application Support/Claude/claude_desktop_config.json\n" +
|
|
78
|
+
" Cursor ~/.cursor/mcp.json\n" +
|
|
79
|
+
" Windsurf ~/.codeium/windsurf/mcp_config.json\n" +
|
|
80
|
+
" Zed ~/.config/zed/settings.json (context_servers format)\n" +
|
|
81
|
+
" VS Code ~/.vscode/mcp.json\n\n");
|
|
102
82
|
}
|
|
103
83
|
}
|
|
104
84
|
return true;
|
|
@@ -118,69 +98,42 @@ export async function runCliCommand(args) {
|
|
|
118
98
|
process.exitCode = 1;
|
|
119
99
|
return true;
|
|
120
100
|
}
|
|
121
|
-
const CLOCK_ART = [
|
|
122
|
-
" .-.-. ",
|
|
123
|
-
" (( (__I__) )) ",
|
|
124
|
-
" .'_....._'. ",
|
|
125
|
-
" / / .12 . \\ \\ ",
|
|
126
|
-
" | | ' | ' | | ",
|
|
127
|
-
" | | 9 / 3 | | ",
|
|
128
|
-
" \\ \\ '.6.' / / ",
|
|
129
|
-
" '.`-...-'.' ",
|
|
130
|
-
" /'-- --'\\ ",
|
|
131
|
-
" `\"\"\"\"\"\"\"\"\"` ",
|
|
132
|
-
" ",
|
|
133
|
-
" Mr Mainspring ",
|
|
134
|
-
" Memory · Anchor · Pay ",
|
|
135
|
-
].join("\n");
|
|
136
101
|
async function runInteractiveSetup() {
|
|
137
|
-
|
|
138
|
-
clack.intro("setup");
|
|
139
|
-
// ── 1. Local files ──────────────────────────────────────────────────────────
|
|
140
|
-
const hadKey = !!process.env.GRIMOIRE_MASTER_KEY;
|
|
102
|
+
clack.intro("Mr Mainspring — setup");
|
|
141
103
|
const result = initializeLocalSetup();
|
|
142
|
-
|
|
143
|
-
clack.log.success(`Local files ready\n Config: ${result.envFile}\n Data: ${result.dataDir}\n ${keyNote}`);
|
|
144
|
-
// ── 2. Storage backend ──────────────────────────────────────────────────────
|
|
145
|
-
const storageChoice = await clack.select({
|
|
146
|
-
message: "Storage backend?",
|
|
147
|
-
options: [
|
|
148
|
-
{ value: "file", label: "Local files", hint: result.dataDir },
|
|
149
|
-
{ value: "supabase", label: "Supabase (cloud)", hint: "requires PROJECT_URL + SECRET_KEY" }
|
|
150
|
-
]
|
|
151
|
-
});
|
|
152
|
-
if (clack.isCancel(storageChoice)) {
|
|
153
|
-
clack.cancel("Setup cancelled.");
|
|
154
|
-
process.exitCode = 1;
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
if (storageChoice === "supabase") {
|
|
158
|
-
const projectUrl = await clack.text({ message: "Supabase PROJECT_URL:", placeholder: "https://xxx.supabase.co" });
|
|
159
|
-
if (clack.isCancel(projectUrl)) {
|
|
160
|
-
clack.cancel("Setup cancelled.");
|
|
161
|
-
process.exitCode = 1;
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
const secretKey = await clack.text({ message: "Supabase SECRET_KEY (service role):", placeholder: "eyJ..." });
|
|
165
|
-
if (clack.isCancel(secretKey)) {
|
|
166
|
-
clack.cancel("Setup cancelled.");
|
|
167
|
-
process.exitCode = 1;
|
|
168
|
-
return;
|
|
169
|
-
}
|
|
170
|
-
appendFileSync(result.envFile, `\nSIGIL_STORAGE_BACKEND=supabase\nPROJECT_URL=${projectUrl}\nSECRET_KEY=${secretKey}\n`, "utf8");
|
|
171
|
-
clack.log.success("Supabase config saved.");
|
|
172
|
-
}
|
|
173
|
-
// ── 3. MCP clients ──────────────────────────────────────────────────────────
|
|
104
|
+
clack.log.success(`Local files ready\n Config: ${result.envFile}\n Data: ${result.dataDir}`);
|
|
174
105
|
const clients = detectClients();
|
|
175
106
|
const installed = clients.filter(c => c.installed);
|
|
107
|
+
const notInstalled = clients.filter(c => !c.installed);
|
|
108
|
+
let selected;
|
|
109
|
+
if (installed.length === 0) {
|
|
110
|
+
clack.log.warn("No MCP clients detected on this machine.");
|
|
111
|
+
clack.log.info("Add this JSON to your client config manually:\n\n" +
|
|
112
|
+
formatMcpConfig() + "\n\n" +
|
|
113
|
+
" Claude Desktop ~/Library/Application Support/Claude/claude_desktop_config.json\n" +
|
|
114
|
+
" Cursor ~/.cursor/mcp.json\n" +
|
|
115
|
+
" Windsurf ~/.codeium/windsurf/mcp_config.json\n" +
|
|
116
|
+
" Zed ~/.config/zed/settings.json\n" +
|
|
117
|
+
" VS Code ~/.vscode/mcp.json");
|
|
118
|
+
clack.outro("Restart your client after updating the config.");
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
176
121
|
const choices = await clack.multiselect({
|
|
177
122
|
message: "Which MCP clients should we configure?",
|
|
178
|
-
options:
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
123
|
+
options: [
|
|
124
|
+
...installed.map(c => ({
|
|
125
|
+
value: c,
|
|
126
|
+
label: c.name,
|
|
127
|
+
hint: c.configPath,
|
|
128
|
+
selected: true
|
|
129
|
+
})),
|
|
130
|
+
...notInstalled.map(c => ({
|
|
131
|
+
value: c,
|
|
132
|
+
label: c.name,
|
|
133
|
+
hint: "not found",
|
|
134
|
+
selected: false
|
|
135
|
+
}))
|
|
136
|
+
],
|
|
184
137
|
required: false
|
|
185
138
|
});
|
|
186
139
|
if (clack.isCancel(choices)) {
|
|
@@ -188,31 +141,13 @@ async function runInteractiveSetup() {
|
|
|
188
141
|
process.exitCode = 1;
|
|
189
142
|
return;
|
|
190
143
|
}
|
|
191
|
-
|
|
144
|
+
selected = choices;
|
|
192
145
|
if (selected.length === 0) {
|
|
193
|
-
clack.log.warn("No clients selected.");
|
|
194
|
-
|
|
195
|
-
message: "Enter a config file path to configure manually (or press Enter to skip):",
|
|
196
|
-
placeholder: "~/.config/myapp/mcp.json",
|
|
197
|
-
validate: () => undefined
|
|
198
|
-
});
|
|
199
|
-
if (!clack.isCancel(customPath) && customPath && customPath.trim()) {
|
|
200
|
-
const expandedPath = customPath.replace(/^~/, process.env.HOME ?? "");
|
|
201
|
-
const r = configureClients([{ name: "Custom", configPath: expandedPath, installed: true, format: "standard" }])[0];
|
|
202
|
-
if (r?.status === "written")
|
|
203
|
-
clack.log.success(`Configured: ${expandedPath}`);
|
|
204
|
-
else if (r?.status === "already-set")
|
|
205
|
-
clack.log.info(`Already configured: ${expandedPath}`);
|
|
206
|
-
else if (r?.error)
|
|
207
|
-
clack.log.error(`Failed: ${r.error}`);
|
|
208
|
-
}
|
|
209
|
-
else {
|
|
210
|
-
clack.log.info("Add this JSON to your MCP client config:\n\n" + formatMcpConfig());
|
|
211
|
-
}
|
|
212
|
-
clack.outro("Restart your MCP client after updating the config.");
|
|
146
|
+
clack.log.warn("No clients selected — nothing configured.");
|
|
147
|
+
clack.outro("Run mainspring setup again when ready.");
|
|
213
148
|
return;
|
|
214
149
|
}
|
|
215
|
-
const configResults = configureClients(selected);
|
|
150
|
+
const configResults = configureClients(selected.filter(c => c.installed));
|
|
216
151
|
const written = configResults.filter(r => r.status === "written").map(r => r.name);
|
|
217
152
|
const alreadySet = configResults.filter(r => r.status === "already-set").map(r => r.name);
|
|
218
153
|
const errors = configResults.filter(r => r.status === "error");
|
|
@@ -222,154 +157,36 @@ async function runInteractiveSetup() {
|
|
|
222
157
|
clack.log.info(`Already configured: ${alreadySet.join(", ")}`);
|
|
223
158
|
for (const e of errors)
|
|
224
159
|
clack.log.error(`${e.name}: ${e.error}`);
|
|
225
|
-
|
|
226
|
-
|
|
160
|
+
const wantCasper = await clack.confirm({
|
|
161
|
+
message: "Enable Casper on-chain anchoring?",
|
|
162
|
+
initialValue: false
|
|
163
|
+
});
|
|
227
164
|
if (clack.isCancel(wantCasper)) {
|
|
228
165
|
clack.cancel("Setup cancelled.");
|
|
229
166
|
return;
|
|
230
167
|
}
|
|
231
|
-
let casperRpcUrl = "https://node.testnet.casper.network/rpc";
|
|
232
|
-
let casperNetwork = "testnet";
|
|
233
168
|
if (wantCasper) {
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
]
|
|
240
|
-
});
|
|
241
|
-
if (clack.isCancel(network)) {
|
|
242
|
-
clack.cancel("Setup cancelled.");
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
casperNetwork = network;
|
|
246
|
-
casperRpcUrl = casperNetwork === "mainnet"
|
|
247
|
-
? "https://node.mainnet.casper.network/rpc"
|
|
248
|
-
: "https://node.testnet.casper.network/rpc";
|
|
249
|
-
const casperBin = process.env.CASPER_CLIENT_BIN ?? "casper-client";
|
|
250
|
-
const casperAvailable = !spawnSync(casperBin, ["--version"], { stdio: "pipe" }).error;
|
|
251
|
-
const keyOptions = [
|
|
252
|
-
{ value: "have", label: "I already have a key pair (.pem)" },
|
|
253
|
-
{ value: "skip", label: "Skip for now" }
|
|
254
|
-
];
|
|
255
|
-
if (casperAvailable) {
|
|
256
|
-
keyOptions.splice(1, 0, { value: "generate", label: "Generate a new key pair now", hint: "runs casper-client keygen ./keys" });
|
|
257
|
-
}
|
|
258
|
-
const keyAction = await clack.select({ message: "Casper key pair?", options: keyOptions });
|
|
259
|
-
if (clack.isCancel(keyAction)) {
|
|
260
|
-
clack.cancel("Setup cancelled.");
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
if (keyAction === "generate") {
|
|
264
|
-
mkdirSync("./keys", { recursive: true });
|
|
265
|
-
const keygen = spawnSync(casperBin, ["keygen", "./keys"], { stdio: "pipe" });
|
|
266
|
-
if (keygen.status === 0) {
|
|
267
|
-
clack.log.success("Key pair generated in ./keys/\n Secret: ./keys/secret_key.pem\n Public: ./keys/public_key.pem");
|
|
268
|
-
}
|
|
269
|
-
else {
|
|
270
|
-
clack.log.error("keygen failed: " + (keygen.stderr?.toString() ?? "unknown error"));
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
const keyPath = keyAction === "generate" ? "./keys/secret_key.pem" : "./keys/your-secret-key.pem";
|
|
274
|
-
const casperVars = {
|
|
275
|
-
CASPER_ENABLE_REAL_SUBMISSION: "true",
|
|
276
|
-
CASPER_RPC_URL: casperRpcUrl,
|
|
277
|
-
CASPER_ACCOUNT_KEY_PATH: keyPath
|
|
278
|
-
};
|
|
279
|
-
clack.log.info("Casper vars:\n\n" +
|
|
280
|
-
Object.entries(casperVars).map(([k, v]) => ` ${k}=${v}`).join("\n") +
|
|
281
|
-
`\n\n .env: ${result.envFile}`);
|
|
282
|
-
const writeCasper = await clack.confirm({ message: "Write these to your .env now?", initialValue: true });
|
|
283
|
-
if (!clack.isCancel(writeCasper) && writeCasper) {
|
|
284
|
-
const written = appendEnvVars(result.envFile, casperVars);
|
|
285
|
-
if (written.length > 0)
|
|
286
|
-
clack.log.success(`Written: ${written.join(", ")}`);
|
|
287
|
-
else
|
|
288
|
-
clack.log.info("Already set in .env — skipped.");
|
|
289
|
-
}
|
|
169
|
+
clack.log.info("Add to your .env file:\n\n" +
|
|
170
|
+
" CASPER_ENABLE_REAL_SUBMISSION=true\n" +
|
|
171
|
+
" CASPER_RPC_URL=https://node.testnet.casper.network/rpc\n" +
|
|
172
|
+
" CASPER_ACCOUNT_KEY_PATH=./keys/your-key.pem\n\n" +
|
|
173
|
+
"Then restart your MCP client.");
|
|
290
174
|
}
|
|
291
|
-
|
|
292
|
-
|
|
175
|
+
const wantX402 = await clack.confirm({
|
|
176
|
+
message: "Enable x402 micropayments?",
|
|
177
|
+
initialValue: false
|
|
178
|
+
});
|
|
293
179
|
if (clack.isCancel(wantX402)) {
|
|
294
180
|
clack.cancel("Setup cancelled.");
|
|
295
181
|
return;
|
|
296
182
|
}
|
|
297
183
|
if (wantX402) {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
{ value: "testnet", label: "Testnet", hint: "free faucet available" },
|
|
305
|
-
{ value: "mainnet", label: "Mainnet", hint: "real CSPR" }
|
|
306
|
-
]
|
|
307
|
-
});
|
|
308
|
-
if (!clack.isCancel(network)) {
|
|
309
|
-
x402Network = network;
|
|
310
|
-
x402RpcUrl = x402Network === "mainnet"
|
|
311
|
-
? "https://node.mainnet.casper.network/rpc"
|
|
312
|
-
: "https://node.testnet.casper.network/rpc";
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
const explorerBase = x402Network === "mainnet" ? "https://cspr.live" : "https://testnet.cspr.live";
|
|
316
|
-
clack.log.info("x402 setup — 3 steps:");
|
|
317
|
-
clack.log.info("Step 1 — Get your Casper account hash\n\n" +
|
|
318
|
-
" Your account hash identifies your wallet on-chain.\n" +
|
|
319
|
-
" From a .pem file:\n\n" +
|
|
320
|
-
" casper-client account-address --public-key ./keys/public_key.pem\n\n" +
|
|
321
|
-
" From a hex public key:\n\n" +
|
|
322
|
-
" casper-client account-address --public-key 02<your-hex-pubkey>\n\n" +
|
|
323
|
-
" Output looks like:\n" +
|
|
324
|
-
" account-hash-d0a57c6a95e74463de156cac761e17f0923eafc730ce3ce3a0c747c6598b0500\n\n" +
|
|
325
|
-
" No casper-client? Install: cargo install casper-client");
|
|
326
|
-
const x402Vars = {
|
|
327
|
-
X402_ENABLE_REAL_SETTLEMENT: "true",
|
|
328
|
-
X402_SETTLEMENT_MODE: "casper-cli",
|
|
329
|
-
X402_BUYER_ACCOUNT_HASH: "account-hash-REPLACE_WITH_YOUR_HASH",
|
|
330
|
-
CASPER_ENABLE_REAL_SUBMISSION: "true",
|
|
331
|
-
CASPER_RPC_URL: x402RpcUrl,
|
|
332
|
-
CASPER_ACCOUNT_KEY_PATH: "./keys/secret_key.pem"
|
|
333
|
-
};
|
|
334
|
-
clack.log.info("Step 2 — .env vars:\n\n" +
|
|
335
|
-
Object.entries(x402Vars).map(([k, v]) => ` ${k}=${v}`).join("\n") +
|
|
336
|
-
`\n\n .env: ${result.envFile}`);
|
|
337
|
-
const writeX402 = await clack.confirm({
|
|
338
|
-
message: "Write these to your .env? (you'll still need to replace X402_BUYER_ACCOUNT_HASH)",
|
|
339
|
-
initialValue: true
|
|
340
|
-
});
|
|
341
|
-
if (!clack.isCancel(writeX402) && writeX402) {
|
|
342
|
-
const written = appendEnvVars(result.envFile, x402Vars);
|
|
343
|
-
if (written.length > 0) {
|
|
344
|
-
clack.log.success(`Written: ${written.join(", ")}`);
|
|
345
|
-
if (written.includes("X402_BUYER_ACCOUNT_HASH")) {
|
|
346
|
-
clack.log.warn(`Edit X402_BUYER_ACCOUNT_HASH in ${result.envFile} with your actual account hash after running Step 1.`);
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
else {
|
|
350
|
-
clack.log.info("Already set in .env — skipped.");
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
clack.log.info("Step 3 — Fund your account\n\n" +
|
|
354
|
-
(x402Network === "testnet"
|
|
355
|
-
? ` Faucet: ${explorerBase}/tools/faucet\n`
|
|
356
|
-
: " Transfer CSPR to your account.\n") +
|
|
357
|
-
` Verify balance: ${explorerBase} → search your account hash`);
|
|
358
|
-
}
|
|
359
|
-
// ── 6. Doctor check ─────────────────────────────────────────────────────────
|
|
360
|
-
const doctorOutput = formatDoctorReport();
|
|
361
|
-
const doctorLines = doctorOutput.split("\n").filter(Boolean);
|
|
362
|
-
const hasIssues = doctorLines.some(l => l.startsWith("[warn]") || l.startsWith("[error]"));
|
|
363
|
-
const doctorMsg = doctorLines
|
|
364
|
-
.slice(1)
|
|
365
|
-
.map(l => l.startsWith("[ok]") ? ` ✓ ${l.slice(5)}` :
|
|
366
|
-
l.startsWith("[warn]") ? ` ⚠ ${l.slice(7)}` :
|
|
367
|
-
l.startsWith("[error]") ? ` ✗ ${l.slice(8)}` : ` ${l}`).join("\n");
|
|
368
|
-
if (hasIssues) {
|
|
369
|
-
clack.log.warn(`System check:\n${doctorMsg}`);
|
|
370
|
-
}
|
|
371
|
-
else {
|
|
372
|
-
clack.log.success(`System check:\n${doctorMsg}`);
|
|
184
|
+
clack.log.info("Add to your .env file:\n\n" +
|
|
185
|
+
" X402_ENABLE_REAL_SETTLEMENT=true\n" +
|
|
186
|
+
" X402_SETTLEMENT_MODE=casper-cli\n" +
|
|
187
|
+
" X402_BUYER_ACCOUNT_HASH=account-hash-<64 hex chars>\n" +
|
|
188
|
+
" CASPER_ENABLE_REAL_SUBMISSION=true\n\n" +
|
|
189
|
+
"Get your account hash: casper-client account-address --public-key <your-pubkey-hex>");
|
|
373
190
|
}
|
|
374
191
|
clack.outro("Restart your MCP clients to load the server.");
|
|
375
192
|
}
|
|
@@ -397,7 +214,17 @@ export function initializeLocalSetup(env = process.env) {
|
|
|
397
214
|
logsDir: paths.logsDir
|
|
398
215
|
};
|
|
399
216
|
}
|
|
400
|
-
export function formatMcpConfig() {
|
|
217
|
+
export function formatMcpConfig(target) {
|
|
218
|
+
if (normalizeMcpClientTarget(target) === "codex") {
|
|
219
|
+
return [
|
|
220
|
+
"[mcp_servers.mainspring]",
|
|
221
|
+
'command = "npx"',
|
|
222
|
+
'args = ["-y", "mrmainspring"]',
|
|
223
|
+
"startup_timeout_sec = 20",
|
|
224
|
+
"tool_timeout_sec = 60",
|
|
225
|
+
"enabled = true"
|
|
226
|
+
].join("\n");
|
|
227
|
+
}
|
|
401
228
|
return JSON.stringify({
|
|
402
229
|
mcpServers: {
|
|
403
230
|
mainspring: {
|
|
@@ -445,14 +272,15 @@ function formatDoctorReport(env = process.env) {
|
|
|
445
272
|
function formatCheck(ok, success, failure) {
|
|
446
273
|
return ok ? `[ok] ${success}` : `[warn] ${failure}`;
|
|
447
274
|
}
|
|
448
|
-
function
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
275
|
+
function normalizeMcpClientTarget(target) {
|
|
276
|
+
const normalized = target?.trim().toLowerCase();
|
|
277
|
+
if (normalized === "codex")
|
|
278
|
+
return "codex";
|
|
279
|
+
if (normalized === "cursor")
|
|
280
|
+
return "cursor";
|
|
281
|
+
if (normalized === "claude" || normalized === "claude-desktop" || normalized === "claude_desktop")
|
|
282
|
+
return "claude";
|
|
283
|
+
return "generic";
|
|
456
284
|
}
|
|
457
285
|
function quoteEnvValue(value) {
|
|
458
286
|
return `"${value.replace(/"/g, "")}"`;
|
package/dist/client-setup.js
CHANGED
|
@@ -11,106 +11,20 @@ const CLIENTS = [
|
|
|
11
11
|
{ name: "Claude Desktop", path: "%APPDATA%/Claude/claude_desktop_config.json", platforms: ["win32"], format: "standard" },
|
|
12
12
|
{ name: "Claude Desktop", path: "~/.config/Claude/claude_desktop_config.json", platforms: ["linux"], format: "standard" },
|
|
13
13
|
// Claude Code CLI
|
|
14
|
-
{
|
|
15
|
-
name: "Claude Code", path: "~/.claude/settings.json", platforms: ["darwin", "linux", "win32"], format: "standard",
|
|
16
|
-
appPaths: ["/usr/local/bin/claude", "/usr/bin/claude"]
|
|
17
|
-
},
|
|
14
|
+
{ name: "Claude Code", path: "~/.claude/settings.json", platforms: ["darwin", "linux", "win32"], format: "standard" },
|
|
18
15
|
// Cursor
|
|
19
|
-
{
|
|
20
|
-
|
|
21
|
-
appPaths: ["/Applications/Cursor.app", `${homedir()}/Applications/Cursor.app`]
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
name: "Cursor", path: "%USERPROFILE%/.cursor/mcp.json", platforms: ["win32"], format: "standard",
|
|
25
|
-
appPaths: ["C:/Users/Default/AppData/Local/Programs/cursor/Cursor.exe"]
|
|
26
|
-
},
|
|
16
|
+
{ name: "Cursor", path: "~/.cursor/mcp.json", platforms: ["darwin", "linux"], format: "standard" },
|
|
17
|
+
{ name: "Cursor", path: "%USERPROFILE%/.cursor/mcp.json", platforms: ["win32"], format: "standard" },
|
|
27
18
|
// Windsurf
|
|
28
|
-
{
|
|
29
|
-
|
|
30
|
-
appPaths: ["/Applications/Windsurf.app", `${homedir()}/Applications/Windsurf.app`]
|
|
31
|
-
},
|
|
19
|
+
{ name: "Windsurf", path: "~/.codeium/windsurf/mcp_config.json", platforms: ["darwin", "linux", "win32"], format: "standard" },
|
|
20
|
+
// Windsurf (also on Windows via AppData)
|
|
32
21
|
{ name: "Windsurf", path: "%APPDATA%/Windsurf/User/globalStorage/codeium.windsurf/mcp_config.json", platforms: ["win32"], format: "standard" },
|
|
33
22
|
// Zed
|
|
34
|
-
{
|
|
35
|
-
name: "Zed", path: "~/.config/zed/settings.json", platforms: ["darwin", "linux"], format: "zed",
|
|
36
|
-
appPaths: ["/Applications/Zed.app", `${homedir()}/Applications/Zed.app`]
|
|
37
|
-
},
|
|
23
|
+
{ name: "Zed", path: "~/.config/zed/settings.json", platforms: ["darwin", "linux"], format: "zed" },
|
|
38
24
|
// Continue.dev
|
|
39
25
|
{ name: "Continue", path: "~/.continue/config.json", platforms: ["darwin", "linux", "win32"], format: "continue" },
|
|
40
|
-
// VS Code (
|
|
41
|
-
{
|
|
42
|
-
name: "VS Code", path: "~/.vscode/mcp.json", platforms: ["darwin", "linux"], format: "standard",
|
|
43
|
-
appPaths: ["/Applications/Visual Studio Code.app", `${homedir()}/Applications/Visual Studio Code.app`, "/usr/bin/code", "/usr/local/bin/code"]
|
|
44
|
-
},
|
|
45
|
-
{ name: "VS Code", path: "~/.vscode/mcp.json", platforms: ["win32"], format: "standard" },
|
|
46
|
-
// Cline (VS Code extension by saoudrizwan)
|
|
47
|
-
{
|
|
48
|
-
name: "Cline",
|
|
49
|
-
path: "~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json",
|
|
50
|
-
detectDir: "~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev",
|
|
51
|
-
platforms: ["darwin"], format: "standard"
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
name: "Cline",
|
|
55
|
-
path: "~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json",
|
|
56
|
-
detectDir: "~/.config/Code/User/globalStorage/saoudrizwan.claude-dev",
|
|
57
|
-
platforms: ["linux"], format: "standard"
|
|
58
|
-
},
|
|
59
|
-
{
|
|
60
|
-
name: "Cline",
|
|
61
|
-
path: "%APPDATA%/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json",
|
|
62
|
-
detectDir: "%APPDATA%/Code/User/globalStorage/saoudrizwan.claude-dev",
|
|
63
|
-
platforms: ["win32"], format: "standard"
|
|
64
|
-
},
|
|
65
|
-
// Roo Code (VS Code extension, fork of Cline)
|
|
66
|
-
{
|
|
67
|
-
name: "Roo Code",
|
|
68
|
-
path: "~/Library/Application Support/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/cline_mcp_settings.json",
|
|
69
|
-
detectDir: "~/Library/Application Support/Code/User/globalStorage/rooveterinaryinc.roo-cline",
|
|
70
|
-
platforms: ["darwin"], format: "standard"
|
|
71
|
-
},
|
|
72
|
-
{
|
|
73
|
-
name: "Roo Code",
|
|
74
|
-
path: "~/.config/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/cline_mcp_settings.json",
|
|
75
|
-
detectDir: "~/.config/Code/User/globalStorage/rooveterinaryinc.roo-cline",
|
|
76
|
-
platforms: ["linux"], format: "standard"
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
name: "Roo Code",
|
|
80
|
-
path: "%APPDATA%/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/cline_mcp_settings.json",
|
|
81
|
-
detectDir: "%APPDATA%/Code/User/globalStorage/rooveterinaryinc.roo-cline",
|
|
82
|
-
platforms: ["win32"], format: "standard"
|
|
83
|
-
},
|
|
84
|
-
// Kilo Code (VS Code extension)
|
|
85
|
-
{
|
|
86
|
-
name: "Kilo Code",
|
|
87
|
-
path: "~/Library/Application Support/Code/User/globalStorage/kilocode.kilo-code/settings/cline_mcp_settings.json",
|
|
88
|
-
detectDir: "~/Library/Application Support/Code/User/globalStorage/kilocode.kilo-code",
|
|
89
|
-
platforms: ["darwin"], format: "standard"
|
|
90
|
-
},
|
|
91
|
-
{
|
|
92
|
-
name: "Kilo Code",
|
|
93
|
-
path: "~/.config/Code/User/globalStorage/kilocode.kilo-code/settings/cline_mcp_settings.json",
|
|
94
|
-
detectDir: "~/.config/Code/User/globalStorage/kilocode.kilo-code",
|
|
95
|
-
platforms: ["linux"], format: "standard"
|
|
96
|
-
},
|
|
97
|
-
{
|
|
98
|
-
name: "Kilo Code",
|
|
99
|
-
path: "%APPDATA%/Code/User/globalStorage/kilocode.kilo-code/settings/cline_mcp_settings.json",
|
|
100
|
-
detectDir: "%APPDATA%/Code/User/globalStorage/kilocode.kilo-code",
|
|
101
|
-
platforms: ["win32"], format: "standard"
|
|
102
|
-
},
|
|
103
|
-
// OpenCode (terminal AI coding assistant)
|
|
104
|
-
{ name: "OpenCode", path: "~/.config/opencode/config.json", platforms: ["darwin", "linux"], format: "standard" },
|
|
105
|
-
{ name: "OpenCode", path: "%APPDATA%/opencode/config.json", platforms: ["win32"], format: "standard" },
|
|
106
|
-
// Amazon Q Developer
|
|
107
|
-
{ name: "Amazon Q", path: "~/.aws/amazonq/mcp.json", platforms: ["darwin", "linux"], format: "standard" },
|
|
108
|
-
{ name: "Amazon Q", path: "%USERPROFILE%/.aws/amazonq/mcp.json", platforms: ["win32"], format: "standard" },
|
|
109
|
-
// Gemini CLI (Google)
|
|
110
|
-
{ name: "Gemini CLI", path: "~/.gemini/settings.json", platforms: ["darwin", "linux"], format: "standard" },
|
|
111
|
-
{ name: "Gemini CLI", path: "%USERPROFILE%/.gemini/settings.json", platforms: ["win32"], format: "standard" },
|
|
112
|
-
// Codex CLI (OpenAI)
|
|
113
|
-
{ name: "Codex CLI", path: "~/.codex/config.json", platforms: ["darwin", "linux", "win32"], format: "standard" },
|
|
26
|
+
// VS Code (workspace-agnostic user MCP config — requires MCP extension)
|
|
27
|
+
{ name: "VS Code", path: "~/.vscode/mcp.json", platforms: ["darwin", "linux", "win32"], format: "standard" },
|
|
114
28
|
];
|
|
115
29
|
function expandPath(p, env) {
|
|
116
30
|
const home = env.HOME ?? env.USERPROFILE ?? homedir();
|
|
@@ -119,11 +33,8 @@ function expandPath(p, env) {
|
|
|
119
33
|
.replace(/%APPDATA%/gi, env.APPDATA ?? "")
|
|
120
34
|
.replace(/%USERPROFILE%/gi, env.USERPROFILE ?? home);
|
|
121
35
|
}
|
|
122
|
-
function isInstalled(configPath
|
|
123
|
-
|
|
124
|
-
if (existsSync(dir) || existsSync(configPath))
|
|
125
|
-
return true;
|
|
126
|
-
return appPaths?.some(p => existsSync(p)) ?? false;
|
|
36
|
+
function isInstalled(configPath) {
|
|
37
|
+
return existsSync(dirname(configPath)) || existsSync(configPath);
|
|
127
38
|
}
|
|
128
39
|
function readJson(path) {
|
|
129
40
|
if (!existsSync(path))
|
|
@@ -183,14 +94,17 @@ export function detectClients(env = process.env) {
|
|
|
183
94
|
if (seen.has(key))
|
|
184
95
|
continue;
|
|
185
96
|
seen.add(key);
|
|
186
|
-
|
|
187
|
-
results.push({ name: client.name, configPath, installed: isInstalled(configPath, detectDir, client.appPaths), format: client.format });
|
|
97
|
+
results.push({ name: client.name, configPath, installed: isInstalled(configPath), format: client.format });
|
|
188
98
|
}
|
|
189
99
|
return results;
|
|
190
100
|
}
|
|
191
101
|
export function configureClients(selected, env = process.env) {
|
|
192
102
|
const results = [];
|
|
193
103
|
for (const client of selected) {
|
|
104
|
+
if (!client.installed) {
|
|
105
|
+
results.push({ name: client.name, configPath: client.configPath, status: "not-installed" });
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
194
108
|
try {
|
|
195
109
|
const json = readJson(client.configPath);
|
|
196
110
|
if (alreadySet(json, client.format)) {
|
|
@@ -219,8 +133,7 @@ export function setupAllClients(env = process.env) {
|
|
|
219
133
|
if (seen.has(key))
|
|
220
134
|
continue;
|
|
221
135
|
seen.add(key);
|
|
222
|
-
|
|
223
|
-
if (!isInstalled(configPath, detectDir)) {
|
|
136
|
+
if (!isInstalled(configPath)) {
|
|
224
137
|
results.push({ name: client.name, configPath, status: "not-installed" });
|
|
225
138
|
continue;
|
|
226
139
|
}
|
|
@@ -26,11 +26,6 @@ export function registerGrimoireTools(server, grimoireService) {
|
|
|
26
26
|
}
|
|
27
27
|
}, async (input) => {
|
|
28
28
|
const secret = await grimoireService.putSecret(input);
|
|
29
|
-
server.sendLoggingMessage?.({
|
|
30
|
-
level: "info",
|
|
31
|
-
logger: "mainspring",
|
|
32
|
-
data: `Secret stored [${input.type}] ${input.name} (agent=${input.agent_id})`
|
|
33
|
-
})?.catch(() => { });
|
|
34
29
|
return jsonResult({
|
|
35
30
|
status: "stored",
|
|
36
31
|
secret
|
|
@@ -67,11 +62,6 @@ export function registerGrimoireTools(server, grimoireService) {
|
|
|
67
62
|
}
|
|
68
63
|
}, async (input) => {
|
|
69
64
|
const policy = await grimoireService.setPolicy(input);
|
|
70
|
-
server.sendLoggingMessage?.({
|
|
71
|
-
level: "info",
|
|
72
|
-
logger: "mainspring",
|
|
73
|
-
data: `Policy set [${input.policy_id}] max=${input.max_amount_per_call} per call (agent=${input.agent_id})`
|
|
74
|
-
})?.catch(() => { });
|
|
75
65
|
return jsonResult({
|
|
76
66
|
status: "stored",
|
|
77
67
|
policy
|
package/dist/mcp/memoryTools.js
CHANGED
|
@@ -18,14 +18,6 @@ export function registerMemoryTools(server, memoryService) {
|
|
|
18
18
|
}
|
|
19
19
|
}, async (input) => {
|
|
20
20
|
const memory = await memoryService.write(input);
|
|
21
|
-
const anchorNote = memory.anchor_status === "anchored" && memory.casper_transaction_hash
|
|
22
|
-
? ` · anchored tx=${memory.casper_transaction_hash.slice(0, 12)}…`
|
|
23
|
-
: memory.anchor_status === "pending" ? " · anchor pending" : "";
|
|
24
|
-
server.sendLoggingMessage?.({
|
|
25
|
-
level: "info",
|
|
26
|
-
logger: "mainspring",
|
|
27
|
-
data: `Memory saved [${input.type}] ${memory.memory_id}${anchorNote}`
|
|
28
|
-
})?.catch(() => { });
|
|
29
21
|
return jsonResult({
|
|
30
22
|
memory_id: memory.memory_id,
|
|
31
23
|
content_hash: memory.content_hash,
|
package/dist/mcp/paymentTools.js
CHANGED
|
@@ -21,14 +21,6 @@ export function registerPaymentTools(server, paymentService) {
|
|
|
21
21
|
}
|
|
22
22
|
}, async (input) => {
|
|
23
23
|
const result = await paymentService.fetch(input);
|
|
24
|
-
const status = result.status ?? "unknown";
|
|
25
|
-
const level = status === "settlement_unavailable" || status === "policy_blocked"
|
|
26
|
-
? "warning" : "info";
|
|
27
|
-
server.sendLoggingMessage?.({
|
|
28
|
-
level,
|
|
29
|
-
logger: "mainspring",
|
|
30
|
-
data: `Payment [${status}] ${input.method} ${input.url} (policy=${input.policy_id})`
|
|
31
|
-
})?.catch(() => { });
|
|
32
24
|
return jsonResult(result);
|
|
33
25
|
});
|
|
34
26
|
server.registerTool("payment.receipt", {
|
package/package.json
CHANGED
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "mrmainspring",
|
|
3
|
-
"version": "0.3.
|
|
4
|
-
"description": "Mr Mainspring MCP backend with memory, Grimoire policies, audit, Casper anchoring, and x402 settlement boundaries.",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"type": "module",
|
|
7
|
-
"bin": {
|
|
8
|
-
"mainspring": "dist/index.js",
|
|
9
|
-
"mrmainspring": "dist/index.js"
|
|
10
|
-
},
|
|
11
|
-
"main": "./dist/server.js",
|
|
12
|
-
"types": "./dist/server.d.ts",
|
|
13
|
-
"exports": {
|
|
14
|
-
".": {
|
|
15
|
-
"types": "./dist/server.d.ts",
|
|
16
|
-
"import": "./dist/server.js"
|
|
17
|
-
},
|
|
18
|
-
"./mcp": {
|
|
19
|
-
"types": "./dist/index.d.ts",
|
|
20
|
-
"import": "./dist/index.js"
|
|
21
|
-
},
|
|
22
|
-
"./package.json": "./package.json"
|
|
23
|
-
},
|
|
24
|
-
"publishConfig": {
|
|
25
|
-
"access": "public"
|
|
26
|
-
},
|
|
27
|
-
"files": [
|
|
28
|
-
"dist/**/*.js",
|
|
29
|
-
"dist/**/*.d.ts",
|
|
30
|
-
"LICENSE",
|
|
31
|
-
"README.md",
|
|
32
|
-
"package.json"
|
|
33
|
-
],
|
|
34
|
-
"scripts": {
|
|
35
|
-
"build": "tsc -p tsconfig.json",
|
|
36
|
-
"demo:stdio": "npm run build && tsx scripts/demo-stdio.ts",
|
|
37
|
-
"demo:x402-http": "tsx scripts/x402-demo-http-server.ts",
|
|
38
|
-
"demo:x402-sidecars": "tsx scripts/x402-local-sidecars.ts",
|
|
39
|
-
"demo:x402-sidecars:smoke": "tsx scripts/x402-local-sidecars.ts --smoke",
|
|
40
|
-
"dev": "tsx src/index.ts",
|
|
41
|
-
"mcp:stdio": "node dist/index.js",
|
|
42
|
-
"prepack": "npm run build",
|
|
43
|
-
"smoke:x402-payment-fetch": "tsx scripts/x402-payment-fetch-smoke.ts",
|
|
44
|
-
"test": "vitest run",
|
|
45
|
-
"x402:facilitator": "tsx scripts/x402-facilitator-sidecar.ts",
|
|
46
|
-
"x402:resource": "tsx scripts/x402-local-sidecars.ts",
|
|
47
|
-
"x402:signer": "tsx scripts/x402-signer-sidecar.ts"
|
|
48
|
-
},
|
|
49
|
-
"dependencies": {
|
|
50
|
-
"@clack/prompts": "^1.5.1",
|
|
51
|
-
"@modelcontextprotocol/sdk": "^1.13.0",
|
|
52
|
-
"zod": "^3.25.76"
|
|
53
|
-
},
|
|
54
|
-
"devDependencies": {
|
|
55
|
-
"@types/node": "^22.15.30",
|
|
56
|
-
"tsx": "^4.19.4",
|
|
57
|
-
"typescript": "^5.8.3",
|
|
58
|
-
"vitest": "^4.1.8"
|
|
59
|
-
},
|
|
60
|
-
"engines": {
|
|
61
|
-
"node": ">=20.0.0"
|
|
62
|
-
}
|
|
63
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "mrmainspring",
|
|
3
|
+
"version": "0.3.1",
|
|
4
|
+
"description": "Mr Mainspring MCP backend with memory, Grimoire policies, audit, Casper anchoring, and x402 settlement boundaries.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mainspring": "dist/index.js",
|
|
9
|
+
"mrmainspring": "dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"main": "./dist/server.js",
|
|
12
|
+
"types": "./dist/server.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/server.d.ts",
|
|
16
|
+
"import": "./dist/server.js"
|
|
17
|
+
},
|
|
18
|
+
"./mcp": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./package.json": "./package.json"
|
|
23
|
+
},
|
|
24
|
+
"publishConfig": {
|
|
25
|
+
"access": "public"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist/**/*.js",
|
|
29
|
+
"dist/**/*.d.ts",
|
|
30
|
+
"LICENSE",
|
|
31
|
+
"README.md",
|
|
32
|
+
"package.json"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc -p tsconfig.json",
|
|
36
|
+
"demo:stdio": "npm run build && tsx scripts/demo-stdio.ts",
|
|
37
|
+
"demo:x402-http": "tsx scripts/x402-demo-http-server.ts",
|
|
38
|
+
"demo:x402-sidecars": "tsx scripts/x402-local-sidecars.ts",
|
|
39
|
+
"demo:x402-sidecars:smoke": "tsx scripts/x402-local-sidecars.ts --smoke",
|
|
40
|
+
"dev": "tsx src/index.ts",
|
|
41
|
+
"mcp:stdio": "node dist/index.js",
|
|
42
|
+
"prepack": "npm run build",
|
|
43
|
+
"smoke:x402-payment-fetch": "tsx scripts/x402-payment-fetch-smoke.ts",
|
|
44
|
+
"test": "vitest run",
|
|
45
|
+
"x402:facilitator": "tsx scripts/x402-facilitator-sidecar.ts",
|
|
46
|
+
"x402:resource": "tsx scripts/x402-local-sidecars.ts",
|
|
47
|
+
"x402:signer": "tsx scripts/x402-signer-sidecar.ts"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"@clack/prompts": "^1.5.1",
|
|
51
|
+
"@modelcontextprotocol/sdk": "^1.13.0",
|
|
52
|
+
"zod": "^3.25.76"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@types/node": "^22.15.30",
|
|
56
|
+
"tsx": "^4.19.4",
|
|
57
|
+
"typescript": "^5.8.3",
|
|
58
|
+
"vitest": "^4.1.8"
|
|
59
|
+
},
|
|
60
|
+
"engines": {
|
|
61
|
+
"node": ">=20.0.0"
|
|
62
|
+
}
|
|
63
|
+
}
|