ToolScope: per-prompt automatic tool selection for LLM tool calling.
Project description
ToolScope
ToolScope is a lightweight, production-ready Tool RAG library for agentic systems.
It solves a core scalability problem in tool-using agents:
As the number of tools grows, LLMs become worse at selecting the right one.
ToolScope fixes this by filtering tools per turn using semantic retrieval — without changing how the model interacts with tools.
No meta-tools.
No retrievers exposed to the model.
No framework lock-in.
Why ToolScope?
When agents see hundreds of tools:
- tool selection accuracy drops
- context windows overflow
- latency increases
- small models break first
ToolScope:
- indexes tool descriptions in a vector database
- retrieves only the most relevant tools per prompt
- hands those tools to the model exactly as before
The model doesn’t know ToolScope exists — it just performs better.
Use ToolScope when:
- you have dozens to hundreds of tools
- tools come from MCP servers or registries
- you want to keep using standard agent frameworks
- you want predictable, debuggable behavior
Quickstart
1. Install
pip install toolscope
(or from source)
pip install -e .
2. Minimal filtering
import toolscope
class TinyEmbedder:
def embed_texts(self, texts):
return [[len(t) % 97, t.count("jira"), sum(map(ord, t)) % 101] for t in texts]
tools = [
{"name": "jira_create_issue", "description": "Create a Jira issue", "inputSchema": {}},
{"name": "confluence_search", "description": "Search Confluence pages", "inputSchema": {}},
]
filtered = toolscope.filter(
messages=[{"role": "user", "content": "Create a Jira ticket"}],
tools=tools,
embedder=TinyEmbedder(),
k=1,
)
print(filtered) # same tools, fewer of them
or, with an embedding configuration (requires sentence-transformers):
import toolscope
embedding_config = toolscope.EmbeddingConfig(
provider="sentence-transformers",
model="sentence-transformers/all-MiniLM-L6-v2",
allow_download=False,
)
tools = [
{"name": "jira_create_issue", "description": "Create a Jira issue", "inputSchema": {}},
{"name": "confluence_search", "description": "Search Confluence pages", "inputSchema": {}},
]
filtered = toolscope.filter(
messages=[{"role": "user", "content": "Create a Jira ticket"}],
tools=tools,
embedding=embedding_config,
k=1,
)
print(filtered) # same tools, fewer of them
3. Indexed (stateful) usage
idx = toolscope.index(
tools,
embedder=TinyEmbedder(),
)
filtered = idx.filter(
messages="Create a Jira ticket",
k=1,
)
Core Concepts and Features
Canonical tools
ToolScope normalizes tools from many schemas into a canonical form:
- name
- description
- input schema
- tags
- fingerprint
Original tool objects are preserved and returned unchanged.
Embeddings
ToolScope supports pluggable embedding backends.
Option A: Provide your own embedder (recommended default)
class MyEmbedder:
def embed_texts(self, texts): ...
Option B: Use EmbeddingConfig (HTTP, OpenAI-style, etc.)
toolscope.EmbeddingConfig(
provider="http",
endpoint="http://localhost:8000/embed",
model="my-embedding-model",
)
ToolScope never downloads models behind your back.
Tool text control
You control what text is embedded:
toolscope.ToolTextConfig(
use_name=True,
use_description=True,
use_schema=False,
truncate=256,
)
Defaults (battle-tested):
- name + description only
- truncate to 256 chars
- no preprocessing
Advanced Features
✅ Allow / deny filters
idx.filter(
messages,
allow_tags=["jira"],
deny_tags=["dangerous"],
)
🔁 Sticky toolsets (multi-turn sessions)
Reuse tools across turns when the query stays similar:
toolscope.StickySessionConfig(
enabled=True,
similarity_threshold_reuse=0.95,
similarity_threshold_refresh=0.8,
sticky_keep=2,
)
This reduces latency and improves consistency.
🧠 Reranking
Boost retrieval quality using a cross-encoder:
toolscope.RerankingConfig(
model="cross-encoder/ms-marco-MiniLM-L-6-v2",
pool_size=20,
)
Not enabled by default — you opt in explicitly.
📊 Observability
Inspect what ToolScope is doing:
tools, trace = idx.filter_with_trace(messages)
print(trace)
Includes:
- candidate counts
- timings
- allow/deny decisions
- reranking effects
Backends
In-memory (default)
Fast, simple, zero dependencies.
toolscope.MemoryBackend()
Milvus Lite
Persistent, scalable local vector DB:
toolscope.MilvusLiteBackend(path="./toolscope.db")
ToolScope is backend-agnostic; more vector DBs can be added.
Adapters (Plug & Play)
ToolScope integrates cleanly with popular agent stacks.
LangChain / LangGraph
- full agent loops
- per-turn tool filtering
- middleware-based integration
from toolscope.adapters.langchain import (
ToolSelector,
make_toolscope_tool_selection_middleware,
)
See:
examples/langchain/
FastMCP
- drop-in MCP client wrapper
- supports multi-server clients
- reacts to tools/list_changed notifications
from toolscope.adapters.fastmcp import ToolScopeFastMCPClient
See:
examples/fastmcp/
License
This project is licensed under the Apache License 2.0.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file toolscope-0.1.0.tar.gz.
File metadata
- Download URL: toolscope-0.1.0.tar.gz
- Upload date:
- Size: 38.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ac6a1cdde96e4c44f66279f3cd57d668a9e57fe56152b58a4acc11fb21841eca
|
|
| MD5 |
3afb87ca9308c8718f4cd341568b5b90
|
|
| BLAKE2b-256 |
4465f80af33a475cc9446ea0a5650906ca2748714c6d739e29c45064525f6031
|
File details
Details for the file toolscope-0.1.0-py3-none-any.whl.
File metadata
- Download URL: toolscope-0.1.0-py3-none-any.whl
- Upload date:
- Size: 39.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
da580077a6d4cd656446620a6a8dad30a1ba9a493f1135331fc37b60bdf34908
|
|
| MD5 |
ac9d205e92eedadbc49982316cca98d7
|
|
| BLAKE2b-256 |
05c16c9b5d4f9d161634dae7bccc9c6ffdce0ce970914a63ad278d17998d5533
|