1"use strict";(self.webpackChunkspring_ai_alibaba_website=self.webpackChunkspring_ai_alibaba_website||[]).push([[4904],{28453:(e,n,s)=>{s.d(n,{R:()=>o,x:()=>l});var t=s(96540);const r={},i=t.createContext(r);function o(e){const n=t.useContext(i);return t.useMemo(function(){return"function"==typeof e?e(n):{...n,...e}},[n,e])}function l(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(r):e.components||r:o(e.components),t.createElement(i.Provider,{value:n},e.children)}},40876:(e,n,s)=>{s.r(n),s.d(n,{assets:()=>c,contentTitle:()=>l,default:()=>p,frontMatter:()=>o,metadata:()=>t,toc:()=>a});const t=JSON.parse('{"id":"mcps/annotations/mcp-annotations-server","title":"MCP Server Annotations","description":"MCP Server Annotations \u63d0\u4f9b\u4e86\u4e00\u79cd\u4f7f\u7528 Java \u6ce8\u89e3\u5b9e\u73b0 MCP \u670d\u52a1\u5668\u529f\u80fd\u7684\u58f0\u660e\u5f0f\u65b9\u6cd5\u3002","source":"@site/integration/mcps/annotations/mcp-annotations-server.md","sourceDirName":"mcps/annotations","slug":"/mcps/annotations/mcp-annotations-server","permalink":"/integration/mcps/annotations/mcp-annotations-server","draft":false,"unlisted":false,"editUrl":"https://github.com/spring-ai-alibaba/website/tree/main/integration/mcps/annotations/mcp-annotations-server.md","tags":[],"version":"current","lastUpdatedBy":"Ken Liu","lastUpdatedAt":1765761850000,"frontMatter":{},"sidebar":"integrationSidebar","previous":{"title":"MCP Annotations","permalink":"/integration/mcps/annotations/mcp-annotations-overview"},"next":{"title":"MCP Client Annotations","permalink":"/integration/mcps/annotations/mcp-annotations-client"}}');var r=s(74848),i=s(28453);const o={},l="MCP Server Annotations",c={},a=[{value:"Server Annotations",id:"server-annotations",level:2},{value:"@McpTool",id:"mcptool",level:3},{value:"Basic Usage",id:"basic-usage",level:4},{value:"Advanced Features",id:"advanced-features",level:4},{value:"With Request Context",id:"with-request-context",level:4},{value:"Dynamic Schema Support",id:"dynamic-schema-support",level:4},{value:"Progress Tracking",id:"progress-tracking",level:4},{value:"@McpResource",id:"mcpresource",level:3},{value:"Basic Usage",id:"basic-usage-1",level:4},{value:"With ReadResourceResult",id:"with-readresourceresult",level:4},{value:"With Request Context",id:"with-request-context-1",level:4},{value:"@McpPrompt",id:"mcpprompt",level:3},{value:"Basic Usage",id:"basic-usage-2",level:4},{value:"With Optional Arguments",id:"with-optional-arguments",level:4},{value:"@McpComplete",id:"mcpcomplete",level:3},{value:"Basic Usage",id:"basic-usage-3",level:4},{value:"With CompleteRequest.CompleteArgument",id:"with-completerequestcompleteargument",level:4},{value:"With CompleteResult",id:"with-completeresult",level:4},{value:"Stateless vs Stateful Implementations",id:"stateless-vs-stateful-implementations",level:2},{value:"Unified Request Context (Recommended)",id:"unified-request-context-recommended",level:3},{value:"Simple Operations (No Context)",id:"simple-operations-no-context",level:3},{value:"Lightweight Stateless (with McpTransportContext)",id:"lightweight-stateless-with-mcptransportcontext",level:3},{value:"Method Filtering by Server Type",id:"method-filtering-by-server-type",level:2},{value:"Synchronous vs Asynchronous Filtering",id:"synchronous-vs-asynchronous-filtering",level:3},{value:"Synchronous Servers",id:"synchronous-servers",level:4},{value:"Asynchronous Servers",id:"asynchronous-servers",level:4},{value:"Stateful vs Stateless Filtering",id:"stateful-vs-stateless-filtering",level:3},{value:"Stateful Servers",id:"stateful-servers",level:4},{value:"Stateless Servers",id:"stateless-servers",level:4},{value:"Filtering Summary",id:"filtering-summary",level:3},{value:"Async Support",id:"async-support",level:2},{value:"Spring Boot Integration",id:"spring-boot-integration",level:2},{value:"Configuration Properties",id:"configuration-properties",level:2}];function d(e){const n={blockquote:"blockquote",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.header,{children:(0,r.jsx)(n.h1,{id:"mcp-server-annotations",children:"MCP Server Annotations"})}),"\n",(0,r.jsx)(n.p,{children:"MCP Server Annotations \u63d0\u4f9b\u4e86\u4e00\u79cd\u4f7f\u7528 Java \u6ce8\u89e3\u5b9e\u73b0 MCP \u670d\u52a1\u5668\u529f\u80fd\u7684\u58f0\u660e\u5f0f\u65b9\u6cd5\u3002\n\u8fd9\u4e9b\u6ce8\u89e3\u7b80\u5316\u4e86\u5de5\u5177\u3001\u8d44\u
16e90\u3001prompts \u548c completion \u5904\u7406\u5668\u7684\u521b\u5efa\u3002"}),"\n",(0,r.jsx)(n.h2,{id:"server-annotations",children:"Server Annotations"}),"\n",(0,r.jsx)(n.h3,{id:"mcptool",children:"@McpTool"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"@McpTool"})," \u6ce8\u89e3\u5c06\u65b9\u6cd5\u6807\u8bb0\u4e3a MCP \u5de5\u5177\u5b9e\u73b0\uff0c\u81ea\u52a8\u751f\u6210 JSON schema\u3002"]}),"\n",(0,r.jsx)(n.h4,{id:"basic-usage",children:"Basic Usage"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@Component\npublic class CalculatorTools {\n\n @McpTool(name = "add", description = "Add two numbers together")\n public int add(\n @McpToolParam(description = "First number", required = true) int a,\n @McpToolParam(description = "Second number", required = true) int b) {\n return a + b;\n }\n}\n'})}),"\n",(0,r.jsx)(n.h4,{id:"advanced-features",children:"Advanced Features"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@McpTool(name = "calculate-area", \n description = "Calculate the area of a rectangle",\n annotations = McpTool.McpAnnotations(\n title = "Rectangle Area Calculator",\n readOnlyHint = true,\n destructiveHint = false,\n idempotentHint = true\n ))\npublic AreaResult calculateRectangleArea(\n @McpToolParam(description = "Width", required = true) double width,\n @McpToolParam(description = "Height", required = true) double height) {\n \n return new AreaResult(width * height, "square units");\n}\n'})}),"\n",(0,r.jsx)(n.h4,{id:"with-request-context",children:"With Request Context"}),"\n",(0,r.jsx)(n.p,{children:"\u5de5\u5177\u53ef\u4ee5\u8bbf\u95ee\u8bf7\u6c42\u4e0a\u4e0b\u6587\u4ee5\u8fdb\u884c\u9ad8\u7ea7\u64cd\u4f5c\uff1a"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@McpTool(name = "process-data", description = "Process data with request context")\npublic String processData(\n McpSyncRequestContext context,\n @McpToolParam(description = "Data to process", required = true) String data) {\n \n // Send logging notification\n context.info("Processing data: " + data);\n \n // Send progress notification (using convenient method)\n context.progress(p -> p.progress(0.5).total(1.0).message("Processing..."));\n \n // Ping the client\n context.ping();\n \n return "Processed: " + data.toUpperCase();\n}\n'})}),"\n",(0,r.jsx)(n.h4,{id:"dynamic-schema-support",children:"Dynamic Schema Support"}),"\n",(0,r.jsxs)(n.p,{children:["\u5de5\u5177\u53ef\u4ee5\u63a5\u53d7 ",(0,r.jsx)(n.code,{children:"CallToolRequest"})," \u8fdb\u884c\u8fd0\u884c\u65f6 schema \u5904\u7406\uff1a"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@McpTool(name = "flexible-tool", description = "Process dynamic schema")\npublic CallToolResult processDynamic(CallToolRequest request) {\n Map<String, Object> args = request.arguments();\n \n // Process based on runtime schema\n String result = "Processed " + args.size() + " arguments dynamically";\n \n return CallToolResult.builder()\n .addTextContent(result)\n .build();\n}\n'})}),"\n",(0,r.jsx)(n.h4,{id:"progress-tracking",children:"Progress Tracking"}),"\n",(0,r.jsx)(n.p,{children:"\u5de5\u5177\u53ef\u4ee5\u63a5\u6536\u8fdb\u5ea6\u4ee4\u724c\u4ee5\u8ddf\u8e2a\u957f\u65f6\u95f4\u8fd0\u884c\u7684\u64cd\u4f5c\uff1a"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@McpTool(name = "long-task", description = "Long-running task with progress")\npublic String performLongTask(\n McpSyncRequestContext context,\n @McpToolParam(description = "Task name", required = true) String taskName) {\n \n // Access progress token from context\n String progressToken = context.request().progressToken();\n \n if (progressToken != null) {\n context.progress(p -> p.progress(0.0).total(1.0).message("Starting task"));\n \n // Perform work...\n \n context.progress(p -> p.progress(1.0).total(1.0).message("Task completed"));\n }\n \n return "Task " + taskName + " completed";\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"mcpresource",children:"@McpResource"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"@McpResource"})," \u6ce8\u89e3\u901a\u8fc7 URI \u6a21\u677f\u63d0\u4f9b\u8d44\u6e90\u8bbf\u95ee\u3002"]}),"\n",(0,r.jsx)(n.h4,{id:"basic-usage-1",children:"Basic Usage"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@Component\npublic class ResourceProvider {\n\n @McpResource(\n uri = "config://{key}", \n name = "Configuration", \n description = "Provides configuration data")\n public String getConfig(String key) {\n return configData.get(key);\n }\n}\n'})}),"\n",(0,r.jsx)(n.h4,{id:"with-readresourceresult",children:"With ReadResourceResult"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@McpResource(\n uri = "user-profile://{username}", \n name = "User Profile", \n description = "Provides user profile information")\npublic ReadResourceResult getUserProfile(String username) {\n String profileData = loadUserProfile(username);\n \n return new ReadResourceResult(List.of(\n new TextResourceContents(\n "user-profile://" + username,\n "application/json", \n profileData)\n ));\n}\n'})}),"\n",(0,r.jsx)(n.h4,{id:"with-request-context-1",children:"With Request Context"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@McpResource(\n uri = "data://{id}", \n name = "Data Resource", \n description = "Resource with request context")\npublic ReadResourceResult getData(\n McpSyncRequestContext context, \n String id) {\n \n // Send logging notification using convenient method\n context.
1info("Accessing resource: " + id);\n \n // Ping the client\n context.ping();\n \n String data = fetchData(id);\n \n return new ReadResourceResult(List.of(\n new TextResourceContents("data://" + id, "text/plain", data)\n ));\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"mcpprompt",children:"@McpPrompt"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"@McpPrompt"})," \u6ce8\u89e3\u4e3a AI \u4ea4\u4e92\u751f\u6210 prompt \u6d88\u606f\u3002"]}),"\n",(0,r.jsx)(n.h4,{id:"basic-usage-2",children:"Basic Usage"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@Component\npublic class PromptProvider {\n\n @McpPrompt(\n name = "greeting", \n description = "Generate a greeting message")\n public GetPromptResult greeting(\n @McpArg(name = "name", description = "User\'s name", required = true) \n String name) {\n \n String message = "Hello, " + name + "! How can I help you today?";\n \n return new GetPromptResult(\n "Greeting",\n List.of(new PromptMessage(Role.ASSISTANT, new TextContent(message)))\n );\n }\n}\n'})}),"\n",(0,r.jsx)(n.h4,{id:"with-optional-arguments",children:"With Optional Arguments"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@McpPrompt(\n name = "personalized-message",\n description = "Generate a personalized message")\npublic GetPromptResult personalizedMessage(\n @McpArg(name = "name", required = true) String name,\n @McpArg(name = "age", required = false) Integer age,\n @McpArg(name = "interests", required = false) String interests) {\n \n StringBuilder message = new StringBuilder();\n message.append("Hello, ").append(name).append("!\\n\\n");\n \n if (age != null) {\n message.append("At ").append(age).append(" years old, ");\n // Add age-specific content\n }\n \n if (interests != null && !interests.isEmpty()) {\n message.append("Your interest in ").append(interests);\n // Add interest-specific content\n }\n \n return new GetPromptResult(\n "Personalized Message",\n List.of(new PromptMessage(Role.ASSISTANT, new TextContent(message.toString())))\n );\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"mcpcomplete",children:"@McpComplete"}),"\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.code,{children:"@McpComplete"})," \u6ce8\u89e3\u4e3a prompts \u63d0\u4f9b\u81ea\u52a8\u5b8c\u6210\u529f\u80fd\u3002"]}),"\n",(0,r.jsx)(n.h4,{id:"basic-usage-3",children:"Basic Usage"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@Component\npublic class CompletionProvider {\n\n @McpComplete(prompt = "city-search")\n public List<String> completeCityName(String prefix) {\n return cities.stream()\n .filter(city -> city.toLowerCase().startsWith(prefix.toLowerCase()))\n .limit(10)\n .toList();\n }\n}\n'})}),"\n",(0,r.jsx)(n.h4,{id:"with-completerequestcompleteargument",children:"With CompleteRequest.CompleteArgument"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@McpComplete(prompt = "travel-planner")\npublic List<String> completeTravelDestination(CompleteRequest.CompleteArgument argument) {\n String prefix = argument.value().toLowerCase();\n String argumentName = argument.name();\n \n // Different completions based on argument name\n if ("city".equals(argumentName)) {\n return completeCities(prefix);\n } else if ("country".equals(argumentName)) {\n return completeCountries(prefix);\n }\n \n return List.of();\n}\n'})}),"\n",(0,r.jsx)(n.h4,{id:"with-completeresult",children:"With CompleteResult"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@McpComplete(prompt = "code-completion")\npublic CompleteResult completeCode(String prefix) {\n List<String> completions = generateCodeCompletions(prefix);\n \n return new CompleteResult(\n new CompleteResult.CompleteCompletion(\n completions,\n completions.size(), // total\n hasMoreCompletions // hasMore flag\n )\n );\n}\n'})}),"\n",(0,r.jsx)(n.h2,{id:"stateless-vs-stateful-implementations",children:"Stateless vs Stateful Implementations"}),"\n",(0,r.jsx)(n.h3,{id:"unified-request-context-recommended",children:"Unified Request Context (Recommended)"}),"\n",(0,r.jsxs)(n.p,{children:["\u4f7f\u7528 ",(0,r.jsx)(n.code,{children:"McpSyncRequestContext"})," \u6216 ",(0,r.jsx)(n.code,{children:"McpAsyncRequestContext"})," \u83b7\u5f97\u7edf\u4e00\u63a5\u53e3\uff0c\u9002\u7528\u4e8e\u6709\u72b6\u6001\u548c\u65e0\u72b6\u6001\u64cd\u4f5c\uff1a"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'public re
1cord UserInfo(String name, String email, int age) {}\n\n@McpTool(name = "unified-tool", description = "Tool with unified request context")\npublic String unifiedTool(\n McpSyncRequestContext context,\n @McpToolParam(description = "Input", required = true) String input) {\n \n // Access request and metadata\n String progressToken = context.request().progressToken();\n \n // Logging with convenient methods\n context.info("Processing: " + input);\n \n // Progress notifications (Note client should set a progress token \n // with its request to be able to receive progress updates)\n context.progress(50); // Simple percentage \n \n // Ping client\n context.ping();\n \n // Check capabilities before using\n if (context.elicitEnabled()) {\n // Request user input (only in stateful mode)\n StructuredElicitResult<UserInfo> elicitResult = context.elicit(UserInfo.class);\n if (elicitResult.action() == ElicitResult.Action.ACCEPT) {\n // Use elicited data\n }\n }\n \n if (context.sampleEnabled()) {\n // Request LLM sampling (only in stateful mode)\n CreateMessageResult samplingResult = context.sample("Generate response");\n // Use sampling result\n }\n \n return "Processed with unified context";\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"simple-operations-no-context",children:"Simple Operations (No Context)"}),"\n",(0,r.jsx)(n.p,{children:"\u5bf9\u4e8e\u7b80\u5355\u64cd\u4f5c\uff0c\u53ef\u4ee5\u5b8c\u5168\u7701\u7565\u4e0a\u4e0b\u6587\u53c2\u6570\uff1a"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@McpTool(name = "simple-add", description = "Simple addition")\npublic int simpleAdd(\n @McpToolParam(description = "First number", required = true) int a,\n @McpToolParam(description = "Second number", required = true) int b) {\n return a + b;\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"lightweight-stateless-with-mcptransportcontext",children:"Lightweight Stateless (with McpTransportContext)"}),"\n",(0,r.jsx)(n.p,{children:"\u5bf9\u4e8e\u9700\u8981\u6700\u5c0f\u4f20\u8f93\u4e0a\u4e0b\u6587\u7684\u65e0\u72b6\u6001\u64cd\u4f5c\uff1a"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@McpTool(name = "stateless-tool", description = "Stateless with transport context")\npublic String statelessTool(\n McpTransportContext context,\n @McpToolParam(description = "Input", required = true) String input) {\n // Access transport-level context only\n // No bidirectional operations (roots, elicitation, sampling)\n return "Processed: " + input;\n}\n'})}),"\n",(0,r.jsxs)(n.blockquote,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"\u91cd\u8981\u63d0\u793a\uff1a"})," \u65e0\u72b6\u6001\u670d\u52a1\u5668\u4e0d\u652f\u6301\u53cc\u5411\u64cd\u4f5c\uff1a"]}),"\n"]}),"\n",(0,r.jsxs)(n.p,{children:["\u56e0\u6b64\uff0c\u5728\u65e0\u72b6\u6001\u6a21\u5f0f\u4e0b\u4f7f\u7528 ",(0,r.jsx)(n.code,{children:"McpSyncRequestContext"})," \u6216 ",(0,r.jsx)(n.code,{children:"McpAsyncRequestContext"})," \u7684\u65b9\u6cd5\u4f1a\u88ab\u5ffd\u7565\u3002"]}),"\n",(0,r.jsx)(n.h2,{id:"method-filtering-by-server-type",children:"Method Filtering by Server Type"}),"\n",(0,r.jsx)(n.p,{children:"MCP annotations \u6846\u67b6\u6839\u636e\u670d\u52a1\u5668\u7c7b\u578b\u548c\u65b9\u6cd5\u7279\u5f81\u81ea\u52a8\u8fc7\u6ee4\u5e26\u6ce8\u89e3\u7684\u65b9\u6cd5\u3002\u8fd9\u786e\u4fdd\u53ea\u4e3a\u6bcf\u4e2a\u670d\u52a1\u5668\u914d\u7f6e\u6ce8\u518c\u9002\u5f53\u7684\u65b9\u6cd5\u3002\n\u6bcf\u4e2a\u88ab\u8fc7\u6ee4\u7684\u65b9\u6cd5\u90fd\u4f1a\u8bb0\u5f55\u8b66\u544a\uff0c\u4ee5\u5e2e\u52a9\u8c03\u8bd5\u3002"}),"\n",(0,r.jsx)(n.h3,{id:"synchronous-vs-asynchronous-filtering",children:"Synchronous vs Asynchronous Filtering"}),"\n",(0,r.jsx)(n.h4,{id:"synchronous-servers",children:"Synchronous Servers"}),"\n",(0,r.jsxs)(n.p,{children:["\u540c\u6b65\u670d\u52a1\u5668\uff08\u914d\u7f6e\u4e3a ",(0,r.jsx)(n.code,{children:"spring.ai.mcp.server.type=SYNC"}),"\uff09\u4f7f\u7528\u540c\u6b65\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u5b83\u4eec\uff1a"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"\u63a5\u53d7"})," \u5177\u6709\u975e\u54cd\u5e94\u5f0f\u8fd4\u56de\u7c7b\u578b\u7684\u65b9\u6cd5\uff1a"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\u57fa\u672c\u7c7b\u578b\uff08",(0,r.jsx)(n.code,{children:"int"}),"\u3001",(0,r.jsx)(n.code,{children:"double"}),"\u3001",(0,r.jsx)(n.code,{children:"boolean"}),"\uff09"]}),"\n",(0,r.jsxs)(n.li,{children:["\u5bf9\u8c61\u7c7b\u578b\uff08",(0,r.jsx)(n.code,{children:"String"}),"\u3001",(0,r.jsx)(n.code,{children:"Integer"}),"\u3001\u81ea\u5b9a\u4e49 POJOs\uff09"]}),"\n",(0,r.jsxs)(n.li,{children:["MCP \u7c7b\u578b\uff08",(0,r.jsx)(n.code,{children:"CallToolResult"}),"\u3001",(0,r.jsx)(n.code,{children:"ReadResourceResult"}),"\u3001",(0,r.jsx)(n.code,{children:"GetPromptResult"}),"\u3001",(0,r.jsx)(n.code,{children:"CompleteResult"}),"\uff09"]}),"\n",(0,r.jsxs)(n.li,{children:["\u96c6\u5408\uff08",(0,r.jsx)(n.code,{children:"List<String>"}),"\u3001",(0,r.jsx)(n.code,{children:"Map<String, Object>"}),"\uff09"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"\u8fc7\u6ee4\u6389"})," \u5177\u6709\u54cd\u5e94\u5f0f\u8fd4\u56de\u7c7b\u578b\u7684\u65b9\u6cd5\uff1a"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"Mono<T>"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"Flux<T>"})}),"\n",(0,r.jsx)(n.li,{children:(0,r.jsx)(n.code,{children:"Publisher<T>"})}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@Component\npublic class SyncTools {\n \n @McpTool(name = "sync-tool", description = "Synchronous tool")\n public String syncTool(String input) {\n // This method WILL be registered on sync servers\n return "Processed: " + input;\n }\n \n @McpTool(name = "async-tool", description = "Async tool")\n public Mono<String> asyncTool(String input) {\n // This method will be FILTERED OUT on sync servers\n // A warning will be logged\n return Mono.just("Processed: " + input);\n }\n}\n'})}),"\n",(0,r.jsx)(n.h4,{id:"asynchronous-servers",children:"Asynchronous Servers"}),"\n",(0,r.jsxs)(n.p,{children:["\u5f02\u6b65\u670d\u52a1\u5668\uff08\u914d\u7f6e\u4e3a ",(0,r.jsx)(n.code,{children:"spring.ai.mcp.server.type=ASYNC"}),"\uff09\u4f7f\u7528\u5f02\u6b65\u63d0\u4f9b\u7a0b\u5e8f\uff0c\u5b83\u4eec\uff1a"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"\u63a5\u53d7"})," \u5177\u6709\u54cd\u5e94\u5f0f\u8fd4\u56de\u7c7b\u578b\u7684\u65b9\u6cd5\uff1a"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"Mono<T>"}),"\uff08\u7528\u4e8e\u5355\u4e2a\u7ed3\u679c\uff09"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"Flux<T>"}),"\uff08\u7528\u4e8e\u6d41\u5f0f\u7ed3\u679c\uff09"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"Publisher<T>"}),"\uff08\u901a\u7528\u54cd\u5e94\u5f0f\u7c7b\u578b\uff09"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"\u8fc7\u6ee4\u6389"})," \u5177\u6709\u975e\u54cd\u5e94\u5f0f\u8fd4\u56de\u7c7b\u578b\u7684\u65b9\u6cd5\uff1a"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"\u57fa\u672c\u7c7b\u578b"}),"\n",(0,r.jsx)(n.li,{children:"\u5bf9\u8c61\u7c7b\u578b"}),"\n",(0,r.jsx)(n.li,{children:"\u96c6\u5408"}),"\n",(0,r.jsx)(n.li,{children:"MCP \u7ed3\u679c\u7c7b\u578b"}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@Component\npublic class AsyncTools {\n \n @McpTool(name = "async-tool", description = "Async tool")\n public Mono<String> asyncTool(String input) {\n // This method WILL be registered on async servers\n return Mono.just("Processed: " + input);\n }\n \n @McpTool(name = "sync-tool", description = "Sync tool")\n public String syncTool(String input) {\n // This method will be FILTERED OUT on async servers\n // A warning will be logged\n return "Processed: " + input;\n }\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"stateful-vs-stateless-filtering",children:"Stateful vs Stateless Filtering"}),"\n",(0,r.jsx)(n.h4,{id:"stateful-servers",children:"Stateful Servers"}),"\n",(0,r.jsx)(n.p,{children:"\u6709\u72b6\u6001\u670d\u52a1\u5668\u652f\u6301\u53cc\u5411\u901a\u4fe1\uff0c\u5e76\u63a5\u53d7\u5177\u6709\u4ee5\u4e0b\u5185\u5bb9\u7684\u65b9\u6cd5\uff1a"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"\u53cc\u5411\u4e0a\u4e0b\u6587\u53c2\u6570"}),"\uff1a"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"McpSyncRequestContext"}),"\uff08\u7528\u4e8e\u540c\u6b65\u64cd\u4f5c\uff09"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"McpAsyncRequestContext"}),"\uff08\u7528\u4e8e\u5f02\u6b65\u64cd\u4f5c\uff09"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"McpSyncServerExchange"}),"\uff08\u9057\u7559\uff0c\u7528\u4e8e\u540c\u6b65\u64cd\u4f5c\uff09"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"McpAsyncServerExchange"}),"\uff08\u9057\u7559\uff0c\u7528\u4e8e\u5f02\u6b65\u64cd\u4f5c\uff09"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsx)(n.p,{children:"\u652f\u6301\u53cc\u5411\u64cd\u4f5c\uff1a"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"roots()"})," - \u8bbf\u95ee\u6839\u76ee\u5f55"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"elicit()"})," - \u8bf7\u6c42\u7528\u6237\u8f93\u5165"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"sample()"})," - \u8bf7\u6c42 LLM sampling"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@Component\npublic class StatefulTools {\n \n @McpTool(name = "interactive-tool", description = "Tool with bidirectional operations")\n public String interactiveTool(\n McpSyncRequestContext context,\n @McpToolParam(description = "Input", required = true) String input) {\n \n // This method WILL be registered on stateful servers\n // Can use elicitation, sampling, roots\n if (context.sampleEnabled()) {\n var samplingResult = context.sample("Generate response");\n // Process sampling result...\n }\n \n return "Processed with context";\n }\n}\n'})}),"\n",(0,r.jsx)(n.h4,{id:"stateless-servers",children:"Stateless Servers"}),"\n",(0,r.jsx)(n.p,{children:"\u65e0\u72b6\u6001\u670d\u52a1\u5668\u9488\u5bf9\u7b80\u5355\u7684\u8bf7\u6c42-\u54cd\u5e94\u6a21\u5f0f\u8fdb\u884c\u4e86\u4f18\u5316\uff0c\u5e76\u4e14\uff1a"}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"\u8fc7\u6ee4\u6389"})," \u5177\u6709\u53cc\u5411\u4e0a\u4e0b\u6587\u53c2\u6570\u7684\u65b9\u6cd5\uff1a"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:["\u5177\u6709 ",(0,r.jsx)(n.code,{children:"McpSyncRequestContext"})," \u7684\u65b9\u6cd5\u4f1a\u88ab\u8df3\u8fc7"]}),"\n",(0,r.jsxs)(n.li,{children:["\u5177\u6709 ",(0,r.jsx)(n.code,{children:"McpAsyncRequestContext"})," \u7684\u65b9\u6cd5\u4f1a\u88ab\u8df3\u8fc7"]}),"\n",(0,r.jsxs)(n.li,{children:["\u5177\u6709 ",(0,r.jsx)(n.code,{children:"McpSyncServerExchange"})," \u7684\u65b9\u6cd5\u4f1a\u88ab\u8df3\u8fc7"]}),"\n",(0,r.jsxs)(n.li,{children:["\u5177\u6709 ",(0,r.jsx)(n.code,{children:"McpAsyncServerExchange"})," \u7684\u65b9\u6cd5\u4f1a\u88ab\u8df3\u8fc7"]}),"\n",(0,r.jsx)(n.li,{children:"\u6bcf\u4e2a\u88ab\u8fc7\u6ee4\u7684\u65b9\u6cd5\u90fd\u4f1a\u8bb0\u5f55\u8b66\u544a"}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"\u63a5\u53d7"})," \u5177\u6709\u4ee5\u4e0b\u5185\u5bb9\u7684\u65b9\u6cd5\uff1a"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"McpTransportContext"}),"\uff08\u8f7b\u91cf\u7ea7\u65e0\u72b6\u6001\u4e0a\u4e0b\u6587\uff09"]}),"\n",(0,r.jsx)(n.li,{children:"\u5b8c\u5168\u6ca1\u6709\u4e0a\u4e0b\u6587\u53c2\u6570"}),"\n",(0,r.jsxs)(n.li,{children:["\u53ea\u6709\u5e38\u89c4\u7684 ",(0,r.jsx)(n.code,{children:"@McpToolParam"})," \u53c2\u6570"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(n.li,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"\u4e0d\u652f\u6301"})," \u53cc\u5411\u64cd\u4f5c\uff1a"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"roots()"})," - \u4e0d\u53ef\u7528"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"elicit()"})," - \u4e0d\u53ef\u7528"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"sample()"})," - \u4e0d\u53ef\u7528"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@Component\npublic class StatelessTools {\n \n @McpTool(name = "simple-tool", description = "Simple stateless tool")\n public String simpleTool(@McpToolParam(description = "Input") String input) {\n // This method WILL be registered on stateless servers\n return "Processed: " + input;\n }\n \n @McpTool(name = "context-tool", description = "Tool with transport context")\n public String contextTool(\n McpTransportContext context,\n @McpToolParam(description = "Input") String input) {\n // This method WILL be registered on stateless servers\n return "Processed: " + input;\n }\n \n @McpTool(name = "bidirectional-tool", description = "Tool with bidirectional context")\n public String bidirectionalTool(\n McpSyncRequestContext context,\n @McpToolParam(description = "Input") String input) {\n // This method will be FILTERED OUT on stateless servers\n // A warning will be logged\n return "Processed with sampling";\n }\n}\n'})}),"\n",(0,r.jsx)(n.h3,{id:"filtering-summary",children:"Filtering Summary"}),"\n",(0,r.jsxs)(n.table,{children:[(0,r.jsx)(n.thead,{children:(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.th,{children:"Server Type"}),(0,r.jsx)(n.th,{children:"Accepted Methods"}),(0,r.jsx)(n.th,{children:"Filtered Methods"})]})}),(0,r.jsxs)(n.tbody,{children:[(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.strong,{children:"Sync Stateful"})}
1),(0,r.jsx)(n.td,{children:"Non-reactive returns + bidirectional context"}),(0,r.jsx)(n.td,{children:"Reactive returns (Mono/Flux)"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.strong,{children:"Async Stateful"})}),(0,r.jsx)(n.td,{children:"Reactive returns (Mono/Flux) + bidirectional context"}),(0,r.jsx)(n.td,{children:"Non-reactive returns"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.strong,{children:"Sync Stateless"})}),(0,r.jsx)(n.td,{children:"Non-reactive returns + no bidirectional context"}),(0,r.jsx)(n.td,{children:"Reactive returns OR bidirectional context parameters"})]}),(0,r.jsxs)(n.tr,{children:[(0,r.jsx)(n.td,{children:(0,r.jsx)(n.strong,{children:"Async Stateless"})}),(0,r.jsx)(n.td,{children:"Reactive returns (Mono/Flux) + no bidirectional context"}),(0,r.jsx)(n.td,{children:"Non-reactive returns OR bidirectional context parameters"})]})]})]}),"\n",(0,r.jsxs)(n.blockquote,{children:["\n",(0,r.jsxs)(n.p,{children:[(0,r.jsx)(n.strong,{children:"\u63d0\u793a\uff1a"})," \u65b9\u6cd5\u8fc7\u6ee4\u7684\u6700\u4f73\u5b9e\u8df5\uff1a"]}),"\n"]}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\u4fdd\u6301\u65b9\u6cd5\u4e0e\u670d\u52a1\u5668\u7c7b\u578b\u4e00\u81f4"})," - \u540c\u6b65\u670d\u52a1\u5668\u4f7f\u7528\u540c\u6b65\u65b9\u6cd5\uff0c\u5f02\u6b65\u670d\u52a1\u5668\u4f7f\u7528\u5f02\u6b65\u65b9\u6cd5"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\u5c06\u6709\u72b6\u6001\u548c\u65e0\u72b6\u6001\u5b9e\u73b0\u5206\u79bb"}),"\u5230\u4e0d\u540c\u7684\u7c7b\u4e2d\u4ee5\u63d0\u9ad8\u6e05\u6670\u5ea6"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\u68c0\u67e5\u542f\u52a8\u65f6\u7684\u65e5\u5fd7"}),"\u4ee5\u67e5\u770b\u88ab\u8fc7\u6ee4\u65b9\u6cd5\u7684\u8b66\u544a"]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\u4f7f\u7528\u6b63\u786e\u7684\u4e0a\u4e0b\u6587"})," - \u6709\u72b6\u6001\u4f7f\u7528 ",(0,r.jsx)(n.code,{children:"McpSyncRequestContext"}),"/",(0,r.jsx)(n.code,{children:"McpAsyncRequestContext"}),"\uff0c\u65e0\u72b6\u6001\u4f7f\u7528 ",(0,r.jsx)(n.code,{children:"McpTransportContext"})]}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.strong,{children:"\u6d4b\u8bd5\u4e24\u79cd\u6a21\u5f0f"}),"\uff08\u5982\u679c\u60a8\u540c\u65f6\u652f\u6301\u6709\u72b6\u6001\u548c\u65e0\u72b6\u6001\u90e8\u7f72\uff09"]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"async-support",children:"Async Support"}),"\n",(0,r.jsx)(n.p,{children:"\u6240\u6709\u670d\u52a1\u5668\u6ce8\u89e3\u90fd\u652f\u6301\u4f7f\u7528 Reactor \u7684\u5f02\u6b65\u5b9e\u73b0\uff1a"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:'@Component\npublic class AsyncTools {\n\n @McpTool(name = "async-fetch", description = "Fetch data asynchronously")\n public Mono<String> asyncFetch(\n @McpToolParam(description = "URL", required = true) String url) {\n \n return Mono.fromCallable(() -> {\n // Simulate async operation\n return fetchFromUrl(url);\n }).subscribeOn(Schedulers.boundedElastic());\n }\n\n @McpResource(uri = "async-data://{id}", name = "Async Data")\n public Mono<ReadResourceResult> asyncResource(String id) {\n return Mono.fromCallable(() -> {\n String data = loadData(id);\n return new ReadResourceResult(List.of(\n new TextResourceContents("async-data://" + id, "text/plain", data)\n ));\n }).delayElements(Duration.ofMillis(100));\n }\n}\n'})}),"\n",(0,r.jsx)(n.h2,{id:"spring-boot-integration",children:"Spring Boot Integration"}),"\n",(0,r.jsx)(n.p,{children:"\u901a\u8fc7 Spring Boot \u81ea\u52a8\u914d\u7f6e\uff0c\u5e26\u6ce8\u89e3\u7684 beans \u4f1a\u81ea\u52a8\u68c0\u6d4b\u5e76\u6ce8\u518c\uff1a"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-java",children:"@SpringBootApplication\npublic class McpServerApplication {\n public static void main(String[] args) {\n SpringApplication.run(McpServerApplication.class, args);\n }\n}\n\n@Component\npublic class MyMcpTools {\n // Your @McpTool annotated methods\n}\n\n@Component\npublic class MyMcpResources {\n // Your @McpResource annotated methods\n}\n"})}),"\n",(0,r.jsx)(n.p,{children:"\u81ea\u52a8\u914d\u7f6e\u5c06\uff1a"}),"\n",(0,r.jsxs)(n.ol,{children:["\n",(0,r.jsx)(n.li,{children:"\u626b\u63cf\u5e26\u6709 MCP \u6ce8\u89e3\u7684 beans"}),"\n",(0,r.jsx)(n.li,{children:"\u521b\u5efa\u9002\u5f53\u7684\u89c4\u8303"}),"\n",(0,r.jsx)(n.li,{children:"\u5c06\u5b83\u4eec\u6ce8\u518c\u5230 MCP \u670d\u52a1\u5668"}),"\n",(0,r.jsx)(n.li,{children:"\u6839\u636e\u914d\u7f6e\u5904\u7406\u540c\u6b65\u548c\u5f02\u6b65\u5b9e\u73b0"}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"configuration-properties",children:"Configuration Properties"}),"\n",(0,r.jsx)(n.p,{children:"\u914d\u7f6e\u670d\u52a1\u5668\u6ce8\u89e3\u626b\u63cf\u5668\uff1a"}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-yaml",children:"spring:\n ai:\n mcp:\n server:\n type: SYNC # or ASYNC\n annotation-scanner:\n enabled: true\n"})})]})}function p(e={}){const{wrapper:n}={...(0,i.R)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.