diff --git a/design/design.go b/design/design.go
index 7fb32d206..b690a40e4 100644
--- a/design/design.go
+++ b/design/design.go
@@ -24,5 +24,7 @@ var _ = API("arduino-create-agent", func() {
 	such as detecting which boards are connected and upload sketches on them.`)
 	HTTP(func() {
 		Path("/v2")
+		Consumes("application/json")
+		Consumes("plain/text")
 	})
 })
diff --git a/gen/http/openapi.json b/gen/http/openapi.json
index a315391ad..e6a796113 100644
--- a/gen/http/openapi.json
+++ b/gen/http/openapi.json
@@ -1 +1 @@
-{"swagger":"2.0","info":{"title":"Arduino Create Agent","description":"A companion of Arduino Create. \n\tAllows the website to perform operations on the user computer, \n\tsuch as detecting which boards are connected and upload sketches on them.","version":""},"host":"localhost:80","basePath":"/v2","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/pkgs/indexes":{"get":{"tags":["indexes"],"summary":"list indexes","operationId":"indexes#list","responses":{"200":{"description":"OK response.","schema":{"type":"array","items":{"type":"string","example":"Repudiandae dignissimos consectetur eos molestiae culpa soluta."}}},"400":{"description":"Bad Request response.","schema":{"$ref":"#/definitions/IndexesListInvalidURLResponseBody"}}},"schemes":["http"]}},"/pkgs/indexes/add":{"post":{"tags":["indexes"],"summary":"add indexes","operationId":"indexes#add","parameters":[{"name":"AddRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/IndexesAddRequestBody","required":["url"]}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/IndexesAddResponseBody"}},"400":{"description":"Bad Request response.","schema":{"$ref":"#/definitions/IndexesAddInvalidURLResponseBody"}}},"schemes":["http"]}},"/pkgs/indexes/delete":{"post":{"tags":["indexes"],"summary":"remove indexes","operationId":"indexes#remove","parameters":[{"name":"RemoveRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/IndexesRemoveRequestBody","required":["url"]}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/IndexesRemoveResponseBody"}},"400":{"description":"Bad Request response.","schema":{"$ref":"#/definitions/IndexesRemoveInvalidURLResponseBody"}}},"schemes":["http"]}},"/pkgs/tools/available":{"get":{"tags":["tools"],"summary":"available tools","operationId":"tools#available","responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/ToolsToolResponseCollection"}}},"schemes":["http"]}},"/pkgs/tools/installed":{"get":{"tags":["tools"],"summary":"installed tools","operationId":"tools#installed","responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/ToolsToolResponseCollection"}}},"schemes":["http"]},"post":{"tags":["tools"],"summary":"install tools","operationId":"tools#install","parameters":[{"name":"InstallRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/ToolsInstallRequestBody","required":["name","version","packager"]}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/ToolsInstallResponseBody"}}},"schemes":["http"]}},"/pkgs/tools/installed/{packager}/{name}/{version}":{"delete":{"tags":["tools"],"summary":"remove tools","operationId":"tools#remove","parameters":[{"name":"packager","in":"path","description":"The packager of the tool","required":true,"type":"string"},{"name":"name","in":"path","description":"The name of the tool","required":true,"type":"string"},{"name":"version","in":"path","description":"The version of the tool","required":true,"type":"string"},{"name":"RemoveRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/ToolsRemoveRequestBody"}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/ToolsRemoveResponseBody"}}},"schemes":["http"]}}},"definitions":{"IndexesAddInvalidURLResponseBody":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":true},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":true},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":false}},"description":"url invalid (default view)","example":{"fault":false,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":false,"timeout":false},"required":["name","id","message","temporary","timeout","fault"]},"IndexesAddRequestBody":{"title":"IndexesAddRequestBody","type":"object","properties":{"url":{"type":"string","description":"The url of the index file","example":"https://downloads.arduino.cc/packages/package_index.json"}},"example":{"url":"https://downloads.arduino.cc/packages/package_index.json"},"required":["url"]},"IndexesAddResponseBody":{"title":"Mediatype identifier: application/vnd.arduino.operation; view=default","type":"object","properties":{"status":{"type":"string","description":"The status of the operation","example":"ok"}},"description":"AddResponseBody result type (default view)","example":{"status":"ok"},"required":["status"]},"IndexesListInvalidURLResponseBody":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":true},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":false},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":false}},"description":"url invalid (default view)","example":{"fault":true,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":true,"timeout":true},"required":["name","id","message","temporary","timeout","fault"]},"IndexesRemoveInvalidURLResponseBody":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":false},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":true},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":true}},"description":"url invalid (default view)","example":{"fault":false,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":true,"timeout":false},"required":["name","id","message","temporary","timeout","fault"]},"IndexesRemoveRequestBody":{"title":"IndexesRemoveRequestBody","type":"object","properties":{"url":{"type":"string","description":"The url of the index file","example":"https://downloads.arduino.cc/packages/package_index.json"}},"example":{"url":"https://downloads.arduino.cc/packages/package_index.json"},"required":["url"]},"IndexesRemoveResponseBody":{"title":"Mediatype identifier: application/vnd.arduino.operation; view=default","type":"object","properties":{"status":{"type":"string","description":"The status of the operation","example":"ok"}},"description":"RemoveResponseBody result type (default view)","example":{"status":"ok"},"required":["status"]},"ToolResponse":{"title":"Mediatype identifier: application/vnd.arduino.tool; view=default","type":"object","properties":{"name":{"type":"string","description":"The name of the tool","example":"avrdude"},"packager":{"type":"string","description":"The packager of the tool","example":"arduino"},"version":{"type":"string","description":"The version of the tool","example":"6.3.0-arduino9"}},"description":"A tool is an executable program that can upload sketches. (default view)","example":{"name":"avrdude","packager":"arduino","version":"6.3.0-arduino9"},"required":["name","version","packager"]},"ToolsInstallRequestBody":{"title":"ToolsInstallRequestBody","type":"object","properties":{"checksum":{"type":"string","description":"A checksum of the archive. Mandatory when url is present. \n\tThis ensures that the package is downloaded correcly.","example":"Totam cum inventore exercitationem in."},"name":{"type":"string","description":"The name of the tool","example":"avrdude"},"packager":{"type":"string","description":"The packager of the tool","example":"arduino"},"url":{"type":"string","description":"The url where the package can be found. Optional. \n\tIf present checksum must also be present.","example":"Totam vero ipsum corporis nihil voluptatem id."},"version":{"type":"string","description":"The version of the tool","example":"6.3.0-arduino9"}},"example":{"checksum":"Modi dolorem reprehenderit perspiciatis illo aspernatur.","name":"avrdude","packager":"arduino","url":"Officia optio inventore atque in voluptatibus qui.","version":"6.3.0-arduino9"},"required":["name","version","packager"]},"ToolsInstallResponseBody":{"title":"Mediatype identifier: application/vnd.arduino.operation; view=default","type":"object","properties":{"status":{"type":"string","description":"The status of the operation","example":"ok"}},"description":"InstallResponseBody result type (default view)","example":{"status":"ok"},"required":["status"]},"ToolsRemoveRequestBody":{"title":"ToolsRemoveRequestBody","type":"object","properties":{"checksum":{"type":"string","description":"A checksum of the archive. Mandatory when url is present. \n\tThis ensures that the package is downloaded correcly.","example":"Et qui id et cumque illo."},"url":{"type":"string","description":"The url where the package can be found. Optional. \n\tIf present checksum must also be present.","example":"Officia maiores reiciendis est nemo."}},"example":{"checksum":"Corporis eum et numquam sapiente.","url":"Est voluptatem eos reprehenderit quo sint quod."}},"ToolsRemoveResponseBody":{"title":"Mediatype identifier: application/vnd.arduino.operation; view=default","type":"object","properties":{"status":{"type":"string","description":"The status of the operation","example":"ok"}},"description":"RemoveResponseBody result type (default view)","example":{"status":"ok"},"required":["status"]},"ToolsToolResponseCollection":{"title":"Mediatype identifier: application/vnd.arduino.tool; type=collection; view=default","type":"array","items":{"$ref":"#/definitions/ToolResponse"},"description":"AvailableResponseBody is the result type for an array of ToolResponse (default view)","example":[{"name":"avrdude","packager":"arduino","version":"6.3.0-arduino9"},{"name":"avrdude","packager":"arduino","version":"6.3.0-arduino9"}]}}}
\ No newline at end of file
+{"swagger":"2.0","info":{"title":"Arduino Create Agent","description":"A companion of Arduino Create. \n\tAllows the website to perform operations on the user computer, \n\tsuch as detecting which boards are connected and upload sketches on them.","version":""},"host":"localhost:80","basePath":"/v2","consumes":["application/json","plain/text"],"produces":["application/json","application/xml","application/gob"],"paths":{"/pkgs/indexes":{"get":{"tags":["indexes"],"summary":"list indexes","operationId":"indexes#list","responses":{"200":{"description":"OK response.","schema":{"type":"array","items":{"type":"string","example":"Repudiandae dignissimos consectetur eos molestiae culpa soluta."}}},"400":{"description":"Bad Request response.","schema":{"$ref":"#/definitions/IndexesListInvalidURLResponseBody"}}},"schemes":["http"]}},"/pkgs/indexes/add":{"post":{"tags":["indexes"],"summary":"add indexes","operationId":"indexes#add","parameters":[{"name":"AddRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/IndexesAddRequestBody","required":["url"]}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/IndexesAddResponseBody"}},"400":{"description":"Bad Request response.","schema":{"$ref":"#/definitions/IndexesAddInvalidURLResponseBody"}}},"schemes":["http"]}},"/pkgs/indexes/delete":{"post":{"tags":["indexes"],"summary":"remove indexes","operationId":"indexes#remove","parameters":[{"name":"RemoveRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/IndexesRemoveRequestBody","required":["url"]}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/IndexesRemoveResponseBody"}},"400":{"description":"Bad Request response.","schema":{"$ref":"#/definitions/IndexesRemoveInvalidURLResponseBody"}}},"schemes":["http"]}},"/pkgs/tools/available":{"get":{"tags":["tools"],"summary":"available tools","operationId":"tools#available","responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/ToolsToolResponseCollection"}}},"schemes":["http"]}},"/pkgs/tools/installed":{"get":{"tags":["tools"],"summary":"installed tools","operationId":"tools#installed","responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/ToolsToolResponseCollection"}}},"schemes":["http"]},"post":{"tags":["tools"],"summary":"install tools","operationId":"tools#install","parameters":[{"name":"InstallRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/ToolsInstallRequestBody","required":["name","version","packager"]}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/ToolsInstallResponseBody"}}},"schemes":["http"]}},"/pkgs/tools/installed/{packager}/{name}/{version}":{"delete":{"tags":["tools"],"summary":"remove tools","operationId":"tools#remove","parameters":[{"name":"packager","in":"path","description":"The packager of the tool","required":true,"type":"string"},{"name":"name","in":"path","description":"The name of the tool","required":true,"type":"string"},{"name":"version","in":"path","description":"The version of the tool","required":true,"type":"string"},{"name":"RemoveRequestBody","in":"body","required":true,"schema":{"$ref":"#/definitions/ToolsRemoveRequestBody"}}],"responses":{"200":{"description":"OK response.","schema":{"$ref":"#/definitions/ToolsRemoveResponseBody"}}},"schemes":["http"]}}},"definitions":{"IndexesAddInvalidURLResponseBody":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":true},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":true},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":false}},"description":"url invalid (default view)","example":{"fault":false,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":false,"timeout":false},"required":["name","id","message","temporary","timeout","fault"]},"IndexesAddRequestBody":{"title":"IndexesAddRequestBody","type":"object","properties":{"url":{"type":"string","description":"The url of the index file","example":"https://downloads.arduino.cc/packages/package_index.json"}},"example":{"url":"https://downloads.arduino.cc/packages/package_index.json"},"required":["url"]},"IndexesAddResponseBody":{"title":"Mediatype identifier: application/vnd.arduino.operation; view=default","type":"object","properties":{"status":{"type":"string","description":"The status of the operation","example":"ok"}},"description":"AddResponseBody result type (default view)","example":{"status":"ok"},"required":["status"]},"IndexesListInvalidURLResponseBody":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":true},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":false},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":false}},"description":"url invalid (default view)","example":{"fault":true,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":true,"timeout":true},"required":["name","id","message","temporary","timeout","fault"]},"IndexesRemoveInvalidURLResponseBody":{"title":"Mediatype identifier: application/vnd.goa.error; view=default","type":"object","properties":{"fault":{"type":"boolean","description":"Is the error a server-side fault?","example":false},"id":{"type":"string","description":"ID is a unique identifier for this particular occurrence of the problem.","example":"123abc"},"message":{"type":"string","description":"Message is a human-readable explanation specific to this occurrence of the problem.","example":"parameter 'p' must be an integer"},"name":{"type":"string","description":"Name is the name of this class of errors.","example":"bad_request"},"temporary":{"type":"boolean","description":"Is the error temporary?","example":true},"timeout":{"type":"boolean","description":"Is the error a timeout?","example":true}},"description":"url invalid (default view)","example":{"fault":false,"id":"123abc","message":"parameter 'p' must be an integer","name":"bad_request","temporary":true,"timeout":false},"required":["name","id","message","temporary","timeout","fault"]},"IndexesRemoveRequestBody":{"title":"IndexesRemoveRequestBody","type":"object","properties":{"url":{"type":"string","description":"The url of the index file","example":"https://downloads.arduino.cc/packages/package_index.json"}},"example":{"url":"https://downloads.arduino.cc/packages/package_index.json"},"required":["url"]},"IndexesRemoveResponseBody":{"title":"Mediatype identifier: application/vnd.arduino.operation; view=default","type":"object","properties":{"status":{"type":"string","description":"The status of the operation","example":"ok"}},"description":"RemoveResponseBody result type (default view)","example":{"status":"ok"},"required":["status"]},"ToolResponse":{"title":"Mediatype identifier: application/vnd.arduino.tool; view=default","type":"object","properties":{"name":{"type":"string","description":"The name of the tool","example":"avrdude"},"packager":{"type":"string","description":"The packager of the tool","example":"arduino"},"version":{"type":"string","description":"The version of the tool","example":"6.3.0-arduino9"}},"description":"A tool is an executable program that can upload sketches. (default view)","example":{"name":"avrdude","packager":"arduino","version":"6.3.0-arduino9"},"required":["name","version","packager"]},"ToolsInstallRequestBody":{"title":"ToolsInstallRequestBody","type":"object","properties":{"checksum":{"type":"string","description":"A checksum of the archive. Mandatory when url is present. \n\tThis ensures that the package is downloaded correcly.","example":"Totam cum inventore exercitationem in."},"name":{"type":"string","description":"The name of the tool","example":"avrdude"},"packager":{"type":"string","description":"The packager of the tool","example":"arduino"},"url":{"type":"string","description":"The url where the package can be found. Optional. \n\tIf present checksum must also be present.","example":"Totam vero ipsum corporis nihil voluptatem id."},"version":{"type":"string","description":"The version of the tool","example":"6.3.0-arduino9"}},"example":{"checksum":"Modi dolorem reprehenderit perspiciatis illo aspernatur.","name":"avrdude","packager":"arduino","url":"Officia optio inventore atque in voluptatibus qui.","version":"6.3.0-arduino9"},"required":["name","version","packager"]},"ToolsInstallResponseBody":{"title":"Mediatype identifier: application/vnd.arduino.operation; view=default","type":"object","properties":{"status":{"type":"string","description":"The status of the operation","example":"ok"}},"description":"InstallResponseBody result type (default view)","example":{"status":"ok"},"required":["status"]},"ToolsRemoveRequestBody":{"title":"ToolsRemoveRequestBody","type":"object","properties":{"checksum":{"type":"string","description":"A checksum of the archive. Mandatory when url is present. \n\tThis ensures that the package is downloaded correcly.","example":"Et qui id et cumque illo."},"url":{"type":"string","description":"The url where the package can be found. Optional. \n\tIf present checksum must also be present.","example":"Officia maiores reiciendis est nemo."}},"example":{"checksum":"Corporis eum et numquam sapiente.","url":"Est voluptatem eos reprehenderit quo sint quod."}},"ToolsRemoveResponseBody":{"title":"Mediatype identifier: application/vnd.arduino.operation; view=default","type":"object","properties":{"status":{"type":"string","description":"The status of the operation","example":"ok"}},"description":"RemoveResponseBody result type (default view)","example":{"status":"ok"},"required":["status"]},"ToolsToolResponseCollection":{"title":"Mediatype identifier: application/vnd.arduino.tool; type=collection; view=default","type":"array","items":{"$ref":"#/definitions/ToolResponse"},"description":"AvailableResponseBody is the result type for an array of ToolResponse (default view)","example":[{"name":"avrdude","packager":"arduino","version":"6.3.0-arduino9"},{"name":"avrdude","packager":"arduino","version":"6.3.0-arduino9"}]}}}
\ No newline at end of file
diff --git a/gen/http/openapi.yaml b/gen/http/openapi.yaml
index 30aaaa8d7..4079b44c9 100644
--- a/gen/http/openapi.yaml
+++ b/gen/http/openapi.yaml
@@ -7,8 +7,7 @@ host: localhost:80
 basePath: /v2
 consumes:
     - application/json
-    - application/xml
-    - application/gob
+    - plain/text
 produces:
     - application/json
     - application/xml
diff --git a/main_test.go b/main_test.go
index 0f84ff42a..238ae2a2d 100644
--- a/main_test.go
+++ b/main_test.go
@@ -16,11 +16,20 @@
 package main
 
 import (
+	"bytes"
 	"crypto/x509"
+	"encoding/json"
 	"encoding/pem"
+	"io"
+	"net/http"
+	"net/http/httptest"
 	"path/filepath"
 	"testing"
 
+	"github.com/arduino/arduino-create-agent/config"
+	"github.com/arduino/arduino-create-agent/gen/tools"
+	v2 "github.com/arduino/arduino-create-agent/v2"
+	"github.com/gin-gonic/gin"
 	"github.com/stretchr/testify/require"
 )
 
@@ -38,3 +47,35 @@ func TestValidSignatureKey(t *testing.T) {
 	require.NoError(t, err)
 	require.NotNil(t, key)
 }
+
+func TestInstallToolDifferentContentType(t *testing.T) {
+	r := gin.New()
+	goa := v2.Server(config.GetDataDir().String())
+	r.Any("/v2/*path", gin.WrapH(goa))
+	ts := httptest.NewServer(r)
+
+	URL := "http://downloads.arduino.cc/tools/bossac-1.7.0-arduino3-linux64.tar.gz"
+	Checksum := "SHA-256:1ae54999c1f97234a5c603eb99ad39313b11746a4ca517269a9285afa05f9100"
+	request := tools.ToolPayload{
+		Name:     "bossac",
+		Version:  "1.7.0-arduino3",
+		Packager: "arduino",
+		URL:      &URL,
+		Checksum: &Checksum,
+	}
+
+	payload, err := json.Marshal(request)
+	require.NoError(t, err)
+
+	// for some reason the fronted sends requests with "text/plain" content type.
+	// Even if the request body contains a json object.
+	// With this test we verify is parsed correctly.
+	for _, encoding := range []string{"encoding/json", "text/plain"} {
+		resp, err := http.Post(ts.URL+"/v2/pkgs/tools/installed", encoding, bytes.NewBuffer(payload))
+		require.NoError(t, err)
+		body, err := io.ReadAll(resp.Body)
+		require.NoError(t, err)
+		require.Contains(t, string(body), "ok")
+		require.Equal(t, http.StatusOK, resp.StatusCode)
+	}
+}
diff --git a/v2/http.go b/v2/http.go
index efafbfd7e..3e9c00965 100644
--- a/v2/http.go
+++ b/v2/http.go
@@ -17,6 +17,7 @@ package v2
 
 import (
 	"context"
+	"encoding/json"
 	"net/http"
 	"path/filepath"
 
@@ -56,7 +57,7 @@ func Server(home string) http.Handler {
 		Indexes: &indexesSvc,
 	}
 	toolsEndpoints := toolssvc.NewEndpoints(&toolsSvc)
-	toolsServer := toolssvr.New(toolsEndpoints, mux, goahttp.RequestDecoder, goahttp.ResponseEncoder, errorHandler(logger), nil)
+	toolsServer := toolssvr.New(toolsEndpoints, mux, CustomRequestDecoder, goahttp.ResponseEncoder, errorHandler(logger), nil)
 	toolssvr.Mount(mux, toolsServer)
 
 	// Mount middlewares
@@ -76,3 +77,14 @@ func errorHandler(logger *logrus.Logger) func(context.Context, http.ResponseWrit
 		logger.Printf("[%s] ERROR: %s", id, err.Error())
 	}
 }
+
+// CustomRequestDecoder overrides the RequestDecoder provided by goahttp package
+// It returns always a json.NewDecoder for legacy reasons:
+// The web editor sends always request to the agent setting "Content-Type: text/plain"
+// even when it should set "Content-Type: application/json". This breaks the parsing with:
+// "can't decode text/plain to *server.InstallRequestBody" error message.
+// This was working before the bump to goa v3 only because a "text/plain" decoder was not implemented
+// and it was fallbacking to the json decoder. (https://github.com/goadesign/goa/pull/2310)
+func CustomRequestDecoder(r *http.Request) goahttp.Decoder {
+	return json.NewDecoder(r.Body)
+}