# How to ask this data a question

**Connect any MCP client to `https://cow-tools.sophia-labs.com/mcp` (no account), or POST SPARQL to `https://cow-tools.sophia-labs.com/api/sparql/query` with `{"graphId": "uruguay-cows", "query": …}`. Wrap every pattern in `GRAPH ?g { … }`. An empty answer means the question was asked wrong, not that the answer is zero.**

## Three ways in

1. **An agent, over MCP.** Point Claude, ChatGPT or any MCP client at the endpoint:

```json
{
 "mcpServers": {
  "cow-tools": {
   "url": "https://cow-tools.sophia-labs.com/mcp"
  }
 }
}
```

The curated tools answer common questions with provenance attached (`cow_area_profile`, `cow_compare`, `cow_export_table`, `cow_geo_sources`, `cow_herd`, `cow_map`, `cow_metric`, `cow_quality_report`, `cow_rank`, `cow_report`, `cow_reports`, `cow_schema`, `cow_sidecar_status`, `cow_sources`); the graph tools (`sparql_query`, `semantic_search`, `read_document`, `search_documents` …) reach everything else.

1. **SPARQL over HTTP**, from anything that can POST JSON:

```sh
curl -s https://cow-tools.sophia-labs.com/api/sparql/query -H 'Content-Type: application/json' \
  -d '{"graphId":"uruguay-cows","query":"PREFIX cow: <https://sophia.dev/ontology/cattle-aggregates#> SELECT (COUNT(*) AS ?n) WHERE { GRAPH ?g { ?o a cow:MilkProductionObservation } }"}'
```

1. **Python**, with the notebooks' helper (`cowtools_client.py`, in the notebooks zip):

```python
import cowtools_client as cw
cw.sparql('SELECT ... WHERE { GRAPH ?g { ... } }')   # a DataFrame
cw.tool('cow_rank', metric='bovine_count', entity='department', year=2025)
```

## Examples, run when this page was built

Each query below was executed against the endpoint as this document was written; the answer shown is what it returned.

```sparql
PREFIX cow:  <https://sophia.dev/ontology/cattle-aggregates#>
PREFIX qb:   <http://purl.org/linked-data/cube#>
PREFIX prov: <http://www.w3.org/ns/prov#>
PREFIX skos: <http://www.w3.org/2004/02/skos/core#>
PREFIX dct:  <http://purl.org/dc/terms/>
PREFIX dcat: <http://www.w3.org/ns/dcat#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX xsd:  <http://www.w3.org/2001/XMLSchema#>
```

### How many cattle did Uruguay declare in 2025?

```sparql
SELECT (SUM(?n) AS ?cattle)
WHERE {
  GRAPH ?g {
    ?obs a cow:AnimalFlowObservation ;
         cow:year "2025"^^xsd:gYear ;
         cow:species ?s ;
         cow:animalsCount ?n .
    VALUES ?s { <urn:sophia:cow:species/1> <urn:sophia:cow:species/11> }
  }
}
```

| cattle |
| --- |
| 12,265,269 |

### Which five departments have the most sheep?

```sparql
SELECT ?department (SUM(?n) AS ?sheep)
WHERE {
  GRAPH ?g {
    ?obs a cow:AnimalFlowObservation ; cow:year "2025"^^xsd:gYear ;
         cow:species <urn:sophia:cow:species/2> ;
         cow:department ?department ; cow:animalsCount ?n .
  }
}
GROUP BY ?department ORDER BY DESC(?sheep) LIMIT 5
```

| department | sheep |
| --- | --- |
| urn:sophia:cow:department/15 | 1,032,181 |
| urn:sophia:cow:department/1 | 801,403 |
| urn:sophia:cow:department/11 | 555,079 |
| urn:sophia:cow:department/18 | 398,742 |
| urn:sophia:cow:department/3 | 303,495 |

### Where did a number come from? (the source file and row of one observation)

```sparql
SELECT ?obs ?file ?filename ?sha256 ?row
WHERE {
  GRAPH ?g {
    ?obs a cow:MilkProductionObservation ; cow:year "2025"^^xsd:gYear ;
         cow:department <urn:sophia:cow:department/7> ;
         cow:sourceFile ?file ; cow:sourceRowNumber ?row .
  }
  GRAPH ?s { ?file cow:filename ?filename ; cow:sha256 ?sha256 }
}
ORDER BY ?row LIMIT 1
```

| obs | file | filename | sha256 | row |
| --- | --- | --- | --- | --- |
| urn:sophia:cow:obs/2025/produccion-leche/a39876896a157117 | urn:sophia:cow:file/2025/produccionleche-csv/3645c711b69c | produccionleche.csv | 3645c711b69cbd8669e204caf421791ee7fae1c052ca72bc92cf79eed4b978c4 | 1,889 |

## The rules of the house

- **Wrap patterns in `GRAPH ?g { … }`.** The cube lives in named graphs (observations, codelists, derived metrics and quality, per year). An unwrapped pattern matches nothing.
- **Filter years with the literal** `cow:year "2025"^^xsd:gYear`.
- **Cattle are two species**: beef `1` and dairy `11`. Sheep are `2`.
- **Stock is PD_AD** (`cow:animalsCount`) unless you mean the holder's own animals (`cow:animalsCountPf`, the dairy convention).
- **Read the year's quality warnings** (`cow:QualityWarning`) before comparing years.
- **Fail loudly.** If a number looks wrong, it probably is: check it against the source file named in its provenance (`cow:sourceFile`, with its SHA-256).

## Talking to an agent

The demo also hosts a personal agent over the data (the ride protocol). Reading and the tools are free; a conversation needs your own OpenRouter key (sent per request as `X-Model-Key`, kept in memory for the session) or a Sophia account. See the notebook [*Ask the agent*](https://cow-tools.sophia-labs.com/guide/notebook-ask-the-agent/index.md).

See also: [`glossary-dicose`](https://cow-tools.sophia-labs.com/guide/glossary-dicose/index.md), [`reading-path`](https://cow-tools.sophia-labs.com/guide/reading-path/index.md).

---

This document is CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/), credit "cow-tools, Sophia Labs"; the data it describes keeps its own licence (Uruguay's open-data licence).

The cow-tools guide, Reference: https://cow-tools.sophia-labs.com/guide/how-to-ask-this-data/ (this page for people) · the whole guide: https://cow-tools.sophia-labs.com/guide/index.md · in Sophia: the graph `cow-tools-guide`, document `how-to-ask-this-data` (MCP `read_document` at https://cow-tools.sophia-labs.com/mcp). CC BY 4.0, credit "cow-tools, Sophia Labs".
