Преглед на файлове

master恢复到mvc模式

andyliu преди 1 месец
родител
ревизия
19389f7df3

+ 1 - 1
pom.xml

@@ -56,7 +56,7 @@
     <dependencies>
         <dependency>
             <groupId>org.springframework.ai</groupId>
-            <artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
+            <artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
             <exclusions>
                 <exclusion>
                     <groupId>org.springframework.boot</groupId>

+ 1 - 1
src/main/java/com/shkpr/service/mcpcenterservice/KprMcpCenterServiceApplication.java

@@ -24,7 +24,7 @@ public class KprMcpCenterServiceApplication {
                 .build();
     }
     /**
-     * 1) 现在cmd终点调用:curl -N -i -X GET -H "Authorization: xxx" "http://127.0.0.1:9100/kpr-mcp-center/sse"
+     * 1) 现在cmd终点调用:curl -N -i -X GET "http://127.0.0.1:9100/kpr-mcp-center/sse"
      *    以获取sessionId并保持连接
      * 2) 以post方法调用:http://127.0.0.1:9100/kpr-mcp-center/sse/message?sessionId=xxx
      *    ```

+ 0 - 38
src/main/java/com/shkpr/service/mcpcenterservice/commtools/HttpUtils.java

@@ -1,38 +0,0 @@
-package com.shkpr.service.mcpcenterservice.commtools;
-
-import com.shkpr.service.mcpcenterservice.constants.ApiURI;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.util.StringUtils;
-
-import java.net.InetSocketAddress;
-
-public class HttpUtils {
-    public static String getIpAddress(ServerHttpRequest request) {
-        String fromSource = ApiURI.HEADER_X_SOURCE_IP;
-        String ip = request.getHeaders().getFirst(fromSource);
-        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)){
-            fromSource = "X-Real-IP";
-            ip = request.getHeaders().getFirst(fromSource);
-        }
-        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
-            fromSource = "X-Forwarded-For";
-            ip = request.getHeaders().getFirst(fromSource);
-        }
-        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
-            fromSource = "Proxy-Client-IP";
-            ip = request.getHeaders().getFirst(fromSource);
-        }
-        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
-            fromSource = "WL-Proxy-Client-IP";
-            ip = request.getHeaders().getFirst(fromSource);
-        }
-        if (StringUtils.isEmpty(ip) || "unknown".equalsIgnoreCase(ip)) {
-            fromSource = "request.getRemoteAddr";
-            InetSocketAddress addr = request.getRemoteAddress();
-            ip = addr != null ? addr.getAddress().getHostAddress() : "unknown";
-        }
-        if (!StringUtils.isEmpty(ip) && ip.contains(","))
-            return ip.split(",")[0];
-        return ip;
-    }
-}

+ 1 - 1
src/main/java/com/shkpr/service/mcpcenterservice/commtools/JwtTokenUtils.java

@@ -5,7 +5,7 @@ import io.jsonwebtoken.Claims;
 import io.jsonwebtoken.ExpiredJwtException;
 import io.jsonwebtoken.Jwts;
 
-public class JwtTokenUtils {
+public class JwtTokenUtil {
     public static final String SECRET = "TRICP_ALAM_DMA";                              // JWT密码
     public static final String CLAIM_FLAGKEY = "flagkey";
     public static final String CLAIM_ACCOUNT = "account";

+ 21 - 23
src/main/java/com/shkpr/service/mcpcenterservice/configuration/McpSecurityConfig.java

@@ -5,17 +5,17 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.http.HttpStatus;
-import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
-import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
-import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
-import org.springframework.security.config.web.server.ServerHttpSecurity;
-import org.springframework.security.web.server.SecurityWebFilterChain;
-import org.springframework.security.web.server.authentication.HttpStatusServerEntryPoint;
-import org.springframework.security.web.server.context.NoOpServerSecurityContextRepository;
+import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.web.SecurityFilterChain;
+import org.springframework.security.web.authentication.HttpStatusEntryPoint;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
 
 @Configuration
-@EnableWebFluxSecurity
-@EnableReactiveMethodSecurity
+@EnableWebSecurity
+@EnableMethodSecurity(prePostEnabled = true)
 public class McpSecurityConfig {
     @Value("${spring.ai.mcp.server.sseEndpoint:/kpr-mcp-center/sse}")
     private String mcpSSEPath;
@@ -24,20 +24,18 @@ public class McpSecurityConfig {
     private String mcpSSEMsgPath;
 
     @Bean
-    public SecurityWebFilterChain filterChain(ServerHttpSecurity http) {
-        http.csrf(csrf -> csrf.disable())
-            .httpBasic(basic -> basic.disable())
-            .formLogin(form -> form.disable())
-            .securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
-            .authorizeExchange(auth -> auth
-                    .pathMatchers("/").permitAll()
-                    .pathMatchers("/actuator/health").permitAll()
-                    .pathMatchers(mcpSSEPath, mcpSSEMsgPath).authenticated()
-                    .anyExchange().authenticated()
-            )
-            .exceptionHandling(eh -> eh.authenticationEntryPoint(
-                    new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED)))
-            .addFilterAt(new JwtAuthenticationFilter(), SecurityWebFiltersOrder.AUTHENTICATION);
+    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
+        http
+                .csrf(csrf -> csrf.disable())
+                .sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
+                .authorizeHttpRequests(auth -> auth
+                        .requestMatchers("/").permitAll()
+                        .requestMatchers("/actuator/health").permitAll()
+                        .requestMatchers(mcpSSEPath, mcpSSEMsgPath).authenticated()
+                        .anyRequest().authenticated()
+                )
+                .exceptionHandling(eh -> eh.authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED)))
+                .addFilterBefore(new JwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
 
         return http.build();
     }

+ 6 - 1
src/main/java/com/shkpr/service/mcpcenterservice/constants/ApiURI.java

@@ -1,5 +1,11 @@
 package com.shkpr.service.mcpcenterservice.constants;
 
+/**
+ * 认证相关全局常量。
+ * <p>
+ * 包括 HTTP Header 名、JWT claim 字段名、认证错误码等。
+ * 错误码与 {@code ResponseRes} 统一格式中的 {@code rescode} 对齐。
+ */
 public final class ApiURI {
 
     private ApiURI() {
@@ -9,7 +15,6 @@ public final class ApiURI {
     public static final String HEADER_AUTHORIZATION = "Authorization";
     public static final String BEARER_PREFIX = "Bearer ";
     public static final String QUERY_TOKEN_PARAM = "access_token";
-    public static final String HEADER_X_SOURCE_IP = "X-Source-IP";
 
 
     public static final String ROLE_AUTHORITY_PREFIX = "ROLE_";

+ 82 - 60
src/main/java/com/shkpr/service/mcpcenterservice/filters/JwtAuthenticationFilter.java

@@ -3,35 +3,33 @@ package com.shkpr.service.mcpcenterservice.filters;
 import com.global.base.log.LogLevelFlag;
 import com.global.base.log.LogPrintMgr;
 import com.global.base.tools.FastJsonUtil;
-import com.shkpr.service.mcpcenterservice.commtools.HttpUtils;
-import com.shkpr.service.mcpcenterservice.commtools.JwtTokenUtils;
+import com.shkpr.service.mcpcenterservice.commtools.JwtTokenUtil;
 import com.shkpr.service.mcpcenterservice.constants.ApiURI;
 import com.shkpr.service.mcpcenterservice.dto.LogFlagBizType;
 import com.shkpr.service.mcpcenterservice.dto.McpAuthUser;
 import com.shkpr.service.mcpcenterservice.dto.ResponseCode;
 import com.shkpr.service.mcpcenterservice.dto.ResponseRes;
+import com.shkpr.service.mcpcenterservice.globalmgr.McpAuthContextMgr;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
 import org.apache.commons.lang3.StringUtils;
-import org.springframework.core.io.buffer.DataBuffer;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.MediaType;
-import org.springframework.http.server.reactive.ServerHttpRequest;
-import org.springframework.http.server.reactive.ServerHttpResponse;
 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
 import org.springframework.security.core.authority.SimpleGrantedAuthority;
-import org.springframework.security.core.context.ReactiveSecurityContextHolder;
-import org.springframework.web.server.ServerWebExchange;
-import org.springframework.web.server.WebFilter;
-import org.springframework.web.server.WebFilterChain;
-import reactor.core.publisher.Mono;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.web.filter.OncePerRequestFilter;
 
-import java.nio.charset.StandardCharsets;
+import java.io.IOException;
 import java.util.List;
 
-public class JwtAuthenticationFilter implements WebFilter {
-    private final String mStrClassName;
-    private final String mBusinessType;
-    private final String logTag;
-
+public class JwtAuthenticationFilter extends OncePerRequestFilter {
+    private String mStrClassName = "";
+    private String mBusinessType = "";
+    private String logTag = "";
     public JwtAuthenticationFilter() {
         mStrClassName = this.getClass().getSimpleName();
         mBusinessType = LogFlagBizType.BIZ_AUTH.toStrValue();
@@ -39,75 +37,99 @@ public class JwtAuthenticationFilter implements WebFilter {
     }
 
     @Override
-    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
-        ServerHttpRequest request = exchange.getRequest();
-        ServerHttpResponse response = exchange.getResponse();
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
         String token = extractToken(request);
-
         if (StringUtils.isEmpty(token)) {
-            logWarn(request, "Empty Token");
-            return writeAuthError(response, ResponseCode.STATUS_EMPTY_TOKEN);
+            writeAuthError(response, ResponseCode.STATUS_EMPTY_TOKEN);
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_WARN, mBusinessType, mStrClassName
+                    , String.format("Empty Token, Uri{%s} Remote{%s:%d}"
+                            ,request.getRequestURI()
+                            ,request.getRemoteAddr()
+                            ,request.getRemotePort()));
+            return;
         }
 
-        McpAuthUser user;
+        McpAuthUser user = null;
         try {
-            user = JwtTokenUtils.toAuthUser(token);
+            user = JwtTokenUtil.toAuthUser(token);
+            List<SimpleGrantedAuthority> authorities = StringUtils.isEmpty(user.getRoleId())
+                    ? List.of() : List.of(new SimpleGrantedAuthority(ApiURI.ROLE_AUTHORITY_PREFIX + user.getRoleId()));
+
+            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(user, null, authorities);
+            authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
+            SecurityContextHolder.getContext().setAuthentication(authentication);
+            McpAuthContextMgr.set(token, user);
         } catch (Exception ex) {
-            logWarn(request, "Token Parse Failed");
-            return writeAuthError(response, ResponseCode.STATUS_INVALID_TOKEN);
+            SecurityContextHolder.clearContext();
+            McpAuthContextMgr.clear();
+            writeAuthError(response, ResponseCode.STATUS_INVALID_TOKEN);
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_WARN, mBusinessType, mStrClassName
+                    , String.format("Token Parse Failed, Uri{%s} Remote{%s:%d}"
+                            ,request.getRequestURI()
+                            ,request.getRemoteAddr()
+                            ,request.getRemotePort()));
+            return;
         }
 
-        if (user == null) {
-            logWarn(request, "Invalid Token");
-            return writeAuthError(response, ResponseCode.STATUS_INVALID_TOKEN);
+        if (user == null){
+            SecurityContextHolder.clearContext();
+            McpAuthContextMgr.clear();
+            writeAuthError(response, ResponseCode.STATUS_INVALID_TOKEN);
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_WARN, mBusinessType, mStrClassName
+                    , String.format("Invalid Token, Uri{%s} Remote{%s:%d}"
+                            ,request.getRequestURI()
+                            ,request.getRemoteAddr()
+                            ,request.getRemotePort()));
+            return;
+        }else {
+            if (user.getExpiredTm() < System.currentTimeMillis()){
+                SecurityContextHolder.clearContext();
+                McpAuthContextMgr.clear();
+                writeAuthError(response, ResponseCode.STATUS_EXPIRED_TOKEN);
+                LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_WARN, mBusinessType, mStrClassName
+                        , String.format("Token Expired, Uri{%s} Remote{%s:%d}"
+                                ,request.getRequestURI()
+                                ,request.getRemoteAddr()
+                                ,request.getRemotePort()));
+                return;
+            }
         }
 
-        if (user.getExpiredTm() < System.currentTimeMillis()) {
-            logWarn(request, "Token Expired");
-            return writeAuthError(response, ResponseCode.STATUS_EXPIRED_TOKEN);
+        try {
+            filterChain.doFilter(request, response);
+        } finally {
+            McpAuthContextMgr.clear();
+            SecurityContextHolder.clearContext();
         }
-
-        List<SimpleGrantedAuthority> authorities = StringUtils.isEmpty(user.getRoleId())
-                ? List.of()
-                : List.of(new SimpleGrantedAuthority(ApiURI.ROLE_AUTHORITY_PREFIX + user.getRoleId()));
-
-        UsernamePasswordAuthenticationToken authentication =
-                new UsernamePasswordAuthenticationToken(user, token, authorities);
-
-        return chain.filter(exchange).contextWrite(ReactiveSecurityContextHolder.withAuthentication(authentication));
     }
 
-    private String extractToken(ServerHttpRequest request) {
-        String header = request.getHeaders().getFirst(ApiURI.HEADER_AUTHORIZATION);
+    private String extractToken(HttpServletRequest request) {
+        String header = request.getHeader(ApiURI.HEADER_AUTHORIZATION);
         if (!StringUtils.isEmpty(header))
             return header.trim();
 
-        String queryToken = request.getQueryParams().getFirst(ApiURI.QUERY_TOKEN_PARAM);
+        String queryToken = request.getParameter(ApiURI.QUERY_TOKEN_PARAM);
         if (!StringUtils.isEmpty(queryToken))
             return queryToken.trim();
         return "";
     }
 
-    private Mono<Void> writeAuthError(ServerHttpResponse response, ResponseCode code) {
-        response.getHeaders().set("Access-Control-Allow-Origin", "*");
-        response.getHeaders().set("Access-Control-Allow-Methods", "*");
-        response.getHeaders().set("Access-Control-Allow-Headers", ApiURI.ALLOW_HEADERS);
-        response.setStatusCode(HttpStatus.UNAUTHORIZED);
-        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
+    private void writeAuthError(HttpServletResponse response, ResponseCode code) throws IOException {
+        response.setHeader("Access-Control-Allow-Origin", "*");
+        response.setHeader("Access-Control-Allow-Methods", "*");
+        response.setHeader("Access-Control-Allow-Headers", ApiURI.ALLOW_HEADERS);
+        response.setStatus(HttpStatus.UNAUTHORIZED.value());
+        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
 
-        ResponseRes<String> resResult = new ResponseRes<>();
+        ResponseRes<String> resResult = new ResponseRes<String>();
         resResult.setRescode(code.toStrCode());
         resResult.setResmsg(code.toStrMsg());
         resResult.setResdata(code.toString());
         resResult.setTimestamp(System.currentTimeMillis());
-
-        byte[] bytes = FastJsonUtil.toJSON(resResult).getBytes(StandardCharsets.UTF_8);
-        DataBuffer buffer = response.bufferFactory().wrap(bytes);
-        return response.writeWith(Mono.just(buffer));
-    }
-
-    private void logWarn(ServerHttpRequest request, String msg) {
-        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_WARN, mBusinessType, mStrClassName,
-                String.format("%s, Uri{%s} Remote{%s}", msg, request.getURI().getPath(), HttpUtils.getIpAddress(request)));
+        try {
+            response.getWriter().write(FastJsonUtil.toJSON(resResult));
+            response.getWriter().flush();
+        }catch (Exception e){
+        }
     }
 }

+ 12 - 64
src/main/java/com/shkpr/service/mcpcenterservice/globalmgr/McpAuthContextMgr.java

@@ -1,80 +1,28 @@
 package com.shkpr.service.mcpcenterservice.globalmgr;
 
 import com.shkpr.service.mcpcenterservice.dto.McpAuthUser;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.ReactiveSecurityContextHolder;
-import org.springframework.security.core.context.SecurityContextHolder;
-import reactor.core.publisher.Mono;
 
 public final class McpAuthContextMgr {
+    private static final ThreadLocal<String> TOKEN_HOLDER = new ThreadLocal<>();
+    private static final ThreadLocal<McpAuthUser> USER_HOLDER = new ThreadLocal<>();
+
     private McpAuthContextMgr() {}
 
-    public static McpAuthUser getCurrentUser() {
-        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
-        if (auth != null && auth.getPrincipal() instanceof McpAuthUser user) {
-            return user;
-        }
-        return null;
+    public static void set(String rawToken, McpAuthUser user) {
+        TOKEN_HOLDER.set(rawToken);
+        USER_HOLDER.set(user);
     }
 
     public static String getCurrentToken() {
-        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
-        if (auth != null && auth.getCredentials() instanceof String token) {
-            return token;
-        }
-        return null;
-    }
-
-    /*public static McpAuthUser requireCurrentUser() {
-        McpAuthUser user = getCurrentUser();
-        if (user != null) return user;
-
-        return ReactiveSecurityContextHolder.getContext()
-                .mapNotNull(ctx -> {
-                    Authentication auth = ctx.getAuthentication();
-                    if (auth != null && auth.getPrincipal() instanceof McpAuthUser u) return u;
-                    return null;
-                })
-                .block();
+        return TOKEN_HOLDER.get();
     }
 
-    public static String requireCurrentToken() {
-        String token = getCurrentToken();
-        if (token != null) return token;
-
-        return ReactiveSecurityContextHolder.getContext()
-                .mapNotNull(ctx -> {
-                    Authentication auth = ctx.getAuthentication();
-                    if (auth != null && auth.getCredentials() instanceof String t) return t;
-                    return null;
-                })
-                .block();
-    }*/
-
-    public static Mono<McpAuthUser> rxCurrentUser() {
-        McpAuthUser fast = getCurrentUser();
-        if (fast != null)
-            return Mono.just(fast);
-
-        return ReactiveSecurityContextHolder.getContext()
-                .mapNotNull(ctx -> {
-                    Authentication auth = ctx.getAuthentication();
-                    if (auth != null && auth.getPrincipal() instanceof McpAuthUser u)
-                        return u;
-                    return null;
-                });
+    public static McpAuthUser getCurrentUser() {
+        return USER_HOLDER.get();
     }
 
-    public static Mono<String> rxCurrentToken() {
-        String fast = getCurrentToken();
-        if (fast != null)
-            return Mono.just(fast);
-
-        return ReactiveSecurityContextHolder.getContext()
-                .mapNotNull(ctx -> {
-                    Authentication auth = ctx.getAuthentication();
-                    if (auth != null && auth.getCredentials() instanceof String t) return t;
-                    return null;
-                });
+    public static void clear() {
+        TOKEN_HOLDER.remove();
+        USER_HOLDER.remove();
     }
 }

+ 41 - 35
src/main/java/com/shkpr/service/mcpcenterservice/mcptool/DateMcpTool.java

@@ -1,81 +1,87 @@
 package com.shkpr.service.mcpcenterservice.mcptool;
 
 import com.global.base.tools.FastJsonUtil;
+import com.shkpr.service.mcpcenterservice.dto.McpAuthUser;
 import com.shkpr.service.mcpcenterservice.globalmgr.McpAuthContextMgr;
 import io.modelcontextprotocol.spec.McpSchema.CallToolResult;
 import io.modelcontextprotocol.spec.McpSchema.TextContent;
 import org.springaicommunity.mcp.annotation.McpTool;
 import org.springaicommunity.mcp.annotation.McpToolParam;
 import org.springframework.stereotype.Service;
-import reactor.core.publisher.Mono;
 
 import java.time.LocalDate;
 import java.util.List;
 
 /**
  * 注:1) 使用@McpTool的工具方法,会被自动扫描注册,前提是所在类型添加了@Service或@Component注解
- *    2) 使用@McpTool的工具方法,WebFlux/WebMVC的SYNC模式下,方法返回的是CallToolResult类型时,服务不会在进行封装,而是直接返回
- *    3) 使用@McpTool的工具方法,WebFlux/WebMVC的SYNC模式下,方法返回的是非CallToolResult类型时,服务会自动封装成CallToolResult结构后再返回
- *    4) 使用@McpTool的工具方法,WebFlux的ASYNC模式下,方法返回任何类型,都需要自己显示地封装成Mono<>
+ *    2) 当@McpTool的工具方法返回的是CallToolResult结构时,服务不会在进行封装,而是直接返回
+ *    3) 当@McpTool的工具方法返回的是非CallToolResult结构时,服务会自动封装成CallToolResult结构后再返回
  */
 @Service
 public class DateMcpTool {
-
+    /**
+     *
+     * @param days
+     * @return
+     */
     @McpTool(name = "addDays", description = "Adds days to the current date")
-    public Mono<CallToolResult> addDays(@McpToolParam(description = "The number of days to add", required = true) Integer days) {
-        if (days == null) {
-            return Mono.just(new CallToolResult(
+    public CallToolResult addDays(@McpToolParam(description = "The number of days to add", required = true) Integer days) {
+        if (days == null){
+            return new CallToolResult(
                     List.of(new TextContent("缺少必要参数days,无法完成存储操作。")),
                     true
-            ));
+            );
         }
-        if (days < 0) {
-            return Mono.just(new CallToolResult(
+        if (days < 0){
+            return new CallToolResult(
                     List.of(new TextContent("参数days不能小于0,请重新输入。")),
                     true
-            ));
+            );
         }
-        return Mono.just(new CallToolResult(
+        return new CallToolResult(
                 List.of(new TextContent(LocalDate.now().plusDays(days).toString())),
                 false
-        ));
+        );
     }
 
     @McpTool(name = "subtractDays", description = "Subtracts days from the current date")
-    public Mono<CallToolResult> subtractDays(@McpToolParam(description = "The number of days to subtract", required = true) Integer days) {
-        if (days == null) {
-            return Mono.just(new CallToolResult(
+    public CallToolResult subtractDays(@McpToolParam(description = "The number of days to subtract", required = true) Integer days) {
+        if (days == null){
+            return new CallToolResult(
                     List.of(new TextContent("缺少必要参数days,无法完成存储操作。")),
                     true
-            ));
+            );
         }
-        if (days < 0) {
-            return Mono.just(new CallToolResult(
+        if (days < 0){
+            return new CallToolResult(
                     List.of(new TextContent("参数days不能小于0,请重新输入。")),
                     true
-            ));
+            );
         }
-        return Mono.just(new CallToolResult(
+        return new CallToolResult(
                 List.of(new TextContent(LocalDate.now().minusDays(days).toString())),
                 false
-        ));
+        );
     }
 
+    //服务会自动将string封装成CallToolResult后再返回给前端
     @McpTool(name = "today", description = "Return current date")
-    public Mono<String> today() {
-        return Mono.just(LocalDate.now().toString());
+    public String today() {
+        return LocalDate.now().toString();
     }
 
     @McpTool(name = "myUser", description = "Returns current user info.")
-    public Mono<CallToolResult> myUser() {
-        return McpAuthContextMgr.rxCurrentUser()
-                .map(user -> new CallToolResult(
-                        List.of(new TextContent(FastJsonUtil.toJSON(user))),
-                        false
-                ))
-                .defaultIfEmpty(new CallToolResult(
-                        List.of(new TextContent("无法识别当前用户")),
-                        true
-                ));
+    public CallToolResult myUser() {
+        McpAuthUser user = McpAuthContextMgr.getCurrentUser();
+        if (user == null) {
+            return new CallToolResult(
+                    List.of(new TextContent("未检查到Token令牌")),
+                    true
+            );
+        }
+        return new CallToolResult(
+                List.of(new TextContent(FastJsonUtil.toJSON(user))),
+                false
+        );
     }
 }

+ 1 - 2
src/main/java/com/shkpr/service/mcpcenterservice/mcptool/MathMcpTool.java

@@ -7,8 +7,7 @@ import org.springframework.stereotype.Service;
 /**
  * 注:1) 使用@Tool的工具方法,不会被自动扫描注册,需要显示调用MethodToolCallbackProvider.builder()进行注册
  *       [!!!]哪怕是所在类型添加了@Service或@Component注解[!!!]
- *    2) 使用@Tool的工具方法,WebFlux/WebMVC的SYNC模式下,方法返回任何类型,都会被自动封装成CallToolResult结构后再返回
- *    3) 使用@Tool的工具方法,WebFlux的ASYNC模式下,方法返回任何类型,都会被自动封装成Mono<CallToolResult>结构后再返回
+ *    2) 使用@Tool的工具方法,其返回参数不管是什么类型,都会被自动封装成CallToolResult结构后再返回
  */
 @Service
 public class MathMcpTool {

+ 16 - 4
src/main/resources/application.properties

@@ -1,10 +1,22 @@
-#项目的全局配置=============>
+#\u9879\u76EE\u7684\u5168\u5C40\u914D\u7F6E==============>
 spring.application.name=kpr-mcp-center-service
+server.servlet.context-path=/
 server.error.path= /
-# 服务端口
+# \u670D\u52A1\u7AEF\u53E3
 server.port=9100
+server.tomcat.max-http-post-size=-1
+spring.servlet.multipart.max-file-size=200MB
+spring.servlet.multipart.max-request-size=200MB
+
+server.servlet.session.timeout=60s
 server.connection-timeout=60s
 
+#Tomcat\u914D\u7F6E================>
+server.tomcat.uri-encoding=UTF-8
+server.tomcat.basedir=./trilog/tomcattmp
+server.tomcat.access-log-enabled=false
+server.tomcat.access-log-pattern=common
+
 global.sql.config.path=./sql.properties
 
 spring.ai.mcp.server.request-timeout=60s
@@ -19,7 +31,7 @@ spring.ai.mcp.server.tool-change-notification=true
 spring.ai.mcp.server.prompt-change-notification=true
 spring.ai.mcp.server.sse-endpoint=/kpr-mcp-center/sse
 spring.ai.mcp.server.sse-message-endpoint=/kpr-mcp-center/sse/message
-spring.ai.mcp.server.type=ASYNC
+spring.ai.mcp.server.type=SYNC
 spring.ai.mcp.server.capabilities.completion=true
 spring.ai.mcp.server.capabilities.prompt=true
 spring.ai.mcp.server.capabilities.tool=true
@@ -27,4 +39,4 @@ spring.ai.mcp.server.capabilities.resource=true
 spring.ai.mcp.server.capabilities.ping=true
 
 #logging.level.io.modelcontextprotocol=DEBUG
-#logging.level.org.springframework.ai.mcp=DEBUG
+#logging.level.org.springframework.ai.mcp=DEBUG