Inspecting the graph with the REST API
The MCP is the research interface: discover with the search tools, qualify with
get_variable_metadata, retrieve with the observation tools. The knowledge graph
behind the server also answers plain HTTP requests, and five narrow structural
questions are easier to answer that way, because the current MCP flattens or does not
expose the structure involved: the other governed slices of a statistical family, the
vocabulary a constraint draws on, the groupings a place belongs to, the thematic
organisation of the corpus, and the governed comparison set a variable belongs to. This
page documents those five recipes and nothing else.
Each starts from an identifier the UN System Data Commons workflow established,
inspects only the structure the question needs, and returns to the MCP for the
statistical work. It is not a second research workflow and not a fallback: a search
that did not find what you expected is answered by reading the
candidate list and the metadata, not
by turning to REST.
MCP discovery
↓
known UN System Data Commons identifier
↓
optional REST graph inspection (this page)
↓
better-informed choice
↓
get_variable_metadata / get_observations / get_child_observationsThe request¶
Everything on this page is one kind of request: a GET on the V2 node endpoint of
the host that serves the MCP, naming one node and one property to follow.
https://unsd-datacommons.gcp.un-icc.cloud/core/api/v2/node?nodes=<dcid>&property=<arc>An arc is a property with a direction: ->populationType follows the property out
of the node, to the values it carries; <-populationType follows it in, to the nodes
that carry this node as a value. The answer is JSON: under data, the node you named,
its arcs, and for each property the linked nodes, each with a dcid, a display
name, its types and the provenanceId of whoever asserted the arc. UN statistical
nodes carry provenances under undata/p/; shared places carry dc/base/Place.
REST='https://unsd-datacommons.gcp.un-icc.cloud/core/api/v2'
curl -sG "$REST/node" \
--data-urlencode 'nodes=undata/unicef/DM_POP.AGE--Y0T17__SEX--F' \
--data-urlencode 'property=->populationType'{"data": {"undata/unicef/DM_POP.AGE--Y0T17__SEX--F": {"arcs": {"populationType": {"nodes": [
{"dcid": "undata/unicef/SERIES-DM_POP", "name": "Total population",
"types": ["undata/unicef/SERIES"], "provenanceId": "undata/p/UNICEF"}]}}}}}--data-urlencode matters: the arrows and braces in a property must reach the server
encoded. The deployment answered these requests without credentials when the page was
written; that is a deployment setting, not a property of the API, so a 401 or 403
is a question for the platform team, not a sign that a recipe is wrong. Every request
below was run on 2026-09-11 and is re-checked by the book’s live tests, so the counts
quoted are what the graph held that day.
1. See the statistical variable’s family¶
When. A search returned one slice of a series and you want to know what other governed slices belong to the same statistical family, structurally rather than by re-running semantic search with different words.
Start from a variable the search tools returned; its metadata names the
populationType, which is the series.
Ask for the series node, then for everything that shares it:
curl -sG "$REST/node" --data-urlencode 'nodes=undata/unicef/DM_POP.AGE--Y0T17__SEX--F' \
--data-urlencode 'property=->populationType'
# → undata/unicef/SERIES-DM_POP (Total population)
curl -sG "$REST/node" --data-urlencode 'nodes=undata/unicef/SERIES-DM_POP' \
--data-urlencode 'property=<-populationType'Read: 27 statistical variables, each with its DCID and name — the total, four age bands with and without sex, two sex-only slices and twelve urbanisation slices. Take the sibling you want from that list as written; never construct one by editing a code into an identifier.
Return to the MCP with get_variable_metadata for the siblings of interest, then
retrieve as usual.
Large families. If the series answer arrives with a nextToken, the family is
larger than one page, and following tokens is not something this page teaches. Walk
the navigational groups instead: every UN variable is a member of one group
(undata/g/…), each group specialises its series group, and the series group’s
specialisations are the family’s slices, named by the dimensions they fix and the one
they vary. Four arcs, each answered in one page:
V='undata/unhcr/END_YEAR_POPULATION.COO--G00000020__POPULATION_GROUP--REFUGEES'
curl -sG "$REST/node" --data-urlencode "nodes=$V" --data-urlencode 'property=->memberOf'
# → undata/g/unhcr/END_YEAR_POPULATION.073
# "… [Population group=Refugees], by Country or area of origin"
curl -sG "$REST/node" --data-urlencode 'nodes=undata/g/unhcr/END_YEAR_POPULATION.073' \
--data-urlencode 'property=->specializationOf'
# → undata/g/unhcr/END_YEAR_POPULATION (the series group)
curl -sG "$REST/node" --data-urlencode 'nodes=undata/g/unhcr/END_YEAR_POPULATION' \
--data-urlencode 'property=<-specializationOf'
# → 75 slices, e.g. "[Age=Under 5 years old, Population group=Refugees,
# Sex=Female], by Country or area of origin"
curl -sG "$REST/node" --data-urlencode 'nodes=undata/g/unhcr/END_YEAR_POPULATION.073' \
--data-urlencode 'property=<-memberOf'
# → the 208 variables of that slice, one per country of originThe groups are a way to walk a large family, not a concept to learn; the statistical variable is still what you select and carry back to the MCP.
Stay inside. The series node, the groups and the members are all undata/ nodes
with undata/p/ provenances. Do not continue above the series group: the UN group
root, undata/g/Root, specialises the wider graph’s root, and the groups above it
organise other publishers’ variables. Never ask <-populationType of a shared class
such as Person: that lists the wider graph’s variables, which are not part of this
corpus.
2. Inspect the governed vocabulary behind a constraint¶
When. Metadata says a variable fixes Age to Under 18 years old, and you want to know what that dimension is, which values are governed for it, which of them this family uses, and what else in the corpus is broken down the same way.
Start from the constraint metadata get_variable_metadata returned: for
undata/unicef/DM_POP.AGE--Y0T17__SEX--F, constraintProperties Age and Sex,
with undataAge fixed to Under 18 years old. Those are labels; the graph holds the
property, the class it draws values from, and every governed value of that class.
Ask for the value node behind the label, the class the property ranges over, and the class’s values:
curl -sG "$REST/node" --data-urlencode 'nodes=undata/unicef/DM_POP.AGE--Y0T17__SEX--F' \
--data-urlencode 'property=->undataAge'
# → undata/AGE-Y0T17 "Under 18 years old" (types: undata/AGE)
curl -sG "$REST/node" --data-urlencode 'nodes=undataAge' \
--data-urlencode 'property=->rangeIncludes'
# → undata/AGE "Age"
curl -sG "$REST/node" --data-urlencode 'nodes=undata/AGE' \
--data-urlencode 'property=<-typeOf'
# → the governed age values: 208 on 2026-09-11, each with dcid, name and unCodeRead with one distinction in mind: the controlled vocabulary defines the values that are governed for the dimension; a statistical family may use only a subset of them. UNICEF’s population family fixes Age to four of the 208, and you read which four from the family listing of recipe 1, whose names and per-variable constraint arcs state them. The class says what could be fixed; the family says what is. Optionally, ask which UN variables actually fix a value, a structural answer to “what else is reported for under-18s”:
curl -sG "$REST/node" --data-urlencode 'nodes=undata/AGE-Y0T17' \
--data-urlencode 'property=<-undataAge'
# → 196 variables on 2026-09-11, from UNFPA, the SDG database, UNICEF, WHO and UNAIDSThe same three steps read undata/SEX, undata/URBANIZATION, undata/COO (country
or area of origin) and undata/POPULATION_GROUP behind the properties the metadata
names.
Return to the MCP with get_variable_metadata for the variables you selected from
those answers; the metadata, not the vocabulary, qualifies a candidate.
Stay inside. The UN vocabulary’s properties, classes and values carry undata/
identifiers, and only UN variables fix them, so the usage answer is UN-scoped by
construction. Select identifiers from the answers; never derive a variable DCID from a
value code. The shared unit Percent and the shared schema classes are reference
nodes: read their names if you need them and ask them nothing else.
3. Find the groupings a place belongs to¶
When. You want to compare a country within the regions and groupings that contain it, or to see what a grouping contains before asking for it. The MCP can tell you a place’s type; it cannot list the groupings that contain it, and some grouping names its search tools cannot resolve at all.
Start from a place DCID discovery returned in dcidNameMappings or
resolvedParentPlace, or a shared place identifier such as country/RWA.
Ask for the place’s parents, then for a grouping’s countries:
curl -sG "$REST/node" --data-urlencode 'nodes=country/RWA' \
--data-urlencode 'property=->containedInPlace'
# → Eastern Africa and Sub-Saharan Africa (UNGeoRegion), Africa (Continent), and the
# GeoRegion groupings Landlocked developing countries, LLDCs: Africa,
# Least developed countries (undata-geo/G00404000) and LDCs: Africa
curl -sG "$REST/node" --data-urlencode 'nodes=undata-geo/G00404000' \
--data-urlencode 'property=<-containedInPlace{typeOf:Country}'
# → the countries the graph records in the LDC grouping: 46 on 2026-09-11Read the parents with their DCIDs and types. {typeOf:Country} is the one
qualifier this page uses; it limits the inward answer to countries.
Return to the MCP. The search tools take place names, and Least Developed Countries is one they cannot resolve; the retrieval tools take DCIDs. Discover as usual with a parent the search can resolve, then retrieve for the grouping by its DCID:
search_child_indicators(query="total population", parent_place="World", …)
→ undata/unicef/DM_POP (the MCP establishes the variable)
REST: country/RWA ->containedInPlace
→ undata-geo/G00404000 (REST identifies the grouping)
get_child_observations(
variable_dcid="undata/unicef/DM_POP",
parent_place_dcid="undata-geo/G00404000",
child_place_type="Country",
date="latest",
)
→ one latest value per country in the groupingThe countries returned are those the knowledge graph records as contained in the grouping: not necessarily an official membership list, nor the set from which a source aggregated its own regional observation — see Geographic scope.
Stay inside. Places are shared reference entities; reading their type and containment touches no statistics. This page uses no observation request. If you ever call the REST observation endpoint, name a UN variable the MCP established: a request for everything observed about a place answers with the wider graph’s statistics too.
4. Orient yourself in the UN corpus¶
Optional, and outside the normal workflow: it does not replace search_indicators; it
helps you phrase the next search in the corpus’s own terms.
When. The MCP returns topics as candidates, and in the current server each topic
candidate lists every variable beneath it as one flat memberVariables list while
memberTopics stays empty, so the hierarchy between a theme, an agency’s series and its
slices is not visible in search results. The graph holds that hierarchy under an
explicit UN root, and one property walks it in either direction.
Start from the UN topic roots only.
Ask:
curl -sG "$REST/node" --data-urlencode 'nodes=undata/topic/Root' \
--data-urlencode 'property=->relevantVariable'
# → 42 top-level topics on 2026-09-11: one per agency (undata/topic/unicef, …),
# the seven ABAS sections (undata/topic/abas/sec-1 …), the 17 SDG goals
# (undata/topic/sdgf/goal-1 …) and the theme root
curl -sG "$REST/node" --data-urlencode 'nodes=undata/topic/theme/Root' \
--data-urlencode 'property=->relevantVariable'
# → the twelve themes, e.g. Population and demography (undata/topic/theme/T10)
curl -sG "$REST/node" --data-urlencode 'nodes=undata/topic/theme/T10' \
--data-urlencode 'property=->relevantVariable'
# → its sub-themes, e.g. Population (undata/topic/theme/S65), Migration, WorkforceRead downwards with the same property: a sub-theme lists the series topics beneath
it across agencies (Population holds SDG census and registration indicators, UNFPA
age and sex ratios, and UNICEF’s and UNIDO’s population series); an SDG goal lists its
targets, a target its indicators, an indicator the series topic that carries the
variables. Upwards, <-relevantVariable on a series topic names its theme and agency:
UNHCR’s end-year population series sits under Forced displacement and refugees,
itself under Disasters and humanitarian action.
Return to the MCP with a better search: the concept in the corpus’s vocabulary in
query, the place in places, as the
operating rules
say. A series topic reached this way can be read as a family with
recipe 1, and the terminal topics it lists each name one governed
comparison set, read as in recipe 5.
Stay inside. Start at undata/topic/Root or undata/topic/theme/Root, never at
dc/topic/Root or the group tree under dc/g/Root, which organise other publishers’
variables. The UN topic root has no parent in the graph, so a downward walk from it
stays within the corpus.
5. Find the governed comparison set a variable belongs to¶
When. The MCP returned a useful statistical variable but not the terminal topic that names its governed comparison set (see When the user asks for a breakdown or comparison), and you want that set structurally rather than by re-running the search.
Start from a variable the search tools returned.
Ask which peer group holds it, then for the group’s members:
curl -sG "$REST/node" --data-urlencode 'nodes=undata/unicef/DM_POP.SEX--F' \
--data-urlencode 'property=<-member'
# → undata/svpg/unicef/DM_POP.004 "Total population, by Sex" (StatVarPeerGroup)
curl -sG "$REST/node" --data-urlencode 'nodes=undata/svpg/unicef/DM_POP.004' \
--data-urlencode 'property=->member'
# → undata/unicef/DM_POP.SEX--F, undata/unicef/DM_POP.SEX--MRead the answer to “what governed comparison set does this variable belong to?”.
The group’s name states the view: the series, the constraints held fixed in brackets,
the dimension the members vary across after by, and the classification used after a
dash; ->undataShortName gives the same view without the series title. If several
groups come back, they are different governed classifications of the same varying
dimension: undata/ilo/UNE_DEAP_RT.AGE--Y15T24 belongs to three age groupings, the
ten-year bands, the working-age components and the youth and adult frame. Select by
the group names and what the question needs, never by position in the answer. The
group’s <-relevantVariable names the terminal topic it is paired with, and a terminal
topic’s ->relevantVariable is its group, so either is one step from the other.
Return to the MCP with get_variable_metadata for the members and the place, and
apply the checks of the research pattern: the group lists the governed set, not the
members with data for your place. Retrieve as usual.
Ordering. The group also carries memberList, the same members as one string in
identifier order; it is not a presentation order. If order matters, an ordered governed
vocabulary provides it: the class behind the constraint (undata/AGE, reached as in
recipe 2) carries ->undataOrderSemantics, and each of its values
carries ->undataSortOrder. Otherwise infer no order from the group.
Stay inside. Peer groups and terminal topics are undata/ nodes, and the two arcs
above never leave them. Do not enumerate the shared class StatVarPeerGroup with
<-typeOf: it lists other publishers’ groups too. Do not inspect dc/svpg/ groups, and
do not derive a group DCID from a topic DCID, or a member DCID from a code, by editing
strings: read them from the arcs.
Not for these tasks¶
REST is not recommended here for the following; the MCP handles each with the playbook, the place resolution, the facet selection and the attribution the workflow depends on:
Statistical variable search. The REST resolution endpoint is the index the MCP searches, without the playbook and, unless explicitly scoped, with the wider graph’s variables ranked first. Use
search_indicatorsandsearch_child_indicators.Observation retrieval.
get_observationsandget_child_observationsselect the facet, name the source and apply the date modes.Observation availability checks.
get_variable_metadatawithentity_dcidsreports each facet’s coverage, count and date range for the places you name, and the child-place tools return every country with data.Place resolution. The search tools resolve names and return DCIDs in
dcidNameMappingsandresolvedParentPlace.SPARQL. Not available on this deployment.
The website’s internal API endpoints. Undocumented, unscoped and subject to change.
Whole-corpus enumeration. Listing every statistical variable, or every value of a shared class, pages through content from outside the corpus: maintainers’ work, not a research step.