This is an automated email from the ASF dual-hosted git repository.

Aias00 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shenyu.git


The following commit(s) were added to refs/heads/master by this push:
     new 7683f56377 fix(mcp): serialize message responses safely (#7115)
7683f56377 is described below

commit 7683f56377b8bbec732e21fe919d38fd6f244854
Author: Liming Deng <[email protected]>
AuthorDate: Tue Sep 22 07:21:08 2026 +0800

    fix(mcp): serialize message responses safely (#7115)
    
    Co-authored-by: aias00 <[email protected]>
---
 .../shenyu/plugin/mcp/server/McpServerPlugin.java  | 31 ++++++++++++++--------
 .../plugin/mcp/server/McpServerPluginTest.java     | 14 ++++++++++
 2 files changed, 34 insertions(+), 11 deletions(-)

diff --git 
a/shenyu-plugin/shenyu-plugin-mcp-server/src/main/java/org/apache/shenyu/plugin/mcp/server/McpServerPlugin.java
 
b/shenyu-plugin/shenyu-plugin-mcp-server/src/main/java/org/apache/shenyu/plugin/mcp/server/McpServerPlugin.java
index ef62e517b2..0284b633f3 100644
--- 
a/shenyu-plugin/shenyu-plugin-mcp-server/src/main/java/org/apache/shenyu/plugin/mcp/server/McpServerPlugin.java
+++ 
b/shenyu-plugin/shenyu-plugin-mcp-server/src/main/java/org/apache/shenyu/plugin/mcp/server/McpServerPlugin.java
@@ -17,6 +17,8 @@
 
 package org.apache.shenyu.plugin.mcp.server;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.shenyu.common.constant.Constants;
 import org.apache.shenyu.common.dto.RuleData;
 import org.apache.shenyu.common.dto.SelectorData;
@@ -42,14 +44,14 @@ import org.springframework.http.codec.HttpMessageReader;
 import org.springframework.web.reactive.function.server.ServerRequest;
 import org.springframework.web.server.ServerWebExchange;
 import reactor.core.publisher.Mono;
-import com.fasterxml.jackson.databind.ObjectMapper;
 
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
-import java.nio.charset.StandardCharsets;
 
 /**
  * MCP (Model Context Protocol) Server Plugin for Shenyu Gateway.
@@ -65,6 +67,8 @@ public class McpServerPlugin extends AbstractShenyuPlugin {
 
     private static final Logger LOG = 
LoggerFactory.getLogger(McpServerPlugin.class);
 
+    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
     /**
      * Standard message endpoint path.
      */
@@ -613,17 +617,23 @@ public class McpServerPlugin extends AbstractShenyuPlugin 
{
                     exchange.getResponse().getHeaders().add("Content-Type", 
"application/json");
                     setCorsHeaders(exchange);
 
-                    // Create response body
-                    final String responseBody = 
String.format("{\"message\":\"%s\"}", result.getResponseBody());
-                    LOG.debug("Sending message response with length: {} 
chars", responseBody.length());
-
-                    return exchange.getResponse()
-                            
.writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(responseBody.getBytes())));
+                    try {
+                        final byte[] responseBody = 
serializeMessageResponse(result.getResponseBody());
+                        LOG.debug("Sending message response with length: {} 
bytes", responseBody.length);
+                        return exchange.getResponse()
+                                
.writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(responseBody)));
+                    } catch (JsonProcessingException e) {
+                        return Mono.error(e);
+                    }
                 })
                 .doOnSuccess(aVoid -> LOG.debug("Message response completed"))
                 .doOnError(error -> LOG.error("Error in message response: {}", 
error.getMessage(), error));
     }
 
+    private byte[] serializeMessageResponse(final Object message) throws 
JsonProcessingException {
+        return 
OBJECT_MAPPER.writeValueAsBytes(Collections.singletonMap("message", message));
+    }
+
     /**
      * Sets CORS headers for cross-origin requests.
      *
@@ -715,10 +725,9 @@ public class McpServerPlugin extends AbstractShenyuPlugin {
         }
 
         try {
-            final String errorResponse = new ObjectMapper()
-                    .writeValueAsString(errorBody);
+            final byte[] errorResponse = 
OBJECT_MAPPER.writeValueAsBytes(errorBody);
             return exchange.getResponse()
-                    
.writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(errorResponse.getBytes())));
+                    
.writeWith(Mono.just(exchange.getResponse().bufferFactory().wrap(errorResponse)));
         } catch (Exception e) {
             LOG.error("Error writing JSON response: {}", e.getMessage(), e);
             return Mono.empty();
diff --git 
a/shenyu-plugin/shenyu-plugin-mcp-server/src/test/java/org/apache/shenyu/plugin/mcp/server/McpServerPluginTest.java
 
b/shenyu-plugin/shenyu-plugin-mcp-server/src/test/java/org/apache/shenyu/plugin/mcp/server/McpServerPluginTest.java
index 603e3ec008..8e1fb2771e 100644
--- 
a/shenyu-plugin/shenyu-plugin-mcp-server/src/test/java/org/apache/shenyu/plugin/mcp/server/McpServerPluginTest.java
+++ 
b/shenyu-plugin/shenyu-plugin-mcp-server/src/test/java/org/apache/shenyu/plugin/mcp/server/McpServerPluginTest.java
@@ -17,6 +17,8 @@
 
 package org.apache.shenyu.plugin.mcp.server;
 
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.shenyu.common.constant.Constants;
 import org.apache.shenyu.common.dto.RuleData;
 import org.apache.shenyu.common.dto.SelectorData;
@@ -37,12 +39,14 @@ import org.springframework.http.codec.HttpMessageReader;
 import org.springframework.http.server.reactive.ServerHttpRequest;
 import org.springframework.mock.http.server.reactive.MockServerHttpRequest;
 import org.springframework.mock.web.server.MockServerWebExchange;
+import org.springframework.test.util.ReflectionTestUtils;
 import org.springframework.web.reactive.function.server.HandlerStrategies;
 import org.springframework.web.server.ServerWebExchange;
 import reactor.core.publisher.Mono;
 import reactor.test.StepVerifier;
 
 import java.net.URI;
+import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.Locale;
 
@@ -164,6 +168,16 @@ class McpServerPluginTest {
         assertEquals("/test/path", rawPath);
     }
 
+    @Test
+    void testMessageResponseIsEscapedAndUtf8Encoded() throws Exception {
+        final String message = "quoted \"value\" with slash \\ and 中文\nnext";
+
+        final byte[] response = 
ReflectionTestUtils.invokeMethod(mcpServerPlugin, "serializeMessageResponse", 
message);
+        final JsonNode json = new ObjectMapper().readTree(new String(response, 
StandardCharsets.UTF_8));
+
+        assertEquals(message, json.get("message").asText());
+    }
+
     @Test
     void testPreflightWithConfiguredAllowHeaders() {
         final McpServerPlugin plugin = new 
McpServerPlugin(shenyuMcpServerManager,

Reply via email to