66 "encoding/json"
77 "io"
88 "net/http"
9+ "strings"
910
1011 "github.com/sourcegraph/src-cli/internal/api"
1112
@@ -14,22 +15,33 @@ import (
1415
1516const McpURLPath = ".api/mcp/v1"
1617
18+ type jsonRPCError struct {
19+ Code int `json:"code"`
20+ Message string `json:"message"`
21+ }
22+
1723func FetchToolDefinitions (ctx context.Context , client api.Client ) (map [string ]* ToolDef , error ) {
1824 resp , err := doJSONRPC (ctx , client , "tools/list" , nil )
1925 if err != nil {
2026 return nil , errors .Wrap (err , "failed to list tools from mcp endpoint" )
2127 }
28+ defer resp .Body .Close ()
29+
2230 data , err := readSSEResponseData (resp )
2331 if err != nil {
2432 return nil , errors .Wrap (err , "failed to read list tools SSE response" )
2533 }
2634
2735 var rpcResp struct {
2836 Result json.RawMessage `json:"result"`
37+ Error * jsonRPCError `json:"error"`
2938 }
3039 if err := json .Unmarshal (data , & rpcResp ); err != nil {
3140 return nil , errors .Wrap (err , "failed to unmarshal JSON-RPC response" )
3241 }
42+ if rpcResp .Error != nil {
43+ return nil , errors .Newf ("MCP tools/list failed: %d %s" , rpcResp .Error .Code , rpcResp .Error .Message )
44+ }
3345
3446 return loadToolDefinitions (rpcResp .Result )
3547}
@@ -70,9 +82,21 @@ func doJSONRPC(ctx context.Context, client api.Client, method string, params any
7082 return nil , err
7183 }
7284 req .Header .Add ("Content-Type" , "application/json" )
73- req .Header .Add ("Accept" , "*/* " )
85+ req .Header .Add ("Accept" , "application/json, text/event-stream " )
7486
75- return client .Do (req )
87+ resp , err := client .Do (req )
88+ if err != nil {
89+ return nil , err
90+ }
91+
92+ if resp .StatusCode < 200 || resp .StatusCode >= 300 {
93+ body , _ := io .ReadAll (io .LimitReader (resp .Body , 4096 ))
94+ resp .Body .Close ()
95+ return nil , errors .Newf ("MCP endpoint %s returned %d: %s" ,
96+ McpURLPath , resp .StatusCode , strings .TrimSpace (string (body )))
97+ }
98+
99+ return resp , nil
76100}
77101
78102func DecodeToolResponse (resp * http.Response ) (map [string ]json.RawMessage , error ) {
@@ -86,16 +110,18 @@ func DecodeToolResponse(resp *http.Response) (map[string]json.RawMessage, error)
86110 }
87111
88112 jsonRPCResp := struct {
89- Version string `json:"jsonrpc"`
90- ID int `json:"id"`
91- Result struct {
113+ Result struct {
92114 Content []json.RawMessage `json:"content"`
93115 StructuredContent map [string ]json.RawMessage `json:"structuredContent"`
94116 } `json:"result"`
117+ Error * jsonRPCError `json:"error"`
95118 }{}
96119 if err := json .Unmarshal (data , & jsonRPCResp ); err != nil {
97120 return nil , errors .Wrapf (err , "failed to unmarshal MCP JSON-RPC response" )
98121 }
122+ if jsonRPCResp .Error != nil {
123+ return nil , errors .Newf ("MCP tools/call failed: %d %s" , jsonRPCResp .Error .Code , jsonRPCResp .Error .Message )
124+ }
99125
100126 return jsonRPCResp .Result .StructuredContent , nil
101127}
0 commit comments