Skip to content

Commit 2f9b5b0

Browse files
asoormwilsonriverahardworker-bot
authored
feat(mcp): use GraphQL operation descriptions for MCP tool descriptions
Co-authored-by: Wilson Rivera <[email protected]> Co-authored-by: hardworker-bot <[email protected]>
1 parent 59af0f8 commit 2f9b5b0

File tree

9 files changed

+423
-30
lines changed

9 files changed

+423
-30
lines changed

router-tests/go.mod

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ require (
3636
go.uber.org/goleak v1.3.0
3737
go.uber.org/zap v1.27.0
3838
golang.org/x/net v0.46.0
39-
google.golang.org/grpc v1.68.1
39+
google.golang.org/grpc v1.71.0
4040
google.golang.org/protobuf v1.36.9
4141
gopkg.in/yaml.v3 v3.0.1
4242
)
@@ -170,15 +170,15 @@ require (
170170
go.uber.org/ratelimit v0.3.1 // indirect
171171
go.withmatt.com/connect-brotli v0.4.0 // indirect
172172
golang.org/x/crypto v0.43.0 // indirect
173-
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 // indirect
173+
golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 // indirect
174174
golang.org/x/mod v0.29.0 // indirect
175175
golang.org/x/sync v0.17.0 // indirect
176176
golang.org/x/sys v0.37.0 // indirect
177177
golang.org/x/text v0.30.0 // indirect
178178
golang.org/x/time v0.9.0 // indirect
179179
golang.org/x/tools v0.38.0 // indirect
180-
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 // indirect
181-
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a // indirect
180+
google.golang.org/genproto/googleapis/api v0.0.0-20250811230008-5f3141c8851a // indirect
181+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a // indirect
182182
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
183183
)
184184

router-tests/go.sum

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -416,8 +416,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
416416
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
417417
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
418418
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
419-
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
420-
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
419+
golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 h1:SbTAbRFnd5kjQXbczszQ0hdk3ctwYf3qBNH9jIsGclE=
420+
golang.org/x/exp v0.0.0-20250813145105-42675adae3e6/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
421421
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
422422
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
423423
golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA=
@@ -464,12 +464,12 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
464464
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
465465
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
466466
gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU=
467-
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 h1:GVIKPyP/kLIyVOgOnTwFOrvQaQUzOzGMCxgFUOEmm24=
468-
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw=
469-
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
470-
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
471-
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
472-
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
467+
google.golang.org/genproto/googleapis/api v0.0.0-20250811230008-5f3141c8851a h1:DMCgtIAIQGZqJXMVzJF4MV8BlWoJh2ZuFiRdAleyr58=
468+
google.golang.org/genproto/googleapis/api v0.0.0-20250811230008-5f3141c8851a/go.mod h1:y2yVLIE/CSMCPXaHnSKXxu1spLPnglFLegmgdY23uuE=
469+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a h1:tPE/Kp+x9dMSwUm/uM0JKK0IfdiJkwAbSMSeZBXXJXc=
470+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo=
471+
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
472+
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
473473
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
474474
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
475475
gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=

router-tests/mcp_test.go

Lines changed: 203 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import (
44
"encoding/json"
55
"fmt"
66
"net/http"
7+
"os"
8+
"path/filepath"
79
"strings"
810
"sync"
911
"testing"
@@ -14,6 +16,10 @@ import (
1416
"github.com/wundergraph/cosmo/router-tests/testenv"
1517
"github.com/wundergraph/cosmo/router/core"
1618
"github.com/wundergraph/cosmo/router/pkg/config"
19+
"github.com/wundergraph/cosmo/router/pkg/schemaloader"
20+
"github.com/wundergraph/graphql-go-tools/v2/pkg/astparser"
21+
"github.com/wundergraph/graphql-go-tools/v2/pkg/asttransform"
22+
"go.uber.org/zap"
1723
)
1824

1925
func TestMCP(t *testing.T) {
@@ -126,7 +132,7 @@ func TestMCP(t *testing.T) {
126132
// Verify MyEmployees operation
127133
require.Contains(t, resp.Tools, mcp.Tool{
128134
Name: "execute_operation_my_employees",
129-
Description: "Executes the GraphQL operation 'MyEmployees' of type query. This is a GraphQL query that retrieves a list of employees.",
135+
Description: "This is a GraphQL query that retrieves a list of employees.",
130136
InputSchema: mcp.ToolInputSchema{
131137
Type: "object",
132138
Properties: map[string]interface{}{"criteria": map[string]interface{}{"additionalProperties": false, "description": "Allows to filter employees by their details.", "nullable": false, "properties": map[string]interface{}{"hasPets": map[string]interface{}{"nullable": true, "type": "boolean"}, "nationality": map[string]interface{}{"enum": []interface{}{"AMERICAN", "DUTCH", "ENGLISH", "GERMAN", "INDIAN", "SPANISH", "UKRAINIAN"}, "nullable": true, "type": "string"}, "nested": map[string]interface{}{"additionalProperties": false, "nullable": true, "properties": map[string]interface{}{"hasChildren": map[string]interface{}{"nullable": true, "type": "boolean"}, "maritalStatus": map[string]interface{}{"enum": []interface{}{"ENGAGED", "MARRIED"}, "nullable": true, "type": "string"}}, "type": "object"}}, "type": "object"}},
@@ -143,7 +149,7 @@ func TestMCP(t *testing.T) {
143149
// Verify UpdateMood operation
144150
require.Contains(t, resp.Tools, mcp.Tool{
145151
Name: "execute_operation_update_mood",
146-
Description: "Executes the GraphQL operation 'UpdateMood' of type mutation. This mutation update the mood of an employee.",
152+
Description: "This mutation update the mood of an employee.",
147153
InputSchema: mcp.ToolInputSchema{Type: "object", Properties: map[string]interface{}{"employeeID": map[string]interface{}{"type": "integer"}, "mood": map[string]interface{}{"enum": []interface{}{"HAPPY", "SAD"}, "type": "string"}}, Required: []string{"employeeID", "mood"}}, RawInputSchema: json.RawMessage(nil),
148154
Annotations: mcp.ToolAnnotation{
149155
Title: "Execute operation UpdateMood",
@@ -555,6 +561,201 @@ func TestMCP(t *testing.T) {
555561
})
556562
})
557563

564+
t.Run("Operation Description Extraction", func(t *testing.T) {
565+
// TestMCPOperationDescriptionExtraction tests that the MCP server properly extracts
566+
// descriptions from GraphQL operations and uses them for tool descriptions
567+
t.Run("Extract descriptions from GraphQL operations", func(t *testing.T) {
568+
// Create a temporary directory for test operations
569+
tempDir := t.TempDir()
570+
571+
// Create test operation files
572+
testCases := []struct {
573+
name string
574+
filename string
575+
content string
576+
expectedDesc string
577+
expectDescEmpty bool
578+
}{
579+
{
580+
name: "operation with multi-line description",
581+
filename: "FindUser.graphql",
582+
content: `"""
583+
Finds a user by their unique identifier.
584+
Returns comprehensive user information including profile and settings.
585+
586+
Required permissions: user:read
587+
"""
588+
query FindUser($id: ID!) {
589+
user(id: $id) {
590+
id
591+
name
592+
email
593+
}
594+
}`,
595+
expectedDesc: "Finds a user by their unique identifier.\nReturns comprehensive user information including profile and settings.\n\nRequired permissions: user:read",
596+
},
597+
{
598+
name: "operation with single-line description",
599+
filename: "GetProfile.graphql",
600+
content: `"""Gets the current user's profile"""
601+
query GetProfile {
602+
me {
603+
id
604+
name
605+
}
606+
}`,
607+
expectedDesc: "Gets the current user's profile",
608+
},
609+
{
610+
name: "operation without description",
611+
filename: "ListUsers.graphql",
612+
content: `query ListUsers {
613+
users {
614+
id
615+
name
616+
}
617+
}`,
618+
expectDescEmpty: true,
619+
},
620+
{
621+
name: "mutation with description",
622+
filename: "CreateUser.graphql",
623+
content: `"""
624+
Creates a new user in the system.
625+
Requires admin privileges.
626+
"""
627+
mutation CreateUser($input: UserInput!) {
628+
createUser(input: $input) {
629+
id
630+
name
631+
}
632+
}`,
633+
expectedDesc: "Creates a new user in the system.\nRequires admin privileges.",
634+
},
635+
}
636+
637+
// Write test files
638+
for _, tc := range testCases {
639+
err := os.WriteFile(filepath.Join(tempDir, tc.filename), []byte(tc.content), 0644)
640+
require.NoError(t, err, "Failed to write test file %s", tc.filename)
641+
}
642+
643+
// Create a simple schema for validation
644+
schemaStr := `
645+
type Query {
646+
user(id: ID!): User
647+
users: [User!]!
648+
me: User
649+
}
650+
651+
type Mutation {
652+
createUser(input: UserInput!): User
653+
}
654+
655+
type User {
656+
id: ID!
657+
name: String!
658+
email: String
659+
}
660+
661+
input UserInput {
662+
name: String!
663+
email: String
664+
}
665+
`
666+
schemaDoc, report := astparser.ParseGraphqlDocumentString(schemaStr)
667+
require.False(t, report.HasErrors(), "Failed to parse schema")
668+
669+
// Normalize the schema (required for validation)
670+
err := asttransform.MergeDefinitionWithBaseSchema(&schemaDoc)
671+
require.NoError(t, err, "Failed to normalize schema")
672+
673+
// Load operations using the OperationLoader
674+
logger := zap.NewNop()
675+
loader := schemaloader.NewOperationLoader(logger, &schemaDoc)
676+
operations, err := loader.LoadOperationsFromDirectory(tempDir)
677+
require.NoError(t, err, "Failed to load operations")
678+
require.Len(t, operations, len(testCases), "Expected %d operations to be loaded", len(testCases))
679+
680+
// Verify each operation has the correct description
681+
for _, tc := range testCases {
682+
t.Run(tc.name, func(t *testing.T) {
683+
// Find the operation by name
684+
var op *schemaloader.Operation
685+
for i := range operations {
686+
if operations[i].FilePath == filepath.Join(tempDir, tc.filename) {
687+
op = &operations[i]
688+
break
689+
}
690+
}
691+
require.NotNil(t, op, "Operation not found: %s", tc.filename)
692+
693+
// Verify description
694+
if tc.expectDescEmpty {
695+
assert.Empty(t, op.Description, "Expected empty description for %s", tc.name)
696+
} else {
697+
assert.Equal(t, tc.expectedDesc, op.Description, "Description mismatch for %s", tc.name)
698+
}
699+
})
700+
}
701+
})
702+
})
703+
704+
t.Run("Tool Description Usage", func(t *testing.T) {
705+
// TestMCPToolDescriptionUsage tests that operation descriptions are properly used
706+
// when creating MCP tool descriptions
707+
tests := []struct {
708+
name string
709+
operationDesc string
710+
operationName string
711+
operationType string
712+
expectedToolDesc string
713+
expectDefaultFormat bool
714+
}{
715+
{
716+
name: "uses operation description when present",
717+
operationDesc: "Finds a user by ID and returns their profile",
718+
operationName: "FindUser",
719+
operationType: "query",
720+
expectedToolDesc: "Finds a user by ID and returns their profile",
721+
},
722+
{
723+
name: "uses default format when description is empty",
724+
operationDesc: "",
725+
operationName: "GetUsers",
726+
operationType: "query",
727+
expectDefaultFormat: true,
728+
},
729+
{
730+
name: "uses mutation description",
731+
operationDesc: "Creates a new user with the provided input",
732+
operationName: "CreateUser",
733+
operationType: "mutation",
734+
expectedToolDesc: "Creates a new user with the provided input",
735+
},
736+
}
737+
738+
for _, tt := range tests {
739+
t.Run(tt.name, func(t *testing.T) {
740+
// Simulate what the MCP server does when creating tool descriptions
741+
var toolDescription string
742+
if tt.operationDesc != "" {
743+
toolDescription = tt.operationDesc
744+
} else {
745+
// This is the default format used in server.go
746+
toolDescription = "Executes the GraphQL operation '" + tt.operationName + "' of type " + tt.operationType + "."
747+
}
748+
749+
if tt.expectDefaultFormat {
750+
assert.Contains(t, toolDescription, tt.operationName, "Default description should contain operation name")
751+
assert.Contains(t, toolDescription, tt.operationType, "Default description should contain operation type")
752+
} else {
753+
assert.Equal(t, tt.expectedToolDesc, toolDescription, "Tool description should match operation description")
754+
}
755+
})
756+
}
757+
})
758+
558759
t.Run("Header Forwarding", func(t *testing.T) {
559760
t.Run("All request headers are forwarded from MCP client through to subgraphs", func(t *testing.T) {
560761
// This test validates that ALL headers sent by MCP clients are forwarded

router/go.mod

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ require (
5252
go.withmatt.com/connect-brotli v0.4.0
5353
golang.org/x/sync v0.17.0
5454
golang.org/x/sys v0.37.0 // indirect
55-
google.golang.org/grpc v1.68.1
55+
google.golang.org/grpc v1.71.0
5656
google.golang.org/protobuf v1.36.9
5757
)
5858

@@ -82,7 +82,7 @@ require (
8282
github.com/wundergraph/astjson v0.0.0-20250106123708-be463c97e083
8383
go.uber.org/goleak v1.3.0
8484
go.uber.org/ratelimit v0.3.1
85-
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8
85+
golang.org/x/exp v0.0.0-20250813145105-42675adae3e6
8686
golang.org/x/text v0.30.0
8787
golang.org/x/time v0.9.0
8888
)
@@ -166,8 +166,8 @@ require (
166166
go.uber.org/multierr v1.11.0 // indirect
167167
golang.org/x/crypto v0.43.0 // indirect
168168
golang.org/x/net v0.46.0 // indirect
169-
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 // indirect
170-
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect
169+
google.golang.org/genproto/googleapis/api v0.0.0-20250811230008-5f3141c8851a // indirect
170+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a // indirect
171171
gopkg.in/cenkalti/backoff.v1 v1.1.0 // indirect
172172
gopkg.in/yaml.v3 v3.0.1 // indirect
173173
)

router/go.sum

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -382,8 +382,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
382382
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
383383
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
384384
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
385-
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
386-
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8/go.mod h1:jj3sYF3dwk5D+ghuXyeI3r5MFf+NT2An6/9dOA95KSI=
385+
golang.org/x/exp v0.0.0-20250813145105-42675adae3e6 h1:SbTAbRFnd5kjQXbczszQ0hdk3ctwYf3qBNH9jIsGclE=
386+
golang.org/x/exp v0.0.0-20250813145105-42675adae3e6/go.mod h1:4QTo5u+SEIbbKW1RacMZq1YEfOBqeXa19JeshGi+zc4=
387387
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
388388
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
389389
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
@@ -426,12 +426,12 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
426426
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
427427
gonum.org/v1/gonum v0.14.0 h1:2NiG67LD1tEH0D7kM+ps2V+fXmsAnpUeec7n8tcr4S0=
428428
gonum.org/v1/gonum v0.14.0/go.mod h1:AoWeoz0becf9QMWtE8iWXNXc27fK4fNeHNf/oMejGfU=
429-
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422 h1:GVIKPyP/kLIyVOgOnTwFOrvQaQUzOzGMCxgFUOEmm24=
430-
google.golang.org/genproto/googleapis/api v0.0.0-20250106144421-5f5ef82da422/go.mod h1:b6h1vNKhxaSoEI+5jc3PJUCustfli/mRab7295pY7rw=
431-
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f h1:OxYkA3wjPsZyBylwymxSHa7ViiW1Sml4ToBrncvFehI=
432-
google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f/go.mod h1:+2Yz8+CLJbIfL9z73EW45avw8Lmge3xVElCP9zEKi50=
433-
google.golang.org/grpc v1.68.1 h1:oI5oTa11+ng8r8XMMN7jAOmWfPZWbYpCFaMUTACxkM0=
434-
google.golang.org/grpc v1.68.1/go.mod h1:+q1XYFJjShcqn0QZHvCyeR4CXPA+llXIeUIfIe00waw=
429+
google.golang.org/genproto/googleapis/api v0.0.0-20250811230008-5f3141c8851a h1:DMCgtIAIQGZqJXMVzJF4MV8BlWoJh2ZuFiRdAleyr58=
430+
google.golang.org/genproto/googleapis/api v0.0.0-20250811230008-5f3141c8851a/go.mod h1:y2yVLIE/CSMCPXaHnSKXxu1spLPnglFLegmgdY23uuE=
431+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a h1:tPE/Kp+x9dMSwUm/uM0JKK0IfdiJkwAbSMSeZBXXJXc=
432+
google.golang.org/genproto/googleapis/rpc v0.0.0-20250811230008-5f3141c8851a/go.mod h1:gw1tLEfykwDz2ET4a12jcXt4couGAm7IwsVaTy0Sflo=
433+
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
434+
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
435435
google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw=
436436
google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU=
437437
gopkg.in/cenkalti/backoff.v1 v1.1.0 h1:Arh75ttbsvlpVA7WtVpH4u9h6Zl46xuptxqLxPiSo4Y=

router/pkg/mcpserver/server.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -510,10 +510,10 @@ func (s *GraphQLSchemaServer) registerTools() error {
510510
// Convert the operation name to snake_case for consistent tool naming
511511
operationToolName := strcase.ToSnake(op.Name)
512512

513+
// Use the operation description directly if provided, otherwise generate a default description
513514
var toolDescription string
514-
515515
if op.Description != "" {
516-
toolDescription = fmt.Sprintf("Executes the GraphQL operation '%s' of type %s. %s", op.Name, op.OperationType, op.Description)
516+
toolDescription = op.Description
517517
} else {
518518
toolDescription = fmt.Sprintf("Executes the GraphQL operation '%s' of type %s.", op.Name, op.OperationType)
519519
}

0 commit comments

Comments
 (0)