Content
# Mainframe MCP Server
A **Model Context Protocol (MCP) server for IBM z/OS mainframes**. It exposes the
RSE (Remote System Explorer) REST API — read datasets and members (COBOL, JCL,
PROC, copybooks), manage datasets, and submit and monitor jobs — as MCP tools.
Because it speaks the MCP protocol, the **same server works in every
MCP-compatible client**: VS Code (GitHub Copilot), Cursor, Claude Desktop,
Gemini CLI, and more. Configure it once per client.
It ships as a **single pure-Python package** (`httpx`, no PowerShell) exposing
**31 tools**, so it runs anywhere — Linux containers, macOS, Windows — and is
publishable to PyPI and the MCP Registry.
## Install (native package)
```bash
pip install mainframe-mcp # or, from the mcp-server folder: pip install -e .
```
> If public PyPI is blocked, use a mirror, e.g.
> `pip install --index-url https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com mainframe-mcp`
This installs a `mainframe-mcp` command that speaks MCP over stdio.
## Configure (native)
| Variable | Required | Default | Purpose |
|----------|----------|---------|---------|
| `MF_HOSTNAME` | yes | — | RSE API hostname |
| `MF_PORT` | no | `443` | RSE API port |
| `MF_RSE_BASE_PATH` | no | `/rseapi/api/v1` | API base path |
| `MF_USERNAME` | yes | — | TSO user id |
| `MF_PASSWORD` | yes | — | TSO password |
| `MF_VERIFY_TLS` | no | *(off)* | `1` to verify the server certificate |
| `MF_PDS_LOCATIONS` | no | `pds_locations.txt` beside the module | Segment → dataset map for the `get_*` tools |
| `MF_SEG_*` | no | generic names | Per-site segment names (`MF_SEG_COBOL`, `MF_SEG_COPYBOOK`, `MF_SEG_CT1`, `MF_SEG_JCL`, `MF_SEG_PROC`, `MF_SEG_JOBDOC`) used in `pds_locations.txt` |
| `MF_READ_ONLY` | no | *(unset)* | `1` disables all write/destructive tools |
| `MF_ALLOWED_DSN` | no | *(unset)* | Comma-separated dataset prefixes; write/destructive tools may only target these |
| `MF_AUDIT_LOG` | no | `logs/audit.log` | JSONL audit trail (sensitive fields redacted) |
Copy `pds_locations.sample.txt` to `pds_locations.txt` and edit it for your site.
## Client configuration
The native package installs a `mainframe-mcp` command. Point your client at it
and pass the endpoint + credentials via `env`.
### VS Code (GitHub Copilot)
Add to `.vscode/mcp.json` in your workspace:
```json
{
"servers": {
"mainframe": {
"type": "stdio",
"command": "mainframe-mcp",
"env": {
"MF_HOSTNAME": "your.host.example.com",
"MF_USERNAME": "${input:mf_username}",
"MF_PASSWORD": "${input:mf_password}"
}
}
}
}
```
### Cursor
Add to `~/.cursor/mcp.json` (or `.cursor/mcp.json` in the project):
```json
{
"mcpServers": {
"mainframe": {
"command": "mainframe-mcp",
"env": {
"MF_HOSTNAME": "your.host.example.com",
"MF_USERNAME": "you",
"MF_PASSWORD": "..."
}
}
}
}
```
### Claude Desktop
Add to `claude_desktop_config.json`
(`%APPDATA%\Claude\claude_desktop_config.json`):
```json
{
"mcpServers": {
"mainframe": {
"command": "mainframe-mcp",
"env": {
"MF_HOSTNAME": "your.host.example.com",
"MF_USERNAME": "you",
"MF_PASSWORD": "..."
}
}
}
}
```
## Available tools (31)
**Retrieval:** `get_cobol`, `get_copybook`, `get_ct1`, `get_jcl`, `get_proc`,
`get_job_docs`, `get_content`, `scan_source`
**Datasets:** `get_dataset_list`, `get_dataset_members`, `get_gdg_versions`,
`search_seq_datasets`, `create_dataset`, `create_dataset_like`, `delete_dataset`,
`rename_dataset`, `recall_dataset`, `copy_member`, `modify_module`, `upload_member`
**Jobs:** `submit_job`, `submit_jcl_string`, `get_job_status`,
`get_job_steps`, `get_job_files`, `get_job_file_content`, `get_job_jcl`,
`get_job_notification`, `get_spool_details`, `export_spool_to_dataset`
**TSO:** `run_tso_command`
## Architecture
Components:
| Layer | File | Role |
|-------|------|------|
| Transport / entry | `server_native.py` (`main()` → `mcp.run()`) | Registers tools, speaks MCP over stdio |
| Safety layer | `mcp_common.py` | Intent annotations, read-only mode, confirm guards, scope allowlist, audit |
| RSE client | `rse_client.py` | Pure-Python `httpx` calls to the z/OS RSE REST API |
| Config | env + `pds_locations.txt` | Endpoint, credentials, segment → dataset map |
What happens on a tool call:
```mermaid
sequenceDiagram
participant C as MCP client
participant S as server_native (FastMCP)
participant W as mf_tool + _run
participant SF as Safety (mcp_common)
participant R as RSEClient (httpx)
participant MF as RSE API
C->>S: tools/call get_cobol(["PROG1"])
S->>W: dispatch tool
W->>SF: _dsn_allowed? / _needs_confirmation?
alt blocked
SF-->>C: {status:"error"|"needs_confirmation"}
else allowed
W->>W: _client() builds creds (MF_* env)
W->>R: client.read_member(dsn)
R->>MF: GET /datasets/{dsn}/content (Basic auth, TLS)
MF-->>R: 200 + records
R-->>W: unwrap_records()
W->>SF: _audit(tool, args, "success", ms)
W-->>C: {status:"success", data:{...}}
end
```
Safety gates, in order:
1. **Registration filter** — `MF_READ_ONLY=1` means the 10 write + 4 destructive tools are never registered (clients see only the 20 read tools).
2. **Scope allowlist** — `MF_ALLOWED_DSN` rejects out-of-scope datasets before any network call.
3. **Confirm guard** — destructive tools return `needs_confirmation` unless called with `confirm=true`.
4. **Per-session credentials** — creds come from `MF_*` env (or a per-session override); missing creds return a clean error.
5. **Audit** — every call appends a redacted JSONL line (tool, args, status, duration).
The safety layer (`mcp_common.py`) and RSE client (`rse_client.py`) are
transport-agnostic, so the same tool bodies can be reused behind another
transport (e.g. an HTTP/OAuth front end) without changing the mainframe logic.
## Deploy
```bash
python -m build # -> dist/mainframe_mcp-<ver>-py3-none-any.whl + .tar.gz
twine upload dist/* # publish to PyPI
```
Then submit `server.json` to the MCP Registry. Users install with
`pip install mainframe-mcp` and point their MCP client at the `mainframe-mcp`
command with `MF_HOSTNAME` / `MF_USERNAME` / `MF_PASSWORD` set (see above).
## Hosting over HTTP (Render, Cloud Run, ...)
To run as a hosted service instead of stdio, `server_http.py` serves the same
tools over MCP **streamable-HTTP** at `/mcp`, guarded by a bearer token.
Local:
```bash
pip install -e ".[http]"
$env:MF_MCP_TOKEN="secret"; $env:MF_HOSTNAME="..."; $env:MF_USERNAME="..."; $env:MF_PASSWORD="..."
python server_http.py # clients connect to http://localhost:8000/mcp
# with header: Authorization: Bearer secret
```
Render: a `Dockerfile` and `render.yaml` are included. In Render →
**New → Blueprint / Web Service** from the (private) repo — it reads
`render.yaml`, generates `MF_MCP_TOKEN`, and you set `MF_HOSTNAME` /
`MF_USERNAME` / `MF_PASSWORD` in the dashboard. Endpoint:
`https://<your-app>.onrender.com/mcp`.
**Security:** these tools can modify datasets and submit jobs. Keep
`MF_MCP_TOKEN` set, serve only over HTTPS (Render terminates TLS), and prefer
`MF_READ_ONLY=1` (the `render.yaml` default). The host must also be able to
**reach your mainframe's RSE API** — a public host cannot reach an internal
z/OS system without a tunnel or VPN.
MCP Config
Below is the configuration for this MCP Server. You can copy it directly to Cursor or other MCP clients.
mcp.json
Connection Info
You Might Also Like
everything-claude-code
Complete Claude Code configuration collection - agents, skills, hooks,...
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
cc-switch
All-in-One Assistant for Claude Code, Codex & Gemini CLI across platforms.
servers
Model Context Protocol Servers
servers
Model Context Protocol Servers
Time
A Model Context Protocol server for time and timezone conversions.