Skip to main content

mcp-lens

Progressive disclosure for large MCP tool catalogs.

CI License Python Spec Status

Quick Start · Spec · Examples · Contributing

Most MCP servers expose one tool per endpoint. That works until your catalog grows — 20 endpoints becomes 20 tool definitions loaded into every context window, 200 becomes 200, and the model starts guessing wrong between similarly-named tools long before you get there.

mcp-lens is a small, dependency-light pattern (and a Python reference implementation) for the alternative: expose exactly 3 stable meta-tools — search_capabilities, get_capability_schema, execute_capability — no matter how many capabilities sit behind them. The tool-definition cost the model pays is O(1) in catalog size; only what search_capabilities actually returns grows with your catalog.

from mcp_lens import Capability, CapabilityRegistry, build_server

registry = CapabilityRegistry()
registry.register(
    Capability(
        key="billing.create_invoice",
        description="Create an invoice for a customer",
        input_schema={
            "type": "object",
            "properties": {"customer_id": {"type": "string"}, "amount": {"type": "number"}},
            "required": ["customer_id", "amount"],
        },
        executor=lambda customer_id, amount: {"invoice_id": "INV-001", "amount": amount},
    )
)
# ...register 5, 50, or 5,000 more capabilities the same way...

mcp = build_server(registry, name="my-server")
mcp.run()

Whether registry holds 1 capability or 5,000, the MCP client always sees the same 3 tools.

Why this, specifically

  • The registry has no MCP dependency. mcp_lens.registry is plain Python — testable, reusable, and swappable behind any transport. The FastMCP adapter in mcp_lens.server is a thin, optional layer on top.
  • Search is pluggable. The default matcher is keyword substring matching, fine for demos. Pass your own search_fn to CapabilityRegistry for Postgres full-text, embeddings, or whatever search backend you already run — the 3-tool contract doesn't change.
  • It's a spec, not just a library. SPEC.md defines the contract (tool names, schemas, semantics) independently of this implementation, so it can be implemented in other languages and still interoperate conceptually.
  • Validated with real traffic, not just a thought experiment — this pattern (search → schema → execute) has been running in production MCP servers before this repository existed; this is the extracted, product-agnostic version of that mechanism.

Installation

Add mcp-lens to a new or existing Python project with uv:

uv add mcp-lens

Or with pip:

pip install mcp-lens

Installing from source — track main:

uv add "mcp-lens @ git+https://github.com/helygp/mcp-lens.git@main"

Quick Start

1. Define your capabilities

A Capability is a key, a description, a JSON Schema for its input, and a callable (sync or async) that runs it:

from mcp_lens import Capability

def get_weather(city: str) -> str:
    return f"Sunny in {city}"

weather = Capability(
    key="weather.get_weather",
    description="Get current weather for a city",
    input_schema={
        "type": "object",
        "properties": {"city": {"type": "string"}},
        "required": ["city"],
    },
    executor=get_weather,
    tags=("weather", "forecast"),
)

2. Register them

from mcp_lens import CapabilityRegistry

registry = CapabilityRegistry()
registry.register(weather)
# or: registry.register_many([weather, other_capability, ...])

3. Serve them

from mcp_lens import build_server

mcp = build_server(registry, name="my-server")

if __name__ == "__main__":
    mcp.run()

Run the checked-in example instead of writing your own from scratch:

uv run examples/basic/server.py

See examples/README.md for the full walkthrough, including the token-cost comparison in examples/benchmark/.

Learn more

  • SPEC.md — the formal contract: tool names, schemas, semantics, and what's deliberately left out of scope (auth, persistence, discovery UI — those are yours to build).
  • examples/ — a runnable 5-capability example server and a before/after token-cost comparison as the catalog grows.
  • CONTRIBUTING.md — how to propose changes, including changes to the spec itself.

This pattern isn't new — Twenty CRM uses a similar fixed-meta-tool approach for its MCP server, and "don't load every tool definition up front" is an increasingly common idea across the MCP ecosystem as catalogs grow. What mcp-lens adds is not the idea itself but: a formal, implementation-agnostic contract for it (SPEC.md), a tested reference implementation with the MCP-specific parts cleanly separated from the reusable core, and measured numbers for the tradeoff instead of just the claim. If you know of other implementations of this pattern, a PR adding them here is welcome.

Non-goals

mcp-lens is deliberately narrow. It does not provide: authentication, capability persistence/storage, an approval or review UI, or AI-assisted onboarding of new capabilities. Those are real, useful things to build on top of this — but they're product decisions, not part of the protocol pattern this repo exists to document and implement.

Contributing

git clone https://github.com/helygp/mcp-lens.git
cd mcp-lens
uv sync --group dev
uv run pytest
uv run ruff check

See CONTRIBUTING.md for the full workflow.

Citation

If mcp-lens or the pattern in SPEC.md is useful in your work, you can cite the repository:

@software{mcp_lens,
  title  = {mcp-lens: Progressive disclosure for large MCP tool catalogs},
  author = {Pasqual, Hely},
  year   = {2026},
  url    = {https://github.com/helygp/mcp-lens}
}

License

Apache 2.0. See LICENSE.

Metadata

Release files for mcp-lens-py 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for mcp-lens-py 0.1.0
File Size Uploaded
mcp_lens_py-0.1.0.tar.gz 16.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for mcp-lens-py 0.1.0
File Interpreter ABI Platform
mcp_lens_py-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 28.1 kB

Release files / mcp_lens_py-0.1.0.tar.gz

Download URL mcp_lens_py-0.1.0.tar.gz
Size 16.4 kB
Tags Source
SHA-256 checksum
How to use checksums
8386fab3230703db5b544834aa33d27e43cf4781faa14fd6df2dbfc086d9552c
BLAKE2b-256 checksum
How to use checksums
8643b7883fd260f51b545bc32a8d0db2d0c22d2cc6ec4bbf712050316c362120
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release files / mcp_lens_py-0.1.0-py3-none-any.whl

Download URL mcp_lens_py-0.1.0-py3-none-any.whl
Size 11.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
daeb4c06a5da9b3a224fc0eaa655d6b851bbaff7f5bab3a8625d1a78cfb566b0
BLAKE2b-256 checksum
How to use checksums
b272f83a2adfbea7b274592dcee0def3d779cb45152a52fe045c1d6be4561676
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.13

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page