Demonstrates how Agentic AI combined with MongoDB Atlas enables conversational Open Finance consent management, loan portability analysis, and personalized financial advice — all through a multi-agent chatbot powered by LangGraph.
This is one of three interconnected repositories that make up the Leafy Bank Open Finance solution:
Repository Description Port open-finance-next-gen FastAPI backend — consents, accounts, transactions, Queryable Encryption 8003 leafy-bank-backend-openfinance-reactagent-chatbot (this repo) LangGraph multi-agent chatbot — consent flows, portability analysis, financial advice 8080 open-finance-next-gen-ui Next.js 15 frontend — dashboard, multi-bank views, AI assistant 3000
- Conversation Persistence: MongoDB's document model stores full LangGraph checkpoint state — messages, tool call history, interrupt payloads, and active consents — as a single document per conversation turn. Resume any conversation exactly where it left off, across sessions.
- Atlas Vector Search for Transaction Classification: The Portability Agent uses Atlas Vector Search to semantically classify spending transactions (e.g., "Uber ride" maps to
TRANSPORTATION), built into Atlas without a separate vector database. - MCP Server for Ad-Hoc Queries: The Internal Data Agent connects to MongoDB via the official MCP server, enabling natural language queries against Leafy Bank's internal data — accounts, transactions, products, credit scores — without custom tool code for each collection.
- Queryable Encryption for Consent Privacy: The Consent Agent creates and queries consents stored with Queryable Encryption in the Open Finance backend. Sensitive fields (consumer identity, permissions, source institution) are encrypted at rest — the Atlas server never sees plaintext, and equality queries on encrypted fields enable consent lookups without decryption server-side.
- Queryable Encryption for Agent Profiles: Agent system prompts and tool configurations are stored in MongoDB with Queryable Encryption — the
agent_namefield supports equality queries on ciphertext, whilesystem_promptandtool_configare encrypted at rest. Even with full database access, an attacker cannot read or tamper with the instructions governing agent behavior. - Flexible Document Model: Consent records, external bank data, and underwriting rules all have different shapes. MongoDB stores them naturally without schema conflicts, and the agent reads whatever structure each API returns.
User Request → Supervisor (Router)
│
┌─────────┼──────────────┐
▼ ▼ ▼
Consent Portability Internal Data
Agent Agent Agent
(9 tools) (7 tools) (MongoDB MCP)
│ │ │
▼ ▼ ▼
Open Finance Open Finance MongoDB Atlas
REST API REST API (Leafy Bank DB)
A Supervisor Agent reads the conversation and routes each request to the right specialist:
- Consent Agent — Guides users through secure data-sharing consent with external banks using a 4-pillar framework (Scope, Purpose, Source, Duration). Handles institution selection, consent creation, bank login, explicit user approval, and revocation.
- Portability Agent — Analyzes external bank data to produce spending scores, credit assessments, and deterministic loan portability offers. Compares current loan terms against Leafy Bank's rates to show potential savings.
- Internal Data Agent — Answers ad-hoc questions about the user's Leafy Bank accounts, transactions, and products by querying MongoDB directly through the MCP server.
The chatbot uses LangGraph's interrupt() to pause the workflow at two critical points:
- Bank Login — The user needs to authenticate with their external bank. The agent pauses, the frontend shows the bank login UI, and the workflow resumes once login succeeds.
- Consent Approval — Before any consent is finalized, the agent pauses and presents the full consent details (permissions, purpose, bank, duration). The user explicitly approves or declines before the workflow continues.
- MongoDB Atlas for conversation checkpointing and internal bank data
- MongoDB Atlas Vector Search for semantic transaction classification
- MongoDB MCP Server for natural language queries against internal collections
- LangGraph for multi-agent orchestration with supervisor pattern
- LangChain for agent tooling and abstractions
- MongoDB Queryable Encryption for encrypted agent profile storage
- AWS Bedrock — Claude Sonnet 4.6 for agents, Claude Haiku 4.5 for supervisor routing and suggestion generation
- Voyage AI for embedding generation used by Atlas Vector Search
- FastAPI (Python) for the REST API backend
- Poetry for Python dependency management
Before you begin, ensure you have met the following requirements:
- Python 3.11 or higher (but less than 3.14)
- Poetry 1.8.4 (install via Poetry's official docs or
pipx install poetry==1.8.4) - Node.js 20 or higher (required for MongoDB MCP server via
npx) - MongoDB Atlas cluster
- AWS credentials with Bedrock access (for Claude Sonnet)
- Voyage AI API key for embedding generation (get one at Voyage AI's dashboard)
- Open Finance Backend API running locally — this is the
open-finance-next-genrepo, must be running on port 8003 - Docker & Docker Compose (optional, for containerized deployment)
- Set up a MongoDB Atlas cluster if you don't have one already.
- Locate your cluster, click Connect, and select Connect your application.
- Copy the connection string.
You'll need this connection string for two environment variables:
MONGODB_URI(agent checkpointing) andLEAFY_BANK_MONGODB_URI(internal data MCP server).
- Log in to the AWS Management Console.
- Navigate to the Bedrock service.
- Request model access for Anthropic Claude Sonnet if you haven't already.
- Ensure your local AWS credentials (
~/.aws/credentialsor environment variables) have the appropriate Bedrock permissions.
Keep your AWS credentials secure and never commit them to version control.
-
Open your terminal and navigate to the directory where you want to store the project:
cd /path/to/your/desired/directory -
Clone the repository:
git clone <repository-url>
-
Navigate into the cloned project:
cd leafy-bank-backend-openfinance-react-agent-chatbot
The chatbot depends on the Open Finance backend API for consent management, institution lookups, and external bank data. Clone and start the open-finance-next-gen repo on port 8003 before running the chatbot.
Without this service running, consent and portability tools will fail with connection errors.
Agent profiles are stored with MongoDB Queryable Encryption. The setup requires a master key and an encrypted collection with Data Encryption Keys (DEKs).
-
Generate a 96-byte local master key:
python -c "import os; open('backend/master-key.bin', 'wb').write(os.urandom(96))" -
Run the encrypted agent profiles setup script:
cd backend && poetry run python ../scripts/setup_encrypted_profiles.py
This creates the
encrypted_agent_profilescollection, generates DEKs, and savesencryption_config.json(gitignored). -
Agent prompts are seeded from
.mdfiles on first startup. To force a re-sync from files:curl -X POST http://localhost:8080/admin/reload
For production, replace the local master key with AWS KMS by setting
KMS_PROVIDER=awsandAWS_KMS_KEY_ARNin your.env. Never commitmaster-key.binorencryption_config.jsonto version control.
The Leafy Bank internal data agent requires seed data in your Atlas cluster. Import the following collections into a database called leafy_bank_test:
| Collection | Purpose |
|---|---|
accounts |
User account balances and types |
transactions |
Transaction history (DEBIT/CREDIT) |
users |
User profiles |
products |
Leafy Bank product catalog (loans, credit cards) |
credit_bureau_scores |
User credit scores |
spending_best_practices |
MCC code ranges and category targets |
These collections are used by the Internal Data Agent (MongoDB MCP) and the Portability Agent's spending analysis tools.
-
(Optional) Set your project description and author information in
backend/pyproject.toml:description = "Your Description" authors = [{name = "Your Name", email = "you@example.com"}]
-
Ensure you are in the root project directory where the
makefileis located. -
Run the setup commands:
make setup
This configures Poetry for in-project virtual environments and installs all dependencies. Verify that the
.venvfolder has been generated within thebackend/directory. -
Create a
backend/.envfile with your configuration:# MongoDB (conversation checkpointing) MONGODB_URI= DATABASE_NAME=agentic_open_finance # AWS Bedrock AWS_REGION=us-east-1 CHAT_COMPLETIONS_MODEL_ID=us.anthropic.claude-sonnet-4-6 # Checkpointer Collections CHECKPOINTS_AIO_COLLECTION=checkpoints_aio CHECKPOINTS_WRITES_AIO_COLLECTION=checkpoint_writes_aio # Open Finance Backend API OPEN_FINANCE_API_URL=http://localhost:8003 # MongoDB MCP Server (Leafy Bank internal data) LEAFY_BANK_MONGODB_URI= # Vector Embeddings (transaction classification) VOYAGE_API_KEY= # Queryable Encryption (agent profiles) KMS_PROVIDER=local LOCAL_MASTER_KEY_PATH=backend/master-key.bin ENCRYPTION_CONFIG_PATH=backend/encryption_config.json
Start the development server with:
make dev- Chat API: http://localhost:8080
- Swagger Docs: http://localhost:8080/docs
- Embedded Chat UI: http://localhost:8080/chatbot
You can also run with different verbosity levels:
make run # Production mode (no reload)
make run-verbose # Debug logging
make logs # Trace logging (most verbose)Quick health check:
make check # Verify app imports correctlyCLI test harness (no server required):
cd backend && poetry run python3 console_chat.pyMake sure to run this from the root directory.
To run with Docker:
make buildThe chatbot will be available at http://localhost:8080.
To manage the container:
make start # Start existing container
make stop # Stop container
make clean # Remove container and images| Method | Path | Purpose |
|---|---|---|
GET |
/ |
Health check |
GET |
/chatbot |
Embedded React chat UI |
POST |
/chat |
Send message, get response + optional interrupt |
POST |
/chat/resume |
Resume after interrupt (bank login or consent approval) |
POST |
/chat/stream |
Send message, stream agent steps via SSE |
POST |
/chat/stream/resume |
Stream after resume |
POST |
/checkpointer/clear-all-memory |
Clear all conversation threads |
GET |
/api/v1/encryption-demo/compare/{agent_name} |
QE encrypted vs decrypted agent profile comparison |
{
"user_id": "fridaklo",
"message": "I want to share my data from Banco do Brasil",
"thread_id": "optional-thread-id",
"profile": "Balanced"
}{
"thread_id": "abc-123",
"response": "I can help you share your data...",
"interrupt": null
}When the agent pauses for human input, response is empty and interrupt contains the payload:
{
"thread_id": "abc-123",
"response": "",
"interrupt": {
"type": "BANK_LOGIN",
"consent_id": "consent-456",
"institution_name": "Banco do Brasil"
}
}The /chat/stream and /chat/stream/resume endpoints return Server-Sent Events with these event types:
| Event Type | Description |
|---|---|
thread_id |
Conversation thread identifier |
status |
Agent routing status (which agent is active) |
tool_call |
Tool invocation with name and arguments |
tool_result |
Tool execution result |
progress |
Sub-step progress updates |
agent_complete |
Agent finished its turn |
response |
Final agent response text |
suggestions |
Contextual reply suggestions (e.g., "Accept offer", bank names) |
interrupt |
Workflow paused for human input |
error |
Error details |
done |
Stream complete |
| Tool | Purpose |
|---|---|
list_institutions |
List available external banks |
get_default_permissions |
Show permissions for a consent purpose |
create_consent |
Create a new consent (returns ConsentId and status) |
get_consent |
Check consent status by ID |
list_user_consents |
List all of the user's consents |
request_bank_login |
Pause agent — user logs into external bank |
approve_consent |
Pause agent — user explicitly approves consent |
revoke_consent |
Revoke an active consent |
verify_consent_data |
Probe external data after consent approval |
Consent Purposes:
| Purpose | Description |
|---|---|
PERSONAL_LOAN_PORTABILITY |
Compare personal loan rates |
PAYROLL_LOAN_PORTABILITY |
Compare payroll-deductible loan rates |
VEHICLE_LOAN_PORTABILITY |
Compare vehicle loan rates |
FINANCIAL_ADVICE |
General financial insights |
| Tool | Purpose |
|---|---|
find_user |
Look up user by username, get MongoDB ObjectId |
analyze_spending |
Classify transactions via vector search, produce spending score (0–100) |
fetch_customer_identification |
Get identity verification from external bank |
fetch_credit_score |
Fetch credit bureau score |
evaluate_portability_offer |
Deterministic underwriting: score → tier → rate → payment → savings |
fetch_internal_accounts |
Get Leafy Bank accounts |
calculate_financial_position |
Concurrent fetch of total balance + total debt |
| Tool | Purpose |
|---|---|
get_current_user_id |
Get authenticated user identifier |
MongoDB MCP find |
Query any allowed collection |
MongoDB MCP aggregate |
Run aggregation pipelines |
MongoDB MCP count |
Count documents |
MongoDB MCP list-collections |
List available collections |
MongoDB MCP collection-schema |
Inspect collection schema |
Command not found: uvicorn— Runmake setupto install dependencies.get_config outside of a runnable context— Python < 3.11. Recreate the venv with Python 3.11+:rm -rf backend/.venv && cd backend && poetry env use python3.13 && poetry install --no-root.Address already in use— Kill the existing process:lsof -ti :8080 | xargs kill -9.- Open Finance API connection errors — Ensure the
open-finance-next-genbackend is running on port 8003. - AWS Bedrock errors — Verify your AWS credentials have Bedrock model access for Claude Sonnet.
- MongoDB connection failures — Check that your
MONGODB_URIandLEAFY_BANK_MONGODB_URIare correct and your Atlas cluster is accessible.
- Consent tools return auth errors — The Open Finance backend may need a running user session. Check that the
user_idin your request matches a registered user. - Spending analysis returns empty results — Ensure the
leafy_bank_testdatabase has seed data in thetransactionsandspending_best_practicescollections. - MongoDB MCP tools fail — Node.js 20+ must be installed for
npx mongodb-mcp-serverto work.
The Supervisor reads the conversation history and active_consents state to decide which agent should handle each turn. Key behaviors:
- Automatic consent detection — When a consent is newly approved, the Supervisor detects it from tool messages and tracks it in shared state, making it available for handoff to the Portability Agent.
- Deterministic guards — Critical transitions (like post-approval routing) use deterministic logic, not LLM decisions, ensuring they always happen correctly.
- Goal-oriented prompts — Each agent has a focused markdown prompt that defines its role, tools, and conversational guidelines.
Every consent is explained to the user via four pillars:
- Scope — What data categories are accessed (loans, accounts, balances, transactions, repayment history, customer ID)
- Purpose — Why the data is needed and what benefit the user gets
- Source — Which external bank the data comes from
- Duration — How long access lasts (one-time or up to 30 days)
The Portability Agent runs a deterministic underwriting pipeline:
- Spending Analysis — Fetches all transactions (internal + external), classifies them via Atlas Vector Search, and produces a spending score (0–100) with category breakdowns.
- Credit Assessment — Fetches the user's credit bureau score.
- Offer Evaluation — Deterministic computation: spending score → tier matching → base rate × tier multiplier → amortization → monthly payment → savings vs. current loan.
The result shows the user exactly how much they'd save by porting their loan to Leafy Bank.
The chatbot streams agent activity in real time via Server-Sent Events:
- Supervisor routing — Which agent is being invoked
- Tool calls — What tools are being used with what arguments
- Tool results — What the tools returned
- Sub-step progress — Custom progress events from within tools
- Final response or interrupt — The agent's reply or a pause for human input




