What Matters Powered by Claude

The MCP connection

What Matters speaks Model Context Protocol, so an AI assistant can read your list and suggest changes to it. This page is the whole of how that works.

Nothing lands without you

An assistant working on a schedule — overnight, or while you are away — cannot change your list. It writes a proposal, and you see every suggestion with its reason before anything happens: accept them, reject any line, or edit the wording first.

Direct writes exist for the other case — you are in a conversation, you say "add that", and you are right there to see the result. The split is enforced by the tools themselves, not by a setting you could forget.

The tools

get_document

Reads

Returns the whole list — every item with its section, priority and due date, plus the standing rules and the suggestions already declined. Every run starts here.

put_proposal

Proposes

Replaces the pending set of suggested changes. This is the only write a scheduled run makes: nothing in a proposal reaches the list until the account holder reviews and accepts it.

add_item

Writes

Adds one item immediately. Meant for live conversation, when the person is there to see the result — not for autonomous runs, which propose instead.

complete_item

Writes

Marks an existing item done, keeping the record that it was completed rather than dropped.

manage_rule

Writes

Creates, pauses or deletes a standing rule — "stop suggesting anything from that channel" — taking effect at once. A scheduled run proposes rules instead of setting them.

Connecting

  1. Sign in, open Connections, name a connection and generate a token.
  2. Copy the connection URL it shows you. It is shown once and cannot be retrieved later.
  3. In Claude — or anything else that speaks MCP — add a custom connector and paste that URL. There is nothing else to configure.

Authentication

A connection is a long-lived bearer token you mint yourself. There is no OAuth flow to complete and no client to register. The token can travel in the path or in a header — whichever your client supports:

https://matters.blackdogranch.com/mcp/<token>

Authorization: Bearer <token>

The token resolves to one account, and every tool builds its view from that account alone — no tool takes a user as a parameter, so there is nowhere to put someone else's. Revoking a connection kills its token immediately.

The guide your assistant reads

Every connected assistant is handed this text, in full, as the guide://what-matters resource. It is reproduced here exactly as served — not summarised — so what the model is told and what you were told cannot come apart.

What Matters is the user's personal list of action items.

THE SECTIONS — every item lives in exactly one:
  • action  — something the user owes someone or themselves. The next move is
              theirs.
  • waiting — something owed TO them. They are blocked; the next move is not
              theirs.
  • note    — worth knowing, no action attached.
Choosing between action and waiting is the distinction the whole app rests on:
if the ball is in someone else's court, it is waiting, not action.

The document has a "settings" object — the user's UI preferences, synced across
their devices (e.g. hide_done). It is not part of the list: never set, propose
or mention it; no delta can touch it and none should try.

There is no "today" section. Today is DERIVED from an item's due date — anything
dated today or earlier is pulled out of its section and shown at the top. So set
"due" only when there is a real deadline; a speculative date drags an item to the
top of their day for no reason.

CHANNEL describes where an item ORIGINATED — self, teams, email, meeting, other —
not who typed it. An item you add from an email thread is still "email". This is
what makes an item legible to them days later.

PRIORITY is low, medium or high, and defaults to medium. Leave it at medium
unless you have a specific reason — the list shows a marker only for high and
low, precisely so the exceptions stand out. Use "high" when someone is blocked
on them or a real deadline is close, and "low" for things that genuinely can
wait. If you mark most things high, the field stops carrying any information
and they lose the one signal that told them where to start.

NOTE vs LINKS — these are different fields and mixing them up makes the list
worse:
  • note  — prose they read. Context, the reason something matters, what was
            agreed. Do not paste URLs in here.
  • links — up to 3 entries, each {"label", "url"}. Somewhere they go: the Teams
            thread, the document, the ticket. The label is what gets displayed,
            so write "the signed contract", never the raw URL and never
            "click here". http and https only.
A URL buried in the note renders as a wall of text; the same URL in "links"
renders as a button. When you have both context and a destination, write the
context in "note" and the destination in "links".
This applies just as much when you CHANGE an existing item as when you add one:
an update delta's "patch" carries the same "note" and "links" fields, and links
replaces the whole list, so include any existing ones worth keeping.

THE TWO WRITE PATHS, and the difference matters:
  • Scheduled or autonomous runs: get_document, then put_proposal. Nothing you
    propose reaches their list until they review and accept it. This is the path
    to use whenever you are working on a schedule rather than in conversation.
  • The user asking you directly, in conversation: add_item and complete_item
    write straight through, because they are right there to see the result.

INITIATED — every add_item call declares who set it in motion, and there are
exactly two accepted values:
  • "human" — the user asked for this item in the current conversation. "The
    user" means whoever is talking to this MCP server right now, not one
    specific person — this server serves more than one account.
  • "auto"  — you are adding it on your own initiative, with no direct
    instruction from the user.
Populate it truthfully; nothing infers it for you, and the app trusts what you
say.

THE URGENT PUNCH-THROUGH: add_item with initiated "auto" AND priority "high"
immediately sends a native push notification to the user's phone ("Added
urgently by your AI" plus the title). This is the ONE sanctioned way an
autonomous run may bypass put_proposal review — for something that genuinely
cannot wait for the user's next review, someone-is-blocked-right-now urgent.
The interruption is the feature, so spend it carefully: an autonomous add that
can wait belongs in put_proposal, and marking routine things urgent teaches the
user to ignore the one signal that means look now. Human-initiated adds never
notify (the user is in the conversation and already knows), and auto adds at
medium or low priority land silently for the next review. The user can switch
this notification off per device in the phone's Settings.

On any auto add, ALWAYS stamp source_id when the thing came from a message or
event with a stable id. It is what lets your NEXT run — and the nightly
proposal pass — recognise the item as already handled instead of pinging or
proposing it again. An urgent add without a source_id can only be matched by
its title, which you are told to reword.

A PROPOSAL IS A LIST OF DELTAS. Four kinds, and picking the right one matters:
  • add      — something the user does not have yet.
  • complete — they have already DONE this: the meeting happened, the reply
               went. This is almost always the right verb when something looks
               finished. It keeps the record that they completed it.
  • remove   — clear it WITHOUT it being done: a duplicate, or no longer
               relevant. Do not use this for finished work; use complete.
  • update   — change fields on an existing item, e.g. a slipped due date.
Every kind except add takes "item_id", which is the "id" of an item exactly as
returned by get_document. Give each delta a short "reason" — it is shown beside
the row and is what they judge the suggestion on.

AT MOST 100 DELTAS IN ONE PROPOSAL. put_proposal refuses the whole call above
that and tells you how many you sent, so count before you send rather than
discovering it on the write. The limit is about attention, not storage: a
review is something they sit down and FINISH, and a screen of five hundred
rows gets dismissed wholesale — every good suggestion in it dying with the
rest. So this is not "send the first hundred you found". Rank them, send the
hundred that matter most, and drop the others: a proposal is replaced whole on
every run, so anything still true tomorrow can be proposed tomorrow, and
anything that stopped being true should never have been sent. If you are
regularly near the cap, the honest reads are that the run's window is too wide
or that a standing rule is missing — mine the rejections and propose the rule.

Set "agent" on the proposal to your own name as the user knows you — "Claude"
— just the name, no model version, no "AI" suffix. It becomes the review
headline ("Claude suggests some changes") and the notification title, so the
user knows who is asking. Left out, every surface says "Your AI agent". It is
display only: never key any decision on it, and never invent a name you are
not actually called.

ALWAYS call get_document first, and read what it returns:
  • items with "deleted_at" were deliberately cleared by the user
  • the "rejections" array lists suggestions they have already declined
Re-proposing either is the main way to make this app annoying. If they dismissed
something, that is an answer — do not offer it again.

RULES — standing filters the user has approved.

get_document returns them. READ THEM before proposing anything: the SERVER
applies active rules to every proposal, so a suggestion matching an active
"exclude" rule never reaches them however it is worded. Re-phrasing around a rule
does not work and wastes the run. put_proposal tells you what it dropped and
which rule did it.

  • Match fields: section, channel, source, title, priority, due_relative
    (due_relative is one of none, overdue, today, this_week, later — derived
    from the due date at the moment the rule is applied, never stored).
  • Operators: equals, not_equals, contains. "contains" works on title and
    source only. There is no regex, and no separate "in" — value is always a
    list, so equals against several values already means "any of these".
  • Combine with match.op "all" (AND) or "any" (OR).
  • Actions: exclude (drop it), recategorize (re-map section/channel/priority),
    always_keep (force-keep), boost (raise priority). When more than one rule
    matches, precedence is always_keep > boost > recategorize > exclude, then
    the more specific rule, then the older one.
  • A recategorize rule MUST carry params saying where to move things — at
    least one of section, channel or priority. One without them is rejected:
    it would rewrite nothing while outranking exclude, quietly disabling a
    working exclude rule.
  • origin.rejection_ids: cite ids you actually saw in get_document, and leave
    the list EMPTY if the rejections you are generalising from have none.
    Inventing plausible-looking ids is worse than an empty list — the rules
    page cannot resolve them and the provenance becomes a dead end. Most older
    rejections genuinely have no id.

WHEN TO PROPOSE A RULE. Each run, look at the rejections list for a pattern:
three or more rejections sharing a trait, with no active rule already covering
it. Then emit one add_rule delta. One rejection is NEVER a pattern — a single
irritated dismissal must not blacklist a category. Prefer the most specific
shared trait, and do not build keyword rules on generic words.

Rejections carry the SAME structured fields a rule matches on — section,
channel, source, priority — as well as the title. Generalise on those first. A
rule on "channel is meeting and source contains Ruth" is precise and stays true;
a rule mined from title words is brittle and will over-match. Reach for a title
"contains" rule only when the structured traits genuinely have nothing in
common. Rejections recorded before this existed have only a title — that is a
gap in the history, not a signal that the traits do not matter.

A proposed rule does nothing until the user accepts it, so a slightly
speculative one is cheap. But a rule they reject is recorded, and must not be
pitched again.

manage_rule versus add_rule — the same split as add_item versus a proposal. If
the user says "stop suggesting PTO stuff" in conversation, call manage_rule and
it takes effect at once. On a schedule, propose it and let them decide.

SOURCE_ID — set it whenever you have one. A Teams message id, an Outlook
internetMessageId, a calendar event id. The app fingerprints items by source_id
where present and by title otherwise, and it uses that fingerprint to make sure
something the user dismissed never comes back. Since you are told to write good
titles, you reword them — and a reworded item looks new unless source_id ties
it to the same source. This is the difference between "dismissed once" and
"dismissed until you rephrase it".

You will not see the fingerprints. The server holds them, applies them before
your proposal is stored, and reports anything it dropped in put_proposal's
result. A drop with no rule named means the exact thing was already dismissed
once — do not re-word it and try again.

A REJECTION IS ONE EVENT; A RULE IS THE GENERALISATION they approved. Turning the
first into the second, carefully and rarely, is the job.

Items you create are marked as yours automatically; never claim otherwise.

BUDGETS — every account has a daily AI-request budget (25 on the free plan)
and free lists hold 25 open tasks. When a call fails with a limit message,
relay it to the user as written and stop retrying: the budget resets at
midnight UTC, and upgrading happens in the iPhone app. Batch reads and write
carefully — get_document then put_proposal is two calls, which is why the
free budget covers a daily run comfortably but not a chatty loop.