Skip to content

feat(search): add schema-backed query guidance (2/6) - #587

Open
sowju-hashicorp wants to merge 1 commit into
sowju/search-01-discoveryfrom
sowju/search-02-configuration
Open

sowju-hashicorp wants to merge 1 commit into
sowju/search-01-discoveryfrom
sowju/search-02-configuration

Conversation

@sowju-hashicorp

Copy link
Copy Markdown

Summary

PR 2 of 6 in the Terraform Search stack.

Branch: sowju/search-02-configuration
Base: sowju/search-01-discovery

Adds generate_query_configuration to guide callers in constructing a Terraform Search query from discovered provider capabilities.

Changes

  • Adds schema-backed query guidance on both MCP SDKs.
  • Supports wrapped and bare list-resource schemas.
  • Preserves the exact provider version and resource type names supplied from discovery.
  • Describes scalar attributes, nested blocks, required inputs, nesting modes, and cardinality.
  • Provides configuration examples and guidance for supported filters and variables.
  • Registers the generator without requiring TFE credentials.
  • Adds validation, adapter parity, registration, credential-gating, logging, and documentation tests.

Security impact

  • Processes caller-supplied schema data without submitting queries or making backend requests.
  • Extends Search argument-logging suppression to the new tool.
  • Does not execute generated configuration, read local files, upload configuration, create Runs, import resources, or apply changes.
  • Generated guidance is not a guarantee that the backend will accept the resulting configuration.

Validation

  • Focused tests passed for Search logic, client middleware, both SDK integrations, registration, toolsets, instructions, and CLI.
  • Server build and diff checks passed.
  • No live HCP Terraform operations were performed.

Reviewer focus

  • Fidelity to the supplied provider schema and exact resource names/version.
  • Correct handling of nested blocks, cardinality, required values, and unsupported resource selections.
  • Equivalent behavior across both MCP SDKs.
  • Generator availability without TFE credentials.

Stack scope

Depends on PR 1 for provider discovery and shared foundation. Set this PR's base to sowju/search-01-discovery so the diff shows only query guidance.

Query execution/status, validated summaries, import preparation, and Plan verification are deferred to subsequent PRs.

Next branch: sowju/search-03-execution, based on this branch.

Some source-preserved tool guidance references later execution/status/summary tools. Those tools are not registered here; this is an incremental review layer, not the complete Search workflow.

Rollback

Revert this PR before dependent layers merge. If dependent layers have merged, coordinate their rollback in reverse dependency order. PR 1's provider discovery can remain in place. No data migration or infrastructure rollback is required.

PCI review checklist

  • I have documented a clear reason for, and description of, the change I am making.

  • If applicable, I've documented a plan to revert these changes if they require more than reverting the pull request.

  • If applicable, I've documented the impact of any changes to security controls.

    Examples of changes to security controls include using new access control methods, adding or removing logging pipelines, etc.

@sowju-hashicorp
sowju-hashicorp requested a review from a team as a code owner October 22, 2026 01:44
Copilot AI balanced review requested due to automatic review settings October 22, 2026 01:44
@sowju-hashicorp sowju-hashicorp changed the title feat(search): add schema-backed query guidance feat(search): add schema-backed query guidance (2/6) Oct 22, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🟡 Changes recommended

Schema validation and rendering can lose required nested structure and produce examples that violate supplied types or cardinality.

7 open issues
What changed in this PR

Adds credential-free query configuration guidance to the Terraform Search toolset, building on provider discovery. Both MCP SDKs share the generator; query execution remains outside this release.

Changes:

  • Adds schema parsing, resource selection, attribute catalogs, examples, and variable guidance.
  • Registers the generator on both SDKs without requiring Terraform credentials.
  • Extends tests and documentation for transport parity, credential gating, logging suppression, and workflow boundaries.
File Description
README.md Documents generator usage and release boundaries.
pkg/​toolsets/​toolsets.go Updates the Search toolset description.
pkg/​toolsets/​search.go Adds credential-free generator metadata.
pkg/​toolsets/​search_test.go Tests tool selection and credential gating.
pkg/​tools/​search/​provider_list_schema_list_test.go Connects discovered schemas to generation.
pkg/​tools/​search/​generate_query_configuration.go Implements shared guidance and the legacy tool.
pkg/​tools/​search/​generate_query_configuration_test.go Tests parsing, catalogs, examples, and guidance.
pkg/​tools/​search/​descriptions.go Exports the shared generator description.
pkg/​tools/​search/​descriptions_test.go Checks generator description contracts.
pkg/​tools/​factories.go Registers the legacy SDK generator.
pkg/​tools/​factories_test.go Tests registration without credentials.
pkg/​mcp-official/​tools/​tools.go Registers the official SDK generator.
pkg/​mcp-official/​tools/​tools_test.go Tests registration, discovery integration, and parity.
pkg/​mcp-official/​tools/​search/​search.go Adds official SDK arguments and handler.
pkg/​mcp-official/​tools/​search/​search_test.go Tests annotations and input validation.
pkg/​mcp-official/​tools/​middleware/​tool_logging_test.go Tests official SDK logging suppression.
pkg/​instructions/​instructions.md Defines the discovery-to-guidance workflow.
pkg/​instructions/​instructions_test.go Checks guidance and release boundaries.
pkg/​client/​tool_logging_middleware_test.go Tests legacy SDK argument suppression.
CHANGELOG.md Announces configuration guidance support.

Review effort: Balanced

Comment on lines +66 to +70
type listResourceAttribute struct {
Description string `json:"description"`
Required bool `json:"required"`
Optional bool `json:"optional"`
Type any `json:"type"` // "string" | "bool" | "number" | ["list","string"] | ...
Comment on lines +201 to +223
// resource-type map. It uses a structural heuristic: a bare map whose first
// entry has a "block" child is the resource-type map; anything else is treated
// as the wrapped file format.
func parseListResourceSchemas(raw string) (map[string]listResourceEntry, error) {
// Try the bare map first. A valid bare map has entries with a "block" key
// rather than a top-level "list_resource_schemas" key.
var bare map[string]listResourceEntry
if err := json.Unmarshal([]byte(raw), &bare); err == nil {
if _, hasWrapper := bare["list_resource_schemas"]; !hasWrapper {
return bare, nil
}
}

// Try the wrapped file format.
var wrapped listResourceSchemaFile
if err := json.Unmarshal([]byte(raw), &wrapped); err != nil {
return nil, fmt.Errorf("input is not valid JSON: %w", err)
}
if wrapped.ListResourceSchemas == nil {
return nil, fmt.Errorf("no list_resource_schemas key found in input")
}
return wrapped.ListResourceSchemas, nil
}
}
}
// ["list","string"], ["set","string"], ["map","string"], etc.
return fmt.Sprintf("%s(%s)", outer, humanType(v[1]))
subNames := sortedKeys(subAttrs)
subSummary := make([]string, 0, len(subNames))
for _, sub := range subNames {
subSummary = append(subSummary, fmt.Sprintf("`%s` (%s)", sub, humanType(subAttrs[sub].Type)))
Comment on lines +572 to +575
result = append(result, map[string]any{
"attribute": name,
"value": buildExampleBlockValue(bt.Block.Attributes),
})
Comment on lines +583 to +587
func buildExampleBlockValue(subAttrs map[string]listResourceAttribute) map[string]any {
obj := make(map[string]any, len(subAttrs))
for _, name := range sortedKeys(subAttrs) {
attr := subAttrs[name]
obj[name] = exampleValueForType(name, attr.Type)
Comment on lines +596 to +610
func exampleValueForType(attrName string, rawType any) any {
t := humanType(rawType)
switch {
case t == "bool" || t == "boolean":
return false
case t == "number":
return 0
case strings.HasPrefix(t, "list") || strings.HasPrefix(t, "set"):
return []string{"<value>"}
case strings.HasPrefix(t, "map") || strings.HasPrefix(t, "object"):
return map[string]string{"<key>": "<value>"}
default:
return fmt.Sprintf("<your-%s>", strings.ReplaceAll(attrName, "_", "-"))
}
}
@mjyocca
mjyocca added this pull request to stack #593 October 22, 2026 16:45
@mjyocca
mjyocca force-pushed the sowju/search-02-configuration branch from 76af936 to 87eb91c Compare October 22, 2026 18:54

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants