the console, conversational

Talk to your whole platform.

Chat is an MCP host whose tools are the other plugins. It discovers every plugin's tool surface, runs one Claude turn on Bedrock, dispatches each tool call back through the owning plugin — as the signed-in user — and streams the result as typed blocks. Writes preview and wait for your yes.

available
Aggregates every plugin's MCP tools into one turnRuns a Claude turn on Bedrock via IRSADispatches back through each owning plugin — as youConfirm-gated writes: preview first, act on approvalTyped blocks — the model renders, never re-dumps data
every plugin
tools, one conversation
discovered at runtime
7
plugin backends wired
agent · builds · depot · forge · mycelium · spec · tbzl
1
model turn
Bedrock Claude, as the signed-in user
confirm
gated writes
preview, then act on approval
why it's different

Not a chatbot on one API. A host over all of them.

A typical assistant is wired to a single service. Chat's data plane is the whole platform: every plugin already speaks MCP, so the host just unions their tools and lets one model turn reach across them.

On each turn, chat calls tools/list on every configured backend and merges the results into one catalog, namespaced plugin__tool. The model picks tools; chat dispatches each tool_use back to the owning plugin over that plugin's own MCP endpoint — forwarding your identity per call. It's a faithful deputy: each plugin stays the authorization boundary, so an agent can only do what you could. There is no proto to maintain and no bespoke integration per capability — a new plugin's tools simply appear.

The host forwards your identity on every tool call. Each plugin's MCP server is the authorization boundary — an agent's reach is exactly yours.

plugin-chat · a faithful deputy
the console

One question, across plugins.

A turn streams over SSE as a sequence of typed blocks — the user message, the model's reasoning, each tool call updating in place from running to done, and the rendered result. A reconnecting client resumes mid-turn.

you
which of my open PRs have failing CI?
now
assistant
Let me check forge·list_pull_requests, then the pipeline status.
now
tool · forge__list_pull_requests
RUNNING → OK — 12 open PRs across 2 forges
now
render · ui__render_table
renders the results as a table block — the model doesn't re-type the data
now
you
open an issue to track the flaky cross-cache one
now
tool · forge__open_issue
preview — needs confirmation: 'Flaky remote cache on cross builds'
now
you
yes
now
tool · forge__open_issue
confirmed → opened rules_cc_cross#43
now
one catalog

Every plugin's tools, namespaced.

Backends are configured, not hardcoded — each FASTVERK_BACKEND_<x> becomes an MCP client, and its tools appear as plugin__tool. A plugin that's down is skipped with a warning; the catalog never fails.

tools/list · unioned
namespaced plugin__tool · discovered per turn
pluginexample toolsnamespace
forge list_repos · open_mr · merge_change forge__*
tbzl query_rdeps · run_build · assess_merge tbzl__*
builds overview · cache_hit_rate builds__*
depot list_repos · log · browse depot__*
mycelium query mycelium__*
agent dispatch · list · cancel agent__*
host-local: ui__render_table · fields · listper turn: up to 8 tool round-trips
the loop

Discover → converse → dispatch → render.

Four stages, up to eight tool round-trips per turn.

01

Discover

Union every backend's tools/list into one namespaced catalog, plus three host-local presentation tools. A backend that's unreachable is skipped, not fatal.

02

Converse

One Bedrock turn (Claude, us.anthropic.claude-opus-4-8, reached via IRSA — no static key) sees the catalog and chooses which tools to call.

03

Dispatch

Each tool_use routes back to the owning plugin over its own MCP endpoint, carrying your user context — so the call runs as you, inside that plugin's authorization.

04

Render

Results become typed blocks — markdown, table, list, fields. A write returns a preview flagged needs_confirmation, shown as an approval prompt instead of an action.

how it renders + guards

The model renders. It never re-types your data.

Two ideas keep the surface clean and safe: the model can choose to render, and writes can't fire without a turn boundary.

The rules of the loop

  • Presentation-as-tools: ui__render_table / ui__render_fields / ui__render_list are host-local — calling one emits a typed block directly, so the model presents results instead of pasting a wall of JSON.
  • Confirm-gating is by shape, not a hardcoded list: any tool result flagged needs_confirmation becomes an approval prompt with a summary and the proposed fields — the owning plugin decides what mutates.
  • Never in the same turn: a write only fires after you approve and the model re-calls it with confirm:true on a later turn. It can't ask and act at once.
  • Streams over SSE with a monotonic sequence — a reconnecting client resumes from the last event it saw, surviving a dropped connection mid-turn.
vs a bolted-on chatbot

A deputy, not a dashboard with a text box.

The alternative wires an assistant to one API, trusts a shared service account, and hands you raw output.

fastverk chat
single-API assistant
Scope
✓ Every plugin's tools, one turn
One API, one integration
Identity
✓ Acts as the signed-in user, per call
A shared service account
Authorization
✓ Each plugin's MCP is the boundary
Whatever the bot token allows
Writes
✓ Confirm-gated by the owning plugin
Hope the prompt said no
Output
✓ Typed blocks, no re-typed data
A wall of JSON
Adding a capability
✓ A new plugin's tools just appear
Build another integration

Never confirm a write in the same turn you were asked. Preview the action, wait for yes.

plugin-chat · confirm-gated by design

source · github.com/fastverk/plugin-chat · tools: ui__render_table, ui__render_fields, ui__render_list

Prove it's safe to merge.

chat is one of 14 plugins in the fastverk console — hosted, or in your own cloud.