diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..a08808b --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,410 @@ +--- +title: Architecture +description: Internals of the Go MCP server and PHP Laravel package -- types, data flow, subsystems, and security model. +--- + +# Architecture + +Core MCP is split into two cooperating halves: a Go binary that speaks the +native MCP protocol over stdio/TCP/Unix sockets, and a PHP Laravel package +that exposes an HTTP MCP API with multi-tenant auth, quotas, and analytics. + +## Go server (`pkg/mcp/`) + +### Service + +`mcp.Service` is the central type. It owns an `mcp.Server` from the official +Go SDK, a sandboxed filesystem `Medium`, optional subsystems, and an ordered +slice of `ToolRecord` metadata that powers the REST bridge. + +```go +svc, err := mcp.New( + mcp.WithWorkspaceRoot("/home/user/project"), + mcp.WithSubsystem(mcp.NewMLSubsystem(mlService)), + mcp.WithProcessService(processService), + mcp.WithWSHub(wsHub), +) +``` + +Options follow the functional-options pattern. `WithWorkspaceRoot` creates a +sandboxed `io.Medium` that confines all file operations to a single directory +tree. Passing an empty string disables sandboxing (not recommended for +untrusted clients). + +### Tool registration + +Every tool is registered through a single generic function: + +```go +func addToolRecorded[In, Out any]( + s *Service, + server *mcp.Server, + group string, + t *mcp.Tool, + h mcp.ToolHandlerFor[In, Out], +) +``` + +This function does three things in one call: + +1. Registers the handler with the MCP server for native protocol calls. +2. Reflects on the `In` and `Out` type parameters to build JSON Schemas. +3. Creates a `RESTHandler` closure that unmarshals raw JSON into the concrete + `In` type, calls the handler, and returns the `Out` value -- enabling the + REST bridge without any per-tool glue code. + +The resulting `ToolRecord` structs are stored in `Service.tools` and exposed +via `Tools()` and `ToolsSeq()` (the latter returns a Go 1.23 `iter.Seq`). + +### Built-in tool groups + +The service registers the following tools at startup: + +| Group | Tools | Source | +|-------|-------|--------| +| **files** | `file_read`, `file_write`, `file_delete`, `file_rename`, `file_exists`, `file_edit`, `dir_list`, `dir_create` | `mcp.go` | +| **language** | `lang_detect`, `lang_list` | `mcp.go` | +| **metrics** | `metrics_record`, `metrics_query` | `tools_metrics.go` | +| **rag** | `rag_query`, `rag_ingest`, `rag_collections` | `tools_rag.go` | +| **process** | `process_start`, `process_stop`, `process_kill`, `process_list`, `process_output`, `process_input` | `tools_process.go` | +| **webview** | `webview_connect`, `webview_disconnect`, `webview_navigate`, `webview_click`, `webview_type`, `webview_query`, `webview_console`, `webview_eval`, `webview_screenshot`, `webview_wait` | `tools_webview.go` | +| **ws** | `ws_start`, `ws_info` | `tools_ws.go` | + +Process and WebSocket tools are conditionally registered -- they require +`WithProcessService` and `WithWSHub` respectively. + +### Subsystem interface + +Additional tool groups are plugged in via the `Subsystem` interface: + +```go +type Subsystem interface { + Name() string + RegisterTools(server *mcp.Server) +} +``` + +Subsystems that need teardown implement `SubsystemWithShutdown`: + +```go +type SubsystemWithShutdown interface { + Subsystem + Shutdown(ctx context.Context) error +} +``` + +Two subsystems ship with this repo: + +#### ML subsystem (`tools_ml.go`) + +`MLSubsystem` wraps a `go-ml.Service` and exposes five tools: + +- `ml_generate` -- text generation via any registered inference backend. +- `ml_score` -- heuristic and semantic scoring of prompt/response pairs. +- `ml_probe` -- capability probes (predefined prompts run through the model). +- `ml_status` -- training and generation progress from InfluxDB. +- `ml_backends` -- lists registered inference backends and their availability. + +#### IDE subsystem (`pkg/mcp/ide/`) + +Bridges the desktop IDE to a Laravel `core-agentic` backend over WebSocket. +Registers tools in three groups: + +- **Chat**: `ide_chat_send`, `ide_chat_history`, `ide_session_list`, + `ide_session_create`, `ide_plan_status` +- **Build**: `ide_build_status`, `ide_build_list`, `ide_build_logs` +- **Dashboard**: `ide_dashboard_overview`, `ide_dashboard_activity`, + `ide_dashboard_metrics` + +The IDE bridge (`Bridge`) maintains a persistent WebSocket connection to the +Laravel backend with exponential-backoff reconnection. Messages are forwarded +from Laravel to a local `ws.Hub` for real-time streaming to the IDE frontend. + +#### Brain subsystem (`pkg/mcp/brain/`) + +Proxies OpenBrain knowledge-store operations to the Laravel backend via the +IDE bridge. Four tools: + +- `brain_remember` -- store a memory (decision, observation, bug, etc.). +- `brain_recall` -- semantic search across stored memories. +- `brain_forget` -- permanently delete a memory. +- `brain_list` -- list memories with filtering (no vector search). + +### Transports + +The Go server supports three transports, all using line-delimited JSON-RPC: + +| Transport | Activation | Default address | +|-----------|-----------|-----------------| +| **Stdio** | No `MCP_ADDR` env var | stdin/stdout | +| **TCP** | `MCP_ADDR=host:port` | `127.0.0.1:9100` | +| **Unix** | `ServeUnix(ctx, path)` | caller-specified socket path | + +TCP binds to `127.0.0.1` by default when the host component is empty. Binding +to `0.0.0.0` emits a security warning. Each accepted connection spawns a +fresh `mcp.Server` instance with its own tool set. + +### REST bridge + +`BridgeToAPI` populates a `go-api.ToolBridge` from the recorded tool +metadata. Each tool becomes a `POST` endpoint that: + +1. Reads and size-limits the JSON body (10 MB max). +2. Calls the tool's `RESTHandler` (which deserialises to the correct input + type). +3. Wraps the result in a standard `api.Response` envelope. + +JSON parse errors return 400; all other errors return 500. This allows any +MCP tool to be called over plain HTTP without additional code. + +### Data flow (Go) + +``` +AI Client (Claude Code, IDE) + | + | JSON-RPC over stdio / TCP / Unix + v +mcp.Server (go-sdk) + | + | typed handler dispatch + v +Service.readFile / Service.writeFile / ... + | + | sandboxed I/O + v +io.Medium (go-io) + +--- or via REST --- + +HTTP Client + | + | POST /api/tools/{name} + v +gin.Router -> BridgeToAPI -> RESTHandler -> typed handler +``` + +--- + +## PHP package (`src/php/`) + +### Namespace structure + +The PHP side is split into three namespace roots, each serving a different +stage of the Laravel request lifecycle: + +| Namespace | Path | Purpose | +|-----------|------|---------| +| `Core\Front\Mcp` | `src/Front/Mcp/` | **Frontage** -- defines the `mcp` middleware group, fires `McpRoutesRegistering` and `McpToolsRegistering` lifecycle events | +| `Core\Mcp` | `src/Mcp/` | **Module** -- service provider, models, services, middleware, tools, admin panel, migrations | +| `Core\Website\Mcp` | `src/Website/Mcp/` | **Website** -- public-facing Livewire pages (playground, API explorer, metrics dashboard) | + +### Boot sequence + +1. **`Core\Front\Mcp\Boot`** (auto-discovered via `composer.json` extra) -- + registers the `mcp` middleware group with throttling and route-model + binding, then fires `McpRoutesRegistering` and `McpToolsRegistering` + lifecycle events. + +2. **`Core\Mcp\Boot`** listens to those events via the `$listens` array: + - `McpRoutesRegistering` -- registers MCP API routes under the configured + domain with `mcp.auth` middleware. + - `McpToolsRegistering` -- hook for other modules to register tool + handlers. + - `AdminPanelBooting` -- loads admin views and Livewire components. + - `ConsoleBooting` -- registers artisan commands. + +3. Services are bound as singletons: `ToolRegistry`, `ToolAnalyticsService`, + `McpQuotaService`, `ToolDependencyService`, `AuditLogService`, + `ToolVersionService`, `QueryAuditService`, `QueryExecutionService`. + +### HTTP API + +The `McpApiController` exposes five endpoints behind `mcp.auth` middleware: + +| Method | Path | Handler | +|--------|------|---------| +| `GET` | `/servers.json` | List all MCP servers from YAML registry | +| `GET` | `/servers/{id}.json` | Server details with tool definitions | +| `GET` | `/servers/{id}/tools` | List tools for a server | +| `POST` | `/tools/call` | Execute a tool | +| `GET` | `/resources/{uri}` | Read a resource (not yet implemented -- returns 501) | + +`POST /tools/call` accepts: + +```json +{ + "server": "hosthub-agent", + "tool": "brain_remember", + "arguments": { "content": "...", "type": "observation" } +} +``` + +The controller validates arguments against the tool's JSON Schema, executes +via the `AgentToolRegistry`, logs the call, records quota usage, and +dispatches webhooks. + +### Authentication + +`McpApiKeyAuth` middleware extracts an API key from either: + +- `Authorization: Bearer hk_xxx_yyy` +- `X-API-Key: hk_xxx_yyy` + +It checks expiry, per-server access scopes, and records usage. The resolved +`ApiKey` model is attached to the request for downstream use. + +### McpToolHandler contract + +Tool handlers implement `Core\Front\Mcp\Contracts\McpToolHandler`: + +```php +interface McpToolHandler +{ + public static function schema(): array; + public function handle(array $args, McpContext $context): array; +} +``` + +`McpContext` abstracts the transport layer (stdio vs HTTP), providing: +session tracking, plan context, notification sending, and session logging. + +### Tool registry + +`Core\Mcp\Services\ToolRegistry` loads server and tool definitions from +YAML files in `resources/mcp/`. It provides: + +- Server discovery (`getServers()`) +- Tool listing with optional version info (`getToolsForServer()`) +- Category grouping and search (`getToolsByCategory()`, `searchTools()`) +- Example input generation from JSON Schema +- 5-minute cache with manual invalidation + +### SQL security + +`QueryDatabase` is the most security-hardened tool. It implements seven +layers of defence: + +1. **Keyword blocking** -- `INSERT`, `UPDATE`, `DELETE`, `DROP`, `ALTER`, + `GRANT`, `SET`, and 20+ other dangerous keywords are rejected outright. +2. **Dangerous pattern detection** -- stacked queries, UNION injection, + hex encoding, `SLEEP()`, `BENCHMARK()`, comment obfuscation, and + `INFORMATION_SCHEMA` access are blocked before comment stripping. +3. **Whitelist matching** -- only queries matching predefined regex patterns + (simple SELECT, COUNT, explicit column lists) are allowed. +4. **Blocked table list** -- configurable list of tables that cannot appear + in FROM or JOIN clauses. +5. **Tier-based row limits** -- results are truncated with a warning when + they exceed the configured limit. +6. **Query timeout** -- per-query time limit prevents runaway queries. +7. **Audit logging** -- every query attempt (allowed, blocked, or errored) + is recorded with workspace, user, IP, and session context. + +### Circuit breaker + +`CircuitBreaker` provides fault tolerance for external service dependencies. +It implements the standard three-state pattern: + +- **Closed** -- requests pass through normally; failures are counted. +- **Open** -- requests fail fast; a configurable timeout triggers transition + to half-open. +- **Half-Open** -- a single trial request is allowed (with a lock to prevent + concurrent trials); success closes the circuit, failure re-opens it. + +Configuration is per-service via `config('mcp.circuit_breaker.{service}.*')`. + +### Metrics and analytics + +`McpMetricsService` provides dashboard data from `McpToolCallStat` aggregate +records: + +- Overview stats with period-over-period trend comparison +- Daily call trends for charting +- Top tools by call count +- Per-tool performance percentiles (p50, p95, p99) +- Hourly distribution heatmap +- Error breakdown by tool and error code +- Plan activity tracking + +`ToolAnalyticsService` and `ToolVersionService` handle deeper per-tool +analytics and schema versioning respectively. + +### Quota management + +`McpQuotaService` enforces per-workspace usage limits tracked in the +`mcp_usage_quotas` table. The `CheckMcpQuota` middleware blocks requests +when the quota is exhausted. + +### Audit logging + +`AuditLogService` records tamper-evident audit logs in the `mcp_audit_logs` +table. The `VerifyAuditLogCommand` artisan command checks log integrity. + +### Admin panel + +The module registers nine Livewire components for the admin panel: + +- **ApiKeyManager** -- create, revoke, and scope API keys +- **Playground / McpPlayground** -- interactive tool testing +- **RequestLog** -- full request/response replay +- **ToolAnalyticsDashboard / ToolAnalyticsDetail** -- visual metrics +- **QuotaUsage** -- per-workspace quota status +- **AuditLogViewer** -- searchable audit trail +- **ToolVersionManager** -- schema versioning and deprecation + +### Data flow (PHP) + +``` +AI Agent / External Client + | + | POST /tools/call (Bearer hk_xxx_yyy) + v +McpApiKeyAuth middleware + | + | auth + scope check + v +CheckMcpQuota middleware + | + | quota enforcement + v +McpApiController::callTool() + | + | schema validation + v +AgentToolRegistry::execute() + | + | permission + dependency check + v +Tool handler (e.g. QueryDatabase, brain_remember) + | + | result + v +Log (McpToolCall, McpApiRequest, AuditLog, Webhook) +``` + +--- + +## Brain-seed utility (`cmd/brain-seed/`) + +A standalone Go program that bulk-imports knowledge into OpenBrain via the +PHP MCP HTTP API. It discovers three sources: + +1. **MEMORY.md** files from `~/.claude/projects/*/memory/` +2. **Plan documents** from `~/Code/*/docs/plans/` +3. **CLAUDE.md** files from `~/Code/` (up to 4 levels deep) + +Each markdown file is split by headings into sections. Each section becomes a +`brain_remember` API call with inferred type (architecture, convention, +decision, bug, plan, research, observation), project tag, and confidence +level. Content is truncated to 3,800 characters to fit within embedding model +limits. + +```bash +# Dry run (preview without storing) +go run ./cmd/brain-seed -dry-run + +# Import memories +go run ./cmd/brain-seed -api-key YOUR_KEY + +# Also import plans and CLAUDE.md files +go run ./cmd/brain-seed -api-key YOUR_KEY -plans -claude-md +``` diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 0000000..03d34fb --- /dev/null +++ b/docs/development.md @@ -0,0 +1,372 @@ +--- +title: Development +description: How to build, test, and contribute to the core/mcp repository. +--- + +# Development + +## Prerequisites + +- **Go 1.26+** -- the module uses Go 1.26 features (range-over-func + iterators, `reflect.Type.Fields()`) +- **PHP 8.2+** -- required by the Laravel package +- **Composer** -- for PHP dependency management +- **Core CLI** -- `core build`, `core go test`, etc. (built from + `forge.lthn.ai/core/cli`) +- **Go workspace** -- this module is part of the workspace at `~/Code/go.work` + +## Building + +### Go binary + +```bash +# From the repo root +core build # produces ./core-mcp (arm64 by default) + +# Or with Go directly +go build -o core-mcp ./cmd/core-mcp/ +``` + +Build configuration lives in `.core/build.yaml`: + +```yaml +project: + name: core-mcp + binary: core-mcp +``` + +### PHP package + +The PHP code is consumed as a Composer package. There is no standalone build +step. To develop locally, symlink or use a Composer path repository in your +Laravel application: + +```json +{ + "repositories": [ + { + "type": "path", + "url": "../core/mcp" + } + ] +} +``` + +Then run `composer require lthn/mcp:@dev`. + +## Testing + +### Go tests + +```bash +# Run all tests +core go test + +# Run a single test +core go test --run TestBridgeToAPI + +# With coverage +core go cov +core go cov --open # opens HTML report in browser + +# Full QA (format + vet + lint + test) +core go qa +core go qa full # also runs race detector, vuln scan, security audit +``` + +Test files follow the `_Good`, `_Bad`, `_Ugly` suffix convention: + +| Suffix | Meaning | +|--------|---------| +| `_Good` | Happy path -- expected behaviour with valid inputs | +| `_Bad` | Error paths -- expected failures with invalid inputs | +| `_Ugly` | Edge cases -- panics, nil pointers, concurrent access | + +Key test files: + +| File | What it covers | +|------|----------------| +| `mcp_test.go` | Service creation, workspace sandboxing, file operations | +| `registry_test.go` | Tool recording, schema extraction, REST handler creation | +| `bridge_test.go` | `BridgeToAPI`, JSON error classification, 10 MB body limit | +| `subsystem_test.go` | Subsystem registration and shutdown | +| `transport_tcp_test.go` | TCP transport, loopback default, `0.0.0.0` warning | +| `transport_e2e_test.go` | End-to-end TCP client/server round-trip | +| `tools_metrics_test.go` | Duration parsing, metrics record/query | +| `tools_ml_test.go` | ML subsystem tool registration | +| `tools_process_test.go` | Process start/stop/kill/list/output/input | +| `tools_process_ci_test.go` | CI-safe process tests (no external binaries) | +| `tools_rag_test.go` | RAG query/ingest/collections | +| `tools_rag_ci_test.go` | CI-safe RAG tests (no Qdrant required) | +| `tools_webview_test.go` | Webview tool registration and error handling | +| `tools_ws_test.go` | WebSocket start/info tools | +| `iter_test.go` | Iterator helpers (`SubsystemsSeq`, `ToolsSeq`) | +| `integration_test.go` | Cross-subsystem integration | +| `ide/bridge_test.go` | IDE bridge connection, message dispatch | +| `ide/tools_test.go` | IDE tool registration | +| `brain/brain_test.go` | Brain subsystem registration and bridge-nil handling | + +### PHP tests + +```bash +# From the repo root (or src/php/) +composer test + +# Single test +composer test -- --filter=SqlQueryValidatorTest +``` + +PHP tests use Pest syntax. Key test files: + +| File | What it covers | +|------|----------------| +| `SqlQueryValidatorTest.php` | Blocked keywords, injection patterns, whitelist | +| `McpQuotaServiceTest.php` | Quota recording and enforcement | +| `QueryAuditServiceTest.php` | Audit log recording | +| `QueryExecutionServiceTest.php` | Query execution with limits and timeouts | +| `ToolAnalyticsServiceTest.php` | Analytics aggregation | +| `ToolDependencyServiceTest.php` | Dependency validation | +| `ToolVersionServiceTest.php` | Version management | +| `ValidateWorkspaceContextMiddlewareTest.php` | Workspace context validation | +| `WorkspaceContextSecurityTest.php` | Multi-tenant isolation | + +## Code style + +### Go + +- Format with `core go fmt` (uses `gofmt`) +- Lint with `core go lint` (uses `golangci-lint`) +- Vet with `core go vet` +- All three run automatically via `core go qa` + +### PHP + +- Format with `composer lint` (uses Laravel Pint, PSR-12) +- Format only changed files: `./vendor/bin/pint --dirty` + +### General conventions + +- **UK English** in all user-facing strings and documentation (colour, + organisation, centre, normalise, serialise). +- **Strict types** in every PHP file: `declare(strict_types=1);` +- **SPDX headers** in Go files: `// SPDX-License-Identifier: EUPL-1.2` +- **Type hints** on all PHP parameters and return types. +- Conventional commits: `type(scope): description` + +## Project structure + +``` +core/mcp/ ++-- .core/ +| +-- build.yaml # Build configuration ++-- cmd/ +| +-- core-mcp/ +| | +-- main.go # Binary entry point +| +-- mcpcmd/ +| | +-- cmd_mcp.go # CLI command registration +| +-- brain-seed/ +| +-- main.go # OpenBrain import utility ++-- pkg/ +| +-- mcp/ +| +-- mcp.go # Service, file tools, Run() +| +-- registry.go # ToolRecord, addToolRecorded, schema extraction +| +-- subsystem.go # Subsystem interface, WithSubsystem option +| +-- bridge.go # BridgeToAPI (MCP-to-REST adapter) +| +-- transport_stdio.go +| +-- transport_tcp.go +| +-- transport_unix.go +| +-- tools_metrics.go # Metrics record/query +| +-- tools_ml.go # MLSubsystem (generate, score, probe, status, backends) +| +-- tools_process.go # Process management tools +| +-- tools_rag.go # RAG query/ingest/collections +| +-- tools_webview.go # Chrome DevTools automation +| +-- tools_ws.go # WebSocket server tools +| +-- brain/ +| | +-- brain.go # Brain subsystem +| | +-- tools.go # remember/recall/forget/list tools +| +-- ide/ +| +-- ide.go # IDE subsystem +| +-- config.go # Config, options, defaults +| +-- bridge.go # Laravel WebSocket bridge +| +-- tools_chat.go +| +-- tools_build.go +| +-- tools_dashboard.go ++-- src/ +| +-- php/ +| +-- src/ +| | +-- Front/Mcp/ # Frontage (middleware group, contracts) +| | +-- Mcp/ # Module (services, models, tools, admin) +| | +-- Website/Mcp/ # Public pages (playground, explorer) +| +-- tests/ +| +-- config/ +| +-- routes/ ++-- composer.json ++-- go.mod ++-- go.sum +``` + +## Running locally + +### MCP server (stdio, for Claude Code) + +Add to your Claude Code MCP configuration: + +```json +{ + "mcpServers": { + "core": { + "command": "/path/to/core-mcp", + "args": ["mcp", "serve", "--workspace", "/path/to/project"] + } + } +} +``` + +### MCP server (TCP, for multi-client) + +```bash +MCP_ADDR=127.0.0.1:9100 ./core-mcp mcp serve +``` + +Connect with any JSON-RPC client over TCP. Each line is a complete JSON-RPC +message. Maximum message size is 10 MB. + +### PHP development server + +Use Laravel Valet or the built-in server: + +```bash +cd /path/to/laravel-app +php artisan serve +``` + +The MCP API is available at the configured domain under the routes registered +by `Core\Mcp\Boot::onMcpRoutes`. + +### Brain-seed + +```bash +# Preview what would be imported +go run ./cmd/brain-seed -dry-run + +# Import with API key +go run ./cmd/brain-seed \ + -api-key YOUR_KEY \ + -api https://lthn.sh/api/v1/mcp \ + -plans \ + -claude-md +``` + +## Adding a new Go tool + +1. Define input and output structs with `json` tags: + +```go +type MyToolInput struct { + Query string `json:"query"` + Limit int `json:"limit,omitempty"` +} + +type MyToolOutput struct { + Results []string `json:"results"` + Total int `json:"total"` +} +``` + +2. Write the handler function: + +```go +func (s *Service) myTool( + ctx context.Context, + req *mcp.CallToolRequest, + input MyToolInput, +) (*mcp.CallToolResult, MyToolOutput, error) { + // Implementation here + return nil, MyToolOutput{Results: results, Total: len(results)}, nil +} +``` + +3. Register in `registerTools()`: + +```go +addToolRecorded(s, server, "mygroup", &mcp.Tool{ + Name: "my_tool", + Description: "Does something useful", +}, s.myTool) +``` + +The `addToolRecorded` generic function automatically generates JSON Schemas +from the struct tags and creates a REST-compatible handler. No additional +wiring is needed. + +## Adding a new Go subsystem + +1. Create a new package under `pkg/mcp/`: + +```go +package mysubsystem + +type Subsystem struct{} + +func (s *Subsystem) Name() string { return "mysubsystem" } + +func (s *Subsystem) RegisterTools(server *mcp.Server) { + mcp.AddTool(server, &mcp.Tool{ + Name: "my_subsystem_tool", + Description: "...", + }, s.handler) +} +``` + +2. Register when creating the service: + +```go +mcp.New(mcp.WithSubsystem(&mysubsystem.Subsystem{})) +``` + +## Adding a new PHP tool + +1. Create a tool class implementing `McpToolHandler`: + +```php +namespace Core\Mcp\Tools; + +use Core\Front\Mcp\Contracts\McpToolHandler; +use Core\Front\Mcp\McpContext; + +class MyTool implements McpToolHandler +{ + public static function schema(): array + { + return [ + 'name' => 'my_tool', + 'description' => 'Does something useful', + 'inputSchema' => [ + 'type' => 'object', + 'properties' => [ + 'query' => ['type' => 'string'], + ], + 'required' => ['query'], + ], + ]; + } + + public function handle(array $args, McpContext $context): array + { + return ['result' => 'done']; + } +} +``` + +2. Register via the `McpToolsRegistering` lifecycle event in your module's + Boot class. + +## Contributing + +- All changes must pass `core go qa` (Go) and `composer test` (PHP) before + committing. +- Use conventional commits: `feat(mcp): add new tool`, `fix(mcp): handle nil + input`, `docs(mcp): update architecture`. +- Include `Co-Authored-By: Claude Opus 4.5 ` when + pair-programming with Claude. +- Licence: EUPL-1.2. All new files must include the appropriate SPDX header. diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..aba35a6 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,97 @@ +--- +title: Core MCP +description: Model Context Protocol server and tooling for AI agents -- Go binary + Laravel PHP package. +--- + +# Core MCP + +`forge.lthn.ai/core/mcp` provides a complete Model Context Protocol (MCP) +implementation spanning two languages: + +- **Go** -- a standalone MCP server binary (`core-mcp`) with file operations, + ML inference, RAG, process management, webview automation, and WebSocket + streaming. +- **PHP** -- a Laravel package (`lthn/mcp`) that adds an HTTP MCP API, tool + registry, SQL query tools, quota enforcement, circuit breakers, audit + logging, and an admin panel to any Host UK application. + +Both halves speak the same protocol and can bridge to one another via REST or +WebSocket. + +## Quick start + +### Go binary + +```bash +# Build +core build # produces ./core-mcp + +# Start on stdio (for Claude Code / IDE integration) +./core-mcp mcp serve + +# Start on TCP +MCP_ADDR=127.0.0.1:9100 ./core-mcp mcp serve + +# Restrict file operations to a directory +./core-mcp mcp serve --workspace /path/to/project +``` + +### PHP package + +Add the Composer dependency to a Laravel application: + +```bash +composer require lthn/mcp +``` + +The package auto-registers via `Core\Front\Mcp\Boot`. No manual provider +registration is needed. Run migrations, then visit the admin panel at +`/admin/mcp`. + +## Package layout + +| Path | Language | Purpose | +|------|----------|---------| +| `pkg/mcp/` | Go | Core MCP server: `Service`, transports, tool registry, REST bridge | +| `pkg/mcp/brain/` | Go | OpenBrain knowledge-store subsystem (remember/recall/forget/list) | +| `pkg/mcp/ide/` | Go | IDE subsystem: Laravel WebSocket bridge, chat, builds, dashboard | +| `cmd/core-mcp/` | Go | Binary entry point (`core-mcp`) | +| `cmd/mcpcmd/` | Go | CLI command registration (`mcp serve`) | +| `cmd/brain-seed/` | Go | Utility to import CLAUDE.md / MEMORY.md files into OpenBrain | +| `src/php/src/Mcp/` | PHP | Laravel service provider, models, services, middleware, tools | +| `src/php/src/Front/Mcp/` | PHP | MCP frontage: middleware group, `McpToolHandler` contract, `McpContext` | +| `src/php/src/Website/Mcp/` | PHP | Public-facing MCP pages: playground, API explorer, metrics | + +## Dependencies + +### Go + +| Module | Role | +|--------|------| +| `forge.lthn.ai/core/go` | DI container and service lifecycle | +| `forge.lthn.ai/core/cli` | CLI framework (bubbletea TUI) | +| `forge.lthn.ai/core/go-io` | Filesystem abstraction (`Medium`, sandboxing) | +| `forge.lthn.ai/core/go-log` | Structured logger | +| `forge.lthn.ai/core/go-ai` | AI event metrics | +| `forge.lthn.ai/core/go-ml` | ML inference, scoring, capability probes | +| `forge.lthn.ai/core/go-inference` | Backend registry (Ollama, MLX, ROCm) | +| `forge.lthn.ai/core/go-rag` | Qdrant vector search and document ingestion | +| `forge.lthn.ai/core/go-process` | External process lifecycle management | +| `forge.lthn.ai/core/go-webview` | Chrome DevTools Protocol automation | +| `forge.lthn.ai/core/go-ws` | WebSocket hub and channel messaging | +| `forge.lthn.ai/core/go-api` | REST API framework and `ToolBridge` | +| `github.com/modelcontextprotocol/go-sdk` | Official MCP Go SDK | +| `github.com/gin-gonic/gin` | HTTP router (REST bridge) | +| `github.com/gorilla/websocket` | WebSocket client for IDE bridge | + +### PHP + +| Package | Role | +|---------|------| +| `lthn/php` (core/php) | Foundation framework: lifecycle events, modules, actions | +| Laravel 12 | Application framework | +| Livewire / Flux Pro | Admin panel components | + +## Licence + +EUPL-1.2. See the `SPDX-License-Identifier` headers in each source file.