cf4f3125 by Ean Schuessler

WIP Servlet 4 MCP

1 parent fc1526cc
......@@ -11,52 +11,13 @@
<https://creativecommons.org/publicdomain/zero/1.0/>. -->
<component xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/component-definition-3.xsd"
name="moqui-mcp-2">
<!-- MCP SDK dependencies -->
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp</artifactId>
<version>0.16.0</version>
</dependency>
<dependency>
<groupId>io.modelcontextprotocol.sdk</groupId>
<artifactId>mcp-core</artifactId>
<version>0.16.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.15.2</version>
</dependency>
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.5.10</version>
</dependency>
xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/moqui-conf-3.xsd"
name="moqui-mcp-2" version="1.0.0">
<entity-factory load-path="entity/" />
<service-factory load-path="service/" />
<!-- <screen-factory load-path="screen/" /> -->
<!-- Load seed data -->
<entity-factory load-data="data/McpSecuritySeedData.xml" />
<!-- Register MCP filter
<webapp-list>
<webapp name="webroot">
<filter name="McpFilter" class="org.moqui.mcp.McpFilter">
<url-pattern>/mcpservlet/*</url-pattern>
</filter>
</webapp>
</webapp-list> -->
</component>
......
......@@ -22,7 +22,6 @@
<moqui.security.ArtifactGroup artifactGroupId="McpScreenTransitions" description="MCP Screen Transitions"/>
<!-- MCP Artifact Group Members -->
<moqui.security.ArtifactGroupMember artifactGroupId="McpServices" artifactName="mo-mcp.mo-mcp.*" artifactTypeEnumId="AT_SERVICE"/>
<moqui.security.ArtifactGroupMember artifactGroupId="McpServices" artifactName="McpServices.*" artifactTypeEnumId="AT_SERVICE"/>
<moqui.security.ArtifactGroupMember artifactGroupId="McpServices" artifactName="McpServices.mcp#Ping" artifactTypeEnumId="AT_SERVICE"/>
<moqui.security.ArtifactGroupMember artifactGroupId="McpServices" artifactName="McpServices.handle#McpRequest" artifactTypeEnumId="AT_SERVICE"/>
......@@ -31,10 +30,8 @@
<moqui.security.ArtifactGroupMember artifactGroupId="McpServices" artifactName="McpServices.mcp#ToolsCall" artifactTypeEnumId="AT_SERVICE"/>
<moqui.security.ArtifactGroupMember artifactGroupId="McpServices" artifactName="McpServices.mcp#ResourcesList" artifactTypeEnumId="AT_SERVICE"/>
<moqui.security.ArtifactGroupMember artifactGroupId="McpServices" artifactName="McpServices.mcp#ResourcesRead" artifactTypeEnumId="AT_SERVICE"/>
<moqui.security.ArtifactGroupMember artifactGroupId="McpRestPaths" artifactName="/mcp/rpc" artifactTypeEnumId="AT_REST_PATH"/>
<moqui.security.ArtifactGroupMember artifactGroupId="McpRestPaths" artifactName="/mcp/rpc/*" artifactTypeEnumId="AT_REST_PATH"/>
<moqui.security.ArtifactGroupMember artifactGroupId="McpScreenTransitions" artifactName="component://moqui-mcp-2/screen/webroot/mcp.xml/rpc" artifactTypeEnumId="AT_XML_SCREEN_TRANS"/>
<moqui.security.ArtifactGroupMember artifactGroupId="McpScreenTransitions" artifactName="component://moqui-mcp-2/screen/webroot/mcp.xml" artifactTypeEnumId="AT_XML_SCREEN"/>
<moqui.security.ArtifactGroupMember artifactGroupId="McpRestPaths" artifactName="/mcp" artifactTypeEnumId="AT_REST_PATH"/>
<moqui.security.ArtifactGroupMember artifactGroupId="McpRestPaths" artifactName="/mcp/*" artifactTypeEnumId="AT_REST_PATH"/>
<!-- MCP Artifact Authz -->
<moqui.security.ArtifactAuthz userGroupId="McpUser" artifactGroupId="McpServices" authzTypeEnumId="AUTHZT_ALLOW" authzActionEnumId="AUTHZA_ALL"/>
......
......@@ -258,8 +258,8 @@
def userAccountId = userId ? userId : null
// Get user-specific tools and resources
def toolsResult = ec.service.sync().name("org.moqui.mcp.McpServices.mcp#ToolsList").parameters([:]).call()
def resourcesResult = ec.service.sync().name("org.moqui.mcp.McpServices.mcp#ResourcesList").parameters([:]).call()
def toolsResult = ec.service.sync().name("McpServices.mcp#ToolsList").parameters([:]).call()
def resourcesResult = ec.service.sync().name("McpServices.mcp#ResourcesList").parameters([:]).call()
// Build server capabilities based on what user can access
def serverCapabilities = [
......
......@@ -22,7 +22,7 @@ import org.slf4j.Logger
import org.slf4j.LoggerFactory
import javax.servlet.AsyncContext
import javax.servlet.AsyncContextListener
import javax.servlet.AsyncListener
import javax.servlet.AsyncEvent
import javax.servlet.ServletConfig
import javax.servlet.ServletException
......@@ -205,7 +205,7 @@ class ServiceBasedMcpServlet extends HttpServlet {
])
// Set up connection close handling
asyncContext.addListener(new AsyncContextListener() {
asyncContext.addListener(new AsyncListener() {
@Override
void onComplete(AsyncEvent event) throws IOException {
sseConnections.remove(sessionId)
......
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- MCP SDK Services Servlet Configuration -->
<servlet>
<servlet-name>McpSdkServicesServlet</servlet-name>
<servlet-class>org.moqui.mcp.McpSdkServicesServlet</servlet-class>
<!-- Configuration parameters -->
<init-param>
<param-name>moqui-name</param-name>
<param-value>moqui-mcp-2</param-value>
</init-param>
<!-- Enable async support (required for SSE) -->
<async-supported>true</async-supported>
<!-- Load on startup to initialize MCP server -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Servlet mappings for MCP SDK Services endpoints -->
<!-- The MCP SDK will handle both SSE and message endpoints through this servlet -->
<servlet-mapping>
<servlet-name>McpSdkServicesServlet</servlet-name>
<url-pattern>/mcp/*</url-pattern>
</servlet-mapping>
<!-- Session configuration -->
<session-config>
<session-timeout>30</session-timeout>
<cookie-config>
<http-only>true</http-only>
<secure>false</secure>
</cookie-config>
</session-config>
</web-app>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- MCP SDK SSE Servlet Configuration -->
<servlet>
<servlet-name>McpSdkSseServlet</servlet-name>
<servlet-class>org.moqui.mcp.McpSdkSseServlet</servlet-class>
<!-- Configuration parameters -->
<init-param>
<param-name>moqui-name</param-name>
<param-value>moqui-mcp-2</param-value>
</init-param>
<!-- Enable async support (required for SSE) -->
<async-supported>true</async-supported>
<!-- Load on startup to initialize MCP server -->
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Servlet mappings for MCP SDK SSE endpoints -->
<!-- The MCP SDK will handle both SSE and message endpoints through this servlet -->
<servlet-mapping>
<servlet-name>McpSdkSseServlet</servlet-name>
<url-pattern>/mcp/*</url-pattern>
</servlet-mapping>
<!-- Session configuration -->
<session-config>
<session-timeout>30</session-timeout>
<cookie-config>
<http-only>true</http-only>
<secure>false</secure>
</cookie-config>
</session-config>
</web-app>
\ No newline at end of file