@kvidzibo/pi-web-access
Native Pi extension for keyless web search, URL fetching, and cached content
Package details
Install @kvidzibo/pi-web-access from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:@kvidzibo/pi-web-access- Package
@kvidzibo/pi-web-access- Version
0.3.0- Published
- Oct 30, 2026
- Downloads
- 724/mo · 203/wk
- Author
- kvidzibo
- License
- MIT
- Types
- extension
- Size
- 67 KB
- Dependencies
- 3 dependencies · 2 peers
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-web-access
Search the web, fetch pages as Markdown and inspect cached results in the Pi coding agent, without supplying search API keys. Revisit long results in chunks or find a passage without fetching the page again.
No GitHub clone, PDF, video or curator UI.
| tool | job |
|---|---|
web_search |
Exa MCP, DuckDuckGo HTML fallback |
fetch_content |
this machine GETs the URL, Readability → markdown |
get_search_content |
page/find cached full text |
Security: Pi extensions run with your full system permissions. Search and content requests hit the public internet from this machine. A local SSRF gate blocks private/loopback/link-local/special-use IPs, URL credentials, and non-http(s), rechecks every redirect, and pins DNS lookup to the connecting socket (no second resolve). Install only from a source you trust.
Quick example
After installing, ask Pi:
Search nodejs.org for the Node.js test runner documentation.
Fetch the relevant documentation page as Markdown, then use
get_search_content with the fetch responseId to find "node --test".
Include the source URL in your answer.
The tool sequence is search → fetch → inspect the cached text:
web_search:{ "query": "Node.js test runner documentation", "domainFilter": ["nodejs.org"], "numResults": 3 }fetch_content, using a relevant result URL (for example):{ "url": "https://nodejs.org/api/test.html" }get_search_content, using the ID returned by that fetch:{ "responseId": "REPLACE_WITH_FETCH_RESPONSE_ID", "findText": "node --test" }
Replace the placeholder with the actual responseId. These are example arguments, not captured results. Search and fetch need public network access; the final lookup reads the local cache, whose entries expire after one hour. Provider availability and limits still apply even without API keys.
Design trade-off: HTTP fetching and Readability extraction avoid launching a browser, but do not execute page JavaScript. Use pi-browser when content needs interaction or rendering. See fetch handling, HTML extraction and extraction tests.
Install as a Pi extension
Requires Node.js 22.19+ and Pi; native loading is tested with Pi 1.4.0. This README tracks repository source. npm packages and Git tags may be behind it. Version 0.3.0 removes the standalone MCP server and its executable. Finish old gateway work and remove its web service/package entries before loading this extension; do not load both backends. Existing cached results remain usable.
pi install npm:@kvidzibo/pi-web-access
Git:
pi install git:github.com/kvidzibo/pi-web-access
Local checkout — Pi adds the path only; it does not run npm install for local sources:
cd /absolute/path/to/pi-web-access
npm install --omit=peer
pi install /absolute/path/to/pi-web-access
pi install of npm or git sources installs the HTML extraction dependencies.
Pi supplies @earendil-works/pi-coding-agent and typebox; no compilation or
standalone server is needed. Exa's outbound search protocol is still used directly
over HTTP; no local MCP server or MCP SDK is involved.
Do not also list this path in settings.json extensions — package load is enough.
Then /reload (or restart Pi).
HTTP handling
- Unsupported final HTTP status codes (outside 200–599), protocol upgrades, and response-conversion failures become request errors instead of terminating Pi.
HEAD,204,205, and304responses have no body. - Gzip, deflate, and Brotli are decoded as streams (up to three stacked encodings). The 2,000,000-byte response limit applies after decoding. Invalid encodings and truncated bodies are errors; unused streams are canceled.
- The 30-second request timeout and cancellation include waiting for DNS. A canceled lookup cannot start an HTTP connection afterward.
- Redirects discard cross-origin credentials and stale Host headers. POST-to-GET redirects also discard the body and its headers; HEAD remains HEAD on a 303.
Readable Markdown resolves relative links and image sources against the final fetched URL, including a valid HTML <base> element. Fragment anchors and non-HTTP links remain links only; extraction never fetches them.
Search and errors
Use queries for batches of up to 4 searches (500 characters per query), or
urls for up to 20 fetched URLs (2,048 characters per URL). numResults accepts
1–20 results per query, defaulting to 5.
Domain filters are sent to both providers and enforced on returned URLs; multiple allowed domains use OR. DuckDuckGo uses its date filter for recencyFilter; Exa receives a relative-date query hint, not a guaranteed date constraint. Empty matching results are identified explicitly.
A failed query no longer discards successful queries from the same batch. A provider timeout ends that query without fallback; later queries still run. Caller cancellation stops the batch and does not cache canceled results. All-failed batches and invalid tool arguments throw errors in Pi; partial results remain available. All-failed batch errors include a cache response ID for inspection with get_search_content.
Cache
~/.pi/agent/web-access-cache (dir 0700, files 0600). Entries expire after 1 hour. Expired and over-quota files are deleted when the extension loads and on store/get. Inactive leftover files can remain until the next load.
get_search_content returns up to 30,000 characters per page; use offset and
limit to continue. To search instead, pass findText without offset or limit.
Caps: 128 entries, 128 MiB. Case-insensitive and fuzzy match offsets refer to the original UTF-16 text, even when Unicode lowercasing changes its length.
Development
index.ts is the native Pi entry point; src/tools.ts registers tools. Search providers and fallback live in src/search/; URL policy, pinned transport, redirects, and bounded body reading are separated in src/network/. Page extraction and caching live in src/pages.ts, src/html.ts, and src/cache.ts. Tests are in tests/, with Pi loader checks in tests/load/.
npm ci --omit=peer
npm test # unit + native factory load (needs `pi` on PATH)
npm run test:unit # no Pi required
CI runs both suites with Pi 1.4.0. The default suite uses fixtures and loopback servers, never the public network. Optional live smoke:
WEB_ACCESS_LIVE=1 node --test --experimental-strip-types tests/live.test.ts