Udhaar
Integrates with Amazon Bedrock to parse mixed-language speech into credit/payment entries and to draft collection/reminder messages, with a regex/template fallback. Also designed as a self-hosted Alexa+ MCP server for voice-first credit ledger interactions.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@UdhaarRamu took 200 rupees of rice on credit, Kumar paid 500"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Udhaar
A voice-first credit ledger (udhaar/khata) for small shopkeepers, built as a self-hosted Alexa+ MCP server over Streamable HTTP, backed by Amazon Bedrock for understanding mixed-language speech and drafting collection messages.
Built for Amazon's Build, Ship, Shape hackathon — Alexa+ track, plus the AWS Builder and Open Source mini-challenges.
The problem
Millions of small Indian shops run on a paper notebook (khata) of who owes what. It's error-prone, hard to search, impossible to back up, and useless hands-free when a shopkeeper is mid-sale with both hands full of goods. A voice assistant that can record "Ramu took two hundred rupees of rice on credit" while the shopkeeper keeps working — and later tell them who to follow up with — replaces that notebook without asking anyone to learn an app.
Related MCP server: voiceledger-mcp
The demo in 30 seconds
Open the web simulator (GET /, see Setup) and speak or
type:
"Ramu took two hundred rupees of rice on credit and Kumar paid five hundred" → both entries recorded in one sentence, parsed by Bedrock (or a regex fallback if Bedrock isn't configured).
"How much does Ramu owe?" → spoken balance.
"Who should I follow up with today?" → ranked list with a drafted, polite reminder message per customer.
The ledger panel on the right updates live after every action.
Why this isn't a thin wrapper
Bedrock-backed understanding with a graceful fallback. Spoken, code-mixed sentences (English + transliterated Tamil/Hindi — udhaar, baaki, kadan) are parsed by a Bedrock
ConverseCommandcall (src/parser.ts). If Bedrock is unavailable, misconfigured, or disabled (UDHAAR_DISABLE_BEDROCK=1), a regex-based rules engine takes over automatically — the tool never crashes or goes silent, it just reports which engine it used (structuredContent.engine).Proactive collection planning, not just a balance lookup.
collection_planranks customers bybalance × recencyand drafts a warm, non-threatening reminder per customer — in the shopkeeper's requested language — via Bedrock, again falling back to a plain template if Bedrock is unavailable.Multilingual by design, not just English with a translation layer bolted on: the Bedrock prompts are written to understand code-mixed Tamil/Hindi/English input directly, and
collection_plancan draft output in a requested language.Voice-shaped responses. Every tool returns one or two short spoken sentences (plus
structuredContentfor UIs) — not JSON dumps, not markdown tables, because the Alexa+ assistant on the other end has to read it aloud.A real, spec-compliant MCP server, not a demo stub: stateless Streamable HTTP per MCP 2025-11-25, validated against the official
@modelcontextprotocol/inspectorCLI and the official SDK client end-to-end (src/smoke-test.ts), with bearer-token auth and a Docker/App Runner deployment path.
Architecture
flowchart LR
subgraph Client
Alexa["Alexa+ (voice)<br/>— unverified, see docs/ALEXA_SETUP.md"]
Sim["Web simulator<br/>(public/, this repo)"]
Inspector["MCP Inspector / SDK client"]
end
subgraph Server["Express server (src/server.ts)"]
MCP["POST /mcp — Streamable HTTP<br/>(stateless, MCP 2025-11-25)"]
Ask["POST /api/ask — intent router<br/>(src/intent.ts)"]
State["GET /api/state"]
Health["GET /health"]
end
subgraph Logic
Parser["src/parser.ts<br/>parseUtterance()"]
Planner["src/planner.ts<br/>collectionPlan()"]
Ledger["src/ledger.ts<br/>JSON-file store"]
end
Bedrock["Amazon Bedrock<br/>ConverseCommand"]
Alexa -->|Bearer auth| MCP
Inspector -->|Bearer auth| MCP
Sim --> Ask
Ask -->|self-call, same auth| MCP
MCP --> Parser
MCP --> Planner
MCP --> Ledger
Parser -.fallback to regex.-> Parser
Parser --> Bedrock
Planner --> Bedrock
Planner --> LedgerTools
Tool | Use when the shopkeeper says... | Notes |
| "Ramu took 200 rupees of rice on credit" | Direct, structured input |
| "Kumar paid 500" | Reports "fully settled" at balance ≤ 0 |
| Any free-form sentence, possibly multiple entries, possibly code-mixed | Bedrock or rules fallback |
| "How much does Ramu owe?" | Includes last 3 movements |
| "Who owes me money?" | Biggest balance first, optional overdue filter |
| "How was today?" | Credit, payments, entry count, total outstanding |
| "Remind Ramu to pay" | Optional UPI deep link ( |
| "Who should I follow up with today?" | Ranked by |
Setup and run
npm install
cp .env.example .env # fill in what you need; see below
npm run dev # tsx src/server.ts, serves on :3000Open http://localhost:3000/ for the web simulator, or point an MCP client
at http://localhost:3000/mcp.
Everything works with no AWS credentials at all if you set
UDHAAR_DISABLE_BEDROCK=1 — speech parsing and reminder drafting fall back
to deterministic regex/template logic, useful for offline development or a
no-AWS demo.
Bedrock setup
In the Bedrock console for your target region, go to Model access and request access to an Anthropic Claude model (usually instant approval).
Find a valid, invokable model ID for your region/credentials:
aws bedrock list-inference-profiles --region <your-region> \ --query "inferenceProfileSummaries[].inferenceProfileId"Many current Claude models require an inference profile ID (
us.anthropic.claude-...,eu.anthropic.claude-...,global.anthropic.claude-...), not the raw foundation-model ID.Set in
.env:AWS_REGION=<your-region> BEDROCK_MODEL_ID=<the inference profile ID from step 2>Standard AWS credential chain only (
aws configure,AWS_PROFILE, instance/task role) — no credentials are ever hardcoded.
Environment variables
See .env.example for the full, documented list (PORT, AWS_REGION,
BEDROCK_MODEL_ID, UDHAAR_API_KEY, UDHAAR_DISABLE_BEDROCK,
UDHAAR_DATA_FILE).
Tests
npx tsc --noEmit # type check
npm run test:unit # node:test unit tests — ledger, parser, planner, intent router
npm test # end-to-end: spins up a real server, drives it with the
# official MCP SDK client over Streamable HTTP, asserts
# on actual tool results (not just "it responded")Deploy
Docker + AWS App Runner, with an IAM instance role scoped to exactly
bedrock:InvokeModel, a health-check wired to /health, and a cost/shutdown
note: see deploy/README.md. The Docker image has been
built and smoke-tested locally (non-root user, /health and /mcp both
verified inside the container); the App Runner deployment steps themselves
require an AWS account and have not been executed by anyone but you.
Security notes
No hardcoded credentials anywhere; AWS access only via the standard SDK credential chain.
/mcpand/api/*requireAuthorization: Bearer <UDHAAR_API_KEY>when that variable is set (constant-time comparison); unset means auth is open — set it before exposing the server publicly./healthalways stays open for load balancer health checks.The bearer-token scheme here is not full OAuth 2.1 — Alexa+'s documented requirement for real device registration is OAuth 2.1 with PKCE, which this repo does not implement (see
docs/ALEXA_SETUP.mdfor the honest gap analysis).The JSON-file ledger store is demo-grade (not concurrent-write-safe, not durable across container restarts on App Runner) — see the DynamoDB note in
deploy/README.mdfor the production path.
What's verified vs simulated
Verified: Streamable HTTP MCP server behavior (Inspector CLI + the official SDK client, both over real HTTP), bearer auth (401/200 paths), Bedrock parsing/drafting with regex/template fallback, the Docker image running as non-root locally.
Simulated: the "Alexa+" experience is demonstrated via the included web simulator (
public/), which speaks to the same/mcptools over the same Streamable HTTP protocol an Alexa+ registration would use — browser speech recognition/synthesis stand in for the device. Real Alexa+ device registration has not been completed; seedocs/ALEXA_SETUP.mdfor exactly what that would take and why it's marked unverified.
Hackathon mapping
Alexa+ track (primary): self-hosted MCP server, Streamable HTTP, MCP spec 2025-11-25, voice-shaped tool responses.
AWS Builder mini-challenge: Amazon Bedrock (
ConverseCommand) for speech parsing and message drafting; AWS App Runner + ECR deployment path.Open Source mini-challenge: see the project's hackathon submission notes for the external contribution made during the hackathon window (tracked separately from this repo's own commits).
License
MIT — see LICENSE.
This server cannot be deployed
Maintenance
Related MCP Connectors
AI for Tally Prime and Tally ERP 9. Hosted MCP server to ask your accounts in any language.
Hosted MCP server for LLM cost estimation, model comparison, and budget-aware routing.
Invoicing you drive by talking to your AI: log time, raise invoices and track what's owed via MCP.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables users to track personal expenses through natural language interactions with comprehensive category support and financial summaries. Provides both local and remote MCP server options with SQLite storage for fast expense management operations.-
- AlicenseNot gradedqualityCmaintenanceEnables assistants to answer spoken questions about a cash trader's sales, expenses, stock levels, and outstanding debts from an append-only ledger, with deterministic figures for speech.MIT
- AlicenseAqualityCmaintenanceEnables MCP clients to let shop owners ask voice-first questions about KiotViet inventory, sales, and reordering, including drafting and confirming purchase orders.7MIT
- AlicenseNot gradedqualityBmaintenanceEnables small dairy and crop farmers in India to talk to a voice-friendly farm ledger, with every number verified rather than guessed. It is a self-hosted MCP server over Streamable HTTP, planned to run on AWS Lambda with DynamoDB and Amazon Bedrock.MIT