Skip to main content

Billing SDK for MCP servers

Project description

metrify

Billing SDK for MCP servers. Add pay-per-call monetization to any MCP tool in under 5 minutes — no payment infrastructure required.


Quickstart

1. Register as a provider

Sign up at the Metrify dashboard and get your pk_live_... provider key.

2. Install the SDK

pip install metrify

3. Configure your provider key

export METRIFY_PROVIDER_KEY="pk_live_your_key_here"

Or pass it directly in code (see step 4).

4. Decorate your tools and register them

from metrify import Metrify

m = Metrify()  # reads METRIFY_PROVIDER_KEY from env

@m.tool(price=0.01, unit="per_call")
async def summarize(consumer_api_key: str, text: str) -> str:
    """Summarize a block of text."""
    # Balance is pre-checked before this runs; charge happens only on success
    return f"Summary of: {text[:50]}..."

# On startup, push all decorated tools to the Metrify dashboard:
await m.register_tools()

register_tools() is idempotent — run it every time your server starts. Tools with no docstring get description=None; pass description= explicitly to override:

@m.tool(price=0.05, unit="per_call", description="OCR a PDF page")
async def ocr_page(consumer_api_key: str, page_url: str) -> str:
    ...

5. Deploy

Your tool now charges consumers on every call. The consumer_api_key is extracted automatically by the decorator — consumers pass it as the first argument or as a keyword argument.


Full example with FastMCP

from metrify import Metrify
from mcp.server.fastmcp import FastMCP

m = Metrify(provider_key="pk_live_your_key_here")
server = FastMCP("my-mcp-server")

@server.tool()
@m.tool(price=0.05, unit="per_call")
async def analyze_document(consumer_api_key: str, content: str) -> str:
    """Analyze a document and return insights."""
    # billing.charge() runs before this line
    analysis = await run_analysis(content)
    return analysis

@server.tool()
@m.tool(price=0.001, unit="per_token")
async def generate_text(consumer_api_key: str, prompt: str) -> str:
    """Generate text from a prompt."""
    result = await llm.complete(prompt)
    return result

Billing flow

The decorator runs a two-phase billing flow on every call:

  1. Pre-check — verify the consumer has enough balance (no charge yet).
  2. Execute — run your tool function.
  3. Charge — deduct only if the function completed without error.

If the function raises any exception the consumer is never charged.

Exception reference

Exception Raised by Behavior
InsufficientBalanceError Pre-check Propagated — consumer has no funds
UpstreamError Your tool Caught — returns message to consumer, no charge
ProviderSuspendedError Pre-check / charge Propagated — your account is suspended
ConsumerSuspendedError Pre-check / charge Propagated — consumer account is suspended
ProviderNotFoundError Pre-check / charge Propagated — your provider key is invalid
GatewayError Pre-check / charge Propagated — network error or backend 5xx
Any other Exception Your tool Caught — returns "Tool error: ...", no charge

Signalling upstream failures with UpstreamError

Use UpstreamError when an external API your tool depends on fails. The decorator catches it, skips billing, and returns your message to the consumer:

from metrify import Metrify, UpstreamError

m = Metrify()

@m.tool(price=0.05, unit="per_call")
async def summarize(consumer_api_key: str, text: str) -> str:
    try:
        result = await anthropic_client.messages.create(...)
    except anthropic.APIError as e:
        raise UpstreamError(f"Anthropic API error: {e.message}")
    return result.content[0].text

The consumer receives "Anthropic API error: ..." and is not charged.

from metrify.exceptions import InsufficientBalanceError, GatewayError

# In your MCP server error handler:
try:
    result = await my_tool(consumer_api_key=ck, query=q)
except InsufficientBalanceError:
    return "Insufficient balance. Please top up at the Metrify dashboard."
except GatewayError:
    return "Billing service temporarily unavailable. Please retry."

Environment variables

Variable Default Description
METRIFY_PROVIDER_KEY Your provider key (pk_live_...)
METRIFY_GATEWAY_URL https://airy-wholeness-production-fcc4.up.railway.app Override backend URL
METRIFY_MCP_URL Public URL of your MCP server (e.g. https://myserver.railway.app/mcp)

Supported billing units (V1)

All units charge a flat price per call. The unit field is displayed in your dashboard for reporting purposes.

Unit Use case
per_call Fixed price per tool invocation
per_token LLM completions (flat in V1)
per_minute Audio/video processing
per_image Image generation or analysis
per_page Document processing

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

metrify_sdk-0.2.1.tar.gz (13.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

metrify_sdk-0.2.1-py3-none-any.whl (7.7 kB view details)

Uploaded Python 3

File details

Details for the file metrify_sdk-0.2.1.tar.gz.

File metadata

  • Download URL: metrify_sdk-0.2.1.tar.gz
  • Upload date:
  • Size: 13.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.8.4

File hashes

Hashes for metrify_sdk-0.2.1.tar.gz
Algorithm Hash digest
SHA256 a8f44968cd2155c62508256fe9b927e7d34a241ba54429bbdc15ad6a819a7068
MD5 abbf23bc0b8bbccdc4a69085df11b3a5
BLAKE2b-256 1354211154899c628faa44da9ffe57b8188bc7809640c039b54e76702c356df0

See more details on using hashes here.

File details

Details for the file metrify_sdk-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: metrify_sdk-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 7.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.8.4

File hashes

Hashes for metrify_sdk-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 a6f1454dd302af72476981ff8937ecb1e7da9b7fa992d705009d83c4858e4481
MD5 0b971d6ccf6b53d4ec88e29de6ac9ad6
BLAKE2b-256 675abeb6125275f73b3c867564c2a72a25fbf9d34c20265096e84c5cdf4d3b0a

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page