Skip to main content
Glama

AI Student Developer Assistant — MCP Server

A production-quality Model Context Protocol server that gives an AI assistant unified access to your GitHub issues, your academic deadlines (LMS), and a personal task tracker — so it can answer questions like "What should I work on today?" with a real, prioritized answer.

Built with Python 3.12+, the official MCP Python SDK (v2), FastAPI-style service separation, SQLite, and httpx. Fully tested with mocked external APIs — no real credentials required to run the suite.


Table of Contents


Project Overview

The problem. A student-developer's work lives in three disconnected places: code tasks in GitHub, assignments and exams in a college LMS, and personal todos scattered in notes. Priorities get decided by memory, so things slip.

The solution. One MCP server that exposes all three sources as small, well-described, strongly-typed tools. An AI assistant reads and reasons over all of them at once: it can pull your assigned issues, this week's deadlines, your pending tasks, detect overdue items, build a prioritized summary — and mutate systems (create/close issues, create tasks, batch-import deadlines) with the same interface.

Status. This is a portfolio-quality implementation of a personal productivity tool. Everything works end-to-end; the LMS integration is deliberately mocked behind a swappable interface (see Limitations).


Features — the MCP tools

Fifteen narrowly-scoped tools. Each has a clear name, a description the AI reads to decide when to call it, validated inputs, and a predictable output:

GitHub (4 tools)

Tool

Description

get_open_issues

List open issues; filter by repository (owner/name), assignee, labels, state. Without a repository, returns issues assigned to you across all repos.

get_issue

Full detail (body, labels, assignee) for one issue.

create_issue

Create a GitHub issue.

close_issue

Close a GitHub issue.

LMS / academic deadlines (3 tools)

Tool

Description

get_upcoming_deadlines

Assignments/exams, optionally filtered by date range and course.

get_course_assignments

All assignments for one course.

get_assignment

Detailed description of one assignment.

Task tracker (8 tools)

Tool

Description

create_task

Add a personal task with title, description, due date, priority.

get_tasks

List/filter tasks by status, priority, due-date window, source.

complete_task

Mark a task done.

delete_task

Remove a task.

get_overdue_tasks

Tasks past their due date and not completed.

create_task_from_issue

GitHub issue → task (duplicate-safe).

create_tasks_from_deadlines

Deadlines → tasks (duplicate-safe).

get_workload_summary

One unified snapshot: open issues + deadlines + pending/overdue tasks.

All tools return the same JSON shape so an agent can parse results reliably:

{ "ok": true,  "data": { "...": "..." }, "error": null }
{ "ok": false, "data": null, "error": { "code": "not_found", "message": "..." } }

Architecture

flowchart TB
    subgraph Host["AI Client (e.g. Claude Desktop)"]
        Agent["Assistant / Agent"]
    end
    subgraph MCP["MCP Protocol (stdio)"]
        S["MCPServer (mcp SDK v2)"]
    end
    subgraph App["app/"]
        Tools["tools/ · 15 thin tool functions"]
        Services["services/ · GitHub · LMS · Task"]
        Repo["TaskRepository"]
        DB[("SQLite")]
        Mock["MockLMSService"]
    end
    Ext["GitHub REST API v3"]
    Agent -->|tools/list · tools/call · server/discover| S
    S --> Tools
    Tools --> Services --> Repo --> DB
    Services --> Ext
    Services --> Mock

The golden rule in this codebase: the MCP layer is only adapters. Each tool function validates inputs via its type signature, calls a service, and renders the result. No business logic lives in tool functions.


Tech Stack

Technology

Why

Python 3.12+

Modern typing, datetime.fromisoformat, enums, dataclasses.

MCP Python SDK v2 (mcp>=2,<3)

The current stable SDK line. Its MCPServer (formerly FastMCP) generates JSON Schema from type hints, speaks stdio + Streamable HTTP, serves both protocol eras, and enables in-memory Client(server) testing.

httpx

Modern async/requests-compatible HTTP client with rich error types (TimeoutException, TransportError) that map cleanly onto our exception hierarchy.

Pydantic v2

Input validation and typed, serializable output models.

SQLAlchemy 2.0

Declarative ORM with type-safe Mapped columns, CHECK constraints, partial indexes — and a painless future migration path to PostgreSQL.

SQLite

Zero-config, single-file, perfect for a personal tool. Not a production multi-user database — see Limitations.

python-dotenv

.env loading (real environment variables still win).

pytest + respx + pytest-asyncio

Deterministic unit tests; respx mocks every GitHub HTTP call; pytest-asyncio drives the in-memory MCP client tests.


Installation

Requirements: Python 3.12+ and git. (The MCP SDK itself needs ≥3.10; this project targets 3.12.)

Windows (PowerShell)

cd "C:\Users\ASUS\mcp project"
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
pip install -r requirements.txt

If Activate.ps1 is blocked by the execution policy:

Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass

macOS / Linux

cd mcp-project
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install -r requirements.txt

Configuration

Copy the placeholder file and fill in your values:

cp .env.example .env     # Windows:  copy .env.example .env

Variable

Meaning

Example

GITHUB_TOKEN

Fine-grained PAT with Issues: Read & Write on your repos.

github_pat_...

LMS_PROVIDER

Only mock is implemented today.

mock

LMS_SEED_FILE

Optional JSON seed file for the mock LMS.

(leave unset)

DATABASE_PATH

SQLite location (relative to project root).

data/tasks.db

LOG_LEVEL

DEBUG, INFO, WARNING, ERROR.

INFO

GITHUB_BASE_URL

GitHub API base. Leave default.

https://api.github.com

REQUEST_TIMEOUT_SECONDS

Outbound timeout.

15.0

MAX_RESULTS

Max issues per request.

100

Creating a GitHub tokenGitHub → Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token → select only the repositories you need → grant only Issues: Read and Write.

⚠️ .env is git-ignored. Never commit it. .env.example contains placeholders only.


Running the Server

1. Initialize the database and seed demo data

python -m scripts.seed_demo

This creates data/tasks.db and inserts a few realistic demo tasks (one deliberately overdue).

2. Run the MCP server

python -m app.server

The server launches over stdio (the default for desktop MCP clients) and stays running until stopped.

Development & debugging

The SDK ships a CLI and an interactive inspector:

mcp dev app/server.py        # launch + open the MCP Inspector in a browser
mcp run app/server.py        # run the server (same behavior as python -m app.server)

Connecting an AI Client

Local MCP servers run over stdio: the AI client launches your server process and speaks to it over stdin/stdout. Configuration format is the client's mcpServers block.

Claude Desktop (Windows)

Edit %APPDATA%\Claude\claude_desktop_config.json (open via Settings → Developer → Edit Config), fully quit, and relaunch:

{
  "mcpServers": {
    "ai-student-assistant": {
      "command": "C:\\Users\\ASUS\\mcp project\\.venv\\Scripts\\python.exe",
      "args": ["C:\\Users\\ASUS\\mcp project\\app\\server.py"]
    }
  }
}

Requirements:

  • Absolute paths — Claude Desktop does not inherit your shell PATH or working directory.

  • Use where python / where git to confirm the exact interpreter path.

  • After saving, fully restart Claude Desktop, then look under the connectors/message-box menu for the server and its tools.

  • Logs if it fails: %APPDATA%\Claude\logs\mcp*.log.

Alternatives

  • MCP Inspector (no config): mcp dev app/server.py gives you a GUI to call every tool by hand — ideal for demos.

  • Cursor.cursor/mcp.json uses the identical mcpServers shape.

  • The server is transport-agnostic: the same MCPServer can be served over Streamable HTTP later (see Future Improvements).


Example Usage

User: What GitHub issues are currently open?

The agent calls get_open_issues (no repository → issues assigned to you), then summarizes:

You have 2 open issues assigned to you: "Fix login bug" (#1, bug) and "Add CI pipeline" (#2).

User: What assignments are due in the next 7 days?

The agent calls get_upcoming_deadlines with start/end computed from today:

Due this week: Quiz 3 (Math, Aug 12), Project Proposal Draft (ENG101, Aug 11), Graph Traversal Assignment (CS101, Aug 13).

User: Create tasks for those assignments.

The agent calls create_tasks_from_deadlines (the server already honors source/source_id dedup, so re-running never duplicates):

Created 3 tasks. Skipped 0 (no duplicates).

User: Which tasks should I work on first?

The agent calls get_workload_summary and get_overdue_tasks, then reasons over priority + due dates:

First: "Fix flaky test in the CI pipeline" (OVERDUE, high). Then: Project Proposal Draft (due tomorrow), Quiz 3 (due in 2 days)...


API Integration

GitHub

  • Endpoints: GET /issues (assigned to you), GET|POST /repos/{owner}/{repo}/issues, GET|PATCH /repos/{owner}/{repo}/issues/{number}.

  • Auth: Authorization: Bearer <GITHUB_TOKEN>. Anonymous access is allowed for public repos; a 401 then returns a clear "auth required" error.

  • Rate limits: mapped 403-with-x-ratelimit-remaining: 0 and 429 to a rate_limited error.

  • Pull requests: the issues endpoint also returns PRs; they are filtered out via the pull_request key.

  • All network/timeout/error states are translated into domain exceptions (see Security).

LMS

No legitimate/accessible college LMS API was assumed for this project, so the LMS lives behind a tiny interface (LMSService) with a realistic mock implementation (MockLMSService) that:

  • seeds a course catalog with due dates relative to today,

  • validates courses (unknown course → not_found),

  • validates dates and ranges (bad input → invalid_input).

Adding a real provider later = implement the same interface + set LMS_PROVIDER=real. No protected pages were scraped; nothing bypasses authentication. The mock behaves like a real service so the rest of the app is tested without modification.


Database

SQLite file at DATABASE_PATH (default data/tasks.db), one table in MVP:

CREATE TABLE tasks (
    id          INTEGER PRIMARY KEY AUTOINCREMENT,
    title       TEXT    NOT NULL,
    description TEXT,
    status      TEXT    NOT NULL DEFAULT 'pending'
                    CHECK (status IN ('pending','completed')),
    priority    TEXT    NOT NULL DEFAULT 'medium'
                    CHECK (priority IN ('low','medium','high','urgent')),
    due_date    TEXT,                      -- ISO-8601 (date or timestamp)
    source      TEXT,                      -- 'github' | 'lms' | NULL
    source_id   TEXT,                      -- e.g. GitHub issue number
    source_url  TEXT,
    created_at  TEXT NOT NULL,
    updated_at  TEXT NOT NULL
);

CREATE INDEX idx_tasks_status    ON tasks(status);
CREATE INDEX idx_tasks_due_date  ON tasks(due_date);
CREATE INDEX idx_tasks_priority  ON tasks(priority, due_date);

CREATE UNIQUE INDEX uq_tasks_source ON tasks(source, source_id)
    WHERE source IS NOT NULL AND source_id IS NOT NULL;

Why each decision matters:

  • Partial unique index on (source, source_id) — SQLite treats NULLs as distinct in a regular UNIQUE, which would let duplicate imports slip in and forbid multiple "personal" (un-sourced) tasks. The WHERE source IS NOT NULL partial index makes imports idempotent at the database layer, exactly where it belongs. This is what makes create_task_from_issue / create_tasks_from_deadlines safe to call repeatedly.

  • status/priority as TEXT + CHECK — SQLite has no enums; the CHECK provides integrity while Python enum.Enums mirror the values for type safety.

  • ISO-8601 UTC timestamps as sortable strings — lexicographic ordering == chronological ordering, no timezone ambiguity, JSON-friendly.

  • source + source_id + source_url preserve provenance so a task can always be traced back to the issue or assignment it came from.


Testing

pytest          # runs the whole suite: mocked GitHub, mock LMS, SQLite tasks, MCP client

Scope (tests/):

File

Covers

test_github_service.py

Success + auth header, no-token mode, 401, 403 (auth vs. rate-limit), 404, malformed JSON, network failure, timeout, 5xx, PR filtering, create payload, invalid inputs — all via respx.

test_lms_service.py

Deadline listing, date-range + course filters, invalid course, bad dates, out-of-order range, assignment lookup, simulated upstream failure.

test_task_service.py

CRUD, filters, overdue detection (incl. completed-tasks-excluded), duplicate prevention, issue→task, deadlines→tasks, idempotency.

test_mcp_tools.py

In-memory MCP Client(server) — tool registration (all 15), valid & invalid inputs, structured error responses, and cross-service workflows end-to-end.

MCP tools are tested against a real protocol connection using the SDK's in-memory client (async with Client(server)) — the same pattern as FastAPI's TestClient. No subprocess, no port, no credentials.


Security

  • Secrets live only in environment variables (.env is git-ignored; .env.example has placeholders).

  • Least privilege: a fine-grained GitHub PAT limited to Issures Read & Write on specific repos — never full repo scope.

  • No secret logging: a redacting filter scrubs Authorization values from logs; and since the server prints nothing on stdout (logging goes to stderr), the stdio protocol stream stays clean.

  • Input validation: Pydantic at the tool boundary + domain validation in services.

  • Parametrized SQL via SQLAlchemy — no string-built queries.

  • Controlled error exposure: the AI gets structured errors (code, message); raw stack traces go only to server logs.

  • Minimum client exposure: the .env token is read by the server process, not passed through client config.

See also the interview-focused discussion in Interview Talking Points.


Limitations

Honest caveats, on purpose:

  • LMS is mocked. LMS_PROVIDER=mock is the only provider. A real API adapter, exported calendar, or other authorized data source must be added to replace it (interchangeably, via the LMSService interface).

  • SQLite is single-user. No concurrency guarantees, no network access, no backend replication. Deliberate for a personal assistant.

  • No OAuth / no HTTP transport yet. The GitHub token is a static secret; the server runs over stdio. Fine for local personal use; remote/hosted use would need OAuth and Streamable HTTP.

  • Issue creation does not support assigning or body markdown explicitly beyond free-text — kept intentionally small.

  • Single-hour granularity on deadlines — no timezone conversion; dates are compared in user-provided ISO-8601 form.

  • Imports describe mutable source items as snapshots: if a GitHub issue is later edited, an already-created task is not updated (a designed behavior, not a bug).


Future Improvements

  • Real LMSService adapter (official API or .ics calendar export)

  • Google Calendar integration for deadlines

  • Slack/Teams notifications for overdue tasks

  • PostgreSQL backend (repository already abstracts this)

  • OAuth for GitHub + Streamable HTTP transport + Docker deployment

  • Task history/audit table; issue updates re-sync into tasks

  • Richer agent workflows (auto-triage, weekly "standup" report resource)


Project Architecture

Layers, in dependency order:

app/tools       MCP adapters — type-hinted params, docstrings as descriptions, guard() → {ok, data, error}
app/services    GitHubService · LMSService (mock) · TaskService — business logic + cross-service workflows
app/database    Database (engine/session) · TaskRepository (all SQL)
app/models      SQLAlchemy ORM (Task) · Pydantic schemas (TaskCreate/Out, GitHubIssue, Deadline)
app/config.py   validated env config
app/exceptions  domain error hierarchy → AI-readable codes

Dependency injection: app/server.py is the composition root — it builds config → database → services → MCPServer, and registers tool functions with the services they need. Nothing is a global; tests assemble the same graph with fakes.

Error flow: tool → service → repository/API raises a StudentAssistantErrorguard() renders {ok: false, error: {code, message}}. Unexpected exceptions are logged (stderr) and returned as a generic internal_error message.


Demo Scenario

  1. Create a fine-grained GitHub token and set GITHUB_TOKEN in your .env.

  2. Seed the task database: python -m scripts.seed_demo (creates a few tasks, one overdue).

  3. Start the server: python -m app.server (or mcp dev app/server.py to launch the Inspector).

  4. Connect Claude Desktop / Inspector to the server.

  5. Ask: "What do I need to work on this week?" → the agent calls get_workload_summary, combines open GitHub issues + upcoming deadlines + pending/overdue tasks, and gives a prioritized answer.

  6. Ask: "Create tasks for all assignments due this week." → the agent calls create_tasks_from_deadlines.

  7. Verify in the database:

    sqlite3 data/tasks.db "SELECT title, due_date, source FROM tasks ORDER BY due_date;"

    → new rows appear with source = 'lms', one per deadline. Re-run the same question and the tool reports skipped instead of duplicating.


Interview Talking Points

Be ready to defend these decisions:

  1. Why MCP? It's a standardized protocol so one server works with any AI client; tools are discovered (tools/list), called (tools/call), and described to the model — naming and descriptions are a UX contract for LLMs.

  2. Why the current MCP SDK v2? The SDK renamed FastMCPMCPServer and now serves both the 2025 and 2026-07-28 protocol revisions from one process; pip install mcp installs v2. Building on the maintained line (not v1 maintenance) is the defensible choice.

  3. Thin MCP layer / service layer. Tool functions are adapters; logic lives in services behind interfaces. This is what makes GitHub, LMS, and tasks pluggable and testable without a network.

  4. Partial unique index for idempotency. Explain why SQLite needs a partial index for (source, source_id) and how it makes create_task_from_issue/create_tasks_from_deadlines safe as a small, reasoned demo of SQL depth.

  5. GitHub 403 ambiguity. Forbidden vs. rate-limited is disambiguated via the x-ratelimit-remaining response header — a real-world API-integration subtlety, not folklore.

  6. Least-privilege tokens. Fine-grained PAT with only Issues: Read & Write vs. a classic repo-scope token. Know the "why" cold.

  7. Error taxonomy. One exception hierarchy mapped to stable AI-readable codes, with stack traces confined to logs. Reliability is a design goal, not an afterthought.

  8. Testing the protocol layer. In-memory Client(server) means the MCP wiring is tested exactly as a client uses it.

  9. Honest scoping. The LMS is explicitly mocked; SQLite is single-user — "personal productivity tool", not a claim of an enterprise multi-user product.


License

MIT — see LICENSE. Copyright (c) 2026 Mahendra Vattikuti.

-
license - not tested
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

  • Driflyte MCP server which lets AI assistants query topic-specific knowledge from web and GitHub.

  • An MCP server that gives your AI access to the source code and docs of all public github repos

  • A MCP server built for developers enabling Git based project management with project and personal…

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mahendravattikuti/MCP-project-'

If you have feedback or need assistance with the MCP directory API, please join our Discord server