Skip to main content
Glama
dalai2

gumroad-publish-mcp

by dalai2
README.md
# gumroad-publish-mcp

An MCP server for [Gumroad](https://gumroad.com) that can ship a product end to end:
upload the file, create the product, set its cover and thumbnail, write its landing
page, publish it. **Zero dependencies.**

## Why another one

There is already [`gumroad-mcp`](https://github.com/rmarescu/gumroad-mcp) (MIT, by
Razvan Marescu), and it is good at what it does: list products, read sales, manage
offer codes. It was last published in April 2025, before Gumroad's API grew the
endpoints that matter for publishing — so it cannot create a product and cannot
upload a file.

This one fills that gap. The two coexist happily: keep that one for offer codes,
use this one to ship.

Gumroad also publishes an [official CLI](https://github.com/antiwork/gumroad-cli)
that wraps every endpoint. If you are on macOS or Linux and want a terminal tool
rather than an MCP server, look there first.

## Zero dependencies, on purpose

This process receives a token with write access to your store. Every dependency is
something that token sits next to. The MCP stdio protocol is newline-delimited
JSON-RPC 2.0, which fits in the first forty lines of `server.mjs`, so there is no
SDK here and no `node_modules` to audit. The whole server is one readable file.

## Install

```json
{
  "mcpServers": {
    "gumroad": {
      "command": "npx",
      "args": ["-y", "gumroad-publish-mcp@1.0.0"],
      "env": { "GUMROAD_ACCESS_TOKEN": "${GUMROAD_ACCESS_TOKEN}" }
    }
  }
}
```

On Windows, use `"command": "cmd", "args": ["/c", "npx", "-y", "gumroad-publish-mcp@1.0.0"]`
— `npx` is a `.cmd` shim there and spawning it directly fails.

Get the token at **gumroad.com/settings/advanced#application-form**: register an
application, then click *Generate access token* on its page. The token needs the
`edit_products` scope to upload and publish, and `view_sales` to read sales.

Check it works without touching your store:

```
GUMROAD_ACCESS_TOKEN=... npx gumroad-publish-mcp --selftest
```

## Tools

| Tool | What it does |
| --- | --- |
| `gumroad_upload_file` | Local path → `file_url`, running the full four-step multipart upload |
| `gumroad_create_product` | Creates a digital product (price in **cents**), optionally attaching uploaded files |
| `gumroad_update_product` | Name, price, description, category, `custom_html` landing page, purchase limit |
| `gumroad_publish` / `gumroad_unpublish` | Enable or disable a product |
| `gumroad_set_thumbnail` / `gumroad_add_cover` | Thumbnail and cover images from a URL |
| `gumroad_list_products` / `gumroad_get_product` | Read your catalogue |
| `gumroad_list_categories` | Valid category paths, which product creation asks for |
| `gumroad_list_sales` | Sales, optionally filtered by date or product |
| `gumroad_whoami` | The account behind the token |

There is deliberately **no delete-product tool**. That one belongs in the dashboard,
where a human confirms it.

## The two things this gets right that are easy to get wrong

**Uploading is four steps, not one.** `presign` returns an upload id, a key and one
presigned URL per 100 MB part; each part is PUT to its URL and its `ETag` captured;
`complete` submits the list of ETags; only then can the resulting `file_url` be
attached to a product. Three traps are handled here: `complete` is never retried
(the upload id is single-use — a lost response means starting over from `presign`),
`abort` is repeated until it answers `already_gone`, and the part size is derived
from the number of parts `presign` actually returned rather than assumed.

**Replacing files deletes files.** In the API, `files` on a product update is a
*full replacement*: anything you leave out is deleted. So `gumroad_update_product`
refuses to send files unless you pass `replace_files: true`, and says why. An agent
that updates a price should not be able to wipe your downloads on the way through.

## Licence

MIT. See `LICENSE`.