Skip to content

Commit 0835bd3

Browse files
fix: handle panic in tools (#96)
1 parent eaef368 commit 0835bd3

2 files changed

Lines changed: 38 additions & 5 deletions

File tree

rest/client.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"encoding/hex"
99
"encoding/json"
1010
"fmt"
11-
"github.com/netapp/ontap-mcp/version"
1211
"log/slog"
1312
"net/http"
1413
"net/url"
@@ -19,6 +18,8 @@ import (
1918
"sync"
2019
"time"
2120

21+
"github.com/netapp/ontap-mcp/version"
22+
2223
"github.com/carlmjohnson/requests"
2324
"github.com/netapp/ontap-mcp/config"
2425
"github.com/netapp/ontap-mcp/ontap"
@@ -425,7 +426,9 @@ func (c *Client) GenericGet(ctx context.Context, path string, params url.Values,
425426
}
426427

427428
var page paginatedResponse
428-
_ = json.Unmarshal(buf.Bytes(), &page)
429+
if err := json.Unmarshal(buf.Bytes(), &page); err != nil {
430+
return nil, fmt.Errorf("failed to decode ONTAP response from %s: %w", nextURL, err)
431+
}
429432
if page.Records == nil {
430433
return buf.Bytes(), nil
431434
}

server/server.go

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,12 @@ import (
77
"errors"
88
"fmt"
99
"io"
10-
"log"
1110
"log/slog"
1211
"net/http"
1312
"net/url"
1413
"os"
1514
"reflect"
15+
"runtime/debug"
1616
"slices"
1717
"sort"
1818
"strconv"
@@ -168,7 +168,9 @@ func (a *App) runHTTPServer(server *mcp.Server) {
168168
// Example debugging; you could also capture the response.
169169
body, err := io.ReadAll(req.Body)
170170
if err != nil {
171-
log.Fatal(err)
171+
a.logger.Error("failed to read request body", slog.Any("error", err))
172+
http.Error(w, "failed to read request body", http.StatusBadRequest)
173+
return
172174
}
173175
//goland:noinspection GoUnhandledErrorResult
174176
req.Body.Close() //nolint:gosec
@@ -410,6 +412,13 @@ func (a *App) OntapGet(ctx context.Context, _ *mcp.CallToolRequest, p tool.Ontap
410412
return errorResult(fmt.Errorf("path must start with /, got %q", p.Path)), nil, nil
411413
}
412414

415+
if p.PathParams == nil {
416+
p.PathParams = make(map[string]string)
417+
}
418+
if p.Filters == nil {
419+
p.Filters = make(map[string]string)
420+
}
421+
413422
// Resolve any path-parameter placeholders (e.g. {volume.uuid}) before making the request.
414423
resolvedPath := p.Path
415424
for k, v := range p.PathParams {
@@ -550,7 +559,28 @@ func addTool[In, Out any](a *App, server *mcp.Server, name string, description s
550559
tt.InputSchema = json.RawMessage(`{"type":"object","properties":{}}`)
551560
}
552561

553-
mcp.AddTool(server, tt, handler)
562+
safeHandler := func(ctx context.Context, req *mcp.CallToolRequest, params In) (*mcp.CallToolResult, Out, error) {
563+
var (
564+
res *mcp.CallToolResult
565+
out Out
566+
err error
567+
)
568+
func() {
569+
defer func() {
570+
if rec := recover(); rec != nil {
571+
a.logger.Error("panic in tool handler",
572+
slog.String("tool", name),
573+
slog.Any("panic", rec),
574+
slog.String("stack", string(debug.Stack())))
575+
res = errorResult(fmt.Errorf("internal error in tool %s", name))
576+
}
577+
}()
578+
res, out, err = handler(ctx, req, params)
579+
}()
580+
return res, out, err
581+
}
582+
583+
mcp.AddTool(server, tt, safeHandler)
554584
}
555585

556586
type loggingResponseWriter struct {

0 commit comments

Comments
 (0)