Skip to main content

lap — how many tokens does your API cost an LLM agent?

Point lap at any OpenAPI spec, live MCP server, or your own agent config and get the token cost decomposed (definitions / call / result), a 0–100 grade, the concrete rule violations driving the cost — and an applicable patch for the fixable ones. Neutral, offline-capable, MIT.

pip install "lap-score[mcp]"

The five commands

lap stack                                  # YOUR installed MCP servers: "N tokens before you type a word"
lap score  openapi.json                    # A/B/C token decomposition + the LAP grade
lap lint   openapi.json                    # which rule violations drive the cost (CI-gateable)
lap lint   --mcp "python -m mcp_server_git"   # ...same for a live MCP server (stdio or --mcp-url)
lap fix    openapi.json --apply patched.json  # the fixable findings as an OpenAPI Overlay patch

What that looks like:

$ lap stack
  server        kind   tools  menu tokens  compact
  time          stdio      2          283       31
  git           stdio     12         1418      153
  TOTAL                    14         1701      184
Your agent pays ~1,701 tokens of tool menus at session start - before you type a word.
Compact signatures of the same tools would cost 184 (+89% saved).

$ lap score api/openapi.json
LAP grade: B (72/100)   [menu 100  result 90  hygiene 0]
  variant       A tokens  saved vs full
  openapi_full  418       +0%
  compact_sig   205       +51%
  tool_search   163       +61%
Estimated call size (bucket B): mean ~18 tokens/call ...
Estimated result size (bucket C): GET /books ~465 tokens (list) -> ~305 if projection were added (R1)

$ lap fix api/openapi.json --apply patched.json
[written] lap-overlay.yaml  (6 action(s))
[written] patched.json  (lint findings: 15 -> 3)      # grade: B (72) -> A (91)

lap fix emits a standard OpenAPI Overlay 1.0.0 (R3 → limit param, R1 → fields, R2 → filter, E1 → declared 4XX) — it declares the contract; your server still implements it. lap badge <spec> writes a shields.io endpoint JSON so your README can carry the grade.

CI gates

Every command is --json-able and can fail a build:

lap score openapi.json --gate-form compact_sig --max-menu-tokens 800   # menu too heavy
lap score --diff old.json new.json --max-growth 500                    # this PR bloated the menu
lap lint  openapi.json --fail-on warn                                  # rule violations (--ignore R2,A1 / .lapignore)

…or the bundled composite Action:

- uses: lCrazyblindl/lap@v0.5.0
  with:
    spec: api/openapi.json
    max-menu-tokens: "800"
    fail-on: warn
    badge-path: docs/lap-badge.json   # optional: grade badge JSON

(Prefer Spectral? The same rules ship as a Spectral ruleset.)

Reading the numbers

  • Bucket A (measured) — the tool-definition menu the model carries every session, under four renderings: naive OpenAPI→tools, compact signatures, numbered, lazy tool_search. With fastmcp installed, a real-MCP baseline row too.
  • Buckets B / C (estimated from the schemas) — the call the model emits (required args in a tool-use envelope) and the result that comes back (per response schema, page-size aware, envelope-aware, real example values honored). Structural lower bounds. List responses also get a projected figure — what field projection would save, per endpoint.
  • The grade — menu tokens/operation (weight 0.45) + heaviest result (0.30) + lint findings/operation (0.25), log-scaled; formula. Calibration: LaunchDarkly B, Spotify C, GitHub D, Google Drive F.
  • Tokenizer — offline = tiktoken approximation (absolutes ≈, ordering robust: checked under 4 BPE vocabularies, Kendall τ ≥ 0.992). Set ANTHROPIC_API_KEY for faithful count_tokens figures.
  • Parses OpenAPI 3.x and Swagger 2.0, YAML, allOf/oneOf/anyOf, $refs, non-JSON media types; crash-free across 175+ real APIs.guru specs.

The receipts

Every number and rule has a reproducible measurement behind it: the live leaderboard of 50 real APIs (naive menus total ~11.2M tokens; ~82% recoverable), the LAP profile (every rule cites its experiment), and the state of the field — which vendor claims we verified live, and which our measurements dispute. Issues/PRs: CONTRIBUTING (there's a "Score my API" issue template — disputes welcome).

Module map

file role
openapi_ir.py any OpenAPI (file/URL) → normalized operations
menu.py the menu forms (naive / compact / numbered / tool_search)
estimate.py bucket B/C estimates (+ projection what-ifs)
lint.py / overlay.py rules (OpenAPI + live-MCP M-rules) / lap fix Overlay
grade.py the composite grade + lap badge
stack.py / mcp_client.py / mcp_form.py your MCP stack / live servers / real-MCP baseline
tokens.py / score.py counting backends / the lap score CLI
examples/ bundled sample specs (Bookstore, gnarly 3.1, Swagger 2.0)

Download files

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

Source Distribution

lap_score-0.5.1.tar.gz (51.5 kB view details)

Uploaded Source

Built Distribution

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

lap_score-0.5.1-py3-none-any.whl (43.3 kB view details)

Uploaded Python 3

File details

Details for the file lap_score-0.5.1.tar.gz.

File metadata

  • Download URL: lap_score-0.5.1.tar.gz
  • Upload date:
  • Size: 51.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.0

File hashes

Hashes for lap_score-0.5.1.tar.gz
Algorithm Hash digest
SHA256 472281ca19aeec82a8c2950cc27d7789b802d0b08a7b9cef0557d78df78ef519
MD5 f7fa1e0dbe0c9635d52a2447de92e677
BLAKE2b-256 9a45b40a134d332a97094d391491f41b01df36bcdef31299015556696e3688d2

See more details on using hashes here.

File details

Details for the file lap_score-0.5.1-py3-none-any.whl.

File metadata

  • Download URL: lap_score-0.5.1-py3-none-any.whl
  • Upload date:
  • Size: 43.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.0

File hashes

Hashes for lap_score-0.5.1-py3-none-any.whl
Algorithm Hash digest
SHA256 1723a4151f884f10a87435eed51c3c3d6d4bac8a76069792045c40a0126b145b
MD5 c534a41a668761910b06d6795c6e5ae4
BLAKE2b-256 d215c94c01a8361aaa761b57d13c96d5749338d02c60691a5e45e6f0278b77c9

See more details on using hashes here.

Release history Release notifications | RSS feed

0.8.0

2 files

0.7.0

2 files

0.6.0

2 files

This release

0.5.1 This release

2 files

0.5.0

2 files

0.4.0

2 files

0.3.0

2 files

Supported by

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