Skip to main content
Glama
README.md
# AI Assistant — Merged Project (Chrono + AI-MCP-ASSISTANT)

## Merge notes (read this first)

This project is the result of merging two separate projects into one app:

1. **`fastmcp_ai_assistant_updated`** ("Chrono") — the base of this merge.
   Clock, stopwatch, alarms, reminders, sign-in/sign-up, email
   notifications, product-price comparison, and web search (via SerpAPI).
2. **`AI-MCP-ASSISTANT`** ("mcp-assistant") — contributed three tools that
   didn't exist in Chrono, now merged into this codebase:
   - **YouTube search** (`tools/youtube_tool.py`) — YouTube Data API v3.
   - **AI trip planner** (`tools/trip_planner_tool.py` + `tools/serp_service.py`)
     — real flights/hotels/places via SerpAPI, formatted into a day-wise
     itinerary by Groq.
   - **Notes** (`tools/notes_tool.py`) — add / delete / list / summarize
     (summarization via Groq), rewritten from SQLAlchemy to this project's
     existing `sqlite3` + `server/utils.connect_db` pattern so no new DB
     dependency was introduced.

**Search**: as requested, the merged app keeps *Chrono's* SerpAPI-based
`google_search` (`tools/search_tool.py`) as the one and only search tool.
AI-MCP-ASSISTANT's DuckDuckGo-based search (`ddgs` library) was **not**
carried over, to avoid having two different, inconsistent search
implementations side by side.

**What was intentionally left behind / not merged**, to keep a single,
consistent architecture instead of running two backends side by side:
- AI-MCP-ASSISTANT's separate Node/Express backend and Flask API
  (`backend/server.js`, `server/api.py`) — this project already has a
  single FastAPI backend (`server/api_server.py`) that both the React
  frontend and the FastMCP tool server call into; the new tools were
  added there instead of standing up a second backend stack.
- AI-MCP-ASSISTANT's Gemini-based MCP Host/Client CLI
  (`host/main.py`, `client/mcp_client.py`) — this project's own
  `server/server.py` (FastMCP) already serves the same purpose (exposing
  tools to any MCP-speaking LLM client), just with a different LLM/client
  pattern (Groq for trip-planner/notes formatting instead of Gemini for
  tool-selection). The new tools were added as `@mcp.tool()`s there.
- The "History" activity-feed page/table from AI-MCP-ASSISTANT was
  replaced by this project's existing per-feature history tables in
  `database/history.db` (`search_history`, plus new `youtube_history` and
  `trip_history` tables added during the merge).

New REST endpoints added to `server/api_server.py`:
| Method | Path | Purpose |
|---|---|---|
| GET | `/api/youtube?query=...&max_results=5` | YouTube search |
| POST | `/api/trip-planner` | `{origin, destination, days, departure_date?}` → itinerary |
| GET | `/api/notes` | List notes |
| POST | `/api/notes` | `{title?, content}` → add a note |
| DELETE | `/api/notes/{id}` | Delete a note |
| POST | `/api/notes/summary` | `{note_ids?}` → AI summary of notes |

New MCP tools added to `server/server.py`: `youtube_search`, `trip_planner`,
`notes_add`, `notes_delete`, `notes_list`, `notes_summarize`.

New frontend pages/tabs added: **YouTube**, **Trip planner**, **Notes**
(`frontend/src/components/YouTubePage.jsx`, `TripPlannerPage.jsx`,
`NotesPage.jsx`), wired into `Header.jsx` and `App.jsx`, styled to match
the existing dark "Studio Grayscale" theme.

New environment variables (see `.env.example`): `YOUTUBE_API_KEY` (YouTube
Data API v3, free tier) and `GROQ_API_KEY` (Groq, free tier — used for the
trip-planner itinerary and notes summarization).

---

## 1. Backend setup

```bash
# from the project root
python -m venv venv
venv\Scripts\activate        # Windows
# source venv/bin/activate   # macOS/Linux

pip install -r requirements.txt

# create/upgrade the sqlite databases (safe to re-run any time)
python server/init_db.py
```

No new pip packages were needed for sign-in or email — both use only
Python's standard library (`hashlib`, `secrets`, `smtplib`).

### `.env` file (project root)

A ready-to-copy template is included: **`.env.example`** — copy it to `.env`
and fill in your real values:

```bash
cp .env.example .env      # macOS/Linux
copy .env.example .env    # Windows
```

```
SERPAPI_KEY=your_serpapi_key

# Option A (recommended): Resend - HTTP email API, works over HTTPS (443)
RESEND_API_KEY=re_your_key_here

# Option B: SMTP - only used if RESEND_API_KEY above is blank
SMTP_HOST=smtp.gmail.com
SMTP_PORT=465
SMTP_USER=your_email@gmail.com
SMTP_PASSWORD=your_16_character_app_password
SMTP_FROM_NAME=Chrono Assistant
```

**Why Resend is recommended:** SMTP (ports 465/587) is frequently blocked
or intercepted by home/college/office networks and some antivirus "mail
scanning" features — this shows up as connection timeouts or
`WRONG_VERSION_NUMBER` SSL errors that have nothing to do with your
password being wrong. Resend sends over plain HTTPS (port 443), the exact
same protocol your browser already uses to load this app, so it works
even when SMTP doesn't.

**Setting up Resend (2 minutes, no credit card):**
1. Sign up free at https://resend.com
2. Dashboard → API Keys → create one → copy it
3. Paste it as `RESEND_API_KEY` in `.env`
4. On the free tier (no custom domain verified), Resend only delivers to
   the email address you signed up with — perfect for personal/testing use.

**If you'd rather use Gmail SMTP:** Gmail will reject your normal password
over SMTP — you need an **App Password**: Google Account → Security →
2-Step Verification (turn on) → App passwords → generate one → paste that
16-character value into `SMTP_PASSWORD`. If port 465 gives a connection
timeout, try `SMTP_PORT=587` instead (the app automatically switches to
STARTTLS for any non-465 port).

If neither option is filled in, the app still works exactly as before
(in-app alert + sound) — it just skips the email step and prints a warning
in the terminal instead of crashing.

### How to verify email is actually working (don't wait for a real alarm!)

1. Start the backend: `python -m server.api_server`. Watch the terminal —
   it now prints, right at startup:
   - `✅ Email is configured via Resend (HTTPS) - ...`, or
   - `✅ Email is configured via SMTP - ...`, or
   - `⚠️ Email is NOT configured - ...` (meaning `.env` is missing/blank).
2. In the frontend, sign in and open the **Settings** tab.
3. Click **"Send test email"**. This calls a dedicated endpoint
   (`POST /api/test-email`) that emails your signed-in address immediately
   and shows you the exact success or error message on screen — no need
   to wait for an alarm/reminder to fire.
4. Once the test email arrives, alarms and reminders will email you the
   same way automatically when they trigger.

**Windows Notepad users:** if you get "not configured" even after filling
in `.env` correctly, Notepad may have saved the file as UTF-16, which
python-dotenv can't read. Fix it in PowerShell:
```powershell
(Get-Content .env -Raw) | Out-File -FilePath .env -Encoding ascii -NoNewline
```

Run the REST API that the React app uses:

```bash
python -m server.api_server
```

This starts on **http://127.0.0.1:8000**. Leave this terminal running.

---

## 2. What changed in this update

### Sign up / Sign in (new: `server/auth.py`, `database/auth.db`)
- Passwords are hashed with PBKDF2-HMAC-SHA256 (never stored in plain text).
- `POST /api/auth/signup` `{name, email, password}` → creates the account
  and immediately signs you in (returns a token).
- `POST /api/auth/login` `{email, password}` → returns `{token, user}`.
- `POST /api/auth/logout` → invalidates the token.
- `GET /api/auth/me` → resolves the current token back to a user (used to
  keep you signed in across page reloads).
- The frontend stores the token in `localStorage` and sends it as
  `Authorization: Bearer <token>` on every alarm/reminder request.

### Alarms & reminders are now per-user
- `alarms` and `reminders` tables gained a `user_email` column.
- Creating an alarm/reminder now requires being signed in — it's stamped
  with your email automatically.
- `GET /api/alarms` / `GET /api/reminders` only return **your own** items.
- Deleting/stopping/snoozing someone else's alarm or reminder is blocked
  (403) — this is checked in `server/api_server.py`.
- **Note:** `/api/time`, `/api/stopwatch/*`, `/api/search`, and
  `/api/ecommerce*` were intentionally left open (no sign-in required) —
  the stopwatch is a single shared instance with no per-user data, and
  search/price-compare don't store anything user-specific. Only
  alarms/reminders needed a real owner, since that's who gets emailed.

### Email notifications (new: `server/email_service.py`)
- When an alarm rings (`check_alarms()` in `tools/clock_tool.py`) or a
  reminder becomes due (`check_reminders()` in `tools/reminder_tool.py`),
  it now also emails the alarm/reminder's owner via SMTP, in addition to
  the existing in-app full-screen alert + sound.
- Snoozed alarms and "Remind me later" reminders send a fresh email when
  they re-fire too.

### Compare two products (fixed the single-product limitation)
- `tools/ecommerce_tool.py` gained `compare_two_products(product1, product2)`
  alongside the original `compare_product(product)` (kept unchanged for
  backward compatibility with the FastMCP tool).
- New endpoint: `POST /api/ecommerce/compare {product1, product2}` →
  `{product1: {name, results}, product2: {name, results}}`.
- The "Compare" page now has two input boxes and shows both products'
  prices side by side.

### Visual redesign ("Studio Grayscale" template)
- `frontend/src/styles.css` and `index.html` were rebuilt around the
  template you sent (`sample3_dark_studio_grayscale.html`): Space Grotesk
  + Inter fonts, a near-black palette (`#0c0d0f` / `#17181b` cards), pill
  tab navigation, and the rotating conic-gradient ring on the clock card.
- Only presentation changed — every existing component still calls the
  same backend endpoints as before (as requested, the backend logic for
  clock/stopwatch/alarm/reminder/search was **not** touched for this part).

### MCP tools now call the REST API for search/ecommerce
- `server/server.py`'s `search`, `ecommerce`, and `ecommerce_compare` tools
  used to import and call `tools/search_tool.py` / `tools/ecommerce_tool.py`
  directly - duplicating the SerpAPI-calling logic in two places.
- They now make an HTTP call to `server/api_server.py`'s own REST endpoints
  instead (the same ones the React app and Postman already use), so
  there's a single source of truth for anything touching SerpAPI.
- Clock/Alarm/Reminder/Stopwatch tools were **not** changed - they don't
  use an external API key, so calling their Python functions directly is
  fine as-is.
- **Requires `python -m server.api_server` to already be running** for
  these 3 tools to work from an LLM/agent.

#### How to verify this actually works
**Method 1 (recommended) — FastMCP Inspector, a Postman-like UI for MCP:**
```bash
# Terminal 1
python -m server.api_server

# Terminal 2
fastmcp dev server/server.py
```
This opens a link like `http://127.0.0.1:6274` — open it in your browser,
pick a tool (e.g. `search`), type a test input, and click Run. Real
results back = the tool → HTTP → SerpAPI chain is working end to end.

**Method 2 (fallback) — a plain Python script:**
```bash
python tests/test_mcp_tools_manually.py
```
Calls the tool functions directly in Python (bypassing the MCP protocol
itself) so you can see the same HTTP-call code path run and print its
result or exact error, without needing `fastmcp dev`.

---

## 3. Frontend setup

```bash
cd frontend
npm install
npm run dev
```

Open **http://localhost:5173**.

### Frontend structure

```
frontend/src/
  api.js                     -> fetch() wrapper; auto-attaches the auth token
  context/AuthContext.jsx    -> signup/login/logout state, persisted in localStorage
  App.jsx                    -> shows Sign in/up when logged out, main app when logged in
  components/
    SignInPage.jsx            -> email + password -> redirects into the app
    SignUpPage.jsx             -> name + email + password -> auto signs in
    Header.jsx                  -> tabs + "Sign out" button
    ClockPage.jsx                -> rotating-ring clock card
    StopwatchPage.jsx             -> HH:MM:SS:MS input, live countdown
    AlarmPage.jsx                  -> HH:MM AM/PM, repeat, weekdays, sound, list
    ReminderPage.jsx                -> title/description/date/time, notify dropdown, list
    SearchPage.jsx                    -> query box -> tools/search_tool.py
    EcommercePage.jsx                  -> TWO product boxes -> side-by-side price compare
    YouTubePage.jsx                     -> query box -> tools/youtube_tool.py (merged in)
    TripPlannerPage.jsx                  -> origin/destination/days -> tools/trip_planner_tool.py (merged in)
    NotesPage.jsx                         -> add/list/delete/summarize -> tools/notes_tool.py (merged in)
    AlertOverlay.jsx                    -> full-screen alert (Stop/Delete, Snooze, Remind later)
```

---

## 4. Quick demo checklist

1. `python server/init_db.py` then `python -m server.api_server`
2. `cd frontend && npm run dev`
3. Open http://localhost:5173 → you land on **Sign up** → create an
   account → you're redirected straight into the app.
4. Click **Sign out** (top right) → you're taken back to **Sign in**.
5. Sign back in with the same email/password → back in the app.
6. Set an alarm 1–2 minutes in the future. If `.env` has valid SMTP
   settings, check that inbox when it rings — you should get an email
   alongside the in-app alert.
7. Go to **Compare**, type two product names, click *Compare prices* —
   both products' results appear side by side.

Maintenance

ActivitySlowing
ResponsivenessNo issues