Inspiration
Big brands reach Alexa+ with a team of engineers. A corner bakery has a website and no time. Several projects already turn a website into "an MCP server for a small business". We think generating the integration is the easy part. The hard part is whether a customer can trust what an assistant says about a business it has never met: a made-up price, a guessed allergen or a stale closing time. To check whether real websites are good enough to go live unaided, we onboarded 23 real small-business sites, read-only. None of them was: every site that could be onboarded needed the owner to settle something first. So the product became a rule: the assistant never guesses. It asks the owner, once, and the answer is reused for every later customer.
What it does
AskOnce is one multi-tenant MCP server that makes small businesses usable from Alexa+ and any other MCP host, plus an onboarding pipeline and a deterministic certifier that decide which businesses may go live.
- Onboard. Give it a website URL. It crawls the site, snapshots every page by SHA-256, and quarantines any text that addresses AI agents ("ignore previous instructions..."). One Amazon Bedrock call per page extracts quoted facts. Price tables, option lists, allergen lines, forms and FAQs are read from the page structure in code. Every quote must be re-located on its page snapshot, or the fact is dropped.
- Ask. Contradictions ("closes at 4" on one page, "6" on another), missing facts and safety confirmations become owner questions, each saying why it is asked. Until the owner answers, the business is CONDITIONAL and disputed facts are withheld, not guessed.
- Certify. The certifier runs the profile through the real MCP server and checks the tool-call trace in code, with no LLM judge: schema conformance (every evidence quote is on its page snapshot), grounded facts, disputed facts withheld, unknowns handed off, confirmation before every commitment, idempotent retries, the Task lifecycle, the injection canary and p95 latency. The verdict is CERTIFIED, CONDITIONAL or NOT_CERTIFIED, and only CERTIFIED businesses are visible to customers.
- Serve. Customers find a business with
find_businessand then use its tools: catalog, items, policies, availability, booking, custom orders and quote requests. Every spoken fact carries its source. Nothing is booked or ordered without an accepted confirmation, and a retry never books twice. - Ask once. When a customer asks something the business never stated, the assistant says "I don't know. Want me to ask Rosa?". That becomes an owner request on the owner's phone page. Rosa answers once. Her answer is injection-checked, re-certified and stored as a cited fact, and every later customer gets it instantly. Custom work ("a cake for 30 on Saturday?") becomes a background MCP Task that the owner approves, declines or quotes, and the customer's device announces the result.
A new vertical is a profile template plus certification cases, not code. The demo runs a bakery, a salon and a home-repair business on the same endpoint.
How we built it
- MCP server: Python 3.12, FastAPI and the MCP Python SDK 2.2.0, with protocol 2026-07-28 over Streamable HTTP and a 2025-11-25 fallback on the same
/mcpendpoint. 16 tools. Confirmations use the stateless multi-round-trip pattern, long waits are SEP-2663 Tasks, and results carry short spoken text, cited facts and an optional MCP Appsui://card. - Tasks extension: the SDK ships Task types but never dispatches
tasks/*, so we wrote theio.modelcontextprotocol/tasksextension (server and client, in-memory and DynamoDB stores) as a standalone open-source package,packages/mcp-tasks, verified against an independent SEP-2663 client. - Plain-tool fallback:
check_request_statusandcancel_requestgive hosts without the Tasks extension the same owner round trip. - Onboarding: a pipeline over a Bedrock model router. The model reads flat facts, reviews contradictions and writes customer phrasings; structure is handled in code.
- Model router (
packages/askonce-bedrock): a new account is capped at about 10 requests per minute per model, so calls are spread over Amazon Nova and other Bedrock inference profiles with token buckets, failover and a hard $5 spend ledger. All model work in the project cost $3.23 in total. - Certifier: pass/fail decided in code on the MCP trace, written to
certification-verdict.json. - Reference voice host: a smart-display web page standing in for Alexa+ (browser speech in and out, cards with citations) that announces the owner's reply the moment it lands.
- Owner phone page: signed, expiring links with one-tap decisions and an Answer box.
- AWS: one CDK stack in ap-southeast-2: ECS Express Mode on arm64 Fargate, DynamoDB, Secrets Manager, ECR, CloudWatch Logs, Amazon Bedrock.
- Agent Skill (
skills/askonce-onboard-business): lets any agent run the owner flow and publish only a CERTIFIED profile.
Challenges we ran into
- Tasks didn't exist in the SDK, so we wrote both halves and proved interoperability with an independent client.
ctx.elicit()stops working on 2026-07-28 (no back-channel), so every confirmation was rewritten as a stateless multi-round-trip request.- A brand-new Free plan account: account verification waits, a 10 RPM cap that self-service quota requests can't raise, and model access changes mid-project. The router fails over automatically, which is why every recorded run went to Amazon Nova.
- Models can't be trusted with structure: they split variants, invented allergens and misread surcharges, so all structure moved into deterministic HTML reading.
- ECS Express Mode on a new account: the service-linked role race, IAM propagation for the infrastructure role, and a draining service name. All fixed in the stack and logged in our friction log.
Accomplishments that we're proud of
- 2,183 automated tests pass, with no AWS call and no network beyond localhost.
- 202 certification cases across the three demo businesses, all passing, decided in code. A planted contradiction and a planted prompt injection on every demo site are caught.
- Real-site census: 23 real small-business websites onboarded read-only (robots.txt respected, aggregates only). 19 onboarded, 617 priced items, 100% of prices cited, 278 unquotable facts dropped, and all 19 came out CONDITIONAL (median 3 owner questions). No real website was complete enough to go live without asking the owner.
- A reusable Tasks extension for the MCP Python SDK.
- The whole project's model spend was $3.23.
What we learned
- Trust comes from refusing to say things: "no source, no statement" and "disputed means withheld".
- An LLM grading an LLM isn't certification. Checking a trace in code is deterministic, repeatable and cheap.
- Let the model write language, and let code read structure.
- A stateless protocol makes horizontal scaling easy, as long as every wait becomes a Task.
What's next
- Run the real Alexa+ client through the same certifier as soon as add-ons open for self-serve testing.
- Demand-led onboarding: a customer's question about a business that isn't on AskOnce becomes that owner's invitation to join.
- Drift re-certification: re-read a site on a schedule and drop any changed fact to "let me check" until the owner confirms it.
- Real owner notifications (SMS or email), and authenticated principals for Tasks.
- Publish
mcp-tasksto PyPI.
Built With
- amazon-bedrock
- amazon-cloudwatch
- amazon-dynamodb
- amazon-ecr
- amazon-ecs
- amazon-nova
- aws-cdk
- aws-fargate
- aws-secrets-manager
- fastapi
- javascript
- mcp
- python
Log in or sign up for Devpost to join the conversation.