Browse Source

feat: mcp sse message no need key (#269)

* feat: mcp sse message no need key

* fix: ci lint
zijiren 6 months ago
parent
commit
5b33964876

+ 1 - 49
core/controller/mcp/embedmcp.go

@@ -6,7 +6,6 @@ import (
 	"fmt"
 	"maps"
 	"net/http"
-	"net/url"
 	"slices"
 	"strings"
 
@@ -357,29 +356,6 @@ func SaveEmbedMCP(c *gin.Context) {
 	middleware.SuccessResponse(c, nil)
 }
 
-type testEmbedMcpEndpointProvider struct {
-	key string
-}
-
-func newTestEmbedMcpEndpoint(key string) EndpointProvider {
-	return &testEmbedMcpEndpointProvider{
-		key: key,
-	}
-}
-
-func (m *testEmbedMcpEndpointProvider) NewEndpoint(session string) (newEndpoint string) {
-	endpoint := fmt.Sprintf("/api/test-embedmcp/message?sessionId=%s&key=%s", session, m.key)
-	return endpoint
-}
-
-func (m *testEmbedMcpEndpointProvider) LoadEndpoint(endpoint string) (session string) {
-	parsedURL, err := url.Parse(endpoint)
-	if err != nil {
-		return ""
-	}
-	return parsedURL.Query().Get("sessionId")
-}
-
 // query like:
 // /api/test-embedmcp/aiproxy-openapi/sse?key=adminkey&config[key1]=value1&config[key2]=value2&reusing[key3]=value3
 func getConfigFromQuery(c *gin.Context) (map[string]string, map[string]string) {
@@ -447,13 +423,11 @@ const (
 )
 
 func handleTestEmbedMCPServer(c *gin.Context, s mcpservers.Server) {
-	token := middleware.GetToken(c)
-
 	// Store the session
 	store := getStore()
 	newSession := store.New()
 
-	newEndpoint := newTestEmbedMcpEndpoint(token.Key).NewEndpoint(newSession)
+	newEndpoint := sseEndpoint.NewEndpoint(newSession)
 	server := mcpproxy.NewSSEServer(
 		s,
 		mcpproxy.WithMessageEndpoint(newEndpoint),
@@ -474,28 +448,6 @@ func handleTestEmbedMCPServer(c *gin.Context, s mcpservers.Server) {
 	server.ServeHTTP(c.Writer, c.Request)
 }
 
-// TestEmbedMCPMessage godoc
-//
-//	@Summary		Test Embed MCP Message
-//	@Description	Send a message to the test embed MCP server
-//	@Tags			embedmcp
-//	@Security		ApiKeyAuth
-//	@Param			sessionId	query	string	true	"Session ID"
-//	@Accept			json
-//	@Produce		json
-//	@Success		200	{object}	nil
-//	@Failure		400	{object}	nil
-//	@Router			/api/test-embedmcp/message [post]
-func TestEmbedMCPMessage(c *gin.Context) {
-	sessionID, _ := c.GetQuery("sessionId")
-	if sessionID == "" {
-		http.Error(c.Writer, "missing sessionId", http.StatusBadRequest)
-		return
-	}
-
-	sendMCPSSEMessage(c, testEmbedMcpType, sessionID)
-}
-
 // TestEmbedMCPStreamable godoc
 //
 //	@Summary		Test Embed MCP Streamable Server

+ 1 - 52
core/controller/mcp/groupmcp-server.go

@@ -1,7 +1,6 @@
 package controller
 
 import (
-	"fmt"
 	"net/http"
 	"net/url"
 
@@ -14,31 +13,6 @@ import (
 	"github.com/mark3labs/mcp-go/mcp"
 )
 
-type groupMcpEndpointProvider struct {
-	key string
-	t   model.GroupMCPType
-}
-
-func newGroupMcpEndpoint(key string, t model.GroupMCPType) EndpointProvider {
-	return &groupMcpEndpointProvider{
-		key: key,
-		t:   t,
-	}
-}
-
-func (m *groupMcpEndpointProvider) NewEndpoint(session string) (newEndpoint string) {
-	endpoint := fmt.Sprintf("/mcp/group/message?sessionId=%s&key=%s&type=%s", session, m.key, m.t)
-	return endpoint
-}
-
-func (m *groupMcpEndpointProvider) LoadEndpoint(endpoint string) (session string) {
-	parsedURL, err := url.Parse(endpoint)
-	if err != nil {
-		return ""
-	}
-	return parsedURL.Query().Get("sessionId")
-}
-
 // GroupMCPSSEServer godoc
 //
 //	@Summary	Group MCP SSE Server
@@ -63,10 +37,7 @@ func GroupMCPSSEServer(c *gin.Context) {
 		return
 	}
 
-	token := middleware.GetToken(c)
-	endpoint := newGroupMcpEndpoint(token.Key, groupMcp.Type)
-
-	handleGroupSSEMCPServer(c, groupMcp, endpoint)
+	handleGroupSSEMCPServer(c, groupMcp, sseEndpoint)
 }
 
 func handleGroupSSEMCPServer(
@@ -128,28 +99,6 @@ func handleGroupSSEMCPServer(
 	}
 }
 
-// GroupMCPMessage godoc
-//
-//	@Summary	MCP SSE Proxy
-//	@Security	ApiKeyAuth
-//	@Router		/mcp/group/message [post]
-func GroupMCPMessage(c *gin.Context) {
-	mcpTypeStr, _ := c.GetQuery("type")
-	if mcpTypeStr == "" {
-		http.Error(c.Writer, "missing mcp type", http.StatusBadRequest)
-		return
-	}
-	mcpType := model.GroupMCPType(mcpTypeStr)
-
-	sessionID, _ := c.GetQuery("sessionId")
-	if sessionID == "" {
-		http.Error(c.Writer, "missing sessionId", http.StatusBadRequest)
-		return
-	}
-
-	handleGroupSSEMessage(c, mcpType, sessionID)
-}
-
 // GroupMCPStreamable godoc
 //
 //	@Summary	Group MCP Streamable Server

+ 2 - 74
core/controller/mcp/host.go

@@ -1,9 +1,7 @@
 package controller
 
 import (
-	"fmt"
 	"net/http"
-	"net/url"
 	"strings"
 
 	"github.com/gin-gonic/gin"
@@ -15,32 +13,6 @@ import (
 	"github.com/mark3labs/mcp-go/mcp"
 )
 
-// hostMcpEndpointProvider implements the EndpointProvider interface for MCP
-type hostMcpEndpointProvider struct {
-	key string
-	t   string
-}
-
-func newHostMcpEndpoint(key, t string) EndpointProvider {
-	return &hostMcpEndpointProvider{
-		key: key,
-		t:   t,
-	}
-}
-
-func (m *hostMcpEndpointProvider) NewEndpoint(session string) (newEndpoint string) {
-	endpoint := fmt.Sprintf("/message?sessionId=%s&key=%s&type=%s", session, m.key, m.t)
-	return endpoint
-}
-
-func (m *hostMcpEndpointProvider) LoadEndpoint(endpoint string) (session string) {
-	parsedURL, err := url.Parse(endpoint)
-	if err != nil {
-		return ""
-	}
-	return parsedURL.Query().Get("sessionId")
-}
-
 func routeHostMCP(
 	c *gin.Context,
 	publicHandler, groupHandler func(c *gin.Context, mcpID string),
@@ -82,10 +54,7 @@ func HostMCPSSEServer(c *gin.Context) {
 			return
 		}
 
-		token := middleware.GetToken(c)
-		endpoint := newHostMcpEndpoint(token.Key, string(publicMcp.Type))
-
-		handlePublicSSEMCP(c, publicMcp, endpoint)
+		handlePublicSSEMCP(c, publicMcp, sseEndpoint)
 	}, func(c *gin.Context, mcpID string) {
 		group := middleware.GetGroup(c)
 
@@ -99,48 +68,7 @@ func HostMCPSSEServer(c *gin.Context) {
 			return
 		}
 
-		token := middleware.GetToken(c)
-		endpoint := newHostMcpEndpoint(token.Key, string(groupMcp.Type))
-
-		handleGroupSSEMCPServer(c, groupMcp, endpoint)
-	})
-}
-
-// HostMCPMessage godoc
-//
-//	@Summary	Public MCP SSE Server
-//	@Security	ApiKeyAuth
-//	@Router		/message [post]
-func HostMCPMessage(c *gin.Context) {
-	routeHostMCP(c, func(c *gin.Context, _ string) {
-		mcpTypeStr, _ := c.GetQuery("type")
-		if mcpTypeStr == "" {
-			http.Error(c.Writer, "missing mcp type", http.StatusBadRequest)
-			return
-		}
-		mcpType := model.PublicMCPType(mcpTypeStr)
-		sessionID, _ := c.GetQuery("sessionId")
-		if sessionID == "" {
-			http.Error(c.Writer, "missing sessionId", http.StatusBadRequest)
-			return
-		}
-
-		handlePublicSSEMessage(c, mcpType, sessionID)
-	}, func(c *gin.Context, _ string) {
-		mcpTypeStr, _ := c.GetQuery("type")
-		if mcpTypeStr == "" {
-			http.Error(c.Writer, "missing mcp type", http.StatusBadRequest)
-			return
-		}
-		mcpType := model.GroupMCPType(mcpTypeStr)
-
-		sessionID, _ := c.GetQuery("sessionId")
-		if sessionID == "" {
-			http.Error(c.Writer, "missing sessionId", http.StatusBadRequest)
-			return
-		}
-
-		handleGroupSSEMessage(c, mcpType, sessionID)
+		handleGroupSSEMCPServer(c, groupMcp, sseEndpoint)
 	})
 }
 

+ 34 - 16
core/controller/mcp/mcp.go

@@ -113,9 +113,9 @@ func prepareEmbedReusingConfig(
 	return processor.ProcessEmbedReusingParams(reusingParams)
 }
 
-func sendMCPSSEMessage(c *gin.Context, mcpType, sessionID string) {
-	backend, ok := getStore().Get(sessionID)
-	if !ok || backend != mcpType {
+func sendMCPSSEMessage(c *gin.Context, sessionID string) {
+	_, ok := getStore().Get(sessionID)
+	if !ok {
 		http.Error(c.Writer, "invalid session", http.StatusBadRequest)
 		return
 	}
@@ -161,19 +161,6 @@ func handleStreamableMCPServer(c *gin.Context, s mcpservers.Server) {
 	c.JSON(http.StatusOK, respMessage)
 }
 
-func handleGroupSSEMessage(c *gin.Context, mcpType model.GroupMCPType, sessionID string) {
-	switch mcpType {
-	case model.GroupMCPTypeProxySSE:
-		sendMCPSSEMessage(c, string(mcpType), sessionID)
-	case model.GroupMCPTypeProxyStreamable:
-		sendMCPSSEMessage(c, string(mcpType), sessionID)
-	case model.GroupMCPTypeOpenAPI:
-		sendMCPSSEMessage(c, string(mcpType), sessionID)
-	default:
-		http.Error(c.Writer, "unknown mcp type", http.StatusBadRequest)
-	}
-}
-
 func handleGroupStreamable(c *gin.Context, groupMcp *model.GroupMCPCache) {
 	switch groupMcp.Type {
 	case model.GroupMCPTypeProxyStreamable:
@@ -257,3 +244,34 @@ func parseOpenAPIFromContent(config *model.MCPOpenAPIConfig, parser *convert.Par
 	}
 	return parser.Parse([]byte(config.OpenAPIContent))
 }
+
+// sseEndpointProvider implements the EndpointProvider interface for MCP
+type sseEndpointProvider struct{}
+
+var sseEndpoint = &sseEndpointProvider{}
+
+func (m *sseEndpointProvider) NewEndpoint(session string) (newEndpoint string) {
+	endpoint := "/message?sessionId=" + session
+	return endpoint
+}
+
+func (m *sseEndpointProvider) LoadEndpoint(endpoint string) (session string) {
+	parsedURL, err := url.Parse(endpoint)
+	if err != nil {
+		return ""
+	}
+	return parsedURL.Query().Get("sessionId")
+}
+
+// MCPMessage godoc
+//
+//	@Summary	MCP SSE Message
+//	@Router		/message [post]
+func MCPMessage(c *gin.Context) {
+	sessionID, _ := c.GetQuery("sessionId")
+	if sessionID == "" {
+		http.Error(c.Writer, "missing sessionId", http.StatusBadRequest)
+		return
+	}
+	sendMCPSSEMessage(c, sessionID)
+}

+ 1 - 66
core/controller/mcp/publicmcp-server.go

@@ -14,32 +14,6 @@ import (
 	"github.com/mark3labs/mcp-go/mcp"
 )
 
-// publicMcpEndpointProvider implements the EndpointProvider interface for MCP
-type publicMcpEndpointProvider struct {
-	key string
-	t   model.PublicMCPType
-}
-
-func newPublicMcpEndpoint(key string, t model.PublicMCPType) EndpointProvider {
-	return &publicMcpEndpointProvider{
-		key: key,
-		t:   t,
-	}
-}
-
-func (m *publicMcpEndpointProvider) NewEndpoint(session string) (newEndpoint string) {
-	endpoint := fmt.Sprintf("/mcp/public/message?sessionId=%s&key=%s&type=%s", session, m.key, m.t)
-	return endpoint
-}
-
-func (m *publicMcpEndpointProvider) LoadEndpoint(endpoint string) (session string) {
-	parsedURL, err := url.Parse(endpoint)
-	if err != nil {
-		return ""
-	}
-	return parsedURL.Query().Get("sessionId")
-}
-
 // PublicMCPSSEServer godoc
 //
 //	@Summary	Public MCP SSE Server
@@ -62,10 +36,7 @@ func PublicMCPSSEServer(c *gin.Context) {
 		return
 	}
 
-	token := middleware.GetToken(c)
-	endpoint := newPublicMcpEndpoint(token.Key, publicMcp.Type)
-
-	handlePublicSSEMCP(c, publicMcp, endpoint)
+	handlePublicSSEMCP(c, publicMcp, sseEndpoint)
 }
 
 func handlePublicSSEMCP(
@@ -259,42 +230,6 @@ func processProxyReusingParams(
 	return nil
 }
 
-// PublicMCPMessage godoc
-//
-//	@Summary	Public MCP SSE Server
-//	@Security	ApiKeyAuth
-//	@Router		/mcp/public/message [post]
-func PublicMCPMessage(c *gin.Context) {
-	mcpTypeStr, _ := c.GetQuery("type")
-	if mcpTypeStr == "" {
-		http.Error(c.Writer, "missing mcp type", http.StatusBadRequest)
-		return
-	}
-	mcpType := model.PublicMCPType(mcpTypeStr)
-	sessionID, _ := c.GetQuery("sessionId")
-	if sessionID == "" {
-		http.Error(c.Writer, "missing sessionId", http.StatusBadRequest)
-		return
-	}
-
-	handlePublicSSEMessage(c, mcpType, sessionID)
-}
-
-func handlePublicSSEMessage(c *gin.Context, mcpType model.PublicMCPType, sessionID string) {
-	switch mcpType {
-	case model.PublicMCPTypeProxySSE:
-		sendMCPSSEMessage(c, string(mcpType), sessionID)
-	case model.PublicMCPTypeProxyStreamable:
-		sendMCPSSEMessage(c, string(mcpType), sessionID)
-	case model.PublicMCPTypeOpenAPI:
-		sendMCPSSEMessage(c, string(mcpType), sessionID)
-	case model.PublicMCPTypeEmbed:
-		sendMCPSSEMessage(c, string(mcpType), sessionID)
-	default:
-		http.Error(c.Writer, "unknown mcp type", http.StatusBadRequest)
-	}
-}
-
 // PublicMCPStreamable godoc
 //
 //	@Summary	Public MCP Streamable Server

+ 7 - 65
core/docs/docs.go

@@ -5531,43 +5531,6 @@ const docTemplate = `{
                 }
             }
         },
-        "/api/test-embedmcp/message": {
-            "post": {
-                "security": [
-                    {
-                        "ApiKeyAuth": []
-                    }
-                ],
-                "description": "Send a message to the test embed MCP server",
-                "consumes": [
-                    "application/json"
-                ],
-                "produces": [
-                    "application/json"
-                ],
-                "tags": [
-                    "embedmcp"
-                ],
-                "summary": "Test Embed MCP Message",
-                "parameters": [
-                    {
-                        "type": "string",
-                        "description": "Session ID",
-                        "name": "sessionId",
-                        "in": "query",
-                        "required": true
-                    }
-                ],
-                "responses": {
-                    "200": {
-                        "description": "OK"
-                    },
-                    "400": {
-                        "description": "Bad Request"
-                    }
-                }
-            }
-        },
         "/api/test-embedmcp/{id}": {
             "get": {
                 "security": [
@@ -6818,17 +6781,6 @@ const docTemplate = `{
                 "responses": {}
             }
         },
-        "/mcp/group/message": {
-            "post": {
-                "security": [
-                    {
-                        "ApiKeyAuth": []
-                    }
-                ],
-                "summary": "MCP SSE Proxy",
-                "responses": {}
-            }
-        },
         "/mcp/group/{id}": {
             "get": {
                 "security": [
@@ -6869,17 +6821,6 @@ const docTemplate = `{
                 "responses": {}
             }
         },
-        "/mcp/public/message": {
-            "post": {
-                "security": [
-                    {
-                        "ApiKeyAuth": []
-                    }
-                ],
-                "summary": "Public MCP SSE Server",
-                "responses": {}
-            }
-        },
         "/mcp/public/{id}": {
             "get": {
                 "security": [
@@ -6922,12 +6863,7 @@ const docTemplate = `{
         },
         "/message": {
             "post": {
-                "security": [
-                    {
-                        "ApiKeyAuth": []
-                    }
-                ],
-                "summary": "Public MCP SSE Server",
+                "summary": "MCP SSE Message",
                 "responses": {}
             }
         },
@@ -8411,6 +8347,9 @@ const docTemplate = `{
                 "github_url": {
                     "type": "string"
                 },
+                "hosted": {
+                    "type": "boolean"
+                },
                 "id": {
                     "type": "string"
                 },
@@ -8500,6 +8439,9 @@ const docTemplate = `{
                 "github_url": {
                     "type": "string"
                 },
+                "hosted": {
+                    "type": "boolean"
+                },
                 "id": {
                     "type": "string"
                 },

+ 7 - 65
core/docs/swagger.json

@@ -5522,43 +5522,6 @@
                 }
             }
         },
-        "/api/test-embedmcp/message": {
-            "post": {
-                "security": [
-                    {
-                        "ApiKeyAuth": []
-                    }
-                ],
-                "description": "Send a message to the test embed MCP server",
-                "consumes": [
-                    "application/json"
-                ],
-                "produces": [
-                    "application/json"
-                ],
-                "tags": [
-                    "embedmcp"
-                ],
-                "summary": "Test Embed MCP Message",
-                "parameters": [
-                    {
-                        "type": "string",
-                        "description": "Session ID",
-                        "name": "sessionId",
-                        "in": "query",
-                        "required": true
-                    }
-                ],
-                "responses": {
-                    "200": {
-                        "description": "OK"
-                    },
-                    "400": {
-                        "description": "Bad Request"
-                    }
-                }
-            }
-        },
         "/api/test-embedmcp/{id}": {
             "get": {
                 "security": [
@@ -6809,17 +6772,6 @@
                 "responses": {}
             }
         },
-        "/mcp/group/message": {
-            "post": {
-                "security": [
-                    {
-                        "ApiKeyAuth": []
-                    }
-                ],
-                "summary": "MCP SSE Proxy",
-                "responses": {}
-            }
-        },
         "/mcp/group/{id}": {
             "get": {
                 "security": [
@@ -6860,17 +6812,6 @@
                 "responses": {}
             }
         },
-        "/mcp/public/message": {
-            "post": {
-                "security": [
-                    {
-                        "ApiKeyAuth": []
-                    }
-                ],
-                "summary": "Public MCP SSE Server",
-                "responses": {}
-            }
-        },
         "/mcp/public/{id}": {
             "get": {
                 "security": [
@@ -6913,12 +6854,7 @@
         },
         "/message": {
             "post": {
-                "security": [
-                    {
-                        "ApiKeyAuth": []
-                    }
-                ],
-                "summary": "Public MCP SSE Server",
+                "summary": "MCP SSE Message",
                 "responses": {}
             }
         },
@@ -8402,6 +8338,9 @@
                 "github_url": {
                     "type": "string"
                 },
+                "hosted": {
+                    "type": "boolean"
+                },
                 "id": {
                     "type": "string"
                 },
@@ -8491,6 +8430,9 @@
                 "github_url": {
                     "type": "string"
                 },
+                "hosted": {
+                    "type": "boolean"
+                },
                 "id": {
                     "type": "string"
                 },

+ 5 - 38
core/docs/swagger.yaml

@@ -250,6 +250,8 @@ definitions:
         $ref: '#/definitions/controller.MCPEndpoint'
       github_url:
         type: string
+      hosted:
+        type: boolean
       id:
         type: string
       logo_url:
@@ -309,6 +311,8 @@ definitions:
         $ref: '#/definitions/model.MCPEmbeddingConfig'
       github_url:
         type: string
+      hosted:
+        type: boolean
       id:
         type: string
       logo_url:
@@ -5591,29 +5595,6 @@ paths:
       summary: Test Embed MCP SSE Server
       tags:
       - embedmcp
-  /api/test-embedmcp/message:
-    post:
-      consumes:
-      - application/json
-      description: Send a message to the test embed MCP server
-      parameters:
-      - description: Session ID
-        in: query
-        name: sessionId
-        required: true
-        type: string
-      produces:
-      - application/json
-      responses:
-        "200":
-          description: OK
-        "400":
-          description: Bad Request
-      security:
-      - ApiKeyAuth: []
-      summary: Test Embed MCP Message
-      tags:
-      - embedmcp
   /api/token/{group}:
     post:
       consumes:
@@ -6284,12 +6265,6 @@ paths:
       security:
       - ApiKeyAuth: []
       summary: Group MCP SSE Server
-  /mcp/group/message:
-    post:
-      responses: {}
-      security:
-      - ApiKeyAuth: []
-      summary: MCP SSE Proxy
   /mcp/public/{id}:
     delete:
       responses: {}
@@ -6312,18 +6287,10 @@ paths:
       security:
       - ApiKeyAuth: []
       summary: Public MCP SSE Server
-  /mcp/public/message:
-    post:
-      responses: {}
-      security:
-      - ApiKeyAuth: []
-      summary: Public MCP SSE Server
   /message:
     post:
       responses: {}
-      security:
-      - ApiKeyAuth: []
-      summary: Public MCP SSE Server
+      summary: MCP SSE Message
   /sse:
     get:
       responses: {}

+ 0 - 1
core/router/api.go

@@ -222,7 +222,6 @@ func SetAPIRouter(router *gin.Engine) {
 		testEmbedMcpRoute := apiRouter.Group("/test-embedmcp")
 		{
 			testEmbedMcpRoute.GET("/:id/sse", mcp.TestEmbedMCPSseServer)
-			testEmbedMcpRoute.POST("/message", mcp.TestEmbedMCPMessage)
 			testEmbedMcpRoute.GET("/:id", mcp.TestEmbedMCPStreamable)
 			testEmbedMcpRoute.POST("/:id", mcp.TestEmbedMCPStreamable)
 			testEmbedMcpRoute.DELETE("/:id", mcp.TestEmbedMCPStreamable)

+ 1 - 3
core/router/mcp.go

@@ -10,19 +10,17 @@ func SetMCPRouter(router *gin.Engine) {
 	mcpRoute := router.Group("/mcp", middleware.MCPAuth)
 
 	mcpRoute.GET("/public/:id/sse", mcp.PublicMCPSSEServer)
-	mcpRoute.POST("/public/message", mcp.PublicMCPMessage)
 	mcpRoute.GET("/public/:id", mcp.PublicMCPStreamable)
 	mcpRoute.POST("/public/:id", mcp.PublicMCPStreamable)
 	mcpRoute.DELETE("/public/:id", mcp.PublicMCPStreamable)
 
 	mcpRoute.GET("/group/:id/sse", mcp.GroupMCPSSEServer)
-	mcpRoute.POST("/group/message", mcp.GroupMCPMessage)
 	mcpRoute.GET("/group/:id", mcp.GroupMCPStreamable)
 	mcpRoute.POST("/group/:id", mcp.GroupMCPStreamable)
 	mcpRoute.DELETE("/group/:id", mcp.GroupMCPStreamable)
 
 	router.GET("/sse", middleware.MCPAuth, mcp.HostMCPSSEServer)
-	router.GET("/message", middleware.MCPAuth, mcp.HostMCPMessage)
+	router.POST("/message", mcp.MCPMessage)
 	router.GET("/mcp", middleware.MCPAuth, mcp.HostMCPStreamable)
 	router.POST("/mcp", middleware.MCPAuth, mcp.HostMCPStreamable)
 	router.DELETE("/mcp", middleware.MCPAuth, mcp.HostMCPStreamable)