MCP server for NOSTR marketplace publishing. Two dialects in one server: NIP-15 stalls + products (kind:30017/30018) for NIP-15-native clients, AND Shopstr-modern shop profile + NIP-99 classified listings (kind:30019/30402) with automatic Shopstr cache-POST so the events surface on shopstr.store. Built on NDK; nsec or NIP-46 signer.
Strong schema definitions with detailed parameter constraints and clear descriptions. All 7 tools have explicit input schemas with type definitions, descriptions, and validation rules (minLength, maximum, enums, format). Tool names follow verb_noun pattern (create_or_update_*, list_*, confirm_*). Descriptions are comprehensive (150-300 chars), explaining WHAT the tool does, WHEN to use it, and prerequisites. However, output schemas are not documented, LLMs cannot predict response structure. Error handling is mentioned in descriptions ('safety pipeline') but recovery guidance is absent. No tool annotations (readOnlyHint/destructiveHint) despite clear read/write distinction.
Execute a previously-prepared marketplace publish, identified by its one-time token. Only meaningful when NOSTR_REQUIRE_CONFIRM=true. Single-use token; the safety pipeline re-runs before signing. For Shopstr-modern tools (kind:30019/30402), the Shopstr cache POST hook is re-attached automatically.
Create or update a NIP-15 product (kind:30018) within a stall. The `stall_id` must match an existing stall's `id`. The `id` is the product's parameterized-replaceable d-tag — republishing with the same id replaces it. `categories` are surfaced as `t` tags for discoverability. Runs the safety pipeline (read-only, signer, rate limit, optional confirm).
Create or update a NIP-15 marketplace stall (kind:30017). The `id` field is the parameterized-replaceable identifier — publishing with the same id replaces the prior stall on relays that honor replaceability. Shopstr is the canonical UI for these events. Runs the safety pipeline (read-only, signer, rate limit, optional confirm).
Fetch + parse the current signer's NIP-15 products (kind:30018). Returns each product's event id, created_at, `d` tag, category `t` tags, and parsed JSON (name, description, price, currency, stall_id, etc.). Optionally filter by stall_id (applied client-side after fetch — NOSTR relays don't index the JSON content). Products with non-JSON or schema-invalid content are returned with `parsed: null`.
Output schemas not documented. LLMs cannot predict response structure for list_my_stalls, list_my_products, or confirm_publish. Descriptions mention 'returns' but do not specify field names, types, or structure.
No tool annotations (readOnlyHint, destructiveHint, idempotentHint). Risk field is present in metadata but not exposed to LLM via MCP tool annotations. LLMs cannot distinguish safe reads from destructive writes without explicit hints.
Error recovery guidance missing. Descriptions mention 'safety pipeline' and 'rate limit' but do not explain what happens on failure or how to recover. No actionable error messages documented.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 59 | 2026-07-28+ | v2 |
Fetch + parse the current signer's NIP-15 stalls (kind:30017). For each stall event found on the configured relays, returns the event id, created_at, `d` tag, and the parsed stall JSON (name, description, currency, shipping). Stalls that don't pass the NIP-15 schema are returned with `parsed: null` so you can see what's wrong.
Create or update a Shopstr-modern NIP-99 classified listing (kind:30402). All product data lives in tags; `content` is the long-form description. After relay publish, the event is POSTed to Shopstr's cache endpoint so it surfaces on shopstr.store/marketplace. Requires the `["t", "shopstr"]` tag for marketplace visibility. Runs the safety pipeline (read-only, signer, rate limit, optional confirm) plus the Shopstr cache hook.
Create or update a Shopstr-modern shop profile (kind:30019). The `pubkey_hex` becomes the `d` tag — one shop per pubkey. After relay publish, the event is POSTed to Shopstr's cache endpoint so it surfaces on shopstr.store. Runs the safety pipeline (read-only, signer, rate limit, optional confirm) plus the Shopstr cache hook.
Naming ambiguity: 'marketplace_shopstr_create_or_update_*' tools use a namespace prefix that may confuse LLMs about whether they are variants or separate systems. Consider 'shopstr_create_or_update_*' or 'create_or_update_shopstr_*' for clarity.
confirm_publish token parameter lacks format guidance. Description says 'one-time token' but does not specify format (UUID, hex, length). LLMs may hallucinate invalid tokens.