@@ -52,10 +52,10 @@ The MCP server will expose the rich domain model through standardized MCP resour
5252- [x] Establish patterns and conventions
5353
5454### 📈 Phase 2: Expand Creature Recruitment Context
55- - [ ] ** creaturerecruitment/write/recruitcreature** : Recruit creature tools/resources
55+ - [x ] ** creaturerecruitment/write/recruitcreature** : Recruit creature tools/resources
5656- [ ] ** creaturerecruitment/write/changeavailablecreatures** : Availability tools/resources
5757- [ ] ** creaturerecruitment/read/getdwellingbyid** : Single dwelling query resources
58- - [ ] ** creaturerecruitment/read/getalldwellings** : Dwellings list query resources
58+ - [x ] ** creaturerecruitment/read/getalldwellings** : Dwellings list query resources
5959- [ ] ** creaturerecruitment** : Shared recruitment strategy prompts
6060
6161### 🔄 Phase 3: Replicate to Other Contexts
@@ -254,17 +254,128 @@ return commandGateway.send(command, GameMetaData.with(gameId, playerId))
254254 ));
255255```
256256
257+ ### MCP Resource Implementation Pattern
258+
259+ Based on the successful implementation of ` GetAllDwellingsMcp ` resource, here's the established pattern for creating MCP resources:
260+
261+ #### 1. ** File Location & Naming**
262+ - Each read slice gets its own MCP class with suffix ` Mcp `
263+ - Location: ` {context}/read/{slice}/{SliceName}Mcp.java `
264+ - Example: ` creaturerecruitment/read/getalldwellings/GetAllDwellingsMcp.java `
265+
266+ #### 2. ** Class Structure**
267+ ``` java
268+ @Component
269+ public class GetAllDwellingsMcp {
270+
271+ private final QueryGateway queryGateway;
272+ private final ObjectMapper objectMapper;
273+
274+ public GetAllDwellingsMcp (QueryGateway queryGateway , ObjectMapper objectMapper ) {
275+ this . queryGateway = queryGateway;
276+ this . objectMapper = objectMapper;
277+ }
278+
279+ @Bean
280+ public List<McpServerFeatures . SyncResourceSpecification > getAllDwellingsResource () {
281+ // Resource definition and handler implementation
282+ }
283+ }
284+ ```
285+
286+ #### 3. ** Key Design Decisions for Resources**
287+ - ** Use ` @Component ` and ` @Bean ` ** for resource specification
288+ - ** Return ` List<McpServerFeatures.SyncResourceSpecification> ` ** from bean methods
289+ - ** Follow MCP URI standard** with custom scheme (e.g., ` heroesofddd://games/{gameId}/dwellings ` )
290+ - ** Include proper MCP annotations** with audience and priority
291+ - ** Reuse existing Query/QueryGateway** infrastructure
292+ - ** Provide structured JSON responses** with metadata
293+
294+ #### 4. ** URI Pattern**
295+ ``` java
296+ // Correct MCP URI with custom scheme following REST-like pattern
297+ " heroesofddd://games/{gameId}/dwellings"
298+
299+ // Path parameter extraction
300+ private Optional<String > extractGameId(String uri) {
301+ final String scheme = " heroesofddd://" ;
302+ final String expectedPath = " games" ;
303+ final String expectedEndpoint = " dwellings" ;
304+
305+ if (! uri. startsWith(scheme)) {
306+ return Optional . empty();
307+ }
308+
309+ String [] pathSegments = uri. substring(scheme. length()). split(" /" );
310+
311+ if (pathSegments. length != 3 ||
312+ ! expectedPath. equals(pathSegments[0 ]) ||
313+ ! expectedEndpoint. equals(pathSegments[2 ])) {
314+ return Optional . empty();
315+ }
316+
317+ String gameId = pathSegments[1 ];
318+ return gameId. trim(). isEmpty() ? Optional . empty() : Optional . of(gameId);
319+ }
320+ ```
321+
322+ #### 5. ** Resource Definition Pattern**
323+ ``` java
324+ var dwellingsResource = new McpSchema .Resource (
325+ " heroesofddd://games/{gameId}/dwellings" , // URI following MCP standard
326+ " All Dwellings" , // Human-readable name
327+ " Provides access to all dwellings in a game..." , // Description
328+ " application/json" , // MIME type
329+ new McpSchema .Annotations (
330+ List . of(McpSchema . Role . USER , McpSchema . Role . ASSISTANT ), // Audience
331+ 0.8 // Priority (0.0-1.0)
332+ )
333+ );
334+ ```
335+
336+ #### 6. ** Response Pattern**
337+ ``` java
338+ // Success Response
339+ String jsonContent = formatDwellings(result);
340+ return new McpSchema .ReadResourceResult (
341+ List . of(new McpSchema .TextResourceContents (
342+ request. uri(),
343+ " application/json" ,
344+ jsonContent
345+ ))
346+ );
347+
348+ // Error Response
349+ String errorContent = String . format(" " "
350+ {
351+ " error" : " Failed to retrieve dwellings: % s" ,
352+ " dwellings" : []
353+ }
354+ " " " , e. getMessage());
355+ return new McpSchema .ReadResourceResult (
356+ List . of(new McpSchema .TextResourceContents (
357+ request. uri(),
358+ " application/json" ,
359+ errorContent
360+ ))
361+ );
362+ ```
363+
257364### Next Implementation Steps
258365
259- With the proven pattern established, implement remaining tools following the same structure:
366+ With proven patterns established for both Tools and Resources, implement remaining components:
367+
368+ ** Completed:**
369+ 1 . ✅ ** creaturerecruitment/write/recruitcreature/RecruitCreatureMcp.java** (Tool)
370+ 2 . ✅ ** creaturerecruitment/read/getalldwellings/GetAllDwellingsMcp.java** (Resource)
260371
261- 1 . ** creaturerecruitment/write/recruitcreature/ModelContextProtocol.java**
262- 2 . ** creaturerecruitment/write/changeavailablecreatures/ModelContextProtocol.java**
263- 3 . ** creaturerecruitment/read/getdwellingbyid/ModelContextProtocol.java** (Resources)
264- 4 . ** creaturerecruitment/read/getalldwellings/ModelContextProtocol.java** (Resources)
372+ ** Remaining:**
373+ 3 . ** creaturerecruitment/write/changeavailablecreatures** - Follow Tool pattern
374+ 4 . ** creaturerecruitment/read/getdwellingbyid** - Follow Resource pattern
265375
266376Each implementation should:
267- - Follow the established class structure
377+ - Follow the established class structure patterns
268378- Use appropriate parameter validation
269- - Maintain consistent response formats
270- - Leverage existing domain infrastructure
379+ - Maintain consistent response formats
380+ - Leverage existing domain infrastructure
381+ - Follow MCP URI standards with custom scheme
0 commit comments