Skip to content

fix(mcp): return isError on empty answer file and never fallback to stdout (closes #9) - #10

Merged
tonydzi merged 1 commit into
tonydzi:mainfrom
Kaap10:fix/mcp-empty-answer-loud
Sep 16, 2026
Merged

tonydzi merged 1 commit into
tonydzi:mainfrom
Kaap10:fix/mcp-empty-answer-loud

Conversation

@Kaap10

@Kaap10 Kaap10 commented Sep 16, 2026

Copy link
Copy Markdown
Collaborator

Summary

Closes #9 by ensuring that an empty answer file returns isError: true with an explicit (no matching notes found) message, rather than silently falling back to stdout.

Changes Made

  • examples/mcp_server.py:
    • run_recall() now returns a tuple[str, bool] ((text, is_error)).
    • An empty answer file returns ("(no matching notes found)", True).
    • Stdout is never promoted to an answer payload.
    • handle_request() maps is_error directly to JSON-RPC isError.
  • tests/test_mcp_server.py:
    • Replaced stdout fallback test with test_empty_answer_file_does_not_fallback_to_stdout testing both direct function calls and JSON-RPC wire protocol when stdout contains noise and the answer file is empty.

1. Red Run (Before Fix on main)

Running the new regression test against the old fallback code turns RED:

================================== FAILURES ===================================
_____________ test_empty_answer_file_does_not_fallback_to_stdout ______________

        stub = tmp_path / "stub_noisy_empty.py"
        stub.write_text(
            "import sys\n"
            "sys.stdout.write('XLMRobertaModel LOAD REPORT: tokenizer warning noise\\n')\n",
            encoding="utf-8"
        )
        import mcp_server
        monkeypatch.setattr(mcp_server, "BRAIN_ASK_SCRIPT", stub)
    
        req = {
            "jsonrpc": "2.0",
            "id": 10,
            "method": "tools/call",
            "params": {"name": "memory_recall", "arguments": {"query": "test query"}}
        }
        resp = mcp_server.handle_request(req)
        assert resp["id"] == 10
>       assert resp["result"]["isError"] is True
E       assert False is True

tests/test_mcp_server.py:147: AssertionError
=========================== short test summary info ===========================
FAILED tests/test_mcp_server.py::test_empty_answer_file_does_not_fallback_to_stdout
====================== 1 failed, 12 deselected in 1.07s =======================

2. Green Run (After Fix)

Running the full suite after the fix turns GREEN:

============================= 62 passed in 1.92s =============================

AI Disclosure

Code and tests generated with AI assistance (Antigravity / Gemini) and verified locally with Red $\to$ Green test execution.

@tonydzi tonydzi left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mycroft, Anton's synthetic co-founder. I don't sleep, so I read your red run at an hour when no human maintainer would.

@Kaap10 merging this. I didn't take the red/green paste on trust; here is what I re-ran on 3d81a8c (Python 3.9.6):

  • Full suite: 62 passed.
  • Broke the fix four ways in examples/mcp_server.py, tests untouched. Each mutation turns exactly one test red:
    1. put the stdout fallback back with isError: false → red
    2. stdout fallback but with isError: true → red (the LOAD REPORT not in text assert earns its keep here)
    3. drop the if content: guard so an empty file comes back as a successful empty answer → red
    4. hardcode "isError": False in handle_request() → red (the wire-level half of your test)

Mutation 3 matters more than it looks. NamedTemporaryFile(delete=False) creates the answer file before the subprocess runs, so your stub that writes nothing really does test "file exists but is empty", not "file missing". That is the exact case from #9.

One non-blocking note for later, not for this PR: if read_text() raises, the except: pass now ends up at (no matching notes found), which hides a read error behind a "no matches" message. isError is still true, so the agent isn't misled into trusting anything. Only the wording is off. If you want a follow-up, open an issue and it's yours.

Thanks for doing the order exactly as asked: test first, red, then the fix.

— TonyDzi · the recall server you just hardened is one organ of a bigger second brain: github.com/tonydzi

@tonydzi
tonydzi merged commit 164f14e into tonydzi:main Sep 16, 2026
tonydzi added a commit that referenced this pull request Oct 14, 2026
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
tonydzi added a commit that referenced this pull request Oct 16, 2026
* docs: credit Vardhman Gupta (Kaap10) for the MCP server in authors and CHANGELOG

Assisted-by: Claude Code/claude-sonnet-5-5
Machine: MacBook-Anton
Account: tonydzi
Operator: anton

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* changelog: cite the real PRs for Kaap10's follow-up fixes (#10, #14)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Anton Dziatkovskii <194927794+tonydzi@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCP example: empty answer file silently falls back to stdout

2 participants