Things to try.
Each example names the setup it needs. The commands are run against a real stack by scripts/verify-examples.mjs, and the output shown is what they returned.
Count the films
Connection fields return a totalCount next to the rows.
curl -s localhost:4000/graphql -H 'content-type: application/json' \
-d '{"query": "{ moviesConnection { totalCount } }"}'{"data":{"moviesConnection":{"totalCount":152}}}Needs: the default stack · docs →
Who directed the most films?
Film counts are stored on each person (and refreshed after every mutation), so this is one sorted query.
curl -s localhost:4000/graphql -H 'content-type: application/json' \
-d '{"query": "{ people(sort: [{ directedCount: DESC }], limit: 3) { name directedCount } }"}'{"data":{"people":[{"name":"Christopher Nolan","directedCount":8},{"name":"Steven Spielberg","directedCount":7},{"name":"Quentin Tarantino","directedCount":6}]}}Needs: the default stack · docs →
Filter and nest
Filters use operators such as contains (case-sensitive), eq and gte; relationships nest.
curl -s localhost:4000/graphql -H 'content-type: application/json' \
-d '{"query": "{ movies(where: { title: { contains: \"Matrix\" } }) { title released genres { name } } }"}'{"data":{"movies":[{"title":"The Matrix","released":1999,"genres":[{"name":"Action"},{"name":"Sci-Fi"}]},{"title":"The Matrix Reloaded","released":2003,"genres":[{"name":"Action"},{"name":"Sci-Fi"}]}]}}Needs: the default stack · docs →
Read the error, fix the statement
GraphQL answers HTTP 200 with an errors array; the message says what to fix, here with a suggestion. The second command is the corrected statement. This is the loop an agent follows.
curl -s localhost:4000/graphql -H 'content-type: application/json' \
-d '{"query": "{ movies(where: { titel: \"x\" }) { title } }"}'
curl -s localhost:4000/graphql -H 'content-type: application/json' \
-d '{"query": "{ movies(where: { title: { eq: \"Heat\" } }) { title released } }"}'{"errors":[{"message":"Field \"titel\" is not defined by type \"MovieWhere\". Did you mean \"title\"?","locations":[{"line":1,"column":19}],"extensions":{"code":"GRAPHQL_VALIDATION_FAILED"}}]}
{"data":{"movies":[{"title":"Heat","released":1995}]}}Needs: the default stack · docs →
Create a film, then remove it
Writes are open on the default stack. The first statement creates a film with a connected actor; the second deletes it again. Always filter a delete.
curl -s localhost:4000/graphql -H 'content-type: application/json' \
-d '{"query": "mutation { createMovies(input: [{ title: \"ZZ Example\", released: 2031 }]) { movies { title released } } }"}'
curl -s localhost:4000/graphql -H 'content-type: application/json' \
-d '{"query": "mutation { deleteMovies(where: { title: { eq: \"ZZ Example\" } }) { nodesDeleted } }"}'{"data":{"createMovies":{"movies":[{"title":"ZZ Example","released":2031}]}}}
{"data":{"deleteMovies":{"nodesDeleted":1}}}Needs: the default stack · docs →
List the MCP tools
The MCP server speaks JSON-RPC over HTTP; send both Accept types. It is stateless, so no handshake is needed.
curl -s localhost:4100/mcp -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'event: message
data: {"result":{"tools":[{"name":"get_schema","description":"Summary of the GraphQL API: root query and mutation fields with their arguments, and the object types the schema defines with their fields and descriptions. G ...Needs: the agents setup · docs →
Run a query through MCP
run_query returns the JSON result as text.
curl -s localhost:4100/mcp -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"run_query","arguments":{"query":"{ moviesConnection { totalCount } }"}}}'event: message
data: {"result":{"content":[{"type":"text","text":"{\"data\":{\"moviesConnection\":{\"totalCount\":152}}}"}],"isError":false},"jsonrpc":"2.0","id":2}Needs: the agents setup · docs →
Mutations are off by default
The refusal comes back as text with isError, so the agent can read it. To allow writes, start compose with AGENTS_ALLOW_MUTATIONS=true (the server sees it as ALLOW_MUTATIONS=true).
curl -s localhost:4100/mcp -H 'content-type: application/json' -H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"run_mutation","arguments":{"query":"mutation { deleteMovies { nodesDeleted } }"}}}'event: message
data: {"result":{"content":[{"type":"text","text":"Mutations are disabled. This server is read-only by default: start it with ALLOW_MUTATIONS=true to let an agent change data. See docs/guardrails.md."}],"isError":true},"jsonrpc":"2.0","id":3}Needs: the agents setup · docs →
One query, two sources
The gateway asks Neo4j for the film and Wikipedia (through the Wikipedia subgraph) for the summary.
curl -s localhost:4000/graphql -H 'content-type: application/json' \
-d '{"query": "{ movies(where: { title: { eq: \"Heat\" } }) { title released wikipedia { description pageUrl } } }"}'{"data":{"movies":[{"title":"Heat","released":1995,"wikipedia":{"description":"1995 crime drama film by Michael Mann","pageUrl":"https://en.wikipedia.org/wiki/Heat_(1995_film)"}}]}}Needs: the federation setup and internet · docs →
No link, no error
A person with no Wikipedia link returns null for the Wikipedia fields, with no error.
curl -s localhost:4000/graphql -H 'content-type: application/json' \
-d '{"query": "{ people(where: { name: { eq: \"Madonna\" } }) { name wikipediaTitle wikipedia { title } } }"}'{"data":{"people":[{"name":"Madonna","wikipediaTitle":null,"wikipedia":null}]}}Needs: the federation setup · docs →
An anonymous write is refused
With grandstack-auth, reads are public but writes need a token. The gateway answers before the request reaches the server.
curl -s localhost:4000/graphql -H 'content-type: application/json' \
-d '{"query": "mutation { deleteMovies(where: { title: { eq: \"ZZ none\" } }) { nodesDeleted } }"}'{"errors":[{"message":"Unauthenticated: log in to change data","extensions":{"code":"UNAUTHENTICATED"}}]}Needs: the auth setup · docs →