registerFree when a tool should stay free up to a per-customer cap you declare in code. Exhaustion uses the same paywall gate as a paid tool. This path is TypeScript SDK only. Managed MCP public tools stay unlimited.
Who this is for
Teams that register MCP tools withcreateSolvaPayMcpServer and want a preview, trial, or otherwise-free tool that still converts into a paid plan when the cap is reached.
What you will achieve
- A free MCP tool with a per-customer cap declared next to the tool
- One shared allowance when several tools name the same free meter
- The existing paywall gate on exhaustion, so hosts recover the same way they recover a paid tool
Prerequisites
- A product with at least one paid plan so the gate can show a plan ladder
- An identified customer (OAuth, or your own
getCustomerRef). Unidentified callers fail with401/identity_required— there is no anonymous bucket
Register a capped free tool
CallregisterFree inside additionalTools. Omitting meter defaults to free-requests.
registerFree counts usage and, on exhaustion, returns the gate before your handler runs — you do not add cap arithmetic in the handler.
scope is rolling_window (pass windowDays) or lifetime (anchored at the customer’s createdAt). billing_period is not valid here because a free-tool caller typically has no purchase cycle to anchor.
Share one allowance across tools
Naming the samelimit.meter is the whole sharing mechanism. Two tools on free-previews draw from one counter. A tool that names its own meter gets a private allowance.
/^free-[a-z0-9-]+$/. It is a naming convention, not a Meter you create in the Console. Do not register a billable meter with a free- name — the backend rejects that collision.
If two tools name the same meter but disagree on cap, scope, or windowDays, registration throws. Hand the same object to both.
Per-tool attribution still rides metadata.toolName on each usage event, so Usage in the Console can still break the shared allowance down by tool.
What happens at the cap
The sixth call (in the example above) never reaches the handler. The result isisError: false with paywallReason: 'limit_reached', used / limit on the free meter, and the product’s plan ladder. Hosts render recovery the same way they render a paid-tool gate. Call account with view: "checkout", or activate_plan when a planRef is known.
Included vs free
The Console usage page splits successful calls into three kinds. Keep them distinct:
A free allowance is not plan-derived. Do not call it included. Free usage does not reduce a customer’s paid remaining.
Managed MCP
Public tools on Managed MCP stay unlimited. There is no Console setting for this cap. If you need a per-customer free allowance that converts to a paid plan, use the TypeScript SDK path on this page.Verify
- Call the free tool under the cap — the handler returns data.
- Exhaust the cap — the next call is a
limit_reachedgate with a plan ladder. - If two tools share a meter, mix the calls and confirm they drain one counter.
- Call a paid tool for the same customer and confirm its remaining is unchanged.
preview_market_quote and preview_company_profile on a shared free-previews allowance. See that repo’s SMOKE_TEST.md for the mixed-tool walkthrough.
Next related tasks
- MCP Server integration —
registerPayableand the factory - Usage events — recording usage from your app
- Monetize an MCP server with SDK integration