F1: Replace `split_whitespace()` with `shlex::split()` in
`configured_mcp_server` so quoted paths with internal spaces (e.g.
`uv run "/My Bot/jambot"`) survive the split. On unmatched quotes,
fall back to verbatim command — D1 surfaces the spawn failure as a
warning instead of a dead agent. Added `shlex` 1.x as a direct dep
(already in Cargo.lock as a transitive dep).
F2: Add focused regression tests for `create_session_and_apply_model`
MCP fallback path — scripted AcpClient returns an MCP-flavored error
on first session/new, success on retry with empty mcpServers. Also
covers non-MCP AgentError propagation (no retry triggered).
D2: The MCP editor's command field is passed verbatim to
Command::new(), so "uv run /path/to/jambot" tries to find a single
binary with that full string as its name. Shell-split in
configured_mcp_server(): first whitespace token becomes the executable,
remaining tokens prepend before user-supplied args.
D1: When a user-configured MCP server fails to spawn, the ACP agent
returns a JSON-RPC error that previously killed the entire turn. Catch
MCP-related AgentError in create_session_and_apply_model and retry
session creation with empty mcp_servers so the agent can still respond.
Surface the original error via observer as a warning.
An inherited-layer mutation (global config or persona definition) could
silently push an existing buzz-agent over the 15-server effective cap,
breaking it at next spawn. Add pre-save cross-checks at both save
paths so the save is rejected atomically with the offending agent named.
F1: Effective-merge MCP cap check at agent create/update save time.
validate_effective_mcp_cap calls effective_buzz_agent_mcp_servers
(the same resolver used at spawn) and rejects when the three-layer
merge (global < definition < agent) exceeds MAX_USER_MCP_SERVERS.
Prevents a per-layer-valid record from silently breaking at spawn or
emptying the WYSIWYG surface. Editor now shows a destructive error
whenever effective count exceeds the cap (fires on rename too).
4 Rust unit tests: 15-global+1-local → Err, at-cap → Ok,
rename-unmask → Err, non-buzz-agent skip.
F2: Complete the client-side Rust mirror — validateMcpServerRow now
checks command NUL + ≤32KB; new validateMcpServerArg checks arg
NUL + ≤32KB with inline subrow errors; new validateMcpServerListPayload
checks aggregate total payload ≤256KB (name+command+args+env bytes
across all servers) with editor-level error. Adds MAX_ENV_TOTAL_BYTES
constant. 9 unit tests: command NUL/oversize/at-limit, arg NUL/oversize
/valid, payload under/over/at-limit.
check-file-sizes.mjs: agent_models.rs override bumped 1079→1082
(+3 lines for the effective-cap block).
D1 CRITICAL: default each field in get_global_agent_config bridge handler
so partial seeds don't crash McpServersEditor; add defense-in-depth
coercion at the McpServersEditor value boundary.
D2 IMPORTANT: split buzzAgentSurface into empty/populated fixtures so
test 06 ("empty MCP servers") doesn't collide with the filesystem row;
add test 06b covering populated WYSIWYG read-only display.
D3 IMPORTANT: count effective enabled servers (local + inherited not
overridden) for the cap, gating both Add button and Enabled switch;
extract effectiveEnabledCount helper with 6 unit tests.
D4 IMPORTANT: add validateMcpServerEnvEntry mirroring Rust's
validate_user_env_keys boundary (POSIX key format, reserved keys,
NUL-free values, per-value byte cap); render inline subrow errors;
12 unit tests covering all rejection paths.
D5 MINOR: replace localeCompare with ASCII byte-order comparator in
mergeMcpServersByName to match Rust BTreeMap ordering; add mixed-case
/symbol test.
New row-based editor for the local buzz-agent MCP server layer, modeled
on EnvVarsEditor: per-server Name/Command/repeatable-Args/repeatable-Env
rows plus an Enabled toggle, client-side validation mirroring the Rust
validate_mcp_servers grammar (name charset, length, __, reserved name,
uniqueness, command-required-when-enabled), and read-only inherited-layer
rows a same-named local row overrides or masks. Command and Args are
separate fields (Q1) — no combined command string, no shell-quote
dependency. Not yet mounted in any dialog (P3).
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Wires the buzzAgentSlot prop that McpServersSection has exposed since
#1780 with the RuntimeConfigSurface.buzzAgentMcpServers field added in
P0. AgentConfigPanel now renders the effective merged (global <
definition < agent) enabled-server list via a new BuzzAgentMcpServerRow,
giving Will's WYSIWYG requirement (Q2) its read-only half. Also fixes
McpServersSection's fallback text, which previously rendered unreachable
for buzz-agent (the extensions-based branch never executes there since
buzz-agent always reports empty extensions).
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Add McpServerConfig/McpServerEnvVar FE types (camelCase mirror of the
Rust McpServerConfig) and mcpServers fields on ManagedAgent, AgentPersona,
GlobalAgentConfig, and the create/update managed-agent and persona IPC
inputs. Threads mcpServers through fromRawManagedAgent/fromRawPersona and
the invoke builders in tauri.ts/tauriPersonas.ts with the same
absent-vs-present contract as envVars (create sends mcpServers ?? [],
update sends it only when provided). Adds the buzzAgentMcpServers surface
field (populated on the backend by 859b8bbbe) to RuntimeConfigSurface.
Wires the e2eBridge.ts mock to match: mcp_servers on the local
RawManagedAgent/RawPersona types, a cloneMcpServer helper mirroring the
existing clone* helpers, mcp_servers handling in the create/update
persona and managed-agent mock handlers, and buzzAgentMcpServers on every
buildMockConfigSurface fixture (a sample entry on the buzz-agent fixture
so the read-only display has something to render by default).
Bumps two file-size overrides (tauri.ts, types.ts) to the gate's own
split-count for this diff.
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Add buzz_agent_mcp_servers to RuntimeConfigSurface, populated by
resolve_config_surface via the existing effective_buzz_agent_mcp_servers
merge (global < definition < agent, enabled-only) for the buzz-agent
runtime only. Every other runtime keeps the field empty and continues
to surface its servers via extensions.
This is the WYSIWYG read path the PR3 UI's read-only buzzAgentSlot will
consume — the effective list is now reachable from the config-bridge
surface the frontend already reads, matching what actually runs at
spawn (spawn_hash.rs, runtime.rs) rather than just the agent's own
record layer.
Also bumps two pre-existing file-size overrides (agent_config.rs,
readiness.rs) to their gate's own split-count, matching this diff and
a prior unaccounted +1 line already on the branch.
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Borrow the disabled mask for validation before moving it into the merge assertion, avoiding an unnecessary clone.
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
New snapshot construction sites added after the original MCP change require empty local-only MCP configuration. Raise the discovery fixture-file exception by the two required fields.
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
F1: Extend env_secrets_from_request in backend.rs to harvest
mcp_servers[*].env[*].value alongside env_vars, so provider errors
that echo MCP env values are redacted from desktop-visible last_error.
Add two regression tests: one verifying harvest coverage, one verifying
end-to-end redaction.
F2: Extend validate_mcp_servers in types/mcp_servers.rs to mirror the
buzz-agent name grammar (1-128 bytes, ASCII alnum/_/-, no __) and
reserve the built-in buzz-dev-mcp name. Both checks fire at every IPC
save boundary, so names that would fail at spawn are rejected at edit
time. Add tests covering invalid chars, double-underscore, reserved
name, valid grammar.
F3: Restructure build_mcp_servers in buzz-acp/src/lib.rs so the
built-in server push is conditional on mcp_command being non-empty, but
configured_mcp_servers are always appended. Previously the early-return
on empty mcp_command silently discarded user-configured servers even
though they don't depend on the built-in slot. Update the test that
pinned the old drop behavior; add a complementary empty-with-no-servers
test.
F4: Add an enabled-server count check to validate_mcp_servers: a layer
with more than MAX_USER_MCP_SERVERS enabled servers is rejected at save
time rather than only at merge/spawn. Add boundary tests (15 passes,
16 fails).
MINOR: Add mcp_servers to the MUST NEVER list in agent_events.rs so
future edits don't miss the local-only invariant.
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>
Add local-only MCP server layering (global < definition < agent) for
buzz-agent. Other runtimes manage their own MCP config and are unchanged.
- McpServerConfig/McpServerTransport types with validate/merge/replace helpers
- BUZZ_ACP_MCP_SERVERS reserved env key; desktop injects transport JSON only
for buzz-agent children, explicitly removes it for all others
- spawn_config_hash includes effective MCP layer so config drift triggers restart
- build_deploy_payload forwards resolved Mcp transport to providers
- agent_snapshot excludes mcp_servers (credentials in env vars)
- GlobalAgentConfig.mcp_servers: inherits to every buzz-agent instance
- AgentDefinition.mcp_servers: definition layer (not copied into record on mint)
- ManagedAgentRecord.mcp_servers: per-agent override layer
- buzz-acp: ConfiguredMcpServer deserialized from BUZZ_ACP_MCP_SERVERS; appended
after built-in buzz-dev-mcp in build_mcp_servers
- Max 15 user-defined servers (slot 16 is reserved for buzz-dev-mcp)
- IPC validation at every save boundary: empty name, duplicate names, enabled
with empty command, NUL bytes, per-field length cap, total payload cap,
reserved env key guard
Co-authored-by: Will Pfleger <pfleger.will@gmail.com>
Signed-off-by: Will Pfleger <pfleger.will@gmail.com>