Skip to content

OpenAI Operator for automated Mainframe CICS interactions

OpenAI Operator for automated Mainframe CICS interactions

Section titled “OpenAI Operator for automated Mainframe CICS interactions”

For decades, CICS (Customer Information Control System) has been the transaction engine of the world economy. It processes billions of transactions daily for banks, airlines, and insurance companies.

However, CICS was designed for green screens (3270 terminals), not AI agents.

This guide provides a “Retrofit” solution: an MCP Server that allows the OpenAI Operator to execute CICS transactions programmatically. We utilize the CICS Web Services (JSON/REST) interface, which is the standard, modern way to expose legacy COBOL programs to the outside world without fragile screen scraping.

  1. OpenAI Operator: Acts as the intelligent decision-maker.
  2. MCP Server (FastMCP): Translates natural language intent (e.g., “Check balance for account 1234”) into structured CICS JSON payloads.
  3. CICS Transaction Gateway (or CICS TS): Receives the HTTP request and triggers the COBOL logic.

This Python server uses fastmcp to create a lightweight bridge. It assumes your CICS region is configured to accept JSON payloads via HTTP (a standard feature in CICS TS 5.x and above).

import os
import json
import logging
from typing import Dict, Any, Optional
import requests
from fastmcp import FastMCP
# Initialize the MCP Server
mcp = FastMCP("CICS-Gateway")
# Configuration
# ideally loaded from environment variables for security
CICS_BASE_URL = os.getenv("CICS_BASE_URL", "http://cics-region.internal:12345/cics/api")
CICS_USER = os.getenv("CICS_USER", "USERID")
CICS_PASSWORD = os.getenv("CICS_PASSWORD", "PASSWORD")
# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@mcp.tool()
def execute_cics_program(program_name: str, payload: Dict[str, Any]) -> str:
"""
Executes a specific CICS program via the CICS Web Services JSON interface.
Use this to trigger transaction logic (e.g., balance check, order update)
that resides on the Mainframe.
Args:
program_name: The 8-character CICS program name (e.g., 'GETBAL01').
payload: The business data required by the program as a dictionary.
Returns:
A JSON string containing the response from the mainframe or error details.
"""
url = f"{CICS_BASE_URL}/{program_name.lower()}"
logger.info(f"Executing CICS Program: {program_name} at {url}")
try:
# Standard Basic Auth is common for CICS Web Services
response = requests.post(
url,
json=payload,
auth=(CICS_USER, CICS_PASSWORD),
timeout=10, # CICS transactions should be fast
headers={"Content-Type": "application/json"}
)
response.raise_for_status()
return json.dumps({
"status": "success",
"cics_return_code": response.status_code,
"data": response.json()
})
except requests.exceptions.HTTPError as e:
# Handle specific Mainframe HTTP return codes
error_msg = f"CICS HTTP Error: {e.response.status_code} - {e.response.text}"
logger.error(error_msg)
return json.dumps({"status": "error", "message": error_msg})
except requests.exceptions.ConnectionError:
error_msg = "Failed to connect to CICS region. Check network/VPN."
logger.error(error_msg)
return json.dumps({"status": "error", "message": error_msg})
except Exception as e:
logger.error(f"Unexpected error: {str(e)}")
return json.dumps({"status": "error", "message": str(e)})
@mcp.tool()
def check_cics_region_health() -> str:
"""
Pings the CICS region to ensure the Web Services interface is active.
"""
url = f"{CICS_BASE_URL}/health" # Assumes a standard health endpoint or root check
try:
response = requests.get(
url,
auth=(CICS_USER, CICS_PASSWORD),
timeout=5
)
if response.status_code == 200:
return "CICS Region is ACTIVE and accepting requests."
else:
return f"CICS Region responded with status: {response.status_code}"
except Exception as e:
return f"CICS Region unreachable: {str(e)}"
if __name__ == "__main__":
mcp.run()

This Dockerfile packages the MCP server. It is critical to ensure the container has access to the private network where the Mainframe resides, often requiring a VPN tunnel (like NordLayer, Tailscale, or a direct Railway private network connection).

# Use an official Python runtime as a parent image
FROM python:3.11-slim
# Set the working directory in the container
WORKDIR /app
# Install system dependencies if needed (usually minimal for this setup)
RUN apt-get update && apt-get install -y --no-install-recommends \
curl \
&& rm -rf /var/lib/apt/lists/*
# Copy the requirements (embedded here for simplicity)
# In production, use a requirements.txt
RUN pip install --no-cache-dir \
fastmcp \
requests
# Copy the current directory contents into the container at /app
COPY server.py .
# Ensure your container has network access (e.g. via NordLayer)
# This is critical for reaching legacy CICS IPs.
# Make port 8000 available to the world outside this container
EXPOSE 8000
# Run server.py when the container launches
CMD ["python", "server.py"]
  1. Network Access: The most common failure point is the container checking the public internet for the Mainframe IP (10.x.x.x). Ensure your Docker runtime (Railway, AWS ECS) is peered with the VPC containing the Mainframe, or use a sidecar VPN.
  2. Authentication: CICS Web Services often use Basic Auth (RACF ID/Password) or Client Certificates (mTLS). Modify the requests.post call in server.py to use cert=('client.pem', 'key.pem') if mTLS is required.
  3. JSON Mapping: CICS normally expects specific JSON schemas that map to the COBOL COPYBOOKs. Ensure your payload in the OpenAI prompt matches the expected structure.

  • Status: ✅ Verified
  • Environment: Python 3.11
  • Auditor: AgentRetrofit CI/CD

Transparency: This page may contain affiliate links.