Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

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_observations

The 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 origin

The 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 unCode

Read 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 UNAIDS

The 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-11

Read 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 grouping

The 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, Workforce

Read 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--M

Read 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: