@crediolabs/policy-builder-mcp 0.1.11 → 0.1.13

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.
@@ -20,14 +20,14 @@
20
20
  // `ZodEffects`, which has no `.shape`). They MUST stay in lockstep with
21
21
  // the strict schemas - a drift in field type or optionality breaks the
22
22
  // SDK's emitted JSON Schema.
23
- import { ComposeUserResponsesSchema, InterpreterOptionsSchema, MandateSpecSchema, NetworkSchema, OzAdapterConfigSchema, RecordedTransactionSchema, RecordTransactionInputSchema, SynthesizePolicyInputSchema, ToolErrorSchema, } from '@crediolabs/policy-synth/run';
23
+ import { ComposeUserResponsesSchema, GetInterpreterInfoInputSchema, InstallPolicyInputSchema, InterpreterOptionsSchema, MandateSpecSchema, NetworkSchema, OraclePriceFixtureSchema, OzAdapterConfigSchema, PredicateNodeSchema, RecordedTransactionSchema, RecordTransactionInputSchema, RevokePolicyInputSchema, SimulatePolicyInputSchema, SynthesizePolicyInputSchema, ToolErrorSchema, VerifyPolicyInputSchema, } from '@crediolabs/policy-synth/run';
24
24
  import { z } from 'zod';
25
25
  // Re-export the strict schemas so MCP package consumers (and existing tests)
26
26
  // still get them from this module. The canonical home is
27
27
  // `@crediolabs/policy-synth/run`; the re-exports here are a shim kept for
28
28
  // backward compatibility with downstream callers that imported from the MCP
29
29
  // package directly.
30
- export { ComposeUserResponsesSchema, InterpreterOptionsSchema, MandateSpecSchema, NetworkSchema, OzAdapterConfigSchema, RecordedTransactionSchema, RecordTransactionInputSchema, SynthesizePolicyInputSchema, ToolErrorSchema, };
30
+ export { ComposeUserResponsesSchema, GetInterpreterInfoInputSchema, InstallPolicyInputSchema, InterpreterOptionsSchema, MandateSpecSchema, NetworkSchema, OraclePriceFixtureSchema, OzAdapterConfigSchema, PredicateNodeSchema, RecordedTransactionSchema, RecordTransactionInputSchema, RevokePolicyInputSchema, SimulatePolicyInputSchema, SynthesizePolicyInputSchema, ToolErrorSchema, VerifyPolicyInputSchema, };
31
31
  /** Flat ZodRawShape used for the MCP SDK tool registration. The body
32
32
  * re-validates against `RecordTransactionInputSchema` so the mutual-exclusion
33
33
  * rule still fires (the SDK does not invoke `.refine()` at registration time). */
@@ -49,4 +49,69 @@ export const SynthesizePolicyToolShape = {
49
49
  confidenceOverride: z.object({ threshold: z.number().min(0).max(1) }).optional(),
50
50
  interpreter: InterpreterOptionsSchema.optional(),
51
51
  ozConfig: OzAdapterConfigSchema.optional(),
52
+ // Without this the tool chain has no join. A ProposedPolicy carries
53
+ // `policyDocuments[].encodedPredicate` (canonical ScVal bytes), while
54
+ // `simulate_policy` and `verify_policy` both want the PredicateNode TREE,
55
+ // and the tree is only returned under `explain`. Omitting it here left an
56
+ // MCP client able to synthesize a policy and then unable to prove anything
57
+ // about it - the two checks were reachable only with `predicate: null`,
58
+ // which skips the interpreter predicate entirely.
59
+ explain: z.boolean().optional(),
60
+ };
61
+ /** Flat ZodRawShape for `simulate_policy`. The `predicate` is typed as
62
+ * `z.unknown()` at the tool boundary because the recursive
63
+ * `PredicateNodeSchema` is a `z.lazy()` union (the SDK does not accept
64
+ * unions at the tool-registration boundary); the body re-validates
65
+ * against `SimulatePolicyInputSchema`, which fails closed on a
66
+ * malformed predicate. `predicate` is nullable here (vs required for
67
+ * verify_policy) so the SDK-emitted JSON Schema mirrors the engine's
68
+ * "OZ-only / no interpreter predicate" contract. */
69
+ export const SimulatePolicyToolShape = {
70
+ predicate: z.unknown().nullable().optional(),
71
+ permitTx: RecordedTransactionSchema,
72
+ validUntilLedger: z.number().int().positive().optional(),
73
+ oraclePricesByAsset: z.record(z.string(), OraclePriceFixtureSchema).optional(),
74
+ };
75
+ /** Flat ZodRawShape for `verify_policy`. Same `z.unknown()` boundary
76
+ * trick for `predicate` as `SimulatePolicyToolShape`; `predicate` is
77
+ * required at the strict-schema level (`VerifyPolicyInputSchema`) so
78
+ * the body fails closed on a missing predicate. */
79
+ export const VerifyPolicyToolShape = {
80
+ predicate: z.unknown(),
81
+ permitTx: RecordedTransactionSchema,
82
+ validUntilLedger: z.number().int().positive().optional(),
83
+ oraclePricesByAsset: z.record(z.string(), OraclePriceFixtureSchema).optional(),
84
+ };
85
+ /** Flat ZodRawShape for `install_policy`. `rule` is typed as `z.unknown()`
86
+ * at the tool boundary because the rule schema is a discriminated union
87
+ * the SDK does not accept at registration; the body re-validates
88
+ * against `InstallPolicyInputSchema`. `encodedPredicate` /
89
+ * `predicateHash` live INSIDE `rule.policies[].predicateBlobBase64`
90
+ * (the policy already carries the encoded predicate); the run-layer
91
+ * extracts them from there. */
92
+ export const InstallPolicyToolShape = {
93
+ smartAccount: z.string().min(1).optional(),
94
+ sourceAccount: z.string().min(1).optional(),
95
+ rule: z.unknown().optional(),
96
+ installNonce: z.number().int().positive().optional(),
97
+ interpreterAddress: z.string().optional(),
98
+ rpcUrl: z.string().url().optional(),
99
+ baseFee: z.number().int().positive().optional(),
100
+ };
101
+ /** Flat ZodRawShape for `revoke_policy`. */
102
+ export const RevokePolicyToolShape = {
103
+ smartAccount: z.string().min(1).optional(),
104
+ sourceAccount: z.string().min(1).optional(),
105
+ ruleId: z.number().int().nonnegative().optional(),
106
+ interpreterAddress: z.string().optional(),
107
+ rpcUrl: z.string().url().optional(),
108
+ baseFee: z.number().int().positive().optional(),
109
+ };
110
+ /** Flat ZodRawShape for `get_interpreter_info`. `verifyLive` triggers an
111
+ * optional RPC `grammar_version()` call so the caller can verify the
112
+ * deployed contract matches the pin. */
113
+ export const GetInterpreterInfoToolShape = {
114
+ network: z.enum(['mainnet', 'testnet']).optional(),
115
+ verifyLive: z.boolean().optional(),
116
+ rpcUrl: z.string().url().optional(),
52
117
  };
@@ -10,9 +10,9 @@
10
10
  // Stateless: a fresh McpServer is constructed per transport (stdio/HTTP). No
11
11
  // shared mutable state across calls; nothing here caches, queues, or holds
12
12
  // key material.
13
- import { runRecordTransaction, runSynthesizePolicy } from '@crediolabs/policy-synth/run';
13
+ import { runGetInterpreterInfo, runInstallPolicy, runRecordTransaction, runRevokePolicy, runSimulatePolicy, runSynthesizePolicy, runVerifyPolicy, } from '@crediolabs/policy-synth/run';
14
14
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
15
- import { RecordTransactionToolShape, SynthesizePolicyToolShape } from "./schemas.js";
15
+ import { GetInterpreterInfoToolShape, InstallPolicyToolShape, RecordTransactionToolShape, RevokePolicyToolShape, SimulatePolicyToolShape, SynthesizePolicyToolShape, VerifyPolicyToolShape, } from "./schemas.js";
16
16
  import { mcpResultFromCore } from "./tools/result.js";
17
17
  /** Build a fresh, stateless MCP server. The caller owns the returned object
18
18
  * and connects it to a single transport (stdio or Streamable HTTP). */
@@ -35,4 +35,24 @@ export function registerTools(server) {
35
35
  const res = await runSynthesizePolicy(args);
36
36
  return mcpResultFromCore(res);
37
37
  });
38
+ server.tool('simulate_policy', 'Replay a RecordedTransaction against a proposed PredicateNode (or null for an OZ-only policy) and emit the SimulationResult envelope (permit verdict + deny-case battery). Returns a SIMULATION_ERROR ToolError on runtime evaluation failure.', SimulatePolicyToolShape, async (args) => {
39
+ const res = await runSimulatePolicy(args);
40
+ return mcpResultFromCore(res);
41
+ });
42
+ server.tool('verify_policy', 'Run the static minimality check on a proposed PredicateNode against a RecordedTransaction (no conjunct is load-bearing-free). Returns VERIFICATION_FAILED with the dropped-constraint fingerprints when the predicate is over-broad.', VerifyPolicyToolShape, async (args) => {
43
+ const res = await runVerifyPolicy(args);
44
+ return mcpResultFromCore(res);
45
+ });
46
+ server.tool('install_policy', 'Build an UNSIGNED Soroban transaction XDR for `account.add_context_rule(...)` that installs a new policy rule on the given smart account. The wallet signs the returned XDR - the signature IS the user-confirmation step (this server is stateless and holds no key material, so there is no two-call confirm pair). Only CALL 1 is emitted; the interpreter `install` follow-up needs the rule id the account assigns in call 1 and is documented in `followUp` in the response.', InstallPolicyToolShape, async (args) => {
47
+ const res = await runInstallPolicy(args);
48
+ return mcpResultFromCore(res);
49
+ });
50
+ server.tool('revoke_policy', 'Build an UNSIGNED Soroban transaction XDR for `account.remove_context_rule(ruleId)` that removes a policy rule from the given smart account. The smart account handles uninstalling each attached policy itself. Auth is master-only - the source account MUST be the master signer set; delegated signers cannot uninstall.', RevokePolicyToolShape, async (args) => {
51
+ const res = await runRevokePolicy(args);
52
+ return mcpResultFromCore(res);
53
+ });
54
+ server.tool('get_interpreter_info', 'Read-only fingerprint lookup for the policy interpreter contract: returns the pinned address, grammar version, and wasm sha256 (from DEPLOYMENTS.md + SELF_VERSION). When `verifyLive=true`, performs an additional `grammar_version()` RPC call against the pinned address and reports whether the deployed contract matches the pin - a live mismatch check is more useful than a fabricated audit field.', GetInterpreterInfoToolShape, async (args) => {
55
+ const res = await runGetInterpreterInfo(args);
56
+ return mcpResultFromCore(res);
57
+ });
38
58
  }