Skip to content
devtoolbox.cc

jsonpath_query MCP tool: query JSON files from an AI agent

· 6 min read

Get the devtoolbox.cc MCP serverOpen the JSONPath tool

A 4 MB API response is a bad thing to paste into a conversation. It eats most of the context window, the model skims it, and when you ask “which orders were refunded?” the answer is only as good as that skim. A query language solves this better: describe what you want, and let a program pull exactly those values out.

The devtoolbox.cc MCP server includes jsonpath_query for this. The assistant writes a JSONPath expression, the tool runs it on your file locally and returns only the matches. The engine is the one behind the JSONPath tester on this site, which implements RFC 9535 and passes the official compliance test suite. Install steps are on the MCP page.

What the tool returns

A query returns a list of matches, as a JSON array. You choose what each match looks like:

  • values (default): the matched values themselves.
  • paths: normalized paths such as $['orders'][1]['id'], which say exactly where each match sits in the document.
  • both: objects with a path and a value, useful when the agent needs to change the document afterwards.

The JSON is read with a parser that keeps numbers exactly as written, and the matched values are written back the same way. Large IDs don’t lose their last digits on the way through, and filters compare numbers by their exact value.

Arguments

Argument Type Meaning
json string The JSON text. Use this or path.
path string A local JSON file to query, preferably an absolute path.
query string The JSONPath expression, starting with $.
result "values", "paths" or "both" Default "values".
output_path string Write the matches to a file instead of returning them.
overwrite boolean Allow output_path to replace an existing file. Default false.

Examples

These examples were run against the real tool with this file:

{
  "store": "Brew & Bytes",
  "orders": [
    {
      "id": 1001,
      "status": "paid",
      "total": 12.5,
      "customer": { "name": "Anna", "email": "anna@example.com" }
    },
    {
      "id": 1002,
      "status": "refunded",
      "total": 4.2,
      "customer": { "name": "Boris", "email": "boris@example.com" }
    },
    { "id": 9007199254740993, "status": "paid", "total": 31, "customer": { "name": "Chen" } }
  ]
}

A filter selects array elements by a condition. The emails of refunded orders:

{
  "path": "/home/dev/data/orders.json",
  "query": "$.orders[?@.status == 'refunded'].customer.email"
}
[
  "boris@example.com"
]

Orders above 10, with paths, so an agent knows where each match lives:

{ "path": "/home/dev/data/orders.json", "query": "$.orders[?@.total > 10].id", "result": "both" }
[
  {
    "path": "$['orders'][0]['id']",
    "value": 1001
  },
  {
    "path": "$['orders'][2]['id']",
    "value": 9007199254740993
  }
]

The third order’s ID is 2^53 + 1. A tool built on JavaScript’s JSON.parse would return 9007199254740992 here.

Recursive descent (..) finds a key at any depth. Chen has no email, so there are two results, not three:

{ "path": "/home/dev/data/orders.json", "query": "$..email" }
[
  "anna@example.com",
  "boris@example.com"
]

A query that matches nothing returns an empty array. That’s a valid answer, different from a field whose value is null:

{ "path": "/home/dev/data/orders.json", "query": "$.orders[?@.coupon].id" }
[]

RFC 9535 also defines functions for filters. length() counts the characters of a string, the elements of an array or the members of an object. Orders whose customer name is longer than four characters:

{ "path": "/home/dev/data/orders.json", "query": "$.orders[?length(@.customer.name) > 4].id" }
[
  1002
]

The other functions are count() for the number of nodes a query selects, match() and search() for regular expressions, and value() to compare a single selected value.

When the query is wrong

Models learned JSONPath from years of older libraries that didn’t agree with each other, so they sometimes write syntax that the standard doesn’t have. The most common case is a script expression like [(@.length-1)], which some old libraries evaluated as JavaScript. RFC 9535 has no script expressions, and the tool says so with a position:

{ "path": "/home/dev/data/orders.json", "query": "$.orders[(@.length-1)].id" }
Query error at column 10: Script expressions (…) are not part of RFC 9535. Use [-1] for the last element or a filter like [?@.price < 10]

That message is meant for the model as much as for you. It reads the column and the hint, rewrites the query as $.orders[-1].id and calls the tool again. A plain syntax error gets the same treatment:

{ "path": "/home/dev/data/orders.json", "query": "$.orders[?@.total >]" }
Query error at column 20: Unexpected character "]", expected a query, literal or function call

Result order

RFC 9535 fixes the order of array elements, and of selectors you list yourself ([2,0] returns index 2 first). It doesn’t fix the order of object members selected by a wildcard or a filter, because JSON objects are unordered. This tool returns object members in the order they appear in the file, but another conforming implementation may not. If an agent compares results from two tools, it should compare them as multisets. The JSONPath guide covers this in more detail.

Things to ask your assistant

  • “In export.json, list the IDs of customers whose subscription status is past_due.”
  • “Find every email field in crm-dump.json, at any depth, and count them.”
  • “Which items in inventory.json have qty below 5? Show their paths.”
  • “Get the last element of the events array in audit.json.”

To experiment with a query yourself first, paste the document into the JSONPath tester. It highlights matches in the document as you type. Before querying a file that arrives as one long line, you can make it readable in the JSON formatter.

Why run the query outside the model

A model reading a large document is doing approximate retrieval. It may miss the 412th record, or return a value from the wrong nesting level when two objects have similar keys. A JSONPath query is exact. It returns every match and nothing else, and the result is short enough to read in full. It’s also cheap: the file stays on disk, and only the matches enter the conversation.

The jsonpath_query tool runs inside the devtoolbox.cc MCP server on your computer, which makes no network requests. Exports with customer data never leave your machine. Instructions for Claude Desktop, Claude Code, Cursor and VS Code are on the MCP install page.

← All posts