MCP server adding metadata version-diff intelligence to OpenMetadata
Project description
ometa-diff
Metadata version-diff intelligence for OpenMetadata.
Answer "what changed in my data catalog?" — via MCP tools for AI agents or a CLI for engineers.
OpenMetadata stores full version history for every entity. ometa-diff reads those snapshots, computes field-by-field diffs, and surfaces them as structured output — something OM's built-in MCP server has never offered.
Install
pip install ometa-diff # CLI only
pip install "ometa-diff[mcp]" # CLI + MCP server
Running OpenMetadata locally
If you don't have an OpenMetadata instance yet, spin one up with the included Docker Compose file.
Prerequisites: Docker Desktop installed and running.
# 1. Start the stack (first run takes ~5 min to pull images)
docker compose -f docker-compose-om.yml up -d
# 2. Wait until the server is healthy
docker compose -f docker-compose-om.yml ps
# openmetadata_server should show "healthy"
OpenMetadata is ready when http://localhost:8585 loads in your browser.
Default login: username admin / password admin
Getting the JWT token
- Log in at
http://localhost:8585 - Go to Settings (gear icon, bottom-left)
- Under Integrations, click Bots
- Click ingestion-bot
- Click Copy Token — this is your
OPENMETADATA_JWT_TOKEN
The token does not expire by default on a fresh local install.
Stopping the stack
docker compose -f docker-compose-om.yml down # stop but keep data
docker compose -f docker-compose-om.yml down -v # stop and delete all data
Quick Start
Set environment variables
macOS / Linux (bash/zsh):
export OPENMETADATA_HOST=http://localhost:8585/api
export OPENMETADATA_JWT_TOKEN=eyJhbG...
Windows (PowerShell):
$env:OPENMETADATA_HOST = "http://localhost:8585/api"
$env:OPENMETADATA_JWT_TOKEN = "eyJhbG..."
Windows (Command Prompt):
set OPENMETADATA_HOST=http://localhost:8585/api
set OPENMETADATA_JWT_TOKEN=eyJhbG...
The JWT token comes from: OM UI → Settings → Bots → Ingestion Bot → Copy Token.
Diff a specific entity
ometa-diff diff table my_service.prod_db.public.payments
ometa-diff diff table my_service.prod_db.public.payments --from 0.2 --to 0.4
ometa-diff diff table my_service.prod_db.public.payments --since 7d
View a changelog
ometa-diff changelog --service my_service --since 30d
ometa-diff changelog --user admin --since 7d
ometa-diff changelog --type table --since 14d
MCP Server
ometa-diff serve starts an MCP server over STDIO transport — the standard used by all MCP-compatible clients. It works with Claude Desktop, Cursor, VS Code (GitHub Copilot), Windsurf, Zed, and any other client that supports the MCP spec.
Generic config (any MCP client)
Most clients accept a JSON config block like this:
{
"mcpServers": {
"ometa-diff": {
"command": "uvx",
"args": ["--from", "ometa-diff[mcp]", "ometa-diff", "serve"],
"env": {
"OPENMETADATA_HOST": "http://localhost:8585/api",
"OPENMETADATA_JWT_TOKEN": "your-jwt-token"
}
}
}
}
Or if ometa-diff is already installed globally:
{
"mcpServers": {
"ometa-diff": {
"command": "ometa-diff",
"args": ["serve"],
"env": {
"OPENMETADATA_HOST": "http://localhost:8585/api",
"OPENMETADATA_JWT_TOKEN": "your-jwt-token"
}
}
}
}
Client-specific config paths
| Client | Config file location |
|---|---|
| Claude Desktop (macOS) | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Claude Desktop (Windows) | %APPDATA%\Claude\claude_desktop_config.json |
| Cursor | Settings → MCP → Add server |
| VS Code + GitHub Copilot | .vscode/mcp.json in your workspace |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| Zed | ~/.config/zed/settings.json under "context_servers" |
| Any STDIO-compatible client | Point command at ometa-diff serve |
MCP Tools
| Tool | Description | Example prompt |
|---|---|---|
metadata_diff |
Field-by-field diff between two entity versions | "What changed in the payments table?" |
metadata_changelog |
Aggregated changes across a service, type, or user | "Show all metadata changes in my service this week" |
metadata_change_summary |
High-level stats: counts, major/minor split, top changers | "Give me a summary of catalog activity this month" |
CLI Reference
ometa-diff diff <entity_type> <fqn> [--from VERSION] [--to VERSION] [--since Nd] [--format terminal|markdown|json]
ometa-diff changelog [--service NAME] [--user NAME] [--type TYPE] [--since Nd] [--format ...]
ometa-diff serve # Start MCP server over STDIO
ometa-diff config # Show current host and auth status
Output formats:
ometa-diff diff table payments --format json | jq '.changes[].field_path'
ometa-diff diff table payments --format markdown > diff.md
Architecture
src/ometa_diff/
├── models.py # Pydantic models: FieldChange, EntityDiff, CatalogChangelog
├── client.py # HTTP client wrapping OM's version REST APIs
├── differ.py # Core diff engine: compares two JSON version snapshots
├── changelog.py # Multi-entity changelog aggregation over time windows
├── formatter.py # Output rendering: terminal (Rich), markdown, JSON
├── mcp_server.py # MCP server with 3 tools
└── cli.py # Typer CLI entry point
No dependency on openmetadata-ingestion — uses httpx directly, same approach as OM's AI SDK.
Platform Support
Tested on Python 3.10, 3.11, 3.12 on Ubuntu, macOS, and Windows via CI.
Terminal output uses ASCII-safe characters to avoid encoding issues on Windows consoles.
Change Severity
| Severity | Examples |
|---|---|
| MAJOR | Column removed, column dataType changed, owner removed |
| MINOR | Description edited, tag added/removed, column added, owner changed |
| PATCH | Display name changed, other cosmetic updates |
Configuration
| Variable | Default | Description |
|---|---|---|
OPENMETADATA_HOST |
http://localhost:8585/api |
OM API base URL |
OPENMETADATA_JWT_TOKEN |
(required) | JWT bearer token from OM Bots settings |
Run ometa-diff config to verify the current values.
Development
git clone https://github.com/SamChawla/ometa-diff
cd ometa-diff
pip install -e ".[dev,mcp]"
pytest tests/ -v # Unit tests (no OM instance needed)
ruff check src/ tests/ # Lint
ruff format src/ tests/ # Format
Integration tests (requires live OM)
Start OpenMetadata (see above), then:
# macOS / Linux
export OPENMETADATA_HOST=http://localhost:8585/api
export OPENMETADATA_JWT_TOKEN=eyJhbG...
pytest tests/test_integration.py -v -m integration
# Windows PowerShell
$env:OPENMETADATA_HOST = "http://localhost:8585/api"
$env:OPENMETADATA_JWT_TOKEN = "eyJhbG..."
pytest tests/test_integration.py -v -m integration
Integration tests are skipped automatically in CI (env vars not set). They verify connectivity, resolve_fqn, list_versions, get_version, diff correctness on real entities, noise-field filtering, and changelog aggregation.
Remaining test coverage gaps
These require scenarios not easily automated:
| Gap | Reason |
|---|---|
ChangelogBuilder.for_service with a real multi-table service |
Needs seeded service data |
ChangelogBuilder.for_user filtering |
Needs multiple users with edit history |
| MCP tool invocation via an actual MCP client | Needs MCP client harness / E2E test |
| CLI output rendering (Rich terminal format) | TTY-dependent, hard to assert in CI |
License
Apache 2.0 — same as OpenMetadata.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ometa_diff-0.1.0b1.tar.gz.
File metadata
- Download URL: ometa_diff-0.1.0b1.tar.gz
- Upload date:
- Size: 51.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4b2062e8cc52af05148afbec0d678593213436f3fece463dfed6761eb7abad0
|
|
| MD5 |
dbdc8b5cb155394b5f2445f71dcf4e86
|
|
| BLAKE2b-256 |
f893b8b28ac24190e2091c5fce85add4921ac480231d0d3c34863af924ecf988
|
Provenance
The following attestation bundles were made for ometa_diff-0.1.0b1.tar.gz:
Publisher:
publish.yml on SamChawla/ometa-diff
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ometa_diff-0.1.0b1.tar.gz -
Subject digest:
c4b2062e8cc52af05148afbec0d678593213436f3fece463dfed6761eb7abad0 - Sigstore transparency entry: 1389496476
- Sigstore integration time:
-
Permalink:
SamChawla/ometa-diff@c593aa876d9faa1611e30459aeec6f3a3b9fd516 -
Branch / Tag:
refs/tags/v0.1.0b1 - Owner: https://github.com/SamChawla
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c593aa876d9faa1611e30459aeec6f3a3b9fd516 -
Trigger Event:
push
-
Statement type:
File details
Details for the file ometa_diff-0.1.0b1-py3-none-any.whl.
File metadata
- Download URL: ometa_diff-0.1.0b1-py3-none-any.whl
- Upload date:
- Size: 26.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ed9eb17876ada99e21172b8e35d4fb4fc27fa6f998d30dd05d4c8cce491ae465
|
|
| MD5 |
31d0d80b9c1529f322cf49c3e991f2cf
|
|
| BLAKE2b-256 |
cd2431690b752cc0a2dca532fa1650d4a701074158d6c648d07e7f6cd5d4d2ac
|
Provenance
The following attestation bundles were made for ometa_diff-0.1.0b1-py3-none-any.whl:
Publisher:
publish.yml on SamChawla/ometa-diff
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
ometa_diff-0.1.0b1-py3-none-any.whl -
Subject digest:
ed9eb17876ada99e21172b8e35d4fb4fc27fa6f998d30dd05d4c8cce491ae465 - Sigstore transparency entry: 1389496553
- Sigstore integration time:
-
Permalink:
SamChawla/ometa-diff@c593aa876d9faa1611e30459aeec6f3a3b9fd516 -
Branch / Tag:
refs/tags/v0.1.0b1 - Owner: https://github.com/SamChawla
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c593aa876d9faa1611e30459aeec6f3a3b9fd516 -
Trigger Event:
push
-
Statement type: