Metadata-Version: 2.4
Name: robinsaige
Version: 0.5.0
Summary: Check the dependency rating of an MCP tool before your agent calls it. A thin, dependency-free client for the Robin Saige observatory.
Author: Robin Saige
License: MIT
Project-URL: Homepage, https://robinsaige.com
Project-URL: Spectrum, https://robinsaige.com/spectrum
Project-URL: Method, https://robinsaige.com/method
Keywords: mcp,agents,tools,trust,rating,verification
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Intended Audience :: Developers
Requires-Python: >=3.8
Description-Content-Type: text/markdown

# robinsaige

**Check the dependency rating of an MCP tool before your agent calls it.**

Humans build agents; agents call tools they've never seen. This is a thin, **dependency-free**
client for [Robin Saige](https://robinsaige.com) — a neutral observatory that probes ~10,000 MCP
servers and publishes what they actually are: alive or dead, honest or drifting, a real server or one
of 1,300 costumes on a single operator. Ask it *before* you depend on a stranger's tool.

```bash
pip install robinsaige
```

## Read a rating

```python
import robinsaige

r = robinsaige.check("io.github.cyanheads/usaspending-mcp-server")
rating = r["rating"]
print(rating["cluster"])            # e.g. "mid-solo"
print(rating["distinctiveness"])    # 0 = typical, 1 = highly unusual
print(rating["reach"], rating["use"], rating["trust"])
```

Every figure is a **percentile or class within the ~10,813-server census** — a dated observation,
not a warranty. What it does *not* claim is spelled out in `rating["not_claimed"]`.

## Find the right tool

Don't know the name? Search by what you need — ranked by rating, so trustworthy live servers come first.

```python
res = robinsaige.find_tools("US tariff data")
for r in res["results"][:5]:
    print(r["cluster"], r["server"], r["matched_tools"])
```

## Gate a tool call

Put a `TrustGate` in front of tool dispatch. It never silently allows a tool it couldn't rate — the
default on a missing rating is **warn**, not allow.

```python
from robinsaige import TrustGate, Blocked

gate = TrustGate()                        # sensible default policy

d = gate.assess("some.registry/name")
if d.ok:
    call_the_tool()                       # allow or warn
else:
    skip_it(d.reason)                     # blocked: dead-listing / unreachable / not-mcp / rate-limited

# or enforce — raises Blocked on a blocked cluster:
try:
    gate.guard("some.registry/name")
except Blocked as b:
    ...
```

## Report how a call went (the tap)

Reading a rating and contributing one are the same install. Wrap a tool call in `gate.tap(...)` — it
times the call and fire-and-forgets a report on exit. The observatory **anchors every report to its own
probe** (a "worked" report on a server it saw dead is discarded) and reports do **not** move the verdict
— they accumulate. Reporting failures are swallowed; the tap never breaks your agent.

```python
with gate.tap("some/server", tool="lookup") as t:
    result = call_the_tool()
    t.ok = looks_good(result)     # optional; defaults to "no exception raised"
```

Policy is yours to widen or narrow:

```python
gate = TrustGate(
    block={"dead-listing", "unreachable", "farm-costume"},   # refuse these
    warn={"stale-thin-solo", "auth-walled"},                 # warn on these
    on_missing="block",                                      # unrated = refused
)
```

## Command line

```bash
robinsaige pulse                       # the whole ecosystem at a glance
robinsaige find tariff                 # discover a server by name fragment
robinsaige check io.github.you/mcp     # full rating (JSON)
robinsaige gate io.github.you/mcp      # ALLOW / WARN / BLOCK  (exit 2 if blocked)
robinsaige lock a/one b/two            # pin the verdicts you depend on -> robinsaige.lock
robinsaige verify                      # CI gate: exit 1 degraded, 2 blocked/missing
```

## Gate your CI on it

Pin once, verify every build — the build fails when a tool your agent depends on dies,
gets blocked, or degrades:

```yaml
# .github/workflows/robinsaige.yml
name: robinsaige verify
on:
  pull_request:
  schedule: [{cron: "17 7 * * *"}]   # daily: catch degradations between PRs
jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pip install robinsaige
      - run: robinsaige verify        # reads robinsaige.lock at the repo root
```

`robinsaige verify --warn-ok` tolerates allow→warn transitions; block/missing always fail.
The lockfile pins a dated observation, not a warranty — verify re-derives from the live
observatory every run.

## What the clusters mean

`dead-listing` a registry entry pointing at a 404 · `farm-costume` many names, one operator ·
`walled-opaque` a login with no legible challenge · `stale-thin` old protocol, few tools ·
`rich-fast-solo` a large, quick, independent server. Browse them all at
[robinsaige.com/spectrum](https://robinsaige.com/spectrum).

## Honesty

Robin Saige is a **signal, not a gate** — it publishes its method and raw data so you can recompute
and disagree. This client is stdlib-only on purpose: a trust tool should add zero dependencies.
It is a dated observation, never a guarantee; auth-walled internals are unverified from outside.

MIT licensed.
