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

@corpusctl/mcp

v0.3.0

Published

Model Context Protocol server for Corpusctl — let an assistant read your content types, draft entries and publish, bounded by your API token's scopes

Downloads

595

Readme

@corpusctl/mcp

Model Context Protocol server for Corpusctl. Point an MCP client at it and an assistant can set up your schema, manage locales, search your content, draft entries and publish them — a space can be built end-to-end without opening the panel, bounded by whatever your API token is allowed to do.

Setup

Create an API token in the panel (Settings → Tokens) with the scopes you want the assistant to have, then add this to your MCP client config:

{
  "mcpServers": {
    "corpusctl": {
      "command": "npx",
      "args": ["-y", "@corpusctl/mcp"],
      "env": {
        "CORPUSCTL_URL": "https://api.corpusctl.com",
        "CORPUSCTL_TOKEN": "cctl_api.…"
      }
    }
  }
}

Both variables are required. CORPUSCTL_URL must be https — the only exception is a loopback address for local development.

CORPUSCTL_TOKEN accepts two kinds of token:

  • Space token (cctl_api.…) — bound to exactly one space. The assistant works in that space and nowhere else.
  • Account token (cctl_acc.…) — spans the owner's memberships. Every space-bound tool takes an optional space argument (a space UUID or slug) to pick the target; without it, requests fall back to the owner's first membership. list_spaces shows what is available, and with the tenants:manage scope create_space can open new spaces.

Tools

| Tool | Scope required | |---|---| | list_content_types | schema:read | | get_content_type | schema:read | | upsert_content_type | schema:write | | delete_content_type | schema:write | | get_locales | content:read | | set_locales | schema:write | | list_documents | content:read | | get_document | content:read | | search_content | search:read | | create_document | content:write | | update_draft | content:write | | publish_document | content:publish | | unpublish_document | content:publish | | list_spaces | account token (cctl_acc.…) | | create_space | account token + tenants:manage |

Every tool except the two account-level ones also takes an optional space argument — a space UUID or slug sent as the x-corpusctl-tenant header. It only matters with an account token; a space token is pinned to its space on the server regardless.

Give the token only the scopes you want used. A token without content:publish produces an assistant that can draft but cannot publish, and the refusal comes from the server — not from this package.

Markdown in, blocks out

Body fields use Corpusctl's block format. The assistant does not need to generate block JSON: create_document and update_draft accept a markdownFields object ({ "body": "# markdown here" }) and the server converts each entry to blocks before sending — headings, lists, task lists, tables, code fences, images, links and inline formatting included. A field present in both data and markdownFields is an error; nothing is silently overwritten.

What it deliberately cannot do

There are no tools for deleting documents, purging trash, managing members or issuing tokens. An assistant produces content; destroying content stays a human decision. The one delete that exists — delete_content_type — cannot touch data: the server refuses to drop a type that still has documents. Member and token management is session-only on the API anyway, so an API token could not perform it even if a tool existed.

Security model

The token is the boundary, and it is enforced on the server.

  • A space token belongs to exactly one space. The space is resolved from the token record in the database — the x-corpusctl-tenant header cannot move it, so this package cannot reach another space even if asked to.
  • An account token selects a space per request, but only among its owner's memberships — the server answers 403 for anything else, and the effective scopes are intersected with the owner's role in the selected space (a viewer membership cannot write, whatever the token's scopes say).
  • Scopes are enforced by the API. This package invents no authorization of its own; a 403 is surfaced to the assistant as a readable error.
  • A token is also bound to its owner's current membership. If the person who created it is removed from the space, or their role is reduced, the token dies or narrows with them.
  • The token is only ever sent to the configured CORPUSCTL_URL. Redirects are refused rather than followed, and no tool takes a base URL argument.
  • Session keys (cctl_ses.…) are rejected. They represent a whole person across every space and do not belong in a config file.

Responses are capped so a large query cannot flood the assistant's context; a truncated result says so rather than looking complete.

Requirements

Node 20 or newer.

Licence

MIT