buzz MCP server cannot start in buzz-acp + streaming-only agents (Goose/Gemini) never deliver replies
- Dominant language
- Rust
- Stars
- 32.7k
- Forks
- 4.3k
- Avg merge
- 1d 13h
- Merged PRs (30d)
- 253
Description
## Title
`buzz` MCP server cannot start in buzz-acp + streaming-only agents (Goose/Gemini) never deliver replies
## Summary
When connecting an external agent that reliably answers prompts by streaming assistant text but does not reliably invoke a publish tool — notably **Goose on Gemini (GCP Vertex)** — the agent's response to an `@mention` is **silently discarded** and never appears in the channel. There are two contributing problems, and I'd like to discuss the intended fix direction before opening a PR.
I have a working local patch for the second problem (auto-publish fallback) on a branch, but per CONTRIBUTING.md ("entirely new features with no prior discussion" → likely closed) I'm opening this issue first to get maintainer sign-off on the approach.
## Environment
- Self-hosted relay (`wss://buzz.aumico.net`), closed-membership mode
- Agent: Goose 1.45.0 via ACP (`goose acp --with-builtin developer`)
- Model: Gemini 2.5 Pro via GCP Vertex AI (Service Account JSON)
- `buzz-acp` built from current `main` (3d7712cc3)
## Problem 1 (clear bug): the `buzz` MCP server cannot start
`build_mcp_servers` (`crates/buzz-acp/src/lib.rs:4190`) configures the agent's `buzz` MCP server with `args: vec![]`:
```rust
vec![McpServer {
name: ...,
command: config.mcp_command.clone(),
args: vec![], // <-- empty
...
}]
```
But the `buzz` CLI has **no implicit MCP mode and no `mcp`/`serve` subcommand**:
```
$ buzz --help
Commands:
agents, messages, channels, canvas, reactions, emoji, dms, users,
workflows, feed, social, notes, repos, patches, issues, pr, media,
upload, mem, pack, moderation, help
```
Result: when `BUZZ_ACP_MCP_COMMAND` points at the `buzz` binary, Goose's `session/new` response carries:
```json
{"_meta": {"extensionResults": [
{"name": "buzz", "success": false,
"error": "process quit before initialization: stderr = 'buzz' requires a subcommand but one was not provided [subcommands: agents, messages, channels, ...]"}
]}}
```
So the agent never gets structured `send_message` / channel tools. Only the `developer` builtin (shell) loads. This appears to be a regression / unfinished wiring: the intent (from the env-pass-through comments in `build_mcp_servers` — `BUZZ_RELAY_URL`, `BUZZ_PRIVATE_KEY`, `BUZZ_AUTH_TAG`) is clearly that `buzz` should expose itself as an MCP server, but no entry point exists for it.
**Likely fix direction:** either give `buzz` an `mcp serve` (or default-to-serve) subcommand, or point `BUZZ_ACP_MCP_COMMAND` at `buzz-dev-mcp` (which is a proper rmcp stdio server, but exposes shell/file tools, not buzz send tools). Would appreciate guidance on which was intended.
## Problem 2 (missing behavior): no reply fallback for streaming-only turns
Even with the system prompt correctly delivered (verified: `_goose/unstable/session/system-prompt/set` carries the full base prompt including *"If your turn produced anything worth knowing, you MUST publish it. Use `buzz messages send`."*), Gemini streams a text answer and never calls a publish tool across many consecutive turns. Three test mentions, three text answers, zero tool calls.
`buzz-agent` has a reply guard for this (`REPLY_GUARD_NAG`, `crates/buzz-agent/src/agent.rs:44`) — it nudges the agent if a turn ends without publishing. **`buzz-acp` has no equivalent fallback.** When the turn ends with `EndTurn` and the agent didn't publish, `PromptOutcome::Ok(_)` is returned and the streamed assistant text is discarded:
```rust
// crates/buzz-acp/src/lib.rs:3252
PromptOutcome::Ok(_) => {
pool.return_agent(result.agent); // streamed text gone
}
```
Assistant text is never shown to channel members, so a model that "answers but doesn't call tools" produces an agent that looks completely silent to users. This makes whole classes of capable models unusable in Buzz.
## Proposed fix (problem 2) — open to alternatives
I implemented an **opt-out auto-publish-reply fallback** on a local branch:
- `acp.rs`: accumulate `agent_message_chunk` text during the turn (`take_turn_text()` accessor, 32 KB cap, trims whitespace, reset on `begin_turn`)
- `pool.rs`: at the `EndTurn` success path, if the agent didn't publish and there is non-empty streamed text, post it as a signed `kind:45001` reply in the triggering thread (reuses the existing `post_failure_notice` build → sign → submit pipeline, renamed to `post_channel_reply`)
- `config.rs`: `--auto-publish-reply` flag (default **on**) / `--no-auto-publish-reply` opt-out
Exemptions (deliberate): heartbeats (no triggering thread), `MaxTokens` (truncated stream ≠ complete answer), whitespace-only text.
665 unit tests pass (4 new), clippy clean, fmt clean, no `unwrap()`/`unsafe` in the new code. ~218 lines across 4 files.
**Trade-off I want feedback on:** this *does* mask problem 1 for the common case. A maintainer may reasonably prefer to fix the MCP server (problem 1) so the agent gets a proper `send_message` tool and reliably uses it, rather than teaching the harness to publish on the agent's behalf. My counter-argument: defense-in-depth — even with a working MCP tool, a model can still finish a turn without calling it, and silently losing the answer is a bad default. But I'll defer to the project's preference.
## Reproduction (problem 1)
```bash
# Any agent that loads MCP servers (e.g. Goose):
export BUZZ_ACP_MCP_COMMAND=/path/to/buzz
buzz-acp
# → inspect the session/new response _meta.extensionResults
# → {"name":"buzz","success":false,"error":"...requires a subcommand..."}
```
## Reproduction (problem 2)
Requires a running relay + Goose configured. `@mention` the Goose agent in a channel; observe in the `buzz-acp` debug log that `agent_message_chunk` text streams but no `tool_call` for `buzz messages send` is emitted, and the turn ends with `EndTurn`. The streamed text never reaches the channel.
## What I'd like
1. Guidance on the intended fix for problem 1 (`buzz` MCP entry point vs. pointing at `buzz-dev-mcp` vs. something else).
2. A thumbs-up (or alternative direction) for the auto-publish fallback in problem 2 before I open a PR.
Happy to split these into two issues / PRs if that's cleaner. I have the working branch ready either way.
— *Related prior work: `buzz-agent`'s reply guard (`REPLY_GUARD_NAG`) solves the same class of problem for the built-in agent path.*
Contributor guide
Research direction
First get maintainer direction on whether to split the two problems and which MCP entry point is intended. Read build_mcp_servers in crates/buzz-acp/src/lib.rs, then trace the EndTurn success path around line 3252 and the related code in acp.rs, pool.rs, and config.rs. Done means the chosen MCP path starts correctly and completed streamed replies are handled without losing valid responses.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend, cli, tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100