MCP Tools

The tools skope exposes to Claude over the Model Context Protocol, the API surface of the lens.

When you connect skope to Claude, it gets six tools. Claude calls them on its own, you just talk to Claude. skope owns the deterministic ledger (profile, dedup, rule scoring, the read log, the reachability seed); Claude owns the active collection (searching the web) and the synthesis (the causal-chain narrative). The tools are the seam between the two.

Tools at a glance

ToolRoleNeeds a key
show_profileRead the current interest profileno
update_profileUpsert axes / user context (federation entry point)no
ingest_newsPrimary collection, Claude searches, hands results hereno
scan_newsFallback collection, skope calls TavilyTavily key
get_briefAssemble the two-layer brief from the ledgerno
mark_readMark articles read so they drop from future briefsno

A typical "what's my news today?" turn: show_profile → Claude generates queries across the axes → Claude searches the web itself → ingest_newsget_brief.

show_profile

Returns the current profile, or { configured: false } if none exists yet.

Parameters: none.

Returns: axes (id, label, normalized weight, keywords), user_context (location, languages), and last_scan. An empty profile means setup is needed via update_profile.

update_profile

Upsert the interest profile. This is the federation entry point: read another tool (firma, memex) yourself and feed the result here. skope never calls those tools, it owns the profile as the single source of truth.

ParameterTypeDescription
axesAxis[] (optional)Full axis set to replace the current one. Weights auto-normalize to sum 1.0; capped at 6 axes.
user_contextobject (optional){ location: string, languages: string[] }. Drives geographic reachability and Tier-2 source selection.

Each Axis is { id, label, weight, keywords[], source? }. Pass the full set you want, update_profile replaces, it does not merge per-axis.

A profile needs at least one axis. Passing an empty set is rejected.

ingest_news

The primary, key-less collection path. You search the web with your own tools, then hand the results here. Generate queries from the profile axes; prefer the user's Tier-1/Tier-2 trusted outlets and articles newer than last_scan.

skope then canonicalizes URLs, derives the trust tier from each source, dedups by URL hash (plus a source+title content key for the same story under URL-parameter variants), rule-scores reachability against the profile, and persists to the ledger.

ParameterTypeDescription
articlesArticle[]Web-search results you collected. At least one.
query_contextstring (optional)What you searched for, audit only.

Each article is:

FieldTypeDescription
urlstring (URL)Must be a real http(s) link.
titlestringNon-empty.
snippetstring (optional)Excerpt / description.
sourcestringPublisher domain or name, e.g. "reuters.com".
published_atstring (optional)A date string, ISO-8601 preferred. Best-effort parsed, a bad date drops the field, never the article.

Returns: { received, new, entered_radar, top[] }, how many you sent, how many were new, how many entered the radar, and the top 5 by impact.

scan_news

The fallback collection path, requires a Tavily API key. Use it only when you have no web-search tool of your own, or when you want skope to enforce the trusted-domain whitelist and the 5-call budget. skope calls Tavily with your queries, injects the Tier-1/2 whitelist, then runs the same dedup/score/persist pipeline as ingest_news.

ParameterTypeDescription
queriesstring[]Search queries, one per intent. Capped at 5.
time_rangestring (optional)Window hint: 1d / 1w / 1m / 1y. Defaults to 1w.

Set the key via SKOPE_TAVILY_API_KEY, or skope config set tavily-key <key> (writes ~/.skope/config.json). Without a key, scan_news returns an error pointing you to ingest_news.

get_brief

Assemble the two-layer brief from the ledger, no web fetch. Run ingest_news first if the ledger is stale.

Parameters: none.

Returns:

  • radar, reachability-scored articles with a path to the user, each carrying impact.seeds (the rule-match seed: which axis, which entity, match type, strength).
  • world, top global headlines, shown regardless of relevance.
  • concentration, the Effective-N attention meter.

You render the causal-chain narrative yourself from each article's impact.seeds (e.g. brazil rate hike → USD strength → TSLA valuation) and synthesize the prose. Never persist that narrative back into the ledger, skope stores only the deterministic seed.

mark_read

Record articles as read so they are deterministically excluded from future briefs.

ParameterTypeDescription
urlsstring[]Article URLs the user has seen/read. At least one.

skope hashes each URL to the ledger key. Returns: { marked }.

Why ingest over a built-in fetcher

skope's deterministic value (dedup, trust-tier, rule scoring, Effective-N, the ledger) is computed after fetch, on the article content. So it does not matter who fetched the bytes. Letting the orchestrating LLM collect (it already has web search) keeps skope key-less and frictionless, and is consistent with the rule: collection is active, the ledger is deterministic. Tavily stays as an optional adapter for clients without web search, or those who want the enforced whitelist and budget.