Ask a human for input from MCP clients using local dialogs or Telegram.
Project description
Ask Human MCP
Simple MCP server that lets AI agents ask humans for input and wait for an answer.
Supports Telegram (including files) and local OS dialogs.
It gives MCP-capable agents a focused tool for cases where guessing is the wrong move. The agent can pause, show the question and relevant context, wait for your answer, then continue the same workflow.
- Why
- Features
- Installation
- MCP client setup
- AGENTS.md instructions
- Configuration
- Tool reference
- Development
- Security and Privacy
- License
Why
Despite agents improving every month, they still tend to make assumptions and produce "perfectly working nonsense" when all they needed to do was pause and ask the human who issued the task for clarification.
Codex (as of May 2026) even has this in its system instructions:
... strongly prefer making reasonable assumptions and executing the user's request rather than stopping to ask questions.
In general, agents often hit decisions that are not knowable from the repository or local environment:
- product or design preferences
- risky implementation tradeoffs
- missing credentials, deployment constraints, or domain rules
- ambiguous requirements that should not be guessed
- offline or real-world context that only the human can provide
Ask Human exposes the ask_human MCP tool, so the agent can ask directly instead of silently making assumptions.
Another useful application is enabling an "interactive mode" when an agent needs to ask several follow-up questions while working on a task. You prompt your agent:
- Using the
ask_humantool, guide me step by step through BIOS debug on my other laptop. I will send you photos of the screen after each step
And Codex (or your agent of choice) will do just that, because it now has a well-suited tool for that workflow.
Features
- Native local dialogs on macOS, Linux, and Windows
- Optional Telegram response channel for mobile/away-from-keyboard replies with support for files and other media (up to 20 MB)
- Configurable timeouts. When the MCP tool is called, the agent waits for your reply for as long as the client allows. Tested up to 24h with Codex.
Installation
Recommended: No installation, use uvx
uvx is the recommended way to run Ask Human from an MCP client. It does
not require a prior install: it downloads the ask-human package on first
invocation, caches it, and runs it in an isolated environment.
Any MCP client that can launch a stdio command can use it that way. Example MCP configuration shape:
command: uvx
args: ask-human --transport stdio
See MCP Client Setup for exact setup with uvx for popular clients.
To manually run the CLI directly:
uvx ask-human --help
Persistent Install via pipx or pip
If you prefer a persistent CLI install instead of uvx, you can use pipx or pip install --user:
pipx install ask-human
or pip:
python -m pip install --user ask-human
For the pip path, make sure your Python user scripts directory is on PATH.
After a persistent install, MCP clients can run the installed executable directly. The MCP config shape is:
command: ask-human
args: --transport stdio
MCP client setup
Codex, Claude Code, Cursor, and other MCP-capable agent clients can use Ask Human by adding the MCP server to their config.
NOTE: Examples below use
ask-humanconsistently as the package name, executable name, and MCP server name. Keeping those names aligned is intentional and recommended, though the MCP server name is configurable in your client.
NOTE: It is also recommended to increase your client's MCP tool-call timeout as much as practical, so you avoid a situation where the agent asks something important, the MCP call times out, and the agent goes back to assumptions / inferring.
Codex
Codex MCP docs: https://developers.openai.com/codex/mcp
Using Codex CLI mcp add:
Using uvx (no install step):
codex mcp add ask-human -- uvx ask-human --transport stdio
Or if you installed using pip / pipx:
codex mcp add ask-human -- ask-human --transport stdio
Or manually add config.toml entry:
Open your ~/.codex/config.toml and add a new entry:
[mcp_servers.ask-human]
command = "uvx"
args = ["ask-human", "--transport", "stdio"]
Configuration is done by adding other args; see Configuration for available options.
Restart any active Codex sessions after adding the MCP server or changing config. If you use the VS Code extension, use "Reload Window" or "Restart Extension Host".
Claude Code
- Claude Code MCP docs: https://docs.anthropic.com/en/docs/claude-code/mcp
One typical setup is to add the server through the Claude Code MCP command:
claude mcp add --transport stdio ask-human -- uvx ask-human --transport stdio
Cursor
- Cursor MCP docs: https://docs.cursor.com/context/model-context-protocol
Add this to your Cursor MCP config:
{
"mcpServers": {
"ask-human": {
"command": "uvx",
"args": ["ask-human", "--transport", "stdio"]
}
}
}
Local Development
{
"mcpServers": {
"ask-human-dev": {
"command": "python",
"args": ["-m", "ask_human", "--transport", "stdio"],
"cwd": "/path/to/ask-human",
"env": {
"PYTHONPATH": "/path/to/ask-human/src"
}
}
}
}
The included mcp-server-config.json has copyable examples for installed,
uvx, and local-dev usage.
AGENTS.md instructions
To make an agent prefer asking questions via this tool instead of making assumptions, add an instruction to your global or workspace AGENTS.md file, such as:
If a required fact or preference cannot be discovered locally and a wrong
assumption could affect correctness, safety, architecture, or user intent, use
the `ask_human` tool before proceeding.
Full tested AGENTS.md instruction example
## Ask human tool
If a missing fact, design choice, or user preference is not 100% clear, and a wrong
assumption could materially affect correctness, safety, architecture, or user intent,
use `ask_human` mcp/tool before proceeding.
If the tool is unavailable or times out without a human response, do not proceed
and do not roll back changes unless it is absolutely necessary (e.g. a broken
live/production system, runaway resource consumption, etc.). Instead, stop, report
the current state, repeat the context and question, and let the user answer normally.
Do not optimize for completing the task in one uninterrupted run if clarification
would lead to a better decision. Making correct design decisions is more important
than finishing a subtask without interruptions.
Use `ask_human` especially for ambiguous requirements, risky tradeoffs, irreversible
actions, external side effects, and situations where multiple reasonable approaches
exist and the preferred one is not 100% clear. Keep the question concise where possible,
but include necessary context details
so the user is properly informed.
When a task requires many decisions from the user, or when the user explicitly asks
you to ask questions or use `ask_human` tool, do not limit that to the initial planning phase.
Continue talking with the user via that tool during implementation whenever a new assumption,
design choice, external value, or behavior decision appears that was not already answered.
Do not treat early answers as broad permission to infer the remaining details silently.
## Contradictions and questionable requests
If the user's request appears to contradict earlier instructions, previous work,
the current state, or a known constraint, do not silently choose one interpretation.
Briefly explain the conflict using `ask_human`.
If the request seems technically wrong, unsafe, or likely to cause unintended consequences,
always use `ask_human` to confirm that the user really means it before proceeding.
Common source of confusion: the user may think they're on one branch or workspace
when they're actually on another.
Even a carefully written AGENTS.md can still hit intrinsic agent limitations: system instructions may override it, or the agent may have learned to provide a "complete solution" instead of asking questions. Whatever the reason, the agent may sometimes ignore the instruction to use this tool in the intended scenarios (true at least for Codex as of May 2026).
To increase the chance that the agent asks before making a wrong assumption, add a reminder like this directly to your prompt when setting a task:
...<your normal prompt>...
P.S. Remember to use the ask_human tool whenever you hit any ambiguity, uncertainty,
non-obvious implications, something that is not 100% explicitly agreed, or for any
other reason requires or might require my input. Never infer or make assumptions
(even "conservative") in such cases, use `ask_human` tool instead (or stop if tool
is unavailable or does not return usable output).
Configuration
Telegram as response channel
To make your agent message you via Telegram when it needs your input, add:
--telegram "<bot_token> <chat_id>" --response-channel telegram # or "--response-channel both"
to the MCP config args list.
When you receive an agent prompt, you can respond with text, a photo, another media/file attachment (up to 20 MB), location, etc. Voice auto-transcription is not supported yet. A capable agent will be able to inspect supported files/media. Files are saved to a temporary directory; see Telegram file download directory.
Telegram prompts render common agent Markdown, such as bold, italic, inline code, fenced code blocks, links, headings, quotes, and lists, through Telegram-supported HTML. The prompt metadata remains in an expandable Telegram quote block. If Telegram rejects the formatting, the same prompt is retried as plain text so the message is still delivered.
How to create a Telegram bot and obtain chat ID
-
Open Telegram and message
@BotFather. -
Run
/newbotand follow BotFather's prompts. -
Copy the bot token.
-
Send any message to your new bot.
-
Open this URL in a browser, replacing
<BOT_TOKEN>:https://api.telegram.org/bot<BOT_TOKEN>/getUpdates
-
Find
message.chat.idin the JSON response. That is the<chat_id>. -
Keep the bot token secret. Anyone with the token can control the bot.
For a group chat, add the bot to the group, send a message in the group, then
call getUpdates and use the group's chat.id.
Important:
If you run agents on different machines or inside different VMs, you must use a different Telegram bot token for each machine/environment. That limitation is due to how Telegram's getUpdates mechanism works. Using the same bot for different environments may be buggy and unreliable.
How Telegram broker works
Telegram delivery uses a local auto-started broker process instead of letting
each agent session poll getUpdates independently.
Current behavior:
- one local broker is created per Telegram target (
bot_token + chat_id) - sessions on the same machine that use the same target reuse that broker
- different Telegram targets on the same machine use different brokers
- broker discovery uses persisted local state plus a health check
- the broker binds to
127.0.0.1on an OS-assigned free port by default
This makes same-machine concurrent Telegram prompts safe.
Current limitation:
- cross-machine or shared-server coordination is not implemented yet
- if two different machines use the same bot target at the same time, replies can still be consumed by the wrong machine
Telegram prompt metadata includes:
Prompt ID: ...Broker: <label> [<id>]
That helps identify which local broker instance sent a prompt and makes some cross-machine mix-ups easier to diagnose.
Advanced/manual broker mode is mainly for debugging and future remote deployment:
ask-human --telegram-broker --telegram "<bot_token> <chat_id>"
Stop a local broker on Windows for testing or troubleshooting:
Get-CimInstance Win32_Process |
Where-Object {
$_.Name -like 'python*' -and
$_.CommandLine -like '*ask_human*' -and
$_.CommandLine -like '*--telegram-broker*'
} |
ForEach-Object { Stop-Process -Id $_.ProcessId -Force }
The next Telegram prompt auto-starts a fresh local broker if one is needed.
In both mode:
- macOS and Linux try to close the local dialog when the Telegram reply arrives first
- Windows keeps the current Tk dialog behavior; if Telegram wins first, the local dialog may stay open and any later answer there will be ignored
Telegram reply behavior:
- use Telegram's Reply feature on the bot's question message
- long text replies that Telegram splits into multiple reply messages are recombined when the split parts still reply to the same bot message
- if a local broker is actively waiting and you send a non-reply message, it sends a short warning that the message is ignored and you must use Reply
- if you reply to a message that is not the currently active question, it sends a warning instead of silently consuming the reply
- if you reply to one of this broker's own older inactive prompt messages, it sends a short warning that the old question is no longer active
- successful replies get a
Received [Prompt ID]acknowledgement - supported replies include text, single files/media messages up to 20 MB, location, venue, and contact
- albums/media groups are not supported yet; reply again with a single message
- files are downloaded locally and returned to the agent as local paths
- replies that appear intended for another broker instance trigger a warning instead of being silently misrouted
- Telegram delivery failures for the initial question or retry/warning messages are returned to the agent as prompt errors
Config stubs
Codex config stub:
Template for your ~/.codex/config.toml:
[mcp_servers.ask-human]
command = "uvx"
args = [
"ask-human",
"--transport", "stdio",
"--timeout-seconds", "86400", # tool internal timeout; 86400 = 24 h
"--show-timing-info", # show remaining time to answer
"--response-channel", "both", # dialog | telegram | both
"--telegram", "<bot_token> <chat_id>", # creds for your personal tg bot used ONLY ON THIS MACHINE
"--dialog-title", "Codex asks..." # Custom OS dialogue title
]
# make sure client tool call timeout is same as or greater than tool internal timeout
tool_timeout_sec = 86400 # 24 h
Claude Code config stub:
Project-scoped .mcp.json equivalent:
{
"mcpServers": {
"ask-human": {
"type": "stdio",
"command": "uvx",
"args": [
"ask-human",
"--transport", "stdio",
"--timeout-seconds", "86400",
"--show-timing-info",
"--response-channel", "both",
"--telegram", "<bot_token> <chat_id>",
"--dialog-title", "Claude asks..."
],
"timeout": 86400000
}
}
}
timeout is Claude Code's per-server tool-call timeout in milliseconds.
Cursor config stub:
Project-local .cursor/mcp.json or global ~/.cursor/mcp.json:
{
"mcpServers": {
"ask-human": {
"type": "stdio",
"command": "uvx",
"args": [
"ask-human",
"--transport", "stdio",
"--timeout-seconds", "86400",
"--show-timing-info",
"--response-channel", "both",
"--telegram", "<bot_token> <chat_id>",
"--dialog-title", "Cursor asks..."
]
}
}
}
Command args reference
Transports
STDIO is the default and is what most local MCP clients use:
ask-human --transport stdio
SSE is available for clients that connect over HTTP:
ask-human --transport sse --host 0.0.0.0 --port 8080
Timeout
The internal timeout that affects OS dialog and Telegram prompts. Defaults to 120 seconds.
ask-human --transport stdio --timeout-seconds 1200
MCP clients may enforce their own tool-call timeout. If your client supports a
tool timeout setting, set it to at least the same value as --timeout-seconds;
otherwise the client may stop waiting before Ask Human does.
Response channels
Use --response-channel to choose where replies are collected:
dialog: local native dialog only, defaulttelegram: Telegram onlyboth: local dialog and Telegram at the same time; first reply wins
ask-human --transport stdio --response-channel telegram --telegram "<bot_token> <chat_id>"
Telegram file download directory:
--telegram-download-dir "~/Downloads/ask-human"
Defaults to a folder under the system temp directory. Supports ~, environment variables such as %USERPROFILE%, and {cwd}.
Timing metadata
Use --show-timing-info to include compact timing metadata showing when the prompt was issued and when the tool will time out:
ask-human --transport stdio --show-timing-info
OS dialog title
The default dialog title is Agent asks....
ask-human --transport stdio --dialog-title "Codex Needs Input"
Tool reference
ask_human
Ask the human for input during agent workflows.
Parameters:
question(string, required): specific question, max 1000 characterscontext(string, optional): short background, max 2000 characters
Returns one of:
User response: ...when the user answersEmpty response receivedwhen the user clicks OK without textTimeout: ...when no response arrives in timeCancelled: ...when the user cancelsError: ...for validation or system failures
Example tool call:
ask_human(
question="Should this import overwrite an existing session or stop?",
context="Both behaviors are possible, but choosing wrong could lose user data."
)
Development
Requires Python 3.10+, and also:
- macOS:
osascript - Linux:
zenity - Windows:
tkinter
Install for development:
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
Run checks:
black --check .
isort --check-only .
mypy src
pyright
pytest
Build locally:
python -m build
python -m twine check dist/*
Security and Privacy
- Local dialog prompts stay on your machine.
- Telegram prompts and replies go through Telegram when that channel is enabled.
- Telegram files are downloaded to a local directory and returned as paths.
- Bot tokens should be treated as secrets.
- Ask Human does not run a remote server by default.
License
MIT License. See LICENSE.
Based on galprz/ask-human-for-context.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ask_human-0.3.1.tar.gz.
File metadata
- Download URL: ask_human-0.3.1.tar.gz
- Upload date:
- Size: 1.2 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f749e96820535b2ccfd52506bb716db88df9f02cfbd58cdb712481dcaad96fc3
|
|
| MD5 |
90e3a7ee857c8eea592bfe0b41168150
|
|
| BLAKE2b-256 |
3c38f432e0d021867409f862514e8cd0f6c19cefc52c5cc7b946a4393bb5d68a
|
Provenance
The following attestation bundles were made for ask_human-0.3.1.tar.gz:
Publisher:
publish-pypi.yml on alexchexes/ask-human
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ask_human-0.3.1.tar.gz -
Subject digest:
f749e96820535b2ccfd52506bb716db88df9f02cfbd58cdb712481dcaad96fc3 - Sigstore transparency entry: 1732468422
- Sigstore integration time:
-
Permalink:
alexchexes/ask-human@ca4e46a16df279fac89f40f484b80853fd6c119f -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/alexchexes
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@ca4e46a16df279fac89f40f484b80853fd6c119f -
Trigger Event:
release
-
Statement type:
File details
Details for the file ask_human-0.3.1-py3-none-any.whl.
File metadata
- Download URL: ask_human-0.3.1-py3-none-any.whl
- Upload date:
- Size: 1.1 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cbcafafbbb31bccf84fa854d4702eeaa30bd4f61c48fa63667be7b611cb84ac9
|
|
| MD5 |
0d5c424d891931e027c3462e32961e94
|
|
| BLAKE2b-256 |
805582bf5edb2e5b881aa1b07db2359b414665965c56fcaca8c2725d501c3a76
|
Provenance
The following attestation bundles were made for ask_human-0.3.1-py3-none-any.whl:
Publisher:
publish-pypi.yml on alexchexes/ask-human
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ask_human-0.3.1-py3-none-any.whl -
Subject digest:
cbcafafbbb31bccf84fa854d4702eeaa30bd4f61c48fa63667be7b611cb84ac9 - Sigstore transparency entry: 1732468446
- Sigstore integration time:
-
Permalink:
alexchexes/ask-human@ca4e46a16df279fac89f40f484b80853fd6c119f -
Branch / Tag:
refs/tags/v0.3.1 - Owner: https://github.com/alexchexes
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-pypi.yml@ca4e46a16df279fac89f40f484b80853fd6c119f -
Trigger Event:
release
-
Statement type: