Tuesday, 25 November 2025

#MCP Index

MCP Tutorial – Module Index

MCP Tutorial – 12 Modules

Latest Edition for AU-CSE Final year Students

Module 1

Introduction to Model Context Protocol

Open

Module 2

Department & Course Setup

Open

Module 3

Semester Automation Engine

Open

Module 4

Subject Allocation & Management

Open

Module 5

Staff Assignment Automation

Open

Module 6

Timetable Generation (40 hrs/week)

Open

Module 7

Attendance APIs

Open

Module 8

Daily/Weekly/Monthly Reports

Open

Module 9

Attendance Logs & Filters

Open

Module 10

Alert & Notification System

Open

Module 11

Analytics & Dashboards

Open

Module 12

Integrated MCP Automation Platform

Open

#Module 12 – Combining All MCP Tools Into A Complete University Attendance Automation System

Module 12 – MCP Tutorial

Module 12 – Combining All MCP Tools Into A Complete University Attendance Automation System

In this final module, we will bring together all the components created in earlier modules—department setup, course management, semester generation, subject allocation, staff management, timetable creation, attendance API, logs, dashboards, and analytics—into a unified Attendance Automation Platform powered by the Model Context Protocol.

✔ Step 1 – Create the MCP Master Server

This server loads every tool module and exposes them under a unified namespace.


from mcp import MCPServer

# Import All Tool Modules
import department
import courses
import semesters
import subjects
import staff
import timetable
import attendance
import analytics

server = MCPServer(title="University Attendance Automation")

# Register Tools From All Modules
server.load_tools_from(department)
server.load_tools_from(courses)
server.load_tools_from(semesters)
server.load_tools_from(subjects)
server.load_tools_from(staff)
server.load_tools_from(timetable)
server.load_tools_from(attendance)
server.load_tools_from(analytics)

if __name__ == "__main__":
    server.start()

✔ Step 2 – Build Unified Frontend UI

Below is the main dashboard HTML that links all 12 modules.


University Attendance Portal

✔ Step 3 – Connecting MCP Server to Client UI

The following JavaScript connects all UI buttons to respective MCP tools.


async function callTool(name, params = {}) {
  return await mcp.call(name, params);
}

async function loadDept() {
  const data = await callTool("list_departments");
  console.log(data);
}
async function loadCourse() {
  const data = await callTool("list_courses");
  console.log(data);
}
async function loadSemester() {
  const data = await callTool("generate_semesters", { course_id: 1 });
  console.log(data);
}

✔ Step 4 – Real-Life Example (Fully Integrated)

Using MCP automation:

  • 2 Courses: B.Tech (8 sem), M.Sc (4 sem)
  • 14 Staff members auto assigned to subjects
  • 6 subjects per semester × 12 semesters = 72 subjects
  • 60 students/semester × 12 = 720 students
  • Each semester auto-creates timetable for 40 hours/week
  • Attendance logged per hour → converted to daily, weekly, monthly reports
  • Analytics module generates staff load, shortage list, student trends

✔ Step 5 – Add Deployment Script

Deploy the complete MCP system using the script below.


#!/bin/bash

echo "Starting MCP University Attendance Server"
python3 mcp_master_server.py

#Module 11 – MCP Tutorial

Module 11 – MCP Tutorial

Module 11 – Integrating Analytics & Department-Wide Dashboards Using MCP

This module focuses on adding analytics and dashboards inside the Attendance Tracking System using Model Context Protocol (MCP). We will add department-level statistics, staff performance summaries, student attendance insights, and semester‑wise overview screens.

✔ Step 1 – Define Analytics Endpoints

Create a new MCP tool file analytics.py:


from mcp import register_tool
from database import db

@register_tool
async def department_attendance_summary(dept_id: int):
    result = db.fetch("""
        SELECT semester, AVG(attendance) AS avg_attendance
        FROM attendance_summary
        WHERE dept_id = ?
        GROUP BY semester;
    """, (dept_id,))
    return result

@register_tool
async def staff_teaching_load(staff_id: int):
    result = db.fetch("""
        SELECT subject_name, total_hours
        FROM staff_load
        WHERE staff_id = ?;
    """, (staff_id,))
    return result

✔ Step 2 – Add Dashboard UI Template


Department Dashboard

✔ Step 3 – Connect MCP Tools to the UI


async function loadDashboard() {
  const semSummary = await mcp.call("department_attendance_summary", { dept_id: 3 });
  const staff = await mcp.call("staff_teaching_load", { staff_id: 12 });

  document.getElementById("sem-summary").innerHTML = JSON.stringify(semSummary, null, 2);
  document.getElementById("staff-load").innerHTML = JSON.stringify(staff, null, 2);
}

loadDashboard();

✔ Step 4 – Add Charts for Visualization


const ctx = document.getElementById('attendanceChart').getContext('2d');
new Chart(ctx, {
  type: 'bar',
  data: {
    labels: semesters,
    datasets: [{ label: 'Attendance %', data: values }]
  }
});

✔ Step 5 – Real-Life Example

Assume:

  • 2 Courses
  • 12 Semesters total
  • 14 Staff
  • 6 Subjects/Semester
  • 60 Students/Semester

MCP analytics allow department head to check:

  • Semester‑wise attendance of each course
  • Staff workload distribution
  • Students with attendance shortage
  • Weekly subject hour utilization (40 hours/week)

#Module 10 – Export, Backup & Data Portability

Module 10 – Export, Backup & Data Portability

Module 10 – Export, Backup & Data Portability

This module covers safe export formats, scheduled backups (pg_dump), uploads to object storage, and restore procedures for the MCP Attendance System.

1. CSV/Excel Export Endpoint (FastAPI)

Return CSV for month/semester reports. Streaming response avoids memory spikes.

# app/export.py
from fastapi import APIRouter, Depends
from fastapi.responses import StreamingResponse
import csv, io

router = APIRouter()

@router.get('/reports/monthly/csv')
async def export_monthly_csv(year: int, month: int, semester: int, db=Depends(get_db)):
    start = f"{year}-{month:02d}-01"
    end = f"{year}-{month:02d}-31"
    query = """
    SELECT st.student_code, st.name,
      (COUNT(*) FILTER (WHERE a.status='present')::float / NULLIF(COUNT(*),0) * 100) AS attendance_pct
    FROM attendance a
    JOIN students st ON st.id = a.student_id
    WHERE a.date BETWEEN :start AND :end AND st.semester = :semester
    GROUP BY st.id, st.student_code, st.name
    ORDER BY attendance_pct DESC;
    """
    rows = await db.fetch_all(query, values={'start':start,'end':end,'semester':semester})

    buf = io.StringIO()
    writer = csv.writer(buf)
    writer.writerow(['student_code','name','attendance_pct'])
    for r in rows:
        writer.writerow([r['student_code'], r['name'], r['attendance_pct']])
    buf.seek(0)
    return StreamingResponse(iter([buf.read()]), media_type='text/csv')

2. Scheduled Backup with pg_dump (Linux cron)

Simple daily backup with retention rotation.

#!/bin/bash
# /usr/local/bin/backup_mcp.sh
BACKUP_DIR=/backups/mcp
mkdir -p "$BACKUP_DIR"
FNAME="$BACKUP_DIR/mcp_db_$(date +%F).sql.gz"
pg_dump -U postgres mcp_db | gzip > "$FNAME"
# keep 14 days
find "$BACKUP_DIR" -type f -mtime +14 -name 'mcp_db_*.sql.gz' -delete
# optional: upload to S3
/usr/local/bin/aws s3 cp "$FNAME" s3://my-mcp-backups/ --storage-class STANDARD_IA

Cron entry (run daily at 02:00): 0 2 * * * /usr/local/bin/backup_mcp.sh

3. Backup to S3 using boto3 (Python)

This script uploads the latest backup to S3 and tags it with the date & env.

# upload_backup.py
import boto3
from pathlib import Path

s3 = boto3.client('s3')
BUCKET = 'my-mcp-backups'

def upload(path: str):
    p = Path(path)
    key = f"backups/{p.name}"
    s3.upload_file(str(p), BUCKET, key, ExtraArgs={'StorageClass':'STANDARD_IA'})
    print('Uploaded', key)

if __name__ == '__main__':
    import sys
    upload(sys.argv[1])

4. Restore Procedure (pg_restore / psql)

Restore full DB from a gzipped dump.

# restore_mcp.sh
set -e
FILE=$1
if [ -z "$FILE" ]; then
  echo "Usage: $0 backupfile.sql.gz"
  exit 1
fi
gunzip -c "$FILE" | psql -U postgres -d mcp_db

5. Point-in-Time Recovery & WAL Archiving (Optional)

Enable WAL archiving and continuous backup for critical systems. Configure postgresql.conf:

# postgresql.conf
archive_mode = on
archive_command = 'test ! -f /var/lib/postgresql/wal_archive/%f && cp %p /var/lib/postgresql/wal_archive/%f'
wal_level = replica

6. Database Migrations (Alembic)

Use Alembic for schema migrations to keep environments in sync.

# Install
pip install alembic

alembic init alembic
# then configure alembic.ini to point to DATABASE_URL
# create migration after model changes
alembic revision --autogenerate -m "add attendance_audit"
alembic upgrade head

7. Docker-compose Backup Strategy

You can run pg_dump from a temporary container targeting the DB service.

# run from host to dump the running postgres container
docker run --rm --network $(docker-compose -f docker-compose.yml ps -q db | xargs docker inspect --format '{{range .NetworkSettings.Networks}}{{.NetworkID}}{{end}}') \
  -v $(pwd)/backups:/backups postgres:15 bash -c "pg_dump -h db -U postgres mcp_db | gzip > /backups/mcp_db_$(date +%F).sql.gz"

8. Data Portability & GDPR-like Considerations

  • Provide per-student export (CSV) on request.
  • Support data deletion/obfuscation requests — use soft-delete or anonymization.
  • Limit backups retention based on policy (e.g., 7 years for academic records).

9. Quick Disaster Recovery Checklist

  1. Identify last good backup file and WAL archives.
  2. Restore DB to a staging environment.
  3. Run integrity checks and sanity queries.
  4. Switch application to restored database after smoke tests.

#Module 9 – Validation Rules & Business Logic (MCP)

Module 9 – Validation Rules & Business Logic (MCP)

Module 9 – Validation Rules & Business Logic (MCP)

This module implements validation and business rules to ensure data integrity and correct workflow behavior in the Attendance System.

Why Validation Matters

  • Prevent invalid attendance entries (wrong date/hour/subject)
  • Enforce staff–subject authorization before marking attendance
  • Avoid timetable conflicts and duplicate sessions
  • Ensure student exists and belongs to the semester

1. Check: Staff is Assigned to the Subject

# file: mcp_server/validators.py
async def staff_assigned(db, staff_id: int, subject_id: int) -> bool:
    q = "SELECT 1 FROM staff_subjects WHERE staff_id = :sid AND subject_id = :sub"
    row = await db.fetch_one(q, values={'sid': staff_id, 'sub': subject_id})
    return bool(row)

# Usage inside FastAPI route
if not await staff_assigned(db, staff_id, subject_id):
    raise HTTPException(status_code=403, detail='Staff not assigned to this subject')

2. Check: Timetable Slot Exists

-- Verify a timetable slot exists for semester/day/hour/subject
SELECT 1 FROM timetable_slots
WHERE semester_id = :semester_id AND day_of_week = :day AND slot_order = :hour AND subject_id = :subject_id;

3. Check: Student Belongs to Semester

# Python helper
async def student_in_semester(db, student_id: int, semester_id: int) -> bool:
    q = 'SELECT 1 FROM students WHERE id = :sid AND semester = :sem'
    return bool(await db.fetch_one(q, values={'sid': student_id, 'sem': semester_id}))

# Raise error if not
if not await student_in_semester(db, student_id, semester_id):
    raise HTTPException(400, 'Student not enrolled in this semester')

4. Prevent Duplicate Attendance for Same Session

-- Check if attendance row already exists for that student/session/hour
SELECT 1 FROM attendance
WHERE subject_id = :subject_id AND student_id = :student_id AND date = :date AND hour = :hour;

5. Business Rule: Attendance Window

Only allow marking attendance within a sensible window (e.g., same day ±1 day) unless an admin overrides.

from datetime import datetime, timedelta

def within_attendance_window(date_str: str) -> bool:
    d = datetime.fromisoformat(date_str).date()
    today = datetime.utcnow().date()
    return abs((today - d).days) <= 1

if not within_attendance_window(payload['date']):
    raise HTTPException(400, 'Attendance can only be marked within 1 day of class')

6. Conflict Checker for Timetable Changes

-- Prevent two subjects assigned to same semester/day/hour
SELECT COUNT(*) FROM timetable_slots
WHERE semester_id = :semester_id AND day_of_week = :day AND slot_order = :hour;
-- if count > 0 then conflict exists

7. Consolidated FastAPI Example: Mark Attendance (with Validation)

@app.post('/api/attendance/mark')
async def mark_attendance(sessionId: str, studentId: int, status: str, db: Database = Depends(get_db), user=Depends(get_current_user)):
    # fetch session metadata
    ses = await db.fetch_one('SELECT * FROM attendance_sessions WHERE id = :sid', values={'sid': sessionId})
    if not ses:
        raise HTTPException(404, 'Session not found')
    # verify staff
    if not await staff_assigned(db, user.staff_id, ses['subject_id']):
        raise HTTPException(403, 'Not authorized')
    # verify student in semester
    if not await student_in_semester(db, studentId, ses['semester_id']):
        raise HTTPException(400, 'Student not in semester')
    # prevent duplicates
    exists = await db.fetch_one('SELECT 1 FROM attendance WHERE subject_id=:sub AND student_id=:stu AND date=:d AND hour=:h', values={'sub': ses['subject_id'],'stu': studentId,'d': ses['date'],'h': ses['hour']})
    if exists:
        raise HTTPException(409, 'Attendance already marked')
    # insert
    await db.execute('INSERT INTO attendance(subject_id, staff_id, date, hour, student_id, status) VALUES(:sub, :staff, :d, :h, :stu, :status)', values={'sub': ses['subject_id'],'staff': user.staff_id,'d': ses['date'],'h': ses['hour'],'stu': studentId,'status': status})
    return { 'status':'ok' }

Testing Tips

  • Use unit tests to test each validator independently.
  • Simulate edge cases: staff not assigned, wrong date, duplicate submissions.
  • Log and audit all failed validation attempts for security review.

#Module 8 – Reports: Date, Range, Month, Semester

Module 8 – Reports: Date, Range, Month, Semester

Module 8 – Reports: Date, Range, Month, Semester

Create SQL queries and FastAPI endpoints to produce daily, date-range, monthly and semester reports for attendance.

1. Daily Report — SQL

-- Daily attendance summary per subject
SELECT s.subject_id, sub.code AS subject_code, sub.name AS subject_name,
  COUNT(*) FILTER (WHERE a.status='present') AS present_count,
  COUNT(*) FILTER (WHERE a.status='absent') AS absent_count,
  COUNT(*) AS total_taken
FROM attendance a
JOIN subjects sub ON sub.id = a.subject_id
JOIN semesters s ON s.id = sub.semester_id
WHERE a.date = '2025-08-10'
GROUP BY s.subject_id, sub.code, sub.name;

2. Date Range Report — SQL

-- Attendance percent per student in a date range
SELECT st.student_code, st.name,
  (COUNT(*) FILTER (WHERE a.status='present')::float / NULLIF(COUNT(*),0) * 100) AS attendance_pct
FROM attendance a
JOIN students st ON st.id = a.student_id
WHERE a.date BETWEEN '2025-08-01' AND '2025-08-31' AND st.semester = 3
GROUP BY st.id, st.student_code, st.name
ORDER BY attendance_pct DESC;

3. Monthly Report — FastAPI Endpoint

# file: app/reports.py
from fastapi import APIRouter
from databases import Database
from fastapi import Depends

router = APIRouter()

@router.get('/reports/monthly')
async def monthly_report(year: int, month: int, semester: int, db: Database = Depends(get_db)):
    start = f"{year}-{month:02d}-01"
    # naive end-of-month, use calendar for real app
    end = f"{year}-{month:02d}-31"
    query = """
    SELECT st.student_code, st.name,
      (COUNT(*) FILTER (WHERE a.status='present')::float / NULLIF(COUNT(*),0) * 100) AS attendance_pct
    FROM attendance a
    JOIN students st ON st.id = a.student_id
    WHERE a.date BETWEEN :start AND :end AND st.semester = :semester
    GROUP BY st.id, st.student_code, st.name
    ORDER BY attendance_pct DESC;
    """
    rows = await db.fetch_all(query, values={"start": start, "end": end, "semester": semester})
    return rows

4. Semester-wise Report (Aggregate)

-- Average attendance % across all students in a semester
SELECT st.course_id, st.semester,
  AVG(pct) AS avg_attendance_pct
FROM (
  SELECT student_id, (COUNT(*) FILTER (WHERE status='present')::float / NULLIF(COUNT(*),0) * 100) AS pct
  FROM attendance
  GROUP BY student_id
) sub
JOIN students st ON st.id = sub.student_id
WHERE st.semester = 3
GROUP BY st.course_id, st.semester;

5. Export to CSV: Endpoint

# file: app/export.py
from fastapi import APIRouter
from fastapi.responses import StreamingResponse
import csv, io

router = APIRouter()

@router.get('/reports/export/monthly')
async def export_monthly_csv(year: int, month: int, semester: int, db: Database = Depends(get_db)):
    rows = await monthly_query(db, year, month, semester)
    buf = io.StringIO()
    writer = csv.writer(buf)
    writer.writerow(['student_code','name','attendance_pct'])
    for r in rows:
        writer.writerow([r['student_code'], r['name'], r['attendance_pct']])
    buf.seek(0)
    return StreamingResponse(iter([buf.read()]), media_type='text/csv')

Notes & Tips

  • For accurate end-of-month calculation use calendar.monthrange or SQL date functions.
  • Large datasets: use pagination or async background jobs for heavy report generation.
  • Cache frequently requested reports for performance.

#Module 7 – Attendance UI & Bulk API

Module 7 – Attendance UI & Bulk API

Module 7 – Attendance UI & Bulk API

Build a simple web UI to mark attendance for 60-student classes and a bulk API endpoint to accept batch updates.

1. Single-page Attendance UI (HTML + JS)

Copy this file as attendance.html

<!doctype html>
<html><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><title>Attendance</title></head><body>
<h2>Mark Attendance</h2>
<div>
  <label>SubjectId:<input id="subject" /></label>
  <label>Date:<input id="date" type="date" /></label>
  <label>Hour:<input id="hour" type="number" min="1" max="8" /></label>
  <button onclick="loadStudents()">Load Students</button>
</div>
<div id="students"></div>

<script>
async function loadStudents(){
  const subject = document.getElementById('subject').value;
  // call API to fetch students in this semester
  const res = await fetch(`/api/students?subjectId=${subject}`);
  const students = await res.json();
  const container = document.getElementById('students');
  container.innerHTML = '';
  students.forEach(s => {
    const row = document.createElement('div');
    row.innerHTML = ` ${s.name} (${s.student_code})`;
    container.appendChild(row);
  });
}

async function submitBulk(){
  const subject = document.getElementById('subject').value;
  const date = document.getElementById('date').value;
  const hour = parseInt(document.getElementById('hour').value||'1');
  const checks = Array.from(document.querySelectorAll('#students input[type=checkbox]'));
  const attendance = checks.map(c => ({ studentId: c.getAttribute('data-id'), status: c.checked? 'present' : 'absent'}));
  await fetch('/api/attendance/bulk',{ method:'POST', headers:{'Content-Type':'application/json'}, body: JSON.stringify({ subjectId: subject, date, hour, attendance }) });
  alert('Submitted');
}
</script>
<button onclick="submitBulk()">Submit Attendance</button>
</body></html>

2. Bulk API Endpoint (FastAPI)

# file: app/main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from typing import List
import databases

DATABASE_URL = "postgresql://postgres:password@localhost/mcp_db"
db = databases.Database(DATABASE_URL)
app = FastAPI()

class AttRow(BaseModel):
  studentId: int
  status: str

class BulkIn(BaseModel):
  subjectId: int
  date: str
  hour: int
  attendance: List[AttRow]

@app.post('/api/attendance/bulk')
async def bulk_att(payload: BulkIn):
  # Basic validation
  if not payload.attendance:
    raise HTTPException(400,'No attendance rows')
  query = "INSERT INTO attendance(subject_id, staff_id, date, hour, student_id, status) VALUES(:subject_id, :staff_id, :date, :hour, :student_id, :status)"
  # staff_id will be set based on session - simplified here as NULL
  async with db.transaction():
    for r in payload.attendance:
      await db.execute(query, values={
        'subject_id': payload.subjectId,
        'staff_id': None,
        'date': payload.date,
        'hour': payload.hour,
        'student_id': r.studentId,
        'status': r.status
      })
  return { 'status': 'success', 'stored': len(payload.attendance) }

Notes

  • In production, attach staff_id from authenticated session and validate subject mapping.
  • Wrap the bulk insert in a transaction to ensure atomicity.
  • For 60 students, this endpoint should handle inserts promptly; consider using COPY or batch inserts for scale.

#Module 6 – MCP Attendance Marking Workflow

Module 6 – MCP Attendance Marking Workflow

Module 6 – MCP Attendance Marking Workflow

This module explains how to implement **Attendance Marking Workflow** using Model Context Protocol (MCP).
We will cover:

  • Generating attendance session
  • Fetching student list
  • Marking present/absent
  • Storing attendance with MCP
  • Validating timetable hour

๐Ÿซ Real Example

Semester S3, Subject SUB301 – Data Structures, Staff T5 taking class at
Monday – Hour 2.


1️⃣ Generate Attendance Session

# Create a new attendance session
mcp call academic_tracker.create '{
  "entity": "attendance_session",
  "data": {
    "id": "SES1001",
    "date": "2025-08-10",
    "semesterId": "S3",
    "subjectId": "SUB301",
    "hour": 2,
    "day": "Monday",
    "staffId": "T5"
  }
}'

2️⃣ Fetch Students of the Semester

# Fetch the list of 60 students in S3
mcp call academic_tracker.read '{
  "entity": "students",
  "filter": { "semesterId": "S3" }
}'

3️⃣ Mark Attendance – Present / Absent

Each student will be marked one by one (or in batch).

# Mark present
mcp call academic_tracker.create '{
  "entity": "attendance",
  "data": {
    "studentId": "STU3301",
    "sessionId": "SES1001",
    "status": "present"
  }
}'
# Mark absent
mcp call academic_tracker.create '{
  "entity": "attendance",
  "data": {
    "studentId": "STU3302",
    "sessionId": "SES1001",
    "status": "absent"
  }
}'

4️⃣ Batch Marking (Optional)

Useful for large classes (60 per semester).

{
  "sessionId": "SES1001",
  "attendance": [
    { "studentId": "STU3301", "status": "present" },
    { "studentId": "STU3302", "status": "absent" },
    { "studentId": "STU3303", "status": "present" }
  ]
}

5️⃣ Validate Timetable Hour (Important Safety Check)

# Ensure the class is actually scheduled for that hour
mcp call academic_tracker.read '{
  "entity": "timetable",
  "filter": {
    "semesterId": "S3",
    "day": "Monday",
    "hour": 2,
    "subjectId": "SUB301"
  }
}'

6️⃣ Final Stored Attendance (Returned JSON)

{
  "status": "success",
  "sessionId": "SES1001",
  "recordsStored": 60,
  "message": "Attendance saved for all students."
}

๐ŸŽ‰ Module 6 Completed!

You now understand how to mark attendance using MCP with: sessions, validation, batch handling, and student lists.

#Module 5 – CRUD Operations using MCP

Module 5 – MCP Commands for CRUD Operations

Module 5 – CRUD Operations using MCP

This module covers how to perform Create, Read, Update, Delete (CRUD) operations using Model Context Protocol (MCP) for the Attendance Tracking System.

๐Ÿ“Œ CRUD Targets

  • Courses
  • Semesters
  • Subjects
  • Staff
  • Students
  • Timetable
  • Attendance Records

▶️ CREATE Commands

# Create a new course
mcp call academic_tracker.create '{
  "id": "C3",
  "name": "M.Tech – Data Science",
  "semesters": 4
}'
# Create a new student
mcp call academic_tracker.create '{
  "id": "STU1201",
  "name": "Rahul",
  "courseId": "C1",
  "semesterId": "S3"
}'

๐Ÿ“– READ Commands

# Read all students of a semester
mcp call academic_tracker.read '{
  "entity": "students",
  "filter": { "semesterId": "S1" }
}'
# Get timetable for Semester 5
mcp call academic_tracker.read '{
  "entity": "timetable",
  "filter": { "semesterId": "S5" }
}'

♻️ UPDATE Commands

# Update a student's semester
mcp call academic_tracker.update '{
  "entity": "students",
  "id": "STU1201",
  "data": { "semesterId": "S4" }
}'
# Change staff assigned to a subject
mcp call academic_tracker.update '{
  "entity": "subjects",
  "id": "SUB101",
  "data": { "staffId": "T3" }
}'

๐Ÿ—‘️ DELETE Commands

# Delete a student
mcp call academic_tracker.delete '{
  "entity": "students",
  "id": "STU1201"
}'
# Delete subject timetable entry
mcp call academic_tracker.delete '{
  "entity": "timetable",
  "id": "TT1"
}'

๐Ÿงพ Sample Output (JSON Returned from MCP)

{
  "status": "success",
  "message": "Student updated successfully",
  "data": {
    "id": "STU1201",
    "name": "Rahul",
    "courseId": "C1",
    "semesterId": "S4"
  }
}

๐ŸŽ‰ Module 5 Completed!

CRUD operations are now fully operational in MCP for your attendance system.

#Module 4 – MCP Data Modeling Structure

Module 4 – MCP Data Modeling Structure

Module 4 – MCP Data Modeling Structure

In this module, we design a complete data model for the Attendance Tracking System. This data model will be carried across all further MCP commands and backend logic.

๐Ÿ“Œ Real-World Scenario

  • 2 Courses: 8-semester degree, 4-semester diploma
  • 14 Staff members
  • 6 Subjects per semester
  • 60 Students per semester
  • Odd Semesters → 1,3,5,7
  • Even Semesters → 2,4,6,8
  • Each semester has a 40-hour weekly timetable

๐ŸŽฏ Goal of This Module

Define a clean MCP-ready data model with all entities, relationships, and JSON structures.

๐Ÿ“˜ Entities We Will Model

  • Course
  • Semester
  • Subject
  • Staff
  • Student
  • Timetable
  • Attendance Records

๐Ÿงฉ Complete JSON Data Model

{
  "courses": [
    {
      "id": "C1",
      "name": "B.E – Computer Science",
      "semesters": 8
    },
    {
      "id": "C2",
      "name": "Diploma – Computer Engineering",
      "semesters": 4
    }
  ],

  "semesters": [
    { "id": "S1", "courseId": "C1", "number": 1, "type": "odd" },
    { "id": "S2", "courseId": "C1", "number": 2, "type": "even" },
    { "id": "S3", "courseId": "C1", "number": 3, "type": "odd" },
    { "id": "S4", "courseId": "C1", "number": 4, "type": "even" },
    { "id": "S5", "courseId": "C1", "number": 5, "type": "odd" },
    { "id": "S6", "courseId": "C1", "number": 6, "type": "even" },
    { "id": "S7", "courseId": "C1", "number": 7, "type": "odd" },
    { "id": "S8", "courseId": "C1", "number": 8, "type": "even" },

    { "id": "S9",  "courseId": "C2", "number": 1, "type": "odd" },
    { "id": "S10", "courseId": "C2", "number": 2, "type": "even" },
    { "id": "S11", "courseId": "C2", "number": 3, "type": "odd" },
    { "id": "S12", "courseId": "C2", "number": 4, "type": "even" }
  ],

  "subjects": [
    {
      "id": "SUB101",
      "name": "Mathematics – I",
      "semesterId": "S1",
      "staffId": "T1",
      "weeklyHours": 4
    }
  ],

  "staff": [
    { "id": "T1", "name": "Dr. Devi", "department": "CSE" },
    { "id": "T2", "name": "Mr. Arun", "department": "CSE" }
  ],

  "students": [
    {
      "id": "STU001",
      "name": "Anitha",
      "courseId": "C1",
      "semesterId": "S1"
    }
  ],

  "timetable": [
    {
      "id": "TT1",
      "semesterId": "S1",
      "weekHours": 40,
      "slots": [
        { "hour": 1, "day": "Monday", "subjectId": "SUB101" },
        { "hour": 2, "day": "Monday", "subjectId": "SUB102" }
      ]
    }
  ],

  "attendance": [
    {
      "id": "A1",
      "studentId": "STU001",
      "subjectId": "SUB101",
      "date": "2025-08-05",
      "status": "present"
    }
  ]
}

๐Ÿ› ️ CLI Commands for MCP Integration

# Register data model inside MCP configuration
mcp set model attendance_model.json --namespace academic_tracker

# Push initial dataset
tool push academic_tracker attendance_model.json

๐ŸŽ‰ Module 4 Complete!

You now have a fully structured MCP-compliant data model for the entire University Attendance System.

#Module 3 – MCP JSON Schemas & Validation Layer

Module 3 – MCP JSON Schemas & Validation Layer

Module 3 – MCP JSON Schemas & Validation Layer

This module defines JSON Schemas for all core MCP data objects for our University Attendance System.

What You Will Build

  • Define JSON Schemas for: Course, Semester, Subject, Staff, Student, Attendance
  • Create schemas/ folder
  • Implement Python JSON schema validation
  • Expose validation as an MCP Tool

๐Ÿ“ Step 1 — Create Folder for Schemas

mkdir schemas

๐Ÿ“„ Step 2 — Create JSON Schemas

Create the file: schemas/course.schema.json

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Course",
  "type": "object",
  "properties": {
    "code": { "type": "string" },
    "name": { "type": "string" },
    "total_semesters": { "type": "number" }
  },
  "required": ["code", "name", "total_semesters"]
}

Semester Schema

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Semester",
  "type": "object",
  "properties": {
    "course_id": { "type": "number" },
    "number": { "type": "number" },
    "type": { "type": "string", "enum": ["odd", "even"] }
  },
  "required": ["course_id", "number", "type"]
}

Subject Schema

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Subject",
  "type": "object",
  "properties": {
    "semester_id": { "type": "number" },
    "code": { "type": "string" },
    "name": { "type": "string" }
  },
  "required": ["semester_id", "code", "name"]
}

Attendance Schema

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "title": "Attendance",
  "type": "object",
  "properties": {
    "subject_id": { "type": "number" },
    "staff_id": { "type": "number" },
    "date": { "type": "string", "format": "date" },
    "hour": { "type": "number" },
    "student_id": { "type": "number" },
    "status": { "type": "string", "enum": ["present", "absent", "late"] }
  },
  "required": ["subject_id", "staff_id", "date", "hour", "student_id", "status"]
}

๐Ÿงช Step 3 — Python Validation Utility

# file: mcp_server/validator.py
import json, os
from jsonschema import validate, ValidationError

SCHEMA_PATH = "schemas"

def load_schema(name):
    with open(os.path.join(SCHEMA_PATH, f"{name}.schema.json")) as f:
        return json.load(f)

def validate_payload(schema_name, payload):
    try:
        schema = load_schema(schema_name)
        validate(payload, schema)
        return {"valid": True}
    except ValidationError as err:
        return {"valid": False, "error": str(err)}

๐Ÿ”ง Step 4 — Register MCP Validation Tool

# file: mcp_server/server.py (append)
from validator import validate_payload

@app.tool()
def validate_json(schema: str, payload: dict):
    """Validate a JSON object using the MCP schema system."""
    return validate_payload(schema, payload)

▶️ Step 5 — Test With Sample JSON

{
  "subject_id": 12,
  "staff_id": 4,
  "date": "2025-07-22",
  "hour": 3,
  "student_id": 91,
  "status": "present"
}

#Module 2 - Data Model: SQL Schema (Postgres)

Module 2 – Data Model: SQL Schema (Postgres)

Module 2 – Data Model: SQL Schema (Postgres)

Goal: create normalized schema for courses, semesters, subjects, staff, students, timetable, attendance.

Overview

We design a relational schema to reflect the MCP entities. This schema supports:

  • 2 courses (8-sem & 4-sem)
  • Semesters with odd/even type
  • Subjects (6 per semester)
  • Staff, student enrollments, timetable, attendance logs

SQL Schema (mcp_schema.sql)

-- MCP Attendance SQL Schema

BEGIN;

CREATE TABLE courses (
  id SERIAL PRIMARY KEY,
  code TEXT UNIQUE NOT NULL,
  name TEXT NOT NULL,
  total_semesters INT NOT NULL
);

CREATE TABLE semesters (
  id SERIAL PRIMARY KEY,
  course_id INT NOT NULL REFERENCES courses(id) ON DELETE CASCADE,
  number INT NOT NULL,
  type TEXT NOT NULL CHECK (type IN ('odd','even'))
);

CREATE TABLE staff (
  id SERIAL PRIMARY KEY,
  staff_code TEXT UNIQUE NOT NULL,
  name TEXT NOT NULL
);

CREATE TABLE subjects (
  id SERIAL PRIMARY KEY,
  semester_id INT NOT NULL REFERENCES semesters(id) ON DELETE CASCADE,
  code TEXT NOT NULL,
  name TEXT NOT NULL,
  UNIQUE(semester_id, code)
);

CREATE TABLE students (
  id SERIAL PRIMARY KEY,
  student_code TEXT UNIQUE NOT NULL,
  name TEXT NOT NULL,
  course_id INT NOT NULL REFERENCES courses(id),
  semester INT NOT NULL
);

CREATE TABLE staff_subjects (
  staff_id INT NOT NULL REFERENCES staff(id) ON DELETE CASCADE,
  subject_id INT NOT NULL REFERENCES subjects(id) ON DELETE CASCADE,
  PRIMARY KEY(staff_id, subject_id)
);

CREATE TABLE timetable_slots (
  id SERIAL PRIMARY KEY,
  semester_id INT NOT NULL REFERENCES semesters(id) ON DELETE CASCADE,
  day_of_week INT NOT NULL CHECK(day_of_week BETWEEN 1 AND 7),
  slot_order INT NOT NULL,
  subject_id INT NOT NULL REFERENCES subjects(id)
);

CREATE TABLE attendance (
  id SERIAL PRIMARY KEY,
  subject_id INT NOT NULL REFERENCES subjects(id),
  staff_id INT NOT NULL REFERENCES staff(id),
  date DATE NOT NULL,
  hour INT NOT NULL,
  student_id INT NOT NULL REFERENCES students(id),
  status TEXT NOT NULL CHECK (status IN ('present','absent','late')) DEFAULT 'present'
);

CREATE INDEX idx_attendance_date ON attendance(date);

COMMIT;

Notes & Constraints

  • students.semester stores the semester number (1..8 or 1..4 depending on course).
  • Use staff_subjects to authorize staff to mark attendance for specific subjects.
  • timetable_slots maps a semester's weekly slots (40 slots = 5 days × 8 slots).
  • Attendance is stored per student per subject per hour to allow hourly reporting.

How to run

Create DB & run the SQL file using psql:

createdb mcp_db
psql -U postgres -d mcp_db -f mcp_schema.sql

Sample queries

-- Count students per semester
SELECT course_id, semester, COUNT(*) AS students_count
FROM students
GROUP BY course_id, semester
ORDER BY course_id, semester;

-- Attendance percentage for a student in a date range
SELECT s.student_code, s.name,
  (COUNT(*) FILTER (WHERE a.status='present')::float / COUNT(*) * 100) AS pct
FROM attendance a
JOIN students s ON s.id = a.student_id
WHERE s.student_code = 'S101' AND a.date BETWEEN '2025-08-01' AND '2025-08-31'
GROUP BY s.student_code, s.name;

Next: Module 3 — MCP Schemas (JSON Schema) & Validation.

#Module 1 - MCP Intro

Module 1 – Introduction to Model Context Protocol (MCP)

Module 1 – Introduction to Model Context Protocol (MCP)

Model Context Protocol (MCP) allows AI agents to interact safely with tools, code, and structured data. In this 12‑module course, we will build an Attendance Tracking System for a university department:

  • 2 Courses
  • 8-semester program & 4-semester program
  • 14 Staff
  • 6 Subjects per semester
  • 60 Students per semester
  • Odd: 1,3,5,7 | Even: 2,4,6,8
  • Each semester has a 40-hour weekly timetable

๐Ÿ”น What You Will Learn in Module 1

  • What MCP is
  • Why MCP is useful for structured academic workflow systems
  • How our Attendance System will use MCP
  • Set up the MCP-compatible project folder

๐Ÿ“Œ Step 1 — Create Project Structure

Run the following commands to create the project folder for the upcoming modules:


mkdir university-attendance-mcp
cd university-attendance-mcp
mkdir mcp_server
mkdir database
mkdir models
mkdir logs

๐Ÿ“Œ Step 2 — Create MCP Server Boilerplate

We will create a simple MCP server using Python.


# file: mcp_server/server.py
from mcp import MCPServer

app = MCPServer(name="UniversityAttendanceMCP")

@app.tool()
def ping():
    return {"message": "MCP Server is running"}

if __name__ == "__main__":
    app.run()

๐Ÿ“Œ Step 3 — Install Dependencies

Install MCP SDK and required libraries:


pip install model-context-protocol uvicorn fastapi

๐Ÿ“Œ Step 4 — Run the MCP Server


python mcp_server/server.py

If everything is correct, MCP should print:


{"message": "MCP Server is running"}

#MCP Index

MCP Tutorial – Module Index MCP Tutorial – 12 Modules Latest Edition for AU-CSE Final year Students Module 1 Introducti...