Skip to main content
Glama
README.md
# Thinkific MCP Server

A production-quality [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server for the [Thinkific](https://www.thinkific.com/) REST Admin API and GraphQL API. Lets AI assistants (Claude, GPT, etc.) interact with your Thinkific site directly — manage courses, students, enrollments, orders, coupons, communities, and more.

## Features

- **108 MCP tools** covering the full Thinkific API surface — 77 REST tools and 31 GraphQL tools
- **Full REST coverage** — courses, users, enrollments, orders, products, bundles, coupons, groups, instructors, reviews, promotions, categories, site scripts, external orders, publish requests, and more
- **GraphQL support** — queries and mutations for communities, posts, lessons, assignments, and advanced data access via `https://api.thinkific.com/stable/graphql`
- **3 MCP resources** for quick site overview data
- **Dual authentication** — API Key or OAuth Bearer token
- **Pagination** on every list endpoint (page + limit params)
- **Rate-limit awareness** — automatic retry with exponential back-off on 429 responses
- **Structured error handling** — human-readable errors, never crashes the server
- **TypeScript** — fully typed, strict mode, JSDoc throughout

## Quick Start

### 1. Install

```bash
# Clone or copy the project
cd ~/Documents/thinkific-mcp

# Install dependencies
npm install

# Build
npm run build
```

### 2. Configure Authentication

You need **one** of the two auth methods:

#### Option A: API Key (single site)

Find your API key in your Thinkific admin: **Settings → Code & Analytics → API**.

```bash
export THINKIFIC_API_KEY="your-api-key"
export THINKIFIC_SUBDOMAIN="your-site-subdomain"
```

#### Option B: OAuth Token (multi-site apps)

```bash
export THINKIFIC_OAUTH_TOKEN="your-oauth-bearer-token"
```

### 3. Run

```bash
# Direct
node dist/index.js

# Or via npm
npm start
```

## Usage with Claude Desktop

Add to your Claude Desktop MCP config (`~/Library/Application Support/Claude/claude_desktop_config.json`):

```json
{
  "mcpServers": {
    "thinkific": {
      "command": "node",
      "args": ["/path/to/thinkific-mcp/dist/index.js"],
      "env": {
        "THINKIFIC_API_KEY": "your-api-key",
        "THINKIFIC_SUBDOMAIN": "your-subdomain"
      }
    }
  }
}
```

## Usage with OpenClaw / mcporter

```bash
# Register the server
mcporter add thinkific -- node /path/to/thinkific-mcp/dist/index.js

# Set env vars
mcporter env thinkific THINKIFIC_API_KEY=your-api-key
mcporter env thinkific THINKIFIC_SUBDOMAIN=your-subdomain

# Verify tools are visible
mcporter tools thinkific
```

## REST Tool Reference

### Users

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_users` | List all users/students | `page`, `limit` |
| `get_user` | Get user details by ID | `user_id` |
| `create_user` | Create a new user | `first_name`, `last_name`, `email`, `password?`, `roles?`, `company?`, `send_welcome_email?` |
| `search_users` | Search users by email/name | `query`, `page`, `limit` |
| `update_user` | Update user details | `user_id`, fields to update |
| `delete_user` | Delete a user | `user_id` |

### Enrollments

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_enrollments` | List enrollments (filterable) | `page`, `limit`, `query_user_id?`, `query_course_id?`, `query_email?` |
| `create_enrollment` | Enroll a user in a course | `course_id`, `user_id`, `activated_at?`, `expiry_date?` |
| `get_enrollment` | Get enrollment details by ID | `enrollment_id` |
| `update_enrollment` | Update an enrollment | `enrollment_id`, fields to update |

### Courses

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_courses` | List all courses with pagination | `page`, `limit` |
| `get_course` | Get a single course by ID | `course_id` |

### Chapters

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_chapters` | List chapters in a course | `course_id`, `page`, `limit` |
| `get_chapter` | Get chapter details by ID | `chapter_id` |

### Contents

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_contents` | List lessons in a chapter | `chapter_id`, `page`, `limit` |
| `get_content` | Get content/lesson details by ID | `content_id` |

### Orders

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_orders` | List orders (filterable) | `page`, `limit`, `query_user_id?`, `query_email?` |
| `get_order` | Get order details by ID | `order_id` |

### Products

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_products` | List all products | `page`, `limit` |
| `get_product` | Get product details by ID | `product_id` |
| `list_related_products` | List related products | `product_id`, `page`, `limit` |

### Bundles

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_bundles` | List course bundles | `page`, `limit` |
| `get_bundle` | Get bundle details by ID | `bundle_id` |
| `list_bundle_courses` | List courses in a bundle | `bundle_id`, `page`, `limit` |
| `list_bundle_enrollments` | List bundle enrollments | `bundle_id`, `page`, `limit` |
| `create_bundle_enrollment` | Enroll a user in a bundle | `bundle_id`, `user_id` |
| `update_bundle_enrollment` | Update a bundle enrollment | `bundle_id`, `enrollment_id`, fields to update |

### Groups

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_groups` | List all groups | `page`, `limit` |
| `get_group` | Get group details by ID | `group_id` |
| `create_group` | Create a new group | `name` |
| `delete_group` | Delete a group | `group_id` |

### Group Analysts

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_group_analysts` | List analysts for a group | `group_id`, `page`, `limit` |
| `add_group_analyst` | Add an analyst to a group | `group_id`, `user_id` |
| `remove_group_analyst` | Remove an analyst from a group | `group_id`, `user_id` |

### Group Users

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `add_user_to_group` | Add a user to a group | `group_id`, `user_id` |

### Coupons

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_coupons` | List all coupons | `page`, `limit` |
| `create_coupon` | Create a discount code | `code`, `discount_type`, `discount_amount`, `note?`, `quantity?`, `product_ids?`, `expires_at?` |
| `get_coupon` | Get coupon details by ID | `coupon_id` |
| `update_coupon` | Update a coupon | `coupon_id`, fields to update |
| `delete_coupon` | Delete a coupon | `coupon_id` |
| `bulk_create_coupons` | Bulk create coupons | `count`, coupon params |

### Promotions

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_promotions` | List promotions | `page`, `limit` |
| `create_promotion` | Create a promotion | `name`, `discount_type`, `discount_amount`, promotion params |
| `get_promotion` | Get promotion details by ID | `promotion_id` |
| `update_promotion` | Update a promotion | `promotion_id`, fields to update |
| `delete_promotion` | Delete a promotion | `promotion_id` |
| `get_promotion_by_coupon` | Get promotion for a coupon code | `coupon_code` |

### Categories

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_categories` | List categories | `page`, `limit` |
| `create_category` | Create a new category | `name` |
| `get_category` | Get category details by ID | `category_id` |
| `update_category` | Update a category | `category_id`, fields to update |
| `delete_category` | Delete a category | `category_id` |
| `list_category_products` | List products in a category | `category_id`, `page`, `limit` |
| `add_products_to_category` | Add products to a category | `category_id`, `product_ids` |
| `remove_products_from_category` | Remove products from a category | `category_id`, `product_ids` |

### Course Reviews

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_course_reviews` | List reviews (filterable) | `course_id?`, `page`, `limit` |
| `create_course_review` | Create a course review | `course_id`, `user_id`, `rating`, `title?`, `review?` |
| `get_course_review` | Get review details by ID | `review_id` |

### Instructors

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_instructors` | List instructors | `page`, `limit` |
| `create_instructor` | Create an instructor profile | `user_id`, instructor fields |
| `get_instructor` | Get instructor details by ID | `instructor_id` |
| `update_instructor` | Update an instructor profile | `instructor_id`, fields to update |
| `delete_instructor` | Delete an instructor profile | `instructor_id` |

### Custom Profile Fields

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_custom_profile_fields` | List all custom profile fields | _(none)_ |

### External Orders

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `create_external_order` | Create an external order | `user_id`, `product_id`, order params |
| `refund_external_order` | Refund an external order | `order_id` |
| `purchase_external_order` | Process an external order purchase | `order_id` |

### Product Publish Requests

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_publish_requests` | List product publish requests | `page`, `limit` |
| `get_publish_request` | Get a publish request by ID | `request_id` |
| `approve_publish_request` | Approve a publish request | `request_id` |
| `deny_publish_request` | Deny a publish request | `request_id` |

### Site Scripts

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `list_site_scripts` | List all site scripts | `page`, `limit` |
| `create_site_script` | Create a site script | `name`, `src`, `load_method?`, `location?` |
| `get_site_script` | Get site script details by ID | `script_id` |
| `update_site_script` | Update a site script | `script_id`, fields to update |
| `delete_site_script` | Delete a site script | `script_id` |

### Site

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `get_site_info` | Site overview (counts and settings) | _(none)_ |

## GraphQL Tool Reference

GraphQL tools use the Thinkific GraphQL endpoint: `https://api.thinkific.com/stable/graphql`

### Queries

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `gql_site` | Fetch site details via GraphQL | _(none)_ |
| `gql_me` | Get current authenticated user | _(none)_ |
| `gql_course` | Get course details by ID | `id` |
| `gql_course_by_slug` | Get course details by slug | `slug` |
| `gql_user` | Get user details by ID | `id` |
| `gql_user_by_email` | Get user details by email | `email` |
| `gql_bundle` | Get bundle details by ID | `id` |
| `gql_category` | Get category details by ID | `id` |
| `gql_chapter` | Get chapter details by ID | `id` |
| `gql_lesson` | Get lesson details by ID | `id` |
| `gql_group` | Get group details by ID | `id` |
| `gql_product` | Get product details by ID | `id` |
| `gql_community` | Get community details by ID | `id` |
| `gql_community_user` | Get community user details | `community_id`, `user_id` |
| `gql_post` | Get a community post by ID | `id` |
| `gql_space` | Get a community space by ID | `id` |

### Mutations

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `gql_create_post` | Create a community post | `space_id`, `content`, `title?` |
| `gql_reply_to_post` | Reply to a community post | `post_id`, `content` |
| `gql_update_post` | Update a community post | `post_id`, `content?`, `title?` |
| `gql_follow_post` | Follow a community post | `post_id` |
| `gql_unfollow_post` | Unfollow a community post | `post_id` |
| `gql_pin_post` | Pin a community post | `post_id` |
| `gql_unpin_post` | Unpin a community post | `post_id` |
| `gql_move_post` | Move a post to another space | `post_id`, `space_id` |
| `gql_react_to_post` | React to a community post | `post_id`, `reaction` |
| `gql_bulk_add_users_to_groups` | Bulk add users to groups | `user_ids`, `group_ids` |
| `gql_bulk_remove_users_from_groups` | Bulk remove users from groups | `user_ids`, `group_ids` |
| `gql_mark_lesson_incomplete` | Mark a lesson as incomplete for a user | `lesson_id`, `user_id` |
| `gql_view_lesson` | Mark a lesson as viewed/complete for a user | `lesson_id`, `user_id` |
| `gql_update_assignment_submission` | Update an assignment submission | `submission_id`, fields to update |
| `gql_update_product` | Update a product via GraphQL | `id`, fields to update |

## Resources

| Resource URI | Description |
|-------------|-------------|
| `thinkific://courses` | JSON listing of all courses (first 100) |
| `thinkific://users` | JSON listing of all users (first 100) |
| `thinkific://site` | JSON overview with total counts |

## Environment Variables

| Variable | Required | Description |
|----------|----------|-------------|
| `THINKIFIC_API_KEY` | Yes (API Key auth) | Your Thinkific API key from Settings → Code & Analytics → API |
| `THINKIFIC_SUBDOMAIN` | Yes (API Key auth) | Your Thinkific site subdomain (e.g. `my-school` from `my-school.thinkific.com`) |
| `THINKIFIC_OAUTH_TOKEN` | Yes (OAuth auth) | OAuth2 Bearer token (alternative to API Key auth) |

> **Note:** If `THINKIFIC_OAUTH_TOKEN` is set, it takes precedence over API Key auth.

## Project Structure

```
thinkific-mcp/
├── src/
│   ├── index.ts       # Entry point — server bootstrap
│   ├── client.ts      # Thinkific API client (auth, pagination, retry)
│   ├── tools.ts       # MCP tool definitions and handlers (REST)
│   ├── gql-tools.ts   # MCP tool definitions and handlers (GraphQL)
│   ├── resources.ts   # MCP resource definitions
│   ├── types.ts       # TypeScript interfaces for API responses
│   └── test.ts        # Validation test script
├── dist/              # Compiled JavaScript (after build)
├── package.json
├── tsconfig.json
├── README.md
├── LICENSE
└── .gitignore
```

## Development

```bash
# Build
npm run build

# Watch mode
npm run dev

# Type-check only
npm run lint

# Run tests (after build)
npm test
```

## Troubleshooting

### "Thinkific authentication not configured"

Set the required environment variables. You need either:
- `THINKIFIC_API_KEY` **and** `THINKIFIC_SUBDOMAIN`, or
- `THINKIFIC_OAUTH_TOKEN`

### 401 Authentication Error

- Verify your API key hasn't been rotated (keys are shown only once after reset)
- Confirm your Thinkific plan supports API access (Grow/Pro + Growth or above)
- Check the subdomain matches exactly (e.g. `my-school`, not `my-school.thinkific.com`)

### 429 Rate Limit

The server automatically retries with exponential back-off (up to 3 retries). If you're consistently hitting rate limits, reduce request frequency or add pagination with smaller page sizes.

### Empty Results

- Check that you're connecting to the correct site (verify subdomain)
- Some endpoints require data to exist first (e.g. no enrollments without courses and users)

### Server Won't Start

- Ensure Node.js 18+ is installed: `node --version`
- Run `npm run build` first — the server runs from `dist/`
- Check stderr for error messages (stdout is reserved for MCP protocol)

## API Documentation

- [Thinkific REST API Reference](https://developers.thinkific.com/api/api-documentation)
- [Thinkific GraphQL API](https://api.thinkific.com/stable/graphql)
- [API Key Authorization](https://support.thinkific.dev/hc/en-us/articles/4422657425431)
- [OAuth Authorization](https://support.thinkific.dev/hc/en-us/articles/4422658129175)
- [Rate Limits](https://support.thinkific.dev/hc/en-us/articles/4422684774935)

## License

MIT — see [LICENSE](./LICENSE).

TDQS

C2.7/5.0

Scored across 109 tools

Disambiguation2/5

Many tools overlap: gql_* tools duplicate REST equivalents (get_product vs gql_product, get_bundle vs gql_bundle), and there are multiple membership tools (add_user_to_group, create_enrollment, create_bundle_enrollment) whose boundaries are unclear. Promotion/coupon creation is also easy to confuse.

Naming Consistency3/5

Most REST tools follow a consistent verb_noun pattern (create_, list_, get_, update_, delete_). However, the 20 GraphQL tools use a separate gql_ prefix with varying verbs (gql_community, gql_create_post, gql_bulk_add_users_to_groups), creating two naming conventions. Within each group, naming is fairly predictable.

Tool Count2/5

109 tools is excessive and will overwhelm agents. While the domain is broad, many tools are redundant (gql_* duplicates REST endpoints) and could be consolidated or removed. The sheer count makes selection and discovery difficult.

Completeness3/5

The surface covers CRUD for many entities (users, categories, coupons, groups, instructors) and community operations via GraphQL. However, core educational workflows are incomplete: there are no create/update/delete operations for courses, chapters, contents, or bundles, and no review moderation tools. This is a notable gap given the platform's purpose.

Maintenance

ActivityInactive
ResponsivenessNo issues