Skip to content

fix(legal-intakes): remove invalid bracket-operator schema property keys (Claude Cowork 400 fix)#80

Merged
adith-dinesh merged 2 commits into
mainfrom
fix/legal-intakes-invalid-schema-property-keys-prod
May 15, 2026
Merged

fix(legal-intakes): remove invalid bracket-operator schema property keys (Claude Cowork 400 fix)#80
adith-dinesh merged 2 commits into
mainfrom
fix/legal-intakes-invalid-schema-property-keys-prod

Conversation

@sd-gh-bot
Copy link
Copy Markdown
Contributor

@sd-gh-bot sd-gh-bot commented May 15, 2026

User description

Problem

Connecting the SpotDraft MCP (EU, OAuth) to Claude Cowork fails immediately with:

400 tools.22.custom.input_schema.properties: Property keys should match pattern '^[a-zA-Z0-9_.-]{1,64}$'

The get_legal_intakes tool's inputSchema.properties contains 6 keys with bracket and dollar-sign characters that Anthropic's validator rejects:

  • filter__priority[$eq], filter__priority[$in], filter__priority[$ne]
  • filter__status[$eq], filter__status[$in], filter__status[$ne]

Claude validates the entire tool list before accepting any request, so one bad property key blocks every conversation for any user with the MCP connector enabled.

Fix

Old key (invalid) Action
filter__priority[$eq] Removed — covered by plain filter__priority
filter__priority[$in] Renamed → filter__priority_in
filter__priority[$ne] Renamed → filter__priority_ne
filter__status[$eq] Removed — covered by plain filter__status
filter__status[$in] Renamed → filter__status_in
filter__status[$ne] Renamed → filter__status_ne

The handler is updated to map the new safe parameter names back to the SpotDraft API's expected filter__*[$in] / filter__*[$ne] query-param format internally — no API behaviour change.

Validation

  • tsc --noEmit ✅ clean
  • Full tool scan: no other schema property keys contain illegal characters

Related


Generated description

Below is a concise technical summary of the changes proposed in this PR:
Enforce getLegalIntakes schema properties to match Claude’s allowed key pattern and explain the invariant across the legal-intake AGENTS guidance so every MCP connector can pass validation. Map the safe filter__* inputs back to the SpotDraft query-param operators inside getLegalIntakes while keeping legacy behavior and cover both schema invariants and handler mappings with focused tests.

TopicDetails
Legal intake schema Ensure getLegalIntakes schema properties follow Claude’s allowed key pattern and update the AGENTS guidance plus schema tests to ban bracketed $ names so every tool validates with strict MCP clients.
Modified files (4)
  • AGENTS.md
  • src/tools/AGENTS.md
  • src/tools/legal-intake/AGENTS.md
  • test/get-legal-intakes.test.mjs
Latest Contributors(2)
UserCommitDate
neo@spotdraft.comtest(legal-intakes): u...May 15, 2026
pranavpandey2511@gmail...Fix/contract list comm...May 14, 2026
Handler mapping tests Map the safe schema names back to the upstream filter__*[$in]/[$ne] query params inside getLegalIntakes and add handler tests that verify the mapping, legacy string support, and exact-match rejecting arrays where inappropriate.
Modified files (2)
  • src/tools/legal-intake/get_legal_intakes.ts
  • test/get-legal-intakes.test.mjs
Latest Contributors(2)
UserCommitDate
neo@spotdraft.comtest(legal-intakes): u...May 15, 2026
pranavpandey2511@gmail...Fix/contract list comm...May 14, 2026
Review this PR on Baz | Customize your next review

The get_legal_intakes inputSchema had 6 property keys containing '[', ']',
and '$' characters which violate Anthropic/Vertex AI Claude's required pattern
^[a-zA-Z0-9_.-]{1,64}$:

  filter__priority[$eq], filter__priority[$in], filter__priority[$ne]
  filter__status[$eq],   filter__status[$in],   filter__status[$ne]

This caused a 400 BadRequestError from Claude Cowork / Claude Sonnet on
Vertex AI (EU), aborting the entire tool-calling session before any tool
was invoked.

Fix:
- Remove $eq variants (covered by the plain filter__priority / filter__status keys)
- Rename $in  -> _in  (filter__priority_in, filter__status_in)
- Rename $ne  -> _ne  (filter__priority_ne, filter__status_ne)
- Update handler to map the new safe names back to the API's expected
  query-param format (filter__priority[$in], filter__status[$ne] etc.)

All property keys now match ^[a-zA-Z0-9_.-]{1,64}$.
tsc --noEmit: clean

Co-authored-by: Adith Dinesh <adith@spotdraft.com>
@sachin-spotdraft sachin-spotdraft added the size/s < 100 lines of changes label May 15, 2026
…md against invalid chars

- Rewrite test/get-legal-intakes.test.mjs to match the renamed schema
  properties from PR #80 (filter__priority_in/ne, filter__status_in/ne)
- Add a schema key validation test asserting every property key matches
  ^[a-zA-Z0-9_.-]{1,64}$, the pattern Anthropic Claude enforces before
  accepting any MCP connection
- Add tests verifying handler mapping: filter__status_in -> filter__status[$in],
  filter__priority_in -> filter__priority[$in], and the *_ne variants ->
  [$ne] in the upstream query params
- Remove tests referencing the deleted bracket keys (filter__status[$eq],
  filter__priority[$eq], etc.)
- Update AGENTS.md at root, src/tools/, and src/tools/legal-intake/ with the
  invariant: all inputSchema.properties keys must match the valid pattern;
  never use [ ] $ in schema key names - map them inside the handler instead

All 63 tests pass (npm test).

Co-authored-by: Jaskaran Bhatia <jaskaran@spotdraft.com>
@sd-gh-bot
Copy link
Copy Markdown
Contributor Author

Follow-up commit: tests + AGENTS.md guardrails (1f34810)

What was added on top of the schema-sanitization fix:

Tests (test/get-legal-intakes.test.mjs) — all 63 pass ✅

New test What it checks
Schema key pattern guard Every inputSchema.properties key matches ^[a-zA-Z0-9_.-]{1,64}$ (the Anthropic validator pattern)
No legacy bracket keys filter__status[$in], filter__status[$eq], etc. are gone from the schema
filter__status_infilter__status[$in] Handler maps safe name to API query-param correctly
filter__priority_infilter__priority[$in] Same for priority
filter__status_nefilter__status[$ne] ne variant maps correctly
filter__priority_nefilter__priority[$ne] Same for priority
Legacy string passthrough String values for _in fields still work
Array rejection on non-$in field Passing an array to filter__status_ne throws ValidationError

AGENTS.md updates (3 files)

  • AGENTS.md (root): repo-wide guardrail — all tool schema keys must match ^[a-zA-Z0-9_.-]{1,64}$
  • src/tools/AGENTS.md: same rule at the tool-registry level
  • src/tools/legal-intake/AGENTS.md: detailed naming invariant + the safe-name→API-param mapping pattern

@sachin-spotdraft sachin-spotdraft added size/m < 500 lines of changes and removed size/s < 100 lines of changes labels May 15, 2026
@adith-dinesh adith-dinesh marked this pull request as ready for review May 15, 2026 05:09
@baz-reviewer
Copy link
Copy Markdown

baz-reviewer Bot commented May 15, 2026

⚠️ Advanced Security cannot run on this PR.

Your organization's Advanced Security usage limit has been reached. To continue using Advanced Security reviews, please upgrade your plan or increase your usage limits in your account settings.

@adith-dinesh adith-dinesh merged commit 7901b17 into main May 15, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m < 500 lines of changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants