flori
Integrates with Kagi as the search provider for web research, enabling search and related research tools such as read, open, grep, corpus search/list, and cite.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@florisearch for recent Alzheimer's research and cite the best papers"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
flori
Web research tools exposed over MCP: search, read, open, grep, corpus_search,
corpus_list, cite. See spec.md for the design, DECISIONS.md for the open questions
resolved during the build, and HANDOFF.md for what still needs a Kagi key.
Layout
src/flori/tool server (types, ports, tools module, SQLite store, adapters, MCP wrapper)fetcher/isolated fetch process (OCI image; Crawl4AI, headless Chromium, PyMuPDF)tests/tool-server tests;tests/fetcher/andtests/e2e/need the container upfetcher/tests/fetcher unit tests, runnable on the host
Related MCP server: myscrape
Run
# 1. build and start the fetcher (Docker/OrbStack; Apple container works the same way)
cd fetcher && DOCKER_BUILDKIT=0 /usr/local/bin/docker build -f Containerfile -t flori-fetcher:dev . && cd ..
./scripts/fetcher-up.sh # also starts the test fixture server
# 2. test
uv run pytest # container tests skip if the fetcher is down
(cd fetcher && uv run pytest)
KAGI_API_KEY=... uv run pytest -m live
# 3. serve over MCP (stdio)
KAGI_API_KEY=... FETCHER_URL=http://127.0.0.1:8765 uv run flori
FLORI_TRANSPORT=http FLORI_PORT=8000 uv run flori # streamable HTTP insteadMCP client config (stdio):
{
"mcpServers": {
"flori": {
"command": "uv",
"args": ["run", "--directory", "/path/to/flori", "flori"],
"env": {"KAGI_API_KEY": "...", "FETCHER_URL": "http://127.0.0.1:8765"}
}
}
}Configuration: [tool.flori] in pyproject.toml for non-secrets (search_engine,
db_path, fetcher_url, search_limit); env vars KAGI_API_KEY, FETCHER_URL,
FLORI_DB_PATH, FLORI_SESSION_ID, FLORI_TRANSPORT.
Acceptance
./scripts/fetcher-up.sh
KAGI_API_KEY=... uv run python tests/e2e/acceptance.pyAvailable Tools
7 toolsciteA
Convert an inspected span of a stored page into a citation. Validates that the page is stored and 0 <= start < end <= len(text) within the length cap, records the verbatim span as an EvidenceEntry, and returns it.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | ||
| span | Yes | Character offsets into page.text. |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does well: it discloses validation rules (0 <= start < end <= len(text)), a length cap, and the side effect of recording an EvidenceEntry. It does not cover failure/error behavior or any permission requirements, which keeps it short of a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense sentence that front-loads the core action, followed by validation and side-effect details. No filler, though the validation clause is packed tightly enough that it reads a little heavy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return format need not be explained, and the description still notes it returns an EvidenceEntry. For a two-parameter nested-object tool with no annotations, the validation and side-effect disclosure makes it nearly complete; only error handling is absent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 50% (the span object is documented, url is not), and the description compensates by spelling out the valid offset range and the constraint that the page must be stored. That adds real meaning beyond the schema's terse 'Character offsets into page.text.'
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Convert...into a citation') and a specific resource ('an inspected span of a stored page'), which is far more than a restatement of the name. It is clearly distinct from siblings like search/read/grep, though it never explicitly names a sibling it is not.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'an inspected span of a stored page' implies a precondition (the page must first be inspected/read), which hints at when the tool applies. However, there is no explicit when-to-use, when-not-to-use, or routing against siblings such as read or corpus_search.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
corpus_listC
Retrieve across the accumulated corpus by metadata: URL, domain, length, fetch time, how many searches surfaced the page, how many evidence entries cite it, and its CSL-JSON record.
| Name | Required | Description | Default |
|---|---|---|---|
| filter | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full behavioral burden. It does not say the operation is read-only, whether results are paginated or capped, how they are ordered, or what happens with an empty corpus. It only states that retrieval happens.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single dense sentence with no filler, and the resource is front-loaded. It is appropriately sized for the amount of genuine information conveyed.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so enumerating returned fields (URL, domain, length, CSL-JSON) is redundant, while the actual gap, how the filter argument behaves, is left unaddressed. With no annotations and 0% schema coverage on the only parameter, the definition is not complete enough to invoke the tool confidently.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% for a nested 'filter' object (domain, min_len, cited_only) with defaults, so the description must compensate. Listing 'domain' and 'length' hints at two filter fields, but the filter semantics, default behavior, and the meaning of cited_only are never explained.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The tool retrieves corpus entries and the description names the resource (accumulated corpus) and the available metadata axes. However, 'Retrieve ... by metadata' is ambiguous about whether metadata is the filter or the payload, and it does not distinguish itself from the sibling corpus_search, which an agent would plausibly confuse it with.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no statement of when to use this tool versus corpus_search, grep, or read. Usage is only weakly implied by the word 'list' in the name. No exclusions, prerequisites, or alternatives are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
corpus_searchA
Retrieve across the accumulated corpus by content: ranks all stored pages against
a natural-language query and returns the top k with their best passage.
| Name | Required | Description | Default |
|---|---|---|---|
| k | No | ||
| query | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It does disclose the ranking behavior and that results are passages (best passage per page), which is genuinely useful. However, it says nothing about read-only safety, cost/latency over a potentially large corpus, pagination beyond k, or how ties/scores behave.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single well-formed sentence that front-loads the action ('Retrieve across the accumulated corpus') and then the mechanics and return shape. No filler, no redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be spelled out, and the description is adequate for a simple 2-parameter read tool. The remaining gap is the absent differentiation from sibling retrieval tools, which matters given how many similar siblings exist.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must compensate, and it partially does: 'natural-language query' clarifies the query parameter and 'top `k`' clarifies that k is the result count. It still omits max/min behavior for k, whether k is bounded, and any query syntax constraints.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a specific verb chain (Retrieve/ranks/returns) and a clear resource (the accumulated corpus), plus the output shape (top k pages with their best passage). It distinguishes itself implicitly by being a natural-language ranking retriever, but it never names or contrasts the siblings (search, grep, corpus_list), so an agent must infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: the phrase 'natural-language query' hints that this is for semantic/fuzzy retrieval rather than grep-style literal matching, and 'across the accumulated corpus' hints at corpus-wide scope. There is no explicit when-to-use/when-not guidance and no routing to search or grep, which are the obvious alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
grepA
Query a stored source, or the whole corpus when url is omitted, with a regular
expression. Returns matches with character offsets; results are capped.
| Name | Required | Description | Default |
|---|---|---|---|
| url | No | ||
| pattern | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It usefully discloses that matches include character offsets and that results are capped, which is real behavioral detail. It is silent on error behavior for invalid regexes, permissions, and how the cap is applied or what happens when it is hit.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, front-loaded with the core action and scoping rule, no filler. Every clause adds information the schema does not carry.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be re-explained beyond the offsets and cap note. For a 2-parameter read tool, the description covers the search target, scoping default, input type, and result shape – enough for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must supply meaning, and it does: it explains that `url` selects a single stored source and that omitting it targets the whole corpus, and that `pattern` is a regular expression. It stops short of clarifying the expected format of `url` (URL vs. identifier) and does not describe the default semantics more deeply.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: querying a stored source or the whole corpus via regular expression, plus the url-omission scoping rule. It does not explicitly differentiate itself from regex-adjacent siblings like search or corpus_search, so an agent must infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives one implied usage rule – omit `url` to search the whole corpus – which is genuinely useful context. However, it never says when to prefer grep over `search` or `corpus_search`, nor when-not to use it, leaving alternative selection to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
openB
Inspect a stored source in full: returns a window of the stored page text
starting at offset with up to length characters (capped).
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | ||
| length | Yes | ||
| offset | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full behavioral burden. It does disclose useful non-obvious behavior: the result is a window, `offset` sets the start, and `length` is capped. However, it omits access/permission requirements, what happens on out-of-range offsets, and error behavior, so transparency is only partial.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single sentence that front-loads the purpose and packs the windowing semantics into the same line, with no padding. The only slack is the mildly misleading 'in full'.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be described, and the windowing parameters are covered. Still, for a tool sitting in a six-sibling family with ambiguous names, the definition is not complete enough: it lacks routing guidance and provenance for `url`, and there are no annotations to fill the gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0% and all three parameters are required, so the description must compensate. It meaningfully explains `offset` (start position), `length` (character count, capped), and implies `url` selects the stored source, but it never clarifies what form `url` takes or where it is obtained, leaving one parameter under-specified.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a concrete resource (a stored source's page text) and the exact mechanics of retrieval (a window starting at `offset` of up to `length` characters). It is clear what the tool returns, but it does not distinguish itself from closely named siblings like `read` or `grep`, and the phrase 'in full' sits awkwardly against 'returns a window'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no statement of when to use `open` rather than `read`, `grep`, `search`, or `corpus_search`, and no prerequisites (e.g. that the url must come from a prior search) are given. The agent is left to infer the routing decision entirely.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
readA
Read a discovered source against a goal and capture citable evidence. Fetches
and stores the page on first access (no fetch if already stored), selects the
heading sections around the passages most relevant to goal, records each as an
EvidenceEntry (with the scoring chunk offsets in hits), and returns them.
max_chars bounds the total text returned (500 to 20000). Refuses any URL not
returned by a prior search in this session.
| Name | Required | Description | Default |
|---|---|---|---|
| url | Yes | ||
| goal | Yes | ||
| max_chars | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden, and it does disclose meaningful behavior: fetch-and-store idempotency ('no fetch if already stored'), section-selection around the goal, EvidenceEntry production with hit offsets, the max_chars range, and a hard refusal for unsearched URLs. It stops short of stating storage/auth details or error behavior beyond the refusal.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two dense sentences, front-loaded with the core action before the mechanics, and every clause carries operational information (fetch caching, section selection, hit offsets, max_chars bounds, URL gate). It is slightly packed but not padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With an output schema present, the description needn't describe return shapes, and it appropriately focuses on the preconditions and side effects of the read. Given three parameters and a gated workflow, it covers the essential context an agent needs to invoke this correctly, with only minor gaps around URL/goal formatting.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate and does: max_chars gets a stated purpose and bounds (500–20000), goal gets its role as the relevance axis for section selection, and url gets the implicit constraint that it must originate from a prior search. This adds real meaning beyond bare types, though it doesn't specify url/goal formats.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb+resource ('Read a discovered source against a goal and capture citable evidence') and distinguishes itself from siblings by naming the gate ('Refuses any URL not returned by a prior search') and by hinting at the search/read pipeline. An agent can tell this apart from search, grep, and open.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the workflow constraint (must follow a prior search in this session) which is effectively a precondition and an exclusion, and the goal parameter indicates the usage mode. However it never names an explicit alternative for cases where the URL wasn't from search, so it's clear context but not a full when/when-not/alternatives rubric.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
searchA
Discover candidate sources. Runs a search-engine query and returns URLs with titles, snippets, and engine metadata. Registers each URL as discovered; this is the sole way a URL becomes readable.
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | ||
| since | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full disclosure burden and does well on the non-obvious trait: it explicitly states the side effect that each URL is registered as discovered and that this is the only path to readability. It omits other behavioral context (rate limits, network/auth requirements), which is a gap but not a major one for a search tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the purpose, then behavior, then the key constraint. Every sentence adds a distinct piece of information and nothing is repeated or padded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists, so return values need not be re-explained, and the description usefully still names what comes back. The remaining gap is the undocumented 'since' parameter, but for a two-parameter tool with a rich output schema the description is otherwise complete enough to call correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate for both parameters. It conveys the meaning of 'query' indirectly ('Runs a search-engine query') but says nothing at all about 'since' (the date-time filter), leaving one of two parameters completely unexplained in both the schema and the description.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific action ('Runs a search-engine query') and concrete output ('URLs with titles, snippets, and engine metadata'), plus the higher-level goal ('Discover candidate sources'). It reads clearly as the web-search entry point, but it never explicitly names or contrasts with siblings like corpus_search or grep, leaving the agent to infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage context is implied: 'Discover candidate sources' and 'the sole way a URL becomes readable' signal this is the first step before read/open. However, it gives no explicit when-to-use vs alternatives (corpus_search, grep), no when-not-to-use, and no prerequisites, so the routing guidance is inferential rather than stated.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
7 tool updates
v0.1.0- First observed
cite - First observed
corpus_list - First observed
corpus_search - First observed
grep - First observed
open - First observed
read - First observed
search
TDQS
Scored across 7 tools
Each tool has a fairly distinct role: search discovers URLs, read extracts goal-relevant evidence, open inspects raw windows, grep is regex retrieval, corpus_search/corpus_list retrieve across the accumulated corpus, and cite builds citations. The main soft spot is that read, open, and grep all surface text from stored pages, so an agent must read carefully to pick the right one, but the descriptions differentiate them well.
Most names are bare verbs (search, read, open, grep, cite) while the corpus family uses a prefix (corpus_search, corpus_list), so conventions are mixed. It is still readable and the corpus_ prefix sensibly groups related tools, but there is no single predictable pattern.
Seven tools is well-scoped for a search-read-cite research workflow, with each tool earning a clear place in the pipeline (discovery, reading, inspection, corpus retrieval, citation). No redundancy or padding.
The core research lifecycle is covered: discover sources, read them against a goal, inspect/grep stored text, search the corpus, and create citations. Minor gaps exist, such as no explicit bibliography export, no tool to list/prioritize collected evidence, and no way to unregister a source, but agents can work around these.
Maintenance
Related MCP Connectors
Scrape, crawl and search the web for AI agents via MCP.
Stealth web browser for agents: search, fetch, click, download and type in persistent MCP sessions.
Web search, scraping, RAG answers with citations, and translation as MCP tools.
Web search, fetch, extract, and research for AI agents. Markdown output + AI-synthesized answers.
Related MCP Servers
- AlicenseAqualityAmaintenanceProvides local-first web intelligence over MCP with tools for search, fetch, crawl, extract, cache, find-similar, research, and autonomous agent loops, requiring no API keys.10839 npm5,245AGPL 3.0
- AlicenseNot gradedqualityCmaintenanceA self-contained web-research MCP server that lets local LLM agents search, fetch, and synthesize web content using tools like web_search, web_fetch, and web_research.2MIT
- AlicenseNot gradedqualityAmaintenanceEnables AI agents to perform web research in one tool call by searching, fetching and cleaning full pages, and ranking cited passages. Provides web_research, web_fetch, web_search, and status tools for MCP clients.MIT
- FlicenseNot gradedqualityCmaintenanceEnables AI agents to perform unified web research through a single MCP server, including search, page fetching, recursive crawling, document parsing, YouTube transcript extraction, and deep multi-query research.2-