feat: v1.3.0 — 6 new tools (batch ops, smart pick, x402, webhooks)#5
Open
ashuran111 wants to merge 14 commits into
Open
feat: v1.3.0 — 6 new tools (batch ops, smart pick, x402, webhooks)#5ashuran111 wants to merge 14 commits into
ashuran111 wants to merge 14 commits into
Conversation
Adds v1.3.0 audit + design pass for the next minor of the MCP server. No implementation logic — stubs only. All v1.2.x tools untouched. Proposed new tools (6 net-new + 2 additive hints): - virtualsms_buy_batch — purchase 1-20 numbers in one call - virtualsms_wait_for_sms_batch — collect SMS for N orders in parallel - virtualsms_find_best_pick — single-shot decision with country pool/exclude - virtualsms_pay_and_buy — x402 deposit-first one-shot (Pattern B) - virtualsms_x402_info — money-path capability discovery - virtualsms_subscribe_webhook — outbound event delivery - virtualsms_manage_webhooks — list/delete/test/deliveries combined Backward compat: zero breaking changes for 1.2.x clients (locked via schema snapshot test in Task 1 of the plan). See docs/v1.3.0-design.md for full design + alternatives considered. See docs/v1.3.0-plan.md for the bite-sized 13-task implementation plan. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds Vitest + a backward-compat snapshot test that pins the name + inputSchema + annotations + description prefix of every tool that shipped in v1.2.x. Any change to one of these fields breaks this test, which means the change broke a 1.2.x client contract. v1.3.x must be additive — new tools only, never edit the 18 v1.2.x ones. Setup: - vitest 2.x as devDep - npm scripts: test, test:watch - vitest.config.ts (include tests/**/*.test.ts) - tsconfig excludes tests/ from production build (dist/ stays clean) Snapshots committed at tests/__snapshots__/. Per docs/v1.3.0-plan.md Task 1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the backend client methods that v1.3.0 tools dispatch through.
No MCP wiring yet — that lands in Tasks 3-9.
Methods:
- getX402Info() — discovery, no api key required
- topup({amount_usd, payment_method,
payment_proof?}) — two-step x402 settlement
- listWebhooks()
- createWebhook({url, events, ...})
- deleteWebhook(id)
- testWebhook(id)
- getDeliveries(id)
- createOrderBatch(service, country, n) — Promise.allSettled fan-out
Types added: X402Info, X402Manifest, X402TopupResult, Webhook,
WebhookDelivery, BatchPurchaseResult.
The 402-on-manifest-path is handled by catching the AxiosError and
returning the manifest body — same pattern x402-fetch uses on the
client side.
Per docs/v1.3.0-plan.md Task 2.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the v1.3.0 stub with real impl. Wires into both stdio (src/index.ts) and StreamableHTTP (src/http-server.ts) transports. Behavior: - Pre-flight balance × cheapest_price guard. If count × price > 80% of balance → returns budget_guard error WITHOUT charging anything. - Backend dispatches via client.createOrderBatch (Promise.allSettled fan-out). Partial failures aggregate into failed[]. - Returns succeeded[] + failed[] + total_charged_usd + remaining_balance_usd + tip pointing at wait_for_sms_batch. - stop_on_failure flag is annotated in the response when set; actual early-stop requires a backend batch endpoint (parking-lot item). TOOL_DEFINITIONS layout: split into TOOL_DEFINITIONS_V1_2_X (locked, snapshot test enforces) + V1_3_TOOL_DEFS (additive). Public surface TOOL_DEFINITIONS = concat of both. Schema snapshot test still GREEN — proves the v1.2.x contract is unchanged. Per docs/v1.3.0-plan.md Task 3. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the v1.3.0 stub. Wires into both stdio + StreamableHTTP transports. Behavior: - Per-order WebSocket race vs polling (5s interval) with shared per-order deadline. WS tries first if api key present; on close or error, falls back to polling for the remaining time. - Aggregates into received[] / timed_out[] / errors[] via Promise.allSettled. No partial failure throws. - return_partial=false → top-level error if anything missed, with the same arrays for inspection. - Each received[] entry: order_id, code, sms_text, delivery_method (instant|websocket|polling), elapsed_ms. Schema snapshot test still GREEN. Per docs/v1.3.0-plan.md Task 4. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…exclude Replaces the v1.3.0 stub. Wires into both stdio + StreamableHTTP transports. Behavior: - listCountries → filter by country_pool whitelist + country_exclude blacklist - checkPrice each (batched 10 at a time, Promise.allSettled, skip OOS) - Score per `prefer`: - cheapest: normalized 1 - (price - min) / range - most_stock: stock binary (0/1) - balanced: 0.7 × price_inverse + 0.3 × stock_signal (default) - Plain-English `reasoning` string explains why pick beat runner-ups (cheapest among pool / X% above cheapest but better stock / etc.) - runner_ups: top 3 alternatives - error: "no_pick" with tip when nothing in stock Schema snapshot still GREEN. Per docs/v1.3.0-plan.md Task 5. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the v1.3.0 stub. Wires into both transports.
Behavior:
- Wraps client.getX402Info()
- Maps backend networks[] → agent-friendly accepts[] with
{network, asset, min_usd, max_usd, pay_to}
- Solana network → solana_relayer pay_to; everything else → evm_relayer
- patterns[] derived: "topup" if topup_endpoint present, "sms-verify"
if resource present (deprecated server-side but surface if leaked)
- Top-level: enabled, x402_version, accepts, min/max/default_topup_usd
CRITICAL — defends against BNB/BSC leakage:
DISABLED_NETWORKS = {bsc, binance, bnb}. Even if a self-hosted backend
returns these, accepts[] strips them. Backed by Vault memory
project_x402_wallet_setup: BNB disabled until Permit2 ships in settler.
Backend 503/missing endpoint → unsupported_on_this_backend error,
no throw.
Schema snapshot still GREEN.
Per docs/v1.3.0-plan.md Task 6.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the v1.3.0 stub. Wires into both transports.
Two-step protocol:
- First call (no payment_proof) → returns 402 manifest from
client.topup({ amount_usd, payment_method }). Tip points to
x402-fetch / wallet to sign.
- Second call (with payment_proof) → topup succeeds, returns
api_key + credited balance. If service+country provided in
the same call, the handler instantiates a fresh client with
the new api_key and bundles createOrder.
Failure isolation: if the bundled buy fails after a successful
topup, response is paid_buy_failed with the api_key still surfaced
so the caller never loses the deposit.
Service/country validation runs BEFORE topup — refuses one-of-pair
input as input_error without charging.
Schema snapshot still GREEN.
Per docs/v1.3.0-plan.md Task 7.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the v1.3.0 stub. (Wiring lands with manage_webhooks in the next commit so transports get both webhook tools at once.) Behavior: - Wraps client.createWebhook - Pre-flight: balance.low requires positive threshold_usd. Refused client-side as `threshold_required` — saves a backend 4xx. - Returns webhook_id, secret (HMAC-SHA256), active flag, created_at - tip points caller at the manage_webhooks(action:"test") flow to fire a synthetic event and verify the endpoint Schema snapshot still GREEN. Per docs/v1.3.0-plan.md Task 8. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the v1.3.0 stub. Wires both subscribe_webhook AND manage_webhooks into stdio + StreamableHTTP transports. Behavior: - action enum dispatches to the right backend route: - list → GET /api/v1/customer/webhooks - delete → DELETE /api/v1/customer/webhooks/:id - test → POST /api/v1/customer/webhooks/:id/test - deliveries → GET /api/v1/customer/webhooks/:id/deliveries - webhook_id required for delete/test/deliveries — enforced at the zod refine layer - Each branch returns a tip explaining the next move (e.g. test failed → check deliveries; no deliveries yet → fire test event) Schema snapshot still GREEN. Per docs/v1.3.0-plan.md Task 9. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ZERO breaking changes — schema-snapshot test still GREEN. handleGetBalance now returns: - balance_usd (unchanged, original field) - topup_url (NEW — points at dashboard topup) - x402_topup_available (NEW — boolean from getX402Info) - tip (NEW, conditional — only when balance < $1) handleBuyNumber now returns: - order_id, phone_number, expires_at, status, tip (unchanged) - webhook_subscribe_hint (NEW, conditional — only when no sms.received webhook exists for this api key) Webhook lookup is cached for 30s in a module-level singleton. Bursty agents calling create_order in tight loops only pay one listWebhooks() round-trip per minute regardless of QPS. Test-only export _resetWebhookCacheForTests() for hermetic tests. Per docs/v1.3.0-plan.md Task 10. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- package.json + server.json: 1.3.0 - src/index.ts (main + sandbox) + src/http-server.ts (per-request + server-card payload): version bumped to 1.3.0 - CHANGELOG.md: new [1.3.0] section listing 6 new tools, 2 additive enhancements, backward-compat note, snapshot-test reference, vitest tooling note - README.md: tagline + Why-VirtualSMS bullet + footer updated to "24 tools". New "What's new in v1.3.0" callout after the virtualsms-io#1 ranking banner Schema-snapshot test still GREEN — proves zero breaking changes. Per docs/v1.3.0-plan.md Task 11. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New runnable example demonstrating the canonical v1.3.0 batch agentic pattern: subscribe_webhook → buy_batch → wait_for_sms_batch → manage_webhooks(action:"deliveries"). - examples/04-batch-buy-with-webhook/run.mjs — 4-step orchestrator, degrades gracefully when WEBHOOK_URL unset (skips webhook steps, still demos buy_batch + wait_for_sms_batch). - examples/04-batch-buy-with-webhook/README.md — env-var contract, expected console output, HMAC verification pseudocode for the receiver. Per docs/v1.3.0-plan.md Task 12. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Status: implementation complete, ready for review
v1.3.0 of the VirtualSMS MCP server. Six new tools + two additive enhancements, locked behind a v1.2.x backward-compat snapshot test.
This PR went from design-only stubs → fully wired implementation in 12 atomic commits following the 13-task plan in
docs/v1.3.0-plan.md.What shipped
6 new tools (18 → 24 total):
virtualsms_buy_batchPromise.allSettledoverPOST /api/v1/customer/purchasevirtualsms_wait_for_sms_batchvirtualsms_find_best_pickGET /api/v1/priceiteration with0.7 × price_inverse + 0.3 × stock_signalforprefer='balanced'virtualsms_x402_infoGET /api/v1/x402/info(BSC/BNB defensively stripped — Permit2 not yet shipped)virtualsms_pay_and_buyPOST /api/v1/x402/topup(two-step: manifest → settle) + bundledcreate_ordervirtualsms_subscribe_webhookPOST /api/v1/customer/webhooksvirtualsms_manage_webhooksactionenum/api/v1/customer/webhooks/:id2 additive enhancements (zero break):
virtualsms_get_balance→ addstopup_url+x402_topup_available(and a low-balancetipwhen balance < $1)virtualsms_create_order→ addswebhook_subscribe_hintfor long-running agents (suppressed when one already exists; cached 30s)Backward compatibility — guaranteed
tests/v1_2_3_schema_snapshot.test.tssnapshots the name +inputSchema+annotations+ description prefix of every v1.2.x tool. The snapshot stays GREEN through every commit in this PR — proving zero breaking change for existing 1.2.x clients.Internal layout:
TOOL_DEFINITIONS_V1_2_X(locked) +V1_3_TOOL_DEFS(additive) → publicTOOL_DEFINITIONS = [...V1_2_X, ...V1_3].Testing
npm test+npm run test:watchscriptstsc) excludestests/sodist/stays cleanCommits in this PR (12 atomic, in order)
Wiring — both transports
The 7 new tools are dispatched on both stdio (
src/index.ts) and StreamableHTTP (src/http-server.ts) — guards against the v1.2.2 dispatch bug (commit 1da145b) where 6 tools were defined but only registered on stdio.What's also new
examples/04-batch-buy-with-webhook/— runnable end-to-end demo of the canonical v1.3.0 batch agentic pattern (subscribe → buy_batch → wait_for_sms_batch → manage_webhooks deliveries audit). Degrades gracefully whenWEBHOOK_URLis unset.[1.3.0] - 2026-05-01section.server.json+package.json— both bumped 1.2.3 → 1.3.0.What's NOT in this PR (parking lot — design doc §10)
/purchase/batch(would let MCP drop the loop)wait_for_sms_batchuse 1 socket)After merge — registry republish
Per existing
reference_mcp_registry_publishrunbook:mcp-publisheragainstregistry.modelcontextprotocol.ionpm publishfrom CITest plan
npm run buildclean — exit 0npm test— 59/59 green🤖 Generated with Claude Code