From 27107cd75ec52ce00b28868cdb32e9987c792a0d Mon Sep 17 00:00:00 2001 From: Virgil Date: Thu, 2 Apr 2026 07:39:19 +0000 Subject: [PATCH] fix(mcp): enforce REST bridge body limit Co-Authored-By: Virgil --- pkg/mcp/bridge.go | 9 +++++++++ pkg/mcp/bridge_test.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/pkg/mcp/bridge.go b/pkg/mcp/bridge.go index 9f6e8b8..36a6a75 100644 --- a/pkg/mcp/bridge.go +++ b/pkg/mcp/bridge.go @@ -3,6 +3,7 @@ package mcp import ( + "errors" "net/http" core "dappco.re/go/core" @@ -38,8 +39,16 @@ func BridgeToAPI(svc *Service, bridge *api.ToolBridge) { bridge.Add(desc, func(c *gin.Context) { var body []byte if c.Request.Body != nil { + c.Request.Body = http.MaxBytesReader(c.Writer, c.Request.Body, maxBodySize) r := core.ReadAll(c.Request.Body) if !r.OK { + if err, ok := r.Value.(error); ok { + var maxBytesErr *http.MaxBytesError + if errors.As(err, &maxBytesErr) || core.Contains(err.Error(), "request body too large") { + c.JSON(http.StatusRequestEntityTooLarge, api.Fail("request_too_large", "Request body exceeds 10 MB limit")) + return + } + } c.JSON(http.StatusBadRequest, api.Fail("invalid_request", "Failed to read request body")) return } diff --git a/pkg/mcp/bridge_test.go b/pkg/mcp/bridge_test.go index 1db2a07..8f59052 100644 --- a/pkg/mcp/bridge_test.go +++ b/pkg/mcp/bridge_test.go @@ -169,6 +169,41 @@ func TestBridgeToAPI_Bad_InvalidJSON(t *testing.T) { } } +func TestBridgeToAPI_Bad_OversizedBody(t *testing.T) { + svc, err := New(Options{WorkspaceRoot: t.TempDir()}) + if err != nil { + t.Fatal(err) + } + + bridge := api.NewToolBridge("/tools") + BridgeToAPI(svc, bridge) + + engine := gin.New() + rg := engine.Group(bridge.BasePath()) + bridge.RegisterRoutes(rg) + + body := strings.Repeat("a", maxBodySize+1) + w := httptest.NewRecorder() + req, _ := http.NewRequest(http.MethodPost, "/tools/file_read", strings.NewReader(body)) + req.Header.Set("Content-Type", "application/json") + engine.ServeHTTP(w, req) + + if w.Code != http.StatusRequestEntityTooLarge { + t.Fatalf("expected 413 for oversized body, got %d: %s", w.Code, w.Body.String()) + } + + var resp api.Response[any] + if err := json.Unmarshal(w.Body.Bytes(), &resp); err != nil { + t.Fatalf("unmarshal error: %v", err) + } + if resp.Success { + t.Fatal("expected Success=false for oversized body") + } + if resp.Error == nil { + t.Fatal("expected error in response") + } +} + func TestBridgeToAPI_Good_EndToEnd(t *testing.T) { svc, err := New(Options{WorkspaceRoot: t.TempDir()}) if err != nil {