docs: add human-friendly documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Snider 2026-03-11 13:02:40 +00:00
parent 9e2d77ed2a
commit 8b9cc2e3d6
3 changed files with 879 additions and 0 deletions

410
docs/architecture.md Normal file
View file

@ -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
```

372
docs/development.md Normal file
View file

@ -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 <noreply@anthropic.com>` when
pair-programming with Claude.
- Licence: EUPL-1.2. All new files must include the appropriate SPDX header.

97
docs/index.md Normal file
View file

@ -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.