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

@doswiftly/storefront-mcp

v4.0.0

Published

MCP server for the DoSwiftly Storefront API — validates GraphQL operations against the schema your project has installed, and searches the operation catalog, so AI coding assistants stop guessing.

Readme

@doswiftly/storefront-mcp

MCP server for the DoSwiftly Storefront API. It lets an AI coding assistant check a GraphQL operation against your schema before writing code around it, and look up operations, types and error codes without loading a whole reference into its context.

The problem it solves is narrow and expensive: an assistant that writes cartLinesAdd instead of cartAddLines produces code that compiles, passes review, and fails against the live API. Documentation asks the assistant to be careful. This asks the schema.

Install

pnpm add -D @doswiftly/storefront-mcp @doswiftly/storefront-operations

Both are dev-only. @doswiftly/storefront-operations carries the schema — this server reads it from your install rather than shipping its own copy, so it can never validate against a different schema than the one your project targets.

Configure

Most tools read a project-level .mcp.json:

{
  "mcpServers": {
    "doswiftly-storefront": {
      "command": "npx",
      "args": ["-y", "@doswiftly/storefront-mcp"]
    }
  }
}

Start it from the project directory — the working directory decides which installed schema is used.

Any MCP client works; the server speaks stdio. If your client has its own config format, point it at the doswiftly-storefront-mcp binary (or npx -y @doswiftly/storefront-mcp) with no arguments.

Tools

| Tool | What it answers | |---|---| | validate_operation | Is this document valid against my schema — and what document id will the API key it by? | | next_step | What is the one thing to do next, and where do I read about it? | | get_project_state | How far along is this project, stage by stage? | | report_friction | Tell the platform what I could not find or could not trust. | | contribute_recipe | Send back how I built something there was no recipe for (opt-in). | | search_operations | Which ready-made operation does what I want ("add lines to cart")? | | get_operation | Give me that operation's body and typed variables, verbatim. | | get_type | What fields / enum values does this type have? | | list_error_codes | Which error code enums does the schema expose? | | get_operation_error_codes | Which codes does this operation document? |

Use validate_operation on everything you write

It reports validation errors with locations, and for a valid document returns a documentId in the API's sha256:<hex> form — the same value the codegen recipe computes, so an id from here is the id the API will accept.

validate_operation({ source: "query P($h: String) { product(handle: $h) { id title } }" })
→ { valid: true, errors: [], documentId: "sha256:…" }

validate_operation({ source: "query P { product(slug: \"x\") { id } }" })
→ { valid: false, errors: [{ message: "Unknown argument \"slug\" on field …" }] }

Pass the whole document, including fragments it spreads — an unresolved spread is reported rather than passed over.

Building a storefront: ask where you are, then what is next

Starting from an empty directory, the hard question is not what the schema contains — it is what to do first, and whether the thing you are about to build already exists.

get_project_state answers the first half by reading the project: each stage of the build (scaffold, dependencies, identity, codegen, client, catalog, session, cart, checkout, account, polish) comes back as done, todo or unknown, each with the reason it was judged that way.

get_project_state()
→ { current: "cart",
    stages: [ { name: "codegen", status: "done",
                reason: "codegen.ts is configured and lib/gql/gql.ts has been generated" },
              { name: "cart", status: "todo",
                reason: "the project has 20 GraphQL documents, none on this stage's root fields" }, … ] }

unknown means "look before you act". It is used whenever a signal is ambiguous — a config file that builds its values in a way a plain read cannot follow, a cart surface that is wired but never filled. Treating it as "not done" is how an assistant overwrites an afternoon of someone else's work.

next_step answers the second half, and answers it once: why this step comes now, what finishes it, and either a command to run or the guide section to read.

next_step()
→ { stage: "cart",
    why: "cart lines refer to what the catalog lists, so the catalog comes first…",
    doneWhen: "the project has cart mutations",
    support: { kind: "guide", package: "@doswiftly/storefront-operations",
               section: "Cart mutation names", file: "…/AGENTS.md", sectionFound: true } }

It never returns code to paste. Mechanical steps get a command; design decisions get a pointer into the AGENTS.md that is already installed in your project — and the pointer is checked against the installed file, so a section that has moved says so instead of sending you to a heading that no longer exists.

When there is no confirmed recipe

Some steps — checkout, catalog filtering, variant selection — have no confirmed recipe yet. The answer degrades rather than emptying: you still get the operations the schema ships for that stage and the guide sections that constrain them, plus an explicit warning that nothing here is proven and every operation should be checked with validate_operation before you build on it.

Tell us what was missing

report_friction records a gap: what you were trying to build and what you could not find or could not trust. Categories are missing_tool, incomplete_answer, misleading_result, schema_gap and docs_contradict_behaviour.

Send only the description. The shop, the package versions, the kind of install and the stage you were on are read from the project, so a report cannot be filed against the wrong shop or an imagined version — and your code stays in your project. The response tells you exactly where the report went, and says so plainly when it went nowhere.

Reports travel to the API address your project already configures. A locally linked build writes a journal next to the checkout instead, so notes taken while developing the platform never crowd out the signal from real projects.

Sending a solution back — only if you say so

Checkout, catalog filtering and variant selection have no confirmed recipe yet, which means the first person to build one does it without a road. contribute_recipe sends back how it was done: which operations, in what order, what bites, and the smallest fragment of glue that makes the sequence legible. Never a file.

It refuses unless your config declares it, and the refusal says what is missing:

// doswiftly.config.ts
const config = {
  contributeRecipes: true,
  shop: { slug: 'my-shop' },
  api: { url: 'https://api.doswiftly.pl' },
};

The literal true is what counts — this file is read, never executed, so a computed value reads as "not declared". Failing that way round is deliberate: the default costs a contribution, never a surprise.

What you send is a description you wrote, and it becomes raw material for a public recipe rather than a published one. report_friction needs no declaration — saying what was missing gives nothing away.

A caveat worth knowing about error codes

UserError.code is typed String, and the schema's own description of it points at per-domain enums (CartErrorCode, CustomerErrorCode, …) that are not part of the published schema. So:

  • list_error_codes returns only the enums that really are exposed, and returns an explicit "not exposed" answer for the others — never an empty list, which would read as "this mutation has no error codes".
  • get_operation_error_codes returns codes named in an operation's description. That covers most cart and customer codes, but it is not exhaustive — the response says so. Always handle an unrecognised code as a generic failure.

Related

  • @doswiftly/storefront-operations — schema, ready-made operations, and an AGENTS.md covering the GraphQL layer.
  • @doswiftly/storefront-sdk — the runtime library, with its own AGENTS.md covering transport, session and cart conventions.

Requirements

Node.js 20 or newer. Works with any MCP-capable client.