Skip to content

fix(get_contract_list): reject non-string metadataFilters values; clarify operator key format#65

Open
sd-gh-bot wants to merge 1 commit into
mainfrom
fix/metadata-filter-object-serialization
Open

fix(get_contract_list): reject non-string metadataFilters values; clarify operator key format#65
sd-gh-bot wants to merge 1 commit into
mainfrom
fix/metadata-filter-object-serialization

Conversation

@sd-gh-bot
Copy link
Copy Markdown
Contributor

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

User description

Problem

LLM called get_contract_list with metadataFilters using operator-in-value format:

{"metadataFilters": {"48802": {"$ne": "NOT_SET"}, "52421": {"$ne": "NOT_SET"}}}

The serialisation code cast the object value to a string via URLSearchParams.append, which produces [object Object]. Django received filter_metadata__48802=[object Object], tried to parse it as a currency value, attempted int('Object]') → ValueError → HTTP 500.

Sentry event: 7e020f86dcfa4dc194efd7e46a9e164a (env: prod-usa, 2026-05-12T15:00:17Z)
LangSmith trace: 019e1cb3-bda0-72d1-8d08-14a64c16591f
User: FullStory workspace, query about Macy's ARR

Root cause

The metadataFilters tool description showed allowed operators but never showed how to include the operator in the key. The LLM inferred the wrong format.

Correct format (matching Django filter_processor spec):
{"48802[$ne]": "NOT_SET", "52421[$gt]": "USD 1000000"}

Changes

  • Validation: throws ValidationError for non-string metadataFilter values with a message directing the LLM to use bracket notation in the key
  • Tool description: explicit key format, examples, and per-data-type value format
  • inputSchema description: concise format reminder
  • Tests: two new tests added (27/27 pass)

Generated description

Below is a concise technical summary of the changes proposed in this PR:
Clarify metadata filters instructions in the get_contract_list tool so operators are embedded via bracket notation, value formats per type are spelled out, and the schema notes that values must be plain strings. Add validation inside getContractList to reject non-string metadata filters and expand tests to cover both rejection and proper serialization.

TopicDetails
Metadata Validation Enforce string-only metadata filters in getContractList, throw a ValidationError when values are not strings, and cover rejection plus correct serialization through tests.
Modified files (2)
  • src/tools/contracts/get_contract_list.ts
  • test/get-contract-list.test.mjs
Latest Contributors(2)
UserCommitDate
neo@spotdraft.comfix(get_contract_list)...May 12, 2026
bot-github@spotdraft.comdocs(mcp): clarify ent...May 12, 2026
Metadata Guidance Clarify metadata filters guidance, embedding operators via bracket notation, detailing value formats per data type, and telling callers to submit plain strings so the documentation and schema teach the correct usage.
Modified files (1)
  • src/tools/contracts/get_contract_list.ts
Latest Contributors(2)
UserCommitDate
neo@spotdraft.comfix(get_contract_list)...May 12, 2026
bot-github@spotdraft.comdocs(mcp): clarify ent...May 12, 2026
Review this PR on Baz | Customize your next review

…clarify operator key format

The LLM incorrectly sent metadataFilters as {"48802": {"\": "NOT_SET"}} (operator
in value) instead of {"48802[\]": "NOT_SET"} (operator in key). The serialization
code cast the object value to string via URLSearchParams.append() which produced
"[object Object]", causing the Django backend to receive an unparseable currency value
and throw ValueError -> 500.

Changes:
- Add ValidationError for non-string metadataFilters values with a message that
  directs the LLM to use bracket notation in the key ("48802[\]")
- Update tool description to document the key format and per-type value format
  explicitly with examples matching the Django filter_processor spec
- Update inputSchema.metadataFilters.description with concise format reminder
- Add two new tests: object-value rejection and correct string serialisation

Sentry event: 7e020f86dcfa4dc194efd7e46a9e164a (prod-usa, 2026-05-12T15:00:17Z)
LangSmith trace: 019e1cb3-bda0-72d1-8d08-14a64c16591f

Co-authored-by: Achuth Karakkat <achuth@spotdraft.com>
@sachin-spotdraft sachin-spotdraft added the size/s < 100 lines of changes label May 12, 2026
Comment on lines 231 to 240
metadataFilters: {
type: 'object',
description: 'Filters to apply to metadata fields. Available operators depend on the field data type.',
description:
'Filters for metadata (key pointer) fields. ' +
'Key format: "<key_pointer_id>[$operator]" (bracket notation, e.g. "48802[$ne]"). ' +
'For $eq the operator is optional. ' +
'Values must be plain strings — never pass objects. ' +
'CURRENCY values: "<CODE> <amount>" e.g. "USD 1000". ' +
'DATE values: ISO 8601 e.g. "2025-06-07T00:00:00Z".',
},
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

metadataFilters is defined in the tool’s inputSchema but still allows the TypeScript shape implied by a loose object typing, while the implementation now rejects any non-string value at runtime (added in the same file around the metadataFilters validation loop). This creates a public contract mismatch: TS callers can compile object-operator formats like { '48802': { $ne: 'NOT_SET' } }, but the call will throw ValidationError instead. Consider tightening the schema/typing to enforce Record<string, string> (and aligning it with the tool schema). (Original place noted by the system: lines 257-263.)

Finding type: Breaking Changes | Severity: 🟢 Low


Want Baz to fix this for you? Activate Fixer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s < 100 lines of changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants