From 2ad93119613bce1b3ef3d8c2a951e7ffee02fd6c Mon Sep 17 00:00:00 2001 From: moosecrap Date: Sun, 1 Nov 2026 21:25:41 -0800 Subject: [PATCH] Ask user tool --- README.md | 6 ++++++ tools/__init__.py | 13 +++++++++++++ tools/ask_user.py | 31 +++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 tools/ask_user.py diff --git a/README.md b/README.md index 8ebf60d..e9a9617 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,12 @@ Allows the model to browse Wikipedia using its API. * **Workflow**: Use `mode='summary'` (default) to get an overview and a Table of Contents. Use `mode='section'` with a linear index from the ToC to dive into specific details. * **Features**: Returns raw Wikitext to save tokens, handles redirects, and automatically falls back to a search result list if a page is not found. +### 🗣️ `ask_user` +Asks the human operator a question and waits for their answer. +* **Best for**: Circuit-breaking when the model is missing critical context or needs guidance. Use this to interject when the model gets stuck. +* **Workflow**: The model calls `ask_user` with a `question` string. The question is printed to the MCP server's terminal, and the server blocks until you type an answer and press Enter. +* **Behavior**: Blocks indefinitely — there is no timeout. The answer is returned to the model as the tool result. + --- ## Installation & Requirements diff --git a/tools/__init__.py b/tools/__init__.py index 5b07e9d..1e0b3f2 100644 --- a/tools/__init__.py +++ b/tools/__init__.py @@ -26,6 +26,7 @@ from .browse_wikipedia import handle as wikipedia_handler from .get_model_info import handle as get_model_info_handler from .generate_image import handle as generate_image_handler from .search_tags import handle as search_tags_handler +from .ask_user import handle as ask_user_handler # Central registry of all available tools TOOL_REGISTRY = [ @@ -167,4 +168,16 @@ TOOL_REGISTRY = [ }, handler=search_tags_handler ), + Tool( + name="ask_user", + description="Asks the human operator a question and waits for their answer. Use this when the model is missing critical information or needs guidance. This blocks the server until the user responds.", + schema={ + "type": "object", + "properties": { + "question": {"type": "string", "description": "The question to ask the human operator."} + }, + "required": ["question"], + }, + handler=ask_user_handler + ), ] diff --git a/tools/ask_user.py b/tools/ask_user.py new file mode 100644 index 0000000..d590d83 --- /dev/null +++ b/tools/ask_user.py @@ -0,0 +1,31 @@ +import asyncio +from typing import Any, Dict +from tools.utils import ToolError + +logger = None # logging not wired up in this module; keep it simple + +async def handle(args: Dict[str, Any]): + """ + Asks the human operator a question and blocks until they type an answer. + Intended as a circuit-breaker when the model is missing critical context + or needs guidance. Prints the question to the MCP server's terminal and + reads the answer from stdin. + """ + question = args.get("question") + if not question: + raise ToolError("Missing 'question' argument") + + # Print the question to the server terminal so the human sees it. + print(f">>> {question}") + + try: + answer = await asyncio.to_thread(input, ">>> ") + except (EOFError, KeyboardInterrupt): + print("\n>>> Input interrupted.") + raise ToolError("ask_user was interrupted") + + answer = (answer or "").strip() + if not answer: + raise ToolError("ask_user received an empty answer") + + return [{"type": "text", "text": answer}]