Support nested or raw JSON bodies for complex MCP tool requests #16
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context from coilyco-bridge/deploy#107. The tailnet-only read-only
signoz-mcplanded using ward-mcp, but the deploy run reported that SigNozquery_rangewas awkward because ward-mcp's current grammar does not model the nested/raw JSON body shape precisely.Problem:
POST /api/v3/query_rangeis the immediate example: the useful query body is nested, and a lossy/scalar-only MCP schema makes the tool less ergonomic or less precise.Design ask:
Acceptance for design:
Related: coilyco-bridge/deploy#107, signoz-mcp query_range.
🔎 ward agent advisor - cross-repo fan-out
ward agent advisor --harness codexran a one-shot standard research pass on this question:Recommendation
Implement this in core, not in chart/config conventions. The limitation is not in the Helm chart or the per-service
.mcp.kdl. It is in the sharedcli-guard/http/opcoremodel that ward-mcp projects.As of 2026-07-09, the deployed SigNoz example in
/substrate/deploy/services/signoz-mcp/signoz.mcp.kdlalready targetsPOST /api/v5/query_range, notv3, and the awkward part is exactly what the issue describes: the request body has nested/object-valued fields likecompositeQuery,variables, andformatOptions.What the code says today
The current behavior is split between runtime capability and schema expressiveness:
opcore.ParseInlineonly accepts flat inline body declarations likebody "title" "body".Field{Name, Type:"string"}values.opcore.Schemais also flat:map[string]Property, with no nested object model.ward-mcpthen exposes that flat schema as MCPinputSchema.ward-mcpalready unmarshals tool arguments asmap[string]anyand passes body values through verbatim.That means nested JSON is already possible at runtime for top-level body keys if the MCP client sends it anyway. The real bug is that the generated schema is lossy or misleading, so clients lose discoverability and may coerce object-valued inputs incorrectly.
Decision
Use a two-tier design:
opcoreand the inline grammar.That preserves typed discoverability for normal cases while avoiding bespoke Go MCP servers for endpoints like SigNoz query builders.
Recommended grammar shape
Keep existing flat syntax unchanged as sugar:
Add an additive block form for richer cases, for example:
And later, if needed, permit fully nested authoring as an extension of the same shape:
The key point is the model, not the exact node spelling:
fieldfor scalar fieldsobjectfor object-valued fieldsarrayfor arraysraw=truefor a JSON blob escape hatch at that fieldWhy this shape
This is the best fit for the current architecture:
opcorerather than hard-coding MCP-only behavior.cli-guarddesign, where the CLI side already has a comparable escape hatch via--body-filefor shapes too complex for flags.Why not chart/config conventions only
A chart-level convention cannot fix the real problem, because the bad abstraction is upstream:
A deploy-side convention can document a workaround, but it cannot restore typed discoverability for all consumers.
Why not raw-JSON-only as the whole answer
A single raw JSON parameter would be the fastest patch, but it is too blunt as the default:
Raw JSON should exist, but as the fallback, not the only surface.
Safety tradeoffs
The safety impact is acceptable if the feature is constrained correctly.
8 MiB) and keepset/fixed-body behavior authoritative.restrict, auth, or method/path controls.Migration guidance
This can be fully additive.
body "a" "b"working exactly as it does now.signoz-mcpcan migrate just itsread_querytool once the core feature lands.Open questions
These are the only design questions worth settling before implementation:
My recommendation: only
string|boolean|integer|number|object|array, plusrequiredandraw=true. Do not start withoneOf,enum, nullable, or full JSON Schema embedding.Not required for v1. The main defect is the lossy advertised schema, not request forwarding. Server-side validation can be a later tightening pass if client interoperability demands it.
Probably not. A
raw=trueobject field is enough for the SigNoz-style query envelope, and typed nested authoring can grow incrementally.Advisory conclusion
The recommendation is:
cli-guardcore (opcore).That gives the narrowest change that fixes the real abstraction leak while preserving backward compatibility for the current flat tools.
The work spans multiple repos, so it was filed as 2 tracked issue(s), in dependency order:
Researched and posted automatically by
ward agent advisor --harness codex(ward#424). This is one-shot research, not a carried change - verify before acting on it.— Codex, via
ward agentDesign acceptance is satisfied by the advisor result above. It recommends implementing the schema model in cli-guard core, then consuming it from ward-mcp, and it filed the follow-up issues in dependency order: coilyco-flight-deck/cli-guard#212 and coilyco-flight-deck/ward-mcp#17. The agent is closing this design ticket and leaving implementation tracked on those issues.