Keenable SELECT lets research agents search the live web with DuckDB SQL
Keenable has published SELECT, an MCP server that lets a research agent search and process the live web from inside a DuckDB SELECT query, using semantic operators that call an LLM per row only when a plain SQL WHERE has narrowed the set.

Image: Keenable
Why it mattersResearch agents can move the read-and-extract work off the model and into the query, so one call can process hundreds of pages under a fixed budget instead of the model spending its own context on each one.
Keenable has published Keenable SELECT, a research agent built on a Model Context Protocol server that runs a single read-only DuckDB SELECT on live web data. The showcase site lists 24 example reports the agent produced between 27 August and 1 September 2026, each with the full trajectory of queries and tool calls attached, and the project appeared on Hacker News on 1 September at 57 points.
What is inside the query
The server exposes one main tool that takes a SELECT statement and returns the rows. Around DuckDB it adds web operators and semantic operators that run inside the query. WEB_SEARCH takes multiple queries at once, merges the ranked results and removes duplicate URLs. WEB_FETCH returns pages as Markdown, one row per URL. Both can also run per row, so an argument can reference a column, for example WEB_SEARCH(name || ' founding year').
The semantic operators are the LLM part. SEM_EXTRACT calls a model once per row to pull one field, or null if the row does not carry it. SEM_EXTRACT_ALL returns a list. SEM_MATCH is a meaning-based WHERE, SEM_SCORE is a low-cost embedding score for ranking, and SEM_NORM gives values with the same meaning the same key so you can GROUP BY them.
The server finds these operators in the parsed statement, runs them outside DuckDB, puts the results back into the row set, and then runs the final SQL. Keenable's own description of the order matters here: exact SQL filters run first, so only the rows that pass the cheap filter reach the LLM operators.
The two agents behind a report
A report in the gallery is produced by two agents. A research agent is a plain tool loop, an LLM with the select tool, that writes and runs queries until it can answer. A second generate_html_report tool takes the brief and the saved result set ids and hands them to a report agent that builds the page in a sandboxed Python session, with the result sets present as dataframes so the model does not retype the data. After each publish the server renders the draft and returns screenshots and a JavaScript error count, and the agent fixes and re-publishes under a fixed budget. Only the final draft stays published.
The interesting part here is where the reading work happens. A traditional web-search tool hands an agent ten links, and the agent then spends its own context reading each page and pulling what it needs. SELECT moves that step into the query, so one SEM_EXTRACT call runs once per remaining row instead of the whole page being paid for in the model's context window. Whether that pattern beats a plain retrieval loop in practice will depend on how well the exact SQL prefilter narrows the set before the LLM operator runs, and the showcase does not yet publish cost or accuracy numbers against a comparable agent. But the design is worth watching, because it is one of the few designs that treats a research agent as a query planner rather than a chat over a page reader.
Source
Keenable SELECT showcase (linked from Hacker News)
This item was written by an AI system from the linked source. Reveneau is responsible for what it publishes.
Get AI News in your inbox
New developer tools, model and agent releases, and how teams are actually using them to release software. Short, and only when there is something worth reading.