spark-mcp 0.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- spark_mcp-0.4.1/LICENSE +21 -0
- spark_mcp-0.4.1/MANIFEST.in +3 -0
- spark_mcp-0.4.1/PKG-INFO +329 -0
- spark_mcp-0.4.1/README.md +297 -0
- spark_mcp-0.4.1/pyproject.toml +77 -0
- spark_mcp-0.4.1/requirements.txt +2 -0
- spark_mcp-0.4.1/scripts/security_sanitizer.py +318 -0
- spark_mcp-0.4.1/scripts/verify_api_integration.py +279 -0
- spark_mcp-0.4.1/setup.cfg +4 -0
- spark_mcp-0.4.1/spark_mcp/__init__.py +3 -0
- spark_mcp-0.4.1/spark_mcp/__main__.py +4 -0
- spark_mcp-0.4.1/spark_mcp/api/__init__.py +1 -0
- spark_mcp-0.4.1/spark_mcp/api/api_client_base.py +51 -0
- spark_mcp-0.4.1/spark_mcp/api/api_client_rest.py +371 -0
- spark_mcp-0.4.1/spark_mcp/api/api_client_spark.py +676 -0
- spark_mcp-0.4.1/spark_mcp/api_client.py +13 -0
- spark_mcp-0.4.1/spark_mcp/auth.py +194 -0
- spark_mcp-0.4.1/spark_mcp/connectors/__init__.py +1 -0
- spark_mcp-0.4.1/spark_mcp/kg_ingest.py +286 -0
- spark_mcp-0.4.1/spark_mcp/mcp_config.json +1 -0
- spark_mcp-0.4.1/spark_mcp/mcp_server.py +67 -0
- spark_mcp-0.4.1/spark_mcp/models.py +84 -0
- spark_mcp-0.4.1/spark_mcp/ontology/__init__.py +7 -0
- spark_mcp-0.4.1/spark_mcp/ontology/certification.json +34 -0
- spark_mcp-0.4.1/spark_mcp/ontology/fixtures/records.json +5 -0
- spark_mcp-0.4.1/spark_mcp/ontology/mappings/source.yaml +9 -0
- spark_mcp-0.4.1/spark_mcp/ontology/migrations/manifest.json +6 -0
- spark_mcp-0.4.1/spark_mcp/ontology/shapes/connector.shacl.ttl +104 -0
- spark_mcp-0.4.1/spark_mcp/ontology/spark.ttl +81 -0
- spark_mcp-0.4.1/spark_mcp/prompts/__init__.py +1 -0
- spark_mcp-0.4.1/spark_mcp/skills/__init__.py +1 -0
- spark_mcp-0.4.1/spark_mcp/skills/spark-kg-ingestion/SKILL.md +59 -0
- spark_mcp-0.4.1/spark_mcp/skills/spark-transform-operations/SKILL.md +80 -0
- spark_mcp-0.4.1/spark_mcp.egg-info/PKG-INFO +329 -0
- spark_mcp-0.4.1/spark_mcp.egg-info/SOURCES.txt +44 -0
- spark_mcp-0.4.1/spark_mcp.egg-info/dependency_links.txt +1 -0
- spark_mcp-0.4.1/spark_mcp.egg-info/entry_points.txt +11 -0
- spark_mcp-0.4.1/spark_mcp.egg-info/requires.txt +19 -0
- spark_mcp-0.4.1/spark_mcp.egg-info/top_level.txt +9 -0
- spark_mcp-0.4.1/tests/conftest.py +0 -0
- spark_mcp-0.4.1/tests/test_api_client.py +180 -0
- spark_mcp-0.4.1/tests/test_auth_env.py +115 -0
- spark_mcp-0.4.1/tests/test_kg_ingest.py +172 -0
- spark_mcp-0.4.1/tests/test_ownership.py +97 -0
- spark_mcp-0.4.1/tests/test_rest_operations.py +96 -0
- spark_mcp-0.4.1/tests/test_startup.py +9 -0
spark_mcp-0.4.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Knuckles-Team
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
spark_mcp-0.4.1/PKG-INFO
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: spark-mcp
|
|
3
|
+
Version: 0.4.1
|
|
4
|
+
Summary: Spark Connect (gRPC) API + MCP Server for Agentic AI!
|
|
5
|
+
Author-email: Project Maintainers <maintainers@users.noreply.github.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
|
8
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Requires-Python: <3.15,>=3.12
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.6
|
|
16
|
+
Requires-Dist: httpx>=0.28.1
|
|
17
|
+
Requires-Dist: numpy>=2.5.4
|
|
18
|
+
Requires-Dist: pandas>=3.0.6
|
|
19
|
+
Requires-Dist: pyarrow>=26.0.0
|
|
20
|
+
Requires-Dist: pyspark-client<4.2.0,>=4.1.3
|
|
21
|
+
Requires-Dist: requests>=2.34.2
|
|
22
|
+
Provides-Extra: mcp
|
|
23
|
+
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.6; extra == "mcp"
|
|
24
|
+
Provides-Extra: all
|
|
25
|
+
Requires-Dist: agent-connector-sdk[mcp]<1.0.0,>=0.3.6; extra == "all"
|
|
26
|
+
Provides-Extra: test
|
|
27
|
+
Requires-Dist: pytest-xdist>=3.8.0; extra == "test"
|
|
28
|
+
Requires-Dist: pytest>=9.1.1; extra == "test"
|
|
29
|
+
Requires-Dist: pytest-asyncio>=1.4.0; extra == "test"
|
|
30
|
+
Requires-Dist: pytest-cov>=7.1.0; extra == "test"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# Spark Mcp
|
|
34
|
+
## CLI or API | MCP
|
|
35
|
+
|
|
36
|
+

|
|
37
|
+

|
|
38
|
+

|
|
39
|
+

|
|
40
|
+

|
|
41
|
+

|
|
42
|
+

|
|
43
|
+

|
|
44
|
+

|
|
45
|
+

|
|
46
|
+

|
|
47
|
+

|
|
48
|
+

|
|
49
|
+

|
|
50
|
+

|
|
51
|
+

|
|
52
|
+

|
|
53
|
+

|
|
54
|
+
|
|
55
|
+
*Version: 0.4.1*
|
|
56
|
+
|
|
57
|
+
> **Documentation** — Installation, deployment, and usage across the API, CLI, MCP,
|
|
58
|
+
> and A2A agent interfaces are maintained in the
|
|
59
|
+
> [official documentation](https://knuckles-team.github.io/spark-mcp/).
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Table of Contents
|
|
64
|
+
- [Overview](#overview)
|
|
65
|
+
- [Installation](#installation)
|
|
66
|
+
- [Usage](#usage)
|
|
67
|
+
- [Architecture](#architecture)
|
|
68
|
+
- [Environment Variables](#environment-variables)
|
|
69
|
+
- [MCP Tools](#mcp-tools)
|
|
70
|
+
- [Documentation](#documentation)
|
|
71
|
+
|
|
72
|
+
## Overview
|
|
73
|
+
`spark-mcp` exposes a standardized interface to the live Spark Connect deployment
|
|
74
|
+
via the Model Context Protocol — SQL/session execution, versioned Transform
|
|
75
|
+
submission/tracking/rerun against the shared Iceberg `lakehouse` catalog
|
|
76
|
+
(`scope=lakekeeper`, explicit — the same landmine Trino/Lakekeeper hit if dropped),
|
|
77
|
+
namespace/table catalog reads, OpenLineage config/status reporting, and a
|
|
78
|
+
Wire-First `spark_ingest_run` tool that pushes the
|
|
79
|
+
`SparkApplication -> SparkJob -> Transform -> TransformRun -> DatasetVersion` chain
|
|
80
|
+
into the epistemic-graph Knowledge Graph.
|
|
81
|
+
|
|
82
|
+
**Spark Connect is live**, confirmed 2026-08-26 against
|
|
83
|
+
`spark-connect.apps.svc:15002` with a real `pyspark.sql.connect` session — a query
|
|
84
|
+
against `lakehouse.analytics.trino_verify` returned the same 3 rows Trino's sibling
|
|
85
|
+
lane already proved reading/writing (cross-engine Iceberg interop). See
|
|
86
|
+
[docs/architecture.md](docs/architecture.md) for the full evidence and this
|
|
87
|
+
package's `AGENTS.md` for known gaps (identity-token attach, `ActionSpec`
|
|
88
|
+
typed-Actions deferral).
|
|
89
|
+
|
|
90
|
+
Talks directly to Spark over `pyspark-client` (the thin Spark Connect client) for SQL, DataFrame and catalog operations, and over the Spark monitoring REST API (`/api/v1` on the driver UI and the History Server) for applications, jobs, stages, executors, storage, environment and SQL executions, never
|
|
91
|
+
`bin/spark-shell --remote` (does not work on the vanilla Spark image) and never a
|
|
92
|
+
`kubectl exec spark-sql` fallback.
|
|
93
|
+
|
|
94
|
+
## Installation
|
|
95
|
+
|
|
96
|
+
Pick the extra that matches what the operator want to run:
|
|
97
|
+
|
|
98
|
+
| Extra | Installs | Use when |
|
|
99
|
+
|-------|----------|----------|
|
|
100
|
+
| `spark-mcp[mcp]` | Connector-focused MCP server (`agent-connector-sdk` — FastMCP/FastAPI + `epistemic-graph[full]`) | The operator only run the **MCP server** (smallest install / image) |
|
|
101
|
+
| `spark-mcp[all]` | Everything (`mcp` + `agent` + `logfire`) | Development / both surfaces |
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
uv pip install "spark-mcp[mcp]"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Container images (`:mcp`)
|
|
108
|
+
|
|
109
|
+
One multi-stage `docker/Dockerfile` builds the MCP-only image (`--target mcp`):
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
docker build --target mcp -t spark-mcp:mcp .
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Both images install a headless JRE at runtime — `pyspark[connect]`'s gRPC client has
|
|
116
|
+
a JVM-side dependency, unlike the fleet's pure-Python REST connectors.
|
|
117
|
+
|
|
118
|
+
## Usage
|
|
119
|
+
Run the MCP server directly:
|
|
120
|
+
```bash
|
|
121
|
+
python -m spark_mcp
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### MCP Configuration Example (stdio)
|
|
125
|
+
|
|
126
|
+
```json
|
|
127
|
+
{
|
|
128
|
+
"mcpServers": {
|
|
129
|
+
"spark-mcp": {
|
|
130
|
+
"command": "uv",
|
|
131
|
+
"args": ["run", "spark-mcp"],
|
|
132
|
+
"env": {
|
|
133
|
+
"MCP_TOOL_MODE": "intent",
|
|
134
|
+
"SPARK_CONNECT_URL": "sc://spark-connect.apps.svc:15002",
|
|
135
|
+
"SPARK_LAKEHOUSE_CATALOG": "lakehouse",
|
|
136
|
+
"SPARK_LAKEHOUSE_SCOPE": "lakekeeper",
|
|
137
|
+
"SPARK_ENABLE_TRANSFORMS": "False",
|
|
138
|
+
"SPARKTOOL": "True"
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Architecture
|
|
146
|
+
|
|
147
|
+
`api_client.py` wraps `api/api_client_spark.py`'s `SparkApi`, a thin gRPC client
|
|
148
|
+
over `pyspark.sql.connect.session.SparkSession`, behind `api/api_client_base.py`'s
|
|
149
|
+
typed-error layer (`SparkApiError` with a `kind`: `unreachable` / `job_failed` /
|
|
150
|
+
`session_evicted` / `disabled` — never a silent empty result). `auth.py` mints
|
|
151
|
+
Keycloak client-credentials identity tokens and can attach them as real gRPC bearer
|
|
152
|
+
credentials, but the deployed Spark Connect endpoint is plaintext gRPC today, so
|
|
153
|
+
attach is disabled by default (see `docs/architecture.md`).
|
|
154
|
+
|
|
155
|
+
`mcp_server.py` serves one typed `spark_<operation>` tool per `SparkApi` method
|
|
156
|
+
(`spark_sql`, `spark_describe`, `spark_cancel`, `spark_submit_transform`,
|
|
157
|
+
`spark_rerun_transform`, `spark_list_transform_runs`, `spark_list_lakekeeper_tables`,
|
|
158
|
+
`spark_lineage_config`, `spark_lineage_events`, `spark_application_status`) through one
|
|
159
|
+
`register_tool_surface(...)` call; GET-like reads are read-only and `spark_cancel` is
|
|
160
|
+
destructive. `kg_ingest.py` exposes
|
|
161
|
+
`ingest_entities`/`ingest_run` plus record-mapping helpers around the required
|
|
162
|
+
`native_ingest` (Wire-First) authority.
|
|
163
|
+
|
|
164
|
+
## Python version
|
|
165
|
+
|
|
166
|
+
Python 3.14 (floor 3.12) against a Spark 4.1 server. `pyspark-client` 4.1 is the
|
|
167
|
+
thin Spark Connect client; it runs on numpy 2, pandas 3 and pyarrow wheels.
|
|
168
|
+
`pyspark-client` ships only a pure-Python sdist, so it is the one package built
|
|
169
|
+
from source (`[tool.pipelines] allow-source-build = ["pyspark-client"]`).
|
|
170
|
+
|
|
171
|
+
## Environment Variables
|
|
172
|
+
|
|
173
|
+
<!-- ENV-VARS-TABLE:START -->
|
|
174
|
+
|
|
175
|
+
#### Package environment variables
|
|
176
|
+
|
|
177
|
+
| Variable | Example | Description |
|
|
178
|
+
|----------|---------|-------------|
|
|
179
|
+
| `SPARK_CONNECT_URL` | `sc://spark-connect.apps.svc:15002` | |
|
|
180
|
+
| `SPARK_UI_URL` | `http://spark-runner.apps.svc:4040` | driver monitoring REST |
|
|
181
|
+
| `SPARK_HISTORY_URL` | `http://spark-history.apps.svc:18080` | History Server REST |
|
|
182
|
+
| `SPARK_REST_TIMEOUT_S` | `30` | |
|
|
183
|
+
| `SPARK_SUBMIT_TIMEOUT_S` | `300` | |
|
|
184
|
+
| `SPARK_LAKEHOUSE_CATALOG` | `lakehouse` | document/verify the invariant client-side — same invalid_scope landmine as |
|
|
185
|
+
| `SPARK_LAKEHOUSE_SCOPE` | `lakekeeper` | |
|
|
186
|
+
| `SPARK_ENABLE_TRANSFORMS` | `False` | egeria-mcp's EGERIA_ENABLE_WRITE) — spark_submit_transform/spark_rerun_transform |
|
|
187
|
+
| `SPARK_CONNECT_ATTACH_IDENTITY_TOKEN` | secret-injected | Service is plaintext gRPC; attaching a bearer token forces a TLS channel the |
|
|
188
|
+
| `SPARK_CONNECT_USE_SSL` | `False` | |
|
|
189
|
+
| `SPARK_SERVICE_CLIENT_ID` | `spark-service` | |
|
|
190
|
+
| `SPARK_SERVICE_CLIENT_SECRET` | secret-injected | |
|
|
191
|
+
| `SPARK_OAUTH_SCOPE` | `lakekeeper` | |
|
|
192
|
+
| `SPARK_OAUTH_TOKEN_URL` | secret-injected | |
|
|
193
|
+
| `SPARK_KEYCLOAK_URL` | `http://localhost:8080` | |
|
|
194
|
+
| `SPARK_KEYCLOAK_REALM` | `homelab` | |
|
|
195
|
+
| `SPARKTOOL` | `True` | |
|
|
196
|
+
| `INGESTTOOL` | `True` | |
|
|
197
|
+
|
|
198
|
+
#### Inherited agent-connector-sdk variables (apply to every connector)
|
|
199
|
+
|
|
200
|
+
| Variable | Example | Description |
|
|
201
|
+
|----------|---------|-------------|
|
|
202
|
+
| `TRANSPORT` | `stdio` | MCP transport: `stdio` \| `streamable-http` \| `sse` |
|
|
203
|
+
| `HOST` | `127.0.0.1` | Loopback bind host (set an authenticated ingress explicitly) |
|
|
204
|
+
| `PORT` | `8000` | Bind port (HTTP transports) |
|
|
205
|
+
| `MCP_TOOL_MODE` | `intent` | Tool surface: `intent` \| `condensed` \| `verbose` \| `both` |
|
|
206
|
+
| `MCP_ENABLED_TOOLS` | — | Comma-separated tool allow-list |
|
|
207
|
+
| `MCP_DISABLED_TOOLS` | — | Comma-separated tool deny-list |
|
|
208
|
+
| `MCP_ENABLED_TAGS` | — | Comma-separated tag allow-list |
|
|
209
|
+
| `MCP_DISABLED_TAGS` | — | Comma-separated tag deny-list |
|
|
210
|
+
| `EUNOMIA_TYPE` | `none` | Authorization mode: `none` \| `embedded` \| `remote` |
|
|
211
|
+
| `EUNOMIA_POLICY_FILE` | `mcp_policies.json` | Embedded Eunomia policy file |
|
|
212
|
+
| `EUNOMIA_REMOTE_URL` | — | Remote Eunomia authorization server URL |
|
|
213
|
+
| `ENABLE_OTEL` | `False` | Enable OpenTelemetry export |
|
|
214
|
+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | — | OTLP collector endpoint |
|
|
215
|
+
| `MCP_CLIENT_AUTH` | — | Outbound MCP child auth: `oidc-client-credentials` \| `basic` \| `none` |
|
|
216
|
+
| `OIDC_CLIENT_ID` | — | OIDC client id (service-account auth) |
|
|
217
|
+
| `OIDC_CLIENT_SECRET_REF` | `secret://identity/oidc-client-secret` | Runtime secret reference for the OIDC service account |
|
|
218
|
+
| `MCP_BASIC_AUTH_USERNAME` | — | HTTP Basic username (`MCP_CLIENT_AUTH=basic`) |
|
|
219
|
+
| `MCP_BASIC_AUTH_PASSWORD_REF` | `secret://identity/mcp-basic-password` | Runtime secret reference for HTTP Basic auth (`MCP_CLIENT_AUTH=basic`) |
|
|
220
|
+
| `DEBUG` | `False` | Verbose logging |
|
|
221
|
+
| `PYTHONUNBUFFERED` | `1` | Unbuffered stdout (recommended in containers) |
|
|
222
|
+
| `MCP_URL` | `http://localhost:8000/mcp` | URL of the MCP server the agent connects to |
|
|
223
|
+
| `PROVIDER` | `openai` | LLM provider for the agent |
|
|
224
|
+
| `MODEL_ID` | `gpt-4o` | Model id for the agent |
|
|
225
|
+
| `ENABLE_WEB_UI` | `True` | Serve the AG-UI web interface |
|
|
226
|
+
|
|
227
|
+
_15 package + 24 inherited variable(s). Auto-generated from `.env.example` + the shared agent-connector-sdk set — do not edit._
|
|
228
|
+
<!-- ENV-VARS-TABLE:END -->
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
| Variable | Required | Notes |
|
|
232
|
+
|----------|----------|-------|
|
|
233
|
+
| `SPARK_CONNECT_URL` | recommended | Spark Connect gRPC endpoint. Defaults to `sc://spark-connect.apps.svc:15002`. |
|
|
234
|
+
| `SPARK_SUBMIT_TIMEOUT_S` | optional | Submission timeout budget. Defaults to `300`. |
|
|
235
|
+
| `SPARK_LAKEHOUSE_CATALOG` / `SPARK_LAKEHOUSE_SCOPE` | optional | Defaults to `lakehouse` / `lakekeeper` — never leave scope at the shared-client default `catalog`. |
|
|
236
|
+
| `SPARK_ENABLE_TRANSFORMS` | ✅ for writes | `spark_submit_transform`/`spark_rerun_transform` refuse unless `true`. |
|
|
237
|
+
| `SPARK_CONNECT_ATTACH_IDENTITY_TOKEN` / `SPARK_CONNECT_USE_SSL` | optional | Both must be `true` together — see `docs/architecture.md`. |
|
|
238
|
+
| `SPARK_SERVICE_CLIENT_ID` / `SPARK_SERVICE_CLIENT_SECRET` | for identity attach | Keycloak client-credentials. |
|
|
239
|
+
| `SPARK_OAUTH_SCOPE` / `SPARK_OAUTH_TOKEN_URL` / `SPARK_KEYCLOAK_URL` / `SPARK_KEYCLOAK_REALM` | optional | Token-mint configuration. |
|
|
240
|
+
|
|
241
|
+
See [.env.example](.env.example) for the full template.
|
|
242
|
+
|
|
243
|
+
## MCP Tools
|
|
244
|
+
|
|
245
|
+
| Group | Tools |
|
|
246
|
+
|-------|-------|
|
|
247
|
+
| session | `spark_sql`, `spark_describe`, `spark_cancel` |
|
|
248
|
+
| transforms | `spark_submit_transform`, `spark_list_transform_runs`, `spark_rerun_transform` |
|
|
249
|
+
| catalog | `spark_list_lakekeeper_tables` |
|
|
250
|
+
| lineage | `spark_lineage_config`, `spark_lineage_events` |
|
|
251
|
+
| ops | `spark_application_status` |
|
|
252
|
+
| ingest | `spark_ingest_run` |
|
|
253
|
+
|
|
254
|
+
## Documentation
|
|
255
|
+
- [Architecture](docs/architecture.md)
|
|
256
|
+
- [Configuration](docs/configuration.md)
|
|
257
|
+
- [AGENTS.md](AGENTS.md) — canonical agent-facing context, live-proof evidence, known gaps
|
|
258
|
+
|
|
259
|
+
## Available MCP Tools
|
|
260
|
+
|
|
261
|
+
<!-- MCP-TOOLS-TABLE:START -->
|
|
262
|
+
|
|
263
|
+
#### Condensed action-routed tools (`MCP_TOOL_MODE=condensed`)
|
|
264
|
+
|
|
265
|
+
| MCP Tool | Toggle Env Var | Description |
|
|
266
|
+
|----------|----------------|-------------|
|
|
267
|
+
| `spark_ingest_run` | `INGESTTOOL` | Push one TransformRun's SparkApplication->SparkJob->Transform->TransformRun |
|
|
268
|
+
|
|
269
|
+
#### Verbose 1:1 API-mapped tools (`MCP_TOOL_MODE=verbose` or `both`)
|
|
270
|
+
|
|
271
|
+
<details>
|
|
272
|
+
<summary>12 per-operation tools — one per public API method (click to expand)</summary>
|
|
273
|
+
|
|
274
|
+
| MCP Tool | Toggle Env Var | Description |
|
|
275
|
+
|----------|----------------|-------------|
|
|
276
|
+
| `spark_application_status` | `SPARKTOOL` | Best-effort application/session status. |
|
|
277
|
+
| `spark_cancel` | `SPARKTOOL` | Interrupt running operations on this session (all, or one tagged operation). |
|
|
278
|
+
| `spark_close` | `SPARK_APITOOL` | Invoke the close operation. |
|
|
279
|
+
| `spark_describe` | `SPARKTOOL` | Schema + column info for one fully-qualified table. |
|
|
280
|
+
| `spark_get_session` | `SPARK_APITOOL` | Return the cached Spark Connect session, building it on first use. |
|
|
281
|
+
| `spark_lineage_config` | `SPARKTOOL` | Report OpenLineage listener config — already set server-side at |
|
|
282
|
+
| `spark_lineage_events` | `SPARKTOOL` | Named per this lane's tool-group contract; NOT a Kafka consumer. |
|
|
283
|
+
| `spark_list_lakekeeper_tables` | `SPARKTOOL` | Invoke the list_lakekeeper_tables operation. |
|
|
284
|
+
| `spark_list_transform_runs` | `SPARKTOOL` | Invoke the list_transform_runs operation. |
|
|
285
|
+
| `spark_rerun_transform` | `SPARKTOOL` | Deterministically re-execute a prior TransformRun's manifest. |
|
|
286
|
+
| `spark_sql` | `SPARKTOOL` | Execute one SQL statement and return rows as plain dicts. |
|
|
287
|
+
| `spark_submit_transform` | `SPARKTOOL` | Execute one Transform manifest, recording a TransformRun (success or typed failure). |
|
|
288
|
+
|
|
289
|
+
</details>
|
|
290
|
+
|
|
291
|
+
_1 action-routed tool(s) · 12 verbose 1:1 tool(s). Each is enabled unless its `<DOMAIN>TOOL` toggle is set false; `MCP_TOOL_MODE` selects the surface (**`intent` default** — the six verb-tools, granular set loaded on demand · `condensed` action-routed · `verbose` 1:1 · `both`). Auto-generated — do not edit._
|
|
292
|
+
<!-- MCP-TOOLS-TABLE:END -->
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Repository Owners
|
|
297
|
+
|
|
298
|
+
<img width="100%" height="180em" src="https://github-readme-stats.vercel.app/api?username=example&show_icons=true&hide_border=true&&count_private=true&include_all_commits=true" />
|
|
299
|
+
|
|
300
|
+

|
|
301
|
+

|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Contribute
|
|
306
|
+
|
|
307
|
+
Contributions are welcome! Please ensure code quality by running local checks before submitting pull requests:
|
|
308
|
+
- Format code using `ruff format .`
|
|
309
|
+
- Lint code using `ruff check .`
|
|
310
|
+
- Validate type-safety with `mypy .`
|
|
311
|
+
- Run test suites using `pytest`
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
<!-- GOVERNED-CAPABILITY:START -->
|
|
316
|
+
## Governed capability contract
|
|
317
|
+
|
|
318
|
+
This package ships a compact canonical skill surface with specialist procedures
|
|
319
|
+
kept as referenced workflows. The current MCP tools, skill metadata,
|
|
320
|
+
`connector_manifest.yml`, ontology, mappings, shapes, fixtures, migrations,
|
|
321
|
+
tool-schema fingerprints, and certification metadata form one versioned
|
|
322
|
+
capability contract. Validate them together; do not rely on stale tool names or
|
|
323
|
+
historical per-task skill wrappers.
|
|
324
|
+
|
|
325
|
+
Runtime endpoints, credentials, certificate trust, tenant identity, retention,
|
|
326
|
+
and observability policy are deployment inputs and are never packaged values.
|
|
327
|
+
See [Configuration, trust, and privacy](docs/configuration.md) before enabling a
|
|
328
|
+
network transport, connector ingestion, Arbora delegation, or trace export.
|
|
329
|
+
<!-- GOVERNED-CAPABILITY:END -->
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
# Spark Mcp
|
|
2
|
+
## CLI or API | MCP
|
|
3
|
+
|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+

|
|
11
|
+

|
|
12
|
+

|
|
13
|
+

|
|
14
|
+

|
|
15
|
+

|
|
16
|
+

|
|
17
|
+

|
|
18
|
+

|
|
19
|
+

|
|
20
|
+

|
|
21
|
+

|
|
22
|
+
|
|
23
|
+
*Version: 0.4.1*
|
|
24
|
+
|
|
25
|
+
> **Documentation** — Installation, deployment, and usage across the API, CLI, MCP,
|
|
26
|
+
> and A2A agent interfaces are maintained in the
|
|
27
|
+
> [official documentation](https://knuckles-team.github.io/spark-mcp/).
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Table of Contents
|
|
32
|
+
- [Overview](#overview)
|
|
33
|
+
- [Installation](#installation)
|
|
34
|
+
- [Usage](#usage)
|
|
35
|
+
- [Architecture](#architecture)
|
|
36
|
+
- [Environment Variables](#environment-variables)
|
|
37
|
+
- [MCP Tools](#mcp-tools)
|
|
38
|
+
- [Documentation](#documentation)
|
|
39
|
+
|
|
40
|
+
## Overview
|
|
41
|
+
`spark-mcp` exposes a standardized interface to the live Spark Connect deployment
|
|
42
|
+
via the Model Context Protocol — SQL/session execution, versioned Transform
|
|
43
|
+
submission/tracking/rerun against the shared Iceberg `lakehouse` catalog
|
|
44
|
+
(`scope=lakekeeper`, explicit — the same landmine Trino/Lakekeeper hit if dropped),
|
|
45
|
+
namespace/table catalog reads, OpenLineage config/status reporting, and a
|
|
46
|
+
Wire-First `spark_ingest_run` tool that pushes the
|
|
47
|
+
`SparkApplication -> SparkJob -> Transform -> TransformRun -> DatasetVersion` chain
|
|
48
|
+
into the epistemic-graph Knowledge Graph.
|
|
49
|
+
|
|
50
|
+
**Spark Connect is live**, confirmed 2026-08-26 against
|
|
51
|
+
`spark-connect.apps.svc:15002` with a real `pyspark.sql.connect` session — a query
|
|
52
|
+
against `lakehouse.analytics.trino_verify` returned the same 3 rows Trino's sibling
|
|
53
|
+
lane already proved reading/writing (cross-engine Iceberg interop). See
|
|
54
|
+
[docs/architecture.md](docs/architecture.md) for the full evidence and this
|
|
55
|
+
package's `AGENTS.md` for known gaps (identity-token attach, `ActionSpec`
|
|
56
|
+
typed-Actions deferral).
|
|
57
|
+
|
|
58
|
+
Talks directly to Spark over `pyspark-client` (the thin Spark Connect client) for SQL, DataFrame and catalog operations, and over the Spark monitoring REST API (`/api/v1` on the driver UI and the History Server) for applications, jobs, stages, executors, storage, environment and SQL executions, never
|
|
59
|
+
`bin/spark-shell --remote` (does not work on the vanilla Spark image) and never a
|
|
60
|
+
`kubectl exec spark-sql` fallback.
|
|
61
|
+
|
|
62
|
+
## Installation
|
|
63
|
+
|
|
64
|
+
Pick the extra that matches what the operator want to run:
|
|
65
|
+
|
|
66
|
+
| Extra | Installs | Use when |
|
|
67
|
+
|-------|----------|----------|
|
|
68
|
+
| `spark-mcp[mcp]` | Connector-focused MCP server (`agent-connector-sdk` — FastMCP/FastAPI + `epistemic-graph[full]`) | The operator only run the **MCP server** (smallest install / image) |
|
|
69
|
+
| `spark-mcp[all]` | Everything (`mcp` + `agent` + `logfire`) | Development / both surfaces |
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
uv pip install "spark-mcp[mcp]"
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Container images (`:mcp`)
|
|
76
|
+
|
|
77
|
+
One multi-stage `docker/Dockerfile` builds the MCP-only image (`--target mcp`):
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
docker build --target mcp -t spark-mcp:mcp .
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Both images install a headless JRE at runtime — `pyspark[connect]`'s gRPC client has
|
|
84
|
+
a JVM-side dependency, unlike the fleet's pure-Python REST connectors.
|
|
85
|
+
|
|
86
|
+
## Usage
|
|
87
|
+
Run the MCP server directly:
|
|
88
|
+
```bash
|
|
89
|
+
python -m spark_mcp
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### MCP Configuration Example (stdio)
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"mcpServers": {
|
|
97
|
+
"spark-mcp": {
|
|
98
|
+
"command": "uv",
|
|
99
|
+
"args": ["run", "spark-mcp"],
|
|
100
|
+
"env": {
|
|
101
|
+
"MCP_TOOL_MODE": "intent",
|
|
102
|
+
"SPARK_CONNECT_URL": "sc://spark-connect.apps.svc:15002",
|
|
103
|
+
"SPARK_LAKEHOUSE_CATALOG": "lakehouse",
|
|
104
|
+
"SPARK_LAKEHOUSE_SCOPE": "lakekeeper",
|
|
105
|
+
"SPARK_ENABLE_TRANSFORMS": "False",
|
|
106
|
+
"SPARKTOOL": "True"
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Architecture
|
|
114
|
+
|
|
115
|
+
`api_client.py` wraps `api/api_client_spark.py`'s `SparkApi`, a thin gRPC client
|
|
116
|
+
over `pyspark.sql.connect.session.SparkSession`, behind `api/api_client_base.py`'s
|
|
117
|
+
typed-error layer (`SparkApiError` with a `kind`: `unreachable` / `job_failed` /
|
|
118
|
+
`session_evicted` / `disabled` — never a silent empty result). `auth.py` mints
|
|
119
|
+
Keycloak client-credentials identity tokens and can attach them as real gRPC bearer
|
|
120
|
+
credentials, but the deployed Spark Connect endpoint is plaintext gRPC today, so
|
|
121
|
+
attach is disabled by default (see `docs/architecture.md`).
|
|
122
|
+
|
|
123
|
+
`mcp_server.py` serves one typed `spark_<operation>` tool per `SparkApi` method
|
|
124
|
+
(`spark_sql`, `spark_describe`, `spark_cancel`, `spark_submit_transform`,
|
|
125
|
+
`spark_rerun_transform`, `spark_list_transform_runs`, `spark_list_lakekeeper_tables`,
|
|
126
|
+
`spark_lineage_config`, `spark_lineage_events`, `spark_application_status`) through one
|
|
127
|
+
`register_tool_surface(...)` call; GET-like reads are read-only and `spark_cancel` is
|
|
128
|
+
destructive. `kg_ingest.py` exposes
|
|
129
|
+
`ingest_entities`/`ingest_run` plus record-mapping helpers around the required
|
|
130
|
+
`native_ingest` (Wire-First) authority.
|
|
131
|
+
|
|
132
|
+
## Python version
|
|
133
|
+
|
|
134
|
+
Python 3.14 (floor 3.12) against a Spark 4.1 server. `pyspark-client` 4.1 is the
|
|
135
|
+
thin Spark Connect client; it runs on numpy 2, pandas 3 and pyarrow wheels.
|
|
136
|
+
`pyspark-client` ships only a pure-Python sdist, so it is the one package built
|
|
137
|
+
from source (`[tool.pipelines] allow-source-build = ["pyspark-client"]`).
|
|
138
|
+
|
|
139
|
+
## Environment Variables
|
|
140
|
+
|
|
141
|
+
<!-- ENV-VARS-TABLE:START -->
|
|
142
|
+
|
|
143
|
+
#### Package environment variables
|
|
144
|
+
|
|
145
|
+
| Variable | Example | Description |
|
|
146
|
+
|----------|---------|-------------|
|
|
147
|
+
| `SPARK_CONNECT_URL` | `sc://spark-connect.apps.svc:15002` | |
|
|
148
|
+
| `SPARK_UI_URL` | `http://spark-runner.apps.svc:4040` | driver monitoring REST |
|
|
149
|
+
| `SPARK_HISTORY_URL` | `http://spark-history.apps.svc:18080` | History Server REST |
|
|
150
|
+
| `SPARK_REST_TIMEOUT_S` | `30` | |
|
|
151
|
+
| `SPARK_SUBMIT_TIMEOUT_S` | `300` | |
|
|
152
|
+
| `SPARK_LAKEHOUSE_CATALOG` | `lakehouse` | document/verify the invariant client-side — same invalid_scope landmine as |
|
|
153
|
+
| `SPARK_LAKEHOUSE_SCOPE` | `lakekeeper` | |
|
|
154
|
+
| `SPARK_ENABLE_TRANSFORMS` | `False` | egeria-mcp's EGERIA_ENABLE_WRITE) — spark_submit_transform/spark_rerun_transform |
|
|
155
|
+
| `SPARK_CONNECT_ATTACH_IDENTITY_TOKEN` | secret-injected | Service is plaintext gRPC; attaching a bearer token forces a TLS channel the |
|
|
156
|
+
| `SPARK_CONNECT_USE_SSL` | `False` | |
|
|
157
|
+
| `SPARK_SERVICE_CLIENT_ID` | `spark-service` | |
|
|
158
|
+
| `SPARK_SERVICE_CLIENT_SECRET` | secret-injected | |
|
|
159
|
+
| `SPARK_OAUTH_SCOPE` | `lakekeeper` | |
|
|
160
|
+
| `SPARK_OAUTH_TOKEN_URL` | secret-injected | |
|
|
161
|
+
| `SPARK_KEYCLOAK_URL` | `http://localhost:8080` | |
|
|
162
|
+
| `SPARK_KEYCLOAK_REALM` | `homelab` | |
|
|
163
|
+
| `SPARKTOOL` | `True` | |
|
|
164
|
+
| `INGESTTOOL` | `True` | |
|
|
165
|
+
|
|
166
|
+
#### Inherited agent-connector-sdk variables (apply to every connector)
|
|
167
|
+
|
|
168
|
+
| Variable | Example | Description |
|
|
169
|
+
|----------|---------|-------------|
|
|
170
|
+
| `TRANSPORT` | `stdio` | MCP transport: `stdio` \| `streamable-http` \| `sse` |
|
|
171
|
+
| `HOST` | `127.0.0.1` | Loopback bind host (set an authenticated ingress explicitly) |
|
|
172
|
+
| `PORT` | `8000` | Bind port (HTTP transports) |
|
|
173
|
+
| `MCP_TOOL_MODE` | `intent` | Tool surface: `intent` \| `condensed` \| `verbose` \| `both` |
|
|
174
|
+
| `MCP_ENABLED_TOOLS` | — | Comma-separated tool allow-list |
|
|
175
|
+
| `MCP_DISABLED_TOOLS` | — | Comma-separated tool deny-list |
|
|
176
|
+
| `MCP_ENABLED_TAGS` | — | Comma-separated tag allow-list |
|
|
177
|
+
| `MCP_DISABLED_TAGS` | — | Comma-separated tag deny-list |
|
|
178
|
+
| `EUNOMIA_TYPE` | `none` | Authorization mode: `none` \| `embedded` \| `remote` |
|
|
179
|
+
| `EUNOMIA_POLICY_FILE` | `mcp_policies.json` | Embedded Eunomia policy file |
|
|
180
|
+
| `EUNOMIA_REMOTE_URL` | — | Remote Eunomia authorization server URL |
|
|
181
|
+
| `ENABLE_OTEL` | `False` | Enable OpenTelemetry export |
|
|
182
|
+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | — | OTLP collector endpoint |
|
|
183
|
+
| `MCP_CLIENT_AUTH` | — | Outbound MCP child auth: `oidc-client-credentials` \| `basic` \| `none` |
|
|
184
|
+
| `OIDC_CLIENT_ID` | — | OIDC client id (service-account auth) |
|
|
185
|
+
| `OIDC_CLIENT_SECRET_REF` | `secret://identity/oidc-client-secret` | Runtime secret reference for the OIDC service account |
|
|
186
|
+
| `MCP_BASIC_AUTH_USERNAME` | — | HTTP Basic username (`MCP_CLIENT_AUTH=basic`) |
|
|
187
|
+
| `MCP_BASIC_AUTH_PASSWORD_REF` | `secret://identity/mcp-basic-password` | Runtime secret reference for HTTP Basic auth (`MCP_CLIENT_AUTH=basic`) |
|
|
188
|
+
| `DEBUG` | `False` | Verbose logging |
|
|
189
|
+
| `PYTHONUNBUFFERED` | `1` | Unbuffered stdout (recommended in containers) |
|
|
190
|
+
| `MCP_URL` | `http://localhost:8000/mcp` | URL of the MCP server the agent connects to |
|
|
191
|
+
| `PROVIDER` | `openai` | LLM provider for the agent |
|
|
192
|
+
| `MODEL_ID` | `gpt-4o` | Model id for the agent |
|
|
193
|
+
| `ENABLE_WEB_UI` | `True` | Serve the AG-UI web interface |
|
|
194
|
+
|
|
195
|
+
_15 package + 24 inherited variable(s). Auto-generated from `.env.example` + the shared agent-connector-sdk set — do not edit._
|
|
196
|
+
<!-- ENV-VARS-TABLE:END -->
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
| Variable | Required | Notes |
|
|
200
|
+
|----------|----------|-------|
|
|
201
|
+
| `SPARK_CONNECT_URL` | recommended | Spark Connect gRPC endpoint. Defaults to `sc://spark-connect.apps.svc:15002`. |
|
|
202
|
+
| `SPARK_SUBMIT_TIMEOUT_S` | optional | Submission timeout budget. Defaults to `300`. |
|
|
203
|
+
| `SPARK_LAKEHOUSE_CATALOG` / `SPARK_LAKEHOUSE_SCOPE` | optional | Defaults to `lakehouse` / `lakekeeper` — never leave scope at the shared-client default `catalog`. |
|
|
204
|
+
| `SPARK_ENABLE_TRANSFORMS` | ✅ for writes | `spark_submit_transform`/`spark_rerun_transform` refuse unless `true`. |
|
|
205
|
+
| `SPARK_CONNECT_ATTACH_IDENTITY_TOKEN` / `SPARK_CONNECT_USE_SSL` | optional | Both must be `true` together — see `docs/architecture.md`. |
|
|
206
|
+
| `SPARK_SERVICE_CLIENT_ID` / `SPARK_SERVICE_CLIENT_SECRET` | for identity attach | Keycloak client-credentials. |
|
|
207
|
+
| `SPARK_OAUTH_SCOPE` / `SPARK_OAUTH_TOKEN_URL` / `SPARK_KEYCLOAK_URL` / `SPARK_KEYCLOAK_REALM` | optional | Token-mint configuration. |
|
|
208
|
+
|
|
209
|
+
See [.env.example](.env.example) for the full template.
|
|
210
|
+
|
|
211
|
+
## MCP Tools
|
|
212
|
+
|
|
213
|
+
| Group | Tools |
|
|
214
|
+
|-------|-------|
|
|
215
|
+
| session | `spark_sql`, `spark_describe`, `spark_cancel` |
|
|
216
|
+
| transforms | `spark_submit_transform`, `spark_list_transform_runs`, `spark_rerun_transform` |
|
|
217
|
+
| catalog | `spark_list_lakekeeper_tables` |
|
|
218
|
+
| lineage | `spark_lineage_config`, `spark_lineage_events` |
|
|
219
|
+
| ops | `spark_application_status` |
|
|
220
|
+
| ingest | `spark_ingest_run` |
|
|
221
|
+
|
|
222
|
+
## Documentation
|
|
223
|
+
- [Architecture](docs/architecture.md)
|
|
224
|
+
- [Configuration](docs/configuration.md)
|
|
225
|
+
- [AGENTS.md](AGENTS.md) — canonical agent-facing context, live-proof evidence, known gaps
|
|
226
|
+
|
|
227
|
+
## Available MCP Tools
|
|
228
|
+
|
|
229
|
+
<!-- MCP-TOOLS-TABLE:START -->
|
|
230
|
+
|
|
231
|
+
#### Condensed action-routed tools (`MCP_TOOL_MODE=condensed`)
|
|
232
|
+
|
|
233
|
+
| MCP Tool | Toggle Env Var | Description |
|
|
234
|
+
|----------|----------------|-------------|
|
|
235
|
+
| `spark_ingest_run` | `INGESTTOOL` | Push one TransformRun's SparkApplication->SparkJob->Transform->TransformRun |
|
|
236
|
+
|
|
237
|
+
#### Verbose 1:1 API-mapped tools (`MCP_TOOL_MODE=verbose` or `both`)
|
|
238
|
+
|
|
239
|
+
<details>
|
|
240
|
+
<summary>12 per-operation tools — one per public API method (click to expand)</summary>
|
|
241
|
+
|
|
242
|
+
| MCP Tool | Toggle Env Var | Description |
|
|
243
|
+
|----------|----------------|-------------|
|
|
244
|
+
| `spark_application_status` | `SPARKTOOL` | Best-effort application/session status. |
|
|
245
|
+
| `spark_cancel` | `SPARKTOOL` | Interrupt running operations on this session (all, or one tagged operation). |
|
|
246
|
+
| `spark_close` | `SPARK_APITOOL` | Invoke the close operation. |
|
|
247
|
+
| `spark_describe` | `SPARKTOOL` | Schema + column info for one fully-qualified table. |
|
|
248
|
+
| `spark_get_session` | `SPARK_APITOOL` | Return the cached Spark Connect session, building it on first use. |
|
|
249
|
+
| `spark_lineage_config` | `SPARKTOOL` | Report OpenLineage listener config — already set server-side at |
|
|
250
|
+
| `spark_lineage_events` | `SPARKTOOL` | Named per this lane's tool-group contract; NOT a Kafka consumer. |
|
|
251
|
+
| `spark_list_lakekeeper_tables` | `SPARKTOOL` | Invoke the list_lakekeeper_tables operation. |
|
|
252
|
+
| `spark_list_transform_runs` | `SPARKTOOL` | Invoke the list_transform_runs operation. |
|
|
253
|
+
| `spark_rerun_transform` | `SPARKTOOL` | Deterministically re-execute a prior TransformRun's manifest. |
|
|
254
|
+
| `spark_sql` | `SPARKTOOL` | Execute one SQL statement and return rows as plain dicts. |
|
|
255
|
+
| `spark_submit_transform` | `SPARKTOOL` | Execute one Transform manifest, recording a TransformRun (success or typed failure). |
|
|
256
|
+
|
|
257
|
+
</details>
|
|
258
|
+
|
|
259
|
+
_1 action-routed tool(s) · 12 verbose 1:1 tool(s). Each is enabled unless its `<DOMAIN>TOOL` toggle is set false; `MCP_TOOL_MODE` selects the surface (**`intent` default** — the six verb-tools, granular set loaded on demand · `condensed` action-routed · `verbose` 1:1 · `both`). Auto-generated — do not edit._
|
|
260
|
+
<!-- MCP-TOOLS-TABLE:END -->
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Repository Owners
|
|
265
|
+
|
|
266
|
+
<img width="100%" height="180em" src="https://github-readme-stats.vercel.app/api?username=example&show_icons=true&hide_border=true&&count_private=true&include_all_commits=true" />
|
|
267
|
+
|
|
268
|
+

|
|
269
|
+

|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Contribute
|
|
274
|
+
|
|
275
|
+
Contributions are welcome! Please ensure code quality by running local checks before submitting pull requests:
|
|
276
|
+
- Format code using `ruff format .`
|
|
277
|
+
- Lint code using `ruff check .`
|
|
278
|
+
- Validate type-safety with `mypy .`
|
|
279
|
+
- Run test suites using `pytest`
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
<!-- GOVERNED-CAPABILITY:START -->
|
|
284
|
+
## Governed capability contract
|
|
285
|
+
|
|
286
|
+
This package ships a compact canonical skill surface with specialist procedures
|
|
287
|
+
kept as referenced workflows. The current MCP tools, skill metadata,
|
|
288
|
+
`connector_manifest.yml`, ontology, mappings, shapes, fixtures, migrations,
|
|
289
|
+
tool-schema fingerprints, and certification metadata form one versioned
|
|
290
|
+
capability contract. Validate them together; do not rely on stale tool names or
|
|
291
|
+
historical per-task skill wrappers.
|
|
292
|
+
|
|
293
|
+
Runtime endpoints, credentials, certificate trust, tenant identity, retention,
|
|
294
|
+
and observability policy are deployment inputs and are never packaged values.
|
|
295
|
+
See [Configuration, trust, and privacy](docs/configuration.md) before enabling a
|
|
296
|
+
network transport, connector ingestion, Arbora delegation, or trace export.
|
|
297
|
+
<!-- GOVERNED-CAPABILITY:END -->
|