# Sell without hosting

> A stdio MCP server can be sold as a pinned npm package that buyers run locally. There's no port and no uptime to maintain, and payment works exactly as for a hosted server.

> **Warning — Preview: check credentials before you ship:**
>
> Your package's payment calls go to Zanora **from the buyer's machine**. On a gateway that requires authentication, including the hosted one, those calls need a credential with `payments:write`. There isn't yet a supported way to give a buyer-run package that credential without publishing your key. **Never put a provider key in a public package.** Until this is supported, host your server (see [Sell an MCP tool](https://docs.zanora.dev/sellers/mcp.md)) or email [support@zanora.dev](mailto:support@zanora.dev) before selling this way.

Most MCP servers speak **stdio**. They're started by the client and aren't reachable on a URL. You can still sell one: during payment your server only sends requests *out* to Zanora, and Zanora never has to reach you. So the buyer can run your package, and payment works the same way.

## Publish the package

### Step 1: Publish to npm as usual

The package must be **public**, because buyers' machines install it. Private packages are refused.

### Step 2: Sell it with `runsLocally`

```ts
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";

const paid = await seller.sell({
  tool: "financial_analysis",
  description: "Advanced AI-powered financial analysis",
  category: "finance",
  price: "$0.10",
  runsLocally: true,        // name + exact version from your package.json
  // runsLocally: "@acme/analysis-mcp@1.4.2"   // or name it explicitly
});

server.tool("financial_analysis", "…", schema, paid(handler));
await server.connect(new StdioServerTransport());
```

The capability's address becomes `{ kind: "package", command: "npx", args: ["-y", "@acme/analysis-mcp@1.4.2"], version: "1.4.2" }`.

## What changes

| | Hosted (`url`) | Package (`runsLocally`) |
|---|---|---|
| You run | a public HTTPS server | nothing |
| Buyer runs | nothing | your package, over stdio |
| Payment, receipts, refunds, policies | the same | the same |
| Buyer opt-in | none | **must allow your package by name** |
| Version | whatever you deploy | pinned **exactly**, and checked before each start |

## What to know

- **Buyers opt in per package.** Buying yours needs the buyer to allow it (`ZANORA_ALLOW_LOCAL_PACKAGES`), so you may sell to fewer agents than a hosted tool would. Say in your description what the package does and what it touches.
- **Exact versions only.** Ranges are refused, because buyers are running code: what was reviewed must be what runs. Shipping a new version means publishing that version and updating the capability.
- **Your package gets a clean environment.** It doesn't inherit the buyer's environment, only the variables the buyer chooses to pass. If you need an upstream API key, document the variable name.

> **Note — Why not just publish on npm for free?:**
>
> You could. Selling through Zanora lets agents find the package in discovery and pay per call with receipts, within their owners' spending rules.
