@polygraphso/litmus 0.8.0 → 0.8.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 CHANGED
@@ -61,9 +61,9 @@ MCP-capable client. It exposes two tools:
61
61
  It also registers two **prompts** that show up as slash commands — in Claude Code,
62
62
  `/mcp__polygraph-litmus__grade <server_ref>` (run a fresh grade) and
63
63
  `/mcp__polygraph-litmus__check <server_ref>` (read a published grade); other
64
- clients surface the same prompts in their own UI. (Want a bare `/polygraph` in
65
- Claude Code? Drop a `.claude/commands/polygraph.md` that calls `run_litmus`a
66
- Claude-Code-only convenience, not shipped here.)
64
+ clients surface the same prompts in their own UI. For a cleaner pair of commands
65
+ in Claude Code `/polygraph:grade` and `/polygraph:check` — install the plugin
66
+ (below), which wires up this server and both commands in one step.
67
67
 
68
68
  **Prerequisites:** Node ≥ 18. Docker is optional (without it, C-02 egress is
69
69
  skipped and the grade caps at B). Set `POLYGRAPH_API_URL=https://polygraph.so` so
@@ -73,7 +73,20 @@ skipped and the grade caps at B). Set `POLYGRAPH_API_URL=https://polygraph.so` s
73
73
  > commonly returns `not_available` today — that means *unevaluated*, not a failing
74
74
  > grade. To grade a server right now, use `run_litmus`.
75
75
 
76
- Add the server once, then just talk to your agent.
76
+ ### Claude Code: one-click plugin (recommended)
77
+
78
+ The plugin bundles this MCP server **and** adds the `/polygraph:grade` and
79
+ `/polygraph:check` commands — one install does everything:
80
+
81
+ ```
82
+ /plugin marketplace add polygraphso/litmus
83
+ /plugin install polygraph@polygraphso
84
+ ```
85
+
86
+ Then just run `/polygraph:grade npm/@modelcontextprotocol/server-filesystem`.
87
+
88
+ Prefer to wire the server up by hand, or using another client? Add it once, then
89
+ just talk to your agent.
77
90
 
78
91
  **Claude Code** — one command:
79
92
 
@@ -38,16 +38,43 @@ function rpcUrl(net = selectedNetwork()) {
38
38
  return override && override.length > 0 ? override : NETWORKS[net].rpc;
39
39
  }
40
40
 
41
- // ../onchain/src/eas-sdk.ts
42
- import { createRequire } from "module";
43
- var require2 = createRequire(import.meta.url);
44
- var sdk = require2(
45
- "@ethereum-attestation-service/eas-sdk"
46
- );
47
- var { EAS, SchemaEncoder, SchemaRegistry } = sdk;
48
-
49
41
  // ../onchain/src/eas.ts
42
+ import { AbiCoder } from "ethers";
50
43
  var LITMUS_SCHEMA = "string serverRef,bytes32 toolDefsFingerprint,uint8 gradeC01,uint8 gradeC02,uint8 gradeC03,string overallGrade,string reportCID,string methodologyVersion,uint64 ranAt,string resolvedVersion";
44
+ var LITMUS_ABI_TYPES = [
45
+ "string",
46
+ // serverRef
47
+ "bytes32",
48
+ // toolDefsFingerprint
49
+ "uint8",
50
+ // gradeC01
51
+ "uint8",
52
+ // gradeC02
53
+ "uint8",
54
+ // gradeC03
55
+ "string",
56
+ // overallGrade
57
+ "string",
58
+ // reportCID
59
+ "string",
60
+ // methodologyVersion
61
+ "uint64",
62
+ // ranAt
63
+ "string"
64
+ // resolvedVersion
65
+ ];
66
+ var LITMUS_ABI_NAMES = [
67
+ "serverRef",
68
+ "toolDefsFingerprint",
69
+ "gradeC01",
70
+ "gradeC02",
71
+ "gradeC03",
72
+ "overallGrade",
73
+ "reportCID",
74
+ "methodologyVersion",
75
+ "ranAt",
76
+ "resolvedVersion"
77
+ ];
51
78
  function categoryUint8(bundle, code) {
52
79
  const status = bundle.categories.find((c) => c.code === code)?.status;
53
80
  return status ? CATEGORY_STATUS_UINT8[status] : CATEGORY_STATUS_UINT8.skipped;
@@ -68,31 +95,36 @@ function litmusFields(bundle, reportCID) {
68
95
  }
69
96
  function encodeLitmusAttestation(bundle, reportCID) {
70
97
  const f = litmusFields(bundle, reportCID);
71
- const enc = new SchemaEncoder(LITMUS_SCHEMA);
72
- return enc.encodeData([
73
- { name: "serverRef", value: f.serverRef, type: "string" },
74
- { name: "toolDefsFingerprint", value: f.toolDefsFingerprint, type: "bytes32" },
75
- { name: "gradeC01", value: f.gradeC01, type: "uint8" },
76
- { name: "gradeC02", value: f.gradeC02, type: "uint8" },
77
- { name: "gradeC03", value: f.gradeC03, type: "uint8" },
78
- { name: "overallGrade", value: f.overallGrade, type: "string" },
79
- { name: "reportCID", value: f.reportCID, type: "string" },
80
- { name: "methodologyVersion", value: f.methodologyVersion, type: "string" },
81
- { name: "ranAt", value: f.ranAt, type: "uint64" },
82
- { name: "resolvedVersion", value: f.resolvedVersion, type: "string" }
83
- ]);
98
+ return AbiCoder.defaultAbiCoder().encode(
99
+ [...LITMUS_ABI_TYPES],
100
+ [
101
+ f.serverRef,
102
+ f.toolDefsFingerprint,
103
+ f.gradeC01,
104
+ f.gradeC02,
105
+ f.gradeC03,
106
+ f.overallGrade,
107
+ f.reportCID,
108
+ f.methodologyVersion,
109
+ f.ranAt,
110
+ f.resolvedVersion
111
+ ]
112
+ );
84
113
  }
85
114
  function decodeLitmusAttestation(encoded) {
86
- const enc = new SchemaEncoder(LITMUS_SCHEMA);
115
+ const values = AbiCoder.defaultAbiCoder().decode([...LITMUS_ABI_TYPES], encoded);
87
116
  const out = {};
88
- for (const item of enc.decodeData(encoded)) {
89
- out[item.name] = item.value.value;
90
- }
117
+ LITMUS_ABI_NAMES.forEach((name, i) => {
118
+ out[name] = values[i];
119
+ });
91
120
  return out;
92
121
  }
93
122
 
94
123
  // ../onchain/src/read.ts
95
- import { JsonRpcProvider, ZeroHash } from "ethers";
124
+ import { Contract, JsonRpcProvider, ZeroHash } from "ethers";
125
+ var EAS_ABI = [
126
+ "function getAttestation(bytes32 uid) view returns ((bytes32 uid, bytes32 schema, uint64 time, uint64 expirationTime, uint64 revocationTime, bytes32 refUID, address recipient, address attester, bool revocable, bytes data))"
127
+ ];
96
128
  function litmusSchemaUID() {
97
129
  const uid = process.env.NEXT_PUBLIC_EAS_SCHEMA_UID;
98
130
  if (!uid) throw new Error("NEXT_PUBLIC_EAS_SCHEMA_UID is required \u2014 register the schema first.");
@@ -101,8 +133,7 @@ function litmusSchemaUID() {
101
133
  async function readAttestation(uid) {
102
134
  const cfg = networkConfig();
103
135
  const provider = new JsonRpcProvider(rpcUrl(), cfg.chainId);
104
- const eas = new EAS(cfg.eas);
105
- eas.connect(provider);
136
+ const eas = new Contract(cfg.eas, EAS_ABI, provider);
106
137
  const att = await eas.getAttestation(uid);
107
138
  if (!att || att.uid === ZeroHash) return null;
108
139
  if (String(att.schema).toLowerCase() !== litmusSchemaUID().toLowerCase()) return null;
package/dist/index.d.ts CHANGED
@@ -494,7 +494,10 @@ declare function decodeLitmusAttestation(encoded: string): Record<string, unknow
494
494
  * §7). Needs an RPC + a registered schema; the agent-gate calls this, then
495
495
  * re-checks the live fingerprint before paying.
496
496
  *
497
- * [verify] eas-sdk EAS.getAttestation return shape (uid / data / revocationTime).
497
+ * The read is a single EAS `getAttestation` view call. We hit the contract
498
+ * directly through a minimal ethers ABI fragment (below) rather than the
499
+ * eas-sdk `EAS` class — same on-chain struct, one fewer dependency (eas-sdk
500
+ * dragged hardhat into the production tree).
498
501
  */
499
502
  /** The registered litmus schema UID for the selected network (from env). */
500
503
  declare function litmusSchemaUID(): string;
package/dist/index.js CHANGED
@@ -14,7 +14,7 @@ import {
14
14
  rpcUrl,
15
15
  runLitmusInputShape,
16
16
  selectedNetwork
17
- } from "./chunk-LBXHFQN3.js";
17
+ } from "./chunk-BPS4YCDL.js";
18
18
  import {
19
19
  parseAuthFlags,
20
20
  resolveTarget
package/dist/mcp.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  readAttestation,
8
8
  runLitmusInputShape,
9
9
  selectedNetwork
10
- } from "./chunk-LBXHFQN3.js";
10
+ } from "./chunk-BPS4YCDL.js";
11
11
  import "./chunk-VOPISHBU.js";
12
12
  import "./chunk-35UOPCBW.js";
13
13
  import {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polygraphso/litmus",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "Behavioral litmus harness for MCP servers — grade a server A–F (tool-output injection, egress, sensitive-data, adversarial-input) with reproducible, content-addressed evidence. Ships a CLI and an MCP server with a run_litmus tool for AI agents.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://polygraph.so",
@@ -52,7 +52,6 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@modelcontextprotocol/sdk": "^1.29.0",
55
- "@ethereum-attestation-service/eas-sdk": "^2.9.1",
56
55
  "ethers": "^6.16.0",
57
56
  "zod": "^3.23.8",
58
57
  "tsx": "^4.19.0"
@@ -63,11 +62,11 @@
63
62
  "typescript": "^5.9.3",
64
63
  "vitest": "^2.1.0",
65
64
  "@polygraph/core": "0.0.0",
66
- "@polygraph/probes": "0.0.0",
67
65
  "@polygraph/onchain": "0.0.0",
66
+ "@polygraph/agent": "0.0.0",
67
+ "@polygraph/probes": "0.0.0",
68
68
  "@polygraph/mcp": "0.0.0",
69
- "@polygraph/cli": "0.0.0",
70
- "@polygraph/agent": "0.0.0"
69
+ "@polygraph/cli": "0.0.0"
71
70
  },
72
71
  "publishConfig": {
73
72
  "access": "public"