midnight-mcp 0.1.39 → 0.1.40

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.
@@ -110,6 +110,19 @@ export declare const TYPE_COMPATIBILITY: {
110
110
  fix: string;
111
111
  note?: undefined;
112
112
  })[];
113
+ typeCasting: ({
114
+ from: string;
115
+ to: string;
116
+ direct: boolean;
117
+ fix: string;
118
+ note?: undefined;
119
+ } | {
120
+ from: string;
121
+ to: string;
122
+ direct: boolean;
123
+ note: string;
124
+ fix?: undefined;
125
+ })[];
113
126
  assignments: {
114
127
  types: string;
115
128
  works: boolean;
@@ -137,8 +150,7 @@ export declare const LEDGER_TYPE_LIMITS: {
137
150
  note: string;
138
151
  }[];
139
152
  typescriptAccess: string;
140
- reason: string;
141
- pattern: string;
153
+ note: string;
142
154
  };
143
155
  Set: {
144
156
  circuitOperations: {
@@ -147,7 +159,7 @@ export declare const LEDGER_TYPE_LIMITS: {
147
159
  note: string;
148
160
  }[];
149
161
  typescriptAccess: string;
150
- reason: string;
162
+ note: string;
151
163
  };
152
164
  MerkleTree: {
153
165
  circuitOperations: {
@@ -190,7 +190,37 @@ export const TYPE_COMPATIBILITY = {
190
190
  {
191
191
  types: "Uint<N> + Uint<N>",
192
192
  works: true,
193
- note: "Must fit in result width",
193
+ note: "Result is bounded type, cast back: (a + b) as Uint<64>",
194
+ },
195
+ {
196
+ types: "Uint<64> + Uint<64>",
197
+ works: true,
198
+ note: "Result is Uint<0..36893488147419103230>, must cast: (a + b) as Uint<64>",
199
+ },
200
+ {
201
+ types: "Uint<64> * Uint<64>",
202
+ works: true,
203
+ note: "Result is wide bounded type, cast back to target type",
204
+ },
205
+ ],
206
+ typeCasting: [
207
+ {
208
+ from: "Uint<64>",
209
+ to: "Bytes<32>",
210
+ direct: false,
211
+ fix: "Go through Field: (amount as Field) as Bytes<32>",
212
+ },
213
+ {
214
+ from: "Uint<N>",
215
+ to: "Field",
216
+ direct: true,
217
+ note: "Safe cast: value as Field",
218
+ },
219
+ {
220
+ from: "arithmetic result",
221
+ to: "Uint<64>",
222
+ direct: true,
223
+ note: "Required cast: (a + b) as Uint<64>",
194
224
  },
195
225
  ],
196
226
  assignments: [
@@ -240,25 +270,17 @@ export const LEDGER_TYPE_LIMITS = {
240
270
  { method: ".remove(key)", works: true, note: "Removes entry" },
241
271
  {
242
272
  method: ".lookup(key)",
243
- works: false,
244
- note: "NOT available in circuits",
273
+ works: true,
274
+ note: "Returns Option<ValueType> - use in circuits",
245
275
  },
246
276
  {
247
277
  method: ".member(key)",
248
- works: false,
249
- note: "NOT available in circuits",
278
+ works: true,
279
+ note: "Returns Boolean - checks if key exists",
250
280
  },
251
281
  ],
252
282
  typescriptAccess: "Query map via `contractState.data.get(key)` in TypeScript SDK",
253
- reason: "ZK circuits prove transitions, not current state. Use witnesses for reads.",
254
- pattern: `// To read a map value in a circuit, use a witness:
255
- witness get_stored_value(key: Bytes<32>): Field;
256
-
257
- export circuit update_if_exists(key: Bytes<32>, new_value: Field): [] {
258
- const current = get_stored_value(key); // Prover fetches from ledger
259
- // ... use current value
260
- data.insert(key, new_value); // Update is allowed
261
- }`,
283
+ note: "Map.lookup() and Map.member() ARE available in circuits (verified with OpenZeppelin contracts)",
262
284
  },
263
285
  Set: {
264
286
  circuitOperations: [
@@ -266,12 +288,12 @@ export circuit update_if_exists(key: Bytes<32>, new_value: Field): [] {
266
288
  { method: ".remove(value)", works: true, note: "Removes from set" },
267
289
  {
268
290
  method: ".member(value)",
269
- works: false,
270
- note: "NOT available in circuits",
291
+ works: true,
292
+ note: "Returns Boolean - checks if value exists in set",
271
293
  },
272
294
  ],
273
295
  typescriptAccess: "Check membership via `contractState.set.has(value)` in TypeScript SDK",
274
- reason: "Same as Map - use witnesses for membership checks",
296
+ note: "Set.member() IS available in circuits",
275
297
  },
276
298
  MerkleTree: {
277
299
  circuitOperations: [
@@ -338,10 +360,34 @@ export ledger myField: Field; // Not Cell<Field>`,
338
360
  },
339
361
  {
340
362
  error: "member access requires struct type",
341
- cause: "Trying to use .member() or .lookup() on Map/Set in circuit",
342
- fix: `Map/Set queries are not available in circuits.
343
- Use a witness to fetch the value from the prover:
344
- witness lookup_value(key: Bytes<32>): Field;`,
363
+ cause: "Trying to access a field on a non-struct type",
364
+ fix: `Make sure you're accessing a struct field, not a primitive.
365
+ Map.lookup() and Map.member() ARE available in circuits.
366
+ Check that the base type is actually a struct.`,
367
+ },
368
+ {
369
+ error: "potential witness-value disclosure must be declared",
370
+ cause: "Circuit parameter flows to ledger operation without disclose()",
371
+ fix: `Disclose parameters at the start of the circuit:
372
+ export circuit my_circuit(param: Bytes<32>): [] {
373
+ const d_param = disclose(param); // Acknowledge on-chain visibility
374
+ ledger.insert(d_param, value); // Now use disclosed value
375
+ }`,
376
+ },
377
+ {
378
+ error: "expected second argument of insert to have type Uint<64> but received Uint<0..N>",
379
+ cause: "Arithmetic result has bounded type, needs cast back to target",
380
+ fix: `Cast arithmetic results back to the target type:
381
+ const new_balance = (current + amount) as Uint<64>;
382
+ ledger_map.insert(key, new_balance);`,
383
+ },
384
+ {
385
+ error: "cannot cast from type Uint<64> to type Bytes<32>",
386
+ cause: "Direct Uint to Bytes cast not allowed",
387
+ fix: `Go through Field first:
388
+ const amount_field = amount as Field;
389
+ const amount_bytes = amount_field as Bytes<32>;
390
+ // Or chained: (amount as Field) as Bytes<32>`,
345
391
  },
346
392
  {
347
393
  error: "cannot prove assertion",
@@ -142,6 +142,15 @@ Based on syntax reference, generate the contract using:
142
142
  - Empty tuple return: \`circuit fn(): []\` (NOT \`Void\`)
143
143
  - Export enums: \`export enum State { ... }\`
144
144
  - Wrap witness conditionals: \`if (disclose(witness == value))\`
145
+ - Disclose circuit params that touch ledger: \`const d = disclose(param); ledger.insert(d, v);\`
146
+ - Cast arithmetic results: \`(a + b) as Uint<64>\`
147
+ - Uint to Bytes needs two casts: \`(amount as Field) as Bytes<32>\`
148
+
149
+ ### IMPORTANT: Compact is NOT TypeScript!
150
+ - Map.lookup() and Set.member() ARE available in circuits
151
+ - No 'function' keyword - use 'circuit' or 'pure circuit'
152
+ - No 'void' - use '[]'
153
+ - Enum access: \`Choice.rock\` NOT \`Choice::rock\`
145
154
 
146
155
  ### Step 3: Validate Before Returning
147
156
  Call \`midnight-extract-contract-structure\` with your generated code to check for:
@@ -386,6 +395,13 @@ If syntax errors found, call \`midnight-get-latest-syntax\` to get:
386
395
  - The \`commonMistakes\` array with correct patterns
387
396
  - Current \`quickStartTemplate\` for reference
388
397
 
398
+ ### Step 3: Check for Common Compiler Errors
399
+ Match error message against known fixes:
400
+ - "cannot cast from type Uint<64> to type Bytes<32>" → Use \`(amount as Field) as Bytes<32>\`
401
+ - "expected type Uint<64> but received Uint<0..N>" → Cast arithmetic: \`(a + b) as Uint<64>\`
402
+ - "potential witness-value disclosure must be declared" → Disclose params: \`const d = disclose(param);\`
403
+ - Map.lookup() and Set.member() ARE available in circuits (ignore old advice saying they aren't)
404
+
389
405
  ---
390
406
 
391
407
  Please help me debug by:
@@ -195,6 +195,19 @@ export declare function getLatestSyntax(input: GetLatestSyntaxInput): Promise<{
195
195
  fix: string;
196
196
  note?: undefined;
197
197
  })[];
198
+ typeCasting: ({
199
+ from: string;
200
+ to: string;
201
+ direct: boolean;
202
+ fix: string;
203
+ note?: undefined;
204
+ } | {
205
+ from: string;
206
+ to: string;
207
+ direct: boolean;
208
+ note: string;
209
+ fix?: undefined;
210
+ })[];
198
211
  assignments: {
199
212
  types: string;
200
213
  works: boolean;
@@ -219,8 +232,7 @@ export declare function getLatestSyntax(input: GetLatestSyntaxInput): Promise<{
219
232
  note: string;
220
233
  }[];
221
234
  typescriptAccess: string;
222
- reason: string;
223
- pattern: string;
235
+ note: string;
224
236
  };
225
237
  Set: {
226
238
  circuitOperations: {
@@ -229,7 +241,7 @@ export declare function getLatestSyntax(input: GetLatestSyntaxInput): Promise<{
229
241
  note: string;
230
242
  }[];
231
243
  typescriptAccess: string;
232
- reason: string;
244
+ note: string;
233
245
  };
234
246
  MerkleTree: {
235
247
  circuitOperations: {
@@ -406,11 +406,6 @@ export circuit increment(): [] {
406
406
  correct: "// Read via witness or TypeScript SDK",
407
407
  error: 'operation "value" undefined for Counter',
408
408
  },
409
- {
410
- wrong: "data.lookup(key)",
411
- correct: "// Use witness: witness get_value(key): Type;",
412
- error: "member access requires struct type",
413
- },
414
409
  {
415
410
  wrong: "Choice::rock (Rust-style)",
416
411
  correct: "Choice.rock (dot notation)",
@@ -426,6 +421,21 @@ export circuit increment(): [] {
426
421
  correct: "pure circuit helper(): T",
427
422
  error: 'unbound identifier "function"',
428
423
  },
424
+ {
425
+ wrong: "amount as Bytes<32> // direct Uint to Bytes",
426
+ correct: "(amount as Field) as Bytes<32> // go through Field",
427
+ error: "cannot cast from type Uint<64> to type Bytes<32>",
428
+ },
429
+ {
430
+ wrong: "ledger.insert(key, a + b) // arithmetic result",
431
+ correct: "ledger.insert(key, (a + b) as Uint<64>) // cast result",
432
+ error: "expected type Uint<64> but received Uint<0..N>",
433
+ },
434
+ {
435
+ wrong: "export circuit fn(param: T): [] { ledger.insert(param, v); }",
436
+ correct: "export circuit fn(param: T): [] { const d = disclose(param); ledger.insert(d, v); }",
437
+ error: "potential witness-value disclosure must be declared",
438
+ },
429
439
  ],
430
440
  syntaxReference: compactReference,
431
441
  sections: [
@@ -453,13 +463,19 @@ export circuit increment(): [] {
453
463
  repo: rc.repo,
454
464
  description: rc.description,
455
465
  })),
456
- note: `CRITICAL: Use quickStartTemplate as your base. Check commonMistakes and commonErrors before submitting code.
457
- KEY GOTCHAS:
466
+ note: `⚠️ CALL THIS TOOL BEFORE generating ANY Compact code!
467
+ Use quickStartTemplate as your base. Check commonMistakes BEFORE submitting code.
468
+
469
+ KEY RULES:
458
470
  1. public_key() is NOT a builtin - use persistentHash pattern
459
471
  2. Counter.value() NOT available in circuits - use witnesses
460
- 3. Map.lookup()/Set.member() NOT available in circuits - use witnesses
461
- 4. Field vs Uint comparison requires casting
462
- This reference is for Compact ${COMPACT_VERSION.min}-${COMPACT_VERSION.max} (last updated: ${COMPACT_VERSION.lastUpdated}).`,
472
+ 3. Map.lookup()/Set.member() ARE available in circuits (verified)
473
+ 4. Arithmetic results need casting: (a + b) as Uint<64>
474
+ 5. Uint→Bytes needs two casts: (amount as Field) as Bytes<32>
475
+ 6. Circuit params touching ledger need disclose(): const d = disclose(param);
476
+
477
+ Compact is NOT TypeScript - don't guess syntax, use this reference!
478
+ Version: ${COMPACT_VERSION.min}-${COMPACT_VERSION.max} (updated: ${COMPACT_VERSION.lastUpdated}).`,
463
479
  };
464
480
  }
465
481
  }
@@ -223,7 +223,15 @@ export const repositoryTools = [
223
223
  },
224
224
  {
225
225
  name: "midnight-get-latest-syntax",
226
- description: "Get the authoritative syntax reference for Compact language at the latest version. Use this as the source of truth when writing or reviewing contracts to ensure they compile.",
226
+ description: `🚨 CALL THIS BEFORE GENERATING ANY COMPACT CODE!
227
+ Get the authoritative Compact syntax reference. Prevents hallucination by providing:
228
+ - Correct syntax patterns (Compact is NOT TypeScript!)
229
+ - commonMistakes array with wrong→correct mappings
230
+ - Type casting rules (Uint→Bytes needs two casts)
231
+ - disclose() requirements for circuit params
232
+ - Map.lookup()/Set.member() ARE available in circuits
233
+
234
+ ALWAYS check this reference before writing Compact contracts.`,
227
235
  inputSchema: {
228
236
  type: "object",
229
237
  properties: {
@@ -237,7 +245,7 @@ export const repositoryTools = [
237
245
  annotations: {
238
246
  readOnlyHint: true,
239
247
  openWorldHint: true,
240
- title: "Get Latest Syntax Reference",
248
+ title: "🚨 Get Syntax Reference (Call First!)",
241
249
  category: "versioning",
242
250
  },
243
251
  handler: getLatestSyntax,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "midnight-mcp",
3
- "version": "0.1.39",
3
+ "version": "0.1.40",
4
4
  "description": "Model Context Protocol Server for Midnight Blockchain Development",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",