Summary
The `mempalace_search` tool marks `wing` and `room` as optional in its schema, but the handler rejects empty-string values with `{"error": "wing must be a non-empty string"}`. This is confusing and trips up LLM agents that default to filling every declared parameter.
Reproduction
# Call via MCP stdio (or from Claude Code / OpenCode / any MCP client)
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "mempalace_search",
"arguments": {
"query": "some topic",
"wing": "",
"room": ""
}
}
}
Response:
{"error": "wing must be a non-empty string"}
Fixing wing and retrying with room: "" returns the equivalent error for room.
Schema context
From mempalace_search's tool definition (trimmed):
{
"name": "mempalace_search",
"inputSchema": {
"type": "object",
"properties": {
"query": {"type": "string", ...},
"wing": {"type": "string", "description": "Filter by wing (optional)"},
"room": {"type": "string", "description": "Filter by room (optional)"},
"limit": {"type": "integer", ...},
...
},
"required": ["query"]
}
}
The tool advertises wing and room as optional ("(optional)" in description, not in required array), so a caller reasonably expects either omission or empty value to mean "don't filter."
Why it matters (real-world agent trace)
In an OpenCode session, we give our agent an instructions file containing:
Before answering... call mempalace_search with just the query text (no wing/room filter).
The agent faithfully tried to comply but interpreted "no filter" as "empty string":
Call 1: {"query": "TrainTrac Express API Feed Management relationship", "wing": "", "room": ""}
→ error: wing must be a non-empty string
Call 2: {"query": "TrainTrac Feed domain relationship", "wing": "all", "room": ""}
→ error: room must be a non-empty string
Agent then gave up on mempalace_search and fell back to grep. Two otherwise-productive queries wasted.
This pattern will hit anyone whose agent instructions tell it to skip the filter — models often default to filling every declared field, especially when schemas mark optionality with description text rather than JSON Schema structure.
Proposed fix
Two options, listed in order of preference:
A) Treat empty string as "no filter" — easiest for callers, matches the "optional" intent:
if wing in (None, ""):
wing = None # -> no filter
B) Improve the error message — less breaking, still helpful:
{"error": "wing is empty — omit the 'wing' field from the request to skip filtering, or pass an actual wing name"}
Either works. (A) means agents never fail on this, and existing working callers are unaffected.
Workarounds I used
For now I've pushed a rule tweak in our devbox repo instructing the agent explicitly to omit wing / room rather than pass empty strings — visible to future readers at MILCGroup/milc-devbox#130. Happy to open a PR here too if option (A) looks good.
Environment
- mempalace 3.3.1 (from
pip install mempalace, installed ~2 days ago)
- Called via MCP stdio from OpenCode 0.x
- Python 3.10 on Ubuntu 22.04
Summary
The `mempalace_search` tool marks `wing` and `room` as optional in its schema, but the handler rejects empty-string values with `{"error": "wing must be a non-empty string"}`. This is confusing and trips up LLM agents that default to filling every declared parameter.
Reproduction
Response:
{"error": "wing must be a non-empty string"}Fixing
wingand retrying withroom: ""returns the equivalent error forroom.Schema context
From
mempalace_search's tool definition (trimmed):{ "name": "mempalace_search", "inputSchema": { "type": "object", "properties": { "query": {"type": "string", ...}, "wing": {"type": "string", "description": "Filter by wing (optional)"}, "room": {"type": "string", "description": "Filter by room (optional)"}, "limit": {"type": "integer", ...}, ... }, "required": ["query"] } }The tool advertises
wingandroomas optional ("(optional)"in description, not inrequiredarray), so a caller reasonably expects either omission or empty value to mean "don't filter."Why it matters (real-world agent trace)
In an OpenCode session, we give our agent an instructions file containing:
The agent faithfully tried to comply but interpreted "no filter" as "empty string":
Agent then gave up on
mempalace_searchand fell back to grep. Two otherwise-productive queries wasted.This pattern will hit anyone whose agent instructions tell it to skip the filter — models often default to filling every declared field, especially when schemas mark optionality with description text rather than JSON Schema structure.
Proposed fix
Two options, listed in order of preference:
A) Treat empty string as "no filter" — easiest for callers, matches the "optional" intent:
B) Improve the error message — less breaking, still helpful:
{"error": "wing is empty — omit the 'wing' field from the request to skip filtering, or pass an actual wing name"}Either works. (A) means agents never fail on this, and existing working callers are unaffected.
Workarounds I used
For now I've pushed a rule tweak in our devbox repo instructing the agent explicitly to omit
wing/roomrather than pass empty strings — visible to future readers at MILCGroup/milc-devbox#130. Happy to open a PR here too if option (A) looks good.Environment
pip install mempalace, installed ~2 days ago)