@binaryandthread/mcp 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -0
- package/dist/bin.js +1076 -0
- package/dist/bin.js.map +1 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# @binaryandthread/mcp
|
|
2
|
+
|
|
3
|
+
Buy a Binary & Thread heavyweight tee **from inside your AI agent** (Claude, etc.). A small,
|
|
4
|
+
deterministic [MCP](https://modelcontextprotocol.io) server (stdio) exposing **7 read-mostly tools**
|
|
5
|
+
over the same shared Store API client the `bt` CLI uses — so the agent can browse, stage, and
|
|
6
|
+
**hand off** a purchase without ever putting a card in the chat.
|
|
7
|
+
|
|
8
|
+
> The agent can never complete a purchase or set a shipping address. The card is entered by **you**,
|
|
9
|
+
> on the storefront's Stripe page, in your own browser. The MCP just hands you the link.
|
|
10
|
+
|
|
11
|
+
## The 7 tools
|
|
12
|
+
|
|
13
|
+
| tool | what it does |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| `list_products` | the catalog, **text-only** (no per-item images — keeps the agent's context lean) |
|
|
16
|
+
| `get_product` | one tee's specs + its image (rendered **and** the Blob URL as a text floor) |
|
|
17
|
+
| `add_to_cart` | create-or-reuse a cart; returns the `cart_id` as the durable handle |
|
|
18
|
+
| `get_cart` | the authoritative server cart + total (incl. VAT) |
|
|
19
|
+
| `checkout` | mints `{checkout_url, session_id}` **instantly** — never polls, never opens a browser, never sets an address |
|
|
20
|
+
| `check_payment` | polls the session **once**; the agent re-calls at its own cadence |
|
|
21
|
+
| `get_order_status` | status/timeline by display id + exact email (no address; not-found on a mismatch) |
|
|
22
|
+
|
|
23
|
+
## Install / run
|
|
24
|
+
|
|
25
|
+
Distributed via **npx from the verified `@binaryandthread` npm namespace** — published from locked
|
|
26
|
+
CI with **npm 2FA (hardware key) + publish provenance** (signed releases). Always install the
|
|
27
|
+
scoped package; do not trust a bare `bt-mcp` binary from an unverified source (anti-impersonation,
|
|
28
|
+
SECURITY G11/G14/T10/T11). An MCP Registry listing is **deferred** until the API is stable.
|
|
29
|
+
|
|
30
|
+
Zero-config — the server ships pointed at the live store (the store URL + publishable key are
|
|
31
|
+
baked in; the key is public by design). The minimal config is just:
|
|
32
|
+
|
|
33
|
+
```jsonc
|
|
34
|
+
// Claude Desktop / Claude Code MCP config (claude_desktop_config.json or .mcp.json)
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"binary-and-thread": {
|
|
38
|
+
"command": "npx",
|
|
39
|
+
"args": ["-y", "@binaryandthread/mcp"]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Override any of it via `env` for local dev / staging, or to attach your customer token:
|
|
46
|
+
|
|
47
|
+
```jsonc
|
|
48
|
+
{
|
|
49
|
+
"mcpServers": {
|
|
50
|
+
"binary-and-thread": {
|
|
51
|
+
"command": "npx",
|
|
52
|
+
"args": ["-y", "@binaryandthread/mcp"],
|
|
53
|
+
"env": {
|
|
54
|
+
"BT_STORE_URL": "http://localhost:9000", // override the baked-in prod URL (dev/staging)
|
|
55
|
+
"BT_PUBLISHABLE_KEY": "pk_...", // PUBLIC by design — never a secret key
|
|
56
|
+
"BT_REGION": "se", // optional ISO-2; pricing is region-resolved, never hardcoded
|
|
57
|
+
"BT_TOKEN": "..." // optional customer JWT (own scope) — from your keychain, NEVER the chat
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Config (environment only — all optional; env overrides the baked-in prod defaults)
|
|
65
|
+
|
|
66
|
+
| var | required | notes |
|
|
67
|
+
| --- | --- | --- |
|
|
68
|
+
| `BT_STORE_URL` | no | the Medusa Store API base URL (default: production) |
|
|
69
|
+
| `BT_PUBLISHABLE_KEY` | no | the **publishable** key — public by design (default: production; a secret `sk_` key is rejected) |
|
|
70
|
+
| `BT_TOKEN` | no | the customer JWT (own data only); read from the OS keychain / a configured env, **never from the chat** |
|
|
71
|
+
| `BT_REGION` | no | ISO-2 country code to resolve pricing (e.g. `se`); never a hardcoded currency literal |
|
|
72
|
+
|
|
73
|
+
## Security posture (the MCP-specific red-team gates)
|
|
74
|
+
|
|
75
|
+
- **No self-completing purchase (G8 confused-deputy):** `checkout` returns a hand-off URL + session id
|
|
76
|
+
and *says so in its result text* — "I can't complete this for you." The human browser-hop is mandatory.
|
|
77
|
+
- **Cards never in the chat:** there is no card / CVC / PAN field anywhere. The card is entered only on
|
|
78
|
+
Stripe's hosted surface.
|
|
79
|
+
- **Image path is SSRF / token-DoS safe (G9 / CLAUDE.md rule 6):** images are fetched **only** from the
|
|
80
|
+
allowlisted Vercel Blob host (the same constant the CLI uses, in `@binaryandthread/store-client`),
|
|
81
|
+
over https, with a ≤2MB byte cap + a timeout. A non-allowlisted / `data:` / `http:` URL is **never**
|
|
82
|
+
fetched — it degrades to the Blob-URL text floor. List views are text-only.
|
|
83
|
+
- **Untrusted backend strings (G8):** every product title / lore / order note is treated as **data** —
|
|
84
|
+
control-char-stripped, whitespace-collapsed, length-capped — so it can't steer the host agent.
|
|
85
|
+
- **No token / PII in output or logs (G10):** all output passes through the shared redactor; the JWT,
|
|
86
|
+
Authorization headers, and full emails never appear. Diagnostics go to **stderr** (stdout is the MCP
|
|
87
|
+
transport). `get_order_status` returns status only — never a shipping address.
|
|
88
|
+
- **Nothing to escalate (T1/T10):** the tools are thin, deterministic wrappers over `/store/*` only —
|
|
89
|
+
no admin op, no shell, no free-form execution.
|
|
90
|
+
|
|
91
|
+
## Why both an image block *and* a URL
|
|
92
|
+
|
|
93
|
+
Claude renders MCP `ImageContent` natively on claude.ai / the API, but Claude Code has a base64-bloat
|
|
94
|
+
bug ([#31208](https://github.com/anthropics/claude-code/issues/31208), ~15–25k tokens/image) and can
|
|
95
|
+
fail to render it. So `get_product` always emits the **Blob URL as a text block too** — the reliable
|
|
96
|
+
floor. The buy is never blocked on rendering.
|