Vaani-Pay MCP Server
Vaani Pay Assistant
安全でリアルタイムの、マルチユーザー対応、**バイリンガル(英語 + ヒンディー語)**の決済サポートチャットボットです。ユーザーは自分のアカウントで登録/ログインし、自分の支払い、注文、返金、取引、不正リスク、統計について質問できます。MCP ツール層でユーザーごとの厳格なデータ分離を適用し、実際の SQLite データベースを使用し、エージェントが何をしているかを示すライブ WebSocket ステータスストリームを備えています。
これは当初、静的デモのハッカソン向けビルド(ハードコードされたユーザー、固定トークン、英語のみ)でしたが、すでに機能していた部分を変更せずに、データベース駆動のマルチユーザー対応・安全・バイリンガルのプラットフォームにアップグレードされました。WebSocket プロトコル、MCP ツールアーキテクチャ、コアエージェントロジックは以前と同じ形を保っており、変更されたのはその下にあるデータソースと認証モデルだけです。
アーキテクチャ
Browser (chat UI + login/signup/profile)
│ REST (/auth, /users/me, /transactions) │ WebSocket (/ws)
▼ ▼
FastAPI — auth endpoints, profile endpoints FastAPI — WebSocket handler
│ │
▼ ▼
app/auth.py (register / login / sessions) AI Agent (app/agent.py)
│ NLU (Grok API) → intent + entities
│ Tool selection → MCP tool
▼ │
app/db.py — SQLite │ MCP (stdio transport)
users, sessions, chat_history, ▼
payments, orders, refunds, transactions MCP Server (mcp_server/server.py)
▲ get_payment_status │ get_order_details
│ get_refund_status │ get_customer_details
└───────────── same DB, same ownership ──── get_transaction_history │ check_fraud_risk
checks on every query get_payment_statistics
│
▼
mcp_server/data_layer.py
— ownership check on every lookup,
now backed by SQLite instead of JSONRelated MCP server: nexi-xpay-mcp-server
1. アカウントとデータプライバシー
実際のアカウント。
POST /auth/registerは、安全にハッシュ化されたパスワード(PBKDF2-HMAC-SHA256、パスワードごとのランダムソルト、260k 回の反復 —app/security.pyを参照)とともに SQLite にユーザー行を作成します。平文パスワードはどこにも保存もログ記録もされません。実際のログインセッション。
POST /auth/loginは認証情報を検証し、不透明で推測不可能なセッショントークン(app/security.pyのgenerate_token()、256 ビットのエントロピー)を発行します。これはsessionsテーブルに有効期限付き(.env内のSESSION_TTL_HOURS、デフォルト 24 時間)で保存されます。期限切れまたは不明なトークンは、チェックされるすべての場所で拒否されます。特定のリソースを参照するすべての MCP ツール(
get_payment_status、get_order_details、get_refund_status、check_fraud_risk)は、requesting_user_idパラメータを必須とし、mcp_server/data_layer.pyで、そのリソースが実際にそのユーザーに属していることを、パラメータ化された SQL のWHERE ... AND user_id = ?句を使用して確認してから、何かを返します。リソースが他のユーザーに属している場合、またはまったく存在しない場合、どちらの場合も同じ一般的な応答が返されます:
"Access denied. You are not authorized to access this information."「見つからない」場合と「他人のデータ」の場合で異なるメッセージを返すと、ユーザーが受け取るエラーの種類を観察することで有効な ID を列挙できてしまうため、これによってそのサイドチャネルを塞ぎます。requesting_user_idは常に呼び出し元の認証済み ID です(WebSocket 認証時 / REST リクエスト時に一度だけ解決されます —app/auth.pyを参照)。チャットメッセージ、URL パラメータ、リクエストボディから解析された値が使われることは決してありません。app/nlu.pyの抽出スキーマにはuser_idフィールドがまったくないため、メッセージ(敵対的なものであっても)が別の ID をツール呼び出しに紛れ込ませる方法はありません。get_customer_details、get_transaction_history、get_payment_statisticsはリソース ID を一切受け取りません。常に呼び出し元自身のデータを返すため、これら 3 つのツールには ID 操作の攻撃面がまったくありません。アカウント削除(
DELETE /users/me)では、確認として現在のパスワードを再入力する必要があります。その後、ユーザー行が削除されます —ON DELETE CASCADE外部キーにより、そのユーザーのセッション、チャット履歴、支払い、注文、返金、取引もすべて一緒に削除されます。
データ分離を直接検証:
python3 test_offline.pyこれは、実際の MCP サーバーに対して実際のツール呼び出しを実行し(実際の SQLite データベースから読み取り)、2 人の異なるデモユーザーとして、ユーザー間のアクセス試行が拒否されること、各ユーザーの取引履歴に自分のデータのみが含まれること、およびバイリンガルの応答が正しくレンダリングされることを検証します。
2. 登録、ログイン、アカウント管理
POST /auth/register— 名前、メール、パスワード、任意の電話番号、言語設定。パスワードは 8 文字以上で、英字と数字を混在させる必要があります(app/security.py)。POST /auth/login— セッショントークンとユーザープロフィールを返します。POST /auth/logout— 現在のセッショントークンをサーバー側で失効させます。GET /users/me/PUT /users/me— プロフィールの表示/更新(名前、電話番号)。POST /users/me/change-password— 現在のパスワードが必要です。変更すると既存のすべてのセッションが無効になり(すべての場所で再ログインが必要)、漏洩した古いトークンが機能しなくなります。GET /users/me/preferences/PUT /users/me/preferences— 言語設定(en/hi)の読み取り/更新。データベースに永続化されるため、ログアウト/ログイン後も保持されます。DELETE /users/me— アカウントの完全削除(パスワードと明示的なconfirm: trueが必要)。
これらはすべて、チャット UI 自体からも、ヘッダーの ⚙️ ボタンで利用できます(プロフィールの表示/編集、言語切り替え、パスワード変更、ログアウト、アカウント削除)。
3. チャット UI
static/index.html — シングルページアプリケーションです:
チャットが可能になる前に、ログインタブ / サインアップタブが表示されます。
プロフィールと設定パネル(名前/電話番号の編集、パスワード変更、言語切り替え、ログアウト、確認ステップ付きのアカウント削除)。
入力欄の上にある折りたたみ可能な候補メニュー。UI の他の部分と同じ翻訳文字列辞書からレンダリングされます。
チャットバブル、ライブステータス行、ヘッダーのステータスインジケーター — 元のデザインから変更なし。
4. リアルタイム通信
チャットは引き続き単一の WebSocket(/ws)を介して行われます。プロトコルの形式は変更されていません。認証トークンが静的値ではなく、実際に DB で管理されたセッショントークンになっただけです:
{"type": "auth", "token": "<session token from /auth/login>"}
↓
{"type": "auth_success", "user_id": "...", "name": "...", "language": "en"}すべてのチャットメッセージに対して、サーバーはステータスイベントをこの順序でストリーミングし、その後、最終的な(ローカライズされた)回答を送信します:
🔍 Understanding your request...
🔧 Checking payment information...
✓ Payment information retrieved
🤖 Generating response...
<final answer, in the user's selected language>すべてのチャットターン(ユーザーとアシスタントの両方のメッセージ)も、認証されたユーザーにスコープされて、chat_history テーブル(app/main.py の _persist_chat_turn)に永続化されます。
5. MCP ベースのアーキテクチャ
mcp_server/server.py は、mcp_server/tools/ 配下のドメインモジュールに分割された、ちょうど以下の 7 つのツールを公開しています:
ツール | ファイル |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
これらはすべて、静的 JSON の代わりに SQLite データベース(mcp_server/data_layer.py → app/db.py)によって支えられています。ツールのシグネチャ、エージェント、フロントエンドは元の設計から変更されていません — data_layer.py の下にあるデータソースだけが変更されており、これは元のアーキテクチャが許可するように設計されていたとおりです。
6. バイリンガル対応(英語 + ヒンディー語)
UI 文字列:
app/i18n.pyのUI_STRINGS辞書で、GET /i18n/{lang}を介して提供されます。フロントエンドは、ロード時と言語変更のたびにこれを取得し、data-i18n/data-i18n-placeholder属性を介して適用します — 翻訳文字列が HTML/JS にハードコードされることはありません。AI アシスタントの応答:
app/i18n.pyのAGENT_STRINGS(挨拶などの固定メッセージ)とREPLY_TEMPLATES(支払いステータスなどの補間メッセージ)。app/agent.pyはすべての応答をこれらを通じてレンダリングします — エージェント内で英語テキストが直接ハードコードされることはありません。NLU:
app/nlu.pyのプロンプトは、Grok モデルにヒンディー語/英語/混合入力の処理を明示的に求め、意図/エンティティ抽出のために内部では常に英語に翻訳するよう指示します。これにより、アシスタントはどちらの言語の質問でも理解し、ユーザーの希望言語で応答します。永続化: 言語設定はデータベースの
users.languageに保持されます(サインアップ時に設定され、PUT /users/me/preferencesでいつでも変更可能)。そのため、ログアウト/ログイン後も維持されます。動的切り替え: 設定で言語を変更すると、UI が即座に更新され、WebSocket が再接続されるため、次のチャット応答は新しい言語で返されます — ページの再読み込みは不要です。
7. セキュリティ要件
要件 | 実装箇所 |
認証 |
|
認可 |
|
ユーザー/セッションの分離 |
|
MCP レベルの権限チェック | アプリの境界だけでなく、MCP ツール自体( |
入力検証 |
|
SQL インジェクション対策 |
|
レート制限 |
|
安全な CORS |
|
安全なパスワードハッシュ化 |
|
トークンの有効期限 |
|
汎用的な認証エラーメッセージ |
|
安全なエラーハンドリング |
|
ID 改ざんへの対策 | ユーザーは任意の |
8. データベーススキーマ
users id, name, email, phone, password_hash, language, created_at, updated_at, last_login
sessions token, user_id, created_at, expires_at
chat_history id, user_id, conversation_id, role, message, timestamp
payments payment_id, user_id, status, amount, method, failure_reason, date
orders order_id, user_id, status, total, items (JSON), date
refunds refund_id, user_id, payment_id, amount, status, date
transactions txn_id, user_id, type, amount, status, date
-- Wallet: the real money-movement system (see section 9 below)
payment_accounts id, user_id, payment_id, account_number, ifsc, balance, currency, status, created_at
wallet_transactions id, transaction_id, sender_account_id, receiver_account_id, amount, transaction_type,
status, description, sender_name, receiver_name, recipient_account_number,
recipient_ifsc, failure_reason, created_at, updated_at
beneficiaries id, user_id, recipient_name, account_number, ifsc, created_at外部キーとインデックスを含む完全な DDL は、app/db.py の SCHEMA を参照してください。
9. ウォレット: 支払い口座、入金、送金
登録されたすべてのユーザーには、単なる支払い履歴ビューアーではなく、実際に使えるウォレットが与えられます。これはデータベース/認証のアップグレードに加えて最大の追加機能であり、REST API と AI/MCP ツールの両方が呼び出す独立したモジュール(app/wallet.py)として構築されています。そのため、資金移動ルールを強制する場所はちょうど1つだけです。
自動アカウント作成。 POST /auth/register は、同じデータベーストランザクション内でユーザー行と payment_accounts 行を作成します(app/auth.py の register() が app/wallet.py の insert_account_row() を呼び出します)。ユーザーがウォレットなしで存在することは決してなく、ウォレットが独立した失敗し得るステップとして作成されることもありません。各アカウントには次のものが付与されます:
一意の 支払い ID(
PAY...、内部識別子)、一意の12桁の 口座番号、
固定の IFSC(
VPAY0000001— Vaani Pay は単一支店の仮想ウォレットであるため、実際のネオバンクの仮想口座と同様に、すべてのアカウントが1つの IFSC を共有します)、初期残高 ₹0。
登録応答には、message: "Your payment account has been successfully created." という確認と新しいアカウントの詳細が含まれ、ユーザーに即座に表示されます(API 応答とサインアップ画面の確認メッセージの両方)。
入金。 POST /wallet/add-money(またはウォレット画面の「入金」ボタン、または AI アシスタントに「口座に ₹5,000 を追加して」と頼む方法)は、金額を検証し(> ₹0、1 トランザクションあたり ≤ ₹2,00,000 — app/wallet.py の MAX_ADD_MONEY)、その後、残高を原子的に更新して wallet_transactions に CREDIT 行を追加します。ハッカソンビルドには実際の決済ゲートウェイは組み込まれていません。これは明示的にシミュレートされたチャージであり、ブリーフの「安全なシミュレートされた資金フロー」要件に一致します。
送金 — 常に2段階の確認。 REST API も AI アシスタントも、1回の呼び出しで資金を移動することはありません:
POST /wallet/transfers(app/wallet.pyのinitiate_transfer)は受取人と送金元の残高を検証し、PENDINGのwallet_transactions行を作成します — まだ残高は変更されません。確認プレビュー(受取人、マスクされた口座番号、IFSC、金額、手数料、合計引き落とし額)を返します。これが「送金を確認」画面を描画するものです。POST /wallet/transfers/{id}/confirm(confirm_transfer)は、実際に資金を移動する唯一の呼び出しです。送金元の残高とアカウントステータスを確認時点で再検証し(開始時だけでなく、その間に何かが変わった場合に備えて — たとえば2つの送金が続けて開始された場合など)、その後、送金元から引き落とし、受取人が実際の Vaani Pay アカウントである場合はそのアカウントに入金します。これらはプロセス全体のロックで保護された1つの原子的な SQLite トランザクション内で行われます。途中で何かが失敗した場合は全体がロールバックされ、送金が「引き落とし済みだが入金されていない」状態になることは決してありません。POST /wallet/transfers/{id}/cancelは、まだPENDINGの送金を残高に一切触れずにキャンセルします。
当システムに存在しない口座番号への送金も成功します(シミュレートされた外部送金として — 送金元からは引き落とされますが、入金先の Vaani Pay アカウントがないだけです)。これはブリーフの「受取人がシミュレートされたシステム内に存在する場合は受取人の残高に入金する」という要件に一致します。
受取人検証。 POST /wallet/validate-recipient(validate_recipient)は以下をチェックします: 口座番号の形式(9〜18桁)、IFSC 形式(^[A-Z]{4}0[A-Z0-9]{6}$)、内部アカウントの場合は IFSC が口座番号と一致すること、そして — 重要なのは — 送金元が自分自身の口座番号に送金していないこと。受取人の名前だけが指定された場合(口座番号なし)、呼び出し元自身の保存済み受取人から名前を検索し、完全一致がちょうど1つある場合に自動的に解決します。
保存済み受取人。 送金が成功すると、UI は「この受取人を保存しますか?」と表示します — POST /beneficiaries は認証済みユーザーのみに対して受取人を保存します(グローバル/共有は一切ありません)。これにより、次回以降、ユーザーは(または AI アシスタントが「Rahul に ₹2,000 を送って」と頼まれたときは)名前だけで送金先を解決できます。
取引履歴とフィルター。 GET /wallet/transactions?filter=...(all / add_money / sent / received / failed / pending)— これらはすべて wallet_transactions からライブで計算され、ハードコードは一切ありません。ウォレット画面の履歴タブと AI の「自分のウォレット取引を表示して」/「今月いくら使った?」はどちらもまったく同じ関数(app/wallet.py の get_wallet_transactions / get_spending_summary)を参照します。
残高は常に導出され、直接設定されることはありません。 コードベースのどこにも set_balance() 関数は意図的に存在しません — 残高が変わる唯一の方法は、add_money() または confirm_transfer() の副作用としてです。どちらも同じ原子的なステップで不変の wallet_transactions 行を追加します。フロントエンドは GET /wallet/account が返すものを表示するだけで、それに影響を与えることはできません。
ウォレットのセキュリティ(具体的には)
ルール | 適用方法 |
ユーザーは自分の残高を直接変更することは決してできない | 公開関数が残高を設定するのは、Add Money / confirm_transfer の副作用としてのみであり、どちらも金額検証済みで監査行を生成する |
ユーザーは他のユーザーの残高を変更することは決してできない | すべてのウォレット関数は、呼び出し元の認証済み |
ユーザーは他人の送金を確認/キャンセルすることは決してできない |
|
自己送金はブロックされる |
|
金額は処理中に改ざんできない |
|
AI は明示的な確認なしにお金を動かすことはできない |
|
原子性 |
|
10. バイリンガル送金フロー
ウォレットは完全なバイリンガル対応で、アプリの他の部分と同じ app/i18n.py の仕組みを使用している — Add Money、Send Money(全 3 ステップ)、確認画面、トランザクションステータス、残高/送金に関するすべての AI 応答は、app/wallet.py、app/agent.py、static/index.html のウォレット UI のどこにもハードコードされた英語を使わず、すべて t()/tpl() を通じてレンダリングされる。たとえば、AI に 「Rahul ko ₹2,000 bhejo」(ヒンディー語/ヒングリッシュ)と尋ねると、英語版とまったく同じ resolve → confirm → execute のフローをたどり、確認画面を含むすべてのメッセージがヒンディー語でレンダリングされる。
セットアップ
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
# Add your Grok API key (get one at https://console.x.ai)データベースは初回実行時に自動的に作成される(空の場合にのみ、2 つのデモユーザーがシードされる — 下記参照)。ローカル開発では、別途マイグレーション手順は不要。事前に明示的に作成するには:
python3 -m app.dbブラウザを操作する前に検証:
python3 diagnose_setup.py実行
uvicorn app.main:app --reload --port 8000http://localhost:8000 を開きます。新しいアカウントにサインアップするか、シードされたデモアカウントのいずれかでログインします:
メール | パスワード |
|
|
|
|
次に、提案メニューを試すか、「check payment status pay_1001」 や 「मेरा भुगतान pay_1001 का स्टेटस क्या है?」 のような質問をしたり、Settings から言語を切り替えたり、あるいはあるユーザーとしてサインインして、他のユーザーの支払い/注文/返金 ID(pay_1003、ord_2002、rfnd_3002 は Priya のもの)について質問して、アクセス拒否の応答を確認してみてください。
ウォレットを試すには:ヘッダーにある 💰 Wallet ボタンを開きます。両方のデモアカウントは、残高(Ramesh は ₹8,500、Priya は ₹8,000)と、履歴にすでに 1 件のデモ送金がある状態で開始します。「Add Money」を試すか、もう一方のデモアカウントの口座番号(各ユーザーの Wallet 画面で確認できます)に「Send Money」を試すか、AI アシスタントに直接尋ねてみてください:「what's my balance?」、「add ₹5,000 to my account」、「send ₹2,000 to Priya Stores」(最初は彼女の口座番号 + IFSC を尋ねられ、送金が成功すると彼女を受取人として保存するよう提案されます — 以降は名前だけで十分です)、またはヒンディー語で 「Mera current balance kitna hai?」。
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
AlicenseNot gradedqualityAmaintenanceEnables AI agents to interact with Juspay's payment processing APIs and merchant dashboard for managing orders, transactions, refunds, customers, gateways, and reporting through natural language.21Apache 2.0- AlicenseAqualityDmaintenanceEnables AI assistants to query orders, transaction details, warnings/anomalies, and payment methods from your Nexi XPay merchant account.4MIT

AlipayPlus MCP Serverofficial
AlicenseAqualityDmaintenanceIntegrates Ant International's AlipayPlus payment APIs, enabling AI assistants to handle payment and refund operations seamlessly.68MIT- FlicenseNot gradedqualityCmaintenanceEnables AI to query a business database for customers, orders, and revenue using natural language through safe, well-defined tools.
Related MCP Connectors
Taiwan payments (ECPay 綠界 + NewebPay 藍新) & e-invoices for AI agents. Stateless, never holds funds.
Korea payments for AI agents — card, KakaoPay/NaverPay, 가상계좌 via Toss Payments. Never holds funds.
Let AI agents add Yolfi crypto checkout, paylinks, webhooks, and status checks.
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/divyaupadhyay56/Vaani-Pay'
If you have feedback or need assistance with the MCP directory API, please join our Discord server