Skip to main content
Glama

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 mcp package 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-3-live-verified)

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:

  1. Re-read the relevant phase section in full before writing any code.

  2. 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.

  3. Follow the file structure under "Project Structure" exactly. New files go where this document says they go.

  4. Match the tool signatures in the "Tool Surface Specification" section. Tool names, parameters, return types, and module assignments are fixed.

  5. At the end of each phase, run the acceptance criteria checklist. Do not move to the next phase until the current one passes.

  6. 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

  2. Target environment

  3. Tech stack

  4. Architecture

  5. Safety model

  6. Project structure

  7. Configuration

  8. Implementation phases

  9. Tool surface specification

  10. Coding conventions

  11. Testing and verification

  12. Distribution

  13. Appendices


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 PAY001 and 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

  1. Read — screens, PDS members, datasets, job output. (Phase 1–2)

  2. Write — edit existing members, create new ones, with Git versioning. (Phase 3)

  3. Audit — analyze code for issues, propose fixes via three-tier autonomy. (Phase 3, refined later)

  4. Submit & monitor — JCL submission, job status, SYSOUT retrieval. (Phase 4)

  5. Navigate — keyboard-only ISPF/CICS navigation through Claude's instruction. (Phase 1+)

  6. 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

147.93.154.32 (public learning instance)

TN3270 port

23 (plain — no TLS available)

Authentication

Plain RACF userid/password

Default test user

ADCDB / TEST (publicly documented defaults)

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

C:\mainframe-mcp

Virtual environment

.venv inside the working directory

3270 client

wc3270 (Windows distribution of x3270) — provides s3270.exe

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.

  • p3270 over py3270: py3270 has not been updated in over a year and is effectively unmaintained. p3270 is actively maintained, has a cleaner API, and wraps the same s3270 binary.


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, logging

System requirements

  • s3270.exe (from wc3270) on PATH

  • git on PATH

  • Node.js + @anthropic-ai/claude-code for the AI client

Why each dependency

Dependency

Purpose

Alternatives considered

mcp

MCP protocol implementation

fastmcp standalone — rejected, extra dep with no benefit for this scope

p3270

TN3270 client

py3270 (unmaintained), robotframework-mainframe3270 (kept as Phase 5 option for full test scripts)

keyring

Credential storage

.env file (rejected — secrets in plaintext)

pyyaml

Config

TOML (acceptable alternative, YAML chosen for familiarity)

ftplib (stdlib)

File transfer to z/OS

Zowe CLI (not available without z/OSMF)

sqlite3 (stdlib)

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 when MAINFRAME_MODE=WRITE is set. Modifies PDS members, submits jobs, deletes things. All operations gated by safety rules.

  • mainframe-test — loaded only when MAINFRAME_MODE=TEST is set. Captures baselines, runs test scripts, compares results.

Why three instead of one:

  1. The write tools literally do not exist in the read server, so they cannot be called by accident.

  2. Different sessions can run different modes (read-only by default, write only when intentional).

  3. 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 proposals/ and returns a summary. No mainframe write happens. User applies manually if desired.

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)

  1. Read-only by default. The write server only loads when MAINFRAME_MODE=WRITE is explicitly set AND the --allow-writes flag is passed at startup.

  2. Dataset scope is enforced. Any write tool calls permissions.check_write_allowed(dataset) as its first line. If the dataset matches any pattern in scope.forbidden_patterns or doesn't match any in scope.allowed_datasets, the tool raises PermissionDenied and refuses.

  3. Sensitive patterns are read-only forever. Patterns like SYS1.*, *.LINKLIB, *.PROD.* (configurable) cannot be written to even in write mode.

  4. 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.

  5. 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.)

  6. Audit log every tool call. Every invocation of any tool — read or write — writes a row to logs/audit.sqlite with timestamp, userid, tool name, arguments (passwords redacted), and outcome.

  7. Rate limits. Default 60 tool calls per minute, configurable. Excess calls block until the window clears.

  8. 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 PermissionDenied or RequiresConfirmation.


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 / contribute

7. Configuration

Sources of truth, in priority order

  1. Command-line flags (highest priority)

  2. Environment variables

  3. config.yaml in working directory

  4. Built-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

MAINFRAME_HOST

Override mainframe.host

No

MAINFRAME_USERID

RACF userid for this session

Yes

MAINFRAME_MODE

READ | WRITE | TEST

No (defaults to READ)

MAINFRAME_CONFIG

Path to config.yaml

No (defaults to ./config.yaml)

MAINFRAME_DEBUG

0 | 1

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 USERID

The 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 and tests/test_jcl_writer.py userid 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. ADCDCADCDCH. 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.exe to be installed and verified by user

  • Network reach to 147.93.154.32:23 confirmed via VISTA emulator

  • Claude 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:

  1. Project skeleton. Create directory structure under src/mainframe_mcp/ exactly as specified in section 6. Empty __init__.py files where needed.

  2. pyproject.toml with declared dependencies.

  3. config.py — load YAML, layer env vars, expose typed config object.

  4. 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
    );
  5. core/session.pyMainframeSession class wrapping p3270.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.

  6. core/screen_parser.pyformat_screen() returns row-numbered text matching hack3270's {i+1:2}| {line} format; identify_screen() checks for known signatures and returns a screen ID.

  7. safety/abend.py — list of abend codes (S0C7, S0C4, ASRA, AICA, AEY7, APCT, ASRB, AEXL, DFHAC2, ABEND, plus generic Sxxx and Uxxxx patterns). Function detect_abend(screen_text) -> Optional[str].

  8. safety/rate_limiter.py — token-bucket implementation, blocking variant.

  9. tools/screen_tools.pyget_screen, find_text, get_text_at, analyze_screen_fields, check_for_errors.

  10. tools/nav_tools.pysend_enter, send_pf (1-24), send_pa (1-3), send_clear, send_keys, wait_for_text, wait_for_screen_change.

  11. servers/read_server.pyFastMCP("mainframe-read", instructions=...). Register all read + nav tools. Define _ensure_connected() helper that wraps every tool. Include connect, login, disconnect, status as session-management tools.

Acceptance criteria:

  • claude mcp add mainframe-read -- python -m mainframe_mcp.servers.read_server succeeds.

  • In Claude Code, asking "connect to the mainframe as ADCDB and tell me what's on the screen" results in Claude calling connect, login, then get_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.sqlite contains 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

ispf (default)

Any reachable host; works against the public ADCD instance

Slower, scrapes ISPF 3.4 and View panels via TN3270, brittle to ISPF panel changes

ftp

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:

  1. core/ftp_client.pyMainframeFTP class:

    • 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.

  2. core/ispf_dataset.pyIspfDatasetAdapter exposing the same surface via ISPF 3.4 navigation and View-panel scraping. Reuses the existing MainframeSession.

  3. core/dataset_transport.pyDatasetDispatcher resolves the active backend on first use, performs the FTP reachability probe, and applies the fallback policy.

  4. tools/dataset_tools.pylist_datasets, list_members, read_member, get_dataset_info. All read-only; no scope restrictions on reads.

  5. 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: ftp against a host with port 21 open, the same prompts work via FTP.

  • With transport: ftp against a host with port 21 closed and fallback_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:

  1. safety/permissions.pycheck_write_allowed(dataset) -> None | raise PermissionDenied. Matches against scope.allowed_datasets, scope.forbidden_patterns, scope.read_only_patterns. Tested exhaustively.

  2. safety/classifier.pyclassify_change(target, change_type, diff) -> Tier. Returns one of AUTO, CONFIRM, SUGGEST. Initial rules:

    • SUGGEST if target matches any pattern in safety.suggest_only_patterns (configurable list including security exits, audit logging code).

    • AUTO if diff is whitespace-only OR comment-only OR JCL syntax fix.

    • Everything else → CONFIRM.

  3. Git integration utilities — wrap subprocess.run("git ...") calls in core/git_helper.py. Functions: init_workspace_repo(), stage_file(), commit(message), diff(file), snapshot_before_write(dataset, member).

  4. Confirmation token systemsafety/tokens.py. Generate short tokens, store in-memory with 5-minute TTL, single-use.

  5. tools/write_tools.pyedit_member, create_member, delete_member, confirm_change, reject_change, propose_change (suggest-only entry point).

  6. servers/write_server.py — separate FastMCP("mainframe-write") server. Refuses to start unless MAINFRAME_MODE=WRITE AND --allow-writes flag 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_server exits 2 with REFUSED when MAINFRAME_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 with PermissionDenied regardless 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:

  1. tools/job_tools.pysubmit_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).

  2. JCL submission is WRITE-tier because it consumes mainframe resources, but checking job status and reading SYSOUT is READ-tier.

  3. 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_tools unit cases; one live submit succeeded in the partial Phase 4 sweep.)

  • ⏸ Checking status returns "RUNNING" then "OUTPUT" then return code. (Code: JobRunner.status returns raw TSO STATUS labels per §14.6; unit-tested. Live deferred.)

  • ⏸ Fetching SYSOUT of a failed compile shows the error messages. (Code: fetch_sysout returns spool body + RC header; unit-tested. Live deferred.)

  • ⏸ An abend in SYSOUT triggers detect_abend and is highlighted. (Code: _apply_change + fetch_sysout trip abend_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 in test_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:

  1. 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 regex ignore_patterns are 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's ignore_patterns. Returns PASS: or FAIL: 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).

  2. Baselines stored as YAML in tests/baselines/<test_name>.yaml (one file per test, human-diffable in git). Schema includes optional top-level ignore_patterns: [<regex>, ...] for masking.

  3. servers/test_server.py — separate FastMCP("mainframe-test") server, loaded only when MAINFRAME_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.py case 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_patterns mask 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() -> str

Screen 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 detection

Navigation

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) -> str

Datasets (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) -> str

Jobs (status only)

def list_my_jobs() -> str
def check_job(job_id: str) -> str
def fetch_sysout(job_id: str, ddname: str = "ALL") -> str

Write 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) -> str

Test 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) -> str

Return 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 logging module configured in mainframe_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.pynav_aid_tools.py + nav_wait_tools.py).


11. Testing and verification

Unit tests (pytest)

  • Located in tests/.

  • Mock the MainframeSession for 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 -v from 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.

After implementing a phase:

  1. Run unit tests: pytest -v

  2. Register MCP server with Claude Code (if not already): claude mcp add ...

  3. Restart Claude Code session.

  4. Run through the natural-language acceptance prompts from section 8.

  5. Inspect audit log to confirm clean records.


12. Distribution

GitHub repository

  • Public repo: github.com/<your-username>/mainframe-mcp

  • License: 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:

  1. Clone the repo.

  2. Install Python 3.11+ and wc3270 (Windows) or x3270 (Linux/Mac).

  3. Create venv and install requirements.

  4. Copy config.example.yamlconfig.yaml, edit host/scope.

  5. Set userid env var and password in keyring.

  6. 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., cp1140 for European EBCDIC) → change mainframe.code_page.

  • Different scope rules → edit scope.allowed_datasets and friends.

  • TLS-enabled mainframe → set mainframe.tls: true and mainframe.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

S0C1

Operation exception

Invalid instruction (uninitialized branch target)

S0C4

Protection exception

Out-of-bounds memory access

S0C7

Data exception

Bad numeric data (non-numeric in numeric field)

S322

Time limit exceeded

Job ran too long

S806

Module not found

Missing load module in STEPLIB

S913

Security violation

RACF denial

U4038

Language Environment

COBOL runtime error

ASRA

CICS abend (program check)

Same family as S0C*

AICA

CICS abend (transaction timeout)

Loop or wait too long

AEY7

CICS abend (no authorization)

Resource not authorized

APCT

CICS abend (program not found)

PROGRAM not in PPT

DFHAC2206

CICS message

Transaction abnormally terminated

B. ADCD-specific notes

  • Default datasets begin with ADCD.* and SYS1.*. These are system datasets — do not write.

  • User-allocated datasets typically begin with the userid (ADCDB.* for user ADCDB).

  • ISPF is started by typing ISPF at the TSO READY prompt.

  • TSO LOGON is automatic upon TN3270 connection if LOGON is 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

TSO_READY

(24, "READY")

TSO command prompt

ISPF_PRIMARY

(1, "ISPF Primary Option Menu")

ISPF main menu

ISPF_DSLIST

(1, "Data Set List Utility")

Option 3.4 dataset list

ISPF_EDIT

(1, "EDIT")

Editing a member

ISPF_BROWSE

(1, "BROWSE")

Browsing a member

SDSF_HOME

(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.html

  • x3270 / wc3270 documentation: https://x3270.org

  • MCP specification: https://modelcontextprotocol.io

  • z/OS FTP user's guide (IBM Knowledge Center)

  • p3270 library: https://github.com/mstiri/p3270

  • hack3270 (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 TSO SUBMIT *. Used when port 21 is firewalled. Implemented in core/jcl_writer.py and routed by core/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 raise NotImplementedError.

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

core/dataset_transport.py

FTP/ISPF/JCL dispatcher with reachability probe + fallback

core/ispf_dataset.py

ISPF panel-based dataset reader (used by ispf/jcl transports)

core/jcl_writer.py

TSO SUBMIT * + IEBGENER/IEBUPDTE + STATUS/OUTPUT/CANCEL primitives

core/job_runner.py

Phase 4 orchestration: history dequeue + abend marking

safety/abend_state.py

Per-process abend lockout counter (split from abend.py)

tools/session_tools.py

connect / login / disconnect / status / reconnect / force_cleanup

runtime.py

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 OUTPUT retrieval command. The plugin frequently observes status=NOT FOUND with 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 TSO LISTDS / panel probe) checks the host directly. Member present after a create/edit → ✅ OK. Member absent after a delete → ✅ OK. Anything else → ❌ ERROR + git reset --hard to the pre-write SHA.

State table for the post-submit verify path:

JES outcome

Host probe

Tool returns

RC = 0

member present

OK: applied

RC = 0

member absent

ERROR: WriteVerificationFailed + git rollback

RC ≠ 0

not consulted

ERROR: RC=<n> (short-circuit)

Abend (S0C7, U4038, …)

not consulted

ERROR: ABENDED <code> + lockout trip

RC unparseable (spool purged)

member present

OK: applied + note: JES spool was unreadable; success confirmed by read-back probe

RC unparseable (spool purged)

member absent

ERROR: WriteVerificationFailed + git rollback + JES detail: <message>

RC unparseable

probe raises

ERROR: WriteVerificationFailed: verification probe raised: <err> + git rollback

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_pds reports "PDS already exists; skipping allocation."

  • bootstrap_members IEBUPDTE submit returns rc=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_pds should 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.

cleanup_pds RC verification

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. ADCDC.MCPTEST.R<timestamp>.SOURCE per run.

Idempotent bootstrap (PDS-exists-empty case)

Detect partial state, use IEBUPDTE PARM=MOD with ./ REPL for existing names.

Reconnect=S precise field positioning

The current 10-tab approach is fragile across panel variants. moveTo(row, col) against discovered field coordinates would be more robust.

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-mcp and the target is ADCD z/OS 1.10.

  • You're working in C:\mainframe-mcp with .venv activated.

  • 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 tools
analyze_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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.9/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
job_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.6/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior2/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
ddnameNoALL
job_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
patternYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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:

  1. Drive the current TN3270 session through the robust logoff protocol (navigate to READY then LOGOFF).

  2. 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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
datasetYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.8/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines2/5

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).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.7/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines2/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
colYes
rowYes
lengthNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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).

ParametersJSON Schema
NameRequiredDescriptionDefault
patternYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters5/5

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.

Purpose5/5

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.

Usage Guidelines4/5

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 (*).

ParametersJSON Schema
NameRequiredDescriptionDefault
pdsYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.3/5.0
Behavior2/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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).

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.3/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
useridYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters3/5

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.

Purpose4/5

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.

Usage Guidelines3/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
pds_memberYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines3/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.2/5.0
Behavior2/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines2/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
textYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A4.4/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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).

ParametersJSON Schema
NameRequiredDescriptionDefault
numberYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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).

ParametersJSON Schema
NameRequiredDescriptionDefault
numberYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

C2.6/5.0
Behavior2/5

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.

Conciseness3/5

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.

Completeness2/5

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.

Parameters2/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

A3.5/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
timeoutNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
patternYes
timeoutNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
resultYes

TDQS

B3.4/5.0
Behavior3/5

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.

Conciseness5/5

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.

Completeness3/5

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.

Parameters4/5

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.

Purpose4/5

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.

Usage Guidelines2/5

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.

  1. 26 tool updatesv0.1.0
    • First observedanalyze_screen_fields
    • First observedcheck_for_errors
    • First observedcheck_job
    • First observedconnect
    • First observeddisconnect
    • First observedfetch_sysout
    • First observedfind_text
    • First observedforce_cleanup
    • First observedget_dataset_info
    • First observedget_screen
    • First observedget_text_at
    • First observedidentify_screen
    • First observedlist_datasets
    • First observedlist_members
    • First observedlist_my_jobs
    • First observedlogin
    • First observedread_member
    • First observedreconnect
    • First observedsend_clear
    • First observedsend_enter
    • First observedsend_keys
    • First observedsend_pa
    • First observedsend_pf
    • First observedstatus
    • First observedwait_for_screen_change
    • First observedwait_for_text

TDQS

B3.4/5.0

Scored across 26 tools

Disambiguation5/5

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.

Naming Consistency4/5

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.

Tool Count3/5

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.

Completeness3/5

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

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers