|
6 | 6 | 2. Getting detailed information about structures |
7 | 7 | 3. Generating structures with various options |
8 | 8 | 4. Validating structure configurations |
| 9 | +5. Visualizing structure dependency graphs |
9 | 10 | """ |
10 | 11 | import asyncio |
11 | 12 | import logging |
|
17 | 18 | from fastmcp import FastMCP |
18 | 19 |
|
19 | 20 | from structkit.commands.generate import GenerateCommand |
| 21 | +from structkit.commands.graph import GraphCommand |
20 | 22 | from structkit.commands.validate import ValidateCommand |
21 | 23 | from structkit import __version__ |
22 | 24 |
|
@@ -167,6 +169,30 @@ class Args: |
167 | 169 | return f"Dry run completed for structure '{structure_definition}' at '{base_path}'" |
168 | 170 | return f"Structure '{structure_definition}' generated successfully at '{base_path}'" |
169 | 171 |
|
| 172 | + def _graph_structure_logic( |
| 173 | + self, |
| 174 | + structure_definition: Optional[str] = None, |
| 175 | + structures_path: Optional[str] = None, |
| 176 | + include_all: bool = False, |
| 177 | + output_format: str = "text", |
| 178 | + ) -> str: |
| 179 | + if not include_all and not structure_definition: |
| 180 | + return "Error: structure_definition is required unless include_all is true" |
| 181 | + |
| 182 | + if output_format not in {"text", "json", "mermaid"}: |
| 183 | + return "Error: output_format must be one of: text, json, mermaid" |
| 184 | + |
| 185 | + import argparse |
| 186 | + dummy_parser = argparse.ArgumentParser() |
| 187 | + command = GraphCommand(dummy_parser) |
| 188 | + graph = command.build_graph(structure_definition, structures_path, include_all) |
| 189 | + |
| 190 | + if output_format == "json": |
| 191 | + return command.format_json(graph) |
| 192 | + if output_format == "mermaid": |
| 193 | + return command.format_mermaid(graph) |
| 194 | + return command.format_text(graph) |
| 195 | + |
170 | 196 | def _validate_structure_logic(self, yaml_file: Optional[str]) -> str: |
171 | 197 | if not yaml_file: |
172 | 198 | return "Error: yaml_file is required" |
@@ -247,6 +273,32 @@ async def generate_structure( |
247 | 273 | self.logger.debug(f"MCP response: generate_structure len={len(result)} preview=\n{preview}") |
248 | 274 | return result |
249 | 275 |
|
| 276 | + @self.app.tool(name="graph_structure", description="Visualize structure dependency graphs from folders[].struct references") |
| 277 | + async def graph_structure( |
| 278 | + structure_definition: Optional[str] = None, |
| 279 | + structures_path: Optional[str] = None, |
| 280 | + include_all: bool = False, |
| 281 | + output_format: str = "text", |
| 282 | + ) -> str: |
| 283 | + self.logger.debug( |
| 284 | + "MCP request: graph_structure args=%s", |
| 285 | + { |
| 286 | + "structure_definition": structure_definition, |
| 287 | + "structures_path": structures_path, |
| 288 | + "include_all": include_all, |
| 289 | + "output_format": output_format, |
| 290 | + }, |
| 291 | + ) |
| 292 | + result = self._graph_structure_logic( |
| 293 | + structure_definition, |
| 294 | + structures_path, |
| 295 | + include_all, |
| 296 | + output_format, |
| 297 | + ) |
| 298 | + preview = result if len(result) <= 1000 else result[:1000] + f"... [truncated {len(result)-1000} chars]" |
| 299 | + self.logger.debug(f"MCP response: graph_structure len={len(result)} preview=\n{preview}") |
| 300 | + return result |
| 301 | + |
250 | 302 | @self.app.tool(name="validate_structure", description="Validate a structure configuration YAML file") |
251 | 303 | async def validate_structure(yaml_file: str) -> str: |
252 | 304 | self.logger.debug(f"MCP request: validate_structure args={{'yaml_file': {yaml_file!r}}}") |
|
0 commit comments