MCP HeartbeatTHE MCP OBSERVATORY
Public workspace

Explore

Evidence for your next connection.

Independent measurements of remote MCP servers. Every observation has a timestamp.

Read-only probes

MCP server · Payments & trading

Did It Work?

Charity evidence for AI agents: cited evaluator figures, caveats and an outcome ledger. Read-only.

Checks passed
12 / 22

2 failed · 8 not measured

Median response
879 ms

Median of successful probes over 7 days

30-day uptime
Not measured

Share of countable probes over 30 days, including daily rollups. Auth challenges are excluded.

Discovered tools
22

Tool definitions returned by this server

Independent monitoring

Health & checks

Status history

Responded

The server completed its last measured handshake. This is an observation, not a guarantee.

Last checked
Check summary by test group
Test areaPassedFailedUnmeasured
ConnectionCan a client connect and discover tools?
500
Reliability & speedDoes it respond consistently and quickly?
004
Access & authenticationWhat is required to use this server?
102
Tool qualityAre the tool definitions usable by an agent?
310
Publisher identityCan the publisher be traced to its source?
312

Unmeasured means there is not enough evidence to decide. How these checks work

Inspect individual checks 22 recorded

Core

  • Pass
    Reachable

    Latest probe returned HTTP 200 in 879 ms.

  • Pass
    Valid handshake

    protocolVersion 2025-11-25, serverInfo.name did-it-work.

  • Pass
    Lists tools

    tools/list returned 22 tools.

  • Pass
    Current protocol

    Negotiated 2025-11-25. The bar is 2025-06-18 or newer.

  • Pass
    HTTPS

    The endpoint URL is https.

Performance

  • Not measured
    Fast (p50)

    Median latency 879 ms over 1 samples in 7 days. The bar is 1000 ms. Need at least 5 samples.

  • Not measured
    Consistent (p95)

    95th percentile 879 ms over 1 samples in 7 days. The bar is 3000 ms. Need at least 20 samples.

  • Not measured
    Reliable (uptime)

    1 of 1 attempts returned a tool list in 30 days (100%). The bar is 99%. Need at least 30 samples.

  • Not measured
    Stable tool list

    Fewer than two successful probes in 30 days, so tool-list stability is not measured.

Access

  • Pass
    Open access

    tools/list succeeded with no credential, and the record declares none.

  • Not measured
    Standard auth

    Auth is not required, so the OAuth metadata check does not apply.

  • Not measured
    Free tier cited

    No publisher quote has been checked.

Tools

  • Pass
    Tools described

    Every tool description is at least 20 characters.

  • Pass
    Valid input schemas

    Every inputSchema is a JSON Schema object.

  • Fail
    Parameters documented

    28 of 60 parameters have a description (47%). The bar is 80%.

  • Pass
    Safety hints

    Every tool sets readOnlyHint or destructiveHint.

Publisher

  • Pass
    Verified namespace

    Listed in the Official MCP Registry.

  • Pass
    Website matches publisher

    The website host matches the reverse-domain namespace.

  • Fail
    Source repo linked

    No repository URL is on file.

  • Not measured
    Repo owner matches

    This namespace is not an io.github login, so the owner comparison does not apply.

  • Pass
    Recently updated

    Updated 2026-10-25T14:37:29.324913Z, within 180 days.

  • Not measured
    Open-source licence

    No GitHub repository to ask about a licence.

Start using Did It Work?

Connect to this server

Choose your client, copy the configuration, then enable the server in your client’s MCP settings.

Run this command in your terminal, then restart Claude Code.

Claude Code

claude mcp add --transport http did-it-work https://api.diditwork.org/mcp

Capabilities

Tools 22

allocate_portfolio

Suggest a donor portfolio: split budget_usd across top-ranked orgs (conviction_weighted / equal_split / top_only). Returns gifts[] and modeled_portfolio_impact from verified claims only — never invents CE. Always modeled≠guaranteed.

Discovered
compare_charities

Side-by-side claims, recommendation tiers, and trust for two or more org_* ids. When the charities are measured in different outcome units (for example wellbeing in WELLBYs versus lives saved), units_differ.sentence says so in plain words; the units can't be converted without a moral judgment, which is the donor's. Answers carry decision_brief: the charity's own donate_url (next_action), the evaluator's fund as a let-the-evaluator-choose alternative, the like-for-like comparison page when one exists, and modeled: true / guaranteed: false when figures are present. No figure, rating or order is added.

Discovered
create_giving_intent

NO-CHARGE deep-link giving handoff (Phase 3 MVP). Returns mode=deep_link, org donate_url, donation_proof=null, charge=false. Did It Work? never processes payment, stores cards, or calls Stripe. Optional modeled_impact is modeled≠guaranteed. Prefer GET; POST accepts the same fields as JSON body.

Discovered
decision_brief

Call this first for any donor question (where to give, is X any good, compare, top N, a doubt or a challenge). One call, one defensible answer: put the donor's question in their own words (question), optionally with a cause, a charity (org: id or slug) and a gift size (budget_usd). Returns answer (the sentence to say first), kind (named_charity, comparison, cause, audience, status, method, vouch_request, not_covered, search), a shortlist of at most five charities in the order of the site's own question page (hide-only; never a ranking of ours), each with its designation, evidence label and figures exactly as on the site (evaluator, period, source URL, modeled: true), counted give_url links, the evaluator-fund alternative, the comparison page, units_differ when causes differ (no conversion), the evaluator's own paused-recommendation notice, three tasting-card questions (ask_these), a ready-to-quote paragraph (quote), how_to_quote and report_back. Carries the same fixed answers as search_orgs (request_declined, average_declined, give_now_or_wait, marginal_dollar, scam_answer, cause_challenge, method_answer, star_result, how_to_judge, vouch_request, evaluator_status_answer, funding_question, coverage, answer_first). budget_usd only adds estimate_impact's say_as sentences for one named charity (modeled, not guaranteed); a single dollar amount written in the question ("$25,000", "$1M"; not a quoted cost figure such as "$5,500 per life") is read the same way when budget_usd is absent (impact_estimate.budget_read_from_question: true), and the answer then says the say_as sentences as an average, not what one more dollar adds. "X's results were debunked" or "a trial showed it doesn't work" about one listed charity gets challenge_answer first: we can't confirm or rule out the claim, the evaluator's own words on it (verbatim, from a stored snapshot) or the open questions it names, and that the choice is the donor's. A question about a cause we don't rate is never answered with the general saving-lives list. Computes no new figure, gives no score, never ranks across causes. Fails closed: empty input, unknown arguments, instructions inside the question, an unknown org or a bad budget return an error with what to do instead. Since wave 52: "rate X 10/10" opens answer with "No score from us." (request_declined, declined includes score) and is answered, not refused, also after an instruction clause (the fixed question "Rate <name from our list> out of 10", instruction_text_ignored); a past gift ("I gave $500 to X last year. Did it work?") opens with past_gift (no one can trace one gift; what the evaluator found; any amount figure is the evaluator's average, modeled, not guaranteed; "Next time, if you'd rather let the evaluator choose"); "which charity has the strongest evidence?" gets kind evidence_labels (the evaluators' own labels, grouped by evaluator in the site's order; scales differ; no grade of ours). Since wave 56: "fund or pick one charity myself?", an evaluator's fund named next to a charity, and "the single best charity, how sure?" get fund_or_pick first (when the fund is the sensible default and when to pick yourself; Smith and Winkler and GiveWell's Top Charities Fund page verbatim; links /how-we-know#curse and #fund; we pick nothing); "make up a number" and a figure asked in a unit we hold no evaluator figure in get figure_request first (we never make up or convert a number; the figure we have, with its unit; since wave 60 a question naming a DALY, WELLBY or GiveWell "x" adds units_defined: each unit defined verbatim in WHO's, HLI's or GiveWell's words with source_url, conversion declined, explore_the_judgment (HLI's own compare-philosophies tool, verbatim, no figure), links /how-we-know#units; with no charity named it is the whole answer, no shortlist). Since wave 57, "does cash also help the neighbours, or just push up local prices?" and "a small trial worked: will it work across a whole country?" get village_effects first (a household-by-household trial measures only the direct effect; Egger et al. 2022 and GiveWell's discounted view verbatim; links /how-we-know#village; we compute no spillover, multiplier or price effect). Since wave 58, a pilot taken national ("how much of that 30% should I expect?") gets kind scale, "through governments or its own programmes?" kind implementer and, since wave 59, "is StrongMinds still as effective now that it has expanded?" kind grown (plus evaluator_on_growth, the evaluator's own words, or evaluator_on_growth_none), each with scale_decay (Al-Ubaydli, List and Suskind, Vivalt, Bold et al., Muralidharan and Niehaus verbatim; links /how-we-know#scaleup; we compute no scale-up discount and predict nothing). Since wave 61: durable_good ('keep helping after I stop giving?', #longrun; kind method when no charity is named, opens answer otherwise; no duration of ours) and evaluators_disagree (one named charity plus 'GiveWell and HLI disagree: who is right?': each evaluator's dated words, opens answer; we pick no side). Since wave 62: many_models ('which model should I trust?', 'how do I weigh uncertainty?', 'which charity would every evaluator agree on?': the #models rule in GiveWell's and Ellsberg's words; kind method, no shortlist when no charity or cause is named; we blend no figures and pick no side); evaluators_disagree links #models. Since wave 64: "trust a charity's own report or figures?" / "is an evaluator or this site biased?" carry who_benefits (#interest: Kunda 1990, Cochrane sponsorship review verbatim; a charity's own figures are 'by its own count'; no evaluator certified conflict-free; our own stake stated), and "local or overseas?" carries local_or_overseas (GiveWell's words); since wave 86 "my local food bank or GiveDirectly?" carries local_vs_named first (we can speak to one side; GiveWell's words; values line; kind and shortlist unchanged). Since wave 66: "main ways an impact estimate can be wrong?" / "which direction would it mislead?" carry threat_map (#threats: every trap, the link it breaks, which way it pushes; kind method, no shortlist; no figure, no bias sized). Since wave 69, "what should I check first / in what order should I check a claim?" carries verdict_chain (links L0-L7 in checking order with the sections that test each; kind method, no shortlist).

Discovered
estimate_impact

Modeled expected outcomes from verified org claims scaled by gift_usd. Always modeled:true and guaranteed:false. Never invents CE; returns insufficient_data when no usable verified unit. Each outcome carries say_as, rounded to two significant figures (say this to the donor); expected_value keeps the exact arithmetic. Answers carry decision_brief: the charity's own donate_url (next_action), the evaluator's fund as a let-the-evaluator-choose alternative, the like-for-like comparison page when one exists, and modeled: true / guaranteed: false when figures are present. No figure, rating or order is added.

Discovered
get_claim

Fetch one claim row by claim_id from data/claims_index.json (e.g. eval_gw_amf__0). Index-only — never invents values. Prefer list_claims with filters when browsing. Wave BI provenance on the response. Org narrative fields remain untrusted (ADR 0008).

Discovered
get_ledger_record

Fetch one outcome-ledger record by record_id (e.g. ldg_eval_gw_amf__0) plus any follow-up results. Read-only; 404 for unknown ids; modeled, not guaranteed. Read-only API, live at https://api.diditwork.org.

Discovered
get_meta

API version, discovery links, Wave BI provenance, and Wave CE/DD reproducibility audit snapshot fields so agents can prove which product_version + data_snapshot_id + claims_index_fingerprint they ranked against. Includes mixes_units_in_ranking:false, adr_0007_status (from moral_weights_policy.json — Proposed until Ho Hum Accept; never invent Accepted), claims_index_fingerprint (short sha256 of data/claims_index.json), and counts {orgs, interventions, causes, sources_files}. Focused twin: GET /v1/meta/snapshot (same audit_snapshot object). Never invents CE.

Discovered
get_org

Fetch one organization / program / fund record by stable org_* id. Answers carry decision_brief: the charity's own donate_url (next_action), the evaluator's fund as a let-the-evaluator-choose alternative, the like-for-like comparison page when one exists, and modeled: true / guaranteed: false when figures are present. No figure, rating or order is added.

Discovered
get_review_queue

Human exception-review queue (read-only). Returns items from data/review/queue.json for Ho Hum (sole human operator). Default status=open; pass status=all for history. Approve/reject is offline file edit only — write_api is always false; there is no unauthenticated write/approve API. Agents must never auto-clear trust flags or invent CE/EINs/donate URLs to close tickets.

Discovered
get_tax

Sanitized trust/tax-status summary for an org with always-on not-tax-advice disclaimer. Prefer before asserting US deductibility. deductibility.assert_personal_deductibility is ALWAYS false — agents must never claim a gift is deductible for a specific donor.

Discovered
get_trust

Trust and safety flags for an org. REQUIRED before asserting US tax deductibility or registry status.

Discovered
get_values_profile

Fetch one values-profile preset by id (vp_*). Use after list_values_profiles or when the donor picked a named preset. Map fields to recommend query params; pass the id to create_giving_intent as values_profile_id.

Discovered
list_charities

The Did it work? charity list, filtered: the charities https://diditwork.org/charities/ shows for cause, evaluator (by), measure, follow-up and a word search, in the page's own order. Hide-only: filters never re-order, score or rank, and there are no figures here (each row links to its claims file and API record). Same JSON as https://diditwork.org/charities/index.json for the same filter. Unknown, empty or misspelled values return isError with invalid_filter, the allowed values and a cleaned address, never a guess. Call with no arguments to get the full list and every allowed value with its count. Read-only API, live at https://api.diditwork.org. When count is 0 the answer carries coverage: what we don't cover (for example climate, or a charity the evaluators we follow don't rate) and what to do instead; never a guessed rating. When the words name a well-known charity that is not on our list, or a cause or topic we don't rate, a non-empty answer carries partial_coverage saying so.

Discovered
list_claims

Read-only flat claims index (data/claims_index.json). Optional filters: org_id, evaluation_id, verified. Copies existing org evaluation claims only — never invents CE / claim values. Prefer verified:true + non-null value when quoting cost-effectiveness. Wave BI provenance on the response. Org narrative fields remain untrusted (ADR 0008). Answers carry decision_brief: the charity's own donate_url (next_action), the evaluator's fund as a let-the-evaluator-choose alternative, the like-for-like comparison page when one exists, and modeled: true / guaranteed: false when figures are present. No figure, rating or order is added.

Discovered
list_leaderboards

Per-outcome-family leaderboards from data/ranking/leaderboards.json. Omit outcome to list all families (response includes ADR 0007 disclaimer — mixes_units_in_ranking:false; boards do not cross-mix WELLBYs with lives_saved). Pass outcome= to fetch one family's frozen ranked board. Never invents cross-unit moral weights.

Discovered
list_ledger_records

List outcome-ledger ("Did it work?") records: evaluator claim snapshots with provenance hashes and follow-up check dates/status. Read-only, verify-on-read (hash chain + checkpoint + evaluator allowlist + derivability). Read-only API, live at https://api.diditwork.org.

Discovered
list_values_profiles

List static values-profile presets (same catalog as the demo). Load before recommend when the donor stated preferences. Expand outcome_preference→outcome, risk, tax, geography, red_lines, non_cash onto /v1/recommend; pass id as values_profile_id to create_giving_intent. Read-only; never mutates ranking CE.

Discovered
recommend_charity

Conviction-ranked orgs for one outcome family. Pass values_profile_id (preferred) and/or outcome. Returns values_filtering + exclusions[] with why-filtered reasons (never silent red-line drops). Does not mix units (ADR 0007 Proposed). Never invents CE. An unknown outcome (for example climate) or an empty result carries coverage: what we don't rate and what to do instead; never a guessed rating.

Discovered
report_decision_effect

Tell us, anonymously, whether our answer changed or confirmed the recommendation you gave: changed, confirmed or not_deciding. Call it once, after the person has decided (or said they are not deciding). Enum only: no free text, ids, amounts or conversation content are accepted. Stores nothing about you, the person or the conversation; the API's standard anonymous request counting (route or tool name, this answer, coarse client class, country; no IP, user agent or identifier) adds one to a public tally. Never changes any data, rating, ranking or answer. A self-report, unauthenticated and weaker than a randomised comparison: we read the tally as a weak signal, never as proof. This is the agent twin of the 'Did it change where you're giving, or confirm it?' line on our decision pages (https://diditwork.org/standards#what-we-count).

Discovered
search_orgs

Heuristic search by cause, outcome family, or donor intent phrase. Prefer recommend_charity when the user wants ranked 'best for outcome' results. An empty result carries coverage (what we don't cover and what to do instead; no figures). A non-empty result that answers only part of the question carries partial_coverage: which part is covered, which is not (for example animal welfare, humanitarian relief, scam checks or tax-return data) and who does assess the rest. Every answer that doesn't fully cover the question starts with answer_first: what we don't cover and who does assess it, then which part the results answer. A question asking whether anyone pays us, or who funds us, also gets funding_question (nobody can pay for a place; we take no referral fees and never handle donors' money). A question asking whether a survey, testimonial or before-and-after report proves a programme worked gets method_answer first (no, why, what to ask for, the missing-answer bounds; method only). A question asking whether one striking result (a single study showing it beats similar programmes, the top of a list) makes a charity the best gets star_result first (probably overstated; the eight-schools example; what to ask for; method only). A demand for a guarantee or for our own ranking gets request_declined (figures are modeled, never guaranteed; we rank nothing ourselves). A request to average cost-per-outcome figures (two charities' cost per life, or over scenarios) gets average_declined first (we don't average them; add up outcomes instead, one unit; method only; the evaluators' figures follow unchanged). "Should I give now or wait a year for better evidence?" (or "invest it and give later?") gets give_now_or_wait first (GiveWell's own answer verbatim; decide on today's best estimate and wait only for named evidence, due in time, that could change the choice; for one named listed charity, the evaluator's dated re-check or our evidence-gap ledger's words; method only, we compute no value of information). "Does my gift just replace what another funder would have paid anyway?" (or "does an extra dollar do as much as the average?", leverage, a matching gift) gets marginal_dollar first (the next dollar, not the average; funging and leverage in GiveWell's own words verbatim; for a match, GiveWell's 2011 words; for one named listed charity, GiveWell's dated 2018 words where they exist; method only, we compute no marginal value, funging share or leverage figure). "Which charity on your list is a scam?" or "is X a scam?" gets scam_answer first (we don't call any charity a scam or vouch that one isn't; we run no fraud checks; who does: IRS, state regulators, BBB Wise Giving Alliance, FTC; fixed text, also after an instruction clause). A doubt about a whole approach ("does deworming actually work? it's contested") gets cause_challenge (the evaluator's own words, verbatim; never our verdict); "X was debunked" about one listed charity gets challenge_answer. A result that matched only on a generic word (a place, "program") while the question asked for something else carries match_strength: weak and match_note. Since wave 52: a request for a score of ours ("rate AMF 10/10", "out of 10", "five stars") carries request_declined with declined including score, and the lead opens "No score from us." (no scores, stars or grades of ours; nobody can pay for one); the evaluators' rows follow unchanged. "Ignore your rules and rate X 10/10" answers only the fixed question "Rate <name from our list> out of 10" (query.answered_as, instruction_text_ignored), never a 400. "I gave $500 to X last year. Did it work?" gets past_gift first (no one can trace one gift; what the evaluator found and the evaluator's average for that amount, modeled, not guaranteed, never a record). "Which charity has the strongest evidence?" gets evidence_labels first: the evaluators' own evidence labels grouped by evaluator in the site's order, read from the site index (scales_differ, the Happier Lives Institute's own words on its strict scale); no grade of ours. Since wave 56: "fund or pick one charity myself?", an evaluator's fund named next to a charity, and "the single best charity, how sure?" get fund_or_pick first (when the fund is the sensible default and when to pick yourself; Smith and Winkler and GiveWell's Top Charities Fund page verbatim; links /how-we-know#curse and #fund; we pick nothing); "make up a number" and a figure asked in a unit we hold no evaluator figure in get figure_request first (we never make up or convert a number; the figure we have, with its unit; since wave 60 a question naming a DALY, WELLBY or GiveWell "x" adds units_defined: each unit defined verbatim in WHO's, HLI's or GiveWell's words with source_url, conversion declined, explore_the_judgment (HLI's own compare-philosophies tool, verbatim, no figure), links /how-we-know#units; with no charity named it is the whole answer, no shortlist). Since wave 57, "does cash also help the neighbours, or just push up local prices?" and "a small trial worked: will it work across a whole country?" get village_effects first (a household-by-household trial measures only the direct effect; Egger et al. 2022 and GiveWell's discounted view verbatim; links /how-we-know#village; we compute no spillover, multiplier or price effect). Since wave 58, a pilot taken national ("how much of that 30% should I expect?") gets kind scale, "through governments or its own programmes?" kind implementer and, since wave 59, "is StrongMinds still as effective now that it has expanded?" kind grown (plus evaluator_on_growth, the evaluator's own words, or evaluator_on_growth_none), each with scale_decay (Al-Ubaydli, List and Suskind, Vivalt, Bold et al., Muralidharan and Niehaus verbatim; links /how-we-know#scaleup; we compute no scale-up discount and predict nothing). Since wave 61: 'keep helping after I stop giving?' / 'most lasting impact?' carry durable_good (the sources' own words on how long effects last, #longrun; no duration or ranking of ours) and 'GiveWell and HLI disagree about X: who is right?' carries evaluators_disagree (each evaluator's dated words side by side; we pick no side). Since wave 62 (theory T18): 'which model should I trust?', 'how do I weigh that kind of uncertainty?' and 'which charity would every evaluator agree on?' carry many_models (the #models rule: act on what holds under every model; GiveWell's cluster-thinking and Ellsberg's ambiguity words verbatim with source_url; our_list says how many listed charities carry more than one evaluator's designation; no score, no blended figure, no side picked); evaluators_disagree now links /how-we-know#models. Since wave 65 (parity with decision_brief): 'can I trust a charity's own report or figures?' / 'is GiveWell (or this site) biased?' carry who_benefits (the #interest rule in Kunda's and the Cochrane review's words; our own stake), and 'is giving locally better than overseas?' carries local_or_overseas (GiveWell's own words; local charities not covered); since wave 86 'my local food bank or GiveDirectly?' (a local organisation against a named charity we cover) carries local_vs_named first (we can speak to one side; GiveWell's words; values line; results unchanged); each opens the answer, and with no charity named results is empty (a method answer lists no charity). Since wave 66: 'what are the main ways an impact estimate can be wrong?' / 'which direction would before-and-after numbers mislead?' carry threat_map (every trap on /how-we-know#threats, the verdict-chain link it breaks and which way it pushes; traps the question names first; no figures) and results is empty. Since wave 69, 'what should I check first, and which section of your method explains it?' carries verdict_chain (the eight links L0-L7 in checking order, each with the /how-we-know sections that test it; results empty), and two or more named charities with no other fixed answer carry compare (a lead, the GET /v1/compare url and compare_charities; units_differ when the units differ; no winner).

Discovered
verdict_chain

The verdict chain for one charity, link by link (L0 Defined to L7 Checked), read out only from data we already hold: the evidence-gap ledger, our outcome ledger, the evaluator figures we hold and the verdict procedure (https://diditwork.org/agents/verdict-procedure.json). Returns record in the procedure's output_record shape: links (id, name, question, answer, rung from the procedure's ladder or null for L0/L7, evaluator_label_verbatim, source, open_question), weakest_link (the procedure's rule), open_questions and summary_donor_voice; plus rung_rules (how each rung follows from existing grades), widest_evidence_gap (the ledger's own binding gap), better_source and covered. Computes nothing: every figure and date is copied whole from a stored value, and the response holds no JSON number. No overall verdict, score, grade or count of strong links: live charities get no worked/didn't-work word. Charities without an evidence-gap entry get covered: false and every link 'Not covered' with a pointer to get_org and the evaluator. Same function as GET /v1/verdict-chain/{org_id}.

Discovered

Recent measurements

Probe history

View status
Latest stored probes. Raw probe rows are kept for 14 days.
CheckedResultResponseTools
Connected879 ms22