ClientPulse
by ShArafat58
README.md
# ClientPulse
Juggling dozens of clients? ClientPulse gives you a morning briefing, preps every call, and warns you when a client's gone quiet, right through Alexa+.
## Status
🚧 In development — Amazon Developer Hackathon 2026 (Alexa+ Track + AWS Builder mini-challenge)
## Why ClientPulse
Freelancers rarely lose clients because they lack a CRM. They lose them because
important signals — CRM notes, invoices, meetings, commitments — are scattered
across tools and easy to miss. ClientPulse turns those scattered signals into
the one next action a freelancer needs to take, voice-first, through Alexa+.
## What It Does
- **Daily briefing** — what needs your attention today, in one glance
- **Call prep** — instant context before any client call, plus an AI-generated
priority explanation and recommended next action
- **Invoice tracking** — never miss an overdue payment
- **Stale client detection** — spot relationships going quiet before they go cold
- **Persistent memory** — remembers commitments and notes across sessions
## Architecture
BACKGROUND (precomputed, not on the voice request path)
GHL + Invoice data → Rules-based relationship scoring → Strands Agent
→ Amazon Bedrock (Nova Micro) → Client insight → Storage (cached)
RUNTIME (fast path, <500ms target for Alexa+)
Alexa+ → FastMCP (Streamable HTTP) → Storage read → Structured response
→ Alexa+ voice response + MCP App visual card
This separation is the core technical decision behind ClientPulse: Alexa+ MCP
requests read pre-scored, pre-cached data instead of calling an LLM live,
keeping latency low while still delivering AI-generated insight.
## Alexa+ MCP Implementation
- MCP spec: 2025-11-25+
- Transport: Streamable HTTP
- Server: Python + [FastMCP](https://gofastmcp.com)
- Verified end-to-end with the official MCP Inspector (5 tools, all
discoverable and callable)
```python
from fastmcp import FastMCP
mcp = FastMCP(name="ClientPulse", ...)
@mcp.tool()
def prep_call(client_id: str) -> dict:
...
```
## AWS Builder Integration
- **Amazon Bedrock** (Nova Micro) — client insight generation: prioritization,
plain-language explanation, and one recommended next action. The model
never computes the priority score itself — that's deterministic, rules-based
scoring (see `src/scoring/relationship.py`) — the model only explains and
prioritizes.
- **AWS Strands Agents SDK** — orchestrates the client-intelligence pipeline
(`src/agent/client_intelligence.py`)
- **Amazon DynamoDB** — persistent client memory backend for production
deployment (single-table design), swappable with local storage for
fully offline development and demo (see Storage Backend below)
- **AWS Lambda** — MCP server hosting, container-based deployment with
AWS Lambda Web Adapter for Streamable HTTP support
- **Amazon Cognito** — OAuth 2.1 (client_credentials grant) for MCP
service-level authentication, verified end-to-end
## Agentic Workflow
Rather than a single LLM call, ClientPulse separates deterministic logic from
AI reasoning:
- **Python (rules)**: days-silent calculation, invoice-overdue check,
meeting-proximity check, relationship score
- **Bedrock (via Strands)**: turns those signals into a human-readable
explanation and one concrete recommended action
This keeps cost and latency low, avoids hallucinated priority scores, and
keeps every recommendation explainable and auditable. A mock model
(`src/agent/mock_model.py`) mirrors this exact contract for offline
development — the real Bedrock call is a single environment variable away.
## MCP Tools
| Tool | Description |
|---|---|
| `get_daily_briefing()` | Today's overview: clients needing attention, overdue invoices, upcoming calls |
| `prep_call(client_id)` | Full call-prep context + AI-generated insight |
| `check_invoices()` | All overdue invoices with client names and amounts |
| `list_stale_clients()` | Clients with no meaningful contact in 7+ days |
| `record_client_note(client_id, note)` | Persist a note/commitment, remembered in future `prep_call` calls |
## Repo Structure
```
clientpulse-mcp/
├── LICENSE
├── README.md
├── requirements.txt
├── Dockerfile
├── .env.example
├── src/
│ ├── server.py # FastMCP entrypoint, registers all 5 tools
│ ├── tools/ # One file per MCP tool
│ ├── integrations/
│ │ ├── ghl.py # CRM provider interface + demo data
│ │ └── invoices/ # Invoice provider interface + demo data
│ ├── storage/
│ │ ├── store.py # Backend switcher (local/dynamodb)
│ │ ├── local_json.py # Local JSON storage (default)
│ │ └── dynamodb.py # AWS DynamoDB storage
│ ├── scoring/
│ │ └── relationship.py # Rules-based relationship scoring
│ ├── agent/
│ │ ├── client_intelligence.py # Strands + Bedrock orchestration
│ │ ├── mock_model.py # Offline-dev mock for the AI layer
│ │ └── prompts.py
│ └── models/
├── workers/
│ └── sync_and_analyze.py # EventBridge-ready background sync
├── apps/
│ └── briefing/
│ └── app.html # MCP App visual card
├── tests/ # pytest suite, 15 tests
└── docs/
├── architecture.md
├── demo-script.md
├── product-feedback.md
└── friction-log.md
```
## Data Sources — Hackathon Scope
This build uses seeded demo data behind clean provider interfaces:
- **CRM (GHL)**: `GHLProvider` interface with `DemoGHLProvider` implementation
(5 realistic seeded clients). A real adapter (`RealGHLProvider`) can be
added using the GHL REST API without changing any calling code.
- **Invoices**: `InvoiceProvider` interface with `DemoInvoiceProvider`.
Production adapters can connect to Stripe, QuickBooks, or GHL invoicing.
This keeps the demo self-contained and reproducible for judges while making
the production integration point explicit.
## Storage Backend
ClientPulse supports two interchangeable storage backends via the
`STORAGE_BACKEND` environment variable:
- **`local`** (default) — JSON file storage (`data/local_store.json`).
Zero external dependencies; the entire product runs and demos with no
AWS account required.
- **`dynamodb`** — Amazon DynamoDB, single-table design, for production
or AWS-hosted deployment.
Both backends implement identical function signatures
(`src/storage/store.py` is the switcher), so calling code — every MCP
tool and the background worker — never needs to know which is active.
## Setup (Local Development)
```bash
git clone https://github.com/ShArafat58/ClientPulse.git
cd ClientPulse
pip install -r requirements.txt
cp .env.example .env
```
By default (`STORAGE_BACKEND=local`), no further setup is needed — run the
server directly:
```bash
python -m src.server
```
**Optional — using DynamoDB instead of local storage:**
```bash
docker run -d -p 8001:8000 --name clientpulse-dynamodb amazon/dynamodb-local
python scripts/create_table.py
```
Then set `STORAGE_BACKEND=dynamodb` in `.env`.
Verify with [MCP Inspector](https://github.com/modelcontextprotocol/inspector):
```bash
npx @modelcontextprotocol/inspector
```
Connect to `http://localhost:8000/mcp` via Streamable HTTP.
## Deployment (AWS)
The MCP server is containerized for AWS Lambda using the
[AWS Lambda Web Adapter](https://github.com/awslabs/aws-lambda-web-adapter):
```bash
docker build -t clientpulse-mcp .
docker tag clientpulse-mcp:latest <ecr-repo-uri>:latest
docker push <ecr-repo-uri>:latest
aws lambda create-function --function-name clientpulse-mcp \
--package-type Image --code ImageUri=<ecr-repo-uri>:latest \
--role <lambda-execution-role-arn> --timeout 30 --memory-size 512 \
--environment "Variables={STORAGE_BACKEND=dynamodb,USE_MOCK_BEDROCK=false}"
```
## Testing
```bash
pytest tests/ -v
```
## Cost Design
Built to stay within AWS Free Tier / Free Plan credits when deployed on AWS:
- DynamoDB: pay-per-request, always-free tier covers demo-scale usage
- Lambda: well within the 1M free requests/month allowance
- Bedrock: capped at `MAX_BEDROCK_CALLS_PER_SYNC=20` per background sync
- No NAT Gateway, no provisioned concurrency, no always-on compute
- The local storage backend means the full product can also be built,
tested, and demoed with $0 cloud spend
## Privacy & Security
- OAuth 2.1 (client_credentials grant) via Amazon Cognito for service-level
authentication
- No real client data used — all CRM and invoice data is seeded/demo data
- AWS credentials are never committed; `.env` is gitignored
## Hackathon Scope
Built during the Amazon Developer Hackathon 2026 (Sept–Oct 2026) as a solo
entry. See `docs/friction-log.md` for a full log of issues encountered and
worked around during development, including new-AWS-account access
restrictions that motivated the swappable storage/model design.
## Product Feedback
See `docs/product-feedback.md`.
## Friction Log
See `docs/friction-log.md`.
## License
MIT — see `LICENSE`.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues