Skip to main content
Glama
ukonduru91

Spark History Server MCP

by ukonduru91

Spark History Server MCP (TypeScript)

Give an LLM read access to your Spark History Server so it can do the tedious part of Spark work: finding why a job failed, and finding where a slow job spends its time.

It is a TypeScript port of kubeflow/mcp-apache-spark-history-server, verified response-for-response against the Python original — see PARITY.md. On top of the port it ships two agent skills that turn the raw tools into an expert workflow for root-cause analysis and performance tuning.

                    ┌──────────────────┐
  data engineer ──▶ │  LLM client      │   Claude Code / Claude Desktop / any MCP client
                    │  + skills        │   ← skills/ supply the method
                    └────────┬─────────┘
                             │ MCP (stdio or streamable-http)
                    ┌────────▼─────────┐
                    │  this server     │   17 tools, 2 prompts
                    └────────┬─────────┘
                             │ HTTP  GET /api/v1/...
                    ┌────────▼─────────┐
                    │ Spark History    │   your existing one, or the bundled demo
                    │ Server           │
                    └────────┬─────────┘
                             │ reads
                    ┌────────▼─────────┐
                    │ event logs       │   s3://…, hdfs://…, file://…
                    └──────────────────┘

The server only ever issues GET requests to the History Server's REST API. It cannot modify anything.


Contents

  1. Quick start

  2. Pointing it at your Spark History Server

  3. Connecting your LLM client

  4. Installing the skills

  5. The tools

  6. How it works

  7. Deployment

  8. Troubleshooting

  9. Development


Related MCP server: Spark EventLog MCP Server

1. Quick start

Option A — Docker (nothing to install but Docker)

Starts a Spark History Server loaded with sample event logs and this MCP:

git clone https://github.com/ukonduru91/spark-history-mcp.git
cd spark-history-mcp
docker compose up --build

The bundled logs include a healthy pipeline and a deliberately failed job, so the tools have something real to show before you point them at your own cluster.

To run only the History Server:

./start_local_spark_history.sh          # macOS / Linux / Git Bash
.\start_local_spark_history.ps1         # Windows PowerShell

Option B — from source

Requires Node.js 20+ (22 recommended).

git clone https://github.com/ukonduru91/spark-history-mcp.git
cd spark-history-mcp
npm install
npm run build
npm start

Verify it works

node scripts/mcp-cli.mjs list-tools
node scripts/mcp-cli.mjs call list_applications '{"limit": 5}'

If applications come back, you are connected.


2. Pointing it at your Spark History Server

This is the one thing you must configure. Three ways, highest precedence first — environment variables win over the .env file, which wins over YAML.

a. Environment variables (best for containers and CI)

Nesting uses a double underscore. LOCAL below is just a name you choose for the server:

export SHS_SERVERS__LOCAL__URL=http://spark-history.internal:18080
export SHS_SERVERS__LOCAL__DEFAULT=true

b. A YAML config file

The server looks for one in this order:

  1. the path given to --config, or $SHS_MCP_CONFIG

  2. ./config.yaml in the working directory

  3. ~/.config/spark-mcp/config.yaml

servers:
  prod:
    url: "https://spark-history.company.com:18080"
    default: true          # used when a tool call omits `server`
    verify_ssl: true
    ssl_ca_cert: "/etc/ssl/custom-ca/ca-bundle.pem"   # private CA
    timeout: 30            # seconds
    auth:
      username: admin
      password: ${SPARK_PASSWORD}   # see the note below
      # token: <bearer token>       # or a bearer token instead

  staging:
    url: "https://spark-history-staging.company.com:18080"

On secrets: values in YAML are literal — ${SPARK_PASSWORD} is not expanded. Keep credentials in environment variables (SHS_SERVERS__PROD__AUTH__PASSWORD), which override the file. This matches the upstream project's behaviour.

c. A .env file

Same variable names as (a), read from .env in the working directory.

Multiple servers

Configure as many as you like. Tools take an optional server argument; when it is omitted the server discovers which configured History Server has that application and uses it (cached for 5 minutes). An engineer can therefore ask about an application id without knowing which cluster ran it.

Every setting

Setting

Env var

Default

Meaning

servers.<n>.url

SHS_SERVERS__<N>__URL

http://localhost:18080

History Server base URL

servers.<n>.default

SHS_SERVERS__<N>__DEFAULT

false

use when no server is given

servers.<n>.auth.username

SHS_SERVERS__<N>__AUTH__USERNAME

basic auth

servers.<n>.auth.password

SHS_SERVERS__<N>__AUTH__PASSWORD

basic auth

servers.<n>.auth.token

SHS_SERVERS__<N>__AUTH__TOKEN

bearer token

servers.<n>.verify_ssl

SHS_SERVERS__<N>__VERIFY_SSL

true

TLS verification

servers.<n>.ssl_ca_cert

SHS_SERVERS__<N>__SSL_CA_CERT

PEM bundle for a private CA

servers.<n>.timeout

SHS_SERVERS__<N>__TIMEOUT

30

request timeout, seconds

servers.<n>.use_proxy

SHS_SERVERS__<N>__USE_PROXY

false

route via socks5h://localhost:8157

servers.<n>.include_plan_description

SHS_SERVERS__<N>__INCLUDE_PLAN_DESCRIPTION

false

default for get_sql_execution's plan text

mcp.transport

SHS_MCP__TRANSPORT

streamable-http

stdio or streamable-http

mcp.address

SHS_MCP__ADDRESS

localhost

bind address for HTTP

mcp.port

SHS_MCP__PORT

18888

bind port for HTTP

mcp.debug

SHS_MCP__DEBUG

false

verbose logging

Single-underscore variables (SHS_MCP_PORT) still work but log a deprecation warning, exactly as upstream.

Reaching a History Server you cannot route to

An SSH tunnel plus use_proxy: true covers the common locked-down-cluster case:

ssh -D 8157 -N user@bastion    # SOCKS5 proxy on :8157

3. Connecting your LLM client

stdio (Claude Code, Claude Desktop, most clients)

{
  "mcpServers": {
    "spark-history": {
      "command": "node",
      "args": ["/absolute/path/to/spark-history-mcp/dist/index.js"],
      "env": {
        "SHS_MCP__TRANSPORT": "stdio",
        "SHS_SERVERS__PROD__URL": "https://spark-history.company.com:18080",
        "SHS_SERVERS__PROD__DEFAULT": "true"
      }
    }
  }
}

Claude Code users can do the same in one line:

claude mcp add spark-history \
  --env SHS_MCP__TRANSPORT=stdio \
  --env SHS_SERVERS__PROD__URL=https://spark-history.company.com:18080 \
  --env SHS_SERVERS__PROD__DEFAULT=true \
  -- node /absolute/path/to/spark-history-mcp/dist/index.js

streamable-http (one shared server for a team)

Run it once, point everyone at it:

SHS_MCP__TRANSPORT=streamable-http SHS_MCP__ADDRESS=0.0.0.0 npm start

Clients connect to http://<host>:18888/mcp. The server is read-only, but it is also unauthenticated — put it behind your normal internal ingress, and enable DNS rebinding protection if it is reachable from a browser:

mcp:
  transport_security:
    enable_dns_rebinding_protection: true
    allowed_hosts: ["spark-mcp.internal:*"]
    allowed_origins: ["https://spark-mcp.internal"]

4. Installing the skills

The tools give the model access to the data. The skills give it the method — the order to gather evidence in, the thresholds that separate a finding from noise, and the rule that it must not name a cause it has not seen in the data.

# per project
mkdir -p .claude/skills
cp -r skills/spark-rca skills/spark-optimization .claude/skills/

# or for every project
mkdir -p ~/.claude/skills
cp -r skills/spark-rca skills/spark-optimization ~/.claude/skills/

Skill

Handles

Triggers on

spark-rca

failed, killed or hung jobs

"why did it fail", a stack trace, an app id, "OOM", "stuck"

spark-optimization

slow, expensive or regressed jobs

"why is this slow", "tune", "it used to take 20 minutes", "reduce cost"

They trigger on their own from a normal question — nobody has to remember a command:

"the 2am load failed again, app_1724… — can you look?"

See skills/README.md for what is inside each one and how to extend them with your team's own knowledge.


5. The tools

All 17 live in src/tools/tools.ts; their JSON schemas are in src/schemas/generated.ts. Run node scripts/mcp-cli.mjs list-tools to see them with their arguments.

Finding things

Tool

Returns

list_applications

applications, filterable by status and date, or one by app_id

list_jobs

jobs for an application — failed first by default; sort_by duration / failed-tasks / id

list_stages

stages, same ordering options, optional summary metrics

list_executors

executors, active by default, include_inactive for the full history

list_sql_executions

curated SQL execution summaries, filterable by description

Going deep

Tool

Returns

get_stage

one stage with per-task metric distributions at your quantiles

list_stage_task_failures

the per-task exceptions and stack traces — where root causes live

get_sql_execution

one query: header, physical plan, per-node metrics, jobs, stages

get_environment

runtime versions, Spark/system/Hadoop properties, classpath — filter by section

get_executor_summary

aggregated executor metrics for the application

get_executor_thread_dump

JVM thread dump — running applications only

Diagnosing

Tool

Returns

get_job_bottlenecks

slowest stages and jobs, spill, GC pressure, utilisation, recommendations

get_resource_usage_timeline

executor add/remove and stage timeline summary

Comparing two runs

Tool

Returns

compare_job_environments

config diff — what changed between two runs

compare_job_performance

resource and duration diff

compare_sql_executions

metrics diff for two queries, plus an optional plan-structure diff

compare_stages

stage metrics and task quantiles side by side

Prompts

investigate_failure(app_id, server?) and compare_applications(app_a, app_b, server?, context?) — interactive walkthroughs from the upstream project, for when the engineer wants to drive instead of handing the analysis over.


6. How it works

A tool call becomes one or more GETs against /api/v1/..., and the JSON comes back shaped exactly as the Python original shaped it.

src/
  index.ts                 CLI entry, transport selection (stdio | streamable-http)
  config/config.ts         YAML + .env + SHS_* resolution and precedence
  core/
    app.ts                 MCP request handlers; maps results to content blocks
    validation.ts          pydantic-compatible argument validation and messages
    json.ts                Python-compatible JSON rendering
    pyfloat.ts             int/float fidelity across the JSON round-trip
    pyrepr.ts              Python repr() for validation messages
    errors.ts              error text shaping
  api/
    httpClient.ts          HTTP transport, ApiException taxonomy, auth, TLS, SOCKS
    sparkClient.ts         Spark REST facade: pagination, attempts, status filters
  models/
    generated.ts           model shapes, generated from the upstream OpenAPI models
    deserialize.ts         from_dict / model_dump equivalents
    mcpTypes.ts            curated LLM-facing output models
  tools/tools.ts           the 17 tools
  prompts/prompts.ts       the 2 prompts
  schemas/generated.ts     tool + prompt catalogue (names, descriptions, schemas)

Three details worth knowing if you plan to modify it:

  • models/generated.ts and schemas/generated.ts are generated, by tools/gen_models.py and tools/gen_schemas.py, from the upstream Python project. Regenerate rather than hand-edit — that is what keeps the catalogue and the response shapes identical to the original.

  • The low-level Server API is used, not McpServer, because the result shape has to match FastMCP's: one text block per list element, and structuredContent only for the tools whose Python signature declared a concrete return type.

  • Application discovery lets tools omit server. ApplicationDiscovery probes each configured server for the application id and caches the answer for 5 minutes.


7. Deployment

Docker

docker build -t spark-history-mcp .
docker run -p 18888:18888 \
  -e SHS_SERVERS__PROD__URL=https://spark-history.company.com:18080 \
  -e SHS_SERVERS__PROD__DEFAULT=true \
  -e SHS_MCP__ADDRESS=0.0.0.0 \
  spark-history-mcp

Kubernetes

Run it as a normal Deployment with the URL in the env and credentials from a Secret:

env:
  - name: SHS_MCP__TRANSPORT
    value: streamable-http
  - name: SHS_MCP__ADDRESS
    value: "0.0.0.0"
  - name: SHS_SERVERS__PROD__URL
    value: http://spark-history-server.spark.svc.cluster.local:18080
  - name: SHS_SERVERS__PROD__DEFAULT
    value: "true"
  - name: SHS_SERVERS__PROD__AUTH__TOKEN
    valueFrom:
      secretKeyRef: { name: spark-history-auth, key: token }

The process is stateless apart from the 5-minute discovery cache, so it scales horizontally without coordination.


8. Troubleshooting

Symptom

Cause and fix

connect ECONNREFUSED

wrong URL or port, or the History Server is down. Check curl $URL/api/v1/applications from the same host

Application '<id>' not found on any server

the id is not on any configured server, or the event log has not been picked up yet — spark.history.fs.update.interval controls the scan

No Spark server named 'x' is configured

the server argument does not match a key under servers:

404 … No tasks reported metrics for N / 0 yet

Spark's own answer for a stage that failed before any task finished. Not a tool problem — read the task exceptions instead

get_executor_thread_dump errors on a finished app

expected: the History Server does not persist thread dumps. They work only while the app is running

Empty list_applications

check spark.history.fs.logDirectory points where your jobs actually write event logs, and that spark.eventLog.enabled=true on the jobs

Very large responses

narrow with length, limit and section. get_stage(with_summaries=false) is much smaller

emr_cluster_arn … not included in this TypeScript port

EMR persistent-UI auth is not ported; point at a directly reachable URL instead

Set SHS_MCP__DEBUG=true for verbose logs.


9. Development

npm install
npm run build        # compile to dist/
npm run dev          # run from source, no build step
npm test             # unit tests
npm run typecheck    # tsc --noEmit

Cross-implementation parity testing lives in parity/ — it runs the same MCP calls against this server and the Python original and diffs every response. PARITY.md records the results and the exact differences that remain.

Not ported from upstream

Upstream module

Status

api/emr_persistent_ui_client.py

not ported — a server configured with emr_cluster_arn fails fast with an explanatory error

tools/aws_troubleshooting.py

not ported — proxies to an AWS-hosted MCP endpoint, registered only when AWS credentials are present

api/spark_html_client.py

not ported — a Playwright screenshot helper no tool calls


License

Apache-2.0, as with the upstream project.

A
license - permissive license
Not graded
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables AI assistants to interact with Delta Lake tables stored in MinIO through Spark using natural language queries. Provides read-oriented data operations on Delta Lake tables through the Model Context Protocol.
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables comprehensive analysis of Apache Spark event logs from S3, HTTP, or local sources, providing performance metrics, resource monitoring, shuffle analysis, and automated optimization recommendations with interactive HTML reports.
    MIT
  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    Exposes Spark History Server metrics and metadata as tools for LLM-based analysis of Spark applications. It enables deep optimization of Spark jobs by providing access to job summaries, stage details, SQL execution plans, and executor performance.
  • A
    license
    Not graded
    quality
    A
    maintenance
    Exposes Spark History Server data as tools for AI agents, enabling natural language querying of Spark applications, jobs, stages, and performance metrics.
    189
    Apache 2.0

View all related MCP servers

Related MCP Connectors

  • The grounded data layer for any LLM: governed SQL, metrics, lineage and catalog over your data.

  • Enable language models to perform advanced AI-powered web scraping with enterprise-grade reliabili…

  • LLM chat, text summarization and AI image generation

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ukonduru91/spark-history-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server