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

@nasdigitaluk/etsy-mcp

v1.0.0

Published

Model Context Protocol server for the Etsy Open API v3. Complete catalogued coverage with tiered access and destructive operations gated.

Readme

etsy-mcp-server

A Model Context Protocol server for the Etsy Open API v3.

All 105 published operations are reachable. Nothing is excluded, because there is nothing to exclude — Etsy's v3 API is entirely seller-facing, with no admin tier and no endpoint an ordinary app is structurally barred from. What varies is the OAuth scopes, and that is what this server surfaces.

MIT licensed.

Install

npm install -g @nasdigitaluk/etsy-mcp

Authentication

Two modes. Pick one.

API key — the 32 public operations (taxonomy, listing lookups, shop and review reads):

{ "env": { "ETSY_KEYSTRING": "your-keystring" } }

Seller — everything, and it refreshes itself:

{
  "env": {
    "ETSY_KEYSTRING": "your-keystring",
    "ETSY_SHARED_SECRET": "your-shared-secret",
    "ETSY_CREDENTIALS_FILE": "~/.etsy-mcp-credentials",
    "ETSY_SHOP_ID": "12345678"
  }
}

Seed the credentials file once from your authorisation flow:

ETSY_ACCESS_TOKEN=...
ETSY_REFRESH_TOKEN=...
ETSY_TOKEN_EXPIRES_AT=1757260800000

ETSY_SHOP_ID is optional; it just defaults the shop_id argument on the shop tools.

Two things about Etsy that cost real time to discover

1. x-api-key wants both halves — keystring:shared_secret. The bare keystring returns 403 on every authenticated call, and the message reads exactly like a scope refusal: "Shared secret is required in x-api-key header." That sends you hunting through your app's scope grants for a problem that is in a header. This server always sends both.

2. Etsy rotates the refresh token on every refresh. The old one stops working the moment the new one is issued, so losing the new one breaks the chain permanently — the only fix is re-authorising in a browser. Running two MCP clients at once is completely normal; both refresh, both spend the same token, and whichever writes second saves one Etsy has already invalidated.

Here the refresh happens inside an exclusive lock, re-reads under the lock before spending anything (another process may have already done the work while this one waited), and the write is atomic (temp file, fsync, rename). There is a test asserting that three concurrent callers cause exactly one refresh.

Scopes are the interesting part

Etsy's access control is entirely scope-shaped, and the scope table has one property worth knowing before you authorise anything:

Of the 13 DELETE operations, exactly ONE needs listings_d — deleting a whole live listing. The other twelve ride on scopes you already hold in order to edit anything at all.

So declining listings_d makes the single catastrophic delete impossible at the OAuth layer while leaving every normal operation working. No other operation, of any method, needs it.

etsy_check_scopes reports this: what the whole API needs, what one operation needs, and — with held: true — what your token actually carries. The two together are what turn a 403 into a fix rather than a guess.

Scope distribution across the 105 operations:

| Scope | Operations | |---|---| | (none — public) | 32 | | shops_w | 21 | | listings_w | 16 | | transactions_r | 12 | | shops_r | 11 | | listings_r | 7 | | address_r | 3 | | transactions_w | 2 | | email_r | 1 | | listings_d | 1 |

Tools

Seven tools for 105 operations. Every tool name and description is paid for in the model's context window on every turn, used or not — 105 tools would not be a tool list, it would be a catalogue with worse ergonomics.

| Tool | | |---|---| | etsy_list_operations | Browse the catalogue. Start here. | | etsy_call | Call any operation by id. | | etsy_check_scopes | What a call needs, and what your token holds. | | etsy_get_me | The authenticated user, including shop_id. | | etsy_list_listings | Listings in a shop, by state. | | etsy_get_listing | One listing in full. Public. | | etsy_list_receipts | Orders. Needs transactions_r. |

Of 105 operations: 64 read, 28 write, 13 destructive.

Read-only and no-destructive modes

MCP_READ_ONLY=1       refuse anything that changes state
MCP_NO_DESTRUCTIVE=1  allow writes, refuse deletes

⚠️ Worth knowing: etsy_call is one door onto all 105 operations, 13 of which are deletes, so it is classified destructive and MCP_READ_ONLY=1 refuses it outright. The dedicated read tools stay usable in that mode — including etsy_check_scopes, because Etsy's scope-introspection endpoint is a POST that changes nothing and is deliberately classified a read. Classifying it by its verb would have read-only mode refuse the one call that diagnoses a permission problem.

Refreshing the catalogue

curl -o vendor/etsy-openapi.json https://www.etsy.com/openapi/generated/oas/3.0.0.json
npm run generate && npm test

The coverage test fails if Etsy publishes an operation the catalogue does not carry, so a stale catalogue is loud rather than silent.

Testing

npm test                                    # 24 tests, incl. the refresh-concurrency one
SMOKE_ENV='{"ETSY_KEYSTRING":"x"}' npm run smoke   # real MCP over stdio

Built on

@nasdigitaluk/mcp-server-core.

Licence

MIT.