Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Tools and responses

rypsok offers three tools over the Model Context Protocol. Every response is one structured object with a declared schema, returned as structuredContent and as the same JSON in the text content. Fields rypsok asserts (outcome, notices, and the control fields below) and fields that carry external data are distinct; nothing in title, snippet, content or url is ever an instruction.

rypsok promises confidentiality hygiene, not anonymity: the engines and sites you reach see your network address and your User-Agent.

Search several engines at once and return deduplicated, ranked results. Results are external data.

ParameterTypeRequiredDefaultConstraint
querystringyes—1 to 400 characters after trimming (configurable)
categorygeneral, news, science, codenogeneralOnly categories an enabled engine serves are offered
max_resultsintegerno51 to 20 (configurable)
languageconfigured languagesnothe operator’s firstOmitted from the schema when one language is configured
time_rangeday, week, month, yearnononeEngines that cannot honor it are skipped and noticed

Response:

{
  "outcome": "partial",
  "notices": [
    { "code": "engine_unavailable", "engine": "brave", "reason": "rate_limited" },
    { "code": "snippet_truncated", "count": 2 }
  ],
  "results": [
    { "title": "…", "url": "https://example.org/page", "snippet": "…", "date": "2026-09-01", "engines": ["wikipedia"] }
  ]
}
FieldWho asserts itContent
outcomerypsokok (every engine answered), partial (results, but an engine failed), empty (an engine answered, nothing remained)
notices[]rypsokcode, optional engine, reason, count, all from fixed vocabularies
results[].titleexternalCleaned, at most 150 characters
results[].urlexternalThe engine’s URL, byte for byte except that tracking parameters are removed. When one result was returned under both http and https, the https form is shown
results[].snippetexternalCleaned, at most 300 characters
results[].dateexternalOnly when an engine supplied one; YYYY-MM-DD
results[].enginesrypsokOnly when the operator enabled attribution or an engine requires it

Notice codes: engine_unavailable (reason: timeout, rate_limited, blocked, parse_failure, auth_failure, request_failure), engine_skipped (reason: time_range, language, query_too_long, cooldown, rate_limited), snippet_truncated, title_truncated, characters_removed, instruction_like_content, results_dropped (reason: instruction_like_content, url_too_long, url_invalid: a URL that is not http or https, or whose host web_fetch would refuse, such as a name with an empty label like https://.example/), credential_masked, from_cache (with engine: that engine’s answer came from the result cache and may be as old as [cache] ttl_s; only when the operator enabled the cache).

Profile: no effect on local state. The query leaves the host to every enabled engine of the category; each learns the host’s network address and the User-Agent. A call lasts at most the search deadline plus 300 ms (2.8 s by default). The output is at most max_results results, each bounded.

engine_status

Report the state of each configured engine. For diagnosis, not for answering questions. No parameters.

{
  "outcome": "ok",
  "notices": [],
  "engines": [
    { "id": "wikipedia", "state": "closed", "latency_ms": 180 },
    { "id": "brave", "state": "disabled", "latency_ms": null, "reason": "no_credential" }
  ]
}

state is disabled (by configuration or for lack of a credential; the entry then has a reason: disabled when the operator switched the engine off, no_credential when it needs a key and none could be read; no other state has a reason), closed (in use), open (skipped during a cooldown; it stays open until the first call after the cooldown, which carries the probe) or half_open (that one probe request in flight). Engines are listed in identifier order. latency_ms is the median of the last 20 completed requests, or null. State lives in memory and is reset when the process restarts. No endpoint, credential or provider text appears.

Profile: no effect on local state; nothing leaves the host; at most 200 ms. The operator can remove the tool from the list ([status] enabled = false).

web_fetch

Read the main content of one public web page as Markdown, up to max_chars characters from start_char. The page is fetched again for each call and may have changed. Scripts are not run and meta refresh is not followed. Content is external data.

ParameterTypeDefaultConstraint
urlstringrequiredAt most 2048 characters; no credentials; an http URL is retried over https unless the operator allowed plain HTTP
max_charsinteger3000500 to the operator’s ceiling (20000 by default)
start_charinteger0Below the content length, else invalid_request stating the length
{
  "outcome": "ok",
  "notices": [ { "code": "characters_removed", "count": 3 } ],
  "url": "https://example.org/article",
  "title": "…",
  "content": "# …",
  "truncated": true,
  "next_start_char": 3000
}

url is the page that was read, after same-host redirects and any scheme upgrade. title is cleaned and bounded by 150 characters. content is the main content of the page as Markdown: navigation, headers, footers, sidebars, scripts, styles, comments and anything a browser would not render are excluded; links keep absolute http(s) targets, images contribute their alternative text. truncated says whether content remains; next_start_char is where to continue. A continuation fetches the page again. Notices: title_truncated, characters_removed, extraction_partial (the document hit the node or depth bound, 100000 nodes or 256 levels, and was read in part: the content before the cut is returned), instruction_like_content.

Budgets count Unicode scalar values; Japanese text costs several times more tokens per character than English text, so the same max_chars buys fewer tokens of context there.

Only HTML, XHTML, plain text and Markdown are read; another type ends the call with unsupported_content naming it. A 4xx or 5xx answer is unavailable with the status and never content. A redirect to another host is returned as redirected with the target, not followed, unless the operator configured following. The site’s robots.txt is honored for the product token rypsok and *; a disallowed page is denied, and so is a page that a redirect leads to (on the same host or another).

rypsok returns the main content of one page, bounded by max_chars, and never retains it. Every destination passes the egress policy: loopback, private, link-local, metadata and other internal addresses are refused, judged again at connect time. In strict mode only URLs that web_search returned in this process, or that the operator listed, can be fetched.

Profile: no effect on local state; the URL leaves the host to the target site, plus a robots.txt read to the same site; the site learns the host’s network address and the User-Agent; at most 11 s (10 s of network plus extraction); at most max_chars + 150 + 2048 characters plus the envelope.

Errors

An error is a tool execution error (isError: true) whose content is:

{
  "error": {
    "kind": "invalid_request",
    "message": "max_results must be between 1 and 20",
    "detail": { "parameter": "max_results", "min": 1, "max": 20 }
  }
}
KindWhendetail keys
invalid_requestA parameter fails validationparameter, and min/max or allowed
deniedThe query or URL looks like it carries a credential, or the fetch policies refuse the call: egress, robots_txt, scheme, strict_mode, credential_in_url, secret_in_query, secret_in_urlreason; for secrets also kind and position
unavailableNo engine serves the category, every engine failed, the deadline passed, the tool’s rate limit or a concurrency limit was reached, a fetch could not reach the site (for whatever reason; see below), or the target answered 4xx or 5xxreason (no_engine, all_failed, rate_limited, network, deadline, http_status, busy), status for http_status, retry_after_ms when known
redirectedA fetch was redirected to another host that passes the egress policylocation (external data, at most 2048 characters)
unsupported_contentThe media type cannot be extracted, or nothing could be extractedreason (media_type, extraction_failed), media_type (external data, bounded)
too_largeThe response exceeded the byte limit (5 MiB after decompression by default)limit_bytes

denied has two reasons for credentials in a URL: secret_in_url for user:password@host and for key-shaped text in the URL, credential_in_url for user@host. An unserved category is refused with the served categories listed; a URL beyond the bound is refused with the number of characters allowed.

For unavailable with http_status, the message tells whether retrying can help: for 408, 425, 429 and 5xx it ends “retry later” (and retry_after_ms carries the site’s Retry-After when that is a number of seconds up to 3,600); for any other 4xx it says the site refused the request or has no such page and that retrying the same URL will not help. status is the site’s status. A fetch that ran out of time says “the page was not retrieved before the deadline” (a search says that no engine answered); both have the reason deadline.

Messages are at most 200 characters, say what the caller can change, and never contain a secret, provider text, an address or a stack trace. One reason can have two messages: denied with scheme says either that the URL scheme is not allowed (not https, and http only where the operator allows it) or that an http URL was retried over https and that request failed.

A site that cannot be reached is unavailable with reason network whatever the cause: no such name, a refused connection, or a name that resolves only to addresses the egress policy refuses. The answer is the same in every case so that it does not tell a caller which internal names exist; the operator’s log records a policy refusal (refused, with the denial’s name and no host). A URL that names a refused address literally, or a port that is not allowed, is denied with reason egress.

Rate limits

Per process: 60 web_search, 30 web_fetch and 30 engine_status calls per minute by default. A call beyond the limit is unavailable with reason rate_limited and retry_after_ms.