From 4353e21e5c0dffafce0874791e2cf14f47f97181 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Apr 2026 14:56:07 +0000 Subject: [PATCH 1/2] Initial plan From da2c5b71203bf287654fbdf5959861ac360c191e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 22 Apr 2026 15:04:59 +0000 Subject: [PATCH 2/2] Deduplicate raw MCP text response envelope construction Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/a3f06b05-31a7-402c-85b4-9fb0e879b2fc Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --- internal/mcp/tool_result.go | 9 +++++++++ internal/mcp/tool_result_test.go | 15 +++++++++++++++ internal/proxy/proxy.go | 8 ++------ internal/server/system_tools.go | 19 +++---------------- internal/server/unified.go | 7 +------ 5 files changed, 30 insertions(+), 28 deletions(-) diff --git a/internal/mcp/tool_result.go b/internal/mcp/tool_result.go index 7eb5c622..8c97e94e 100644 --- a/internal/mcp/tool_result.go +++ b/internal/mcp/tool_result.go @@ -156,3 +156,12 @@ func NewErrorCallToolResult(err error) (*sdk.CallToolResult, interface{}, error) }, }, nil, err } + +// BuildMCPTextResponse returns a raw MCP response map with a single text content item. +func BuildMCPTextResponse(text string) map[string]interface{} { + return map[string]interface{}{ + "content": []map[string]interface{}{ + {"type": "text", "text": text}, + }, + } +} diff --git a/internal/mcp/tool_result_test.go b/internal/mcp/tool_result_test.go index 285ea2c8..6838fe6d 100644 --- a/internal/mcp/tool_result_test.go +++ b/internal/mcp/tool_result_test.go @@ -415,3 +415,18 @@ func TestConvertToCallToolResult_MarshalError(t *testing.T) { assert.Nil(t, result) assert.Contains(t, err.Error(), "failed to marshal backend result") } + +func TestBuildMCPTextResponse(t *testing.T) { + text := `{"permission":"write"}` + + result := BuildMCPTextResponse(text) + + require := require.New(t) + assert := assert.New(t) + + content, ok := result["content"].([]map[string]interface{}) + require.True(ok) + require.Len(content, 1) + assert.Equal("text", content[0]["type"]) + assert.Equal(text, content[0]["text"]) +} diff --git a/internal/proxy/proxy.go b/internal/proxy/proxy.go index 55145133..2bb2fe02 100644 --- a/internal/proxy/proxy.go +++ b/internal/proxy/proxy.go @@ -20,6 +20,7 @@ import ( "github.com/github/gh-aw-mcpg/internal/difc" "github.com/github/gh-aw-mcpg/internal/guard" "github.com/github/gh-aw-mcpg/internal/logger" + "github.com/github/gh-aw-mcpg/internal/mcp" "github.com/github/gh-aw-mcpg/internal/tracing" ) @@ -331,12 +332,7 @@ func (r *restBackendCaller) CallTool(ctx context.Context, toolName string, args } // Wrap in MCP response format: {content: [{type: "text", text: "..."}]} - mcpResp := map[string]interface{}{ - "content": []map[string]interface{}{ - {"type": "text", "text": string(body)}, - }, - } - return mcpResp, nil + return mcp.BuildMCPTextResponse(string(body)), nil } // forwardToGitHub sends a request to the upstream GitHub API. diff --git a/internal/server/system_tools.go b/internal/server/system_tools.go index 13c990b5..6653a757 100644 --- a/internal/server/system_tools.go +++ b/internal/server/system_tools.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/github/gh-aw-mcpg/internal/logger" + "github.com/github/gh-aw-mcpg/internal/mcp" ) var logSys = logger.New("server:system_tools") @@ -89,14 +90,7 @@ func (s *SysServer) callTool(name string, args map[string]interface{}) (interfac func (s *SysServer) sysInit() (interface{}, error) { logSys.Printf("Initializing MCPG system with %d servers", len(s.serverIDs)) - return map[string]interface{}{ - "content": []map[string]interface{}{ - { - "type": "text", - "text": fmt.Sprintf("MCPG initialized. Available servers: %v", s.serverIDs), - }, - }, - }, nil + return mcp.BuildMCPTextResponse(fmt.Sprintf("MCPG initialized. Available servers: %v", s.serverIDs)), nil } func (s *SysServer) listServers() (interface{}, error) { @@ -105,12 +99,5 @@ func (s *SysServer) listServers() (interface{}, error) { serverList += fmt.Sprintf("%d. %s\n", i+1, id) } - return map[string]interface{}{ - "content": []map[string]interface{}{ - { - "type": "text", - "text": fmt.Sprintf("Configured MCP Servers:\n%s", serverList), - }, - }, - }, nil + return mcp.BuildMCPTextResponse(fmt.Sprintf("Configured MCP Servers:\n%s", serverList)), nil } diff --git a/internal/server/unified.go b/internal/server/unified.go index 9fb6cca9..c617f5b7 100644 --- a/internal/server/unified.go +++ b/internal/server/unified.go @@ -346,12 +346,7 @@ func (g *guardBackendCaller) callCollaboratorPermission(ctx context.Context, arg } // Wrap in MCP response format so the WASM guard can parse it consistently - mcpResp := map[string]interface{}{ - "content": []map[string]interface{}{ - {"type": "text", "text": string(body)}, - }, - } - return mcpResp, nil + return mcp.BuildMCPTextResponse(string(body)), nil } // buildCircuitBreakers creates per-backend circuit breakers from the configuration.