Skip to content

Conversation

@wellsiau-aws
Copy link
Contributor

@wellsiau-aws wellsiau-aws commented Jun 27, 2025

Updated to support the new StreamableHTTP transport from mcp-go v0.32.0.

Resolves #68

1. Library Update

  • Updated github.com/mark3labs/mcp-go from v0.27.0 to v0.32.0
  • Added support for server.NewStreamableHTTPServer()

2. API Changes

The new mcp-go version changed how tool arguments are accessed:

Before (v0.27.0):

serviceSlug, ok := request.Params.Arguments["serviceSlug"].(string)
if !ok || serviceSlug == "" {
    return nil, fmt.Errorf("serviceSlug is required")
}

After (v0.32.0):

serviceSlug := request.GetString("serviceSlug", "")
if serviceSlug == "" {
    return nil, fmt.Errorf("serviceSlug is required")
}

3. Transport Implementation

New StreamableHTTP Implementation:

streamableServer := server.NewStreamableHTTPServer(hcServer,
    server.WithEndpointPath("/mcp"), // Standard MCP endpoint
    server.WithLogger(logger),
)

4. Refactor e2e tests

  • Added name for each tests
  • Refactor e2e test for stdio and http mode
  • Add additional clean up

- Update mcp-go from v0.27.0 to v0.32.0
- Add StreamableHTTP server
- Update API calls to use new request.GetString() methods
- Maintain backward compatibility with stdio mode
@hashicorp-cla-app
Copy link

hashicorp-cla-app bot commented Jun 27, 2025

CLA assistant check
All committers have signed the CLA.

@hashicorp-cla-app
Copy link

CLA assistant check

Thank you for your submission! We require that all contributors sign our Contributor License Agreement ("CLA") before we can accept the contribution. Read and sign the agreement

Learn more about why HashiCorp requires a CLA and what the CLA includes

Have you signed the CLA already but the status is still pending? Recheck it.

@wellsiau-aws
Copy link
Contributor Author

Some tests are failing, but I think that's because the underlying error handling in the tfregistry package. I will defer this to future PR to avoid scope creep.

    --- FAIL: TestE2E/Stdio (5.42s)
        --- PASS: TestE2E/Stdio/Initialize (0.14s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/empty_payload (0.00s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/missing_namespace_and_version (0.00s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/without_version (0.37s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/hashicorp_without_namespace (0.75s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/third_party_without_namespace (0.10s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/required_values_resource (0.19s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/data_source_with_prefix (0.20s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/third_party_resource (0.19s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/third_party_data_source (0.20s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/malformed_namespace (0.32s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/malformed_provider_name (0.10s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/guides_documentation (0.51s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/functions_documentation (0.36s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/overview_documentation (0.34s)
        --- PASS: TestE2E/Stdio/Stdio_getProviderDocs/empty_payload (0.00s)
        --- PASS: TestE2E/Stdio/Stdio_getProviderDocs/empty_doc_id (0.00s)
        --- PASS: TestE2E/Stdio/Stdio_getProviderDocs/invalid_doc_id (0.11s)
        --- PASS: TestE2E/Stdio/Stdio_getProviderDocs/valid_doc_id (0.09s)
        --- PASS: TestE2E/Stdio/Stdio_getProviderDocs/incorrect_numeric_doc_id (0.10s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/no_parameters (0.00s)
        --- FAIL: TestE2E/Stdio/Stdio_searchModules/empty_query_all_modules (0.00s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/aws_query_no_offset (0.25s)
        --- FAIL: TestE2E/Stdio/Stdio_searchModules/empty_query_with_offset (0.00s)
        --- FAIL: TestE2E/Stdio/Stdio_searchModules/offset_only (0.00s)
        --- FAIL: TestE2E/Stdio/Stdio_searchModules/negative_offset (0.00s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/unknown_provider (0.14s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/vsphere_capitalized (0.11s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/aviatrix_provider (0.14s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/oci_provider (0.14s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/query_with_spaces (0.12s)
        --- PASS: TestE2E/Stdio/Stdio_moduleDetails/valid_module_id (0.11s)
        --- PASS: TestE2E/Stdio/Stdio_moduleDetails/missing_module_id (0.00s)
        --- PASS: TestE2E/Stdio/Stdio_moduleDetails/empty_module_id (0.00s)
        --- PASS: TestE2E/Stdio/Stdio_moduleDetails/nonexistent_module_id (0.08s)
        --- PASS: TestE2E/Stdio/Stdio_moduleDetails/invalid_format (0.09s)
    --- FAIL: TestE2E/HTTP (5.09s)
        --- PASS: TestE2E/HTTP/Initialize (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/empty_payload (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/missing_namespace_and_version (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/without_version (0.35s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/hashicorp_without_namespace (0.68s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/third_party_without_namespace (0.03s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/required_values_resource (0.20s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/data_source_with_prefix (0.20s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/third_party_resource (0.21s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/third_party_data_source (0.19s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/malformed_namespace (0.23s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/malformed_provider_name (0.02s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/guides_documentation (0.61s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/functions_documentation (0.37s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/overview_documentation (0.44s)
        --- PASS: TestE2E/HTTP/HTTP_getProviderDocs/empty_payload (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_getProviderDocs/empty_doc_id (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_getProviderDocs/invalid_doc_id (0.01s)
        --- PASS: TestE2E/HTTP/HTTP_getProviderDocs/valid_doc_id (0.08s)
        --- PASS: TestE2E/HTTP/HTTP_getProviderDocs/incorrect_numeric_doc_id (0.01s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/no_parameters (0.00s)
        --- FAIL: TestE2E/HTTP/HTTP_searchModules/empty_query_all_modules (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/aws_query_no_offset (0.25s)
        --- FAIL: TestE2E/HTTP/HTTP_searchModules/empty_query_with_offset (0.00s)
        --- FAIL: TestE2E/HTTP/HTTP_searchModules/offset_only (0.00s)
        --- FAIL: TestE2E/HTTP/HTTP_searchModules/negative_offset (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/unknown_provider (0.16s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/vsphere_capitalized (0.11s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/aviatrix_provider (0.14s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/oci_provider (0.15s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/query_with_spaces (0.12s)
        --- PASS: TestE2E/HTTP/HTTP_moduleDetails/valid_module_id (0.14s)
        --- PASS: TestE2E/HTTP/HTTP_moduleDetails/missing_module_id (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_moduleDetails/empty_module_id (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_moduleDetails/nonexistent_module_id (0.01s)
        --- PASS: TestE2E/HTTP/HTTP_moduleDetails/invalid_format (0.01s)

@wellsiau-aws
Copy link
Contributor Author

I forgot, I did made changes to the tfregistry since the bump the mcp-go, I will investigate the error

@wellsiau-aws
Copy link
Contributor Author

tests are passing now:

--- PASS: TestE2E (14.08s)
    --- PASS: TestE2E/Stdio (7.02s)
        --- PASS: TestE2E/Stdio/Initialize (0.16s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/empty_payload (0.00s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/missing_namespace_and_version (0.00s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/without_version (0.35s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/hashicorp_without_namespace (0.65s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/third_party_without_namespace (0.11s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/required_values_resource (0.22s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/data_source_with_prefix (0.55s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/third_party_resource (0.40s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/third_party_data_source (0.20s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/malformed_namespace (0.30s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/malformed_provider_name (0.10s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/guides_documentation (0.56s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/functions_documentation (0.54s)
        --- PASS: TestE2E/Stdio/Stdio_resolveProviderDocID/overview_documentation (0.29s)
        --- PASS: TestE2E/Stdio/Stdio_getProviderDocs/empty_payload (0.00s)
        --- PASS: TestE2E/Stdio/Stdio_getProviderDocs/empty_doc_id (0.00s)
        --- PASS: TestE2E/Stdio/Stdio_getProviderDocs/invalid_doc_id (0.10s)
        --- PASS: TestE2E/Stdio/Stdio_getProviderDocs/valid_doc_id (0.01s)
        --- PASS: TestE2E/Stdio/Stdio_getProviderDocs/incorrect_numeric_doc_id (0.09s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/no_parameters (0.00s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/empty_query_all_modules (0.14s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/aws_query_no_offset (0.39s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/empty_query_with_offset (0.13s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/offset_only (0.13s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/negative_offset (0.12s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/unknown_provider (0.15s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/vsphere_capitalized (0.22s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/aviatrix_provider (0.17s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/oci_provider (0.41s)
        --- PASS: TestE2E/Stdio/Stdio_searchModules/query_with_spaces (0.11s)
        --- PASS: TestE2E/Stdio/Stdio_moduleDetails/valid_module_id (0.12s)
        --- PASS: TestE2E/Stdio/Stdio_moduleDetails/missing_module_id (0.00s)
        --- PASS: TestE2E/Stdio/Stdio_moduleDetails/empty_module_id (0.00s)
        --- PASS: TestE2E/Stdio/Stdio_moduleDetails/nonexistent_module_id (0.09s)
        --- PASS: TestE2E/Stdio/Stdio_moduleDetails/invalid_format (0.09s)
    --- PASS: TestE2E/HTTP (5.40s)
        --- PASS: TestE2E/HTTP/Initialize (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/empty_payload (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/missing_namespace_and_version (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/without_version (0.34s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/hashicorp_without_namespace (0.65s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/third_party_without_namespace (0.02s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/required_values_resource (0.19s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/data_source_with_prefix (0.20s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/third_party_resource (0.19s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/third_party_data_source (0.19s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/malformed_namespace (0.32s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/malformed_provider_name (0.02s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/guides_documentation (0.56s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/functions_documentation (0.49s)
        --- PASS: TestE2E/HTTP/HTTP_resolveProviderDocID/overview_documentation (0.29s)
        --- PASS: TestE2E/HTTP/HTTP_getProviderDocs/empty_payload (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_getProviderDocs/empty_doc_id (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_getProviderDocs/invalid_doc_id (0.01s)
        --- PASS: TestE2E/HTTP/HTTP_getProviderDocs/valid_doc_id (0.01s)
        --- PASS: TestE2E/HTTP/HTTP_getProviderDocs/incorrect_numeric_doc_id (0.01s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/no_parameters (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/empty_query_all_modules (0.12s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/aws_query_no_offset (0.26s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/empty_query_with_offset (0.13s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/offset_only (0.12s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/negative_offset (0.13s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/unknown_provider (0.14s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/vsphere_capitalized (0.11s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/aviatrix_provider (0.15s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/oci_provider (0.14s)
        --- PASS: TestE2E/HTTP/HTTP_searchModules/query_with_spaces (0.12s)
        --- PASS: TestE2E/HTTP/HTTP_moduleDetails/valid_module_id (0.12s)
        --- PASS: TestE2E/HTTP/HTTP_moduleDetails/missing_module_id (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_moduleDetails/empty_module_id (0.00s)
        --- PASS: TestE2E/HTTP/HTTP_moduleDetails/nonexistent_module_id (0.01s)
        --- PASS: TestE2E/HTTP/HTTP_moduleDetails/invalid_format (0.01s)
PASS

@gautambaghel gautambaghel requested a review from Copilot June 27, 2025 22:32
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR updates the MCP server to support the new StreamableHTTP transport from mcp-go v0.32.0 while refactoring tool argument access and end-to-end test implementations. Key changes include:

  • Migrating from manual map lookups (request.Params.Arguments) to using helper methods (RequireString/GetString) for tool arguments.
  • Adding support for HTTP transport in the server and e2e tests, including new Docker commands and health check endpoints.
  • Updating documentation, Makefile targets, and go.mod dependency versions to reflect the latest changes.

Reviewed Changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pkg/hashicorp/tfregistry/utils.go Updated provider detail resolution to use the new request helpers.
pkg/hashicorp/tfregistry/handlers.go Updated tool argument handling for serviceSlug, providerDocID, etc.
go.mod Updated mcp-go dependency and Go version.
e2e/payloads.go Added TestName field to test case struct and updated test payloads.
e2e/e2e_test.go Refactored e2e tests to support both Stdio and HTTP transports.
cmd/terraform-mcp-server/main.go Introduced the new http command and environment-based server launch.
cmd/terraform-mcp-server/init.go Added HTTP command flags to support port and host configuration.
README.md Expanded documentation for transport support and usage examples.
Makefile Added new targets for running and testing the HTTP server and container cleanup.
Dockerfile Updated CMD instructions to allow mode selection via environment.
Comments suppressed due to low confidence (1)

pkg/hashicorp/tfregistry/utils.go:210

  • [nitpick] When providerNamespace is empty, the log message prints an empty value. Consider updating the log message to include a fallback indicator or clarify that an empty providerNamespace is being replaced with "hashicorp".
	providerNamespace := request.GetString("providerNamespace", "")

output, err := cmd.Output()
require.NoError(t, err, "expected to start HTTP container successfully")

containerID := string(output)[:12] // First 12 chars of container ID
Copy link

Copilot AI Jun 27, 2025

Choose a reason for hiding this comment

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

[nitpick] Truncating the container ID by taking the first 12 characters may lead to issues if the output contains extra whitespace or unexpected formatting. Consider trimming the output and verifying the container ID format before using it.

Suggested change
containerID := string(output)[:12] // First 12 chars of container ID
trimmedOutput := strings.TrimSpace(string(output)) // Remove leading/trailing whitespace
matched, err := regexp.MatchString("^[a-f0-9]{64}$", trimmedOutput) // Validate container ID format
require.NoError(t, err, "failed to validate container ID format")
require.True(t, matched, "invalid container ID format")
containerID := trimmedOutput[:12] // First 12 chars of validated container ID

Copilot uses AI. Check for mistakes.
Copy link
Member

@gautambaghel gautambaghel left a comment

Choose a reason for hiding this comment

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

LGTM! Thanks for the contribution

@gautambaghel gautambaghel merged commit 632c30f into hashicorp:main Jun 28, 2025
22 checks passed
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.

how to config terraform mcp server with docker opening port and mcp protocol as sse or streamhttp?

2 participants