Agentic Search
Agentic Search helps agents answer questions when the answer is not in the first chunk returned by retrieval. Instead of searching again and hoping for a better result, the model can work inside the corpus: search to find a source, open it, move through nearby chunks, grep for exact terms, and search again without repeating chunks.
In short, retrieval finds likely sources. Agentic Search lets the model inspect those sources and gather enough evidence to answer. You can use it as a set of Model Context Protocol (MCP) tools that drop into any agent, or as part of the Search Toolkit SDK for custom retrieval pipelines. It works with the indexes you run with Search Toolkit, and you can connect it to Studio agents as a Connector.
Retrieval primitives and the agentic loop
Agentic Search is not another retrieval method next to keyword or semantic search. Keyword and semantic search are retrieval primitives. Agentic Search is an orchestration layer that uses those primitives, adds navigation, and iterates until the model has enough evidence.
| Layer | How it works | Best for |
|---|---|---|
| Keyword (lexical) | Matches exact terms or phrases | Known identifiers, code, exact quotes |
| Hybrid or semantic retrieval | Combines keyword and vector search, or uses vector search alone | Natural-language questions over a corpus |
| Agentic Search | Calls retrieval tools, navigates inside documents, excludes already-seen chunks, and searches again | Complex questions that require source verification or evidence across documents |
Most production search setups start with hybrid retrieval because it combines keyword precision with semantic recall. Agentic Search builds on that foundation: search uses semantic or hybrid retrieval, and grep adds targeted keyword matching inside a specific document.
How Agentic Search works
Agentic Search runs a retrieval loop. The model doesn't stop at the first chunks it receives: it can inspect a result, read the surrounding context in the source document, then search again with what it learned.
- Search: The model runs a query across the collection and receives the most relevant chunks.
- Inspect: The model picks a promising hit and reads the surrounding context within that document, without re-running a global search.
- Grep: The model searches for an exact term or phrase inside the same document to jump to a more specific region.
- Navigate or read: The model steps through adjacent chunks or reads a known source range to gather evidence.
- Re-query: With the new context, the model runs another search with
exclude_idsso that chunks it already saw don't come back.
The loop continues until the model has enough evidence to answer the question. exclude_ids makes corpus-level pagination possible: the agent can move through new results instead of cycling over the same chunks.
The model calls the following tools inside the loop. The search and navigation tools return chunks with their id, source_id, content, score, and start_offset and end_offset positions. ingest and delete return a status message.
| Tool | What it does |
|---|---|
search(query, top_k, exclude_ids) | Runs semantic or hybrid retrieval across the collection. Pass exclude_ids to avoid returning chunks the agent already inspected. |
open(chunk_id, window) | Expands context around a chunk returned by search. Returns the chunk and up to window adjacent chunks on each side, in reading order. |
navigate(source_id, start_offset, end_offset, direction, top_k) | Steps forward (next) or backward (previous) through a document from a known position. |
read(source_id, start_offset, end_offset, top_k) | Reads the chunks of a known source range, without expanding context. Leave an offset empty to read from the start or to the end of the document. |
grep(source_id, pattern, mode, top_k) | Lexical search for an exact phrase (phrase, the default) or for all terms in any order (term) within a single document. |
ingest(uri) | Adds a document to the index. Accepts a local file or directory path, a file:// URI, or an http(s):// URL. |
delete(source_id) | Removes a document and all its chunks from the index. |
Agentic navigation requires a NavigableIndex. When you define your schema migration, set IndexingMode.DOCUMENT_PER_CHUNK so that chunks carry source offsets and can be walked in order.
A Search Index is also a navigable index: it exposes navigate, read, grep, and get_chunk on its API. For details, see Navigate, read, and grep.
Get started with the starter app
To try Agentic Search, start from the search-starter-app template. It is a Copier template that scaffolds a project with ingestion pipelines, a Vespa search index, an MCP server exposing the navigation tools, and sample data.
The starter app is designed to be driven by an agent. You scaffold the project, start Vespa, then launch an agent such as Vibe that discovers the MCP server and calls the search and ingestion tools through natural language.
Before you start, make sure you have the following:
- A Mistral API key from console.mistral.ai
- Docker with Docker Compose, to run Vespa locally
- uv for Python package management. The setup command runs Copier through
uvx, so you don't need to install it. - Vibe or any MCP-compatible agent, to drive the search loop
Scaffold and start the index
Create a new project from the template, then start Vespa and apply the schema migrations. Use the tabs to copy the commands or inspect the generated structure.
uvx copier copy gh:mistralai/search-starter-app my-search-project
cd my-search-project
make setup-vespaCopier asks for the search backend, your Mistral API key, a collection name, and a deployment name for the workflow examples. Keep the default vespa backend: the rest of this page uses Vespa. The make setup-vespa target starts a Vespa container with Docker Compose and deploys the schema migrations. When it finishes, the search index is ready.
Ingest and search with an agent
The starter app registers the MCP server for Vibe in .vibe/config.toml. When you launch Vibe in the project directory, it discovers the server and its seven tools. Use the tabs to start Vibe, ingest a document, then ask a question.
vibe --trustVibe detects the MCP server and the search skill. To check the connection, run /mcp, which lists the server and its tools.
You can also run ingestion and search directly from the shell with make ingest path=sample_data/hello.txt and make search query="hello world". The MCP server is the recommended path for agentic workflows.
Use Agentic Search as MCP tools
The MCP server exposes seven tools that any MCP-compatible agent can call. The starter app registers the server so that Vibe discovers it, but you can also connect it to Studio or to a custom agent.
The server starts automatically when Vibe launches in the project directory. To run it standalone, use the tab that matches your transport mode.
uv run python -m entrypoints.mcp_serverUse stdio mode for local agents such as Vibe.
Register the server with an agent
- Vibe: The
.vibe/config.tomlfile in the generated project registers the server. Runvibe --trustin the project directory and Vibe discovers it. - Studio: Run the server in HTTP mode at a URL that Mistral can reach, then register that URL, ending in
/mcp, as a Connector. A server on127.0.0.1or in stdio mode can't be registered. - Custom agents: Connect any MCP-compatible client to the server's stdio or HTTP endpoint. Clients that read
.mcp.jsonpick up the stdio command from that file.
The MCP server includes instructions that describe the retrieval loop: start with search, drill into results with open, grep, navigate, and read, then call search again to connect information across documents. The search tool describes exclude_ids, so the agent can skip the chunks it already read.
To scope a search to a single document, include the document title or source_id in the query. This narrows the global search.
Use Agentic Search with the SDK
If you need more control than the MCP server provides, build the loop yourself with the Search Toolkit SDK. The MCP tools map onto methods of the search index: search and retrieve find relevant chunks across the index, and navigate, read, grep, and get_chunk work inside a document. The SDK requires Python 3.12 to 3.14.
The SDK snippets build from the smallest setup to a full loop step. Use the tabs to open the index, run a search, then gather evidence around a hit.
from mistralai.search.toolkit.mistral_search_index import MistralSearchIndexService
index = await MistralSearchIndexService().get_search_index("exampledocs")Ingest documents
The ingestion pipeline loads files, extracts text, splits it into chunks, optionally enriches them, generates embeddings, and indexes the result. The starter app routes files by extension: text files use plain-text extraction, and everything else uses Mistral OCR. Use the tabs to compare the two extractor paths.
from mistralai.search.toolkit.ingestion.pipelines import Pipeline
from mistralai.search.toolkit.ingestion.loaders import FilesystemFileLoader
from mistralai.search.toolkit.ingestion.extractors import PlainTextExtractor
from mistralai.search.toolkit.ingestion.text_splitters import (
MarkdownTextSplitter,
MarkdownTextSplitterConfig,
)
pipeline = Pipeline(
loader=FilesystemFileLoader(),
extractor=PlainTextExtractor(),
text_splitter=MarkdownTextSplitter(
MarkdownTextSplitterConfig(chunk_size=4096, chunk_overlap=50)
),
embedder=embedder,
stores=vector_store,
)
total = await pipeline.run(documents=["doc.txt"], use_checkpoint=False)
print(f"Indexed {total} chunks.")You can also ingest documents through the MCP server's ingest tool, which accepts local paths, file:// URIs, and HTTP URLs. The server picks the extractor from the file extension.
Latency and tradeoffs
Each tool call adds latency and tokens. Navigation helps the agent avoid repeated broad searches: it can stay inside the right source, use grep to jump to specific terms, and use exclude_ids to avoid revisiting the same chunks.
For background on Search Toolkit, see Introducing Search Toolkit.
To keep the loop efficient, follow these practices:
- Use
exclude_idson follow-up searches so the agent sees new chunks instead of repeated results. - Scope searches to a single document by including its title or
source_idin the query. - Use
grepbefore broad re-querying when the agent already knows the term or phrase it needs. - Tune
top_kper hop to keep context windows manageable. - Bound the number of hops in your agent definitions to limit the loop depth.
Integrate into agents, workflows, and deployments
- Agents: Register the MCP server as described in Register the server with an agent. With Vibe, run
vibe --trustin the project directory, then run/mcpto check the connection. - Workflows: The starter app includes ingestion workflows for Mistral Workflows in
src/examples/workflows/. Start the worker withmake start-examples, then start an ingestion withmake execute-ingestion file_path=sample_data/hello.txt. Searches stay direct and don't go through a workflow. - Deployments: Self-host the index with Vespa and Docker, or use a managed backend. Expose the MCP server in HTTP mode behind your own authentication for production agents. To snapshot the Vespa application package for CI reproducibility, run
make generate-vespa-lock.
Next steps
- Search Toolkit: learn about ingestion pipelines, retrieval strategies, and the full SDK.
- Libraries: use managed document ingestion and search for built-in RAG.
- Connectors: connect models and agents to external tools and data sources.
- Agents: combine language models with built-in tools for multi-step reasoning.
- search-starter-app: the Copier template for bootstrapping a Search Toolkit project.