Skip to main content
Glama
README.md
# mcp-mainframe

A minimal **Model Context Protocol (MCP) server** that lets an AI assistant
(Claude, or any other MCP-compatible client) browse mainframe datasets, read
COBOL/JCL source, and submit/monitor batch jobs — the way this conversation's
Dice/Indeed connectors let Claude search job postings.

This is the proof-of-concept for the question: *"Mainframe code sits on some
machine — how would an AI tool actually get access to it?"* The answer is:
something has to expose it over an API first. On z/OS, that something is
**z/OSMF** (z/OS Management Facility), IBM's REST API layer over datasets,
jobs, and USS files. This project wraps that API as MCP tools.

## Why this exists

Mainframe shops don't let arbitrary tools touch production z/OS directly.
Real access always goes through a mediated layer — here, that's z/OSMF, with
its own auth and audit trail. This project makes that mediation visible and
concrete rather than hand-waving "AI can just read the mainframe."

## Architecture

```
┌─────────────────┐      MCP protocol       ┌──────────────┐      z/OSMF REST API      ┌──────────┐
│  Claude / any    │  (stdio, JSON-RPC)      │  server.py    │  (HTTPS, Basic Auth)      │  z/OS    │
│  MCP-compatible  │ ──────────────────────▶ │  (MCP tools)  │ ────────────────────────▶ │  mainframe│
│  AI client        │                         │               │                            │           │
└─────────────────┘                         └──────┬───────┘                            └──────────┘
                                                      │
                                                      ▼
                                             ┌─────────────────┐
                                             │ zosmf_client.py  │
                                             │ (mock or live)   │
                                             └─────────────────┘
```

- **`server.py`** — declares the MCP tools (`list_datasets`, `read_member`,
  `submit_jcl`, etc.) and their input/output shapes. This is the only file an
  MCP client ever talks to.
- **`zosmf_client.py`** — the only file that knows about z/OSMF's actual REST
  endpoints. Has two modes:
  - **MOCK_MODE (default)** — returns canned COBOL/JCL data so you can demo
    the whole pipeline with zero mainframe access. This is what's checked in
    and what runs out of the box.
  - **LIVE MODE** — makes real HTTPS calls to a real z/OSMF instance. Flip on
    by setting `ZOSMF_MOCK_MODE=false` plus real credentials (see below).

## Tools exposed

| Tool | What it does |
|---|---|
| `list_datasets(pattern)` | List datasets matching an HLQ pattern, e.g. `NAVEEN.*` |
| `list_members(dataset)` | List members inside a PDS |
| `read_member(dataset, member)` | Read a member's full source (COBOL, JCL, copybook, whatever) |
| `submit_jcl(jcl_text)` | Submit a JCL job to JES, returns jobname/jobid |
| `get_job_status(jobname, jobid)` | Poll a submitted job's status (INPUT/ACTIVE/OUTPUT) and return code |
| `get_job_output(jobname, jobid)` | Pull the spool/SYSOUT text once the job finishes |

## Setup

```bash
python3 -m venv venv
source venv/bin/activate        # Windows: venv\Scripts\activate
pip install -r requirements.txt
```

## Running it

**Quick manual smoke test** (calls the client logic directly, no MCP protocol involved):
```bash
python3 -c "
from zosmf_client import ZosmfClient
c = ZosmfClient()
print(c.list_datasets('NAVEEN.*'))
print(c.read_member('NAVEEN.COBOL.SOURCE', 'PARTUPD'))
"
```

**Full MCP server, with the official MCP Inspector** (browser UI to call each
tool by hand — best for a live demo):
```bash
mcp dev server.py
```

**Point Claude Desktop or Claude Code at it** by adding to that client's MCP
config (e.g. `claude_desktop_config.json`):
```json
{
  "mcpServers": {
    "mainframe": {
      "command": "/absolute/path/to/venv/bin/python",
      "args": ["/absolute/path/to/server.py"]
    }
  }
}
```
Once connected, you can literally ask Claude things like *"list the COBOL
members in NAVEEN.COBOL.SOURCE and explain what PARTUPD does"* and it will
call these tools to answer — using the mock data out of the box.

## Going live against a real z/OS system

Set these environment variables and flip mock mode off:
```bash
export ZOSMF_MOCK_MODE=false
export ZOSMF_BASE_URL=https://your-mainframe-host:443
export ZOSMF_USER=your_tso_userid
export ZOSMF_PASSWORD=your_password
export ZOSMF_VERIFY_TLS=true   # set false only for self-signed dev certs
```
No code changes needed — `zosmf_client.py` will start making real HTTPS calls
to `/zosmf/restfiles/...` and `/zosmf/restjobs/...` instead of returning mock
data. Note: `PARTUPD`, `DLRBATCH`, `NAVEEN.COBOL.SOURCE`, etc. are fictional —
swap in real dataset names once pointed at an actual z/OSMF-enabled LPAR.

## Known limitations

- **z/OSMF must already be configured on the target LPAR.** Hercules/TK4- (a
  classic 3270/TSO setup) does not ship z/OSMF enabled by default — this
  targets a modern z/OS system with z/OSMF turned on, which most current
  mainframe shops run, but it's not "any mainframe out of the box."
- **No write/update tools are implemented** (e.g. no `update_member`) —
  intentionally, since letting an AI agent directly overwrite production
  COBOL source is exactly the kind of unreviewed change most shops' change
  management (ChangeMan, Endevor) would never allow. Read + submit-job only,
  by design.
- **Auth is Basic Auth for simplicity.** A production version would use
  z/OSMF's token-based auth or client certificates, and would run behind
  the same access controls (RACF, ACF2, Top Secret) already governing the
  mainframe.
- **This is a proof-of-concept, not a vetted enterprise tool** — it's meant
  to demonstrate the architecture (MCP ⇄ z/OSMF ⇄ z/OS), not to be pointed at
  a real production LPAR without a security review.

## Talking points this supports

- "AI tools can't reach mainframe code directly — something has to expose it
  over an API first. On z/OS that's z/OSMF; I built an MCP server on top of
  it so any MCP-compatible AI client can browse datasets and submit jobs. 
- "I designed it read-mostly on purpose — job submission but no direct
  dataset writes — because that mirrors how real shops gate mainframe changes
  through formal change management, not ad hoc edits."
- "It runs in mock mode against realistic COBOL/JCL so it's demoable without
  needing a live z/OS system, but the live-mode code path against real
  z/OSMF REST endpoints is implemented and ready to point at a real LPAR."