Substack MCP Server vs Formio MCP

A side-by-side look at the Substack MCP Server and Formio MCP MCP servers: transport, auth, tools, quality signals, and the config to install either one in Claude, Cursor, Windsurf or VS Code.

Substack MCP Server logoSubstack MCP ServerDeveloper Tools · Local subprocess (stdio)Manage Substack publishing, subscribers, analytics, reader feeds, comments, and images through MCP.67GreatAuth: not declaredFormio MCP logoFormio MCPDeveloper Tools · Local subprocess (stdio)Create and manage Form.io forms, resources, actions, roles, and projects from your AI agent.64GoodAuth: not declared

Verdict: choose Substack MCP Server for developer tools work as a local process; choose Formio MCP for developer tools as a local process. You can also run both side by side in one mcpServers block.

Which MCP server should you choose?

Substack MCP Server logoChoose Substack MCP Server when

  • You need dedicated capabilities in the Developer Tools domain.
  • You prefer a local stdio subprocess transport.
  • You have the keys it needs: SUBSTACK_PUBLICATION_URL, SUBSTACK_SESSION_TOKEN, SUBSTACK_USER_ID.
  • You want tools like create_draft_post, set_post_body, upload_image.
Explore Substack MCP Server

Formio MCP logoChoose Formio MCP when

  • You need dedicated capabilities in the Developer Tools domain.
  • You prefer a local stdio subprocess transport.
  • You want tools like hello, form_create, form_get.
Explore Formio MCP

Feature & specification comparison

Rows where the two servers differ are marked.

SpecSubstack MCP Server logoSubstack MCP ServerFormio MCP logoFormio MCP
CategoryDeveloper ToolsDeveloper Tools
Quality signal67/100 · Great64/100 · Good
Install commandConfirmedConfirmed
TransportLocal subprocess (stdio)Local subprocess (stdio)
AuthNot declaredNot declared
PricingNot declaredNot declared
Required env varsSUBSTACK_PUBLICATION_URLSUBSTACK_SESSION_TOKENSUBSTACK_USER_IDNone listed
Verified ownerCommunity listingCommunity listing
GitHub stars878
Directory activity 2 views 0 installs 0 upvotes 3 views 0 installs 0 upvotes
Tools2721

Tools & capabilities

Substack MCP Server tools 27

  • create_draft_postcreate a draft post on your Substack account.
  • set_post_bodyreplace the body of a draft with a Substack document. This is the only way to write structured content — headings, lists, links, code blocks, images, buttons and a paywall. Create the draft first with create_draft_post, then call this with its id. The result reports how many nodes of each type were stored, so a caller can confirm that what it asked for is there. An image must already be hosted by Substack: this cannot upload one.
  • upload_imageHost an image on your Substack publication and get back a Substack URL — the one thing image2.src in set_post_body and cover_image in update_draft will actually render. The source is either an http(s) URL, which the server downloads and re-hosts, or `path`, an absolute path to a local file on the machine running this server, which is read straight from disk: use that for an image you generated or edited locally, with no need to publish it anywhere first. Private and loopback hosts are refused, HEIC is not accepted, max 10 MB.
  • list_subscribersList and filter the subscribers of your Substack publication. Supports the same 48 columns and operators as the Subscribers dashboard, combined with AND, plus free-text search, sorting and pagination. Returns `count`, the total matching the filters regardless of `limit`, so a call with limit 1 is a cheap way to size a segment. Engagement columns (email opens, post views, comments, shares, activity rating) can be filtered on here but are not part of the records this tool returns — use export_subscribers to read their values.
  • export_subscribersExport subscribers with their full column values, including the engagement metrics list_subscribers can filter on but not return: email opens over 7d/30d/6mo, unique emails seen, post views, unique posts seen, comments, shares, links clicked, days active and activity rating. Takes the same filters as list_subscribers and covers the whole matching set — there is no paging. Substack generates the file asynchronously, so this waits for it and returns the parsed records. One column cannot be exported and is reported in `missing_columns` rather than failing: tag_ids.
  • list_postsList the posts of your Substack publication: drafts, published posts or scheduled posts. Supports free-text search, pagination and sort direction. Each post is returned as a summary; use get_draft for the full content of an unpublished one.
  • get_draftRead one draft post of your Substack publication in full, including its body and its audience and email settings. Take the id from list_posts or create_draft_post.
  • update_draftChange an existing draft's title, subtitle or any of its Post settings: audience, who may comment, comment order, cover image, social preview title and description, SEO title and description, and URL slug. The update is partial: only the fields you pass change, everything else — including the body — is left alone. A cover_image not already hosted by Substack is downloaded and re-hosted first. Take the id from list_posts or create_draft_post.
  • publish_draftPublish a draft. The post goes live on the web; `send` additionally emails it to subscribers and defaults to false, because an email cannot be recalled. Publishing cannot be undone from this server — there is no unpublish tool.
  • delete_draftDelete an unpublished draft. Refuses if the id belongs to a published post: Substack deletes both through the same endpoint, and removing a live post is irreversible, so that is left to the dashboard.
  • get_publicationRead the settings and identity of your Substack publication: name, subdomain, custom domain, hero text, copyright, sender name, logo, plans and payment state. Returns a projection by default; pass full: true for all 111 fields.
  • get_user_profileRead the account behind the session: id, handle, name, bio, and every publication you have a role on. This is how to discover which publications the session can reach, beyond the one SUBSTACK_PUBLICATION_URL points at.
  • +15 more on the listing page

Formio MCP tools 21

  • helloSay hello — a connectivity check that confirms the server is running and reachable. Needs no Form.io project or credentials, so it is the first thing to try when other tools fail.
  • form_createCreate a new form in the Form.io project mapped to the user's current working directory. IMPORTANT: Before calling this tool, use the formio-schema skill to construct a properly structured Form.io form JSON definition based on the user's requirements. The skill documents all component types, validation options, layout patterns, and conditional logic available in Form.io. New forms default to `revisions: 'original'` so form change history is preserved. NOT for: creating a draft revision of an existing form. When the user says "create/save a draft", "draft <change>", call form_update with `formId` and `draft: true` instead.
  • form_getFetch a single form definition from the Form.io project mapped to the user's current working directory, by form ID or path. Pass `draft: true` to fetch the form's current in-flight draft instead of the published form.
  • form_listList forms from the Form.io project mapped to the user's current working directory with optional filtering and pagination.
  • form_revision_getFetch a single immutable form revision from the Form.io project mapped to the current working directory. `version` accepts either the revision `_vid` (e.g. "3") or the revision document `_id` (24-character hex). To revert the live form to this revision, pass its `form` body to `form_update` with a `note` like `Revert to v<vid>`.
  • form_revisions_listList immutable published revision summaries for a single form in the Form.io project mapped to the current working directory. Returns compact revision metadata (_vid, _id, modified, user, _vnote) for the form identified by `formIdOrPath`. To inspect a specific revision body, call `form_revision_get` with the desired `_vid`. To revert the live form to a prior revision, pass that revision body to `form_update` with a `note` like `Revert to v<vid>`.
  • form_updateUpdate an existing form in the Form.io project mapped to the user's current working directory. IMPORTANT: Before calling this tool, first use form_get to fetch the current form definition, then use the formio-schema skill to understand the schema so that you can apply the requested modifications (add, remove, or modify fields and settings), and finally call this tool with the complete updated form JSON. `draft`, `publish`, and `revert` are mutually exclusive — pass at most one. If `revisions` in the response differs from the stored value, the per-form revisions-mode gate prompted the USER and they chose.
  • project_exportExport the complete template (roles, resources, forms, actions) of the Form.io project mapped to the user's current working directory as a portable JSON document. Use this to snapshot a project before importing changes.
  • project_getReport which Form.io project the given working directory resolves to, which deployment hosts it, and which layer supplied each — the preflight to run before the first tool call that reads from or writes to a deployment. Answers from inside this server, using the same resolver every other tool uses, so what it reports is what the next call targets. There is no need to run any shell command to ask this. Branch on `status`. "ok" means both URLs resolved and you may proceed. "not-configured" means nothing is mapped for this directory: relay the message, ask the user for the single value it names, record it with project_set, and call this again. "base-url-unresolved" means the project IS recorded and only its deployment is missing — ask for the Base URL alone and do NOT re-ask for the Project URL. Reads only. It resolves and reports; project_set is what records a choice.
  • project_importImport a template JSON into the existing Form.io project mapped to the user's current working directory, merging roles, resources, forms, and actions in one call. Use the formio-resource-planner skill to construct the template before calling this tool. WARNING: import merges into the existing project — use project_export first to snapshot.
  • project_setSet the active Form.io project for the given working directory by recording its URL in ~/.formio/projects.json You MUST call this tool whenever the user asks to set, change, or switch the active Form.io project — do not merely acknowledge the request in text. Persisting the choice requires the tool call. The chosen URL is persisted to ~/.formio/projects.json keyed by the cwd argument when provided (or the MCP server process cwd otherwise). Pass the `cwd` argument whenever you know the user's current working directory — the server process cwd is fixed at spawn and may not match where the user actually is. Every Form.io tool resolves its project on each call, so a mapping written here needs no restart. It takes effect only where the mapping is the record that WINS, though: under a committed formio.json the mapping is the fallback if that file goes away, and this call reports the pair that actually resolves rather than the one it recorded. Read `ok` and `projectUrl` on the result rather than assuming the write governs. You normally pass only projectUrl. The base URL — which builds the portal-login URL and keys the cached token — is derived from it — https://api.form.io for a project on a form.io host, and the parent path for a project addressed as a sub-directory — so there is nothing to supply. Pass baseUrl ONLY when the server reports that it cannot be determined, which happens for a project URL that carries no path on a customer domain: there the deployment is a sibling sub-domain and nothing in the project URL names it. Do not ask the user for a base URL before the server says it needs one. This tool writes the machine-local mapping, which is keyed by absolute path and therefore does not survive a clone. To record the target with the code instead — versioned, visible in a diff, and shared with everyone who clones the repository — write a committed formio.json yourself, in the application's own folder: a JSON object holding {"projectUrl": "..."}, plus "baseUrl" only when it cannot be derived. This server reads that file and never writes it. Resolution is by scope, narrowest first, and precedence runs: a committed formio.json, then the working-directory mapping, then FORMIO_PROJECT_URL in the environment, which is the weakest of the three. So a mapping written here DOES override an environment value, and a committed file overrides both.
  • role_createCreate a new role in the Form.io project mapped to the user's current working directory.
  • +9 more on the listing page

Ready-to-paste client configs

Paste either block (or both) into your client config, e.g. claude_desktop_config.json or ~/.cursor/mcp.json. We only show a config when the install command is confirmed.

Substack MCP Server

mcpServers (Claude Desktop / Cursor)
{
  "mcpServers": {
    "substack-mcp-server": {
      "command": "npx",
      "args": [
        "-y",
        "substack-mcp@latest"
      ],
      "env": {
        "SUBSTACK_PUBLICATION_URL": "YOUR_SUBSTACK_PUBLICATION_URL_HERE",
        "SUBSTACK_SESSION_TOKEN": "YOUR_SUBSTACK_SESSION_TOKEN_HERE",
        "SUBSTACK_USER_ID": "YOUR_SUBSTACK_USER_ID_HERE"
      }
    }
  }
}

Formio MCP

mcpServers (Claude Desktop / Cursor)
{
  "mcpServers": {
    "formio-mcp": {
      "command": "npx",
      "args": [
        "-y",
        "@formio/mcp@0.14.1"
      ]
    }
  }
}

Frequently asked questions

Substack MCP Server is categorized under Developer Tools and uses a local stdio subprocess. Formio MCP belongs to Developer Tools and uses a local stdio subprocess. Pick Substack MCP Server for developer tools work and Formio MCP for developer tools.

Copy the mcpServers block from the config section on this page into your client's config (for example claude_desktop_config.json or ~/.cursor/mcp.json), then fully restart the client.

Substack MCP Server has no declared pricing — check the project's own site. Formio MCP has no declared pricing — check the project's own site. If a server needs environment variables such as API keys, define them under the env key in your client's MCP config.

Yes. MCP clients support multiple servers: add substack-mcp-server and formio-mcp as separate keys in the same mcpServers object, and your assistant will call tools from either one.

On AllMCPs, Substack MCP Server has a quality signal of 67/100 (Great) with 2 views, 0 installs and 87 GitHub stars. Formio MCP has 64/100 (Good) with 3 views, 0 installs and 8 GitHub stars.