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

@sixtyninecommerce/mcp

v0.22.0

Published

MCP server for sixtynine-commerce storefront development

Readme

@sixtyninecommerce/mcp

An MCP server for sixtynine-commerce. It gives an AI agent (Claude Code, Claude Desktop, any MCP client) the storefront tools a developer needs while building a store, and, with an admin credential, one tool per method of the admin SDK @sixtyninecommerce/admin.

{
  "mcpServers": {
    "commerce": {
      "command": "npx",
      "args": ["@sixtyninecommerce/mcp"],
      "env": {
        "STORE_CODE": "your-store-code",
        "CDN_URL": "https://cdn.your-store.com"
      }
    }
  }
}

npx @sixtyninecommerce/mcp init writes the .mcp.json and a project CLAUDE.md for you.

| Variable | Required | What it is | |---|---|---| | STORE_CODE | yes, but for an SEO agency credential | The store (channel) code | | CDN_URL | with STORE_CODE | The store's CDN URL | | VENDURE_URL, CMS_URL, PLUGINS_URL | no | The platform's services; the hosted ones by default | | ORDER_SCOPE | no | CONSUMER or TRADE, only when the store runs two storefronts | | SIXTYNINE_COMMERCE_API_TOKEN | no | A personal API token: turns on the admin tools | | SIXTYNINE_APP_ID, SIXTYNINE_APP_KEY_ID, SIXTYNINE_APP_PRIVATE_KEY_FILE, SIXTYNINE_APP_INSTALLATION_ID | no | An app's own credential instead of a token: all four, never with a token |

Admin tools

With a personal API token, or an app's credential, the server also offers the admin SDK as tools. At start it reads who the credential is (auth.whoami()) and offers one tool per method the credential may call:

  • named admin_<module>_<method> in snake case: orders.settle is admin_orders_settle;
  • described by the method's own documentation, its effect and the permissions it needs;
  • taking the method's parameters as its input, from the published method manifest (@sixtyninecommerce/admin/manifest). admin_payments_refund takes { input: { orderId, amount, reason? } }, the arguments of admin.payments.refund(input).

A method is left out when the credential lacks a permission it declares (@permission in the manifest); nothing else hides a tool. In particular a plugin's tools (AFAS, MyParcel, the till, SEO, …) are offered whether or not the store holds that plugin: the manifest does not say which plugin a method belongs to, and the platform's own gate is the exact line. Without the plugin the platform refuses the call and the tool answers that refusal as its error: the Admin API's PLUGIN_ACCESS_DENIED, whose message names the plugin, or, on a plugins-service route (SEO signals, product feeds), a 403 refusal without that code. The doors the platform keeps open without the plugin (closing a till, money already in flight, switching it off, removing access) simply work. Platform administration needs a signed-in person and is never offered; neither are streams, file and raw byte uploads, a person's own sign-in and the in-product assistant. storefront://admin-guide lists what this credential is offered, and storefront://capabilities reads the store's capability manifest live.

Money and deletions ask first

A tool whose effect is money, destructive or irreversible does nothing on its first call, and sends nothing at all. It answers an error coded CONFIRMATION_REQUIRED, with a plain summary of what would happen and a confirmationToken. The summary lists every argument exactly as it will be sent. A number whose documentation says it is in minor units says so, with the currency code when the call names one beside it (amount: 5000 (minor units; currency EUR)), else amount: 1250 (minor units): nothing is converted, looked up or guessed, so a refund's amount (minor units of the order's currency) shows no currency, and a money field whose documentation names no unit shows its bare number.

{
  "status": "confirmation_required",
  "error": { "code": "CONFIRMATION_REQUIRED", "message": "admin_payments_refund needs the person's agreement first. Nothing has been done." },
  "summary": "Moves money: Hand money back to a customer, never more than the order took.\n…\n- input.amount: 1250 (minor units)\n…",
  "confirmationToken": "v1.…",
  "expiresAt": "2026-10-25T16:08:02.682Z"
}

The agent shows the summary to the person it works for. Only when they agree does it call the same tool again with exactly the same arguments and the token, within five minutes. That call runs the method once, under an idempotency key derived from the token. Calling again with the same token answers the same outcome ("replayed": true) for a day, and never does it twice. A token brought to another tool, with other arguments, or first brought back after five minutes is refused CONFIRMATION_INVALID, and nothing is sent. The token is signed with a secret this server process draws at start, so a restart voids every open confirmation.

When a confirmed call ends without an answer (outcomeUnknown: a timeout, a dropped connection), it may have happened or may still be running. The agent reads the state back first. If it asks again, the new summary and the MCP client's own question (below) say so, and the new confirmation runs under the SAME idempotency key. Only a method that honours that key answers the first call's result instead; most do not, so confirming may do it twice.

Every confirmed call sends that derived key, except the few whose SDK refuses one (creating an event subscription, rotating its secret: the answer carries a secret the platform never keeps for replay); the confirmation alone keeps those to one run. A call that is not confirmed sends no key, except the few whose SDK requires one per attempt (orders.createOrRecover, approving a purchase order, a till's notes), which get a fresh one per call.

When the MCP client can ask its own user (MCP elicitation), the server asks them too before the call runs, as well as the token, not instead of it. A "no" there is CONFIRMATION_DECLINED.

Agency mode

An SEO agency credential (minted by a platform SuperAdmin, scoped to several stores) needs no STORE_CODE: every admin tool then takes a required storeCode, seo_agency_list_stores lists the stores it reaches, storefront://agency/stores/{storeCode}/brief reads one store's SEO brief, and the storefront tools are not offered. See Agency mode.

Recorded as an AI agent

Every call the admin tools make says where it comes from (x-sixtynine-agent: sixtyninecommerce-mcp/<version>). The platform records those calls with the actor type "AI agent" in the store's audit trail and on the events they cause, under the credential's own id and name. For a credential that should only ever act as an AI, mint the token from the ai-agent template (admin.apiTokens.create({ templateKeys: ['ai-agent'], … })): it reads by default, and what it may change is granted beside it.

Deprecated authoring tools

create_form, update_form, remove_form_field, list_form_submissions, list_redirects_admin, create_redirect, upsert_redirect, update_redirect, delete_redirect and import_redirects remain as deprecated aliases of the generated tools (admin_content_forms_*, admin_seo_redirects_*) and will be removed in a later release. Each runs its generated tool, so it is offered with the same permissions and the deletions ask first.