e41ccca9 by Ean Schuessler

WIP: Add SDK-based MCP servlet implementations with SSE support

- Add multiple servlet implementations (EnhancedMcpServlet, ServiceBasedMcpServlet, MoquiMcpServlet)
- Implement SSE servlet support with proper content-type handling
- Add MCP filter for request processing
- Add web.xml configuration for servlet deployment
- Include SDK framework JAR and configuration files
- Remove old screen-based MCP implementation
- Update component configuration for new servlet-based approach
1 parent c65f866b
No preview for this file type
No preview for this file type
No preview for this file type
File mode changed
1 #Fri Nov 14 19:52:12 CST 2025
2 gradle.version=8.9
1 arguments=--init-script /home/ean/.config/Code/User/globalStorage/redhat.java/1.46.0/config_linux/org.eclipse.osgi/58/0/.cp/gradle/init/init.gradle --init-script /home/ean/.config/Code/User/globalStorage/redhat.java/1.46.0/config_linux/org.eclipse.osgi/58/0/.cp/gradle/protobuf/init.gradle
2 auto.sync=false
3 build.scans.enabled=false
4 connection.gradle.distribution=GRADLE_DISTRIBUTION(VERSION(8.9))
5 connection.project.dir=../../..
6 eclipse.preferences.version=1
7 gradle.user.home=
8 java.home=/usr/lib/jvm/java-17-openjdk-amd64
9 jvm.arguments=
10 offline.mode=false
11 override.workspace.settings=true
12 show.console.view=true
13 show.executions.view=true
1 /*
2 * This software is in the public domain under CC0 1.0 Universal plus a
3 * Grant of Patent License.
4 *
5 * To the extent possible under law, the author(s) have dedicated all
6 * copyright and related and neighboring rights to this software to the
7 * public domain worldwide. This software is distributed without any
8 * warranty.
9 *
10 * You should have received a copy of the CC0 Public Domain Dedication
11 * along with this software (see the LICENSE.md file). If not, see
12 * <http://creativecommons.org/publicdomain/zero/1.0/>.
13 */
14
15 apply plugin: 'groovy'
16
17 def componentNode = parseComponent(project)
18 version = componentNode.'@version'
19 def jarBaseName = componentNode.'@name'
20 def moquiDir = projectDir.parentFile.parentFile.parentFile
21 def frameworkDir = file(moquiDir.absolutePath + '/framework')
22
23 repositories {
24 flatDir name: 'localLib', dirs: frameworkDir.absolutePath + '/lib'
25 mavenCentral()
26 }
27
28 // Log4J has annotation processors, disable to avoid warning
29 tasks.withType(JavaCompile) { options.compilerArgs << "-proc:none" }
30 tasks.withType(GroovyCompile) { options.compilerArgs << "-proc:none" }
31
32 dependencies {
33 implementation project(':framework')
34
35 // Servlet API (provided by framework, but needed for compilation)
36 compileOnly 'javax.servlet:javax.servlet-api:4.0.1'
37 }
38
39 // by default the Java plugin runs test on build, change to not do that (only run test if explicit task)
40 check.dependsOn.clear()
41
42 task cleanLib(type: Delete) { delete fileTree(dir: projectDir.absolutePath+'/lib', include: '*') }
43 clean.dependsOn cleanLib
44
45 jar {
46 destinationDirectory = file(projectDir.absolutePath + '/lib')
47 archiveBaseName = jarBaseName
48 }
49 task copyDependencies { doLast {
50 copy { from (configurations.runtimeClasspath - project(':framework').configurations.runtimeClasspath)
51 into file(projectDir.absolutePath + '/lib') }
52 } }
53 copyDependencies.dependsOn cleanLib
54 jar.dependsOn copyDependencies
...\ No newline at end of file ...\ No newline at end of file
...@@ -14,13 +14,49 @@ ...@@ -14,13 +14,49 @@
14 xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/component-definition-3.xsd" 14 xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/component-definition-3.xsd"
15 name="moqui-mcp-2"> 15 name="moqui-mcp-2">
16 16
17 <!-- No dependencies - uses only core framework --> 17
18
19 <!-- MCP SDK dependencies -->
20 <dependency>
21 <groupId>io.modelcontextprotocol.sdk</groupId>
22 <artifactId>mcp</artifactId>
23 <version>0.16.0</version>
24 </dependency>
25 <dependency>
26 <groupId>io.modelcontextprotocol.sdk</groupId>
27 <artifactId>mcp-core</artifactId>
28 <version>0.16.0</version>
29 </dependency>
30 <dependency>
31 <groupId>com.fasterxml.jackson.core</groupId>
32 <artifactId>jackson-databind</artifactId>
33 <version>2.15.2</version>
34 </dependency>
35 <dependency>
36 <groupId>com.fasterxml.jackson.core</groupId>
37 <artifactId>jackson-core</artifactId>
38 <version>2.15.2</version>
39 </dependency>
40 <dependency>
41 <groupId>io.projectreactor</groupId>
42 <artifactId>reactor-core</artifactId>
43 <version>3.5.10</version>
44 </dependency>
18 45
19 <entity-factory load-path="entity/" /> 46 <entity-factory load-path="entity/" />
20 <service-factory load-path="service/" /> 47 <service-factory load-path="service/" />
21 <screen-factory load-path="screen/" /> 48 <!-- <screen-factory load-path="screen/" /> -->
22 49
23 <!-- Load seed data --> 50 <!-- Load seed data -->
24 <entity-factory load-data="data/McpSecuritySeedData.xml" /> 51 <entity-factory load-data="data/McpSecuritySeedData.xml" />
25 52
53 <!-- Register MCP filter
54 <webapp-list>
55 <webapp name="webroot">
56 <filter name="McpFilter" class="org.moqui.mcp.McpFilter">
57 <url-pattern>/mcpservlet/*</url-pattern>
58 </filter>
59 </webapp>
60 </webapp-list> -->
61
26 </component> 62 </component>
......
No preview for this file type
...@@ -257,10 +257,14 @@ ...@@ -257,10 +257,14 @@
257 def userId = ec.user.userId 257 def userId = ec.user.userId
258 def userAccountId = userId ? userId : null 258 def userAccountId = userId ? userId : null
259 259
260 // Build server capabilities 260 // Get user-specific tools and resources
261 def toolsResult = ec.service.sync().name("org.moqui.mcp.McpServices.mcp#ToolsList").parameters([:]).call()
262 def resourcesResult = ec.service.sync().name("org.moqui.mcp.McpServices.mcp#ResourcesList").parameters([:]).call()
263
264 // Build server capabilities based on what user can access
261 def serverCapabilities = [ 265 def serverCapabilities = [
262 tools: [:], 266 tools: toolsResult?.result?.tools ? [listChanged: true] : [:],
263 resources: [:], 267 resources: resourcesResult?.result?.resources ? [subscribe: true, listChanged: true] : [:],
264 logging: [:] 268 logging: [:]
265 ] 269 ]
266 270
...@@ -274,8 +278,10 @@ ...@@ -274,8 +278,10 @@
274 protocolVersion: "2025-06-18", 278 protocolVersion: "2025-06-18",
275 capabilities: serverCapabilities, 279 capabilities: serverCapabilities,
276 serverInfo: serverInfo, 280 serverInfo: serverInfo,
277 instructions: "This server provides access to Moqui ERP services and entities through MCP. Use tools/list to discover available operations." 281 instructions: "This server provides access to Moqui ERP services and entities through MCP. Tools and resources are filtered based on your permissions."
278 ] 282 ]
283
284 ec.logger.info("MCP Initialize for user ${userId}: ${toolsResult?.result?.tools?.size() ?: 0} tools, ${resourcesResult?.result?.resources?.size() ?: 0} resources")
279 ]]></script> 285 ]]></script>
280 </actions> 286 </actions>
281 </service> 287 </service>
...@@ -321,13 +327,27 @@ ...@@ -321,13 +327,27 @@
321 ] 327 ]
322 ] 328 ]
323 329
330 // Add service metadata to help LLM
331 if (serviceInfo.verb && serviceInfo.noun) {
332 tool.description += " (${serviceInfo.verb}:${serviceInfo.noun})"
333 }
334
324 // Convert service parameters to JSON Schema 335 // Convert service parameters to JSON Schema
325 def inParamNames = serviceInfo.getInParameterNames() 336 def inParamNames = serviceInfo.getInParameterNames()
326 for (paramName in inParamNames) { 337 for (paramName in inParamNames) {
327 def paramInfo = serviceInfo.getInParameter(paramName) 338 def paramInfo = serviceInfo.getInParameter(paramName)
339 def paramDesc = paramInfo.description ?: ""
340
341 // Add type information to description for LLM
342 if (!paramDesc) {
343 paramDesc = "Parameter of type ${paramInfo.type}"
344 } else {
345 paramDesc += " (type: ${paramInfo.type})"
346 }
347
328 tool.inputSchema.properties[paramName] = [ 348 tool.inputSchema.properties[paramName] = [
329 type: convertMoquiTypeToJsonSchemaType(paramInfo.type), 349 type: convertMoquiTypeToJsonSchemaType(paramInfo.type),
330 description: paramInfo.description ?: "" 350 description: paramDesc
331 ] 351 ]
332 352
333 if (paramInfo.required) { 353 if (paramInfo.required) {
...@@ -474,10 +494,15 @@ ...@@ -474,10 +494,15 @@
474 def resource = [ 494 def resource = [
475 uri: "entity://${entityName}", 495 uri: "entity://${entityName}",
476 name: entityName, 496 name: entityName,
477 description: "Moqui entity: ${entityName}", 497 description: entityInfo.description ?: "Moqui entity: ${entityName}",
478 mimeType: "application/json" 498 mimeType: "application/json"
479 ] 499 ]
480 500
501 // Add entity metadata to help LLM
502 if (entityInfo.packageName) {
503 resource.description += " (package: ${entityInfo.packageName})"
504 }
505
481 availableResources << resource 506 availableResources << resource
482 507
483 } catch (Exception e) { 508 } catch (Exception e) {
...@@ -536,6 +561,9 @@ ...@@ -536,6 +561,9 @@
536 561
537 def startTime = System.currentTimeMillis() 562 def startTime = System.currentTimeMillis()
538 try { 563 try {
564 // Get entity definition for field descriptions
565 def entityDef = ec.entity.getEntityDefinition(entityName)
566
539 // Query entity data (limited to prevent large responses) 567 // Query entity data (limited to prevent large responses)
540 def entityList = ec.entity.find(entityName) 568 def entityList = ec.entity.find(entityName)
541 .limit(100) 569 .limit(100)
...@@ -543,6 +571,18 @@ ...@@ -543,6 +571,18 @@
543 571
544 def executionTime = (System.currentTimeMillis() - startTime) / 1000.0 572 def executionTime = (System.currentTimeMillis() - startTime) / 1000.0
545 573
574 // Build field info for LLM
575 def fieldInfo = []
576 entityDef.allFieldInfoList.each { field ->
577 fieldInfo << [
578 name: field.name,
579 type: field.type,
580 description: field.description ?: "",
581 isPk: field.isPk,
582 required: field.notNull
583 ]
584 }
585
546 // Convert to MCP resource content 586 // Convert to MCP resource content
547 def contents = [ 587 def contents = [
548 [ 588 [
...@@ -550,7 +590,10 @@ ...@@ -550,7 +590,10 @@
550 mimeType: "application/json", 590 mimeType: "application/json",
551 text: new JsonBuilder([ 591 text: new JsonBuilder([
552 entityName: entityName, 592 entityName: entityName,
593 description: entityDef.description ?: "",
594 packageName: entityDef.packageName,
553 recordCount: entityList.size(), 595 recordCount: entityList.size(),
596 fields: fieldInfo,
554 data: entityList 597 data: entityList
555 ]).toString() 598 ]).toString()
556 ] 599 ]
......
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!-- This software is in the public domain under CC0 1.0 Universal plus a
3 Grant of Patent License.
4
5 To the extent possible under law, author(s) have dedicated all
6 copyright and related and neighboring rights to this software to the
7 public domain worldwide. This software is distributed without any warranty.
8
9 You should have received a copy of the CC0 Public Domain Dedication
10 along with this software (see the LICENSE.md file). If not, see
11 <https://creativecommons.org/publicdomain/zero/1.0/>. -->
12
13 <resource xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/rest-api-3.xsd"
14 name="mcp" displayName="MCP API" version="2.0.0"
15 description="MCP API services for Moqui integration - NOTE: Main functionality moved to screen/webapp.xml">
16
17 <!-- NOTE: Main MCP functionality moved to screen/webapp.xml for unified JSON-RPC and SSE handling -->
18 <!-- Keeping only basic GET endpoints for health checks and debugging -->
19
20 <resource name="rpc">
21 <method type="get">
22 <service name="McpServices.mcp#Ping"/>
23 </method>
24 <method type="get" path="debug">
25 <service name="McpServices.debug#ComponentStatus"/>
26 </method>
27 </resource>
28
29 </resource>
1 /*
2 * This software is in the public domain under CC0 1.0 Universal plus a
3 * Grant of Patent License.
4 *
5 * To the extent possible under law, author(s) have dedicated all
6 * copyright and related and neighboring rights to this software to the
7 * public domain worldwide. This software is distributed without any
8 * warranty.
9 *
10 * You should have received a copy of the CC0 Public Domain Dedication
11 * along with this software (see the LICENSE.md file). If not, see
12 * <http://creativecommons.org/publicdomain/zero/1.0/>.
13 */
14 package org.moqui.mcp
15
16 import org.slf4j.Logger
17 import org.slf4j.LoggerFactory
18
19 import javax.servlet.*
20 import javax.servlet.http.HttpServletRequest
21 import javax.servlet.http.HttpServletResponse
22
23 class McpFilter implements Filter {
24 protected final static Logger logger = LoggerFactory.getLogger(McpFilter.class)
25
26 private MoquiMcpServlet mcpServlet = new MoquiMcpServlet()
27
28 @Override
29 void init(FilterConfig filterConfig) throws ServletException {
30 logger.info("========== MCP FILTER INITIALIZED ==========")
31 // Initialize the servlet with filter config
32 mcpServlet.init(new ServletConfig() {
33 @Override
34 String getServletName() { return "McpFilter" }
35 @Override
36 ServletContext getServletContext() { return filterConfig.getServletContext() }
37 @Override
38 String getInitParameter(String name) { return filterConfig.getInitParameter(name) }
39 @Override
40 Enumeration<String> getInitParameterNames() { return filterConfig.getInitParameterNames() }
41 })
42 }
43
44 @Override
45 void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
46 throws IOException, ServletException {
47
48 logger.info("========== MCP FILTER DOFILTER CALLED ==========")
49
50 if (request instanceof HttpServletRequest && response instanceof HttpServletResponse) {
51 HttpServletRequest httpRequest = (HttpServletRequest) request
52 HttpServletResponse httpResponse = (HttpServletResponse) response
53
54 // Check if this is an MCP request
55 String path = httpRequest.getRequestURI()
56 logger.info("========== MCP FILTER PATH: {} ==========", path)
57
58 if (path != null && path.contains("/mcpservlet")) {
59 logger.info("========== MCP FILTER HANDLING REQUEST ==========")
60 try {
61 // Handle MCP request directly, don't continue chain
62 mcpServlet.service(httpRequest, httpResponse)
63 return
64 } catch (Exception e) {
65 logger.error("Error in MCP filter", e)
66 // Send error response directly
67 httpResponse.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)
68 httpResponse.setContentType("application/json")
69 httpResponse.writer.write(groovy.json.JsonOutput.toJson([
70 jsonrpc: "2.0",
71 error: [code: -32603, message: "Internal error: " + e.message],
72 id: null
73 ]))
74 return
75 }
76 }
77 }
78
79 // Not an MCP request, continue chain
80 chain.doFilter(request, response)
81 }
82
83 @Override
84 void destroy() {
85 mcpServlet.destroy()
86 logger.info("McpFilter destroyed")
87 }
88 }
...\ No newline at end of file ...\ No newline at end of file
1 <?xml version="1.0" encoding="UTF-8"?>
2 <!--
3 This software is in the public domain under CC0 1.0 Universal plus a
4 Grant of Patent License.
5
6 To the extent possible under law, author(s) have dedicated all
7 copyright and related and neighboring rights to this software to the
8 public domain worldwide. This software is distributed without any
9 warranty.
10
11 You should have received a copy of the CC0 Public Domain Dedication
12 along with this software (see the LICENSE.md file). If not, see
13 <http://creativecommons.org/publicdomain/zero/1.0/>.
14 -->
15
16 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
17 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
18 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
19 http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
20 version="4.0">
21
22 <!-- Service-Based MCP Servlet Configuration -->
23 <servlet>
24 <servlet-name>ServiceBasedMcpServlet</servlet-name>
25 <servlet-class>org.moqui.mcp.ServiceBasedMcpServlet</servlet-class>
26
27 <!-- Configuration Parameters -->
28 <init-param>
29 <param-name>sseEndpoint</param-name>
30 <param-value>/sse</param-value>
31 </init-param>
32 <init-param>
33 <param-name>messageEndpoint</param-name>
34 <param-value>/mcp/message</param-value>
35 </init-param>
36 <init-param>
37 <param-name>keepAliveIntervalSeconds</param-name>
38 <param-value>30</param-value>
39 </init-param>
40 <init-param>
41 <param-name>maxConnections</param-name>
42 <param-value>100</param-value>
43 </init-param>
44
45 <!-- Enable async support for SSE -->
46 <async-supported>true</async-supported>
47
48 <!-- Load on startup -->
49 <load-on-startup>5</load-on-startup>
50 </servlet>
51
52 <!-- Servlet Mappings -->
53 <servlet-mapping>
54 <servlet-name>ServiceBasedMcpServlet</servlet-name>
55 <url-pattern>/sse/*</url-pattern>
56 </servlet-mapping>
57
58 <servlet-mapping>
59 <servlet-name>ServiceBasedMcpServlet</servlet-name>
60 <url-pattern>/mcp/message/*</url-pattern>
61 </servlet-mapping>
62
63 <servlet-mapping>
64 <servlet-name>ServiceBasedMcpServlet</servlet-name>
65 <url-pattern>/rpc/*</url-pattern>
66 </servlet-mapping>
67
68 <!-- Session Configuration -->
69 <session-config>
70 <session-timeout>30</session-timeout>
71 <cookie-config>
72 <http-only>true</http-only>
73 <secure>false</secure>
74 </cookie-config>
75 </session-config>
76
77 <!-- Security Constraints (optional - uncomment if needed) -->
78 <!--
79 <security-constraint>
80 <web-resource-collection>
81 <web-resource-name>MCP Endpoints</web-resource-name>
82 <url-pattern>/sse/*</url-pattern>
83 <url-pattern>/mcp/message/*</url-pattern>
84 <url-pattern>/rpc/*</url-pattern>
85 </web-resource-collection>
86 <auth-constraint>
87 <role-name>admin</role-name>
88 </auth-constraint>
89 </security-constraint>
90
91 <login-config>
92 <auth-method>BASIC</auth-method>
93 <realm-name>Moqui MCP</realm-name>
94 </login-config>
95 -->
96
97 <!-- MIME Type Mappings -->
98 <mime-mapping>
99 <extension>json</extension>
100 <mime-type>application/json</mime-type>
101 </mime-mapping>
102
103 <!-- Default Welcome Files -->
104 <welcome-file-list>
105 <welcome-file>index.html</welcome-file>
106 <welcome-file>index.jsp</welcome-file>
107 </welcome-file-list>
108
109 </web-app>
...\ No newline at end of file ...\ No newline at end of file
1 <?xml version="1.0" encoding="UTF-8"?>
2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
5 http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
6 version="4.0">
7
8 <!-- MCP SDK Services Servlet Configuration -->
9 <servlet>
10 <servlet-name>McpSdkServicesServlet</servlet-name>
11 <servlet-class>org.moqui.mcp.McpSdkServicesServlet</servlet-class>
12
13 <!-- Configuration parameters -->
14 <init-param>
15 <param-name>moqui-name</param-name>
16 <param-value>moqui-mcp-2</param-value>
17 </init-param>
18
19 <!-- Enable async support (required for SSE) -->
20 <async-supported>true</async-supported>
21
22 <!-- Load on startup to initialize MCP server -->
23 <load-on-startup>1</load-on-startup>
24 </servlet>
25
26 <!-- Servlet mappings for MCP SDK Services endpoints -->
27 <!-- The MCP SDK will handle both SSE and message endpoints through this servlet -->
28 <servlet-mapping>
29 <servlet-name>McpSdkServicesServlet</servlet-name>
30 <url-pattern>/mcp/*</url-pattern>
31 </servlet-mapping>
32
33 <!-- Session configuration -->
34 <session-config>
35 <session-timeout>30</session-timeout>
36 <cookie-config>
37 <http-only>true</http-only>
38 <secure>false</secure>
39 </cookie-config>
40 </session-config>
41
42 </web-app>
...\ No newline at end of file ...\ No newline at end of file
1 <?xml version="1.0" encoding="UTF-8"?>
2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
5 http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
6 version="4.0">
7
8 <!-- MCP SDK SSE Servlet Configuration -->
9 <servlet>
10 <servlet-name>McpSdkSseServlet</servlet-name>
11 <servlet-class>org.moqui.mcp.McpSdkSseServlet</servlet-class>
12
13 <!-- Configuration parameters -->
14 <init-param>
15 <param-name>moqui-name</param-name>
16 <param-value>moqui-mcp-2</param-value>
17 </init-param>
18
19 <!-- Enable async support (required for SSE) -->
20 <async-supported>true</async-supported>
21
22 <!-- Load on startup to initialize MCP server -->
23 <load-on-startup>1</load-on-startup>
24 </servlet>
25
26 <!-- Servlet mappings for MCP SDK SSE endpoints -->
27 <!-- The MCP SDK will handle both SSE and message endpoints through this servlet -->
28 <servlet-mapping>
29 <servlet-name>McpSdkSseServlet</servlet-name>
30 <url-pattern>/mcp/*</url-pattern>
31 </servlet-mapping>
32
33 <!-- Session configuration -->
34 <session-config>
35 <session-timeout>30</session-timeout>
36 <cookie-config>
37 <http-only>true</http-only>
38 <secure>false</secure>
39 </cookie-config>
40 </session-config>
41
42 </web-app>
...\ No newline at end of file ...\ No newline at end of file
1 <?xml version="1.0" encoding="UTF-8"?>
2 <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
5 http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
6 version="4.0">
7
8 <!-- MCP SSE Servlet Configuration -->
9 <servlet>
10 <servlet-name>McpSseServlet</servlet-name>
11 <servlet-class>org.moqui.mcp.McpSseServlet</servlet-class>
12
13 <!-- Configuration parameters -->
14 <init-param>
15 <param-name>moqui-name</param-name>
16 <param-value>moqui-mcp-2</param-value>
17 </init-param>
18
19 <init-param>
20 <param-name>sseEndpoint</param-name>
21 <param-value>/sse</param-value>
22 </init-param>
23
24 <init-param>
25 <param-name>messageEndpoint</param-name>
26 <param-value>/mcp/message</param-value>
27 </init-param>
28
29 <init-param>
30 <param-name>keepAliveIntervalSeconds</param-name>
31 <param-value>30</param-value>
32 </init-param>
33
34 <init-param>
35 <param-name>maxConnections</param-name>
36 <param-value>100</param-value>
37 </init-param>
38
39 <!-- Enable async support -->
40 <async-supported>true</async-supported>
41 </servlet>
42
43 <!-- Servlet mappings for MCP SSE endpoints -->
44 <servlet-mapping>
45 <servlet-name>McpSseServlet</servlet-name>
46 <url-pattern>/sse/*</url-pattern>
47 </servlet-mapping>
48
49 <servlet-mapping>
50 <servlet-name>McpSseServlet</servlet-name>
51 <url-pattern>/mcp/message/*</url-pattern>
52 </servlet-mapping>
53
54 <!-- Session configuration -->
55 <session-config>
56 <session-timeout>30</session-timeout>
57 <cookie-config>
58 <http-only>true</http-only>
59 <secure>false</secure>
60 </cookie-config>
61 </session-config>
62
63 </web-app>
...\ No newline at end of file ...\ No newline at end of file