# jpx - JMESPath CLI with Extended Functions
[](https://crates.io/crates/jpx)
[](https://crates.io/crates/jpx)
[](https://github.com/joshrotenberg/jmespath-extensions#license)
A command-line tool for querying JSON data using JMESPath expressions with 400+ additional functions beyond the standard JMESPath specification.
## Acknowledgments
jpx builds on the excellent work of the JMESPath community:
- **[JMESPath](https://jmespath.org/)** - The query language specification created by [James Saryerwinnie](https://github.com/jamesls)
- **[jmespath.rs](https://crates.io/crates/jmespath)** - The Rust implementation by [@mtdowling](https://github.com/mtdowling) that provides our parsing, evaluation, and standard functions
- **[jp](https://github.com/jmespath/jp)** - The official JMESPath CLI (Go) - a minimal, focused tool that inspired jpx's design
If you only need standard JMESPath without extensions, consider using [jp](https://github.com/jmespath/jp) or the [`jmespath`](https://crates.io/crates/jmespath) crate directly.
## jpx vs jq
Coming from [jq](https://jqlang.org/)? Here's a quick comparison:
| **Language** | Custom DSL | JMESPath (standardized) |
| **Functions** | ~70 built-in | 400+ extensions |
| **Ecosystem** | Standalone | Works with AWS CLI, Ansible |
| **Streaming** | ✅ | ❌ |
```bash
# jq # jpx
jq '[.[] | select(.age > 30)]' jpx '[?age > `30`]'
jq '.[].name' jpx '[*].name'
**Choose jpx** for: extended functions (geo, hash, fuzzy, semver), multiple output formats, AI/MCP integration, JMESPath ecosystem compatibility.
**Choose jq** for: streaming large files, custom function definitions, complex recursive transformations.
**[Full comparison →](https://joshrotenberg.github.io/jmespath-extensions/examples/jq-comparison.html)**
## Installation
```bash
# Homebrew (macOS/Linux)
brew tap joshrotenberg/brew
brew install jpx
# Pre-built binaries (macOS, Linux, Windows)
# Download from https://github.com/joshrotenberg/jmespath-extensions/releases
# From crates.io
cargo install jpx
# From source
git clone https://github.com/joshrotenberg/jmespath-extensions
cd jmespath-extensions/jpx
cargo install --path .
# Without MCP server support (smaller binary)
cargo install --path . --no-default-features
```
## MCP Server (AI Assistant Integration)
jpx can run as an [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server, allowing AI assistants like Claude to use JMESPath for JSON querying and transformation.
### Building with MCP Support
MCP support is included by default. Simply build:
```bash
cargo build -p jpx --release
```
To build without MCP support (smaller binary):
```bash
cargo build -p jpx --no-default-features --release
```
### Running the Server
```bash
jpx mcp
```
### MCP Tools (17 total)
**Discovery** - Find and explore functionality:
| `search` | Fuzzy search functions by name, description, category, or signature |
| `similar` | Find functions related to a specified function |
| `functions` | List available functions (with optional category filter) |
| `describe` | Get detailed info for a specific function |
| `categories` | List all function categories |
**Data Analysis** - Understand JSON structure:
| `stats` | Analyze JSON structure (type, size, depth, field analysis) |
| `paths` | Extract all paths in dot notation (e.g., `users[0].name`) |
| `keys` | Extract object keys (optionally recursive with dot notation) |
**Querying** - Evaluate expressions:
| `evaluate` | Run JMESPath expressions against JSON input |
| `evaluate_file` | Query JSON files directly from disk (with security checks) |
| `batch_evaluate` | Run multiple expressions against the same input |
| `validate` | Check expression syntax without executing |
**JSON Utilities** - Transform and manipulate:
| `format` | Pretty-print JSON with configurable indentation |
| `diff` | Generate RFC 6902 JSON Patch between two documents |
| `patch` | Apply RFC 6902 JSON Patch operations |
| `merge` | Apply RFC 7396 JSON Merge Patch |
### Claude Desktop Configuration
Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
```json
{
"mcpServers": {
"jpx": {
"command": "/path/to/jpx",
"args": ["mcp"]
}
}
}
```
### Example Usage
Once configured, Claude can use jpx to query JSON data:
```
User: I have this JSON: {"users": [{"name": "alice", "age": 30}, {"name": "bob", "age": 25}]}
Get the names of users over 28.
Claude: [Uses jpx.evaluate with expression "users[?age > `28`].name"]
Result: ["alice"]
```
#### More MCP Examples
**Query a file directly:**
```
Claude: [Uses jpx.evaluate_file with file_path="/data/users.json", expression="users[*].email"]
```
**Batch multiple queries:**
```
Claude: [Uses jpx.batch_evaluate with input and expressions=["length(users)", "users[0].name", "max(users[*].age)"]]
Result: {results: [{expression: "length(users)", result: 10}, ...]}
```
**Compare JSON documents (RFC 6902):**
```
Claude: [Uses jpx.diff with source and target documents]
Result: [{"op": "replace", "path": "/name", "value": "bob"}, {"op": "add", "path": "/age", "value": 30}]
```
**Explore JSON structure:**
```
Claude: [Uses jpx.keys with input and recursive=true]
Result: ["user", "user.name", "user.profile", "user.profile.settings"]
```
## Usage
```bash
jpx [OPTIONS] [EXPRESSIONS]...
Arguments:
[EXPRESSIONS]... JMESPath expression(s) to evaluate (multiple are chained as a pipeline)
Options:
-e, --expression <EXPR> Expression(s) to evaluate (can be chained)
-Q, --query-file <FILE> Read JMESPath expression from file
-f, --file <FILE> Input file (reads from stdin if not provided)
-o, --output <FILE> Output file (writes to stdout if not provided)
-n, --null-input Don't read input, use null as input value
-s, --slurp Read all inputs into an array
--stream, --each Process input line by line (NDJSON/JSON Lines)
Output Formats:
-r, --raw Output raw strings without quotes
-c, --compact Compact output (no pretty printing)
-y, --yaml Output as YAML
--toml Output as TOML
--csv Output as CSV (for arrays of objects)
--tsv Output as TSV (for arrays of objects)
-l, --lines Output one JSON value per line (for arrays)
-t, --table Output as a formatted table (for arrays of objects)
--table-style <STYLE> Table style: unicode, ascii, markdown, plain
--color <MODE> Colorize output (auto, always, never)
JSON Patch Operations:
--diff <SRC> <TGT> Generate JSON Patch (RFC 6902) from two files
--patch <FILE> Apply JSON Patch (RFC 6902) to input
--merge <FILE> Apply JSON Merge Patch (RFC 7396) to input
Data Analysis:
--stats Show statistics about the input data
--paths List all paths in the input JSON
--types Show types alongside paths (use with --paths)
--values Show values alongside paths (use with --paths)
Function Discovery:
--list-functions List all available extension functions
--list-category <NAME> List functions in a specific category
--describe <FUNCTION> Show detailed info for a specific function
--search <QUERY> Search functions by name, description, or category
--similar <FUNCTION> Find functions similar to the specified function
Debugging:
--explain Show how an expression is parsed (AST)
--debug Show diagnostic information
--bench [N] Benchmark expression performance
--warmup <N> Warmup iterations before benchmarking
Modes:
-q, --quiet Suppress errors and warnings
-v, --verbose Show expression details and timing
--strict Strict mode - only standard JMESPath (no extensions)
--repl Start interactive REPL mode
--demo <NAME> Load a demo dataset (use with --repl)
Other:
--completions <SHELL> Generate shell completions (bash, zsh, fish, powershell, elvish)
-h, --help Print help
-V, --version Print version
```
## Environment Variables
Configure jpx defaults via environment variables (CLI flags take precedence):
| `JPX_VERBOSE=1` | Enable verbose mode |
| `JPX_QUIET=1` | Enable quiet mode |
| `JPX_STRICT=1` | Enable strict mode (standard JMESPath only) |
| `JPX_RAW=1` | Output raw strings without quotes |
| `JPX_COMPACT=1` | Compact output (no pretty printing) |
```bash
# Set defaults in your shell profile
export JPX_RAW=1 # Always output raw strings
# Temporarily use strict mode
JPX_STRICT=1 jpx 'length(@)' data.json
# Unset to use extensions again
unset JPX_STRICT
jpx 'upper(name)' data.json # Extension functions work
```
## Function Discovery
```bash
# List all available functions grouped by category
# Shows 26 standard JMESPath functions and 400+ extension functions
jpx --list-functions
# List functions in a specific category
jpx --list-category string
jpx --list-category math
jpx --list-category geo
jpx --list-category standard # List all 26 standard JMESPath functions
# Get detailed info about a specific function
# Shows type (standard JMESPath or extension), category, signature, and example
jpx --describe upper
jpx --describe haversine_km
jpx --describe abs # Standard JMESPath function
```
## Examples
### Basic Queries
```bash
# Simple field access
# Array operations
# Nested access
```
### Streaming (NDJSON/JSON Lines)
Process newline-delimited JSON one line at a time with constant memory usage. Perfect for large log files, event streams, and data pipelines.
```bash
# Basic streaming - each line is processed independently
# With raw output for piping to other tools
# From a file
jpx --stream 'id' -f huge_dataset.jsonl
# Using the --each alias
# With expression functions
**Performance**: ~1.25 million lines/second (processes 100k lines in ~80ms)
**How it works**:
- Each line is parsed as a complete JSON object
- Expression is compiled once, reused for all lines
- Results output immediately (no accumulation)
- Empty lines and null results are skipped
- Errors on individual lines don't stop processing (use `-q` to suppress)
**Comparison with `--slurp`**:
- `--slurp` loads all lines into memory as an array, then queries
- `--stream` processes each line independently with constant memory
- Use `--slurp` when you need to aggregate across lines (e.g., `sum([*].value)`)
- Use `--stream` for large files or when lines are independent
### String Functions
```bash
# Case conversion
# String manipulation
```
### Array Functions
```bash
# Get unique values
# Chunk arrays
# Array statistics
```
### Date/Time Functions
```bash
# Current Unix timestamp
# Format a Unix timestamp
# Date arithmetic (add 7 days to timestamp)
```
### Duration Functions
```bash
# Parse human-readable durations
# Format seconds as duration
```
### Color Functions
```bash
# Convert colors
# Color manipulation
```
### Computing Functions
```bash
# Parse byte sizes
# Format bytes
# Bitwise operations
```
### Hash and Encoding Functions
```bash
# Hash functions
# Base64 encoding
# URL encoding
```
### Geo Functions
```bash
# Calculate distance between coordinates (km)
# Calculate bearing
```
### Network Functions
```bash
# IP address operations
```
### Semver Functions
```bash
# Parse semantic versions
# Compare versions
# Check version constraints
```
### Text Analysis Functions
```bash
# Word and character counts
# Reading time estimation
# Word frequencies
```
### Phonetic Functions
```bash
# Soundex encoding
# Check if names sound alike
# Double Metaphone
```
### Fuzzy Matching Functions
```bash
# Levenshtein distance
# Jaro-Winkler similarity
# Sorensen-Dice coefficient
```
### ID Generation Functions
```bash
# Generate UUIDs
# Generate nanoids
# Generate ULIDs
```
### Validation Functions
```bash
# Email validation
# URL validation
# UUID validation
# IP address validation
```
### Expression Functions (Higher-Order)
```bash
# Filter with expression (expression string first, then array)
echo '[{"name": "Alice"}, {"name": "Bob"}]' | jpx 'map_expr(`"name"`, @)'
# ["Alice", "Bob"]
# Group by expression
```
## Using Test Data Files
The `testdata/` directory contains sample JSON files for experimenting:
```bash
# Users data
jpx -f testdata/users.json '[].name'
jpx -f testdata/users.json 'filter_expr(@, &age > `25`) | [].name'
# Server logs
jpx -f testdata/servers.json 'filter_expr(@, &status == `active`) | length(@)'
jpx -f testdata/servers.json '[].{name: name, uptime: format_duration(uptime_seconds)}'
# E-commerce orders
jpx -f testdata/orders.json 'sum([].total)'
jpx -f testdata/orders.json 'group_by_expr(@, &status)'
# Geo locations
jpx -f testdata/locations.json 'haversine_km([0].lat, [0].lon, [1].lat, [1].lon)'
# Versions
jpx -f testdata/packages.json 'sort_by_expr(@, &semver_parse(version).major)'
```
## Using Query Files
For complex queries, you can store the JMESPath expression in a file and use `-Q` / `--query-file`:
```bash
# Create a query file
cat > transform.jmespath << 'EOF'
{
users: @[?active].{
name: name,
email: contact.email,
joined: format_date(created_at, '%Y-%m-%d')
},
total: length(@[?active]),
generated: now()
}
EOF
# Run the query
jpx -Q transform.jmespath -f users.json
```
Benefits of query files:
- Easier to write and edit complex expressions
- Can be version controlled
- Reusable across different data files
- No shell escaping issues
See the `queries/` directory for example query files.
## Tips
- Use `-r` (raw) when piping string output to other commands
- Use `-c` (compact) for single-line JSON output
- Use `--list-functions` to see all available functions
- Backticks create literal values: `` `5` `` is number 5, `` `"hello"` `` is string
- Use `&` prefix for expression references in higher-order functions
## License
MIT OR Apache-2.0