Ask Agent
Ask Agent — MCP ↔ PWA bridge
A local-first system that lets any MCP-compatible AI agent (OpenCode, Claude Code, Hermes Agent, etc.) ask the human questions in real time via a mobile-friendly PWA with browser push notifications. No Telegram, no Discord, no third-party middlemen.
┌─────────────┐ ask_user() ┌──────────────┐ Socket.IO ┌────────────┐
│ Agent / │ ───────────────► │ MCP server │ ──────────────► │ PWA in │
│ OpenCode │ ◄─────────────── │ (Node.js) │ ◄────────────── │ your phone│
└─────────────┘ user's reply └──────────────┘ answer └────────────┘
│
▼ Web Push (VAPID)
┌──────────────┐
│ Browser │
│ Notification│
└──────────────┘Why?
When an agent runs for hours, it shouldn't have to guess — it should ask. This lets you stay in flow on your phone/PC while the agent waits, without being glued to a terminal or a Telegram session.
Features
5 question types: free text, yes/no, multiple choice, 1–5 scale, confirm
Multiple concurrent questions (each with a UUID, separate timeout)
Real-time delivery via Socket.IO with automatic reconnect
Push notifications even when the PWA tab is in the background (VAPID/web-push)
Installable PWA (manifest + service worker + maskable icons)
Stateless MCP — each agent session gets its own server, scales horizontally
One command to run:
npm starton port 3010
Quick start
npm install
npm start
# open http://localhost:3010That's it. VAPID keys auto-generate on first boot (printed in the console — set VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY / VAPID_SUBJECT env vars to persist them).
MCP client config
OpenCode / Claude Code / Hermes Agent
Add to your MCP config (~/.config/opencode/mcp.json or equivalent):
{
"mcpServers": {
"ask-user": {
"type": "http",
"url": "http://localhost:3010/mcp"
}
}
}The agent will see one tool: ask_user(question, type, options?, timeoutMs?).
GitHub Actions
Expose the server with ngrok/cloudflared and use the same URL:
- run: npm install
- run: npm start &
- run: npx ngrok http 3010 --authtoken=$NGROK_TOKEN > ngrok.log &
- run: sleep 5 && cat ngrok.log # extract https URLThen point your MCP client at the ngrok URL.
Question types
| UI | Response shape |
| Textarea + Enter to submit | string |
| Two big buttons (Sim / Não) |
|
| Grid of buttons (requires | string (selected option) |
| Slider 1–5 | integer 1–5 |
| Single "OK, confirmado" button |
|
Default timeout: 5 minutes. Override per call with timeoutMs.
Endpoints
Path | Purpose |
| The PWA |
| Liveness probe |
| MCP Streamable HTTP |
| VAPID public key (for push subscribe) |
| Register a push subscription |
| Unregister |
| Send a test push |
Architecture
src/
├── server.js Entry point: Express + Socket.IO + MCP, all on 3010
├── questionManager.js In-memory store + EventEmitter; UUID-keyed Promises
├── mcp.js Streamable HTTP MCP, stateless (new McpServer per session)
├── socket.js Socket.IO ↔ QuestionManager glue
├── push.js Web-push init + VAPID key handling
└── pushRoutes.js REST endpoints for push subscription
public/
├── index.html PWA shell
├── app.js Vanilla JS frontend (Socket.IO client, push subscribe)
├── styles.css Dark-mode mobile-first styles
├── manifest.webmanifest PWA manifest (installable, maskable icons)
├── sw.js Service worker (push handler + asset cache)
└── icons/ 192/512/maskable SVG iconsKey design choices
Stateless MCP sessions: each agent that calls
/mcpgets its ownMcpServerinstance. TheMcpServerSDK enforces one transport per server — this is the cleanest workaround that still allows multiple concurrent agents.Shared state via QuestionManager singleton: questions and answers flow through a single in-memory Map. Restart loses pending questions (intentional — these are short-lived conversational exchanges).
Push is best-effort: if no one is subscribed, the question still arrives via Socket.IO. Push is only for when the PWA tab isn't active.
Running in production
This is a local-first tool by design. If you want 24/7 availability:
Run on a VPS with HTTPS (Cloudflare Tunnel, Caddy, or nginx + Let's Encrypt)
Set
VAPID_PUBLIC_KEY,VAPID_PRIVATE_KEY,VAPID_SUBJECTenv vars to persist VAPID across restartsPersist
subscriptionssomewhere (the current in-memory Map dies on restart) — easy swap to SQLite/RedisAdd auth to
/api/push/*and/mcpif exposed beyond localhost
License
MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/coder-mil/ask-agent'
If you have feedback or need assistance with the MCP directory API, please join our Discord server