refactor: add structured output support and MCP spec compliance#960
Merged
matzew merged 3 commits intocontainers:mainfrom Mar 25, 2026
Merged
refactor: add structured output support and MCP spec compliance#960matzew merged 3 commits intocontainers:mainfrom
matzew merged 3 commits intocontainers:mainfrom
Conversation
8b61a18 to
da444aa
Compare
Cali0707
reviewed
Mar 24, 2026
pkg/output/output.go
Outdated
| case *unstructured.UnstructuredList: | ||
| items := make([]map[string]any, 0, len(t.Items)) | ||
| for _, item := range t.Items { | ||
| items = append(items, item.Object) |
Collaborator
There was a problem hiding this comment.
maybe we deepcopy the item.Object? that way any modifications to PrintResult.Structured won't also modify the Unstructured Object
pkg/output/output.go
Outdated
| } | ||
| return &PrintResult{Text: text, Structured: items}, nil | ||
| case *unstructured.Unstructured: | ||
| return &PrintResult{Text: text, Structured: t.Object}, nil |
Collaborator
There was a problem hiding this comment.
maybe we deepcopy the item.Object? that way any modifications to PrintResult.Structured won't also modify the Unstructured Object
| // Note: this checks the top-level reflect.Kind, so a pointer-to-slice (*[]T) | ||
| // would not be wrapped. All current callers pass value types. | ||
| func ensureStructuredObject(v any) any { | ||
| rv := reflect.ValueOf(v) |
Collaborator
There was a problem hiding this comment.
I think we still are missing handling typed nil, e.g. []string(nil). This would still show up as a rv.Kind() == reflect.Slice, but would end up json serializing to {"items": null} which I don't think is correct
Extend the Output interface with a PrintObjStructured method that returns both a human-readable text representation and optional structured data extracted from Kubernetes objects. This lays the groundwork for consumers that need programmatic access to the data alongside the formatted text. - Add PrintResult struct holding Text and Structured fields - Implement PrintObjStructured for yaml (returns deep-copied list items or object map) - Implement PrintObjStructured for table (extracts column-keyed maps via tableToStructured helper) - Refactor table.PrintObj to delegate to printTable for code reuse - Rewrite output tests to testify/suite pattern with new coverage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Marc Nuri <marc@marcnuri.com>
Add a NewToolCallResultFull constructor that creates a ToolCallResult with both human-readable text and structured content as separate fields. Unlike NewToolCallResultStructured (which JSON-serializes structured data into Content), this preserves the original text representation (e.g. table or YAML output) alongside the structured data. Refactor NewToolCallResult and NewToolCallResultStructured to delegate to NewToolCallResultFull, making it the single canonical constructor. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Marc Nuri <marc@marcnuri.com>
The MCP specification requires structuredContent to marshal to a JSON
object, but NewStructuredResult could receive slice/array values. Add
ensureStructuredObject to automatically wrap slices in {"items": [...]}
so that the result always complies with the spec.
Typed nil slices (e.g. []string(nil)) are detected via reflect and
return nil to avoid producing {"items": null}.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Marc Nuri <marc@marcnuri.com>
da444aa to
5fe1ade
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Prerequisite refactors extracted from #920 to reduce its diff size.
These changes are self-contained improvements to the existing codebase
that lay the groundwork for MCP Apps (#753).
Changes
PrintObjStructuredon Output interface — Extends theOutputinterface with a method that returns both human-readable text and
optional structured data extracted from Kubernetes objects. Includes
tableToStructuredhelper for column-keyed extraction from Tableresponses. Rewrites output tests to
testify/suite.NewToolCallResultFullconstructor — New API constructor thatcreates a
ToolCallResultwith separate text and structured contentfields, for cases where the text representation differs from a JSON
serialization of the structured data.
ensureStructuredObjectfor MCP spec compliance — The MCP specrequires
structuredContentto be a JSON object. Slices/arrayspassed to
NewStructuredResultare now automatically wrapped in{"items": [...]}.Refs #753
Refs #920