Model Context Protocol (MCP)¶
Perspt is an optional MCP client for the governed coding agent and the
interactive chat TUI. The implementation uses the official Rust MCP SDK and
speaks MCP 2026-07-28 only. It starts with server/discover and does not
fall back to initialize or an older protocol version. A server that does
not advertise 2026-07-28 is rejected.
The client supports stdio and stateless Streamable HTTP, including:
tools, resources, resource templates, prompts, and completions;
explicit roots disclosure;
opt-in model sampling and user elicitation;
progress, logging, cancellation, catalog-change, resource-update, task, and custom notifications;
subscriptions/listenwith list-change and resource filters;multi-round tool results and the tasks extension for long-running calls.
MCP is absent when no [[external_tools]] table is configured. It does not
replace Perspt’s coding-domain tools, planner, verifier, candidate workspace,
or acceptance gate.
Quick Setup¶
This stdio example enables independent agent and chat lifecycles, discloses one root, permits sampling and elicitation, and subscribes to one resource:
[[external_tools]]
id = "docs"
transport = "stdio"
command = ["company-docs-mcp", "--stdio"]
modes = ["agent", "chat"]
timeout_ms = 30000
max_result_bytes = 1048576
max_stderr_bytes = 65536
max_task_wait_ms = 300000
env_from_env = { DOCS_TOKEN = "COMPANY_DOCS_TOKEN" }
roots = [{ uri = "file:///absolute/path/to/project", name = "Project" }]
sampling = true
max_sampling_tokens = 4096
elicitation = true
subscriptions = true
resource_subscriptions = ["file:///absolute/path/to/project/guide.md"]
tasks = true
[external_tools.tools.search]
effect = "search"
risk = "low"
footprint = { selectors = [{ kind = "scoped_argument", family = "company-docs", field = "query", access = "read" }] }
The policy key must exactly match the remote name. A footprint field must
exist in the advertised input schema. After admission the model-facing tool
is mcp.docs.search.
For Streamable HTTP use these transport fields:
[[external_tools]]
id = "records"
transport = "streamable_http"
url = "https://tools.example.test/mcp"
modes = ["agent", "chat"]
headers_from_env = { Authorization = "RECORDS_AUTHORIZATION" }
[external_tools.tools.lookup]
effect = "data_read"
risk = "low"
footprint = { selectors = [{ kind = "scoped_argument", family = "records", field = "id", access = "read" }] }
Set RECORDS_AUTHORIZATION to the complete server value, for example
Bearer .... Non-loopback endpoints require HTTPS and redirects are
disabled. Streamable HTTP is stateless under 2026-07-28; Perspt does not
recover by negotiating a legacy session.
Chat TUI¶
Run perspt --config ./config.toml chat and type /mcp. It reports
discovery failures, policy rejections, and admitted operations. /help
includes MCP and elicitation commands. The model calls tools automatically;
/mcp performs no remote call.
Normal chat starts without discovery or policy messages in the conversation.
When the model selects an admitted operation, the TUI shows one transient,
human-readable activity label and then the final answer. Raw MCP lifecycle
events, tool arguments, results, subscription notifications, and server logs
stay out of both the conversation and the reasoning panel. Use /mcp when
you explicitly want discovery and admission diagnostics. Ctrl+R remains
the reasoning control and displays only reasoning emitted by the selected
model; tool-aware Qwen turns use the same reasoning stream.
Chat has a fixed read-only authority ceiling. Mutating, shell, network-fetch,
dependency, graph, and policy effects are rejected even when the same tool is
admissible in the governed agent. perspt simple-chat intentionally creates
no MCP lifecycle.
For form or URL elicitation the input remains active and the TUI shows the request as JSON. Respond explicitly with:
/mcp accept {"field":"value"}
/mcp accept
/mcp decline
/mcp cancel
Perspt does not open an elicitation URL automatically. Form responses are JSON objects. Perspt advertises client-side schema validation as disabled, leaving the server responsible for validating the requested schema.
Terminal bracketed paste is enabled in both chat input paths. Normal terminal paste shortcuts (Command-V, Ctrl-Shift-V, or Shift-Insert, depending on the terminal) insert Unicode and multiline clipboard text at the cursor. The mode is disabled again on TUI exit.
Agent Behavior¶
Agent servers are discovered when a session assembles its node catalog. External schemas use the ordinary deferred tool-search path. Proposals, arguments, effects, grants, execution, results, and uncertain completion are governed like the rest of the coding tool plane.
Sampling uses the already selected local route. MCP model preferences cannot
redirect credentials or choose an unconfigured provider. Perspt forwards
maxTokens, temperature, stop sequences, tools, and tool choice. It
advertises tool-aware sampling but not includeContext; requests for
implicit MCP-server context are rejected.
The command-line agent has no interactive MCP form surface, so an enabled
elicitation request receives decline immediately. Chat is interactive.
SDK hosts may install their own McpElicitationProvider.
Subscriptions and Dynamic Catalogs¶
With subscriptions = true (the default), Perspt intersects its filter with
server capabilities before opening subscriptions/listen. Tool-list changes
invalidate the SDK cache; the shared runtime removes old bindings and repeats
local admission before a chat model turn. A removed tool cannot remain
callable. Resource and prompt changes, progress, logging, tasks, cancellation,
and custom extension notifications are typed McpServerEvent values for
product display or SDK consumption.
resource_subscriptions contains exact URIs and should be narrow. An empty
list still permits supported tools/prompts/resources list-change filters.
Multi-Round Results and Tasks¶
Tool calls accept complete results, bounded multi-round input-required responses, or asynchronous task handles. Inputs may request sampling, elicitation, or roots only when locally enabled; unknown kinds fail closed.
Every wire request uses timeout_ms. max_task_wait_ms is an overall
deadline across task polling and input rounds (default five minutes), and poll
hints are clamped. A failed, cancelled, malformed, or expired task becomes an
uncertain external completion for agent reconciliation.
Configuration Reference¶
Field |
Meaning |
|---|---|
|
Required ASCII id used in |
|
Exactly |
|
Direct argv for stdio or HTTP endpoint; mutually exclusive. |
|
|
|
Stdio child variable to source-variable mapping. Children otherwise
receive only |
|
HTTP header to source-variable mapping; values stay out of TOML. |
|
Per-request and discovery deadline; default 30000. |
|
Maximum accepted serialized result and raw SSE event; default 1 MiB. |
|
Rolling stdio stderr tail; default 64 KiB. |
|
Explicit absolute |
|
Opt in to server model calls and cap one request (default 4096). |
|
Opt in to form/URL elicitation; interactive in chat, declined by the non-interactive agent. |
|
Enable the listen stream (default true) and exact resource filters. |
|
Enable task/MRTR handling (default true) and its overall deadline (default 300000). |
|
Local policy tables keyed by exact remote tool name. |
Each policy accepts effect, risk, footprint, and optional
proposal_bindings. Omitting effect or footprint becomes a high-risk opaque
shell declaration and is not admitted by default.
Security Notes¶
A configured stdio command is user-selected code, and an HTTP server acts outside the candidate workspace. Admission constrains calls but does not sandbox the server. Trust its implementation/operator and grant the narrowest policy.
Result objects are size-checked after protocol decoding and SSE events before decoding. Stderr capture, subscription filters, MRTR rounds, task duration, sampling tokens, and chat tool rounds are bounded. The official SDK owns framing, correlation, cancellation, and dispatch; Perspt owns transport security, capabilities, admission, product interaction, and replay policy.
Troubleshooting¶
Symptom |
Check |
|---|---|
|
Add |
Protocol is incompatible |
Upgrade the server to 2026-07-28; there is no legacy fallback. |
No remote tools are admitted |
Add exact policies and schema-valid footprints. Resource/prompt operations may still appear when advertised. |
Stdio program or credential is missing |
Verify direct argv and map variables with |
HTTP is refused |
Use HTTPS outside localhost and check header source variables. |
Sampling is rejected |
Enable it, stay under the token cap, and omit unadvertised context. |
Elicitation is declined in agent mode |
Use chat or install an SDK host provider. |
A task times out |
Increase the overall deadline deliberately or fix the server. |