Skip to content

Commit a06e9e3

Browse files
fix(context): emit structured empty team collections
Keep legacy null text while returning nonnil typed slices so modern clients receive structured content for empty successful results. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
1 parent e227cad commit a06e9e3

2 files changed

Lines changed: 25 additions & 8 deletions

File tree

‎pkg/github/context_tools.go‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,9 @@ func GetTeams(t translations.TranslationHelperFunc) inventory.ServerTool {
234234
// outside contributors (trusted). Org team rosters are visible only
235235
// to org members, so confidentiality is private.
236236
result = attachStaticIFCLabel(ctx, deps, result, ifc.LabelTeam())
237+
if organizations == nil {
238+
organizations = []OrganizationTeams{}
239+
}
237240
return result, organizations, nil
238241
},
239242
)
@@ -302,6 +305,9 @@ func GetTeamMembers(t translations.TranslationHelperFunc) inventory.ServerTool {
302305
// outside contributors (trusted). A team's member roster is visible
303306
// only to org members, so confidentiality is private.
304307
result = attachStaticIFCLabel(ctx, deps, result, ifc.LabelTeam())
308+
if members == nil {
309+
members = []string{}
310+
}
305311
return result, members, nil
306312
},
307313
)

‎pkg/github/context_tools_test.go‎

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -372,24 +372,35 @@ func TestContextToolsTypedRegistration(t *testing.T) {
372372
assert.Equal(t, 2, graphQLCalls, "schema validation must reject empty required strings before the handler")
373373

374374
for _, tc := range []struct {
375-
name string
376-
args map[string]any
377-
text string
378-
matcher githubv4mock.Matcher
375+
name string
376+
args map[string]any
377+
text string
378+
structured string
379+
matcher githubv4mock.Matcher
379380
}{
380-
{"get_teams", map[string]any{"user": "no-orgs"}, "null", emptyOrganizationsMatcher},
381-
{"get_teams", map[string]any{"user": "no-teams"}, `[{"org":"testorg","teams":[]}]`, emptyTeamsMatcher},
382-
{"get_team_members", map[string]any{"org": "testorg", "team_slug": "emptyteam"}, "null", emptyMembersMatcher},
381+
{"get_teams", map[string]any{"user": "no-orgs"}, "null", "[]", emptyOrganizationsMatcher},
382+
{"get_teams", map[string]any{"user": "no-teams"}, `[{"org":"testorg","teams":[]}]`, `[{"org":"testorg","teams":[]}]`, emptyTeamsMatcher},
383+
{"get_team_members", map[string]any{"org": "testorg", "team_slug": "emptyteam"}, "null", "[]", emptyMembersMatcher},
383384
} {
384385
mockedGQLClient = githubv4.NewClient(githubv4mock.NewMockedHTTPClient(tc.matcher))
386+
serverTool := getTeamsTool
387+
if tc.name == "get_team_members" {
388+
serverTool = teamMembersTool
389+
}
390+
request := createMCPRequest(tc.args)
391+
legacyResult, err := serverTool.Handler(deps)(ContextWithDeps(context.Background(), deps), &request)
392+
require.NoError(t, err)
393+
require.False(t, legacyResult.IsError)
394+
assert.Equal(t, tc.text, getTextResult(t, legacyResult).Text)
385395
result, err := clientSession.CallTool(context.Background(), &mcp.CallToolParams{Name: tc.name, Arguments: tc.args})
386396
require.NoError(t, err)
387397
require.False(t, result.IsError)
398+
require.NotNil(t, result.StructuredContent, "empty successful collections must have structured content on the wire")
388399
require.Len(t, result.Content, 1, "SDK fallback must not duplicate the legacy text")
389400
assert.Equal(t, tc.text, getTextResult(t, result).Text)
390401
structuredJSON, err := json.Marshal(result.StructuredContent)
391402
require.NoError(t, err)
392-
assert.JSONEq(t, tc.text, string(structuredJSON))
403+
assert.JSONEq(t, tc.structured, string(structuredJSON))
393404
require.NoError(t, outputSchemas[tc.name].Validate(result.StructuredContent))
394405
}
395406

0 commit comments

Comments
 (0)