brilliant-directories-mcp 6.45.2 → 6.45.3

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.
Files changed (2) hide show
  1. package/index.js +23 -17
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -3695,13 +3695,11 @@ function makeRequest(config, method, urlPath, queryParams, bodyParams, clearFiel
3695
3695
  const params = new URLSearchParams(
3696
3696
  Object.entries(bodyParams || {}).filter(([, v]) => v !== undefined && v !== null && v !== "")
3697
3697
  );
3698
- // Agent passes `_clear_fields: [...]` (single underscore, array).
3699
- // Wrapper translates to BD's native wire parameter
3700
- // `__clear_fields=col1,col2` (DOUBLE underscore, CSV). BD's update
3701
- // controller checks `isset($arguments[$column]) && ($value !== "" || in_array($column, $clearFields))`.
3702
- // We must emit BOTH (a) `field=` per clear-target so isset() is true,
3703
- // AND (b) `__clear_fields=csv` so BD knows the empty is intentional.
3704
- // Without (a), BD's foreach loop skips the column entirely. CEO-directive shape.
3698
+ // BD update controllers gate clears on:
3699
+ // isset($arguments[$column]) && ($value !== "" || in_array($column, $clearFields))
3700
+ // Both halves required on the wire: `col=` (so isset is true) AND
3701
+ // `__clear_fields=csv` (so BD treats the empty as intentional, not
3702
+ // just an unset value to drop).
3705
3703
  if (hasClear) {
3706
3704
  for (const name of clearFields) params.append(name, "");
3707
3705
  params.append("__clear_fields", clearFields.join(","));
@@ -4555,13 +4553,10 @@ async function main() {
4555
4553
  }
4556
4554
  }
4557
4555
 
4558
- // Peel off the wrapper-only `_clear_fields` array before any distribution
4559
- // loop runs — it's not a BD-API param, it's a directive to makeRequest.
4560
- // ALWAYS strip the key first (even if malformed), THEN parse. Without
4561
- // unconditional strip, a non-array `_clear_fields` would leak into the
4562
- // body dispatch, be sent as a regular form param, and BD would route the
4563
- // unknown column name to users_meta as a spurious EAV row — the exact
4564
- // pollution we shipped v6.45.1 to fix. See **Rule: Clearing fields**.
4556
+ // Peel off `_clear_fields` (agent-facing, single underscore) before any
4557
+ // distribution loop runs. ALWAYS strip first, THEN parse — malformed
4558
+ // shapes must not leak to BD as a regular form param (would create a
4559
+ // spurious users_meta row). See **Rule: Clearing fields**.
4565
4560
  let clearFields;
4566
4561
  let rawClear;
4567
4562
  if (args && Object.prototype.hasOwnProperty.call(args, "_clear_fields")) {
@@ -4589,9 +4584,8 @@ async function main() {
4589
4584
  .filter((n) => n.length > 0);
4590
4585
  }
4591
4586
  }
4592
- // Two guards on _clear_fields. (BD v6.45.0+ natively handles clears on
4593
- // base AND EAV-routed fields via __clear_fields=csv on the wire; EAV
4594
- // refusal removed.)
4587
+ // Three guards on _clear_fields. (BD v6.45.0+ natively handles clears on
4588
+ // base AND EAV-routed fields via __clear_fields=csv on the wire.)
4595
4589
  if (clearFields && clearFields.length > 0) {
4596
4590
  // (B) Wrapper-managed fields (auto-injected timestamps + unconditional
4597
4591
  // overwrites). Clearing them violates wrapper invariants.
@@ -4606,6 +4600,18 @@ async function main() {
4606
4600
  if (overlap.length > 0) {
4607
4601
  return { content: [{ type: "text", text: `_clear_fields conflict: field(s) [${overlap.join(", ")}] also passed as value(s). Use one or the other.` }], isError: true };
4608
4602
  }
4603
+ // (D) Unknown column names — refuse. With the v6.45.2 wire fix
4604
+ // (col=&__clear_fields=col), an unknown name passes BD's isset() check
4605
+ // and gets routed to users_meta as a spurious EAV row. Validate against
4606
+ // the tool's bodyProps OR EAV_ROUTES.eavFields (legitimate EAV-routed
4607
+ // columns not in base bodyProps). Any unknown → refuse the whole call
4608
+ // so the agent fixes the typo and retries — never partial success.
4609
+ const eavSet = EAV_ROUTES[name]?.eavFields;
4610
+ const isKnown = (n) => (bodyProps && n in bodyProps) || (eavSet ? eavSet.has(n) : false);
4611
+ const unknownNames = clearFields.filter((n) => !isKnown(n));
4612
+ if (unknownNames.length > 0) {
4613
+ return { content: [{ type: "text", text: `_clear_fields contains unknown column name(s) for ${name}: [${unknownNames.join(", ")}]. Check spelling against the tool schema or EAV-routed field list.` }], isError: true };
4614
+ }
4609
4615
  }
4610
4616
 
4611
4617
  // Build URL path with path params substituted
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "brilliant-directories-mcp",
3
3
  "mcpName": "io.github.brilliantdirectories/brilliant-directories-mcp",
4
- "version": "6.45.2",
4
+ "version": "6.45.3",
5
5
  "description": "Official MCP server for Brilliant Directories — manage members, posts, leads, reviews, and more.",
6
6
  "main": "index.js",
7
7
  "bin": {