|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code when working with this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +`nette/mcp-inspector` is an MCP (Model Context Protocol) server for Nette application introspection. It allows AI assistants to inspect DI containers, database schemas, routing, and other Nette components. |
| 8 | + |
| 9 | +## Architecture |
| 10 | + |
| 11 | +### Core Components |
| 12 | + |
| 13 | +- **`Server`** - Main MCP server orchestrator with dual transport support (CLI/HTTP) |
| 14 | +- **`ServerFactory`** - Creates configured Server instances, registers toolkits |
| 15 | +- **`Toolkit`** - Marker interface for toolkit classes |
| 16 | +- **`BootstrapBridge`** - Bootstraps Nette application to access DI container |
| 17 | + |
| 18 | +### Toolkits |
| 19 | + |
| 20 | +Toolkits implement the `Toolkit` marker interface and use the factory pattern: |
| 21 | + |
| 22 | +```php |
| 23 | +use Mcp\Capability\Attribute\McpTool; |
| 24 | +use Mcp\Schema\ToolAnnotations; |
| 25 | + |
| 26 | +class MyToolkit implements Toolkit |
| 27 | +{ |
| 28 | + // Factory method - returns null if dependencies unavailable |
| 29 | + public static function tryCreate(BootstrapBridge $bridge): ?self |
| 30 | + { |
| 31 | + try { |
| 32 | + $dependency = $bridge->getContainer()->getByType(SomeService::class); |
| 33 | + return new self($dependency); |
| 34 | + } catch (\Throwable) { |
| 35 | + return null; |
| 36 | + } |
| 37 | + } |
| 38 | + |
| 39 | + public function __construct( |
| 40 | + private SomeService $service, |
| 41 | + ) { |
| 42 | + } |
| 43 | + |
| 44 | + /** |
| 45 | + * Tool description from PHPDoc (first line/paragraph). |
| 46 | + * @param string $param Parameter description for AI |
| 47 | + */ |
| 48 | + #[McpTool( |
| 49 | + name: 'my_tool', |
| 50 | + annotations: new ToolAnnotations( |
| 51 | + readOnlyHint: true, // Tool doesn't modify environment |
| 52 | + idempotentHint: true, // Same args = same result |
| 53 | + ), |
| 54 | + )] |
| 55 | + public function myMethod(string $param): array |
| 56 | + { |
| 57 | + return ['result' => $this->service->process($param)]; |
| 58 | + } |
| 59 | +} |
| 60 | +``` |
| 61 | + |
| 62 | +### Built-in Toolkits |
| 63 | + |
| 64 | +- **`DIToolkit`** - DI container introspection (services, types, autowiring) |
| 65 | +- **`DatabaseToolkit`** - Database schema inspection (tables, columns, relationships) |
| 66 | +- **`RouterToolkit`** - Routing inspection (routes, URL matching, URL generation) |
| 67 | + |
| 68 | +## MCP SDK Attributes |
| 69 | + |
| 70 | +### McpTool |
| 71 | + |
| 72 | +```php |
| 73 | +#[McpTool( |
| 74 | + name: 'tool_name', // Optional, defaults to method name |
| 75 | + description: 'Description', // Optional, defaults to PHPDoc |
| 76 | + annotations: new ToolAnnotations(...), |
| 77 | +)] |
| 78 | +``` |
| 79 | + |
| 80 | +### ToolAnnotations |
| 81 | + |
| 82 | +```php |
| 83 | +new ToolAnnotations( |
| 84 | + title: 'Human Title', // Human-readable title |
| 85 | + readOnlyHint: true, // Tool doesn't modify environment |
| 86 | + destructiveHint: false, // Tool doesn't destroy data |
| 87 | + idempotentHint: true, // Repeatable without side effects |
| 88 | + openWorldHint: false, // Closed domain (not web search etc.) |
| 89 | +) |
| 90 | +``` |
| 91 | + |
| 92 | +### Schema (parameter validation) |
| 93 | + |
| 94 | +```php |
| 95 | +use Mcp\Capability\Attribute\Schema; |
| 96 | + |
| 97 | +#[McpTool(name: 'example')] |
| 98 | +public function example( |
| 99 | + #[Schema(minLength: 1, maxLength: 100)] |
| 100 | + string $name, |
| 101 | + |
| 102 | + #[Schema(minimum: 0, maximum: 100)] |
| 103 | + int $percentage, |
| 104 | + |
| 105 | + #[Schema(enum: ['asc', 'desc'])] |
| 106 | + string $order = 'asc', |
| 107 | +): array |
| 108 | +``` |
| 109 | + |
| 110 | +## Coding Standards |
| 111 | + |
| 112 | +- Follow Nette coding standards |
| 113 | +- Use PHP 8.2+ features (readonly, enums, named arguments) |
| 114 | +- All tool methods must return `array` |
| 115 | +- Use PHPDoc for tool and parameter descriptions (SDK extracts them automatically) |
| 116 | +- Use `ToolAnnotations` to hint tool behavior (readOnlyHint, idempotentHint) |
| 117 | + |
| 118 | +## Adding New Toolkits |
| 119 | + |
| 120 | +1. Create class in `src/McpInspector/Toolkits/` implementing `Toolkit` |
| 121 | +2. Add static `tryCreate(BootstrapBridge $bridge): ?self` factory method |
| 122 | +3. Inject actual dependencies via constructor (not BootstrapBridge) |
| 123 | +4. Add methods with `#[McpTool]` attribute and `ToolAnnotations` |
| 124 | +5. Register in `ServerFactory::create()` using `ToolkitClass::tryCreate($bridge)` |
| 125 | + |
| 126 | +## Testing |
| 127 | + |
| 128 | +Run tests: |
| 129 | +```bash |
| 130 | +composer tester |
| 131 | +``` |
| 132 | + |
| 133 | +Run MCP server locally: |
| 134 | +```bash |
| 135 | +php bin/mcp-inspector |
| 136 | +``` |
| 137 | + |
| 138 | +Test in Claude Code by adding to `.mcp.json`: |
| 139 | +```json |
| 140 | +{ |
| 141 | + "mcpServers": { |
| 142 | + "nette": { |
| 143 | + "command": "php", |
| 144 | + "args": ["vendor/bin/mcp-inspector"] |
| 145 | + } |
| 146 | + } |
| 147 | +} |
| 148 | +``` |
0 commit comments