mrmainspring 0.1.6 → 0.1.8

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.
@@ -17,14 +17,21 @@ const CLIENTS = [
17
17
  { name: "Cursor", path: "%USERPROFILE%/.cursor/mcp.json", platforms: ["win32"], format: "standard" },
18
18
  // Windsurf
19
19
  { name: "Windsurf", path: "~/.codeium/windsurf/mcp_config.json", platforms: ["darwin", "linux", "win32"], format: "standard" },
20
+ // Windsurf (also on Windows via AppData)
21
+ { name: "Windsurf", path: "%APPDATA%/Windsurf/User/globalStorage/codeium.windsurf/mcp_config.json", platforms: ["win32"], format: "standard" },
20
22
  // Zed
21
23
  { name: "Zed", path: "~/.config/zed/settings.json", platforms: ["darwin", "linux"], format: "zed" },
24
+ // Continue.dev
25
+ { name: "Continue", path: "~/.continue/config.json", platforms: ["darwin", "linux", "win32"], format: "continue" },
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" },
22
28
  ];
23
29
  function expandPath(p, env) {
30
+ const home = env.HOME ?? env.USERPROFILE ?? homedir();
24
31
  return p
25
- .replace(/^~/, homedir())
32
+ .replace(/^~/, home)
26
33
  .replace(/%APPDATA%/gi, env.APPDATA ?? "")
27
- .replace(/%USERPROFILE%/gi, env.USERPROFILE ?? homedir());
34
+ .replace(/%USERPROFILE%/gi, env.USERPROFILE ?? home);
28
35
  }
29
36
  function isInstalled(configPath) {
30
37
  return existsSync(dirname(configPath)) || existsSync(configPath);
@@ -43,6 +50,10 @@ function alreadySet(json, format) {
43
50
  if (format === "zed") {
44
51
  return !!json.context_servers?.mainspring;
45
52
  }
53
+ if (format === "continue") {
54
+ const servers = json.mcpServers;
55
+ return !!servers?.some(s => s.name === "mainspring");
56
+ }
46
57
  return !!json.mcpServers?.mainspring;
47
58
  }
48
59
  function mergeConfig(json, format) {
@@ -55,6 +66,14 @@ function mergeConfig(json, format) {
55
66
  }
56
67
  };
57
68
  }
69
+ if (format === "continue") {
70
+ const existing = (json.mcpServers ?? [])
71
+ .filter((s) => s.name !== "mainspring");
72
+ return {
73
+ ...json,
74
+ mcpServers: [...existing, { name: "mainspring", command: "npx", args: ["-y", "mrmainspring"] }]
75
+ };
76
+ }
58
77
  return {
59
78
  ...json,
60
79
  mcpServers: {
package/dist/config.d.ts CHANGED
@@ -23,6 +23,7 @@ export type X402Config = {
23
23
  signerUrl: string | null;
24
24
  signerAuthToken: string | null;
25
25
  signerTimeoutMs: number;
26
+ buyerAccountHash: string | null;
26
27
  paymentHeaderName: string;
27
28
  casperSettlementPaymentAmountMotes: string;
28
29
  casperConfirmationPollIntervalMs: number;
package/dist/config.js CHANGED
@@ -31,6 +31,7 @@ export function loadConfig(env = process.env) {
31
31
  signerUrl: optionalEnv(env.X402_SIGNER_URL),
32
32
  signerAuthToken: optionalEnv(env.X402_SIGNER_AUTH_TOKEN),
33
33
  signerTimeoutMs: parsePositiveInteger(env.X402_SIGNER_TIMEOUT_MS, "X402_SIGNER_TIMEOUT_MS", 10_000),
34
+ buyerAccountHash: optionalEnv(env.X402_BUYER_ACCOUNT_HASH),
34
35
  paymentHeaderName: optionalEnv(env.X402_PAYMENT_HEADER_NAME) ?? "PAYMENT-SIGNATURE",
35
36
  casperSettlementPaymentAmountMotes: optionalEnv(env.X402_CASPER_SETTLEMENT_PAYMENT_AMOUNT_MOTES) ?? "7000000000",
36
37
  casperConfirmationPollIntervalMs: parsePositiveInteger(env.X402_CASPER_CONFIRMATION_POLL_INTERVAL_MS, "X402_CASPER_CONFIRMATION_POLL_INTERVAL_MS", 2_000),
package/dist/server.js CHANGED
@@ -10,7 +10,7 @@ import { MemoryService } from "./memory/service.js";
10
10
  import { PaymentService } from "./payments/service.js";
11
11
  import { createBackendStores } from "./storage/store-factory.js";
12
12
  import { X402ChallengeClient } from "./x402/client.js";
13
- import { CasperCliX402SettlementProvider, DisabledX402SettlementProvider, FacilitatorX402SettlementProvider, HttpX402SigningProvider, ResourceRetryX402SettlementProvider } from "./x402/settlement.js";
13
+ import { CasperCliX402SettlementProvider, DisabledX402SettlementProvider, FacilitatorX402SettlementProvider, HttpX402SigningProvider, LocalCasperX402SigningProvider, ResourceRetryX402SettlementProvider } from "./x402/settlement.js";
14
14
  export function createSigilServer(config) {
15
15
  const server = new McpServer({
16
16
  name: config.serverName,
@@ -35,6 +35,26 @@ export function createX402SettlementProvider(config) {
35
35
  if (!config.x402.settlementEnabled) {
36
36
  return new DisabledX402SettlementProvider("x402_settlement_disabled");
37
37
  }
38
+ if (config.x402.settlementMode === "casper-cli" && !config.x402.signerUrl) {
39
+ const localSigner = new LocalCasperX402SigningProvider({
40
+ accountKeyPath: config.casper.accountKeyPath ?? "",
41
+ buyerAccountHash: config.x402.buyerAccountHash
42
+ });
43
+ return new CasperCliX402SettlementProvider(localSigner, {
44
+ networkName: config.casper.networkName,
45
+ caip2ChainId: config.casper.caip2ChainId,
46
+ rpcUrl: config.casper.rpcUrl,
47
+ accountKeyPath: config.casper.accountKeyPath,
48
+ submissionEnabled: config.casper.submissionEnabled,
49
+ clientBin: config.casper.clientBin,
50
+ clientWslDistro: config.casper.clientWslDistro,
51
+ gasPriceTolerance: config.casper.gasPriceTolerance,
52
+ pricingMode: config.casper.pricingMode,
53
+ paymentAmountMotes: config.x402.casperSettlementPaymentAmountMotes,
54
+ confirmationPollIntervalMs: config.x402.casperConfirmationPollIntervalMs,
55
+ confirmationTimeoutMs: config.x402.casperConfirmationTimeoutMs
56
+ });
57
+ }
38
58
  if (!config.x402.signerUrl) {
39
59
  return new DisabledX402SettlementProvider("x402_signing_provider_not_configured");
40
60
  }
@@ -122,6 +122,15 @@ export declare class DisabledX402SettlementProvider implements X402SettlementPro
122
122
  export declare class DisabledX402SigningProvider implements X402SignedPaymentProvider {
123
123
  sign(): Promise<X402SigningResult>;
124
124
  }
125
+ export type LocalCasperX402SigningProviderConfig = {
126
+ accountKeyPath: string;
127
+ buyerAccountHash: string | null;
128
+ };
129
+ export declare class LocalCasperX402SigningProvider implements X402SignedPaymentProvider {
130
+ private readonly config;
131
+ constructor(config: LocalCasperX402SigningProviderConfig);
132
+ sign(input: X402SigningInput): Promise<X402SigningResult>;
133
+ }
125
134
  export declare class HttpX402SigningProvider implements X402SignedPaymentProvider {
126
135
  private readonly config;
127
136
  constructor(config: X402HttpSigningProviderConfig);
@@ -4,6 +4,7 @@ import { canonicalizeJson, toJsonObject, toJsonValue } from "../memory/canonical
4
4
  import { sha256Hex } from "../memory/hash.js";
5
5
  import { redactX402Value } from "./redaction.js";
6
6
  import { validateX402PaymentPayload, verifyX402SettlementResponse } from "./readiness.js";
7
+ import { loadCasperSigningKeyFromFile, signX402PaymentPayload } from "./signer.js";
7
8
  export class DisabledX402SettlementProvider {
8
9
  blocker;
9
10
  constructor(blocker = "x402_settlement_disabled") {
@@ -34,6 +35,44 @@ export class DisabledX402SigningProvider {
34
35
  };
35
36
  }
36
37
  }
38
+ export class LocalCasperX402SigningProvider {
39
+ config;
40
+ constructor(config) {
41
+ this.config = config;
42
+ }
43
+ async sign(input) {
44
+ let signingKey;
45
+ try {
46
+ signingKey = loadCasperSigningKeyFromFile(this.config.accountKeyPath);
47
+ }
48
+ catch {
49
+ return { signed: false, blocker: "x402_signing_provider_not_configured" };
50
+ }
51
+ // Ed25519 publicKey is `01<32-byte-hex>` — accepted directly as account identifier
52
+ const buyerAccountHash = this.config.buyerAccountHash ??
53
+ (signingKey.algorithm === "ed25519" ? signingKey.publicKey : null);
54
+ if (!buyerAccountHash) {
55
+ return { signed: false, blocker: "x402_signing_provider_not_configured" };
56
+ }
57
+ const result = signX402PaymentPayload({
58
+ payment_id: input.payment_id,
59
+ facilitator_url: input.facilitator_url,
60
+ method: input.method,
61
+ url: input.url,
62
+ selected_requirement: input.selected_requirement,
63
+ selected_requirement_hash: input.selected_requirement_hash,
64
+ policy_hash: input.policy_hash
65
+ }, { signingKey, buyerAccountHash });
66
+ if (!result.signed) {
67
+ return { signed: false, blocker: "x402_signer_response_invalid" };
68
+ }
69
+ return {
70
+ signed: true,
71
+ signed_payload: result.signed_payload,
72
+ signed_payload_hash: createSignedPayloadHash(result.signed_payload)
73
+ };
74
+ }
75
+ }
37
76
  export class HttpX402SigningProvider {
38
77
  config;
39
78
  constructor(config) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mrmainspring",
3
- "version": "0.1.6",
3
+ "version": "0.1.8",
4
4
  "description": "Mr Mainspring MCP backend with memory, Grimoire policies, audit, Casper anchoring, and x402 settlement boundaries.",
5
5
  "license": "MIT",
6
6
  "type": "module",