DAY 2

Unlocking AI Potential: Building a Notes Assistant

Learn to create a notes assistant using AI that can help organize and manage your daily tasks, inspired by virtual assistants used by Indian developers, and get ready to supercharge your productivity. By the end of Day 2, you will have a basic notes assistant up and running.

⏱ 15 mins
⚡ +100 XP

Day 2 — Build a Notes Assistant with SQLite

MCP & AI Agents — Agent Bootcamp Part 2 — RohithBuilds

Yesterday your server had one tool that lived only in memory. Today you'll add a real SQLite database and build three tools — add_note, list_notes, and delete_note — so your MCP server can remember things across sessions, just like Part 1's memory.json, but properly structured and queryable.

Step 1 — Recap & Today's Plan

In Part 1, Day 3, you saved conversation memory to a JSON file. That works for chat history, but for structured data — notes, tasks, records — a database is the right tool. Today's plan:

  • Add a SQLite database (notes.db) to your server
  • Build add_note — save a new note
  • Build list_notes — see all saved notes
  • Build delete_note — remove a note by ID
  • Test the full add → list → delete cycle in MCP Inspector

Step 2 — Add a Database to Your Server

Open server.py. At the top, add sqlite3 to your imports:

import sqlite3
from datetime import datetime
from mcp.server.fastmcp import FastMCP

Right after the line mcp = FastMCP("RohiMCP"), add this database setup code:

DB_FILE = "notes.db"

def init_db():
    conn = sqlite3.connect(DB_FILE)
    conn.execute("""
        CREATE TABLE IF NOT EXISTS notes (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            text TEXT NOT NULL,
            created_at TEXT NOT NULL
        )
    """)
    conn.commit()
    conn.close()

init_db()
print("Database ready: notes.db")

This code runs automatically whenever server.py is loaded — by Inspector, by a test script, or by your future Flask app — so the table always exists before any tool tries to use it.

⚠️ Update Your .gitignore

Add notes.db to your .gitignore so your personal notes never get pushed to GitHub:

notes.db

Step 3 — Build the add_note Tool

Add this above if __name__ == "__main__": — following yesterday's pattern of a logic function plus a thin @mcp.tool() wrapper:

def add_note_logic(text: str) -> str:
    conn = sqlite3.connect(DB_FILE)
    cursor = conn.execute(
        "INSERT INTO notes (text, created_at) VALUES (?, ?)",
        (text, datetime.now().strftime("%Y-%m-%d %H:%M"))
    )
    conn.commit()
    note_id = cursor.lastrowid
    conn.close()
    return f'Note #{note_id} saved: "{text}"'


@mcp.tool()
def add_note(text: str) -> str:
    """Save a new note for the student. Returns the note's ID number."""
    return add_note_logic(text)

Step 4 — Build the list_notes Tool

Add this next:

def list_notes_logic() -> str:
    conn = sqlite3.connect(DB_FILE)
    rows = conn.execute(
        "SELECT id, text, created_at FROM notes ORDER BY id"
    ).fetchall()
    conn.close()

    if not rows:
        return "No notes saved yet."

    output = ""
    for row in rows:
        output += f"#{row[0]} [{row[2]}]: {row[1]}\n"
    return output


@mcp.tool()
def list_notes() -> str:
    """List all saved notes with their ID numbers and timestamps."""
    return list_notes_logic()

Notice this tool takes no arguments at all. MCP handles that automatically too — the Inspector will simply show a "Run Tool" button with no input fields.

Step 5 — Build the delete_note Tool

Finally, add the delete tool:

def delete_note_logic(note_id: int) -> str:
    conn = sqlite3.connect(DB_FILE)
    cursor = conn.execute("DELETE FROM notes WHERE id = ?", (note_id,))
    conn.commit()
    deleted = cursor.rowcount
    conn.close()

    if deleted:
        return f"Note #{note_id} deleted."
    return f"No note found with ID #{note_id}."


@mcp.tool()
def delete_note(note_id: int) -> str:
    """Delete a saved note using its ID number."""
    return delete_note_logic(note_id)

Your server now has 4 tools total: exam_countdown from Day 1, plus add_note, list_notes, and delete_note.

Step 6 — Restart Inspector

Stop the Inspector if it's still running (Ctrl+C in that terminal), then start it again so it picks up your changes:

mcp dev server.py

Expected Output

Terminal showing Database ready: notes.db printed, then MCP Inspector starting again

Open the Inspector link in your browser and go to the Tools tab. You should now see all 4 tools listed.

MCP Inspector Tools tab listing exam_countdown, add_note, list_notes, and delete_note

Step 7 — Add Some Notes

Click add_note, enter some text, and run it twice with different notes — for example:

  • "Finish Day 2 of MCP course"
  • "Revise SQL joins before placement test"

Expected Output

MCP Inspector showing add_note tool returning a saved note with its ID number

Now click list_notes and run it (no input needed). You should see both notes, each with its own ID and timestamp.

Expected Output

MCP Inspector showing list_notes returning both saved notes with IDs and timestamps

Step 8 — Delete a Note

Click delete_note, enter the ID of your first note (probably 1), and run it.

Expected Output

MCP Inspector showing delete_note confirming note 1 was deleted

Run list_notes again to confirm only your second note remains.

Expected Output

MCP Inspector showing list_notes now returning only one remaining note

You've just used your MCP server like a real client would: discover tools, call them with the right arguments, and get structured results back — all without writing a single line of routing code.

Step 9 — Fallback Test Without Inspector

As always, the logic underneath is plain Python — you can test the same flow with a script. Create test_local.py:

from server import add_note_logic, list_notes_logic, delete_note_logic

print(add_note_logic("Finish Day 2 of MCP course"))
print(add_note_logic("Revise SQL joins before placement test"))
print()
print("All notes:")
print(list_notes_logic())

print(delete_note_logic(1))
print()
print("After deleting note #1:")
print(list_notes_logic())

Run it:

python test_local.py

Expected Output

Terminal showing add, list, delete, and list-again output for the notes database

💡 Note

Running test_local.py adds more rows to notes.db — including a fresh note with ID 1 again, since the old ID 1 was deleted but IDs keep incrementing. That's expected and fine; it's the same database you were just using in Inspector.

✅ Day 2 Complete

Here is what you accomplished today:

Key Takeaways

  • SQLite database added to your MCP server ✅
  • Built add_note, list_notes, and delete_note tools ✅
  • Server now exposes 4 tools total ✅
  • Tested the full CRUD cycle live in MCP Inspector ✅
  • Verified everything also works as plain Python functions ✅

What Is Coming Tomorrow

On Day 3 you will:

  • Learn the difference between tools, resources, and prompts in MCP
  • Expose your notes as a readable MCP resource
  • Build a reusable MCP prompt template for summarizing notes
  • Test both in the Inspector's Resources and Prompts tabs

See you there! 🚀

← Previous Lesson