643b4b58 by Ean Schuessler

Committing WIP

1 parent 8ad686a8
1 # Moqui MCP v2 Server Agent Guide
2
3 This guide explains how to interact with the Moqui MCP v2 server component for AI-Moqui integration using the Model Context Protocol (MCP).
4
5 ## Architecture Overview
6
7 ```
8 moqui-mcp-2/
9 ├── AGENTS.md # This file - MCP server agent guide
10 ├── component.xml # Component configuration
11 ├── entity/ # MCP entity definitions
12 │ └── McpCoreEntities.xml # Core MCP entities
13 ├── service/ # MCP service implementations
14 │ ├── McpDiscoveryServices.xml # Tool discovery services
15 │ ├── McpExecutionServices.xml # Tool execution services
16 │ ├── McpSecurityServices.xml # Session/security services
17 │ └── mcp.rest.xml # REST API endpoints
18 ├── screen/ # Web interface screens
19 │ └── webapp.xml # MCP web interface
20 └── template/ # UI templates
21 └── McpInfo.html.ftl # MCP info page
22 ```
23
24 ## MCP Server Capabilities
25
26 ### Core Features
27 - **Session Management**: Secure session creation, validation, and termination
28 - **Tool Discovery**: Dynamic discovery of available Moqui services and entities
29 - **Tool Execution**: Secure execution of services with proper authorization
30 - **Entity Operations**: Direct entity query capabilities with permission checks
31 - **Health Monitoring**: Server health and status monitoring
32
33 ### Security Model
34 - **Session-based Authentication**: Uses Moqui's built-in user authentication
35 - **Context Tokens**: Secure token-based session validation
36 - **Permission Validation**: All operations checked against Moqui security framework
37 - **Audit Logging**: Complete audit trail of all MCP operations
38
39 ## REST API Endpoints
40
41 ### Session Management
42 ```
43 POST /mcp-2/session
44 - Create new MCP session
45 - Parameters: username, password, clientInfo, ipAddress, userAgent
46 - Returns: sessionId, contextToken, expiration
47
48 POST /mcp-2/session/{visitId}/validate
49 - Validate existing session
50 - Parameters: visitId (from path), contextToken
51 - Returns: session validity, user info
52
53 POST /mcp-2/session/{visitId}/terminate
54 - Terminate active session
55 - Parameters: visitId (from path), contextToken
56 - Returns: termination confirmation
57 ```
58
59 ### Tool Discovery
60 ```
61 POST /mcp-2/tools/discover
62 - Discover available MCP tools
63 - Parameters: userAccountId, visitId, servicePattern, packageName, verb, noun
64 - Returns: List of available tools with metadata
65
66 POST /mcp-2/tools/validate
67 - Validate access to specific tools
68 - Parameters: userAccountId, serviceNames, visitId
69 - Returns: Access validation results
70 ```
71
72 ### Tool Execution
73 ```
74 POST /mcp-2/tools/execute
75 - Execute service as MCP tool
76 - Parameters: sessionId, contextToken, serviceName, parameters, toolCallId
77 - Returns: Service execution results
78
79 POST /mcp-2/tools/entity/query
80 - Execute entity query as MCP tool
81 - Parameters: sessionId, contextToken, serviceName, parameters, toolCallId
82 - Returns: Entity query results
83 ```
84
85 ### Health Check
86 ```
87 GET /mcp-2/health
88 - Server health status
89 - Returns: Server status, version, available endpoints
90 ```
91
92 ## Agent Integration Patterns
93
94 ### 1. Session Initialization
95 ```bash
96 # Create session
97 curl -X POST http://localhost:8080/mcp-2/session \
98 -H "Content-Type: application/json" \
99 -d '{
100 "username": "admin",
101 "password": "admin",
102 "clientInfo": "AI-Agent-v1.0"
103 }'
104
105 # Response: { "sessionId": "12345", "contextToken": "abc123", "expires": "2025-01-01T00:00:00Z" }
106 ```
107
108 ### 2. Tool Discovery Workflow
109 ```bash
110 # Discover available tools
111 curl -X POST http://localhost:8080/mcp-2/tools/discover \
112 -H "Content-Type: application/json" \
113 -H "Authorization: Bearer abc123" \
114 -d '{
115 "userAccountId": "ADMIN",
116 "visitId": "12345",
117 "servicePattern": "org.moqui.*"
118 }'
119
120 # Response: { "tools": [ { "name": "create#Order", "description": "...", "parameters": [...] } ] }
121 ```
122
123 ### 3. Tool Execution Pattern
124 ```bash
125 # Execute a service
126 curl -X POST http://localhost:8080/mcp-2/tools/execute \
127 -H "Content-Type: application/json" \
128 -H "Authorization: Bearer abc123" \
129 -d '{
130 "sessionId": "12345",
131 "contextToken": "abc123",
132 "serviceName": "org.moqui.example.Services.create#Example",
133 "parameters": { "field1": "value1", "field2": "value2" },
134 "toolCallId": "call_123"
135 }'
136
137 # Response: { "result": { "exampleId": "EX123" }, "success": true }
138 ```
139
140 ## Security Considerations
141
142 ### Authentication Requirements
143 - All MCP operations require valid session authentication
144 - Context tokens must be included in all requests after session creation
145 - Sessions expire based on configured timeout settings
146
147 ### Permission Validation
148 - Tool access validated against Moqui user permissions
149 - Entity operations respect Moqui entity access controls
150 - Service execution requires appropriate service permissions
151
152 ### Audit and Logging
153 - All MCP operations logged to Moqui audit system
154 - Session creation, tool discovery, and execution tracked
155 - Failed authentication attempts monitored
156
157 ## Error Handling
158
159 ### Common Error Responses
160 ```json
161 {
162 "error": "INVALID_SESSION",
163 "message": "Session expired or invalid",
164 "code": 401
165 }
166
167 {
168 "error": "PERMISSION_DENIED",
169 "message": "User lacks permission for tool",
170 "code": 403
171 }
172
173 {
174 "error": "TOOL_NOT_FOUND",
175 "message": "Requested tool not available",
176 "code": 404
177 }
178 ```
179
180 ### Error Recovery Strategies
181 - **Session Expiration**: Re-authenticate and create new session
182 - **Permission Issues**: Request additional permissions or use alternative tools
183 - **Tool Not Found**: Re-discover available tools and update tool registry
184
185 ## Performance Optimization
186
187 ### Caching Strategies
188 - Tool discovery results cached for session duration
189 - Permission validation results cached per user
190 - Entity query results cached based on Moqui cache settings
191
192 ### Connection Management
193 - Use persistent HTTP connections where possible
194 - Implement session pooling for high-frequency operations
195 - Monitor session lifecycle and cleanup expired sessions
196
197 ## Integration Examples
198
199 ### Python Client Example
200 ```python
201 import requests
202 import json
203
204 class MoquiMCPClient:
205 def __init__(self, base_url, username, password):
206 self.base_url = base_url
207 self.session_id = None
208 self.context_token = None
209 self.authenticate(username, password)
210
211 def authenticate(self, username, password):
212 response = requests.post(f"{self.base_url}/mcp-2/session", json={
213 "username": username,
214 "password": password
215 })
216 data = response.json()
217 self.session_id = data["sessionId"]
218 self.context_token = data["contextToken"]
219
220 def discover_tools(self, pattern="*"):
221 response = requests.post(f"{self.base_url}/mcp-2/tools/discover",
222 headers={"Authorization": f"Bearer {self.context_token}"},
223 json={"servicePattern": pattern}
224 )
225 return response.json()
226
227 def execute_tool(self, service_name, parameters):
228 response = requests.post(f"{self.base_url}/mcp-2/tools/execute",
229 headers={"Authorization": f"Bearer {self.context_token}"},
230 json={
231 "sessionId": self.session_id,
232 "contextToken": self.context_token,
233 "serviceName": service_name,
234 "parameters": parameters
235 }
236 )
237 return response.json()
238 ```
239
240 ### JavaScript Client Example
241 ```javascript
242 class MoquiMCPClient {
243 constructor(baseUrl, username, password) {
244 this.baseUrl = baseUrl;
245 this.authenticate(username, password);
246 }
247
248 async authenticate(username, password) {
249 const response = await fetch(`${this.baseUrl}/mcp-2/session`, {
250 method: 'POST',
251 headers: { 'Content-Type': 'application/json' },
252 body: JSON.stringify({ username, password })
253 });
254 const data = await response.json();
255 this.sessionId = data.sessionId;
256 this.contextToken = data.contextToken;
257 }
258
259 async discoverTools(pattern = '*') {
260 const response = await fetch(`${this.baseUrl}/mcp-2/tools/discover`, {
261 method: 'POST',
262 headers: {
263 'Content-Type': 'application/json',
264 'Authorization': `Bearer ${this.contextToken}`
265 },
266 body: JSON.stringify({ servicePattern: pattern })
267 });
268 return response.json();
269 }
270
271 async executeTool(serviceName, parameters) {
272 const response = await fetch(`${this.baseUrl}/mcp-2/tools/execute`, {
273 method: 'POST',
274 headers: {
275 'Content-Type': 'application/json',
276 'Authorization': `Bearer ${this.contextToken}`
277 },
278 body: JSON.stringify({
279 sessionId: this.sessionId,
280 contextToken: this.contextToken,
281 serviceName,
282 parameters
283 })
284 });
285 return response.json();
286 }
287 }
288 ```
289
290 ## Monitoring and Debugging
291
292 ### Health Monitoring
293 - Monitor `/mcp-2/health` endpoint for server status
294 - Track session creation and termination rates
295 - Monitor tool execution success/failure rates
296
297 ### Debug Information
298 - Check Moqui logs for MCP-related errors
299 - Use Moqui's built-in monitoring tools
300 - Monitor REST API access patterns
301
302 ### Performance Metrics
303 - Session creation time
304 - Tool discovery response time
305 - Tool execution duration
306 - Concurrent session limits
307
308 ## Configuration
309
310 ### Component Configuration
311 - Session timeout settings in `component.xml`
312 - Security permission mappings
313 - Cache configuration for performance
314
315 ### Runtime Configuration
316 - Database connection settings
317 - REST API endpoint configuration
318 - Security context configuration
319
320 ---
321
322 **This guide focuses on MCP server interaction patterns and agent integration.**
323 For Moqui framework integration details, see the main project AGENTS.md files.
324 For component-specific implementation details, refer to individual service files.
...\ No newline at end of file ...\ No newline at end of file
1 # Moqui MCP Server v0.2.0
2
3 ## Overview
4 Simplified MCP server that uses Moqui's native service engine directly, eliminating need for manual tool registry management.
5
6 ## Evolution from v0.1.0 (moqui-mcp) to v0.2.0 (moqui-mcp-2)
7
8 ### Architectural Problems Identified in v0.1.0
9
10 The original moqui-mcp implementation had significant architectural duplications with Moqui's native systems:
11
12 1. **McpToolRegistry vs Service Engine**
13 - Manual tool registry duplicated Moqui's service discovery
14 - Required manual maintenance of tool definitions
15 - Added unnecessary database queries and complexity
16
17 2. **McpAuditLog vs ArtifactHit**
18 - Custom audit logging duplicated Moqui's proven ArtifactHit system
19 - Missed built-in performance monitoring and aggregation
20 - Separate audit trail instead of unified system-wide analytics
21
22 3. **McpSession vs Visit Entity**
23 - Custom session management duplicated Moqui's Visit entity
24 - Lost geo-location, referrer tracking, and other built-in features
25 - Separate session lifecycle instead of leveraging existing patterns
26
27 4. **McpToolCall vs ArtifactHit**
28 - Custom tool call tracking duplicated ArtifactHit functionality
29 - Manual performance tracking instead of automatic aggregation
30 - Separate error handling and logging
31
32 ### v0.2.0 Architectural Solutions
33
34 **Complete Elimination of Duplications**:
35 - ❌ McpToolRegistry → ✅ Service Engine (`ec.service.getServiceNames()`)
36 - ❌ McpAuditLog → ✅ ArtifactHit (native audit & performance)
37 - ❌ McpSession → ✅ Visit Entity (extended with MCP fields)
38 - ❌ McpToolCall → ✅ ArtifactHit (with `artifactType="MCP"`)
39
40 **Key Architectural Changes**:
41
42 1. **Native Service Discovery**
43 ```groovy
44 // Before: Query McpToolRegistry
45 def tools = ec.entity.find("McpToolRegistry").list()
46
47 // After: Direct service engine access
48 def allServiceNames = ec.service.getServiceNames()
49 def hasPermission = ec.service.hasPermission(serviceName)
50 ```
51
52 2. **Unified Session Management**
53 ```xml
54 <!-- Before: Custom McpSession entity -->
55 <entity entity-name="McpSession" package="org.moqui.mcp">
56
57 <!-- After: Extend native Visit entity -->
58 <extend-entity entity-name="Visit" package="moqui.server">
59 <field name="mcpContextToken" type="text-medium"/>
60 <field name="mcpStatusId" type="id"/>
61 <field name="mcpExpiresDate" type="date-time"/>
62 </extend-entity>
63 ```
64
65 3. **System-Wide Analytics**
66 ```sql
67 -- Before: Separate MCP tracking
68 SELECT * FROM McpToolCall ORDER BY startTime DESC;
69 SELECT * FROM McpAuditLog WHERE severity = 'McpSeverityWarning';
70
71 -- After: Unified system tracking
72 SELECT * FROM moqui.server.ArtifactHit
73 WHERE artifactType = 'MCP' ORDER BY startDateTime DESC;
74 SELECT * FROM moqui.server.ArtifactHitReport
75 WHERE artifactType = 'MCP';
76 ```
77
78 ### Benefits Achieved
79
80 **Zero Maintenance**:
81 - No manual tool registry updates
82 - Automatic reflection of actual Moqui services
83 - No custom audit infrastructure to maintain
84
85 **Maximum Performance**:
86 - Direct service engine access (no extra lookups)
87 - Native caching and optimization
88 - Built-in performance monitoring
89
90 **Unified Analytics**:
91 - MCP operations visible in system-wide reports
92 - Automatic aggregation via ArtifactHitBin
93 - Standard reporting tools and dashboards
94
95 **Architectural Purity**:
96 - Follows Moqui's established patterns
97 - Leverages proven native systems
98 - REST service pattern (MCP as service invocation layer)
99
100 ### Technical Implementation
101
102 **MCP Operation Flow**:
103 1. Session creation `Visit` record with MCP extensions
104 2. Tool discovery `ec.service.getServiceNames()` + permission check
105 3. Tool execution Direct service call + `ArtifactHit` creation
106 4. Analytics Native `ArtifactHitReport` aggregation
107
108 **Data Model**:
109 - Sessions: `moqui.server.Visit` (extended)
110 - Operations: `moqui.server.ArtifactHit` (filtered)
111 - Performance: `moqui.server.ArtifactHitBin` (automatic)
112 - Security: `moqui.security.UserGroupPermission` (native)
113
114 This evolution represents a complete architectural alignment with Moqui's core design principles while maintaining full MCP functionality.
115
116 ## Quick Start
117
118 ### 1. Add Component to Moqui
119 Add to your `MoquiConf.xml`:
120 ```xml
121 <component name="moqui-mcp-2" location="moqui-mcp-2/"/>
122 ```
123
124 ### 2. Start Moqui
125 ```bash
126 ./gradlew run
127 ```
128
129 ### 3. Test MCP Server
130 ```bash
131 # Health check
132 curl http://localhost:8080/mcp-2/health
133
134 # Create session
135 curl -X POST http://localhost:8080/mcp-2/session \
136 -H "Content-Type: application/json" \
137 -d '{"username": "admin", "password": "admin"}'
138 ```
139
140 ## Integration with Opencode
141
142 ### MCP Skill Configuration
143 Add to your Opencode configuration:
144
145 ```json
146 {
147 "skills": [
148 {
149 "name": "moqui-mcp",
150 "type": "mcp",
151 "endpoint": "http://localhost:8080/mcp-2",
152 "auth": {
153 "type": "session",
154 "username": "admin",
155 "password": "admin"
156 },
157 "description": "Query business data from Moqui ERP system"
158 }
159 ]
160 }
161 ```
162
163 ### Example Business Questions
164 Once configured, you can ask:
165
166 - "Show me all active customers"
167 - "What are recent orders for ACME Corp?"
168 - "List all products in inventory"
169 - "Find unpaid invoices"
170 - "Show user accounts with admin permissions"
171
172 ## API Endpoints
173
174 ### Session Management
175 - `POST /session` - Create session
176 - `POST /session/{visitId}/validate` - Validate session
177 - `POST /session/{visitId}/terminate` - Terminate session
178
179 ### Tool Operations
180 - `POST /tools/discover` - Discover available tools
181 - `POST /tools/validate` - Validate tool access
182 - `POST /tools/execute` - Execute service tool
183 - `POST /tools/entity/query` - Execute entity query
184
185 ### System
186 - `GET /health` - Server health check
187
188 ## Security Model
189
190 ### Permission-Based Access
191 Tools are discovered based on user's `UserGroupPermission` settings:
192 - Services: `ec.service.hasPermission(serviceName)`
193 - Entities: `ec.user.hasPermission("entity:EntityName", "VIEW")`
194
195 ### Audit Trail
196 All operations are tracked via Moqui's native `ArtifactHit` system:
197 - Automatic performance monitoring
198 - Built-in security event tracking
199 - Configurable persistence (database/ElasticSearch)
200 - Standard reporting via `ArtifactHitReport`
201
202 ## Monitoring
203
204 ### Check Logs
205 ```bash
206 # MCP operations
207 tail -f moqui.log | grep "MCP"
208
209 # Session activity
210 tail -f moqui.log | grep "Visit"
211 ```
212
213 ### Database Queries
214 ```sql
215 -- MCP operations via ArtifactHit
216 SELECT * FROM moqui.server.ArtifactHit
217 WHERE artifactType = 'MCP'
218 ORDER BY startDateTime DESC LIMIT 10;
219
220 -- MCP sessions (using Visit entity)
221 SELECT * FROM moqui.server.Visit
222 WHERE mcpStatusId = 'McsActive' AND webappName = 'mcp-2';
223
224 -- MCP service operations
225 SELECT * FROM moqui.server.ArtifactHit
226 WHERE artifactType = 'MCP' AND artifactSubType = 'Service'
227 ORDER BY startDateTime DESC LIMIT 10;
228
229 -- MCP entity operations
230 SELECT * FROM moqui.server.ArtifactHit
231 WHERE artifactType = 'MCP' AND artifactSubType = 'Entity'
232 ORDER BY startDateTime DESC LIMIT 10;
233
234 -- Performance analytics
235 SELECT * FROM moqui.server.ArtifactHitReport
236 WHERE artifactType = 'MCP';
237 ```
238
239 ## Next Steps
240
241 1. **Test Basic Functionality**: Verify session creation and tool discovery
242 2. **Configure Opencode Skill**: Add MCP skill to your Opencode instance
243 3. **Test Business Queries**: Try natural language business questions
244 4. **Monitor Performance**: Check logs and audit tables
245 5. **Extend as Needed**: Add custom services/entities for specific business logic
246
247 ## Architecture Benefits
248
249 - **Zero Maintenance**: No manual tool registry updates
250 - **Always Current**: Reflects actual Moqui services in real-time
251 - **Secure**: Uses Moqui's proven permission system
252 - **Performant**: Direct service engine access, no extra lookups
253 - **Unified Analytics**: All MCP operations tracked via native ArtifactHit
254 - **Built-in Reporting**: Uses ArtifactHitReport for standard analytics
255 - **Native Session Management**: Uses Moqui's Visit entity for session tracking
256 - **REST Service Pattern**: MCP is fundamentally a REST service invocation layer
257 - **Zero Custom Tracking**: Eliminates McpToolCall duplication with ArtifactHit
258
259 This MVP provides core functionality needed to integrate Moqui with Opencode as an MCP skill for business intelligence queries.
...\ No newline at end of file ...\ No newline at end of file
1 // Moqui MCP v2 Component Build File
2 // Minimal dependencies - depends only on moqui framework
3
4 // No additional repositories or dependencies needed
5 // All functionality uses native Moqui framework capabilities
...\ No newline at end of file ...\ No newline at end of file
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, 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 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 <component xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
14 xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/component-definition-3.xsd">
15
16 <!-- No dependencies - uses only core framework -->
17
18 <entity-factory load-path="entity/" />
19 <service-factory load-path="service/" />
20 <screen-factory load-path="screen/" />
21
22 <!-- Load seed data -->
23 <entity-factory load-data="data/McpSecuritySeedData.xml" />
24
25
26 <webapp name="mcp-2"
27 title="MCP Server v2"
28 server="default"
29 location="webapp"
30 https-enabled="false"
31 require-session-token="false">
32 <root-screen host=".*" screen-path="mcp-2"/>
33 </webapp>
34
35
36
37 </component>
...\ No newline at end of file ...\ No newline at end of file
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, 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 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 <entity-facade-xml xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
14 xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/entity-facade-3.xsd">
15
16 <!-- MCP User Group -->
17 <moqui.security.UserGroup userGroupId="McpUser" description="MCP Server Users"/>
18
19 <!-- MCP Artifact Groups -->
20 <moqui.security.ArtifactGroup artifactGroupId="McpRestPaths" description="MCP REST Paths"/>
21 <moqui.security.ArtifactGroup artifactGroupId="McpServices" description="MCP Services"/>
22
23 <!-- MCP Artifact Group Members -->
24 <moqui.security.ArtifactGroupMember artifactGroupId="McpRestPaths" artifactName="/rest/s1/mcp-2" artifactTypeEnumId="AT_REST_PATH"/>
25 <moqui.security.ArtifactGroupMember artifactGroupId="McpRestPaths" artifactName="/rest/s1/mcp-2/*" artifactTypeEnumId="AT_REST_PATH"/>
26 <moqui.security.ArtifactGroupMember artifactGroupId="McpServices" artifactName="org.moqui.mcp.*" artifactTypeEnumId="AT_SERVICE"/>
27
28 <!-- MCP Artifact Authz -->
29 <moqui.security.ArtifactAuthz userGroupId="McpUser" artifactGroupId="McpRestPaths" authzTypeEnumId="AUTHZT_ALLOW" authzActionEnumId="AUTHZA_ALL"/>
30 <moqui.security.ArtifactAuthz userGroupId="McpUser" artifactGroupId="McpServices" authzTypeEnumId="AUTHZT_ALLOW" authzActionEnumId="AUTHZA_ALL"/>
31
32 <!-- Add john.doe to MCP user group -->
33 <moqui.security.UserGroupMember userGroupId="McpUser" userId="JOHN_DOE" fromDate="2025-01-01 00:00:00.000"/>
34
35 <!-- Add MCP user to MCP user group -->
36 <moqui.security.UserGroupMember userGroupId="McpUser" userId="MCP_USER" fromDate="2025-01-01 00:00:00.000"/>
37
38 <!-- Create minimal MCP user for testing -->
39 <moqui.security.UserAccount userId="MCP_USER" username="mcp-user" disabled="N" requirePasswordChange="N"
40 currentPassword="16ac58bbfa332c1c55bd98b53e60720bfa90d394" passwordHashType="SHA" />
41
42 </entity-facade-xml>
...\ No newline at end of file ...\ No newline at end of file
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, 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 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 <entities xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
14 xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/entity-definition-3.xsd">
15
16 <!-- Extend Visit entity for MCP-specific session tracking -->
17 <extend-entity entity-name="Visit" package="moqui.server">
18 <field name="mcpContextToken" type="text-medium"/>
19 <field name="mcpStatusId" type="id"/>
20 <field name="mcpExpiresDate" type="date-time"/>
21 <field name="mcpClientInfo" type="text-long"/>
22 <field name="mcpSessionData" type="text-very-long"/>
23
24 <relationship type="one" related-entity-name="moqui.basic.StatusItem" short-alias="mcpStatus">
25 <key-map field-name="mcpStatusId"/>
26 </relationship>
27
28 <index name="VISIT_MCP_TOKEN" unique="true">
29 <index-field name="mcpContextToken"/>
30 </index>
31 <index name="VISIT_MCP_USER_STATUS">
32 <index-field name="userId"/>
33 <index-field name="mcpStatusId"/>
34 </index>
35 <index name="VISIT_MCP_EXPIRE">
36 <index-field name="mcpExpiresDate"/>
37 </index>
38 </extend-entity>
39
40
41
42
43
44 </entities>
...\ No newline at end of file ...\ No newline at end of file
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, 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 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 <screen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
14 xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/screen-definition-3.xsd">
15
16 <parameter name="sessionId"/>
17 <parameter name="contextToken"/>
18
19 <widgets>
20 <render-mode>
21 <text type="html" location="component://moqui-mcp-2/template/McpInfo.html.ftl"/>
22 </render-mode>
23 </widgets>
24 </screen>
...\ No newline at end of file ...\ No newline at end of file
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, 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 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 <services xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
14 xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/service-definition-3.xsd">
15
16 <!-- MCP Unified Security and Audit Services -->
17
18 <service verb="create" noun="McpSession" authenticate="false" transaction-timeout="30">
19 <description>Create a new MCP session using Moqui's Visit entity</description>
20 <in-parameters>
21 <parameter name="username" type="text-medium" required="true"/>
22 <parameter name="password" type="text-medium" required="true"/>
23 <parameter name="clientInfo" type="text-long"/>
24 <parameter name="ipAddress" type="text-short"/>
25 <parameter name="userAgent" type="text-medium"/>
26 </in-parameters>
27 <out-parameters>
28 <parameter name="visitId" type="id"/>
29 <parameter name="contextToken" type="text-medium"/>
30 <parameter name="userAccountId" type="id"/>
31 <parameter name="success" type="text-indicator"/>
32 <parameter name="errorMessage" type="text-long"/>
33 </out-parameters>
34 <actions>
35 <script><![CDATA[
36 import org.moqui.context.ExecutionContext
37 import java.util.UUID
38
39 ExecutionContext ec = context.ec
40
41 // Authenticate user
42 def userAccount = ec.entity.find("moqui.security.UserAccount")
43 .condition("username", username)
44 .one()
45
46 if (!userAccount) {
47 success = "N"
48 errorMessage = "Invalid username or password"
49 return
50 }
51
52 // Verify password using Moqui's password service
53 try {
54 def authResult = ec.service.sync("org.moqui.security.UserServices.authenticate#User", [
55 username: username,
56 password: password
57 ])
58
59 if (!authResult.authenticated) {
60 success = "N"
61 errorMessage = "Invalid username or password"
62 return
63 }
64 } catch (Exception e) {
65 success = "N"
66 errorMessage = "Authentication error: ${e.message}"
67 return
68 }
69
70 // Create Visit record (Moqui's native session tracking)
71 def visit = ec.entity.makeValue("moqui.server.Visit")
72 visit.setSequencedIdPrimary()
73 visit.userId = userAccount.userAccountId
74 visit.userCreated = "N"
75 visit.sessionId = UUID.randomUUID().toString()
76 visit.webappName = "mcp-2"
77 visit.initialLocale = ec.user.locale.toString()
78 visit.initialRequest = "MCP Session Creation"
79 visit.initialUserAgent = userAgent
80 visit.clientIpAddress = ipAddress
81 visit.fromDate = ec.user.now
82
83 // Add MCP-specific fields
84 visit.mcpContextToken = UUID.randomUUID().toString()
85 visit.mcpStatusId = "McsActive"
86 visit.mcpExpiresDate = new Date(ec.user.now.time + (24 * 60 * 60 * 1000)) // 24 hours
87 visit.mcpClientInfo = clientInfo
88
89 visit.create()
90
91 visitId = visit.visitId
92 contextToken = visit.mcpContextToken
93 userAccountId = userAccount.userAccountId
94 success = "Y"
95
96 // Log session creation via ArtifactHit
97 ec.message.addMessage("MCP session created for user ${username}", "info")
98 ]]></script>
99 </actions>
100 </service>
101
102 <service verb="validate" noun="McpSession" authenticate="false" transaction-timeout="30">
103 <description>Validate MCP session using Visit entity</description>
104 <in-parameters>
105 <parameter name="visitId" type="id" required="true"/>
106 <parameter name="contextToken" type="text-medium" required="true"/>
107 </in-parameters>
108 <out-parameters>
109 <parameter name="valid" type="text-indicator"/>
110 <parameter name="userAccountId" type="id"/>
111 <parameter name="errorMessage" type="text-long"/>
112 </out-parameters>
113 <actions>
114 <script><![CDATA[
115 import org.moqui.context.ExecutionContext
116
117 ExecutionContext ec = context.ec
118
119 def visit = ec.entity.find("moqui.server.Visit")
120 .condition("visitId", visitId)
121 .condition("mcpContextToken", contextToken)
122 .condition("mcpStatusId", "McsActive")
123 .one()
124
125 if (!visit) {
126 valid = "N"
127 errorMessage = "Invalid or expired session"
128 return
129 }
130
131 // Check if session has expired
132 if (visit.mcpExpiresDate && visit.mcpExpiresDate.before(ec.user.now)) {
133 // Mark as expired
134 visit.mcpStatusId = "McsExpired"
135 visit.thruDate = ec.user.now
136 visit.update()
137
138 valid = "N"
139 errorMessage = "Session expired"
140 return
141 }
142
143 // Update Visit thruDate (acts as last accessed)
144 visit.thruDate = ec.user.now
145 visit.update()
146
147 valid = "Y"
148 userAccountId = visit.userId
149 ]]></script>
150 </actions>
151 </service>
152
153 <service verb="terminate" noun="McpSession" authenticate="false" transaction-timeout="30">
154 <description>Terminate MCP session using Visit entity</description>
155 <in-parameters>
156 <parameter name="visitId" type="id" required="true"/>
157 <parameter name="contextToken" type="text-medium" required="true"/>
158 </in-parameters>
159 <out-parameters>
160 <parameter name="success" type="text-indicator"/>
161 <parameter name="errorMessage" type="text-long"/>
162 </out-parameters>
163 <actions>
164 <script><![CDATA[
165 import org.moqui.context.ExecutionContext
166
167 ExecutionContext ec = context.ec
168
169 def visit = ec.entity.find("moqui.server.Visit")
170 .condition("visitId", visitId)
171 .condition("mcpContextToken", contextToken)
172 .one()
173
174 if (!visit) {
175 success = "N"
176 errorMessage = "Invalid session"
177 return
178 }
179
180 // Mark as terminated
181 visit.mcpStatusId = "McsTerminated"
182 visit.thruDate = ec.user.now
183 visit.update()
184
185 success = "Y"
186
187 // Log session termination via ArtifactHit
188 ec.message.addMessage("MCP session terminated", "info")
189 ]]></script>
190 </actions>
191 </service>
192
193
194
195 <service verb="cleanup" noun="ExpiredSessions" authenticate="true" transaction-timeout="300">
196 <description>Cleanup expired MCP sessions</description>
197 <in-parameters>
198 <parameter name="dryRun" type="text-indicator" default="N"/>
199 </in-parameters>
200 <out-parameters>
201 <parameter name="expiredCount" type="number-integer"/>
202 <parameter name="cleanedCount" type="number-integer"/>
203 </out-parameters>
204 <actions>
205 <script><![CDATA[
206 import org.moqui.context.ExecutionContext
207
208 ExecutionContext ec = context.ec
209
210 // Find expired MCP sessions
211 def expiredVisits = ec.entity.find("moqui.server.Visit")
212 .condition("mcpStatusId", "McsActive")
213 .condition("mcpExpiresDate", ec.user.now, "less-than")
214 .list()
215
216 expiredCount = expiredVisits.size()
217 cleanedCount = 0
218
219 if (dryRun != "Y") {
220 for (visit in expiredVisits) {
221 visit.mcpStatusId = "McsExpired"
222 visit.thruDate = ec.user.now
223 visit.update()
224 cleanedCount++
225
226 // Log session expiration via ArtifactHit
227 ec.message.addMessage("MCP session expired during cleanup", "info")
228 }
229 }
230 ]]></script>
231 </actions>
232 </service>
233
234 </services>
...\ No newline at end of file ...\ No newline at end of file
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, 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 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"
14 xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/rest-api-3.xsd"
15 name="mcp-2" displayName="MCP v2 REST API" version="2.0.0"
16 description="Model Context Protocol (MCP) v2 server endpoints for AI-Moqui integration">
17
18 <!-- MCP Session Management -->
19
20 <resource name="session" description="MCP Session Management">
21 <method type="post" json-request="true">
22 <description>Create new MCP session</description>
23 <service name="org.moqui.mcp.McpSecurityServices.create#McpSession"/>
24 <parameter-map>
25 <parameter field-name="username" required="true"/>
26 <parameter field-name="password" required="true"/>
27 <parameter field-name="clientInfo"/>
28 <parameter field-name="ipAddress"/>
29 <parameter field-name="userAgent"/>
30 </parameter-map>
31 </method>
32
33 <id name="visitId">
34 <method type="post" json-request="true">
35 <description>Validate MCP session</description>
36 <service name="org.moqui.mcp.McpSecurityServices.validate#McpSession"/>
37 <parameter-map>
38 <parameter field-name="visitId" from="uri-path"/>
39 <parameter field-name="contextToken" required="true"/>
40 </parameter-map>
41 </method>
42
43 <resource name="terminate">
44 <method type="post" json-request="true">
45 <description>Terminate MCP session</description>
46 <service name="org.moqui.mcp.McpSecurityServices.terminate#McpSession"/>
47 <parameter-map>
48 <parameter field-name="visitId" from="uri-path"/>
49 <parameter field-name="contextToken" required="true"/>
50 </parameter-map>
51 </method>
52 </resource>
53 </id>
54 </resource>
55
56 <!-- MCP Tool Discovery -->
57
58 <resource name="tools" description="MCP Tool Discovery and Execution">
59 <resource name="discover">
60 <method type="post" json-request="true">
61 <description>Discover available MCP tools</description>
62 <service name="org.moqui.mcp.McpDiscoveryServices.discover#McpTools"/>
63 <parameter-map>
64 <parameter field-name="userAccountId" required="true"/>
65 <parameter field-name="visitId"/>
66 <parameter field-name="servicePattern"/>
67 <parameter field-name="packageName"/>
68 <parameter field-name="verb"/>
69 <parameter field-name="noun"/>
70 <parameter field-name="includeParameters"/>
71 </parameter-map>
72 </method>
73 </resource>
74
75 <resource name="validate">
76 <method type="post" json-request="true">
77 <description>Validate access to specific MCP tools</description>
78 <service name="org.moqui.mcp.McpDiscoveryServices.validate#McpToolAccess"/>
79 <parameter-map>
80 <parameter field-name="userAccountId" required="true"/>
81 <parameter field-name="serviceNames" required="true"/>
82 <parameter field-name="visitId"/>
83 </parameter-map>
84 </method>
85 </resource>
86
87 <method type="post" json-request="true">
88 <description>Execute MCP tool (service)</description>
89 <service name="org.moqui.mcp.McpExecutionServices.execute#McpTool"/>
90 <parameter-map>
91 <parameter field-name="sessionId" required="true"/>
92 <parameter field-name="contextToken" required="true"/>
93 <parameter field-name="serviceName" required="true"/>
94 <parameter field-name="parameters" required="true"/>
95 <parameter field-name="toolCallId"/>
96 </parameter-map>
97 </method>
98
99 <resource name="entity">
100 <resource name="query">
101 <method type="post" json-request="true">
102 <description>Execute entity query as MCP tool</description>
103 <service name="org.moqui.mcp.McpExecutionServices.execute#EntityQuery"/>
104 <parameter-map>
105 <parameter field-name="sessionId" required="true"/>
106 <parameter field-name="contextToken" required="true"/>
107 <parameter field-name="serviceName" required="true"/>
108 <parameter field-name="parameters" required="true"/>
109 <parameter field-name="toolCallId"/>
110 </parameter-map>
111 </method>
112 </resource>
113 </resource>
114 </resource>
115
116 <!-- MCP Health Check -->
117
118 <resource name="health" description="MCP Server Health Check">
119 <method type="get">
120 <actions>
121 <script><![CDATA[
122 import groovy.json.JsonBuilder
123
124 def health = [
125 status: "healthy",
126 timestamp: ec.user.now,
127 version: "2.0.0-MVP",
128 server: "Moqui MCP Server v2",
129 endpoints: [
130 "POST /session - Create session",
131 "POST /session/{visitId}/validate - Validate session",
132 "POST /session/{visitId}/terminate - Terminate session",
133 "POST /tools/discover - Discover tools",
134 "POST /tools/validate - Validate tool access",
135 "POST /tools/execute - Execute service tool",
136 "POST /tools/entity/query - Execute entity query",
137 "GET /health - Health check"
138 ]
139 ]
140
141 response = new JsonBuilder(health).toString()
142 ]]></script>
143 </actions>
144 </method>
145 </resource>
146
147 </resource>
...\ No newline at end of file ...\ No newline at end of file
1 <!DOCTYPE html>
2 <html>
3 <head>
4 <title>Moqui MCP Server v2</title>
5 <style>
6 body { font-family: Arial, sans-serif; margin: 40px; }
7 .header { color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px; }
8 .endpoint { background: #f8f9fa; padding: 10px; margin: 5px 0; border-radius: 5px; }
9 .method { color: #28a745; font-weight: bold; }
10 .path { font-family: monospace; background: #e9ecef; padding: 2px 5px; }
11 </style>
12 </head>
13 <body>
14 <h1 class="header">Moqui MCP Server v2 (MVP)</h1>
15
16 <h2>Server Information</h2>
17 <p><strong>Version:</strong> 2.0.0-MVP</p>
18 <p><strong>Status:</strong> Active</p>
19 <p><strong>Description:</strong> Simplified MCP server using Moqui's native service engine</p>
20
21 <h2>Available Endpoints</h2>
22
23 <div class="endpoint">
24 <span class="method">POST</span> <span class="path">/session</span><br>
25 <strong>Description:</strong> Create new MCP session<br>
26 <strong>Required:</strong> username, password<br>
27 <strong>Optional:</strong> clientInfo, ipAddress, userAgent
28 </div>
29
30 <div class="endpoint">
31 <span class="method">POST</span> <span class="path">/session/{sessionId}/validate</span><br>
32 <strong>Description:</strong> Validate MCP session<br>
33 <strong>Required:</strong> contextToken
34 </div>
35
36 <div class="endpoint">
37 <span class="method">POST</span> <span class="path">/session/{sessionId}/terminate</span><br>
38 <strong>Description:</strong> Terminate MCP session<br>
39 <strong>Required:</strong> contextToken
40 </div>
41
42 <div class="endpoint">
43 <span class="method">POST</span> <span class="path">/tools/discover</span><br>
44 <strong>Description:</strong> Discover available MCP tools<br>
45 <strong>Required:</strong> userAccountId<br>
46 <strong>Optional:</strong> sessionId, servicePattern, packageName, verb, noun, includeParameters
47 </div>
48
49 <div class="endpoint">
50 <span class="method">POST</span> <span class="path">/tools/validate</span><br>
51 <strong>Description:</strong> Validate access to specific MCP tools<br>
52 <strong>Required:</strong> userAccountId, serviceNames<br>
53 <strong>Optional:</strong> sessionId
54 </div>
55
56 <div class="endpoint">
57 <span class="method">POST</span> <span class="path">/tools/execute</span><br>
58 <strong>Description:</strong> Execute MCP tool (service)<br>
59 <strong>Required:</strong> sessionId, serviceName, parameters<br>
60 <strong>Optional:</strong> toolCallId
61 </div>
62
63 <div class="endpoint">
64 <span class="method">POST</span> <span class="path">/tools/entity/query</span><br>
65 <strong>Description:</strong> Execute entity query as MCP tool<br>
66 <strong>Required:</strong> sessionId, entityName<br>
67 <strong>Optional:</strong> queryType, conditions, orderBy, limit, offset, toolCallId
68 </div>
69
70 <div class="endpoint">
71 <span class="method">GET</span> <span class="path">/health</span><br>
72 <strong>Description:</strong> Server health check
73 </div>
74
75 <h2>Key Features</h2>
76 <ul>
77 <li><strong>Native Service Engine:</strong> Uses Moqui's service engine directly (no registry)</li>
78 <li><strong>Dynamic Tool Discovery:</strong> Tools = services user has permission to execute</li>
79 <li><strong>Unified Security:</strong> Single permission validation using UserGroupPermission</li>
80 <li><strong>Audit Logging:</strong> Complete audit trail of all operations</li>
81 <li><strong>Session Management:</strong> Secure session handling with expiration</li>
82 </ul>
83
84 <h2>Usage Example</h2>
85 <pre>
86 # 1. Create session
87 curl -X POST http://localhost:8080/mcp-2/session \
88 -H "Content-Type: application/json" \
89 -d '{"username": "admin", "password": "admin"}'
90
91 # 2. Discover tools
92 curl -X POST http://localhost:8080/mcp-2/tools/discover \
93 -H "Content-Type: application/json" \
94 -d '{"userAccountId": "ADMIN", "sessionId": "YOUR_SESSION_ID"}'
95
96 # 3. Execute tool
97 curl -X POST http://localhost:8080/mcp-2/tools/execute \
98 -H "Content-Type: application/json" \
99 -d '{
100 "sessionId": "YOUR_SESSION_ID",
101 "serviceName": "org.moqui.entity.EntityServices.find#Entity",
102 "parameters": {"entityName": "moqui.security.UserAccount"}
103 }'
104 </pre>
105 </body>
106 </html>
...\ No newline at end of file ...\ No newline at end of file