# Kberg MCP bridge for connecting local LLMs to desktop apps. 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. ## Ships - `Tool` trait + `ToolRegistry` — the app-side action surface. - `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. - 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. - Provider-agnostic `Agent` + `InferenceProvider` trait — the tool-use loop is decoupled from the LLM backend. - `provider::ollama::OllamaProvider` — reference implementation for a local Ollama server. ## Scope 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. ## Guardrails Every tool is classified when it's registered: | Kind | Meaning | |---|---| | `Read` | No state change. Freely callable subject to app-level connection auth. | | `Write(WriteCapability)` | Mutates app state. Bound to a named capability, granted per session. | Writes are the finite, app-declared vocabulary of permissions the LLM can be given — webhook-style. A driver session holds a `HashSet` of granted capability IDs; any write tool call whose capability is not in the set is refused with a stable, model-visible error. 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. ## v1 primitive matrix | Primitive | Status | Purpose | |---|---|---| | `Tool` + `ToolRegistry` | shipped | register app functions as MCP tools | | `ToolKind::Read / Write(capability)` | shipped | webhook-style write permissions | | Streamable HTTP MCP server | shipped | speak MCP over local HTTP (POST + GET SSE + DELETE) | | `ResourceRegistry` (list / read) | shipped | expose live objects a client lists and reads | | Resource subscriptions + server push | shipped | `resources/subscribe` + `notifications/resources/updated` over SSE | | Request cancellation | shipped | `notifications/cancelled` both ways; app aborts an in-flight call and tells the client | | `InferenceProvider` + `Agent` | shipped | provider-agnostic tool-use loop | | Ollama provider | shipped | drive tools from a local Ollama model | | Hard refusals (`Refusal`) | shipped | registered "not offered" tools with stable reason | | Compact surface projection | shipped | `SurfaceProjection::Compact` filters to `small_model_safe` tools | | Handles | planned | opaque, wire-safe entity IDs (never leak SHA-256 / row PKs to the model) | | Preview / commit | planned | two-step writes: dry-run returns a preview, commit executes | | Scope | planned | first-class scope arg (`book`, `library`, `inbox`) so small models don't re-specify it | | Human-confirm gating | planned | writes above app-defined thresholds return `pending_human_confirm(ticket)` | | Audit log | planned | every call recorded, especially writes | | Sidecar aggregator | planned | one driver, N apps, namespaced tool ids | | Additional providers | planned | OpenAI, Anthropic, generic OpenAI-compatible | ## Layout ``` src/ lib.rs error.rs tool.rs # Tool, ToolKind, WriteCapability, ToolRegistry, Refusal, SurfaceProjection resource.rs # ResourceRegistry, ResourceDescriptor, ResourceContents (+ notify_updated) agent.rs # Agent, InferenceProvider, Message, RunOutcome server/ # feature = "server" mod.rs # POST/GET-SSE/DELETE routes, JSON-RPC dispatch protocol.rs session.rs # per-session subscriptions, SSE out channel, cancellation stdio.rs provider/ # provider adapters (feature-gated) mod.rs ollama.rs # feature = "ollama" examples/ toy.rs # end-to-end: register tools, serve, drive via Ollama ``` ## Example ``` ollama pull qwen2.5 cargo run --example toy ``` Override the model with `KBERG_MODEL=llama3.2 cargo run --example toy`.