npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@thoughtindustries/thoughtindustries-mcp

v0.3.0

Published

MCP server for the [Thought Industries](https://www.thoughtindustries.com/) Enterprise Learning Platform.

Readme

Thought Industries MCP Server

MCP server for the Thought Industries Enterprise Learning Platform.

Covers both APIs101 tools total:

  • REST (Incoming API v2) — 80 curated tools + search_actions / execute_action for all 135 endpoints
  • GraphQL (Helium) — 19 tools: auth (Login/Logout), schema discovery, catalog query, learner profile, and all documented Learner + Assessment mutations

Credential models

This server supports two ways to supply credentials, selected by MCP_TRANSPORT:

  • stdio (default) — single-tenant. Credentials are read once at startup from env vars. Use this for local npx / docker run -i with Claude Desktop or Cursor.
  • http — multi-tenant. Run one shared server (e.g. on Google Cloud Run) with no TI credentials on the server. Each user passes their own credentials as HTTP headers on every request, so one deployment serves many users across different TI instances. See Multi-tenant HTTP deployment.

Env vars (stdio / single-tenant)

| Env var | Required | Description | |---------|----------|-------------| | TI_BASE_URL | ✅ | Your TI instance, e.g. https://acme.thoughtindustries.com (no trailing slash) | | TI_API_KEY | ✅ | REST Bearer token and default Helium apiKey — from Settings › Security | | TI_HELIUM_API_KEY | optional | Separate Helium apiKey if different from TI_API_KEY | | TI_HELIUM_USER_TOKEN | optional | User "Auth Token" from the Login mutation for user-scoped GraphQL ops |

Request headers (http / multi-tenant)

In http mode the server reads no TI_* env vars — credentials arrive per request:

| Header | Maps to | Required | |--------|---------|----------| | X-TI-Base-URL | TI_BASE_URL | ✅ | | X-TI-Api-Key | TI_API_KEY | ✅ | | X-TI-Helium-Api-Key | TI_HELIUM_API_KEY | optional (defaults to X-TI-Api-Key) | | X-TI-Helium-User-Token | TI_HELIUM_USER_TOKEN | optional |

A POST /mcp request missing X-TI-Base-URL or X-TI-Api-Key is rejected with 401.

Curated tools

Connectivity

| Tool | Endpoint | Description | |------|----------|-------------| | ping | GET /incoming/v2/ping | Test authentication and connectivity |

Users

| Tool | Endpoint | Description | |------|----------|-------------| | list_users | GET /incoming/v2/users | List all learners/admins (filter by email, clientId) | | get_user | GET /incoming/v2/users/{id} | Get a user's full profile and enrollment details | | create_user | POST /incoming/v2/users | Create a new user | | update_user | PUT /incoming/v2/users/{id} | Update a user's profile fields | | delete_user | DELETE /incoming/v2/users/{id} | Permanently delete a user and all their data | | update_user_status | PUT /incoming/v2/users/{id}/updateStatus | Enable or disable a user account | | bulk_import_users | POST /incoming/v2/users/bulkImport | Import users in bulk from a CSV URL (returns job ID) | | bulk_assign_content | POST /incoming/v2/users/bulkContentAssignment | Enroll multiple users in a course at once | | bulk_remove_content_access | POST /incoming/v2/users/bulkContentRemoveAccess | Remove course/path access for multiple users | | reset_user_progress | POST /incoming/v2/users/{id}/resetProgress | Reset all progress for a user on a specific course | | certify_user | POST /incoming/v2/users/{id}/certify | Grant a certificate to a user for a course or path |

Content & Courses

| Tool | Endpoint | Description | |------|----------|-------------| | list_content | GET /incoming/v2/content | Browse the full content catalog | | create_course | POST /incoming/v2/content/course/create | Create a new course (returns job ID) | | update_course | PUT /incoming/v2/content/course/update | Update an existing course's metadata | | list_course_groups | GET /incoming/v2/courseGroups | List all course groups (catalog items) | | get_course_group | GET /incoming/v2/courseGroups/{id} | Get a course group by UUID | | get_course_group_by_slug | GET /incoming/v2/courseGroups/slug/{slug} | Get a course group by URL slug | | list_course_group_courses | GET /incoming/v2/courseGroups/{id}/courses | List all courses/sessions within a course group | | get_course_structure | GET /incoming/v2/courses/{courseId}/structure | Get sections → lessons → topics tree |

Assessments & Assignments

| Tool | Endpoint | Description | |------|----------|-------------| | list_assessment_attempts | GET /incoming/v2/assessmentAttempts | List quiz/assessment attempts | | update_assessment_grade | PUT /incoming/v2/assessmentAttempts/{id}/updateGrade | Manually override the grade for an assessment attempt | | list_assignment_submissions | GET /incoming/v2/assignmentSubmissions | List all learner assignment submissions |

Redemption Codes & Coupons

| Tool | Endpoint | Description | |------|----------|-------------| | list_redemption_codes | GET /incoming/v2/redemptionCodes | List all redemption code groups | | create_redemption_code | POST /incoming/v2/redemptionCodes | Create a redemption code group granting content access | | get_redemption_code | GET /incoming/v2/redemptionCodes/{id} | Get a redemption code group by UUID | | list_coupons | GET /incoming/v2/coupons | List all coupons |

Ecommerce

| Tool | Endpoint | Description | |------|----------|-------------| | list_non_recurring_purchases | GET /incoming/v2/ecommerce/nonRecurringPurchases | List one-time purchases made on the platform |

Meetings

| Tool | Endpoint | Description | |------|----------|-------------| | list_meetings | GET /incoming/v2/meetings | List scheduled meetings (webinar/in-person event sessions) |

Clients (Panorama)

| Tool | Endpoint | Description | |------|----------|-------------| | list_clients | GET /incoming/v2/clients | List client organizations (Panorama accounts) | | get_client | GET /incoming/v2/clients/{id} | Get a client organization by UUID | | create_client | POST /incoming/v2/clients | Create a new client/organization | | list_client_licenses | GET /incoming/v2/clients/{id}/licenses | List all licenses assigned to a client | | create_license | POST /incoming/v2/licenses | Create a new license for a client organization | | get_license | GET /incoming/v2/licenses/{id} | Get a license by UUID |

Discovery

| Tool | Endpoint | Description | |------|----------|-------------| | list_tags | GET /incoming/v2/tags (via search) | List all tags defined in the platform | | get_events_course_action | GET /incoming/v2/events/courseAction | Get enrollment/completion/certificate events | | get_job | GET /incoming/v2/jobs/{id} | Poll async job status (bulk import, course create, etc.) |

All remaining REST endpoints — additional events, logs, licenses, credits, locations, XLF exports, learning path milestones, and more — are accessible via search_actions + execute_action.

GraphQL tools (Helium API)

Authentication flow

gql_login(email, password) → auth_token string
  └─ pass as user_token to all gql_* learner tools

TI uses a non-standard Auth Token header (with a space) for user auth. The server handles this transparently — just pass the token string from gql_login.

apiKey (admin/schema operations) is sent as ?apiKey=… — uses TI_HELIUM_API_KEY, defaulting to TI_API_KEY.

Auth tools

| Tool | Schema | Description | |------|--------|-------------| | gql_login | Login(email, password): String! | Authenticate a learner. Returns the Auth Token string to use as user_token. | | gql_logout | Logout: Boolean! | Invalidate a user's Auth Token. |

Discovery tools

| Tool | Description | |------|-------------| | graphql_query | Execute any Helium query or mutation. Full query, variables, user_token support. | | graphql_introspect | List all root query and mutation field names. Run this first. | | gql_introspect_type | Inspect a specific type's fields (e.g. gql_introspect_type({ type_name: "User" })). |

Query tools

| Tool | Schema | Description | |------|--------|-------------| | gql_catalog_content | CatalogContent(page: Int!, query?, contentTypes?, sortColumn?, sortDirection?): CatalogContent! | Learner-facing content catalog. +3 complexity overhead. | | gql_current_user | CurrentUser: User | Learner profile — id, email, name, balance, course counts. Requires user token. |

Learner mutation tools (all require a learner-or-manager Auth Token)

| Tool | Schema | Description | |------|--------|-------------| | gql_update_course_status | UpdateCourseStatus(id/slug/sku, status, statusChangeDate?): Boolean! | Mark a course started, completed, or not-completed. | | gql_update_topic_progress | UpdateTopicAndCourseProgress(topicId, progress: 0-100): Boolean! | Update percent complete on a topic (propagates to course). | | gql_archive_course | ArchiveUserCourse(id): ID | Hide a course from the learner's dashboard. | | gql_reinstate_course | ReinstateUserCourse(id): ID | Restore an archived course. | | gql_archive_learning_path | ArchiveUserLearningPath(id): ID | Hide a learning path from the learner's dashboard. | | gql_reinstate_learning_path | ReinstateUserLearningPath(id): ID | Restore an archived learning path. | | gql_redeem_balance | RedeemBalance(contentType, contentId): URL! | Redeem credit balance for a course. | | gql_redeem_code | RedeemRegistrationAndRedemptionCodes(codes): { redeemed } | Redeem registration or redemption codes. |

Assessment mutation tools (require Auth Token with MANAGER role)

| Tool | Schema | Description | |------|--------|-------------| | gql_create_assessment_attempt | CreateAssessmentAttempt(topicId, courseId, questions): AssessmentAttempt! | Create a super quiz attempt. |

Run with npx (stdio, for Claude Desktop / Cursor)

npx @thoughtindustries/thoughtindustries

Add to your MCP config:

{
  "mcpServers": {
    "thoughtindustries": {
      "command": "npx",
      "args": ["-y", "@thoughtindustries/thoughtindustries"],
      "env": {
        "TI_BASE_URL": "https://yoursubdomain.thoughtindustries.com",
        "TI_API_KEY": "your-api-key-from-settings-security",
        "TI_HELIUM_USER_TOKEN": "optional-user-auth-token-for-learner-queries"
      }
    }
  }
}

Run with Docker

docker build -t thoughtindustries-mcp -f servers/thoughtindustries/Dockerfile .
docker run -i --rm \
  -e TI_BASE_URL=https://yoursubdomain.thoughtindustries.com \
  -e TI_API_KEY=your-api-key \
  thoughtindustries-mcp

Claude Desktop config (Docker)

{
  "mcpServers": {
    "thoughtindustries": {
      "command": "docker",
      "args": ["run", "-i", "--rm",
        "-e", "TI_BASE_URL",
        "-e", "TI_API_KEY",
        "-e", "TI_HELIUM_USER_TOKEN",
        "thoughtindustries-mcp:latest"
      ],
      "env": {
        "TI_BASE_URL": "https://yoursubdomain.thoughtindustries.com",
        "TI_API_KEY": "your-api-key",
        "TI_HELIUM_USER_TOKEN": "optional-user-token"
      }
    }
  }
}

Multi-tenant HTTP deployment (Cloud Run)

Run one shared server for your whole team. The server holds no credentials — each user's Claude Desktop / Cursor sends their own TI instance + API key as headers on every request (see Request headers). A fresh, fully isolated MCP server is built per request, so users on different TI instances never share state.

flowchart LR
  A["User A (acme.ti.com, keyA)"] -->|"POST /mcp + X-TI-* headers"| CR["Cloud Run\nMCP_TRANSPORT=http\n(no TI creds)"]
  B["User B (beta.ti.com, keyB)"] -->|"POST /mcp + X-TI-* headers"| CR
  CR -->|"REST + GraphQL with A's creds"| TIA["acme.thoughtindustries.com"]
  CR -->|"REST + GraphQL with B's creds"| TIB["beta.thoughtindustries.com"]

Try it locally

docker build -t thoughtindustries-mcp -f servers/thoughtindustries/Dockerfile .
docker run --rm -p 8080:8080 -e MCP_TRANSPORT=http -e PORT=8080 thoughtindustries-mcp
# health check
curl http://localhost:8080/health
# call with per-request credentials
curl -X POST http://localhost:8080/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "X-TI-Base-URL: https://yoursubdomain.thoughtindustries.com" \
  -H "X-TI-Api-Key: your-api-key" \
  -d '{"jsonrpc":"2.0","method":"tools/list","params":{},"id":1}'

Deploy to Google Cloud Run

The server reads the PORT env var (Cloud Run injects 8080) automatically. No TI credentials are set on the service.

# 1. Create an Artifact Registry repo (one-time)
gcloud artifacts repositories create mcps \
  --repository-format=docker --location=us-central1 --project=YOUR_PROJECT_ID

# 2. Build, tag, push
gcloud auth configure-docker us-central1-docker.pkg.dev
docker build -t thoughtindustries-mcp -f servers/thoughtindustries/Dockerfile .
docker tag thoughtindustries-mcp \
  us-central1-docker.pkg.dev/YOUR_PROJECT_ID/mcps/thoughtindustries-mcp:latest
docker push \
  us-central1-docker.pkg.dev/YOUR_PROJECT_ID/mcps/thoughtindustries-mcp:latest

# 3. Deploy — only MCP_TRANSPORT=http, NO TI_* vars
gcloud run deploy thoughtindustries-mcp \
  --image=us-central1-docker.pkg.dev/YOUR_PROJECT_ID/mcps/thoughtindustries-mcp:latest \
  --region=us-central1 \
  --set-env-vars=MCP_TRANSPORT=http \
  --allow-unauthenticated \
  --project=YOUR_PROJECT_ID

Omit --allow-unauthenticated to require Google IAM identity tokens on every request (recommended for production). Note that TI credentials are always per-user; IAM only gates who may reach the service.

Per-user client config (Claude Desktop / Cursor)

Each user points at the shared URL and supplies their own credentials as headers. Credentials live only on the user's machine — never on the server.

{
  "mcpServers": {
    "thoughtindustries": {
      "url": "https://YOUR_SERVICE-HASH-uc.a.run.app/mcp",
      "headers": {
        "X-TI-Base-URL": "https://yoursubdomain.thoughtindustries.com",
        "X-TI-Api-Key": "your-api-key-from-settings-security",
        "X-TI-Helium-User-Token": "optional-user-auth-token"
      }
    }
  }
}

If the Cloud Run service requires IAM auth, also add an identity token:

"headers": {
  "Authorization": "Bearer <gcloud auth print-identity-token>",
  "X-TI-Base-URL": "https://yoursubdomain.thoughtindustries.com",
  "X-TI-Api-Key": "your-api-key-from-settings-security"
}

API coverage

This server covers the full Thought Industries Incoming REST API v2:

| Area | Operations | |------|-----------| | Ping | 1 | | Events / Notifications | 32 | | Users | 23 | | Content & Courses | 17 | | Course Groups | 5 | | Courses / Sections / Lessons / Topics | 10 | | Clients (Organizations) | 14 | | Licenses | 5 | | Assessment Attempts | 3 | | Assignment Submissions | 4 | | Redemption Codes | 4 | | Coupons | 3 | | Ecommerce | 1 | | Meetings & Locations | 3 | | Learning Path Milestones | 1 | | Tags | 2 | | Jobs | 1 | | Logs | 6 | | Total | 135 |