@crediolabs/policy-builder-mcp 0.4.0 → 0.5.0
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/dist/src/schemas.d.ts +16 -0
- package/dist/src/schemas.js +8 -0
- package/dist/src/server.js +2 -2
- package/dist-cjs/src/schemas.d.ts +16 -0
- package/dist-cjs/src/schemas.js +8 -0
- package/dist-cjs/src/server.js +2 -2
- package/package.json +2 -2
- package/src/schemas.ts +8 -0
- package/src/server.ts +2 -2
package/dist/src/schemas.d.ts
CHANGED
|
@@ -848,6 +848,22 @@ export declare const DeclarePolicyToolShape: {
|
|
|
848
848
|
readonly recipients: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
849
849
|
readonly recipientArgIndex: z.ZodOptional<z.ZodNumber>;
|
|
850
850
|
readonly allowZeroCap: z.ZodOptional<z.ZodBoolean>;
|
|
851
|
+
readonly minOutputRatio: z.ZodOptional<z.ZodObject<{
|
|
852
|
+
num: z.ZodString;
|
|
853
|
+
den: z.ZodString;
|
|
854
|
+
inputArgIndex: z.ZodNumber;
|
|
855
|
+
outputArgIndex: z.ZodNumber;
|
|
856
|
+
}, "strip", z.ZodTypeAny, {
|
|
857
|
+
num: string;
|
|
858
|
+
den: string;
|
|
859
|
+
inputArgIndex: number;
|
|
860
|
+
outputArgIndex: number;
|
|
861
|
+
}, {
|
|
862
|
+
num: string;
|
|
863
|
+
den: string;
|
|
864
|
+
inputArgIndex: number;
|
|
865
|
+
outputArgIndex: number;
|
|
866
|
+
}>>;
|
|
851
867
|
};
|
|
852
868
|
/** Flat ZodRawShape for `install_policy`. `rule` is typed as `z.unknown()`
|
|
853
869
|
* at the tool boundary because the rule schema is a discriminated union
|
package/dist/src/schemas.js
CHANGED
|
@@ -98,6 +98,14 @@ export const DeclarePolicyToolShape = {
|
|
|
98
98
|
recipients: z.array(z.string()).optional(),
|
|
99
99
|
recipientArgIndex: z.number().int().nonnegative().optional(),
|
|
100
100
|
allowZeroCap: z.boolean().optional(),
|
|
101
|
+
minOutputRatio: z
|
|
102
|
+
.object({
|
|
103
|
+
num: z.string(),
|
|
104
|
+
den: z.string(),
|
|
105
|
+
inputArgIndex: z.number().int().nonnegative(),
|
|
106
|
+
outputArgIndex: z.number().int().nonnegative(),
|
|
107
|
+
})
|
|
108
|
+
.optional(),
|
|
101
109
|
};
|
|
102
110
|
/** Flat ZodRawShape for `install_policy`. `rule` is typed as `z.unknown()`
|
|
103
111
|
* at the tool boundary because the rule schema is a discriminated union
|
package/dist/src/server.js
CHANGED
|
@@ -32,8 +32,8 @@ export function registerTools(server) {
|
|
|
32
32
|
server.tool('synthesize_policy', 'Synthesize a ProposedPolicy from a RecordedTransaction (`source: recording`).', SynthesizePolicyToolShape, (args) => runSynthesizePolicy(args).then(toCallToolResult));
|
|
33
33
|
server.tool('simulate_policy', 'Evaluate a predicate against one recorded call and report permit/deny with the deny reason. The evaluator is a second implementation of the on-chain semantics, cross-checked against the Rust interpreter by the conformance harness, so a verdict here is a claim about what the contract would do. Pass the `predicate` returned by `synthesize_policy` under `explain`.', SimulatePolicyToolShape, (args) => toCallToolResult(runSimulatePolicy(args)));
|
|
34
34
|
server.tool('verify_policy', 'Check a predicate against the transaction it was synthesised from, plus a generated deny case per dimension. Reports `ok` only when the permit case is permitted AND every deny case is denied - a denied permit case means the policy is too strict, a permitted deny case means it is too loose.', VerifyPolicyToolShape, (args) => toCallToolResult(runVerifyPolicy(args)));
|
|
35
|
-
server.tool('declare_policy',
|
|
36
|
-
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.
|
|
35
|
+
server.tool('declare_policy', "Build an interpreter predicate from a DECLARED constraint - the method to pin, and optionally the contract, a per-call amount cap, a recipient allowlist, and a minimum-output ratio (a swap slippage floor, bounding the output argument against the call's own input). Use this when there is no transaction to record, or when `record_transaction` refuses a contract it does not recognise. Returns the predicate tree, its canonical encoding and hash, ready for `install_policy`. `warnings` names any argument index that was GUESSED rather than supplied - a bound on the wrong argument constrains nothing while looking correct, so read them. There is no rolling spend window and no approval threshold: neither is expressible in grammar 4, and both belong to the OpenZeppelin account layer.", DeclarePolicyToolShape, (args) => Promise.resolve(runDeclarePolicy(args)).then(toCallToolResult));
|
|
36
|
+
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 response carries an `authorityScan`: every rule already on the account that a signer of this install could name INSTEAD, including an unpoliced one against which the predicate never runs - a predicate only constrains a key when the policed rule is the only rule that key is on. The account is READ over RPC to build it; pass `existingRules` to supply them yourself instead (useful offline). `authorityScan: null` means NOT CHECKED - the read failed, or it could not account for every live rule - and must never be read as "nothing found". 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, (args) => runInstallPolicy(args).then(toCallToolResult));
|
|
37
37
|
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, (args) => runRevokePolicy(args).then(toCallToolResult));
|
|
38
38
|
server.tool('get_interpreter_info', 'Read-only fingerprint lookup for the policy interpreter contract: returns the pinned address, grammar version, and wasm sha256 (from the pinned constants + 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, (args) => runGetInterpreterInfo(args).then(toCallToolResult));
|
|
39
39
|
}
|
|
@@ -848,6 +848,22 @@ export declare const DeclarePolicyToolShape: {
|
|
|
848
848
|
readonly recipients: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
849
849
|
readonly recipientArgIndex: z.ZodOptional<z.ZodNumber>;
|
|
850
850
|
readonly allowZeroCap: z.ZodOptional<z.ZodBoolean>;
|
|
851
|
+
readonly minOutputRatio: z.ZodOptional<z.ZodObject<{
|
|
852
|
+
num: z.ZodString;
|
|
853
|
+
den: z.ZodString;
|
|
854
|
+
inputArgIndex: z.ZodNumber;
|
|
855
|
+
outputArgIndex: z.ZodNumber;
|
|
856
|
+
}, "strip", z.ZodTypeAny, {
|
|
857
|
+
num: string;
|
|
858
|
+
den: string;
|
|
859
|
+
inputArgIndex: number;
|
|
860
|
+
outputArgIndex: number;
|
|
861
|
+
}, {
|
|
862
|
+
num: string;
|
|
863
|
+
den: string;
|
|
864
|
+
inputArgIndex: number;
|
|
865
|
+
outputArgIndex: number;
|
|
866
|
+
}>>;
|
|
851
867
|
};
|
|
852
868
|
/** Flat ZodRawShape for `install_policy`. `rule` is typed as `z.unknown()`
|
|
853
869
|
* at the tool boundary because the rule schema is a discriminated union
|
package/dist-cjs/src/schemas.js
CHANGED
|
@@ -106,6 +106,14 @@ exports.DeclarePolicyToolShape = {
|
|
|
106
106
|
recipients: zod_1.z.array(zod_1.z.string()).optional(),
|
|
107
107
|
recipientArgIndex: zod_1.z.number().int().nonnegative().optional(),
|
|
108
108
|
allowZeroCap: zod_1.z.boolean().optional(),
|
|
109
|
+
minOutputRatio: zod_1.z
|
|
110
|
+
.object({
|
|
111
|
+
num: zod_1.z.string(),
|
|
112
|
+
den: zod_1.z.string(),
|
|
113
|
+
inputArgIndex: zod_1.z.number().int().nonnegative(),
|
|
114
|
+
outputArgIndex: zod_1.z.number().int().nonnegative(),
|
|
115
|
+
})
|
|
116
|
+
.optional(),
|
|
109
117
|
};
|
|
110
118
|
/** Flat ZodRawShape for `install_policy`. `rule` is typed as `z.unknown()`
|
|
111
119
|
* at the tool boundary because the rule schema is a discriminated union
|
package/dist-cjs/src/server.js
CHANGED
|
@@ -36,8 +36,8 @@ function registerTools(server) {
|
|
|
36
36
|
server.tool('synthesize_policy', 'Synthesize a ProposedPolicy from a RecordedTransaction (`source: recording`).', schemas_ts_1.SynthesizePolicyToolShape, (args) => (0, run_1.runSynthesizePolicy)(args).then(toCallToolResult));
|
|
37
37
|
server.tool('simulate_policy', 'Evaluate a predicate against one recorded call and report permit/deny with the deny reason. The evaluator is a second implementation of the on-chain semantics, cross-checked against the Rust interpreter by the conformance harness, so a verdict here is a claim about what the contract would do. Pass the `predicate` returned by `synthesize_policy` under `explain`.', schemas_ts_1.SimulatePolicyToolShape, (args) => toCallToolResult((0, run_1.runSimulatePolicy)(args)));
|
|
38
38
|
server.tool('verify_policy', 'Check a predicate against the transaction it was synthesised from, plus a generated deny case per dimension. Reports `ok` only when the permit case is permitted AND every deny case is denied - a denied permit case means the policy is too strict, a permitted deny case means it is too loose.', schemas_ts_1.VerifyPolicyToolShape, (args) => toCallToolResult((0, run_1.runVerifyPolicy)(args)));
|
|
39
|
-
server.tool('declare_policy',
|
|
40
|
-
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.
|
|
39
|
+
server.tool('declare_policy', "Build an interpreter predicate from a DECLARED constraint - the method to pin, and optionally the contract, a per-call amount cap, a recipient allowlist, and a minimum-output ratio (a swap slippage floor, bounding the output argument against the call's own input). Use this when there is no transaction to record, or when `record_transaction` refuses a contract it does not recognise. Returns the predicate tree, its canonical encoding and hash, ready for `install_policy`. `warnings` names any argument index that was GUESSED rather than supplied - a bound on the wrong argument constrains nothing while looking correct, so read them. There is no rolling spend window and no approval threshold: neither is expressible in grammar 4, and both belong to the OpenZeppelin account layer.", schemas_ts_1.DeclarePolicyToolShape, (args) => Promise.resolve((0, run_1.runDeclarePolicy)(args)).then(toCallToolResult));
|
|
40
|
+
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 response carries an `authorityScan`: every rule already on the account that a signer of this install could name INSTEAD, including an unpoliced one against which the predicate never runs - a predicate only constrains a key when the policed rule is the only rule that key is on. The account is READ over RPC to build it; pass `existingRules` to supply them yourself instead (useful offline). `authorityScan: null` means NOT CHECKED - the read failed, or it could not account for every live rule - and must never be read as "nothing found". 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.', schemas_ts_1.InstallPolicyToolShape, (args) => (0, run_1.runInstallPolicy)(args).then(toCallToolResult));
|
|
41
41
|
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.', schemas_ts_1.RevokePolicyToolShape, (args) => (0, run_1.runRevokePolicy)(args).then(toCallToolResult));
|
|
42
42
|
server.tool('get_interpreter_info', 'Read-only fingerprint lookup for the policy interpreter contract: returns the pinned address, grammar version, and wasm sha256 (from the pinned constants + 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.', schemas_ts_1.GetInterpreterInfoToolShape, (args) => (0, run_1.runGetInterpreterInfo)(args).then(toCallToolResult));
|
|
43
43
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crediolabs/policy-builder-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "MCP server exposing the OZ policy-synth core (record_transaction + synthesize_policy) over stdio and Streamable HTTP transports.",
|
|
6
6
|
"type": "module",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"prepack": "bun run build"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@crediolabs/policy-synth": "0.
|
|
66
|
+
"@crediolabs/policy-synth": "0.5.0",
|
|
67
67
|
"@modelcontextprotocol/sdk": "1.30.0",
|
|
68
68
|
"@stellar/stellar-sdk": "14.4.0",
|
|
69
69
|
"zod": "3.25.76"
|
package/src/schemas.ts
CHANGED
|
@@ -138,6 +138,14 @@ export const DeclarePolicyToolShape = {
|
|
|
138
138
|
recipients: z.array(z.string()).optional(),
|
|
139
139
|
recipientArgIndex: z.number().int().nonnegative().optional(),
|
|
140
140
|
allowZeroCap: z.boolean().optional(),
|
|
141
|
+
minOutputRatio: z
|
|
142
|
+
.object({
|
|
143
|
+
num: z.string(),
|
|
144
|
+
den: z.string(),
|
|
145
|
+
inputArgIndex: z.number().int().nonnegative(),
|
|
146
|
+
outputArgIndex: z.number().int().nonnegative(),
|
|
147
|
+
})
|
|
148
|
+
.optional(),
|
|
141
149
|
} as const
|
|
142
150
|
|
|
143
151
|
/** Flat ZodRawShape for `install_policy`. `rule` is typed as `z.unknown()`
|
package/src/server.ts
CHANGED
|
@@ -87,14 +87,14 @@ export function registerTools(server: McpServer): void {
|
|
|
87
87
|
|
|
88
88
|
server.tool(
|
|
89
89
|
'declare_policy',
|
|
90
|
-
|
|
90
|
+
"Build an interpreter predicate from a DECLARED constraint - the method to pin, and optionally the contract, a per-call amount cap, a recipient allowlist, and a minimum-output ratio (a swap slippage floor, bounding the output argument against the call's own input). Use this when there is no transaction to record, or when `record_transaction` refuses a contract it does not recognise. Returns the predicate tree, its canonical encoding and hash, ready for `install_policy`. `warnings` names any argument index that was GUESSED rather than supplied - a bound on the wrong argument constrains nothing while looking correct, so read them. There is no rolling spend window and no approval threshold: neither is expressible in grammar 4, and both belong to the OpenZeppelin account layer.",
|
|
91
91
|
DeclarePolicyToolShape,
|
|
92
92
|
(args) => Promise.resolve(runDeclarePolicy(args)).then(toCallToolResult)
|
|
93
93
|
)
|
|
94
94
|
|
|
95
95
|
server.tool(
|
|
96
96
|
'install_policy',
|
|
97
|
-
'Build an UNSIGNED Soroban transaction XDR for `account.add_context_rule(...)` that installs a new policy rule on the given smart account.
|
|
97
|
+
'Build an UNSIGNED Soroban transaction XDR for `account.add_context_rule(...)` that installs a new policy rule on the given smart account. The response carries an `authorityScan`: every rule already on the account that a signer of this install could name INSTEAD, including an unpoliced one against which the predicate never runs - a predicate only constrains a key when the policed rule is the only rule that key is on. The account is READ over RPC to build it; pass `existingRules` to supply them yourself instead (useful offline). `authorityScan: null` means NOT CHECKED - the read failed, or it could not account for every live rule - and must never be read as "nothing found". 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.',
|
|
98
98
|
InstallPolicyToolShape,
|
|
99
99
|
(args) => runInstallPolicy(args).then(toCallToolResult)
|
|
100
100
|
)
|