Skip to main content
Glama

๐ŸŽฏ SkillOps MCP

AI-powered operations automation for EdTech teams. Five Model Context Protocol tools that turn hours of repetitive weekly busywork โ€” support triage, re-engagement outreach, feedback analysis, progress reporting, and course design โ€” into a single sentence typed into any MCP client.

Python 3.11+ License: MIT MCP Compatible Powered by Gemini Tests


๐Ÿ“‘ Table of Contents

  1. What is SkillOps MCP?

  2. What is MCP? (60-second primer)

  3. The five tools

  4. Architecture

  5. How a request flows (step by step)

  6. Tech stack

  7. Project structure

  8. Prerequisites

  9. Installation

  10. Getting your free Gemini API key

  11. Configuration

  12. How to use it โ€” three ways

  13. Tool reference (inputs, prompts, outputs)

  14. Error handling

  15. Testing

  16. Engineering highlights

  17. Extending it โ€” add your own tool

  18. Troubleshooting

  19. FAQ

  20. Why I built this

  21. License


Related MCP server: Educhain MCP Server

๐Ÿงญ What is SkillOps MCP?

EdTech operations, growth, and product teams spend hours every week on repetitive, judgment-light work:

  • ๐Ÿ“จ Reading and categorizing every incoming support ticket

  • โœ๏ธ Hand-writing re-engagement emails for students who went quiet

  • ๐Ÿ” Skimming hundreds of feedback comments to find what to fix

  • ๐Ÿ“Š Assembling the weekly cohort progress report

  • ๐Ÿ—‚๏ธ Drafting course outlines from a blank page

It's necessary work, but it scales linearly with headcount and quietly burns people out.

SkillOps MCP turns each of those into a single command. It's a server that exposes five purpose-built tools to any MCP client (Claude Desktop, Claude Code, or others). A support lead pastes a ticket and gets an instant triage with a ready-to-send reply. A growth manager generates a personalized win-back message in seconds. A product manager drops in a batch of feedback and gets a structured, prioritized analysis.

The design principle is "deterministic work in code, language work in the model." Anything that must be correct โ€” cohort averages, at-risk thresholds, CSV parsing, input validation โ€” is computed in plain Python so the numbers are never hallucinated. Only the genuinely language-shaped work (writing, classifying, summarizing) is delegated to the LLM. That LLM is Google's Gemini, running free on gemini-2.5-flash via the Google AI Studio free tier โ€” no credit card required.


๐Ÿ”Œ What is MCP? (60-second primer)

The Model Context Protocol (MCP) is an open standard (created by Anthropic) that lets AI assistants call external tools in a uniform way โ€” think of it as "USB-C for AI tools." Instead of every app inventing its own plugin format, a single MCP server exposes tools that any MCP client can discover and call.

   You โ”€โ”€talkโ”€โ”€โ–ถ  MCP CLIENT  โ”€โ”€MCP protocolโ”€โ”€โ–ถ  MCP SERVER  โ”€โ”€โ–ถ  your code
 (English)      (Claude Desktop,   (JSON-RPC over     (this project)
                 Claude Codeโ€ฆ)       stdio)
  • You type plain English into the client.

  • The client (an AI assistant) decides which tool to call and with what arguments.

  • The server (this project) runs the tool and returns a result.

You never speak the protocol yourself โ€” the client translates your English into a tool call for you. SkillOps MCP is the server half: it provides the five EdTech tools; you bring any MCP client to drive them.


๐Ÿ› ๏ธ The five tools

#

Tool

What it does

Example you'd type

1

triage_support_query

Classifies a support ticket (category + urgency), drafts an empathetic reply, and flags whether a human is needed.

"Triage: 'I paid but can't open the videos!'"

2

generate_reengagement_message

Writes a personalized email + WhatsApp win-back message for an inactive student.

"Re-engage Priya โ€” 12 days inactive, 45% through Web Dev."

3

analyze_course_feedback

Turns a batch of raw feedback into sentiment scores, themes, complaints, praises, and prioritized fixes.

"Analyze these 40 reviews for the Python course."

4

batch_generate_reports

Computes cohort metrics in Python, then has the model write the weekly narrative report.

"Weekly report from students.csv for the Spring cohort."

5

create_course_outline

Produces a full course outline: modules, lessons, durations, projects, assessments.

"Outline an 8-week beginner 'Intro to SQL' course."

Full input/output details for each are in the Tool reference.


๐Ÿ—๏ธ Architecture

SkillOps MCP is built in clean, testable layers. Each layer has one job and is independently verifiable.

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  MCP CLIENT   (Claude Desktop ยท Claude Code ยท any MCP client)     โ”‚
โ”‚  You type plain English here. The client picks the tool + args.   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ”‚  MCP protocol (JSON-RPC over stdio)
                                 โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  SERVER LAYER     src/skillops_mcp/server.py                      โ”‚
โ”‚  โ€ข FastMCP app, name = "SkillOps MCP"                             โ”‚
โ”‚  โ€ข 5 thin @mcp.tool adapters (docstrings become tool descriptions)โ”‚
โ”‚  โ€ข Loads .env, configures stderr logging, then mcp.run()          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                 โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  TOOL LAYER       src/skillops_mcp/tools/*.py                     โ”‚
โ”‚  Each tool: validate input โ†’ build prompt โ†’ call model โ†’ format   โ”‚
โ”‚  โ€ข support ยท outreach ยท feedback ยท reports ยท curriculum           โ”‚
โ”‚  โ€ข reports.py computes all metrics in PURE PYTHON (no LLM math)   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
               โ–ผ                                โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”    โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  MODELS    models/        โ”‚    โ”‚  UTILS    utils/                 โ”‚
โ”‚  schemas.py               โ”‚    โ”‚  gemini_client.py โ€” API wrapper  โ”‚
โ”‚  Pydantic v2 input models โ”‚    โ”‚    (retries, JSON mode, logging) โ”‚
โ”‚  + enums (urgency, etc.)  โ”‚    โ”‚  formatters.py โ€” text rendering  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜    โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                                                 โ”‚  Google Gemini API (free tier)
                                                 โ–ผ
                                          gemini-2.5-flash

Layer responsibilities

Layer

File(s)

Responsibility

Server

server.py

Speaks MCP. Registers the 5 tools, each as a thin adapter whose docstring is shown to the AI as the tool's description. Logs to stderr (never stdout โ€” that would corrupt the stdio transport).

Tools

tools/*.py

The actual work. Each follows the same shape: validate โ†’ prompt โ†’ call โ†’ format. reports.py additionally computes cohort statistics in pure Python.

Models

models/schemas.py

Pydantic v2 models enforce every tool's input contract (required fields, enums, numeric bounds) before any API call. Bad input becomes a friendly Error: โ€ฆ string, never a crash.

Gemini client

utils/gemini_client.py

One place for all LLM calls: exponential-backoff retries on 429/5xx, fails fast on 4xx, Gemini-native JSON mode, strict parsing, and structured logging on every call.

Formatters

utils/formatters.py

Turns structured data into the clean, plain-text reports you see in chat.

Key design choices

  • ๐Ÿงฎ Numbers are computed, not generated. In batch_generate_reports, averages, at-risk lists, top performers, and assignment rates are calculated in Python. The model only writes the narrative around those facts โ€” so a report can never invent a statistic.

  • ๐Ÿ›ก๏ธ Validation before spend. Pydantic rejects bad input before a single token is sent, saving API calls and returning precise error messages.

  • ๐Ÿ—„๏ธ No database. Everything is in-memory; reports read from inline data or a CSV path. Zero infrastructure to run.

  • ๐Ÿ” One client, one retry policy. Every tool calls the same GeminiClient, so resilience and logging are uniform.


๐Ÿ”„ How a request flows (step by step)

Take "Triage this ticket: 'I paid but can't open the videos!'"

  1. You type that into your MCP client (e.g. Claude Code).

  2. The client recognizes it matches the triage_support_query tool and calls the server over stdio with { "query": "I paid but can't open the videos!" }.

  3. server.py receives the call and forwards it to tools/support.py.

  4. support.py validates the input with the SupportQueryInput Pydantic model. (Blank/empty โ†’ instant Error: string, no API call.)

  5. It builds a system + user prompt and calls GeminiClient.call_json(...).

  6. gemini_client.py sends the request to Gemini in JSON mode, retrying on rate limits / server errors, and parses the JSON reply into a dict.

  7. support.py formats that dict into the readable triage report via formatters.py.

  8. The string travels back through the server โ†’ client โ†’ and appears in your chat.

Total time: a couple of seconds. Total cost on the free tier: $0.


๐Ÿงฐ Tech stack

Concern

Choice

Why

Language

Python 3.11+

Modern typing, broad availability

MCP framework

FastMCP

Minimal, decorator-based MCP servers

LLM

Google Gemini (gemini-2.5-flash) via google-genai

Free tier, fast, native JSON output

Validation

Pydantic v2

Declarative input contracts, great errors

Config

python-dotenv

.env-based secrets, never hardcoded

Data

Built-in csv / json

No heavy deps for parsing

Logging

Built-in logging

Structured, stderr-safe

Testing

pytest + pytest-asyncio

Fast, fully mocked, offline


๐Ÿ“ Project structure

skillops-mcp/
โ”œโ”€โ”€ src/
โ”‚   โ””โ”€โ”€ skillops_mcp/
โ”‚       โ”œโ”€โ”€ __init__.py
โ”‚       โ”œโ”€โ”€ server.py              # MCP entry point โ€” registers all 5 tools
โ”‚       โ”œโ”€โ”€ tools/
โ”‚       โ”‚   โ”œโ”€โ”€ support.py         # triage_support_query
โ”‚       โ”‚   โ”œโ”€โ”€ outreach.py        # generate_reengagement_message
โ”‚       โ”‚   โ”œโ”€โ”€ feedback.py        # analyze_course_feedback
โ”‚       โ”‚   โ”œโ”€โ”€ reports.py         # batch_generate_reports (Python metrics + narrative)
โ”‚       โ”‚   โ””โ”€โ”€ curriculum.py      # create_course_outline
โ”‚       โ”œโ”€โ”€ models/
โ”‚       โ”‚   โ””โ”€โ”€ schemas.py         # Pydantic v2 input models + enums
โ”‚       โ””โ”€โ”€ utils/
โ”‚           โ”œโ”€โ”€ gemini_client.py   # Gemini API wrapper: retries, JSON mode, logging
โ”‚           โ””โ”€โ”€ formatters.py      # Plain-text output rendering helpers
โ”œโ”€โ”€ tests/
โ”‚   โ”œโ”€โ”€ conftest.py                # mock_client fixture; API-key isolation
โ”‚   โ”œโ”€โ”€ test_support.py
โ”‚   โ”œโ”€โ”€ test_outreach.py
โ”‚   โ”œโ”€โ”€ test_feedback.py
โ”‚   โ”œโ”€โ”€ test_reports.py
โ”‚   โ””โ”€โ”€ test_curriculum.py
โ”œโ”€โ”€ examples/
โ”‚   โ”œโ”€โ”€ sample_feedback.json       # 10 feedback strings for the feedback tool
โ”‚   โ”œโ”€โ”€ sample_students.csv        # 7 student rows for the reports tool
โ”‚   โ””โ”€โ”€ sample_queries.txt         # 3 support tickets for the triage tool
โ”œโ”€โ”€ demo.py                        # interactive terminal demo (no MCP client needed)
โ”œโ”€โ”€ .mcp.json                      # MCP client config (Claude Code auto-detects it)
โ”œโ”€โ”€ .env.example                   # copy to .env and add your free Gemini key
โ”œโ”€โ”€ .gitignore                     # ignores .env (your secret stays local)
โ”œโ”€โ”€ pyproject.toml                 # package metadata + `skillops-mcp` entry point
โ”œโ”€โ”€ requirements.txt               # runtime dependencies
โ”œโ”€โ”€ requirements-dev.txt           # + pytest
โ””โ”€โ”€ README.md

โœ… Prerequisites

  • Python 3.11 or newer (python --version)

  • pip

  • A free Google Gemini API key (how to get one)

  • (Optional) An MCP client โ€” Claude Code or Claude Desktop โ€” to use the tools conversationally. You can also try everything with the bundled demo.py and no client at all.


๐Ÿ“ฆ Installation

# 1. Clone
git clone https://github.com/<your-username>/skillops-mcp.git
cd skillops-mcp

# 2. (Recommended) create a virtual environment
python -m venv .venv && source .venv/bin/activate      # Windows: .venv\Scripts\activate

# 3. Install the package (editable) โ€” this also installs all dependencies
pip install -e .
#    For development/tests, also: pip install -r requirements-dev.txt

# 4. Configure your free Gemini key
cp .env.example .env
#    then open .env and set GEMINI_API_KEY=...

# 5. Smoke-test it (no API call, fully offline)
pytest

pip install -e . registers the package so it's importable from anywhere and creates a skillops-mcp console command. (You can also pip install -r requirements.txt if you prefer not to install the package itself.)


๐Ÿ”‘ Getting your free Gemini API key

The default engine is Gemini's free tier โ€” no credit card, no UPI, no billing of any kind.

  1. Go to https://aistudio.google.com/apikey

  2. Sign in with any Google account

  3. Click Create API key โ†’ choose "Create API key in a new project" (Google makes the free project for you)

  4. Copy the key (looks like AIzaSy...)

  5. Paste it into your .env:

    GEMINI_API_KEY=AIzaSy...your-key...

Free-tier note: Google AI Studio's free tier has generous per-minute/day rate limits โ€” plenty for personal use and demos โ€” and (on the free tier) Google may use prompts to improve its products. For production traffic, enable paid usage in Google Cloud.


โš™๏ธ Configuration

All configuration is via environment variables (loaded from .env):

Variable

Required

Default

Purpose

GEMINI_API_KEY

โœ… Yes

โ€”

Your free Google AI Studio key

GEMINI_MODEL

No

gemini-2.5-flash

Which Gemini model to use (any free-tier Flash model works)

SKILLOPS_LOG_LEVEL

No

INFO

DEBUG ยท INFO ยท WARNING ยท ERROR

SKILLOPS_MAX_RETRIES

No

3

Retry attempts on rate-limit / server errors

The server loads .env from the project root regardless of the directory it's launched from, so MCP clients can start it from anywhere.


๐Ÿš€ How to use it โ€” three ways

Way 1 โ€” Quick demo in the terminal (no MCP client needed)

The fastest way to see all five tools working:

python demo.py

This opens a friendly menu that calls the same tool functions an MCP client would, and prints the output. Great for a first look or a screen-share. (Requires GEMINI_API_KEY in .env.)

Claude Code auto-detects the committed .mcp.json:

{
  "mcpServers": {
    "skillops": {
      "command": "python",
      "args": ["-m", "skillops_mcp.server"]
    }
  }
}
  1. Make sure you ran pip install -e . (so python -m skillops_mcp.server resolves).

  2. Reload the editor window so Claude Code re-reads .mcp.json.

  3. Type /mcp โ€” you should see skillops with its 5 tools. Approve/trust it if prompted.

  4. Now just chat in plain English:

    "Use the skillops tools to triage this ticket: 'I paid but can't open the videos!'"

Way 3 โ€” Inside Claude Desktop

Add this to your claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json ยท Windows: %APPDATA%\Claude\claude_desktop_config.json):

{
  "mcpServers": {
    "skillops": {
      "command": "python",
      "args": ["-m", "skillops_mcp.server"],
      "env": {
        "GEMINI_API_KEY": "your-free-gemini-key-here"
      }
    }
  }
}

Restart Claude Desktop. The five tools appear and you talk to them in plain English.

WSL note: if your Python lives in WSL but Claude Desktop runs on Windows, set "command": "wsl" and "args": ["python", "-m", "skillops_mcp.server"].


๐Ÿ“š Tool reference

Each tool returns a clean, human-readable string (with a ๐Ÿ“‹ RAW JSON appendix for power users). You can call them by describing what you want โ€” the client maps your words to the right tool and arguments.


1. triage_support_query

Analyze a student support message and return a structured triage.

Parameter

Type

Required

Default

Notes

query

string

โœ…

โ€”

The raw support message

student_name

string

"Student"

For personalizing the reply

course_name

string

null

The course they're enrolled in

You type:

Triage this ticket: "I paid but can't open the videos, it's been 2 days!"

You get back (real output):

โœ… SUPPORT TRIAGE COMPLETE
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
Category: technical_issue
Urgency: high โ€” Student has paid but is fully blocked from content for two days.
Escalate to Human: Yes โ€” Payment + access issues need a human to check backend systems.
Estimated Resolution: 1-2 business days
Tags: access_issue, payment_verification, video_access, content_lock

๐Ÿ“ง SUGGESTED RESPONSE:
"Dear Student, I'm very sorry to hear you're having trouble accessing the course
videos despite having paid, especially after two days. Our team is actively
investigating to get you access as quickly as possible, and we'll reach out
shortly with an update. Thank you for your patience."

Output fields: category (one of technical_issue, billing, course_content, mentor_support, certificate, refund, general), urgency (critical/high/medium/low), urgency_reason, suggested_response, escalate_to_human, escalation_reason, estimated_resolution_time, tags.


2. generate_reengagement_message

Write a personalized win-back message for an inactive student.

Parameter

Type

Required

Default

Notes

student_name

string

โœ…

โ€”

First name

course_name

string

โœ…

โ€”

Course they enrolled in

days_inactive

int

โœ…

โ€”

Days since last activity

last_completed_module

string

null

Last module they finished

completion_percentage

float

null

e.g. 45.5

channel

string

"email"

email ยท whatsapp ยท both

You type:

Generate a re-engagement message for Priya โ€” 12 days inactive in Web Development, last finished "CSS Basics", 45% complete. Channel: both.

You get back (illustrative):

๐Ÿ’ฌ RE-ENGAGEMENT MESSAGE READY
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

๐Ÿ“ง EMAIL
Subject: You're closer than you think, Priya ๐Ÿš€

Hi Priya, you crushed CSS Basics and you're already 45% through Web Development โ€”
real momentum, still right where you left it. The next module is where the fun
starts. It takes ~20 minutes to get back in the flow. Want to pick up where you
stopped?  โ†’ Resume Module 6: JavaScript Foundations

๐Ÿ“ฑ WHATSAPP
Hey Priya! ๐Ÿ‘‹ You're 45% through Web Dev and CSS Basics is behind you. The next
module is a fun one โ€” jump back in? Takes ~20 mins ๐Ÿš€

๐ŸŽฏ PERSONALIZATION HOOKS:
  โ€ข Referenced her 45% progress
  โ€ข Named her last completed module (CSS Basics)
  โ€ข Lowered the barrier with a "20 minutes" framing

โฐ Recommended send time: Tuesday 10am or Thursday 6pm

3. analyze_course_feedback

Analyze a batch of raw feedback in a single model call (not one per item).

Parameter

Type

Required

Default

Notes

feedback_list

list[str]

โœ…

โ€”

1โ€“50 items (extras truncated with a note)

course_name

string

null

For context

analysis_focus

string

"balanced"

balanced ยท complaints_only ยท praises_only ยท actionable_only

You type:

Analyze this feedback for Python Basics: [paste the 10 lines from examples/sample_feedback.json]

You get back (illustrative):

๐Ÿ“Š COURSE FEEDBACK ANALYSIS
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
Items analyzed: 10
Overall sentiment: positive (score: 0.45)
Breakdown: ๐Ÿ‘ 6 | ๐Ÿ˜ 1 | ๐Ÿ‘Ž 3

๐Ÿงต TOP THEMES:
  โ€ข Video length & pacing (ร—3, negative) โ€” "Videos are too longโ€ฆ"
  โ€ข Mentor support (ร—2, positive) โ€” "got a response within hours"

โ— KEY COMPLAINTS:  โ€ข Videos too long  โ€ข Need more practice problems
๐ŸŒŸ KEY PRAISES:     โ€ข Clear instruction  โ€ข Real career outcomes
๐Ÿ› ๏ธ  IMPROVEMENT SUGGESTIONS:
  โ€ข [high / medium] Split long videos into 5โ€“8 min segments
  โ€ข [high / low] Add a solutions bank for practice problems

๐Ÿ“ EXECUTIVE SUMMARY:
Net-positive sentiment driven by instruction and mentor support; clearest win is
shorter videos and more solved practice problems.

4. batch_generate_reports

Generate a weekly cohort report. Metrics are computed in Python; only the narrative comes from the model.

Parameter

Type

Required

Default

Notes

data_source

string

โœ…

โ€”

"inline" or "csv"

students_data

list[dict]

conditionally

null

Required when inline

csv_path

string

conditionally

null

Required when csv

report_week

string

null

e.g. "Jun 16โ€“22, 2026"

cohort_name

string

null

e.g. "Spring Cohort"

CSV columns: name, course, completion_pct, last_active_days_ago, quiz_avg_score, assignments_submitted, total_assignments (missing columns are reported clearly; a sample is in examples/sample_students.csv).

You type:

Generate this week's report from examples/sample_students.csv for the "Spring Cohort", week "Jun 16โ€“22, 2026".

You get back (illustrative):

๐Ÿ“ˆ Spring Cohort โ€” Weekly Progress Report
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
Cohort: Spring Cohort | Week: Jun 16โ€“22, 2026 | Students: 7

๐Ÿ“Š COHORT METRICS
  Average completion:     58.4%      โ† computed in Python
  Average quiz score:     68.9
  Assignment completion:  57.1%
  At-risk students:       3
  Top performers:         2

โœ… RECOMMENDED ACTIONS:
  โ€ข [urgent] Personal outreach to Divya Patel (25 days inactive) โ€” Success Team
  โ€ข [this_week] Nudge sequence for Sneha & Priya โ€” Growth

At-risk = inactive > 7 days or completion < 30%. Top performer = completion > 80% and quiz avg > 75. These thresholds are pure Python โ€” never the model's guess.


5. create_course_outline

Generate a complete, structured course outline.

Parameter

Type

Required

Default

Notes

topic

string

โœ…

โ€”

e.g. "Python for Data Science"

audience_level

string

โœ…

โ€”

absolute_beginner ยท beginner ยท intermediate ยท advanced

duration_weeks

int

8

Total weeks

hours_per_week

float

5.0

Study hours/week

delivery_format

string

"self_paced"

self_paced ยท live_cohort ยท hybrid

include_projects

bool

true

Include hands-on projects

You type:

Outline an 8-week beginner course on "Intro to SQL", 5 hrs/week, self-paced, with projects.

You get back (illustrative):

๐ŸŽ“ Intro to SQL: Query Real Data with Confidence
โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
โฑ๏ธ  Total: ~40.0 hours

๐Ÿ† LEARNING OUTCOMES:
  โ€ข Write SELECT queries with filtering, sorting, and joins
  โ€ข Model a small relational database from scratch
  โ€ข Aggregate and report on real datasets

๐Ÿ“š MODULES:
  Module 1: SQL Foundations  (5.0h)
      1. [video] What is a Database? (15 min)
      2. [exercise] Your First SELECT (40 min)
      โš™๏ธ  Project: Query a movie database
      โœ… Module quiz included
  ...
๐Ÿš€ FINAL PROJECT: Build & query an e-commerce schema end-to-end

๐Ÿ›ก๏ธ Error handling

Every tool returns a clean Error: โ€ฆ string instead of crashing the server. The cases handled:

Situation

What you see

Missing API key

Error: GEMINI_API_KEY not set. Add it to your .env file.

API down after retries

Error: Gemini API unavailable after 3 retries. Check your API key and network.

Non-retryable API error (e.g. 400)

Error: Gemini API error (400): <message> โ€” fails fast, no wasted retries

Un-parseable model output

Error: Could not parse Gemini's response as JSON. Raw response: โ€ฆ

Invalid input (empty feedback, bad enum, etc.)

Error: <specific validation message>

CSV file not found

Error: CSV file not found at path: <path>

CSV missing columns

Error: CSV missing required columns: <list>

Validation runs before any API call, so bad input fails instantly and for free.


๐Ÿงช Testing

The suite is fully offline โ€” every Gemini call is mocked, so no API key and no network are needed, and it costs nothing.

pip install -r requirements-dev.txt
pytest                 # 22 tests
pytest -v              # verbose
pytest tests/test_reports.py   # one file

Each tool is tested for: a valid call (mocked model response), invalid/empty input, and the missing-API-key path. reports.py additionally has tests proving the Python-computed metrics are correct and that CSV errors are handled.

tests/test_curriculum.py .....   tests/test_reports.py  ......
tests/test_feedback.py    ....   tests/test_support.py  ...
tests/test_outreach.py    ....   ===== 22 passed =====

๐Ÿ’Ž Engineering highlights

For reviewers, the parts worth a look:

  • Deterministic-vs-generative split. tools/reports.py computes every statistic in Python and hands the model only the facts โ€” a report can't hallucinate a number. This is the project's core design idea.

  • Resilient API client. utils/gemini_client.py retries only what's worth retrying (429 + 5xx) with exponential backoff, fails fast on 4xx, uses Gemini's native JSON mode, and logs every call structurally.

  • Validation as a first-class layer. models/schemas.py (Pydantic v2) enforces every contract before spend; errors are turned into friendly strings, never stack traces.

  • Provider-swappable by design. The entire LLM dependency lives behind one small client class โ€” the project started on Anthropic Claude and moved to free Gemini by changing one file.

  • Stdio-safe logging. Logs go to stderr so they never corrupt the MCP stdout transport โ€” a subtle but real correctness requirement for MCP servers.

  • Tested, typed, documented. Type hints and docstrings on every function; 22 offline tests; no bare except; no print; no hardcoded secrets.


๐Ÿงฉ Extending it โ€” add your own tool

Adding a sixth tool takes three steps:

  1. Define the input model in models/schemas.py:

    class MyToolInput(BaseModel):
        text: str = Field(..., min_length=1)
  2. Write the tool in tools/mytool.py following the standard shape:

    def run(text: str, client: GeminiClient | None = None) -> str:
        try:
            params = MyToolInput(text=text)
        except ValidationError as exc:
            return f"Error: {fmt.validation_message(exc)}"
        try:
            client = client or GeminiClient()
        except MissingAPIKeyError as exc:
            return f"Error: {exc}"
        data = client.call_json(SYSTEM_PROMPT, user_prompt, tool_name="my_tool")
        return _format_output(data)
  3. Register it in server.py:

    @mcp.tool
    def my_tool(text: str) -> str:
        """One-line description the AI will read to decide when to call this."""
        return mytool.run(text=text)

Add a tests/test_mytool.py mirroring the existing tests and you're done.


๐Ÿ”ง Troubleshooting

Symptom

Fix

Error: GEMINI_API_KEY not set

Add the key to .env, or to the env block of your MCP client config.

/mcp doesn't list skillops

Run pip install -e ., then reload your editor. Or add it explicitly: claude mcp add skillops python -m skillops_mcp.server.

No module named skillops_mcp

You skipped pip install -e . (or you're in a different Python env / venv than the one the client launches).

Gemini 429 errors

Free-tier rate limit โ€” wait a moment and retry; the client already backs off automatically.

Server "hangs" when run directly

That's correct โ€” python -m skillops_mcp.server waits silently for an MCP client over stdio. Use demo.py to interact directly.

Claude Desktop on Windows can't find Python in WSL

Use "command": "wsl", "args": ["python", "-m", "skillops_mcp.server"].


โ“ FAQ

Does this cost anything? No. It runs on Gemini's free tier โ€” no credit card, no UPI. The test suite is free too (fully mocked).

Do I need Claude or Anthropic? No. SkillOps MCP is the server. Any MCP client can drive it โ€” Claude Code, Claude Desktop, or others. The LLM doing the work inside is Gemini.

Why MCP instead of a REST API or a CLI? Because the value is being inside the tool the team already uses. With MCP, a support lead triages a ticket without leaving their AI chat โ€” no new app, no copy-pasting into a separate service.

Can I use a different model? Yes โ€” set GEMINI_MODEL in .env to any free-tier Gemini model. Swapping providers entirely is a one-file change in utils/gemini_client.py.

Is my .env safe to commit? No โ€” and it's already in .gitignore. Your key stays on your machine.


๐Ÿ’ก Why I built this

The highest-leverage AI automation isn't flashy โ€” it's the quiet, repetitive operational work that consumes an EdTech team's week. Triaging tickets, chasing inactive learners, reading feedback, and assembling reports are tasks where human judgment matters at the edges but the bulk is mechanical. By packaging that work as MCP tools, it lives directly inside the assistant the team already uses, the deterministic parts stay deterministic, and the model only does the writing. The result turns "an afternoon of busywork" into "a single sentence" โ€” backed by a clean, tested, provider-agnostic codebase that's easy to extend with the next workflow.


๐Ÿ“„ License

Released under the MIT License. See LICENSE (or the badge above) for details.

Install Server
A
license - permissive license
A
quality
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.

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/Ultr0nX/skillops-mcp-server'

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