mainframe-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mainframe-mcpList the COBOL members in ADCDB.SOURCE.COBOL"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mainframe-mcp
Fork note. This fork fixes a connection hang on some self-hosted Hercules setups. The fix adds a spare TN3270 connection before the main session. This avoids a locked startup screen. The fork also pins the
mcppackage below version 2 to fix a broken import. Upstream: sagar25k/mainframe-mcp.
A Model Context Protocol (MCP) plugin for Claude Code that gives an AI assistant safe, structured access to an IBM z/OS mainframe — read screens, browse datasets, edit code, submit jobs, and run regression tests, all through natural-language instructions in the Claude Code terminal.
Target user: A developer with a Claude Code terminal, a Python workstation, and access to a TN3270-reachable mainframe.
Project status — v1.0.0
All five build phases are code complete with comprehensive test coverage. Live verification against the reference host (IBM ADCD z/OS 1.10 at 147.93.154.32:23, userid ADCDC) is in the state below.
Phase | Code | Unit/offline tests | Live verification |
Phase 1 — Read-only TN3270 MCP server | ✅ | included in 260-test suite | ✅ live-verified |
Phase 2 — Dataset reads (ISPF + FTP transports) | ✅ | included | ✅ live-verified |
Phase 3 — Write operations + three-tier autonomy | ✅ | included | ✅ live-verified 8/8 acceptance (tag |
Phase 4 — Job submission + monitoring | ✅ | 40 unit tests | 🟡 1/12 live-verified (gate refusal). 11 remaining cases deferred — see §14.1 |
Phase 5 — Testing automation | ✅ | 51 unit tests + 23/23 offline sweep | 🟡 1 live-runbook case deferred — see §14.1 |
260 unit tests passing. Three real safety bugs found and fixed during Phase 3 live verification: rc-None tolerance (would have falsely reported write success on JES2-purged spool), bare-word "ABEND" false-positive (would have frozen the plugin when a member name happened to be "ABEND"), and the JES2/RACF jobname-prefix rule (would have silently rejected every internally-generated job). All three are pinned by regression tests.
Deferred items are environmental, not code blockers. The remaining 11 Phase 4 cases and the 1 Phase 5 live runbook case require an uninterrupted ADCD login window that the public reference host has not consistently provided. The plugin code paths under those cases are pinned by 91 unit/offline tests; the deferred work is purely a host-availability question. See §14.1 for the saturation observation and §14.9 for the bootstrap-residue quirk discovered during the partial Phase 4 sweep.
Future work tracked in §14.10 "Acknowledged future work" below.
Related MCP server: claude-ssh-mcp
How to use this document (Claude Code, read this first)
This README is both the human-facing project description and the authoritative build specification for Claude Code. When the user asks you to "build Phase N" or "continue the implementation," do the following:
Re-read the relevant phase section in full before writing any code.
Honor the Safety Model section unconditionally. It is not aspirational — every write tool you create must enforce these rules in code, not just in docstrings.
Follow the file structure under "Project Structure" exactly. New files go where this document says they go.
Match the tool signatures in the "Tool Surface Specification" section. Tool names, parameters, return types, and module assignments are fixed.
At the end of each phase, run the acceptance criteria checklist. Do not move to the next phase until the current one passes.
When in doubt, ask the user. Do not invent new tools, change the safety model, or skip phases without explicit confirmation.
If any instruction in this document conflicts with a verbal user request, surface the conflict and ask for clarification rather than silently choosing one.
Table of contents
1. Project goals
What this plugin does
When fully built, mainframe-mcp lets a Claude Code user accomplish mainframe development tasks by talking to Claude in plain English:
"Log in to the mainframe and show me what's on the screen."
"List the COBOL members in
ADCDB.SOURCE.COBOL.""Read
PAY001and explain what it does.""There's an S0C7 in PAY001. Find the bug and fix it." (with confirmation step)
"Submit the compile JCL and tell me when it finishes."
"Run the regression test suite against the payroll transaction."
Six capabilities, built in order
Read — screens, PDS members, datasets, job output. (Phase 1–2)
Write — edit existing members, create new ones, with Git versioning. (Phase 3)
Audit — analyze code for issues, propose fixes via three-tier autonomy. (Phase 3, refined later)
Submit & monitor — JCL submission, job status, SYSOUT retrieval. (Phase 4)
Navigate — keyboard-only ISPF/CICS navigation through Claude's instruction. (Phase 1+)
Test — automated regression testing of screen flows and batch jobs. (Phase 5)
Non-goals
Real-time multi-user collaboration. Single-user, single-session.
Production deployment. This is a learning/portfolio project against ADCD.
Offensive security tooling. No brute force, no fuzzing, no protected-field tampering.
Bypassing mainframe security. Every action is taken as the logged-in user with their normal RACF permissions.
2. Target environment
Mainframe
Property | Value |
Type | IBM ADCD (Application Developer's Controlled Distribution) |
z/OS version | 1.10 |
Host |
|
TN3270 port |
|
Authentication | Plain RACF userid/password |
Default test user |
|
z/OSMF available? | No (z/OS 1.10 predates z/OSMF) |
File transfer | Plain FTP (z/OS FTP server on standard port 21) |
Workstation
Property | Value |
OS | Windows 11 (primary), should also work on Linux/macOS |
Python | 3.11.9 (confirmed installed) |
Working directory |
|
Virtual environment |
|
3270 client |
|
AI client | Claude Code (Anthropic CLI) |
Why these choices
ADCD over real corporate mainframe: no compliance constraints, free to experiment.
Plain FTP over Zowe REST: z/OS 1.10 has no z/OSMF, so Zowe's REST mode is unavailable. FTP is built into z/OS and works against any version.
p3270overpy3270:py3270has not been updated in over a year and is effectively unmaintained.p3270is actively maintained, has a cleaner API, and wraps the sames3270binary.
3. Tech stack
Exact versions
Python >= 3.11.0
mcp >= 1.27.0 # Official MCP SDK with FastMCP
p3270 latest # TN3270 wrapper around s3270
keyring latest # OS credential store
pyyaml latest # Config file parsing
# Standard library: ftplib, sqlite3, subprocess, pathlib, loggingSystem requirements
s3270.exe(from wc3270) on PATHgiton PATHNode.js +
@anthropic-ai/claude-codefor the AI client
Why each dependency
Dependency | Purpose | Alternatives considered |
| MCP protocol implementation |
|
| TN3270 client |
|
| Credential storage |
|
| Config | TOML (acceptable alternative, YAML chosen for familiarity) |
| File transfer to z/OS | Zowe CLI (not available without z/OSMF) |
| Audit log | JSON lines (rejected — harder to query) |
4. Architecture
Diagram
┌─────────────────────┐
│ Claude Code CLI │
│ (your terminal) │
└──────────┬──────────┘
│ stdio / JSON-RPC (MCP protocol)
│
┌───────┴────────┐
│ │
┌──┴──────────┐ ┌──┴───────────┐ ┌──────────────┐
│ read MCP │ │ write MCP │ │ test MCP │
│ (always on) │ │ (opt-in) │ │ (opt-in) │
└──┬──────────┘ └──┬───────────┘ └──┬───────────┘
│ │ │
│ │ │
├────────────────┴──────────────────┤
│ │
▼ ▼
┌──────────────────┐ ┌──────────────────┐
│ s3270 process │ │ FTP client │
│ (TN3270 stream) │ │ (file transfer) │
└────────┬─────────┘ └────────┬─────────┘
│ port 23 │ port 21
│ │
└────────────┬───────────────┘
▼
┌────────────────────────┐
│ ADCD z/OS 1.10 │
│ 147.93.154.32 │
│ (TSO, ISPF, JES, PDS) │
└────────────────────────┘Three MCP servers, not one
The plugin is implemented as three separate MCP server processes, each registered independently with Claude Code:
mainframe-read— always loaded. Read-only tools: screens, datasets, job output, navigation (keystrokes that don't write data).mainframe-write— loaded only whenMAINFRAME_MODE=WRITEis set. Modifies PDS members, submits jobs, deletes things. All operations gated by safety rules.mainframe-test— loaded only whenMAINFRAME_MODE=TESTis set. Captures baselines, runs test scripts, compares results.
Why three instead of one:
The write tools literally do not exist in the read server, so they cannot be called by accident.
Different sessions can run different modes (read-only by default, write only when intentional).
Smaller per-server tool surfaces are easier for the AI to use correctly.
Session model
Each server process maintains one persistent TN3270 session to the mainframe. Sessions are:
Opened on first tool call (lazy connect) or explicitly via
connect().Health-checked before every tool call via a fast ping.
Auto-reconnected on broken pipe (handles mainframe-side timeouts).
Closed cleanly on server shutdown via
atexit.
Code-writing pattern (important)
When Claude edits a member, the flow is:
1. read_member() pulls PDS member → workspace/COBOL/PAY001.cbl
2. Claude reads the local file, proposes changes
3. edit_member() writes new content → workspace/COBOL/PAY001.cbl
4. Auto-stage in git: `git add workspace/COBOL/PAY001.cbl`
5. Show diff to user; require confirmation for sensitive datasets
6. Upload to PDS via FTP: STORE workspace/COBOL/PAY001.cbl → ADCDB.SOURCE.COBOL(PAY001)
7. Commit: `git commit -m "Claude: <description>"`From the user's perspective, the code appears in their ISPF emulator after a refresh (F5). No copy-paste. Git is the safety net — every change is versioned locally before it touches the mainframe.
5. Safety model
These rules are non-negotiable. They are enforced in code, not just in documentation. Tools that violate these rules must refuse to execute even if the AI passes "correct"-looking arguments.
Three-tier autonomy
Every potentially-modifying action is classified into one of three tiers:
Tier | Behavior | Examples |
Auto-apply | Tool executes, logs the action, returns result. | Whitespace fixes, comment additions, lint fixes, JCL syntax corrections. |
Confirm-then-apply | Tool returns a diff and waits. Requires the user to issue an explicit confirmation tool call. | Logic changes, new validation rules, JCL parameter changes. |
Suggest-only | Tool writes a proposal file to | Anything touching financial calculations, security exits, regulated/audit code. |
Implementation rule: The tier of each operation is determined by a deterministic function classify_change(target, change_type) in safety/classifier.py, NOT by the AI's self-reported confidence.
Hard rules (always enforced)
Read-only by default. The write server only loads when
MAINFRAME_MODE=WRITEis explicitly set AND the--allow-writesflag is passed at startup.Dataset scope is enforced. Any write tool calls
permissions.check_write_allowed(dataset)as its first line. If the dataset matches any pattern inscope.forbidden_patternsor doesn't match any inscope.allowed_datasets, the tool raisesPermissionDeniedand refuses.Sensitive patterns are read-only forever. Patterns like
SYS1.*,*.LINKLIB,*.PROD.*(configurable) cannot be written to even in write mode.Snapshot before write. Before any modification of a PDS member, the current content is downloaded to
workspace/<dataset>/<member>and committed to git. If git commit fails, the write does not proceed.Abend stops automation. If
check_for_errors()detects an abend on the current screen, the next 5 tool calls auto-refuse with a message asking the user to investigate. (Prevents runaway loops on broken sessions.)Audit log every tool call. Every invocation of any tool — read or write — writes a row to
logs/audit.sqlitewith timestamp, userid, tool name, arguments (passwords redacted), and outcome.Rate limits. Default 60 tool calls per minute, configurable. Excess calls block until the window clears.
No credential exposure. Passwords are read from OS keychain. They never appear in tool arguments, return values, log output, or screen captures.
Escalation protocol
When a tool would land in confirm-then-apply tier, it returns a structured response Claude shows to the user:
PROPOSED CHANGE: edit_member ADCDB.SOURCE.COBOL(PAY001)
TIER: confirm-then-apply
REASON: Modifies logic inside PROCEDURE DIVISION (not whitespace/comments only).
DIFF:
- 0010 MOVE EMP-ID TO WS-LOOKUP-KEY
+ 0010 IF EMP-ID IS NUMERIC
+ 0011 MOVE EMP-ID TO WS-LOOKUP-KEY
+ 0012 ELSE
+ 0013 DISPLAY 'INVALID EMP-ID'
+ 0014 GOBACK
+ 0015 END-IF
CONFIRM by calling: confirm_change(token="<token>")
REJECT by ignoring or calling: reject_change(token="<token>")The token is single-use and expires in 5 minutes.
What this means for the AI assistant
Claude should:
Always identify the dataset being targeted before any write.
Surface diffs to the user before confirming any change.
Stop and ask the user when uncertain about a fix's impact.
Never claim a change was applied if a tool returned
PermissionDeniedorRequiresConfirmation.
6. Project structure
mainframe-mcp/
├── README.md # This file (the build spec)
├── LICENSE # AGPL-3.0
├── pyproject.toml # Package metadata + dependencies
├── requirements.txt # Pinned deps for reproducibility
├── .gitignore # Excludes .venv, logs/, secrets, workspace/
├── .env.example # Template env file for users
├── config.example.yaml # Template config
│
├── src/mainframe_mcp/
│ ├── __init__.py
│ ├── config.py # YAML + env var loader, keyring access
│ ├── audit.py # SQLite audit log (append-only)
│ │
│ ├── core/
│ │ ├── __init__.py
│ │ ├── session.py # Persistent TN3270 session wrapper around p3270
│ │ ├── ftp_client.py # FTP wrapper for dataset transfer
│ │ ├── screen_parser.py # Row-numbered formatting, signature detection
│ │ └── exceptions.py # PermissionDenied, RequiresConfirmation, etc.
│ │
│ ├── safety/
│ │ ├── __init__.py
│ │ ├── permissions.py # check_write_allowed(), scope rules
│ │ ├── classifier.py # classify_change() — three-tier logic
│ │ ├── abend.py # check_for_errors(), abend code list
│ │ └── rate_limiter.py # Token-bucket rate limiting
│ │
│ ├── servers/
│ │ ├── __init__.py
│ │ ├── read_server.py # mainframe-read MCP server
│ │ ├── write_server.py # mainframe-write MCP server
│ │ └── test_server.py # mainframe-test MCP server
│ │
│ └── tools/
│ ├── __init__.py
│ ├── screen_tools.py # get_screen, find_text, get_text_at, ...
│ ├── nav_tools.py # send_enter, send_pf, wait_for_text, ...
│ ├── dataset_tools.py # list_datasets, read_member, ...
│ ├── job_tools.py # submit_jcl, check_job, fetch_sysout, ...
│ ├── write_tools.py # edit_member, create_member, ...
│ └── test_tools.py # capture_baseline, run_test, ...
│
├── workspace/ # Local git repo of downloaded PDS members
│ └── .gitkeep
│
├── proposals/ # Suggest-only tier writes proposals here
│ └── .gitkeep
│
├── logs/ # SQLite audit log + debug logs
│ └── .gitkeep
│
├── tests/ # pytest suite
│ ├── __init__.py
│ ├── conftest.py
│ ├── test_config.py
│ ├── test_session.py # uses recorded screens, no live mainframe
│ ├── test_permissions.py
│ └── fixtures/
│ └── screens/
│
└── docs/
├── INSTALL.md # User-facing install guide
├── USAGE.md # Example Claude Code prompts
└── DEVELOPMENT.md # How to extend / contribute7. Configuration
Sources of truth, in priority order
Command-line flags (highest priority)
Environment variables
config.yamlin working directoryBuilt-in defaults (lowest priority)
config.example.yaml
mainframe:
host: 147.93.154.32
port: 23
tls: false
model: "3279-2"
code_page: cp037 # ADCD default
s3270_path: "C:\\Program Files\\wc3270\\"
session:
connect_timeout: 30 # seconds
keystroke_delay: 0.3 # seconds between sends
screen_change_timeout: 10 # default wait timeout
scope:
# Allowed dataset patterns (write tools refuse anything not matching)
allowed_datasets:
- "ADCDB.*"
- "STUDENT.*"
# Forbidden patterns (never written, even if otherwise allowed)
forbidden_patterns:
- "SYS1.*"
- "SYS2.*"
- "*.LINKLIB"
- "*.LPALIB"
- "ADCD.*" # ADCD's own system datasets
# Read-only-mandatory patterns (subset of forbidden, more explicit)
read_only_patterns:
- "*.PROD.*"
safety:
default_mode: READ # READ | WRITE | TEST
require_confirmation_token_minutes: 5
abend_lockout_calls: 5 # auto-refuse N calls after abend
audit_log_path: "./logs/audit.sqlite"
audit_retention_days: 30
rate_limits:
calls_per_minute: 60
burst: 10
git:
workspace_path: "./workspace"
auto_commit: true
commit_author_name: "mainframe-mcp"
commit_author_email: "noreply@local"
logging:
level: INFO # DEBUG | INFO | WARNING | ERROR
path: "./logs/mainframe-mcp.log"Environment variables
Variable | Purpose | Required |
| Override | No |
| RACF userid for this session | Yes |
|
| No (defaults to READ) |
| Path to config.yaml | No (defaults to |
|
| No |
Secret storage
The RACF password is stored in the OS keychain via the keyring library:
import keyring
keyring.set_password("mainframe-mcp", os.environ["MAINFRAME_USERID"], password)Set it once with a small helper script (scripts/set_password.py); never type it in code, prompts, or config files.
7a. Known environmental requirements (host-side)
The plugin runs against IBM z/OS hosts in general, but certain JES2 /
TSO / RACF defaults are not universal. Both items below were
discovered during live verification on the ADCD z/OS 1.10 instance
at 147.93.154.32:23 and apply to any host with similar JES2 /
RACF configuration. Plugin code handles them; this section documents
them so future operators (and future maintainers) know what to expect.
7a.1 JOB-card jobname must start with the submitter's userid
ADCD's RACF JES2 rule rejects any job whose JOB-card jobname does
not begin with the userid running the submit, with:
IKJ56328I JOB <jobid> REJECTED - JOBNAME MUST BE YOUR USERID
OR MUST START WITH YOUR USERIDThe rejection happens at JCL conversion time, after JES2 has
already assigned a job id, so the symptom in logs is a submitted job
that reaches NOT FOUND status almost immediately and never produces
a step-execution spool. Code handling:
For internally-generated jobnames (
make_jobname()used by the IEBGENER / IEBUPDTE write transport and by Phase 3/4 verify bootstrap), the userid is passed in and prefixed onto the jobname. See core/jcl_writer.py andtests/test_jcl_writer.pyuserid cases.For user-supplied JCL members (Phase 4
submit_jcl(pds_member)), the JCL author is responsible for the inner JOB-card jobname. Use a jobname that starts with your userid (e.g.//ADCDCH JOB ...for userid ADCDC). The plugin cannot edit user JCL on submit.
7a.1a TSO STATUS/OUTPUT/CANCEL require jobname = userid + 1 char
A stricter, related rule surfaced during Rung-1 live verification
(bug #8). Even when a jobname starts with the userid, TSO
STATUS / OUTPUT / CANCEL on ADCD only operate on a job whose
jobname is the userid plus exactly ONE character. A longer
suffix (e.g. ADCDC + 3 chars = ADCDCHW or ADCDC123) is accepted
by JES2 at submit — IKJ56250I ... SUBMITTED — but then those TSO
commands reject it with the same IKJ56328I ... JOBNAME MUST BE YOUR USERID OR MUST START WITH YOUR USERID message, so job
monitoring (check_job / fetch_sysout / cancel_job) silently
fails to find a job that actually ran.
Why it was masked until Rung-1: write verification uses LISTDS
(member existence), not TSO OUTPUT — so the write path
(create_member / edit_member) never depended on a queryable
jobname. Only the Phase 4 monitoring path, exercised end-to-end
for the first time in Rung-1, hits the TSO STATUS/OUTPUT
restriction. JES2's aggressive spool purge (§7a.2) further hid it in
earlier partial runs by making OUTPUT return nothing regardless.
Fix: make_jobname(userid) now emits userid + exactly 1 char
(36-value 0-9A-Z suffix), total ≤ 8 — e.g. ADCDC → ADCDCH. The
userid portion is truncated to 7 for long userids so userid+1
never exceeds the 8-char slot. User-supplied JCL members must follow
the same rule to be monitorable. Pinned by test_jcl_writer.py
userid+1char cases.
7a.2 Aggressive JES2 spool purge on z/OS 1.10
ADCD's JES2 purges job spool quickly after job termination — often
before the plugin can issue its OUTPUT jobid retrieval command,
even when the request follows the ON OUTPUT QUEUE state
immediately. The plugin handles this with a two-layer verification
contract (see §14.8 "Write verification semantics"): host-state
read-back via member_exists() is the ground truth for write
operations, and the JES2 RC is treated as best-effort diagnostic
only. Operators should not be alarmed by note: JES spool was unreadable; success confirmed by read-back probe messages — that
is the verified-by-host-state success path.
7a.3 Long-lived TSO sessions and ADCD's session table
A (dirty) disconnect leaves a TSO session in the dangling state.
ADCD reclaims dangling sessions on its default TSO timeout
(typically 15-30 min) or via the operator console
F TSO,USER=<userid>,LOGOFF. The plugin's force_cleanup() tool
tries an in-band recovery first; if multiple orphans accumulate
(e.g. during an iterative debug session), the session table can
saturate and new logons return IKJ56425I LOGON rejected, UserId <userid> already logged on. Wait for the timeout or use the
console MODIFY command — there is no other in-band escape.
8. Implementation phases
Each phase is independently shippable. Do not start a phase until the prior phase's acceptance criteria pass.
Phase 0 — Environment verification (already done)
Confirmed:
Python 3.11.9 installed
wc3270 /
s3270.exeto be installed and verified by userNetwork reach to
147.93.154.32:23confirmed via VISTA emulatorClaude Code installed and signed in
Acceptance criteria: Smoke test script (provided separately) prints the ADCD welcome screen to stdout when run.
Phase 1 — Read-only TN3270 MCP server
Goal: Claude Code can log in to the mainframe, read screens, navigate ISPF, and report what it sees.
Deliverables:
Project skeleton. Create directory structure under
src/mainframe_mcp/exactly as specified in section 6. Empty__init__.pyfiles where needed.pyproject.tomlwith declared dependencies.config.py— load YAML, layer env vars, expose typed config object.audit.py— SQLite-backed append-only log with schema:CREATE TABLE audit ( id INTEGER PRIMARY KEY AUTOINCREMENT, timestamp TEXT NOT NULL, userid TEXT NOT NULL, tool_name TEXT NOT NULL, arguments_json TEXT NOT NULL, -- passwords redacted outcome TEXT NOT NULL, -- 'ok' | 'error' | 'refused' details TEXT );core/session.py—MainframeSessionclass wrappingp3270.P3270Client:connect()— opens s3270 subprocess, connects to host.login(userid)— fetches password from keyring, sends VTAM logon sequence, waits for TSO READY.ensure_connected()— health-check + auto-reconnect.disconnect()— clean shutdown.get_raw_screen()— current screen as 24x80 text.send(text)— type into current field.send_aid(key)— send ENTER/PFn/PAn/CLEAR.wait_for_text(pattern, timeout)— poll until match or timeout.wait_for_change(timeout)— poll until screen differs.
core/screen_parser.py—format_screen()returns row-numbered text matching hack3270's{i+1:2}| {line}format;identify_screen()checks for known signatures and returns a screen ID.safety/abend.py— list of abend codes (S0C7,S0C4,ASRA,AICA,AEY7,APCT,ASRB,AEXL,DFHAC2,ABEND, plus genericSxxxandUxxxxpatterns). Functiondetect_abend(screen_text) -> Optional[str].safety/rate_limiter.py— token-bucket implementation, blocking variant.tools/screen_tools.py—get_screen,find_text,get_text_at,analyze_screen_fields,check_for_errors.tools/nav_tools.py—send_enter,send_pf(1-24),send_pa(1-3),send_clear,send_keys,wait_for_text,wait_for_screen_change.servers/read_server.py—FastMCP("mainframe-read", instructions=...). Register all read + nav tools. Define_ensure_connected()helper that wraps every tool. Includeconnect,login,disconnect,statusas session-management tools.
Acceptance criteria:
claude mcp add mainframe-read -- python -m mainframe_mcp.servers.read_serversucceeds.In Claude Code, asking "connect to the mainframe as ADCDB and tell me what's on the screen" results in Claude calling
connect,login, thenget_screen, and returning a sensible description of the ADCD welcome banner.Asking "navigate to ISPF option 3.4" results in Claude sending
ISPF, ENTER,3.4, ENTER, and reporting the dataset list panel.Audit log
logs/audit.sqlitecontains rows for every tool call with no plaintext passwords.Disconnecting and reconnecting works without restarting the MCP server.
Phase 2 — Dataset reads (dual transport: ISPF scrape + FTP)
Goal: Browse PDS contents and read members. Two independent transports are
implemented because most public ADCD instances only expose TN3270 (port 23) —
the FTP port is firewalled and unreachable. The active transport is chosen by
config.dataset.transport.
Transport | When to use | Trade-offs |
| Any reachable host; works against the public ADCD instance | Slower, scrapes ISPF 3.4 and View panels via TN3270, brittle to ISPF panel changes |
| Local Hercules / corporate z/OS where port 21 is open | Fast, structured responses, but requires reachable z/OS FTP server |
If transport: ftp is configured and the FTP control port is unreachable AND
dataset.fallback_to_ispf: true (default), the dispatcher logs a warning and
silently falls back to the ISPF scrape transport for the remainder of the
process. Set fallback_to_ispf: false to hard-fail instead.
Deliverables:
core/ftp_client.py—MainframeFTPclass:connect()— uses same host as TN3270, port 21, same RACF credentials.list_datasets(pattern)/list_members(pds)/read_member(pds_member)/get_dataset_info(name).Module-level
is_ftp_reachable(host, port, timeout)for the dispatcher's probe.
core/ispf_dataset.py—IspfDatasetAdapterexposing the same surface via ISPF 3.4 navigation and View-panel scraping. Reuses the existingMainframeSession.core/dataset_transport.py—DatasetDispatcherresolves the active backend on first use, performs the FTP reachability probe, and applies the fallback policy.tools/dataset_tools.py—list_datasets,list_members,read_member,get_dataset_info. All read-only; no scope restrictions on reads.Register tools in
servers/read_server.py.
Acceptance criteria:
With
transport: ispf(default) against the live ADCD host:"List datasets matching ADCDC.*" returns at least the user's own datasets.
"List the members of ADCD.Z110S.PROCLIB" returns a member list.
"Read PROCLIB(ISPFPROC) and explain it" returns the JCL text.
Reading a non-existent member returns a clean
ERROR: member not found:string, not a crash.
With
transport: ftpagainst a host with port 21 open, the same prompts work via FTP.With
transport: ftpagainst a host with port 21 closed andfallback_to_ispf: true, the dispatcher logs a warning and the same prompts still succeed via the ISPF path.
Phase 3 — Write operations with Git + FTP + three-tier autonomy
Status: ✅ Code complete and live-verified against ADCD z/OS 1.10
at 147.93.154.32:23 with userid ADCDC (commit-tagged
phase-3-live-verified). 239 unit tests pass. 8/8 live acceptance
checks pass — see PHASE3_READINESS.md for the completion record and
the per-case results.
Goal: Claude can edit code, with full safety scaffolding.
Deliverables:
safety/permissions.py—check_write_allowed(dataset) -> None | raise PermissionDenied. Matches againstscope.allowed_datasets,scope.forbidden_patterns,scope.read_only_patterns. Tested exhaustively.safety/classifier.py—classify_change(target, change_type, diff) -> Tier. Returns one ofAUTO,CONFIRM,SUGGEST. Initial rules:SUGGESTif target matches any pattern insafety.suggest_only_patterns(configurable list including security exits, audit logging code).AUTOif diff is whitespace-only OR comment-only OR JCL syntax fix.Everything else →
CONFIRM.
Git integration utilities — wrap
subprocess.run("git ...")calls incore/git_helper.py. Functions:init_workspace_repo(),stage_file(),commit(message),diff(file),snapshot_before_write(dataset, member).Confirmation token system —
safety/tokens.py. Generate short tokens, store in-memory with 5-minute TTL, single-use.tools/write_tools.py—edit_member,create_member,delete_member,confirm_change,reject_change,propose_change(suggest-only entry point).servers/write_server.py— separateFastMCP("mainframe-write")server. Refuses to start unlessMAINFRAME_MODE=WRITEAND--allow-writesflag are both present. Loads ALL read tools (shared) PLUS write tools.
Acceptance criteria:
✅ Read-mode session: asking Claude to edit anything results in "I don't have write tools available; please restart in write mode." (gate refusal verified at server start AND live:
write_serverexits 2 withREFUSEDwhenMAINFRAME_MODE=READ).✅ Write-mode session: editing a member in allow-listed scope works end-to-end (read → diff → confirm → JCL submit → host read-back verify → git commit), member updated on mainframe. Verified live against ADCDC.MCPTEST.SOURCE(NEWMEM1) on ADCD.
✅ Editing a member in
SYS1.*is refused withPermissionDeniedregardless of confirmation. Verified live (SYS1.PARMLIB(IEFSSN00)rejected before any host contact).✅ Whitespace-only edits skip confirmation (auto-tier). Verified live.
✅ Logic edits return a diff + token; calling
confirm_change(token)applies it. Verified live.✅ Workspace git history shows one commit per applied change. Verified live (6 Claude commits in workspace after C/D/E run).
Phase 3 added a third write transport, jcl, that submits inline JCL
via TSO SUBMIT * for hosts where FTP port 21 is firewalled. The
default is now dataset.transport: jcl; ftp is available when port
21 is reachable. The plugin also supports both standard IBM ISPF/PDF
(ADCD z/OS) and Rocket RFE (TK4-/TK5 MVS 3.8j) panel variants via
signature-based detection — see core/ispf_dataset.py
_DSLIST_TITLE_MARKERS / _DSLIST_FIELD_LABELS.
Phase 4 — Job submission and monitoring
Goal: Compile and run code.
Deliverables:
tools/job_tools.py—submit_jcl(pds_member),check_job(job_id),fetch_sysout(job_id, ddname="ALL"),list_my_jobs(),cancel_job(job_id)(write-mode only, confirm tier).JCL submission is WRITE-tier because it consumes mainframe resources, but checking job status and reading SYSOUT is READ-tier.
Job IDs are tracked in a session-local list so Claude can refer to "the last job."
Status: Code complete, 249 unit tests passing. Live verification partial: 1/12 acceptance cases verified (READ-mode gate refusal); the remaining 11 cases are deferred pending ADCD session-table availability. See §14.1 for the saturation observation that drove the deferral.
Acceptance criteria:
✅ Submitting an ALLOCATE JCL succeeds and returns a job ID. (Code verified via 40
test_job_runner/test_job_toolsunit cases; one live submit succeeded in the partial Phase 4 sweep.)⏸ Checking status returns "RUNNING" then "OUTPUT" then return code. (Code:
JobRunner.statusreturns raw TSO STATUS labels per §14.6; unit-tested. Live deferred.)⏸ Fetching SYSOUT of a failed compile shows the error messages. (Code:
fetch_sysoutreturns spool body + RC header; unit-tested. Live deferred.)⏸ An abend in SYSOUT triggers
detect_abendand is highlighted. (Code:_apply_change+fetch_sysouttripabend_state.trip()on abend codes; the bare-word path now requires a structural context marker so screen-scrollback occurrences of "ABEND" (e.g. a job whose jobname happens to be ABEND) don't false-trip. 12 new guard tests intest_abend.py. Live deferred.)
Phase 5 — Testing automation
Status: ✅ Code complete and offline-verified. scripts/phase5_verify.py
passes 23/23 acceptance checks (offline / mock-session). Live ISPF
flow capture deferred to a combined Phase 4+5 live sweep when ADCD
session table is available.
Goal: Regression-test mainframe applications.
Deliverables:
tools/test_tools.py(5 tools, all READ-tier with respect to mainframe state — record/replay does not write to the host):capture_baseline(test_name, description="", ignore_patterns="")— appends one frame (last action + current screen) to the named baseline. Optional comma-separated regexignore_patternsare merged into the baseline on every call (deduped, invalid regex silently skipped).run_test(test_name)— replays each recorded action and diffs the live screen against the recorded screen, honoring the baseline'signore_patterns. ReturnsPASS:orFAIL:with a per-frame row diff.compare_screens(actual, baseline_name)— ad-hoc diff against the LAST frame of a stored baseline.list_baselines(),delete_baseline(name, confirm_token)— delete is two-call CONFIRM-tier (irreversible).
Baselines stored as YAML in
tests/baselines/<test_name>.yaml(one file per test, human-diffable in git). Schema includes optional top-levelignore_patterns: [<regex>, ...]for masking.servers/test_server.py— separateFastMCP("mainframe-test")server, loaded only whenMAINFRAME_MODE=TEST. Audit log entries from this server are tagged so test-mode activity is separable from production read/write traffic.
Diff algorithm: line-by-line screen comparison after right-strip.
When the baseline carries ignore_patterns, each regex match is
replaced with same-length spaces in BOTH screens before the
comparison — so e.g. a time-of-day field that drifts between runs
doesn't surface as a diff. The returned diff tuples carry the
original (unmasked) row text so operators see exactly what changed.
Acceptance criteria:
✅ Recording a 3-screen ISPF navigation flow creates a baseline file. (verified offline in
scripts/phase5_verify.pycase A.)✅ Replaying it against the same target produces
PASS:. (case B.)✅ Replaying against an intentionally-changed screen produces a clear diff and
FAIL:. (case C, with the changed token surfacing in the row diff output.)✅
ignore_patternsmask a time-of-day field so an expected between-run drift is excluded; real divergence still surfaces. (case D — bonus criterion added per Phase 5 environmental note.)
9. Tool surface specification
Naming convention
All tools use snake_case. Group prefixes are NOT used in the function name (FastMCP exposes functions by their Python name). Grouping is done via module organization and clear docstrings.
Read server tools (always available)
Session management
def connect() -> str
def login(userid: str) -> str
def disconnect() -> str
def status() -> str
def reconnect() -> strScreen reading
def get_screen() -> str
def find_text(pattern: str) -> str
def get_text_at(row: int, col: int, length: int = 80) -> str
def analyze_screen_fields() -> str
def identify_screen() -> str # returns known screen_id or "UNKNOWN"
def check_for_errors() -> str # abend detectionNavigation
def send_enter() -> str
def send_pf(number: int) -> str # 1..24
def send_pa(number: int) -> str # 1..3
def send_clear() -> str
def send_keys(text: str) -> str
def wait_for_text(pattern: str, timeout: float = 10.0) -> str
def wait_for_screen_change(timeout: float = 10.0) -> strDatasets (read only)
def list_datasets(pattern: str) -> str
def list_members(pds: str) -> str
def read_member(pds_member: str) -> str
def get_dataset_info(dataset: str) -> strJobs (status only)
def list_my_jobs() -> str
def check_job(job_id: str) -> str
def fetch_sysout(job_id: str, ddname: str = "ALL") -> strWrite server tools (write mode only)
All of the read tools, PLUS:
def edit_member(pds_member: str, new_content: str, description: str) -> str
def create_member(pds_member: str, content: str, description: str) -> str
def delete_member(pds_member: str, confirm_token: str) -> str
def submit_jcl(pds_member: str) -> str
def cancel_job(job_id: str, confirm_token: str) -> str
def confirm_change(token: str) -> str
def reject_change(token: str) -> str
def list_pending_changes() -> str
def propose_change(target: str, description: str, proposed_diff: str) -> strTest server tools (test mode only)
All read tools, PLUS:
def capture_baseline(test_name: str, description: str = "") -> str
def run_test(test_name: str) -> str
def compare_screens(actual: str, baseline_name: str) -> str
def list_baselines() -> str
def delete_baseline(test_name: str, confirm_token: str) -> strReturn value conventions
All tools return
str. Even when returning structured data, format it as readable text. FastMCP exposes the string to the AI.Action tools that modify state return the resulting screen (formatted, row-numbered). Example:
send_enter()returns the new screen, not "ok."Errors return a string starting with
ERROR:followed by a short explanation, NOT a raised exception (raised exceptions are auto-converted by FastMCP but lose context).Refusals return
REFUSED:prefix with reason. Examples:REFUSED: dataset SYS1.PARMLIB matches forbidden pattern,REFUSED: write tools not loaded in READ mode.Confirmation prompts return
CONFIRM:prefix followed by diff + token instructions.
10. Coding conventions
General
Python 3.11+ features OK. Use
match/case, type aliases,dataclass(slots=True).Type hints on every function. FastMCP uses them to generate tool schemas.
Docstrings on every tool. First line is a short description (becomes the tool description in MCP). Following lines explain arguments and return value. Claude reads these — write them for an AI audience.
No bare
except:. Catch specific exceptions; let real bugs surface.Logging, not print. Use the
loggingmodule configured inmainframe_mcp/__init__.py.
Tool function pattern
Every tool follows this skeleton:
@mcp.tool()
def some_action(arg1: str, arg2: int = 0) -> str:
"""One-line description for the AI.
Longer explanation if needed. Mention edge cases the AI should know about.
Args:
arg1: What this is.
arg2: What this is, default 0.
"""
try:
rate_limiter.acquire()
session = ensure_connected()
audit.log_call("some_action", {"arg1": arg1, "arg2": arg2})
# ... actual work ...
audit.log_outcome("ok")
return format_result(result)
except PermissionDenied as e:
audit.log_outcome("refused", str(e))
return f"REFUSED: {e}"
except Exception as e:
audit.log_outcome("error", str(e))
logger.exception("some_action failed")
return f"ERROR: {e}"Imports
Standard library imports first, then third-party, then local. Each group alphabetized.
Use relative imports within the package:
from ..core.session import MainframeSession.
File size
Aim for ≤ 400 lines per file.
If a tools module grows past that, split by feature group (e.g.,
nav_tools.py→nav_aid_tools.py+nav_wait_tools.py).
11. Testing and verification
Unit tests (pytest)
Located in
tests/.Mock the
MainframeSessionfor most tests using recorded screen captures.Permission tests (
test_permissions.py) must be exhaustive — every pattern category gets tests for matching and non-matching cases.Run with
pytest -vfrom project root.
Integration tests
Live tests that hit the real ADCD mainframe. Marked with
@pytest.mark.live.Skipped by default; run with
pytest -m live.Use a dedicated test dataset prefix (
ADCDB.MCPTEST.*) so tests don't conflict with hand-driven work.
Manual acceptance per phase
Each phase has its acceptance criteria listed in section 8. Run through them with Claude Code before declaring the phase done. Document any deviations in docs/CHANGELOG.md.
Recommended verification flow for Claude Code
After implementing a phase:
Run unit tests:
pytest -vRegister MCP server with Claude Code (if not already):
claude mcp add ...Restart Claude Code session.
Run through the natural-language acceptance prompts from section 8.
Inspect audit log to confirm clean records.
12. Distribution
GitHub repository
Public repo:
github.com/<your-username>/mainframe-mcpLicense: GNU AGPL-3.0 (Affero General Public License v3). Copyright (C) 2026 Sagar Kanithi kanithisagar@gmail.com. Strong copyleft — any use, modification, or network deployment must release Corresponding Source under the same license. See
LICENSE.Branch protection: optional for a personal project, recommended for any shared use.
What users need to install
Documented in docs/INSTALL.md. Summary:
Clone the repo.
Install Python 3.11+ and wc3270 (Windows) or x3270 (Linux/Mac).
Create venv and install requirements.
Copy
config.example.yaml→config.yaml, edit host/scope.Set userid env var and password in keyring.
Register MCP servers with Claude Code.
Configurability for other mainframes
The plugin is designed so that other users can target their own mainframe by changing config.yaml:
Different host/port → just change those values.
Different code page (e.g.,
cp1140for European EBCDIC) → changemainframe.code_page.Different scope rules → edit
scope.allowed_datasetsand friends.TLS-enabled mainframe → set
mainframe.tls: trueandmainframe.port: 992.
Defaults in config.example.yaml point at ADCD because that's the assumed development target. Production users override.
Optional: list in the MCP server registry
After the plugin is stable, optionally submit a PR to github.com/modelcontextprotocol/servers to list it in the community registry. Not required.
13. Appendices
A. Abend code reference
Code | Meaning | Typical cause |
| Operation exception | Invalid instruction (uninitialized branch target) |
| Protection exception | Out-of-bounds memory access |
| Data exception | Bad numeric data (non-numeric in numeric field) |
| Time limit exceeded | Job ran too long |
| Module not found | Missing load module in STEPLIB |
| Security violation | RACF denial |
| Language Environment | COBOL runtime error |
| CICS abend (program check) | Same family as S0C* |
| CICS abend (transaction timeout) | Loop or wait too long |
| CICS abend (no authorization) | Resource not authorized |
| CICS abend (program not found) | PROGRAM not in PPT |
| CICS message | Transaction abnormally terminated |
B. ADCD-specific notes
Default datasets begin with
ADCD.*andSYS1.*. These are system datasets — do not write.User-allocated datasets typically begin with the userid (
ADCDB.*for user ADCDB).ISPF is started by typing
ISPFat the TSO READY prompt.TSO LOGON is automatic upon TN3270 connection if
LOGONis the application.The ADCD welcome banner shows documented default credentials — these are not secrets.
C. Common ISPF panels and their signatures
Screen ID | Signature (row, text) | Description |
| (24, "READY") | TSO command prompt |
| (1, "ISPF Primary Option Menu") | ISPF main menu |
| (1, "Data Set List Utility") | Option 3.4 dataset list |
| (1, "EDIT") | Editing a member |
| (1, "BROWSE") | Browsing a member |
| (1, "Display Filter View Print Options") | SDSF main panel |
Add more as discovered during Phase 1 work; store in safety/screens.py.
D. Useful references
ADCD documentation:
http://dtsc.dfw.ibm.com/adcd.htmlx3270 / wc3270 documentation:
https://x3270.orgMCP specification:
https://modelcontextprotocol.ioz/OS FTP user's guide (IBM Knowledge Center)
p3270library:https://github.com/mstiri/p3270hack3270 (reference for screen-handling patterns, NOT offensive tools):
https://github.com/gglessner/hack3270
E. Glossary
Term | Meaning |
ADCD | Application Developer's Controlled Distribution (IBM's z/OS for developer learning) |
AID | Attention Identifier (any key that sends data to host: ENTER, PFn, PAn, CLEAR) |
CICS | Customer Information Control System (online transaction processing) |
EBCDIC | Extended Binary Coded Decimal Interchange Code (mainframe character encoding) |
ISPF | Interactive System Productivity Facility (mainframe TUI/IDE) |
JCL | Job Control Language (batch job specification) |
JES | Job Entry Subsystem (batch scheduler) |
MCP | Model Context Protocol (the standard this plugin implements) |
PDS | Partitioned Data Set (mainframe "folder" containing members) |
RACF | Resource Access Control Facility (z/OS security manager) |
SDSF | System Display and Search Facility (job spool viewer) |
TSO | Time Sharing Option (interactive z/OS user environment) |
TN3270 | Telnet 3270 (the wire protocol for IBM terminals) |
z/OSMF | z/OS Management Facility (REST API for z/OS — not available on z/OS 1.10) |
14. Known deviations from this spec
Items where the running code intentionally diverges from this build specification. Every entry was either explicitly user-approved during implementation or is a strict superset of the spec behaviour.
14.1 Live verification status
The target host is ADCD z/OS 1.10 at 147.93.154.32:23. Phases 1,
2, and 3 are live-verified against this host as userid ADCDC. Phase 3
acceptance pass (8/8) is captured by the git tag
phase-3-live-verified. 249 unit tests pass. Phase 5 acceptance
sweep passes 23/23 offline via scripts/phase5_verify.py (no host
required for record/replay logic).
Phase 4 is code-complete; 1/12 live acceptance cases verified (READ-mode gate refusal). Remaining 11 cases require an unblocked ADCDC login window. Deferred because ADCD's TSO session table saturated during iterative live-verification attempts — see §14.1.1.
14.1.1 Saturation pattern observed during Phase 4 verify
Each (dirty) disconnect during iterative debugging leaves a TSO
session in the dangling state. ADCD reclaims dangling sessions on its
default TSO timeout (15-30 min). When several debug iterations happen
in quick succession (e.g. fixing a script bug, re-running, fixing
another, re-running again), the orphan-creation rate outpaces the
timeout-reclaim rate. Once the session table for the userid is
saturated, every new LOGON returns
IKJ56425I LOGON rejected, UserId <userid> already logged on and
the in-band force_cleanup() + Reconnect=S path can't keep up.
Mitigation: space verification runs across hours, not minutes.
Clean disconnect at the end of each run. If saturation occurs, only
two paths clear it: wait for the host timeout, or operator-console
F TSO,USER=<userid>,LOGOFF. The plugin code is correct in all paths
observed; the saturation is purely a host-side state problem.
Phase 4 live verify will be re-attempted in a single combined sweep with Phase 5 once the host has at least 4 hours of uninterrupted quiet time. Until then, the 1/12 + offline coverage stands.
14.2 Three write transports (FTP + JCL + ISPF) instead of FTP-only
The §4 architecture diagram shows a single FTP path for writes. The running code adds a second write path:
dataset.transport: jcl(current default) — submits inline IEBGENER / IEBUPDTE JCL via TSOSUBMIT *. Used when port 21 is firewalled. Implemented incore/jcl_writer.pyand routed bycore/dataset_transport.py.dataset.transport: ftp— the spec-default path. Still implemented and tested via unit fixtures. Switch back with one config line when an FTP-reachable host is in play.dataset.transport: ispf— read-only TN3270 panel scraping. Reads only; writes via this transport raiseNotImplementedError.
The default was flipped to jcl because every host we attempted
during build had FTP port 21 blocked. Restore the spec default by
setting dataset.transport: ftp in config.example.yaml once an
FTP-reachable target is verified.
14.3 ISPF panel-flavor support
The spec assumes IBM ISPF/PDF (ADCD z/OS 1.10) panel chrome. The
running code additionally detects Rocket RFE chrome (used by the
TK4-/TK5 MVS 3.8j distribution) via signature: see
_DSLIST_TITLE_MARKERS and _DSLIST_FIELD_LABELS in
core/ispf_dataset.py. Default ADCD code path is unchanged; RFE
support is purely additive.
Likewise core/session.py _drive_to_tso_logon_panel accepts either
the full TSO/E LOGON panel (z/OS) or a single-line ENTER CURRENT PASSWORD FOR <userid> prompt (base TSO, MVS 3.8j) as a password-ready
state.
These were added during troubleshooting against a TK5 instance that turned out to be the wrong target. They cost nothing to keep and make the plugin work against any reasonably modern MVS/z/OS host.
14.4 Extra modules not listed in §6
Path | Purpose |
| FTP/ISPF/JCL dispatcher with reachability probe + fallback |
| ISPF panel-based dataset reader (used by ispf/jcl transports) |
| TSO SUBMIT * + IEBGENER/IEBUPDTE + STATUS/OUTPUT/CANCEL primitives |
| Phase 4 orchestration: history dequeue + abend marking |
| Per-process abend lockout counter (split from |
|
|
| Process-wide singleton holding session, audit, tokens, jobs, git |
All implementation detail. None change tool behaviour or safety guarantees relative to the spec.
14.5 Extra tool not listed in §9
force_cleanup() is registered on both read and write servers. Drives
the robust-disconnect protocol to release a dangling host session and,
on failure, surfaces a one-line operator instruction for the Hercules
console MODIFY command. Added after a third reproduction of
IKJ56425I LOGON REJECTED IN USE during build.
14.6 Job status label naming
Phase 4 acceptance text says status returns "RUNNING" then "OUTPUT".
The running code returns the raw TSO STATUS command labels
(EXECUTING, ON OUTPUT QUEUE, ON INPUT QUEUE, ON HOLD QUEUE,
NOT FOUND, UNKNOWN). Functionally identical states; label strings
follow the host wire format rather than the README's prose. If
README-exact labels are required, alias them in JclWriter.status().
14.7 Extra root-level docs
PHASE3_READINESS.md— Phase 3 completion record (acceptance status, fixed bugs, live-verification result).LIVE_VERIFY_PORTABILITY.md— host-swap guide (code page, scope patterns, env vars).config.test-case9.yaml— TTL=1min config for the token-expiry acceptance case.
All explicitly user-requested during build. Consider moving under
docs/ to match the §6 layout in a future cleanup pass.
14.8 Write verification semantics (host state is ground truth)
The §5 safety model requires every applied write to leave an audit trail proving the host state changed. The implementation enforces this via a read-back probe after submit, not by trusting JES2 return codes. Design rationale:
ADCD z/OS 1.10 + JES2 aggressively purges job spool between job completion and the plugin's
OUTPUTretrieval command. The plugin frequently observesstatus=NOT FOUNDwith no parseable RC, even though the submitted utility step ran to completion.Trusting "RC=0 in spool → success" would let a purged-spool job falsely report failure. Trusting "no spool found → failure" would reject successful writes. Neither is the contract callers expect.
The fix: after every write submit,
member_exists()(a TSOLISTDS/ panel probe) checks the host directly. Member present after a create/edit → ✅ OK. Member absent after a delete → ✅ OK. Anything else → ❌ ERROR +git reset --hardto the pre-write SHA.
State table for the post-submit verify path:
JES outcome | Host probe | Tool returns |
RC = 0 | member present |
|
RC = 0 | member absent |
|
RC ≠ 0 | not consulted |
|
Abend (S0C7, U4038, …) | not consulted |
|
RC unparseable (spool purged) | member present |
|
RC unparseable (spool purged) | member absent |
|
RC unparseable | probe raises |
|
Implemented in tools/write_tools.py:_apply_change / _apply_delete /
confirm_change. Pinned by tests/test_write_verification.py (11
cases including all four spool/probe permutations). Live-verified on
ADCD: all three write cases (C/D/E) in the Phase 3 acceptance sweep
took the RC unparseable + member present → OK branch because ADCD's
JES2 purges before the OUTPUT retrieval. Reporting was correct in
every case.
This is the safety-critical contract: the plugin never reports a write succeeded without positive evidence the host state changed. Equally important, it never reports failure when the host state did change — that would force a retry that could double-apply the write.
14.9 Bootstrap residue (Phase 4 verify)
A second pattern observed during Phase 4 partial live verify: an
interrupted verification run can leave ADCDC.MCPTEST.SOURCE in an
inconsistent state — the dataset exists in the catalog but its
expected member set is empty (or partial). The Phase 4 verify script
treats "PDS exists" as "skip allocation, populate via IEBUPDTE
PARM=NEW", which then races against the JES2-purge cycle and yields
POST-SUBMIT VERIFY FAIL — missing: [...] even though the IEBUPDTE
job itself may have completed successfully.
Symptoms:
bootstrap_pdsreports "PDS already exists; skipping allocation."bootstrap_membersIEBUPDTE submit returnsrc=None abend=None(spool purged before retrieval).member_exists()ground-truth check shows all expected members absent.
Plugin behaviour is correct: the read-back verify refuses to
report success without positive evidence, exactly as §14.8 requires.
The fault is in the verify script's bootstrap path — cleanup_pds
is fire-and-forget (no RC verification), and the IEBUPDTE submit
doesn't tolerate "PDS exists but empty".
Mitigation (not implemented in v1.0.0 — tracked in §14.10):
Run-ID-suffixed PDS names (
ADCDC.MCPTEST.SOURCE.R20260527) so each verify run is hermetic.cleanup_pdsshould verify the dataset is actually scratched before returning.Bootstrap should detect "PDS exists but empty" and switch to IEBUPDTE PARM=MOD / REPL or scratch-and-reallocate before populating.
For now: manually delete ADCDC.MCPTEST.SOURCE (via wc3270 ISPF 3.4,
or by a console operator) between Phase 4 verify runs, or wait for
ADCD to reclaim it on its own.
14.10 Acknowledged future work
Tracked items not in v1.0.0 scope; none are correctness blockers, all are quality-of-life or completeness improvements for the live verification surface.
Item | Why |
Phase 4 live verify completion (11 remaining cases) | Requires uninterrupted ADCD login window. Plugin code is unit-tested for every case. |
Phase 5 live runbook ISPF banner case | Same — requires live host. The mechanism is offline-verified 23/23. |
| Currently fire-and-forget. Should poll the catalog post-submit to confirm scratch happened, mirroring the write-tools verify-via-read-back pattern. |
Run-ID-suffixed bootstrap PDS names | Eliminates §14.9 residue entirely. |
Idempotent bootstrap (PDS-exists-empty case) | Detect partial state, use IEBUPDTE PARM=MOD with |
Reconnect=S precise field positioning | The current 10-tab approach is fragile across panel variants. |
README §14.6 status-label normalization | Optional alias to map raw TSO STATUS labels to the README's prose ("RUNNING"/"OUTPUT") if README-exact wording is required. |
These are tracked here rather than as GitHub issues because this project is shipping as a personal/internal release and the issue tracker isn't in active use. Subsequent maintainers should promote these to issues if iteration continues.
Implementation kickoff checklist
Before Claude Code writes its first line, verify:
Phase 0 environment setup is complete and smoke test passes.
You've read this README in full once.
You understand the three-tier autonomy and read-only-by-default model.
You know the project name is
mainframe-mcpand the target is ADCD z/OS 1.10.You're working in
C:\mainframe-mcpwith.venvactivated.Git is initialized; first commit is this README +
.gitignore+LICENSE.
When all six are checked, begin Phase 1.
End of build specification.
Available Tools
26 toolsanalyze_screen_fieldsA
Return a per-row inventory of non-blank content on the current screen.
Heuristic only: returns each non-empty stripped line with its row number so the AI can locate input fields by neighboring labels.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden. It discloses that this is heuristic, operates on the current screen, and returns non-empty stripped lines with row numbers. The word 'Return' implies a read-only inspection, though it does not explicitly state that the screen is not modified.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The definition is compact and front-loaded. The first sentence gives the core purpose, and the second adds the heuristic caveat and intended usage without extra fluff. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter, read-only inspection tool with an output schema, this description is complete. It states what is returned, the heuristic nature, and why the AI would call it. No critical behavioral or contextual information is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are zero parameters, so there is nothing for the description to clarify. The baseline for no parameters is 4, and the description correctly adds no unnecessary parameter details.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource: 'Return a per-row inventory of non-blank content on the current screen.' This clearly distinguishes the tool from siblings like get_screen or find_text because it defines a unique result shape: per-row, non-blank, stripped content.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states the intended use: 'so the AI can locate input fields by neighboring labels.' It also warns 'Heuristic only', which sets expectations. However, it does not explicitly name alternatives or state when not to use this tool, so it stops short of full guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_for_errorsA
Scan the current screen for abend codes or error markers. Trips lockout if abend found.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It goes beyond a basic scan by explicitly revealing a meaningful side effect: 'Trips lockout if abend found.' This is valuable non-obvious behavior for an agent to know. It does not explain what lockout entails or what happens when no error is found, but the presence of an output schema partially covers return expectations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two short sentences with no wasted words. The primary action is front-loaded, and the critical lockout side effect immediately follows. Every sentence contributes essential information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter tool with an output schema present, the description is largely complete: it states what is scanned, what is detected, and the important lockout side effect. Minor ambiguities such as the exact meaning of 'lockout' or which specific error markers are recognized remain, but they do not seriously hinder correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so there are no parameter semantics for the description to clarify. The empty input schema leaves nothing ambiguous, and the description does not need to add parameter-level detail. The baseline of 4 for a zero-parameter tool applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb ('Scan') and a clear resource/scope: the current screen, looking for abend codes or error markers. It also adds a distinctive side effect, 'Trips lockout if abend found,' which clarifies the tool's special role. It does not explicitly distinguish itself from sibling tools such as find_text or analyze_screen_fields, but the purpose is still unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the tool should be used when the agent needs to detect abend codes or error markers on the current screen. However, it gives no explicit guidance about when to prefer this over siblings like find_text, get_text_at, analyze_screen_fields, or check_job, and it mentions no alternatives or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
check_jobA
Return the current JES state of a job.
States: ON INPUT QUEUE | EXECUTING | ON HOLD QUEUE |
ON OUTPUT QUEUE | NOT FOUND | UNKNOWN.
Args:
job_id: JES job id (e.g. JOB01234). The literal "last"
resolves to the most-recently-submitted id this session.
| Name | Required | Description | Default |
|---|---|---|---|
| job_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries full responsibility. It discloses that the tool queries current state, returns an exact set of possible states including NOT FOUND and UNKNOWN, and explains the 'last' resolution. It does not describe side effects (likely none), permissions, nor what happens on errors (e.g., if connection fails). But for a read-only status check, the state list and resolution semantics add transparency beyond the schema. It doesn't mention whether it disconnects or changes connection, but the sibling 'reconnect' and 'status' tools suggest connection state is separate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and efficient: a one-line purpose, a helpfully formatted state list, and a terse but sufficient parameter explanation. It front-loads the core purpose and immediately gives the actionable info (states and the 'last' special value). No wasted words; every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given one parameter, no annotations, a simple output schema (not shown but likely a state string or enum), and low schema coverage, the description provides enough for an agent to call correctly: it defines the parameter format, explains special 'last', and enumerates possible return values. However, it doesn't specify the output schema format (e.g., whether it returns a string or object) nor error handling for missing job id. But with only one param and the tool's simplicity, the gap is minor, so 4 is justified.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, and the schema only says 'job_id' is a string with no description. The description's argument section adds meaning: 'job_id: JES job id (e.g., JOB01234)', and clarifies the special literal 'last'. This adds meaning beyond the schema's bare property name. However, it doesn't specify format constraints beyond example, nor does it clarify if whitespace matters. Still, for a single param with clear naming, the description adequately compensates for low schema coverage.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states it returns the current JES state of a job, with a specific resource (job) and an enumeration of possible states. It distinguishes from siblings like list_my_jobs (which lists jobs) because it checks one job's status, not a list. However, it doesn't explicitly differentiate from potential job-status tools, but among the siblings, none check single job status except fetch_sysout, which is for output.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage: call when you need to know the state of a specific job, using its JES id. It defines special value 'last' for the most-recently-submitted job, which is helpful. However, it doesn't explicitly say when NOT to use it vs. alternatives like fetch_sysout (for output) or list_my_jobs (for finding IDs). The guidance is adequate but not explicit about alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
connectA
Open a TN3270 connection to the configured host. Idempotent.
Does NOT log in; call login(userid) afterwards.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description takes on the full burden and discloses two important behavioral traits: the operation is idempotent and it does not perform login. These go beyond the bare action and shape an agent's expectations about side effects and subsequent steps. It stops short of describing failure conditions or connection state changes, but for a zero-parameter connect tool the provided transparency is solid.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences, no filler. The core action is first, followed by essential qualifiers ('Idempotent') and the critical non-login warning plus next step. Every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter connectivity tool with an output schema, the description covers the key contextual facts an agent needs: what the tool does, that it is safe to repeat, and that authentication must happen separately. It is slightly incomplete in not addressing reconnect/disconnect lifecycle, but this is a minor gap given the tool's simplicity.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and the schema coverage is 100%, so there is no parameter meaning to add. Per the calibration baseline for no parameters, a score of 4 is appropriate; 'configured host' refers to static configuration, not a parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a concrete verb-resource pair: 'Open a TN3270 connection to the configured host', and immediately distinguishes itself from login by stating 'Does NOT log in'. This clearly separates connect from its siblings and makes its function unambiguous.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly instructs the agent to call `login(userid)` afterwards, establishing that connect is only the first step and not a substitute for authentication. It also signals through 'Idempotent' that repeated invocations are safe. It does not, however, contrast with closer siblings like reconnect, leaving some usage selection up to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
disconnectA
Close the TN3270 session cleanly.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It adds 'cleanly' as a behavioral qualifier, but does not disclose prerequisites (active session), side effects (what happens to pending data), or error behavior if no session exists. This is a minimal disclosure for a session-terminating operation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single front-loaded sentence with no filler. It is appropriately sized for a zero-parameter action, and every word contributes to the meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter action with an output schema, the description is mostly adequate, but it omits preconditions and does not contrast with force_cleanup or reconnect. It is not fully complete, though the low complexity keeps the gap from being severe.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and the description correctly adds no parameter information. The baseline for a zero-parameter tool is 4.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Close') and resource ('TN3270 session'), and 'cleanly' implies a graceful teardown that contrasts with the sibling force_cleanup. It is immediately clear what the tool does and how it differs from connect/reconnect/force_cleanup.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The only guidance is 'Close the TN3270 session cleanly,' which implies using it when the agent wants to end a session. It does not explicitly say when to prefer it over force_cleanup or whether it requires an active connection, so the usage context is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
fetch_sysoutA
Fetch a job's SYSOUT and surface RC + abend if present.
Detects abends inside the returned spool body and trips the abend
lockout the same way a screen-side check_for_errors would. The
spool is purged after fetch so the JES output queue stays clean.
Args:
job_id: JES job id, or "last" for the most recent.
ddname: Reserved for future per-DD filtering (requires SDSF; TSO
OUTPUT returns the union). Currently informational only.
| Name | Required | Description | Default |
|---|---|---|---|
| ddname | No | ALL | |
| job_id | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden. It discloses that the spool is purged after fetch, which is a critical side effect, and that abend detection triggers a lockout similar to check_for_errors. It also clarifies the ddname parameter's current informational nature. This is solid but does not cover every edge case like error handling for nonexistent jobs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is concise, around 120 words, with the core purpose front-loaded. It uses a clear structure: a one-sentence summary, then behavioral details, then an args list. Every sentence adds value with no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has a simple signature with one required param and an output schema (indicated but not shown). The description covers the main purpose, side effects, and parameters, which is sufficient for most use cases. However, it does not mention potential error conditions or prerequisites like requiring an active session, though these might be implied by the tool family. Minor gap.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 0%, so the description must explain parameters, and it does excellently. job_id is explained with the 'last' special value, and ddname is given context about its future use and current limitations. This fully compensates for the lack of schema descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'fetch' and resource 'SYSOUT', and adds the key outcome of surfacing RC and abend. It also mentions side effects (purge) which help differentiate from other tools like check_job. The purpose is unambiguous and specific.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage by mentioning detection of abends similar to check_for_errors, but it does not explicitly state when to prefer this tool over alternatives like check_job or list_my_jobs. There is no clear exclusionary guidance or conditional use case. The 'currently informational only' for ddname is a useful hint but not a full usage rule.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
find_textB
Return all (row, col) coordinates where the literal pattern appears on the current screen.
Args: pattern: Exact text to search for. Case-sensitive.
| Name | Required | Description | Default |
|---|---|---|---|
| pattern | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses meaningful behavioral details: searching is literal and case-sensitive, and it is scoped to the current screen. However, with no annotations, it remains silent on no-match behavior and whether any refresh or waiting occurs.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short, front-loaded, and free of fluff. The first sentence states the purpose, and the second documents the argument without repeating schema boilerplate.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter tool, it covers the required argument and the output shape. Its main gaps are the lack of sibling-routing guidance and missing edge-case behavior such as what happens when the pattern is not found.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema only defines pattern as a string, so the description's 'Exact text to search for. Case-sensitive.' adds real semantic value. This compensates for the 0% schema description coverage and makes the single parameter unambiguous.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a clear operation: 'Return all (row, col) coordinates where the literal pattern appears on the current screen.' The mention of coordinates and literal pattern gives it a distinct identity among siblings, though it does not explicitly name alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The only usage cue is 'current screen,' which implies a direct, non-waiting screen search. There is no guidance on when to prefer this over siblings like wait_for_text or get_text_at, and no exclusions or alternative conditions are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
force_cleanupA
Force-reset the host-side session for the configured userid.
Use when a prior dirty disconnect (or external session) is holding the userid as "IN USE" and blocking new logons. Steps:
Drive the current TN3270 session through the robust logoff protocol (navigate to READY then LOGOFF).
If still dirty, surface a one-line operator instruction for the Hercules console MODIFY command which always works:
/F TSO,USER=<userid>,LOGOFF.
Returns a single-line status that the AI can echo verbatim.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full burden of behavioral disclosure. It details the two-step process (robust logoff, then operator instruction) and states the output ('Returns a single-line status'). It does not explicitly warn about side effects or risks, but the destructive nature is implied and the steps are transparent enough.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the purpose, uses a clear numbered step structure, and each sentence contributes meaning (purpose, condition, steps, output). It is concise without being terse, and every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the zero-parameter tool, an output schema (if present) would handle return details, and the description already mentions the return format. It covers when to use, the process, and expected output. Combined with the sibling context, an agent has all information needed to select and invoke the tool correctly. No gaps are evident.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the schema coverage is 100% trivially. Baseline for 0 params is 4. The description references a 'configured userid' but that is a config context, not a parameter, so no parameter-specific semantics are needed. The description adds no import because there are no parameters to explain.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening line 'Force-reset the host-side session for the configured userid' names a specific verb (force-reset) and resource (host-side session) and ties it to a specific scenario ('holding the userid as IN USE'), clearly distinguishing it from siblings like reconnect or disconnect.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly states when to use: 'Use when a prior dirty disconnect (or external session) is holding the userid as "IN USE" and blocking new logons.' This is a precise trigger condition, though it does not explicitly mention alternatives or when not to use; the condition is specific enough to route correctly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_dataset_infoA
Return DCB attributes (RECFM, LRECL, BLKSIZE, DSORG, volume) for a dataset.
Args: dataset: Fully-qualified dataset name.
| Name | Required | Description | Default |
|---|---|---|---|
| dataset | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden. 'Return' indicates a read-only operation and the exact output fields are listed, which is transparent. However, it does not disclose prerequisites, error behavior, or whether an active connection is required, leaving some behavioral gaps.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is minimal and front-loaded: one sentence states the purpose and exact output, followed by a single-line parameter explanation. Every element earns its place with no redundant wording.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with one required parameter, no nested objects, and an output schema present, the description covers purpose and parameter adequately. The main missing element is usage guidance, but the simple read-only nature of the tool makes the description mostly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema only defines 'dataset' as a string with no description, while the description's Args section adds meaningful semantics: 'Fully-qualified dataset name'. This compensates for the 0% schema coverage, though it could include an example or naming convention for full clarity.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Return') and resource ('DCB attributes') for a single dataset, enumerating exact attributes (RECFM, LRECL, BLKSIZE, DSORG, volume). This clearly distinguishes it from sibling tools like list_datasets or read_member, which operate on dataset lists or member content.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit guidance is given about when to use this tool versus siblings such as list_datasets or read_member. The purpose is implied by the description, but there are no usage conditions, exclusions, or alternative-selection heuristics.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_screenA
Return the current 3270 screen, row-numbered (24 rows x 80 cols).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the behavioral disclosure burden. It transparently states that this is a read operation returning the current screen and discloses the row-numbered 24x80 format. However, it does not mention whether the call waits for screen stability, how connection failures are handled, or whether the snapshot is immediate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no filler. It states the action, object, and output format efficiently, earning its place entirely.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool is simple, has no parameters, and has an output schema, so the return shape is covered. However, given the large sibling set of screen-related tools, the absence of any guidance on when to choose get_screen over alternatives leaves the description slightly incomplete for correct tool selection.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters and the schema covers 100% of them (empty properties). The baseline for no parameters is 4; the description adds no parameter details because none are needed. Nothing is left undocumented.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Return'), names the resource ('current 3270 screen'), and specifies the format ('row-numbered, 24 rows x 80 cols'). This clearly distinguishes it from sibling screen tools like find_text or get_text_at, which operate on content rather than returning the full screen.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is given on when to use this tool versus alternatives such as wait_for_screen_change, identify_screen, or get_text_at. The description implies it is for retrieving the full current screen, but it does not state exclusions or recommend sibling tools for other screen-related tasks.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_text_atA
Return text at a specific screen position.
Args: row: 1-based row index (1-24). col: 1-based column index (1-80). length: Number of characters to read.
| Name | Required | Description | Default |
|---|---|---|---|
| col | Yes | ||
| row | Yes | ||
| length | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. 'Return' implies a read-only operation, and the coordinate ranges (1-24, 1-80) give some screen size context. However, it doesn't disclose what happens on out-of-range inputs, whether it returns an empty string for blank areas, or explicitly state that it has no side effects.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and well-structured: a single clear purpose sentence followed by a bullet-like Args block. Each parameter line adds specific meaning without redundancy or fluff, and the key purpose is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool has an output schema, return type details are covered elsewhere. The description supplies enough for correct invocation: coordinate ranges, character count, and the default of 80. It doesn't address when to choose this over siblings, but that gap is more about usage guidelines than operational completeness.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With schema description coverage at 0%, the description provides essential semantics: row and col are 1-based with valid ranges, and length is the number of characters to read. This fully compensates for the barren schema. The default length of 80 is only in the schema, but the description still clarifies each parameter's purpose.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence 'Return text at a specific screen position' clearly states a specific verb and resource, making the core function obvious. It differentiates from siblings like get_screen or find_text by emphasizing location-based reading, though it doesn't explicitly name an alternative.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives no indication of when to use this tool versus alternatives such as get_screen, find_text, or analyze_screen_fields. There is no mention of context, prerequisites, or exclusions, leaving the agent to infer appropriate usage from the tool name alone.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
identify_screenA
Identify the current screen against known signatures.
Returns a screen_id like TSO_READY, ISPF_PRIMARY, ISPF_DSLIST, ISPF_EDIT, SDSF_HOME, or UNKNOWN.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden. It discloses that the tool matches against known signatures and returns screen_id values including UNKNOWN, which clarifies the non-mutating classification behavior. It does not explicitly state that it performs no writes or describe error/prerequisite behavior, but the verb and return values imply read-only analysis.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences: one purpose statement and one output-format line with helpful examples. No filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter tool with an output schema, the description is nearly complete: it gives the action, the mechanism, and example outputs. A small gap is that it does not mention whether an active connection is required or that no screen mutation occurs, but the simple tool shape makes this minor.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters in the input schema, so there is nothing to document. The description's list of example screen_id values adds semantic context even though no parameters exist.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (identify), a resource (current screen), and a concrete output (screen_id from known signatures, with example values). This distinguishes it from sibling tools like get_screen, which would return raw screen content rather than a classification.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies the use case: call this when you need to know which screen you are on. However, it does not explicitly state when to prefer it over siblings such as get_screen or analyze_screen_fields, nor does it provide exclusion criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_datasetsA
List MVS datasets whose name matches pattern (e.g. ADCDC.*).
Uses ISPF 3.4 or z/OS FTP depending on config.dataset.transport. With
the ISPF transport, the TN3270 session must already be logged in.
Args:
pattern: Fully-qualified dataset name with wildcards (* matches any qualifier).
| Name | Required | Description | Default |
|---|---|---|---|
| pattern | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description bears the full burden. It discloses the underlying transport (ISPF vs FTP) and the login requirement for ISPF, which are meaningful behavioral details. It does not discuss rate limits or error handling, but for a read-only list operation, this level of transparency is sufficient. The output schema likely covers return values, so no need to duplicate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and well-organized: a one-sentence purpose, a brief usage note about transport and login, and a clear Args definition. Every sentence earns its place, with the most critical information (matching pattern) front-loaded. No filler or redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter list operation with an output schema, the description covers the essential aspects: what it lists, how to specify the pattern, and the operational prerequisites. It doesn't mention potential limitations (e.g., case sensitivity, session state for FTP), but these are minor and the core usage is fully explained.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema itself has zero description coverage for the single 'pattern' parameter, but the description's Args section fully compensates: 'Fully-qualified dataset name with wildcards (``*`` matches any qualifier)'. This adds precise semantics that the schema lacks, including wildcard syntax and qualification format, making it easy for an agent to construct valid inputs.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action: 'List MVS datasets whose name matches pattern' – a specific verb and resource. It also distinguishes from siblings like list_members (which lists members within a dataset) and get_dataset_info (which fetches info on a single dataset), leaving no ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explains the transport mechanism (ISPF 3.4 or z/OS FTP) and the prerequisite that the TN3270 session must be logged in when using ISPF. This gives clear context on when the tool is usable. It doesn't explicitly mention alternatives or when not to use it, but the prerequisites and transport choice serve as adequate guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_membersB
List members of a PDS (e.g. ADCDC.SOURCE.COBOL).
Args:
pds: PDS dataset name without trailing (*).
| Name | Required | Description | Default |
|---|---|---|---|
| pds | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It discloses the input format constraint (no trailing (*)) but doesn't mention what the output looks like, whether it requires a connection, or any side effects. For a read-only listing tool, this is a moderate gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely concise, with a clear example and a single important constraint. Every sentence earns its place, and the key usage note is front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple one-parameter tool with an output schema, the description is mostly adequate. It covers the essential input format. However, it doesn't mention whether a connection must be active, what happens with invalid PDS names, or how the output is structured, which an agent might need to know for error handling.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. It does explain the pds parameter meaning and format, which adds value beyond the bare schema. However, it doesn't provide examples of valid values beyond the one example or clarify edge cases like quoted vs unquoted names.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool lists members of a PDS and gives a concrete example. It is distinct from siblings like list_datasets and read_member, though it doesn't explicitly differentiate itself.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage by specifying the input format (PDS name without trailing (*)), but it doesn't state when to use this tool versus alternatives like list_datasets or read_member. The context is clear enough for a simple tool, but no explicit exclusions or alternatives are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_my_jobsA
List jobs owned by the current userid (TSO STATUS with no jobid).
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the behavioral transparency burden. The verb 'List' clearly signals a read-only, non-mutating operation, and the parenthetical TSO STATUS comparison adds precise behavioral context about what is returned. It could go further by noting there are no side effects or prerequisites, but for a zero-parameter read tool this is largely sufficient.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, tightly worded sentence with no filler. It front-loads the core purpose and adds the TSO comparison as a useful parenthetical without bloating the text.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter list operation with an output schema present, the description is complete. It tells the agent what is listed, whose jobs are included, and the mainframe command it corresponds to, which is enough to select and invoke the tool correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are zero parameters, so the baseline is 4; there is nothing the description needs to add beyond the empty schema. The description also indirectly clarifies why no jobid is needed by referencing TSO STATUS with no jobid.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('List') and a clear resource ('jobs owned by the current userid'), and the TSO STATUS comparison clarifies exactly what the tool does. This distinguishes it from sibling tools like check_job (a single job) and list_datasets/list_members (different resource types).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description establishes clear scope: it lists only the current user's jobs, equivalent to TSO STATUS with no jobid. However, it does not explicitly name alternative tools or state when to prefer this over check_job or fetch_sysout; usage timing is implied rather than directly guided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
loginA
Log in to TSO as userid. Password is fetched from the OS keychain.
Set the password once via scripts/set_password.py before calling this.
Args: userid: RACF userid.
| Name | Required | Description | Default |
|---|---|---|---|
| userid | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description must disclose behavior on its own. It usefully explains that the password is fetched from the OS keychain and must be set once beforehand, which is valuable context. However, it does not describe side effects such as session creation, failure behavior, or whether an existing connection is required.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is short and front-loaded: the first sentence states the action, the second explains authentication behavior, and the third gives the prerequisite. Every sentence contributes value with no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter login tool, the description covers purpose, authentication source, and setup, and an output schema exists. However, it omits whether a prior connection is required, how it interacts with the sibling connect/disconnect tools, and what happens on login failure. These gaps matter in an environment with connection-management siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema has 0% description coverage, so the description must compensate. It does add meaning by defining userid as a RACF userid, but it provides no additional format, validation, or usage details beyond that single label. This is minimal but non-redundant.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Log in to TSO') and the target resource (TSO) with the userid parameter. It does not explicitly distinguish itself from the sibling tool 'connect', which could be a related but different operation, so it stops short of a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives a clear prerequisite ('Set the password once via scripts/set_password.py before calling this') and implies when to use the tool, but it does not discuss when not to use it or how it compares with siblings like connect, reconnect, or status. This is adequate but not explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
read_memberA
Read a PDS member as text.
Args:
pds_member: PDS.NAME(MEMBER) form.
| Name | Required | Description | Default |
|---|---|---|---|
| pds_member | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the disclosure burden. It communicates that the operation is a read and returns text, but does not mention behavior on missing members, encoding, or any preconditions like an active connection. 'Read' implies no mutation, though the description does not explicitly confirm side-effect-free behavior.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two purposeful lines with no filler. The core behavior is front-loaded, and the Args section directly supports the only parameter.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter read operation, the description covers the essential input format and purpose, and an output schema exists so return-value details need not be repeated. It does not mention prerequisites such as an established connection or what happens when the member does not exist, but these are minor for such a simple tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must supply parameter meaning. It does so by specifying the expected PDS.NAME(MEMBER) form for pds_member, which is essential and not present in the schema. It stops short of giving examples or formatting details, but the single-parameter case is well addressed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Read') and resource ('PDS member') and clarifies the output format ('as text'), making the tool's purpose unambiguous. This also differentiates it from sibling tools like list_members and list_datasets, which operate on collections rather than a single member's contents.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The purpose statement implies when to use the tool: when the contents of one PDS member are needed as text. However, it does not explicitly state when not to use it or name alternatives such as list_members for discovering members, leaving usage context to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
reconnectB
Force a disconnect + reconnect. Re-logs in if a userid was previously set.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions the force disconnect and re-login behavior, but does not disclose potential side effects (e.g., interrupting ongoing operations, requiring authentication, failure modes, or what happens if no userid was set). This is a significant gap for a session-management tool that could affect system state.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single concise sentence that immediately conveys the core action and a key conditional behavior. It is front-loaded and contains no extraneous information. Efficient and well-structured.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
While the output schema exists (which covers return values), the description lacks important contextual details such as prerequisites, side effects, and typical use cases. Given the sibling set includes connect, login, and disconnect, the tool's role as a combined reset is implied but not fully explained. The description is adequate for a trivial tool but misses opportunities to clarify when to use it.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, and the schema is empty. The baseline for 0 params is 4, as no parameter explanation is needed. The description adds behavioral context beyond the schema, which is appropriate. There is no parameter-related ambiguity.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool's action: 'Force a disconnect + reconnect.' It also adds a specific behavior about re-logging in if a userid was previously set. This distinguishes it from plain connect or disconnect siblings, though it doesn't explicitly name them. It is specific enough for an agent to understand the primary function.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives like calling disconnect followed by connect. It does not mention prerequisites, scenarios where this is preferred, or when it should be avoided. The 'Force' hint implies a reset, but the lack of explicit usage context leaves the agent to infer.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_clearA
Send the CLEAR AID key. Returns the resulting screen.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the full behavioral burden. It states the action and that the tool returns the resulting screen, which is useful, but it does not explain what the CLEAR AID key does (e.g., cleans the current screen) or any side effects, timeouts, or error behavior. This is minimum viable transparency for a zero-parameter key-send tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single front-loaded sentence with no filler. The action verb comes first and the return behavior second; every word carries meaning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-argument tool with an output schema present, the description conveys the essential purpose and return behavior. It could be slightly more complete by explaining when CLEAR is useful versus other AID keys, but nothing needed to invoke the tool correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema has zero parameters stub, and description coverage is 100%, so there is no parameter information missing from either source. With no parameters to document, the baseline of 4 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb ('Send') and resource ('the CLEAR AID key'), and adds the return behavior ('Returns the resulting screen'). This is clearer than the tool name alone, though it does not explicitly contrast with sibling key-sending tools like send_keys, send_pf, or send_pa.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to choose send_clear over sibling key-sending tools, nor any mention of prerequisites or when not to use it. The only implied context is 'when you need to press CLEAR,' which is not enough to differentiate usage.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_enterA
Send the ENTER AID key. Returns the resulting screen.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does a good job: it states the primary action and the outcome ('Returns the resulting screen'). This goes beyond the name by confirming the tool both sends the key and waits for/returns the updated screen state.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single, front-loaded sentence containing exactly two pieces of information: what is sent and what is returned. There is no filler, repetition, or ambiguity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a parameterless action with an output schema, the description covers the essential call semantics — the specific key and the response. It doesn't mention preconditions like an active connection, but that is plausibly handled by the broader tool set and the simplicity of the operation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema is empty, and the parameter count is 0, so there are no parameters to describe. The baseline for 0 params is 4, and the description adds no unnecessary parameter detail.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Identifies the exact action (send the ENTER AID key) and specifies the resource (the ENTER AID key), clearly differentiating it from siblings like send_pf, send_pa, and send_clear. Also states the resulting action returns the screen, which adds operational clarity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance on when to use this tool instead of alternatives such as send_pf or send_keys. The context of the tool is implied by the name, but the description does not provide explicit when-to-use or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_keysA
Type text into the current input field at the cursor position. Does NOT submit.
Use send_enter / send_pf afterwards to submit. Do NOT use for passwords; the login tool fetches them from the OS keychain.
Args: text: Characters to type.
| Name | Required | Description | Default |
|---|---|---|---|
| text | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and it discloses key non-obvious behaviors: it does not submit, and it should not be used for passwords. This goes beyond the schema. However, it omits edge cases like what happens if no input field is focused, so it is not fully exhaustive but still strong.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact: three sentences covering purpose, non-submit behavior, and usage guidance, plus a one-line args description. Every sentence adds essential information, and the key behavioral points are front-loaded.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The tool has an output schema, so return values are covered elsewhere. The description fully explains the tool's action and its place in the workflow (followed by send_enter/send_pf). It could mention error conditions or behavior without a focused field, but for a simple single-parameter typing tool, this is nearly complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate. The 'text' parameter is described only as 'Characters to type,' which is minimal but does convey its purpose. It lacks details about formatting, encoding, or special keys, but given the parameter's simplicity, this is adequate yet not rich.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description explicitly states 'Type text into the current input field at the cursor position' with a specific verb and resource, and immediately clarifies 'Does NOT submit.' This clearly distinguishes it from sibling tools like send_enter and send_pf, leaving no ambiguity about its function.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It provides direct instructions: 'Use send_enter / send_pf afterwards to submit' and explicitly warns 'Do NOT use for passwords; the login tool fetches them from the OS keychain.' This gives clear when-to-use and when-not-to-use guidance with specific alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_paB
Send a PA key (1-3). Returns the resulting screen.
Args: number: PA key number (1-3).
| Name | Required | Description | Default |
|---|---|---|---|
| number | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the behavioral burden. It usefully discloses that the tool 'Returns the resulting screen' and that the key number is 1-3. It does not mention attention-key semantics or potential side effects, but for a simple one-parameter send action this is minimally adequate.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact and front-loaded: the action and parameter range appear immediately, and the Args section is clear. Every sentence contributes meaning, with no filler or repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple tool with one parameter and an output schema, the description covers the core details: what is sent, the allowed range, and the return value. However, given the sibling context with send_pf, send_enter, and send_keys, an agent still lacks enough guidance to confidently choose send_pa over the alternatives.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 0%, so the description must compensate, and it does: it defines 'number' as 'PA key number (1-3),' adding a valid range and domain meaning beyond the bare integer schema. This is sufficient for an agent to invoke the tool correctly.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a clear verb and resource: 'Send a PA key (1-3).' This is specific and intelligible. It does not explicitly differentiate from sibling tools like send_pf, send_enter, or send_keys, though the term 'PA key' provides some inherent distinction.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance about when to use send_pa versus the many related send_* tools. The description implies usage only by naming the action, but it does not explain when a PA key is appropriate, when not to use it, or how it differs from PF/Enter/Clear keys.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
send_pfC
Send a PF key (1-24). Returns the resulting screen.
Args: number: PF key number (1-24).
| Name | Required | Description | Default |
|---|---|---|---|
| number | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are present, so the description carries full responsibility for behavioral disclosure. It only states that it sends a PF key and returns the resulting screen. It omits details about synchronization, error handling, connection prerequisites, or side effects beyond the screen change.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is very short and front-loaded with the core action and return value, which is efficient. However, it is under-specified rather than concise in a helpful way, lacking any additional context that would justify its brevity.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity and the existence of an output schema, the description covers the basic function but misses important context such as when to use it (e.g., for mainframe navigation), whether a connection must be active, and how it differs from related tools. It is adequate for a trivial tool but not fully complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema provides a required integer 'number' with no description (0% schema coverage). The tool description adds the range '1-24' and clarifies it is a PF key number, which is some added meaning, but it does not explain the semantics of PF keys, valid ranges, or out-of-range behavior. The compensation is minimal.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the verb 'Send' and the resource 'PF key' with a numeric range (1-24), and notes the return value is the resulting screen. It is specific enough to distinguish from siblings like send_enter or send_pa by the tool name and the PF key focus, though it does not explicitly contrast them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to use this tool versus alternatives such as send_keys or send_pa. The intended usage is only implied by the tool name and description; no exclusions or contextual cues are provided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
statusA
Return a one-line status: host, connected flag, userid, mode.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It does imply a read-only operation by saying 'Return a one-line status', which suggests no side effects. However, it doesn't explicitly state that it's safe, nor does it disclose any potential errors or network dependencies. For a simple status check, this is adequate but not rich.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single sentence, concise and front-loaded with the action and key fields. It wastes no words and is appropriately sized for a simple status tool. Every word adds value.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the tool's simplicity, the description is complete. It lists the returned fields, and since an output schema exists, the description doesn't need to elaborate on return formats. It could optionally clarify what 'mode' refers to, but that's likely covered in the schema. Overall, an agent has enough to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool has zero parameters, so the schema coverage is effectively 100%. The description doesn't need to explain parameters. It does add context about the output fields, but that's not parameter semantics. Baseline is 4 for zero-parameter tools, and the description is sufficient.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool returns a one-line status with specific fields (host, connected flag, userid, mode). It uses a specific verb ('Return') and resource ('status'), making the purpose unambiguous. It doesn't explicitly name a sibling tool, but among the siblings (connect, disconnect, get_screen, etc.), none duplicate this exact function, so it's adequately distinguishable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description provides no guidance on when to use this tool versus alternatives. It doesn't mention any prerequisites, typical scenarios, or exclusions. For example, it doesn't indicate whether this should be used before or after connection, or how it relates to 'connect' or 'login'. This is a clear gap.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_for_screen_changeB
Block until the screen changes from its last observed state, or timeout elapses.
Args: timeout: Seconds to wait. Default 10.
| Name | Required | Description | Default |
|---|---|---|---|
| timeout | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries the behavioral burden. It usefully discloses that the tool blocks and that a timeout can end the wait, but it does not clarify what happens on timeout, whether the 'last observed state' persists across calls, or what is returned after the screen changes.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is extremely compact and front-loaded with the core behavior. The Args section is minimal but sufficient for the single parameter, and every sentence contributes useful information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter tool with an output schema, the description covers the main entry point: what it waits for and how long. However, it leaves ambiguity around the meaning of 'last observed state,' which is essential context for an agent to know when the tool can be called and what it compares against.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The schema only provides the parameter name, type, and default, while the description adds the semantic meaning 'Seconds to wait.' This compensates for the 0% schema description coverage by clearly defining the unit and purpose of the timeout parameter.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies a specific operation: blocking execution until the screen changes from its last observed state or a timeout elapses. It is distinct enough from siblings like wait_for_text, though it does not explicitly differentiate itself from any named alternative.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance about when to use this tool versus alternatives like wait_for_text, get_screen, or check_for_errors. The description explains what the tool does but not the situations that call for it or when it should be avoided.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
wait_for_textB
Block until pattern appears anywhere on screen or timeout elapses.
Args: pattern: Literal text to wait for (case-insensitive). timeout: Seconds to wait. Default 10.
| Name | Required | Description | Default |
|---|---|---|---|
| pattern | Yes | ||
| timeout | No |
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden. It discloses blocking until match-or-timeout, case-insensitive matching, and screen-wide scope, but it does not state timeout semantics (e.g., success/failure/exception), leaving a gap.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Extremely concise: the core behavior is front-loaded, followed by a two-item arg list. Every line adds useful information without repetition.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple two-parameter wait tool, the essential call contract is covered and the output schema likely handles return values. However, missing guidance on alternatives and timeout/error behavior, combined with no annotation coverage, leaves some autonomy gaps.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Adds meaningful semantics beyond the raw schema: pattern is 'literal text' and case-insensitive, timeout is 'seconds to wait' with a default. With 0% schema coverage, this compensation is valuable, though no timeout range or validation rules are given.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific blocking-wait operation on a literal pattern anywhere on screen with a timeout. The 'block until' phrasing and 'anywhere on screen' scope distinguish it from search-style siblings like find_text, but it never names alternatives explicitly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit when-to-use, prerequisites, or alternative routing is provided. An agent must infer that this is for waiting rather than immediate lookup; siblings like find_text and wait_for_screen_change are never referenced.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
26 tool updates
v0.1.0- First observed
analyze_screen_fields - First observed
check_for_errors - First observed
check_job - First observed
connect - First observed
disconnect - First observed
fetch_sysout - First observed
find_text - First observed
force_cleanup - First observed
get_dataset_info - First observed
get_screen - First observed
get_text_at - First observed
identify_screen - First observed
list_datasets - First observed
list_members - First observed
list_my_jobs - First observed
login - First observed
read_member - First observed
reconnect - First observed
send_clear - First observed
send_enter - First observed
send_keys - First observed
send_pa - First observed
send_pf - First observed
status - First observed
wait_for_screen_change - First observed
wait_for_text
TDQS
Scored across 26 tools
Each tool targets a distinct action or resource: session management, screen inspection, screen input, dataset retrieval, and job monitoring all have specific tools with clear boundaries. Even similar helpers like find_text and wait_for_text are differentiated by intent (scan vs wait), preventing confusion.
The majority of tool names follow a consistent snake_case verb-first pattern (list_datasets, get_screen, check_job). Minor deviations like 'status' (a noun rather than get_status) and 'reconnect' (no underscore) are acceptable and do not obscure meaning.
26 tools is slightly above the typical comfortable range, but the complexity of mainframe interaction justifies a large set covering session control, screen access, and specific operations. Still, some tools like send_clear and send_enter could potentially be consolidated, making it feel a bit heavy.
The tool set covers read-oriented workflows well (listing members, reading datasets, checking jobs, fetching SYSOUT), but lacks write operations such as dataset creation/update, job submission, or file upload. This leaves notable gaps for any workflow requiring modifications rather than just inspection.
Maintenance
Related MCP Connectors
Governed app access for AI agents: 1,000+ apps & 12,000+ tools via Code Mode MCP.
Your apps, skills, MCP servers and keys from ahel.ai, served to Claude, ChatGPT, Cursor and Codex.
Claude Code / MCP skills for the dev pipeline: discover, spec, design, build, ship, operate.
Use AI models for chat, image, and video generation from Claude Code and other MCP hosts.
Related MCP Servers
- AlicenseBqualityDmaintenanceEnables interaction with z/OS mainframe systems via FTP, including dataset listing/download/upload, JCL job submission and monitoring, with advanced text processing and pagination support.81MIT
- AlicenseAqualityCmaintenanceEnables Claude to connect to servers via SSH, execute commands, transfer files, and manage connections through natural language.98 npm1MIT
- AlicenseNot gradedqualityDmaintenanceEnables Claude Code to interact with network devices over serial and SSH with command safety classification and a persistent knowledge base.MIT
- AlicenseNot gradedqualityDmaintenanceProvides safe, structured access to an IBM z/OS mainframe through natural language in Claude Code, enabling screen reading, dataset browsing, code editing, job submission, and regression testing.1MIT