Sets up the Cargo workspace (harness-core, harness-tools, harness-providers, harness-mcp, harness-lsp, harness-app, harness-tui) and the ten architecture docs under docs/. harness-core gets its foundational types (session/message/part/model ids), an in-process event bus, a table-driven permission evaluate function, and a SQLite-backed storage actor with schema and roundtrip coverage. Every crate compiles empty and a bin stub prints its version.
37 lines
2.9 KiB
Markdown
37 lines
2.9 KiB
Markdown
# 09 — Integrations: MCP, LSP, Commands & Skills
|
|
|
|
## MCP client (`harness-mcp`)
|
|
|
|
- For each configured server (`config.mcp`): `rmcp` client over `TokioChildProcess` transport — spawn, `initialize`, `list_tools`.
|
|
- Each MCP tool wraps into `McpTool: Tool` named `{server}_{tool}` (sanitized to `[a-zA-Z0-9_-]`, 64-char cap). `parameters()` passes the server's JSON Schema through untouched. `execute` → `call_tool`; text content items concatenated, images noted and saved to the session data dir.
|
|
- **Permissions:** key `mcp`, pattern `{server}_{tool}`; bundled default rule `{ permission: "mcp", pattern: "*", action: "ask" }`.
|
|
- Failure handling: a server that fails to start is marked failed with a `ServerNotice` — other tools unaffected; restart attempted on next use after a crash.
|
|
- Out of scope for v1: MCP resources, prompts, sampling; non-stdio transports (HTTP/SSE later).
|
|
|
|
## LSP diagnostics (`harness-lsp`)
|
|
|
|
Implements a seam trait defined in core, so `harness-tools` never links this crate:
|
|
|
|
```rust
|
|
// in harness-core
|
|
pub trait DiagnosticsSource: Send + Sync {
|
|
async fn touch(&self, path: &Path); // spawn-if-needed + didOpen/didChange
|
|
async fn diagnostics(&self, path: &Path, wait: Duration) -> Vec<Diagnostic>;
|
|
}
|
|
```
|
|
|
|
- `LspPool`: extension → server config. Built-ins (spawned only if the binary exists on PATH, all config-overridable): rust-analyzer (.rs), typescript-language-server (.ts/.tsx/.js), gopls (.go), pyright/basedpyright (.py).
|
|
- Client = hand-rolled JSON-RPC over child stdio (`Content-Length` framing, ~150 lines: request map `id → oneshot`, notification broadcast) using `lsp-types` for the payloads. Only ~6 methods needed: `initialize`, `initialized`, `didOpen`, `didChange`, `publishDiagnostics`, optionally `textDocument/diagnostic`.
|
|
- Edit/write tools call `touch(path)` then `diagnostics(path, 1500ms)` — wait for the first `publishDiagnostics` after the change version, or time out. Error-severity items are appended to the tool output:
|
|
`LSP errors detected in this file, please fix:\n{file}: L{line}: {message}`; the full set goes into part metadata for the TUI.
|
|
- All failures are silent to the model (log only) — diagnostics are best-effort.
|
|
|
|
## Commands & skills
|
|
|
|
- **Commands** (`command/*.md`, see [06-config.md](06-config.md)): a pure input-layer concern — `/name args` expands the template into the user message, optionally switching agent/model for that run.
|
|
- **Skills** (`skill/<name>/SKILL.md`): the system prompt lists name + description of each available skill; the model loads a skill's body on demand with the built-in `skill` tool. Per-agent skill filtering via the agent's `tools`/permission config.
|
|
|
|
## Child-process hygiene
|
|
|
|
MCP servers, LSP servers, and bash all spawn children. A single `ChildRegistry` tracks them; process-group kills + `Drop` guards ensure cleanup on exit or panic (flagged risk: zombie children).
|