| 1 |
# Kberg |
| 2 |
|
| 3 |
MCP bridge for connecting local LLMs to desktop apps. |
| 4 |
|
| 5 |
Named after Königsberg — the city whose seven bridges seeded graph theory (Euler, 1736). The library is a bridge in that sense: it routes tool-call edges between an LLM node and a set of app nodes. |
| 6 |
|
| 7 |
## Ships |
| 8 |
|
| 9 |
- `Tool` trait + `ToolRegistry` — the app-side action surface. |
| 10 |
- `ResourceRegistry` — the app-side object surface: live things a client lists, reads, and subscribes to. Dynamic (register/remove at runtime); `notify_updated` pushes a change to subscribed clients. |
| 11 |
- Streamable HTTP MCP server (JSON-RPC 2.0) — how any MCP-speaking client reaches your app. POST for requests, a GET SSE stream for server-initiated notifications, DELETE to end a session. |
| 12 |
- Provider-agnostic `Agent` + `InferenceProvider` trait — the tool-use loop is decoupled from the LLM backend. |
| 13 |
- `provider::ollama::OllamaProvider` — reference implementation for a local Ollama server. |
| 14 |
|
| 15 |
## Scope |
| 16 |
|
| 17 |
Kberg is a *bridge*, not a model manager. You bring the inference endpoint (a local Ollama, LM Studio, vLLM, or a hosted API); Kberg wires it to the app-side tool surface. Future providers (OpenAI, Anthropic, OpenAI-compatible) drop in behind `InferenceProvider` without touching the agent loop. |
| 18 |
|
| 19 |
## Guardrails |
| 20 |
|
| 21 |
Every tool is classified when it's registered: |
| 22 |
|
| 23 |
|
| 24 |
|
| 25 |
| `Read` | No state change. Freely callable subject to app-level connection auth. | |
| 26 |
| `Write(WriteCapability)` | Mutates app state. Bound to a named capability, granted per session. | |
| 27 |
|
| 28 |
Writes are the finite, app-declared vocabulary of permissions the LLM can be given — webhook-style. A driver session holds a `HashSet<String>` of granted capability IDs; any write tool call whose capability is not in the set is refused with a stable, model-visible error. |
| 29 |
|
| 30 |
Capability IDs are a public contract the app owns. Renaming means a new capability + a deprecated old one — you do not silently reassign an existing id. |
| 31 |
|
| 32 |
## v1 primitive matrix |
| 33 |
|
| 34 |
|
| 35 |
|
| 36 |
| `Tool` + `ToolRegistry` | shipped | register app functions as MCP tools | |
| 37 |
| `ToolKind::Read / Write(capability)` | shipped | webhook-style write permissions | |
| 38 |
| Streamable HTTP MCP server | shipped | speak MCP over local HTTP (POST + GET SSE + DELETE) | |
| 39 |
| `ResourceRegistry` (list / read) | shipped | expose live objects a client lists and reads | |
| 40 |
| Resource subscriptions + server push | shipped | `resources/subscribe` + `notifications/resources/updated` over SSE | |
| 41 |
| Request cancellation | shipped | `notifications/cancelled` both ways; app aborts an in-flight call and tells the client | |
| 42 |
| `InferenceProvider` + `Agent` | shipped | provider-agnostic tool-use loop | |
| 43 |
| Ollama provider | shipped | drive tools from a local Ollama model | |
| 44 |
| Hard refusals (`Refusal`) | shipped | registered "not offered" tools with stable reason | |
| 45 |
| Compact surface projection | shipped | `SurfaceProjection::Compact` filters to `small_model_safe` tools | |
| 46 |
| Handles | planned | opaque, wire-safe entity IDs (never leak SHA-256 / row PKs to the model) | |
| 47 |
| Preview / commit | planned | two-step writes: dry-run returns a preview, commit executes | |
| 48 |
| Scope | planned | first-class scope arg (`book`, `library`, `inbox`) so small models don't re-specify it | |
| 49 |
| Human-confirm gating | planned | writes above app-defined thresholds return `pending_human_confirm(ticket)` | |
| 50 |
| Audit log | planned | every call recorded, especially writes | |
| 51 |
| Sidecar aggregator | planned | one driver, N apps, namespaced tool ids | |
| 52 |
| Additional providers | planned | OpenAI, Anthropic, generic OpenAI-compatible | |
| 53 |
|
| 54 |
## Layout |
| 55 |
|
| 56 |
``` |
| 57 |
src/ |
| 58 |
lib.rs |
| 59 |
error.rs |
| 60 |
tool.rs # Tool, ToolKind, WriteCapability, ToolRegistry, Refusal, SurfaceProjection |
| 61 |
resource.rs # ResourceRegistry, ResourceDescriptor, ResourceContents (+ notify_updated) |
| 62 |
agent.rs # Agent, InferenceProvider, Message, RunOutcome |
| 63 |
server/ # feature = "server" |
| 64 |
mod.rs # POST/GET-SSE/DELETE routes, JSON-RPC dispatch |
| 65 |
protocol.rs |
| 66 |
session.rs # per-session subscriptions, SSE out channel, cancellation |
| 67 |
stdio.rs |
| 68 |
provider/ # provider adapters (feature-gated) |
| 69 |
mod.rs |
| 70 |
ollama.rs # feature = "ollama" |
| 71 |
examples/ |
| 72 |
toy.rs # end-to-end: register tools, serve, drive via Ollama |
| 73 |
``` |
| 74 |
|
| 75 |
## Example |
| 76 |
|
| 77 |
``` |
| 78 |
ollama pull qwen2.5 |
| 79 |
cargo run --example toy |
| 80 |
``` |
| 81 |
|
| 82 |
Override the model with `KBERG_MODEL=llama3.2 cargo run --example toy`. |
| 83 |
|