Pythia: Ask Your Dataspace
Ask your Gaia-X data space in plain language. MCP-native Python SDK for Eclipse EDC.
Pythia is a natural-language and MCP client for Gaia-X / Eclipse EDC data spaces. Instead of working with provider URLs, asset IDs, ODRL policies, and the EDC negotiation state machine directly, you ask a question in plain language and Pythia handles catalog discovery, contract negotiation, transfer, and retrieval.
from pythia import DataSpace
ds = DataSpace(
management_url="http://consumer:29193/management",
providers=[{"dsp": "http://provider:19194/protocol/2025-1", "id": "provider"}],
)
# Natural language query — Pythia negotiates, retrieves, and returns a readable
# Answer (a synthesized table + provenance). Pass raw=True for the raw asset bytes.
answer = await ds.ask("CO2 emissions data for German automotive suppliers 2023")
print(answer.to_markdown())
It also ships as an MCP server, exposing data-space queries as tools for Claude, GPT, or any MCP-compatible agent.
Components
| Layer | Component |
|---|---|
| 1 — Core client | Async httpx EDC client, full DSP state machine, typed errors, no RabbitMQ |
| 2 — NL interface | ds.ask() — parallel catalog fan-out + offline granite-embedding-97m-multilingual-r2 ranking + auto-negotiate; returns a readable Answer by default (synthesized table on success, or an explained refusal in Answer.note), raw=True for bytes |
| 3 — MCP server | pythia-mcp — wraps ds.ask() as MCP tools for Claude / GPT / any agent |
Install
pip install 'pythia-edc[all]'
Running the demo
The repo ships a self-contained demo stack driven by a single ./demo entrypoint.
./demo up # start the stack
./demo ask "CO2 emissions for German automotive suppliers 2023"
./demo repl # interactive query loop
./demo down # stop the stack
By default ./demo up runs everything locally: provider + consumer EDC
connectors, a mock data server, and provider seeding.
Config profiles
Any setting can live in a profile file instead of inline env vars. ./demo
loads demo.env by default and exports every assignment to both the stack
scripts and the Python client. Copy the example to get started:
cp demo.env.example demo.env # edit, then ./demo up
Keep several named profiles and select one per run with ENV_FILE:
ENV_FILE=demo.consumer.env ./demo up
Local consumer, remote providers
To run only the consumer locally and talk to providers that run on separate
servers, set CONSUMER_ONLY=1 (skips the local provider, mock server, and
seeding) and point PYTHIA_PROVIDERS at the remote DSP endpoints. See
demo.env.example for the full template, including the TLS variables
(PYTHIA_CA_BUNDLE, PYTHIA_CLIENT_CERT/KEY) for talking to remote providers.
CONSUMER_ONLY=1 \
PYTHIA_PROVIDERS='[{"dsp":"https://provider1.example/protocol/2025-1","id":"rheinmobil"}]' \
./demo up
Usage
# Low-level
catalog = await ds.catalog.query(provider_dsp="...", provider_id="...")
agreement_id = await ds.negotiate(provider_dsp="...", provider_id="...",
offer_id=offer.id, asset_id=asset.id)
data = await ds.fetch(provider_dsp="...", provider_id="...",
agreement_id=agreement_id, asset_id=asset.id)
# Natural language — returns a readable Answer (table + provenance)
answer = await ds.ask("quarterly SVHC substance reports from EU chemical suppliers")
print(answer.to_markdown())
# ...or the raw asset bytes, for the developer/agent path
raw = await ds.ask("quarterly SVHC substance reports", raw=True)
Command line
Installing the package puts a pythia command on your PATH, so you can query a
data space from anywhere:
# Install globally in an isolated environment (uv) — or use pipx
uv tool install 'pythia-edc[all]'
# Point it at your consumer connector + providers, then ask
export PYTHIA_MANAGEMENT_URL="http://localhost:29193/management"
export PYTHIA_PROVIDERS='[{"dsp": "http://localhost:19194/protocol/2025-1", "id": "provider"}]'
pythia ask "CO2 emissions for German automotive suppliers 2023"
pythia ask "quarterly SVHC reports" --verify-trust --json
# Inspect what a data space offers, without negotiating (mirrors the MCP
# browse_catalog tool). Lists assets across all configured providers.
pythia catalog
pythia catalog --provider rheinmobil https://provider1.example/protocol/2025-1 --json
Connection settings are read from PYTHIA_* environment variables (see
pythia.config.ConnectorConfig); --management-url and --provider ID DSP
(repeatable) override them per invocation. Run pythia ask --help for all options.
Provider responses are streamed and capped at 100 MiB by default (a memory-DoS
guard against a hostile connector); override with PYTHIA_MAX_RESPONSE_BYTES or
the max_response_bytes kwarg on DataSpace.
The repo's
./demo askis the zero-config local playground;pythia askis the same query path pointed at real connectors you configure.
MCP server
export PYTHIA_MANAGEMENT_URL="http://localhost:29193/management"
export PYTHIA_PROVIDERS='[{"dsp": "http://localhost:19194/protocol/2025-1", "id": "provider"}]'
pythia-mcp
Gaia-X standards
| Standard | Usage |
|---|---|
DSP dataspace-protocol-http:2025-1 |
Full state machine: catalog → negotiate → transfer → EDR |
| DCAT | Catalog parsing, asset/offer extraction |
| ODRL | Policy offer construction with correct context |
| MCP (Model Context Protocol) | AI agent integration (pythia-mcp server) |
| Verifiable Credentials + SHACL | Trust slice: verify a provider VC (structure + signature) and validate the offer + ODRL policy against a SHACL shape before negotiating |
Provider VC verification
When verify_trust=True and a credential_source is supplied, Pythia verifies each
provider's Verifiable Credential fully offline before validating its offer:
- structural validation (required
@context/type/id/issuerfields, SHACL shape) - validity-window check (
validFrom/ expiry) - Ed25519
JsonWebSignature2020detached-JWS signature verification viadid:key - issuer ↔ signing-key binding (the verifying key must belong to the credential issuer)
- an optional issuer trust-list of allowed issuer DIDs
from pythia import DataSpace, StaticCredentialSource
ds.ask("CO2 emissions from German automotive suppliers 2023",
verify_trust=True,
credential_source=StaticCredentialSource({"provider": provider_vc}),
trust_list={"did:key:z6Mk..."})
Rejections surface as structured CredentialError.failures, rendered into prose by the
Explainer (e.g. "the credential has expired", "the credential issuer is not trusted").
In the demo, trust verification is on by default: ./demo ask "..." verifies each
provider's VC and SHACL-validates its offer before negotiating. The demo mints VCs from a
fixed demo CA for the trusted providers, while DonauTech is intentionally untrusted —
its VC is signed by an issuer not on the consumer's trust-list, so it is rejected
(UntrustedIssuer) and the query falls through to a trusted provider. Disable the gate
with ./demo ask --no-verify-trust "...". (The library default of verify_trust is
unchanged — off — so non-demo callers opt in explicitly as shown above.)
Roadmap: full GXDCH / Notary online credential verification, and resolving did:web
issuer DID-documents (the current crypto path effectively trusts did:key issuers, since
the verifying key must equal the issuer); provider auto-discovery (the Meta Registry is a
trust-profile source, not a connector directory, so endpoint discovery needs an EDC
FederatedCatalog or a self-description convention).
Prerequisites
- Python 3.13+, running EDC consumer + provider connectors
sentence-transformersfords.ask()ranking (offline,ibm-granite/granite-embedding-97m-multilingual-r2, ~130MB, multilingual)- A local LM Studio server for the default
ds.ask()answer (the synthesized table) and the optionalLLMExplainer. LM Studio exposes an OpenAI-compatible API athttp://localhost:1234/v1(Developer → Start Server); load a model and Pythia will use it. Override the endpoint/model withPYTHIA_LLM_BASE_URL/PYTHIA_LLM_MODEL. Without it,ds.ask()still ranks, negotiates, and fetches — passraw=Truefor the asset bytes, or the defaultAnswercarries anoteexplaining the synthesizer was unreachable.
The local end-to-end demo additionally needs Docker and a checkout of the
Eclipse EDC Samples (point EDC_SAMPLES_DIR at it).
Contributing
Contributions are welcome — see CONTRIBUTING.md for setup and the checks to run.
License
MIT © Pareo
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 pythia_edc-0.3.0.tar.gz.
File metadata
- Download URL: pythia_edc-0.3.0.tar.gz
- Upload date:
- Size: 67.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5e3c6e84aedb378127d17770cf17e9b6ec007c0db6af598766c0f62c6d7a29b6
|
|
| MD5 |
0acfa809428516653e2255dec8715553
|
|
| BLAKE2b-256 |
bd33b18d13cf6fb7630efe3ba3334c3c8c610d3fad5910ff48056574496f5678
|
Provenance
The following attestation bundles were made for pythia_edc-0.3.0.tar.gz:
Publisher:
publish.yml on Pareo-AI/pythia-edc
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pythia_edc-0.3.0.tar.gz -
Subject digest:
5e3c6e84aedb378127d17770cf17e9b6ec007c0db6af598766c0f62c6d7a29b6 - Sigstore transparency entry: 2205038955
- Sigstore integration time:
-
Permalink:
Pareo-AI/pythia-edc@e2f79fc449e110d24ee2101305c277d369a968e1 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/Pareo-AI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e2f79fc449e110d24ee2101305c277d369a968e1 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pythia_edc-0.3.0-py3-none-any.whl.
File metadata
- Download URL: pythia_edc-0.3.0-py3-none-any.whl
- Upload date:
- Size: 45.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
baaad02e642495a584674ff066609c8e264e5692f502c8168b054c1bc2cd98c4
|
|
| MD5 |
0c23cec2cbe7e7792a5c35b9d9974b9e
|
|
| BLAKE2b-256 |
9321a0823f087d029e0e17b1f192eb3eb185249b21a61b728f979f19784cbbf0
|
Provenance
The following attestation bundles were made for pythia_edc-0.3.0-py3-none-any.whl:
Publisher:
publish.yml on Pareo-AI/pythia-edc
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pythia_edc-0.3.0-py3-none-any.whl -
Subject digest:
baaad02e642495a584674ff066609c8e264e5692f502c8168b054c1bc2cd98c4 - Sigstore transparency entry: 2205038974
- Sigstore integration time:
-
Permalink:
Pareo-AI/pythia-edc@e2f79fc449e110d24ee2101305c277d369a968e1 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/Pareo-AI
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e2f79fc449e110d24ee2101305c277d369a968e1 -
Trigger Event:
push
-
Statement type: