Skip to main content
Glama
chandrabhanu18

University Course Catalog MCP Server

README.md
# University Course Catalog MCP Server

A production-grade [Model Context Protocol](https://modelcontextprotocol.io/) server that exposes a university course catalog through structured tools, resources, and prompt templates. Built with Python 3.12, FastAPI, SQLAlchemy 2.x, and the official MCP SDK.

## Project Overview

This MCP server provides intelligent access to a university course catalog with the following capabilities:

- **Full-text course search** with optional department filtering
- **Prerequisite dependency tracking** with cycle prevention
- **Instructor lookups** with contact information and department associations
- **Prerequisite graph analysis** for understanding course dependencies
- **Course catalog resource** with complete course descriptions
- **Department directory resource** for department information
- **Course comparison prompt template** for structured LLM analysis

The server is designed to work seamlessly with Claude, ChatGPT, and other LLM clients through the MCP protocol.

## Architecture

### Design Principles

- **Clean Separation of Concerns**: Service layer abstraction decouples MCP tools from database operations
- **Production Quality**: Full logging, error handling, type hints, and docstrings throughout
- **Scalability**: SessionLocal factory pattern for thread-safe database access
- **Maintainability**: Centralized configuration, structured schemas, and comprehensive tests

### Layer Structure

```
MCP Tools/Resources/Prompts (src/tools, src/resources, src/prompts)
                ↓
Pydantic Schemas (src/schemas) - Input/output validation
                ↓
Service Layer (src/services) - Business logic, database queries
                ↓
SQLAlchemy ORM (src/models) - Database mapping
                ↓
SQLite Database (data/catalog.db)
```

### Data Flow

1. **MCP Client** sends request with validated input
2. **Tool/Resource Handler** validates input via Pydantic schema
3. **Service Layer** queries database using SQLAlchemy 2.x with select()
4. **ORM** marshals database results to Python objects
5. **Response** returned as typed Pydantic model for JSON serialization

## Folder Structure

```
university-mcp-server/
├── src/
│   ├── config.py                 # Environment configuration (Pydantic BaseSettings)
│   ├── database.py               # SQLAlchemy engine and SessionLocal
│   ├── mcp_app.py                # Shared FastMCP instance
│   ├── server.py                 # FastAPI application with MCP transport mounting
│   ├── models/                   # SQLAlchemy ORM models
│   │   ├── course.py
│   │   ├── department.py
│   │   ├── instructor.py
│   │   └── prerequisite.py
│   ├── schemas/                  # Pydantic validation schemas
│   │   └── course.py
│   ├── services/                 # Business logic and database queries
│   │   ├── course_service.py
│   │   ├── department_service.py
│   │   ├── graph_service.py
│   │   └── instructor_service.py
│   ├── tools/                    # MCP tools (registered via @mcp.tool)
│   │   ├── search_courses.py
│   │   ├── get_prerequisites.py
│   │   ├── lookup_instructor.py
│   │   └── get_prerequisite_graph.py
│   ├── resources/                # MCP resources (registered via @mcp.resource)
│   │   ├── course_descriptions.py
│   │   └── department_directory.py
│   └── prompts/                  # MCP prompts (registered via @mcp.prompt)
│       └── course_comparison.py
├── data/
│   ├── seed.py                   # Database seeding script
│   └── catalog.db                # SQLite database (created at runtime)
├── tests/                        # Pytest test suite
│   ├── conftest.py               # Fixtures and test configuration
│   ├── test_mcp_app.py
│   ├── test_endpoints.py
│   ├── test_tools.py
│   ├── test_resources.py
│   └── test_prompts.py
├── Dockerfile                    # Container image definition
├── docker-compose.yml            # Multi-container orchestration
├── .env.example                  # Environment variable template
├── requirements.txt              # Python dependencies
├── pytest.ini                    # Pytest configuration
└── README.md                     # This file
```

## Installation

### Prerequisites

- Python 3.12+
- pip or conda package manager
- Docker and Docker Compose (optional, for containerized deployment)

### Local Setup

1. **Clone the repository**
   ```bash
   cd university-mcp-server
   ```

2. **Create and activate virtual environment**
   ```bash
   # Windows
   python -m venv venv
   .\venv\Scripts\Activate.ps1

   # macOS/Linux
   python3 -m venv venv
   source venv/bin/activate
   ```

3. **Install dependencies**
   ```bash
   pip install -r requirements.txt
   ```

4. **Initialize database**
   ```bash
   # Windows
   .\venv\Scripts\python.exe data/seed.py

   # macOS/Linux
   python data/seed.py
   ```

5. **Configure environment (optional)**
   ```bash
   # Copy template and customize if needed
   cp .env.example .env
   ```

### Docker Setup

1. **Build and start with Docker Compose**
   ```bash
   docker-compose up --build
   ```

  The container bootstraps the SQLite schema and seed data on startup, so a fresh checkout works without a prebuilt database file.

2. **Verify server is running**
   ```bash
   curl http://localhost:8080/health
   # Response: {"status": "healthy"}
   ```

3. **Stop the service**
   ```bash
   docker-compose down
   ```

## Environment Variables

Configure via `.env` file (see `.env.example`):

| Variable | Default | Description |
|----------|---------|-------------|
| `DATABASE_URL` | `sqlite:///./data/catalog.db` | SQLAlchemy database connection string; supports sqlite, PostgreSQL, MySQL |
| `HOST` | `0.0.0.0` | Server binding address; use `127.0.0.1` for localhost-only |
| `PORT` | `8080` | Server port number (1-65535) |

### Docker Environment

Docker Compose automatically sets all environment variables. Override in `docker-compose.yml`:

```yaml
environment:
  DATABASE_URL: sqlite:///./data/catalog.db
  HOST: 0.0.0.0
  PORT: 8080
```

## Running Locally

### Start the server

```bash
# Windows
.\venv\Scripts\python.exe -m src.server

# macOS/Linux
python -m src.server
```

Server will start on `http://0.0.0.0:8080` with logging output.

### Health check

```bash
curl http://localhost:8080/health
```

Expected response:
```json
{"status": "healthy"}
```

### Access MCP endpoints

- **HTTP (Streamable)**: `http://localhost:8080/mcp`
- **SSE (Server-Sent Events)**: `http://localhost:8080/sse`
- **SSE message endpoint**: `http://localhost:8080/sse/messages/`

## Docker Notes

- The image runs `create_db.py` and `data/seed.py` on startup before launching the API.
- The build excludes the local virtual environment and cache directories with `.dockerignore`.
- The container exposes port `8080` and uses the same `DATABASE_URL`, `HOST`, and `PORT` settings as local runs.

## Testing

Run the full pytest suite:

```bash
# All tests
pytest

# Verbose output
pytest -v

# Specific test file
pytest tests/test_tools.py

# Specific test class
pytest tests/test_tools.py::TestSearchCoursesTool

# With coverage
pip install pytest-cov
pytest --cov=src --cov-report=html
```

### Test Structure

- **test_mcp_app.py**: Startup smoke tests for FastAPI app composition and MCP registration (2 tests)
- **test_endpoints.py**: Health endpoint validation (3 tests)
- **test_tools.py**: MCP tool functionality (18 tests)
  - search_courses: keyword search, filtering, no results, case insensitivity
  - get_prerequisites: with/without prerequisites, error handling
  - lookup_instructor: success, not found, whitespace handling
  - get_prerequisite_graph: graph generation, structure validation
- **test_resources.py**: MCP resource generation (12 tests)
  - course_descriptions: format, field inclusion, multiple courses
  - department_directory: format, codes, alphabetical ordering
- **test_prompts.py**: Prompt template rendering (10 tests)

**Coverage**: 45 test cases covering app wiring, success paths, and failure paths.

## Available MCP Tools

### 1. search_courses

Search the university course catalog by keyword with optional department filtering.

**Input Schema**
```json
{
  "query": "string (required, non-empty)",
  "department_code": "string (optional, e.g., 'CS', 'AI')"
}
```

**Output Schema**
```json
{
  "root": [
    {
      "course_code": "CS101",
      "title": "Introduction to Computer Science",
      "credits": 3
    }
  ]
}
```

**Example Queries**
- "Find all programming courses"
- "Search for data science courses in the DS department"
- "What computer science courses are available?"

### 2. get_prerequisites

Retrieve all direct prerequisite courses for a given course code.

**Input Schema**
```json
{
  "course_code": "string (required, e.g., 'CS201')"
}
```

**Output Schema**
```json
{
  "course_code": "CS201",
  "prerequisites": [
    {
      "course_code": "CS101",
      "title": "Introduction to Computer Science"
    }
  ]
}
```

**Example Queries**
- "What are the prerequisites for CS201?"
- "Can I take AI101 without any prerequisites?"
- "What courses do I need to complete before taking CS301?"

### 3. lookup_instructor

Find instructor contact information and department assignment.

**Input Schema**
```json
{
  "instructor_name": "string (required, e.g., 'Dr. Alice Smith')"
}
```

**Output Schema**
```json
{
  "name": "Dr. Alice Smith",
  "email": "alice@university.edu",
  "department_name": "Computer Science"
}
```

**Example Queries**
- "How can I contact Dr. Alice Smith?"
- "What department is Dr. Bob Johnson in?"
- "Find the email for Dr. Carol White"

### 4. get_prerequisite_graph

Build a complete prerequisite dependency graph for a course, showing all direct and transitive prerequisites.

**Input Schema**
```json
{
  "course_code": "string (required, e.g., 'CS301')"
}
```

**Output Schema**
```json
{
  "nodes": [
    {"id": "CS101"},
    {"id": "CS201"},
    {"id": "CS301"}
  ],
  "edges": [
    {"source": "CS101", "target": "CS201"},
    {"source": "CS201", "target": "CS301"}
  ]
}
```

**Example Queries**
- "Show me the prerequisite chain for CS301"
- "What's the full dependency graph for AI301?"
- "Create a graph of all prerequisites needed for DS301"

## Available MCP Resources

### course_descriptions

A comprehensive text resource listing all university courses with complete descriptions.

**URI**: `resource://course_descriptions`

**Format**
```
[CODE] Title
Credits: N
Description: ...
------------------------------------
```

**Example Response**
```
[CS101] Introduction to Computer Science
Credits: 3
Description: Fundamentals of programming and computational thinking
------------------------------------
[CS201] Data Structures and Algorithms
Credits: 4
Description: Advanced programming concepts and algorithm design
------------------------------------
```

### department_directory

A formatted text resource containing all university departments.

**URI**: `resource://department_directory`

**Format**
```
Name (Code)
Name (Code)
...
```

**Example Response**
```
Artificial Intelligence (AI)
Computer Science (CS)
Data Science (DS)
```

## Prompt Template

### course_comparison_template

A reusable prompt template for comparing two courses, useful for generating structured LLM analysis.

**Parameters**
- `course_code_1`: First course code (e.g., "CS101")
- `course_code_2`: Second course code (e.g., "CS201")

**Generated Prompt**
The template instructs the LLM to create a comparison table with:
- Course titles
- Credit hours
- Course descriptions
- Instructors
- Departments
- Prerequisites
- Recommendations for student types

**Example Usage**
```
Compare CS101 vs CS201 to understand which course would be better for a beginner programmer
```

## Example Natural Language Queries

### Course Discovery
- "What programming courses are available in the CS department?"
- "Find all courses about machine learning"
- "Show me the data science curriculum"
- "What courses can I take without prerequisites?"

### Prerequisite Planning
- "What do I need to take CS301?"
- "Show me the full prerequisite chain for AI301"
- "Can I take DS201 if I've completed CS101?"
- "Map out all the required courses for the AI track"

### Instructor Information
- "Who teaches CS201?"
- "How do I contact Dr. Alice Smith?"
- "What courses are taught by the Data Science department?"
- "Find all instructors in the Computer Science department"

### Course Comparison
- "Compare CS101 and CS201 to decide which to take"
- "What's the difference between AI101 and DS101?"
- "Should I take the AI course or the DS course?"

### Curriculum Planning
- "Create a 2-semester course plan for CS major"
- "What's the recommended order to take CS courses?"
- "Show me all prerequisites needed to take the advanced AI courses"

## Technology Stack

### Core Framework
- **FastAPI 0.139.0** - Async web framework for Python
- **Uvicorn** - ASGI server for FastAPI

### Database & ORM
- **SQLAlchemy 2.x** - Modern Python ORM with select() queries
- **SQLite** - Lightweight embedded database (default; easily swappable)

### MCP & LLM Integration
- **mcp 1.28.1** - Official Model Context Protocol SDK
- **Pydantic v2** - Data validation and serialization

### Utilities
- **httpx** - HTTP client for health checks
- **NetworkX 3.x** - Graph algorithms for prerequisite dependency analysis

### Development & Testing
- **pytest** - Testing framework
- **Docker & Docker Compose** - Containerization and orchestration

### Python Version
- **Python 3.12** - Latest stable Python version with improved performance

## Future Improvements

### Phase 2: Enhanced Features
- [ ] Course enrollment management (add/drop functionality)
- [ ] Student transcript tracking
- [ ] GPA calculation and academic standing
- [ ] Course schedule/timetable queries
- [ ] Room and building location resources
- [ ] Instructor office hours and availability

### Phase 3: Advanced Analytics
- [ ] Course recommendation engine based on student history
- [ ] Prerequisite conflict detection and resolution suggestions
- [ ] Workload analysis (credits per semester)
- [ ] Course difficulty ratings and student feedback
- [ ] Prerequisite weakness identification

### Phase 4: Integration & Deployment
- [ ] PostgreSQL support for production environments
- [ ] Authentication and authorization (OAuth2)
- [ ] Rate limiting and API key management
- [ ] WebSocket support for real-time updates
- [ ] Kubernetes deployment manifests
- [ ] AWS/Azure cloud deployment guides

### Phase 5: UX Improvements
- [ ] Multi-language support (Spanish, Chinese, etc.)
- [ ] Accessibility enhancements (screen reader optimization)
- [ ] Interactive prerequisite tree visualization
- [ ] Course planning calendar with drag-and-drop
- [ ] Mobile-friendly response formatting

## License

This project is provided as-is for educational and demonstration purposes. Modify and distribute freely with attribution.

---

**Questions or Issues?**

For bugs, feature requests, or questions, refer to the project documentation or contact the development team.

**Happy course planning! 🎓**