stepik-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@stepik-mcpCreate a new private course titled 'Python for Beginners' with a first lesson on variables."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
stepik-mcp
An MCP server that lets an AI assistant author courses on Stepik: browse the catalogue, read a course's structure, and create or edit courses, modules, lessons and steps through the Stepik REST API.
It cannot publish. Courses it creates stay private drafts and no tool can make one public — that stays a human decision in the Stepik web interface. See Safety below.
Requirements
Python 3.10+
Stepik OAuth application credentials (free)
Getting credentials
Go to https://stepik.org/oauth2/applications/ and register a new application.
Set Client type to
Confidentialand Authorization grant type toClient credentials.Copy the Client id and Client secret.
The token issued by this grant belongs to the account that owns the application, so everything
this server creates is owned by that account. Run stepik_whoami to confirm which one it is.
Install
With uv (no manual install needed — uvx fetches on demand):
uvx --from git+https://github.com/prog420/stepik-mcp stepik-mcpOr from a clone:
git clone https://github.com/prog420/stepik-mcp
cd stepik-mcp
uv sync --extra dev
uv run stepik-mcpConfiguration
All configuration is via environment variables.
Variable | Default | Meaning |
| — | Required. OAuth application client id. |
| — | Required. OAuth application client secret. |
|
| Set to |
|
| Set to |
|
| Override for a self-hosted instance. |
|
| HTTP timeout in seconds. |
|
| Page cap when following paginated listings. |
A .env file in the working directory is loaded automatically; copy .env.example to start.
Claude Code
claude mcp add stepik \
--env STEPIK_CLIENT_ID=your-id \
--env STEPIK_CLIENT_SECRET=your-secret \
-- uvx --from git+https://github.com/prog420/stepik-mcp stepik-mcpClaude Desktop / Cursor
In claude_desktop_config.json or .cursor/mcp.json:
{
"mcpServers": {
"stepik": {
"command": "uvx",
"args": ["--from", "git+https://github.com/prog420/stepik-mcp", "stepik-mcp"],
"env": {
"STEPIK_CLIENT_ID": "your-id",
"STEPIK_CLIENT_SECRET": "your-secret"
}
}
}
}Remote / containerised
stepik-mcp --transport http --host 0.0.0.0 --port 8000
# -> streamable HTTP at http://<host>:8000/mcpThe HTTP transport has no authentication of its own. Do not expose it to a network you do not control — anyone who can reach it can act as your Stepik account.
Content model
Stepik's hierarchy is worth knowing, because one part of it is not obvious:
course
└── section (a module)
└── unit (a placement, not content)
└── lesson (exists independently of any course!)
└── step (theory or a quiz)A lesson is a standalone object, not a child of a course. Placing one into a course means
creating a unit that points at a section and a lesson. stepik_add_lesson_to_course does the
lesson + unit + steps sequence in a single call, which is the normal way to add content.
Steps are edited through step-sources (the authoring object), not steps (the read-only
learner view).
Tools
Reading
Tool | Purpose |
| Which Stepik account the server acts as. |
| Credentials, API reachability, and which safety switches are on. |
| Free-text search of the public catalogue. |
| List courses; with no arguments, the ones you own. |
| One course's metadata. |
| The whole tree — sections, units, lessons, steps, with every id. |
| One lesson and its step ids. |
| Steps of a lesson with short previews. |
| A step's full editable content, including quiz options and answers. |
Authoring
Tool | Purpose |
| Create a course. Always a private draft. |
| Edit title, summary, description, workload, audience, requirements. |
| Manage modules. |
| Manage standalone lessons. |
| Place and reorder lessons within a course. |
| Manage step content of any type. |
| Composite: lesson + unit + steps in one call. |
| Deletion; each requires |
Positions are optional everywhere — omit position and the new object is appended to the end.
Step types
stepik_create_step covers every type through one block_type argument:
| Extra arguments |
| none — a theory/reading step |
|
|
|
|
|
|
|
|
|
|
|
|
| none — reviewed manually |
|
|
Invalid combinations are rejected before the request is sent, with a message that says what is missing rather than a bare HTTP 400.
Resources
stepik://me— the authenticated accountstepik://course/{course_id}— a markdown outline of a course
Safety
The point of this server is that an assistant can build a course without being able to ship it.
Publishing is blocked in the client, not in the tools. Removing a publish tool alone would
be theatre: an agent could still call update_course(is_enabled=true). Instead, every write
passes through one chokepoint in client.py that strips or rejects
fields which would widen visibility (is_enabled, is_public, is_featured). Consequences:
Created courses are forced to
is_enabled: false.Created lessons are forced to
is_public: false.An update that would publish raises an error and no request reaches Stepik.
Editing a course that is already published still works — only widening visibility is blocked, and unpublishing is always allowed.
STEPIK_ALLOW_PUBLISH=1lifts the block. It is an operator decision made when starting the server, not something a tool call can reach.
This is covered by tests/test_publish_guard.py; if those tests
fail, the guarantee is gone.
Deletion is gated twice: STEPIK_ALLOW_DELETE must be on (it is by default) and each delete
call must pass confirm=true. Delete tools are marked with the MCP destructiveHint annotation
so clients can prompt. Deleting a lesson or step also destroys learner submissions, and Stepik has
no undo.
Development
uv sync --extra dev
uv run pytest # 86 tests, no network access
uv run ruff check .
uv run ruff format .Tests mock the HTTP layer with respx, so the suite never touches stepik.org and needs no credentials.
To inspect the server interactively:
npx @modelcontextprotocol/inspector uv run stepik-mcpNotes on the Stepik API
Things that surprised us, recorded so the next person does not have to rediscover them:
Every GET returns a list, even for a single id:
/api/courses/1yields{"courses": [...]}. A missing object comes back as an empty list with HTTP 200, not a 404.The schema is flat — there are no nested endpoints like
/courses/1/sections. Use/sections?course=1or the?ids[]=batch form, which every endpoint supports./api/stepics/1("who am I") is a trap. The1means "me", but thestepicsobject it returns also hasid: 1, so trusting that id resolves to user #1 — the site's very first account — for everyone. The real profile is the siblingusersarray of the same response.Request bodies are wrapped in a singular envelope:
{"course": {...}}. Step sources are the exception and use camelCase{"stepSource": {...}}; this client sends that and retries withstep-sourceif Stepik rejects it.PUTreplaces the whole object, so all updates here are read-modify-write. Sending only the changed field would blank out everything else.
License
MIT — see LICENSE.
This server cannot be installed
Maintenance
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
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/prog420/stepik-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server