AutoGen agents for Mainframe CICS batch job monitoring and control
AutoGen Agents for Mainframe CICS Batch Job Monitoring
Section titled “AutoGen Agents for Mainframe CICS Batch Job Monitoring”Bridging the gap between modern autonomous agents and legacy “Big Iron” infrastructure requires a robust translation layer. While AutoGen agents are excellent at planning and reasoning, they cannot natively speak the JCL or JES2 protocols used by IBM Mainframes.
This guide implements a FastMCP server (Model Context Protocol) that acts as a sidecar, exposing Mainframe batch operations as standard tools. We then connect an AutoGen workflow to this server, allowing agents to monitor and control CICS batch jobs via a clean abstraction.
🏗️ Architecture
Section titled “🏗️ Architecture”- Bridge Server (FastMCP): A Dockerized Python server that wraps Mainframe interactions (z/OSMF REST API) into MCP tools.
- Agent Client (AutoGen): A standard AutoGen workflow that connects to the Bridge Server via SSE (Server-Sent Events) to dynamically discover and utilize Mainframe tools.
🛠️ Step 1: The FastMCP Server
Section titled “🛠️ Step 1: The FastMCP Server”Create server.py. This server defines the tools the agent can use. It handles the specific headers, authentication, and error parsing required by the Mainframe.
import osimport loggingfrom fastmcp import FastMCP
# Pro Tip: Wrap this server with Helicone for production logging# from helicone.helpers import log_to_helicone# log_to_helicone()
# Initialize FastMCPmcp = FastMCP("Mainframe-Batch-Controller")
# ConfigurationMAINFRAME_HOST = os.getenv("MAINFRAME_HOST", "https://mainframe.internal.corp:443")MAINFRAME_USER = os.getenv("MAINFRAME_USER", "IBMUSER")MAINFRAME_PASS = os.getenv("MAINFRAME_PASS", "SYS1")
logging.basicConfig(level=logging.INFO)logger = logging.getLogger(__name__)
@mcp.tool()def submit_jcl_job(jcl_content: str) -> str: """ Submits a JCL (Job Control Language) batch job to the Mainframe (JES).
Args: jcl_content: The full JCL script as a string.
Returns: The Job ID (e.g., JOB00123) or error message. """ logger.info("Agent is submitting a JCL job...")
# Ensure your container has network access (e.g. via NordLayer) # url = f"{MAINFRAME_HOST}/zosmf/restjobs/jobs"
try: # In production, use requests to POST to z/OSMF # resp = requests.put(url, data=jcl_content, auth=(MAINFRAME_USER, MAINFRAME_PASS))
# MOCK RESPONSE if "ERROR" in jcl_content: return "submit_jcl_job failed: JCL Syntax Error in line 4." return "JOB00451"
except Exception as e: return f"Connection Error to Mainframe: {str(e)}"
@mcp.tool()def check_job_status(job_id: str) -> str: """ Checks the status of a submitted batch job.
Args: job_id: The ID returned by submit_jcl_job (e.g., JOB00451).
Returns: Status string (e.g., 'ACTIVE', 'CC 0000' (Success), 'ABEND S0C4'). """ logger.info(f"Checking status for {job_id}...")
# MOCK RESPONSE if job_id == "JOB00451": return "OUTPUT (CC 0000) - Job Completed Successfully" return "ACTIVE - Job is currently executing in CICS partition"
if __name__ == "__main__": # Must bind to 0.0.0.0 for Docker compatibility mcp.run(transport='sse', host='0.0.0.0', port=8000)🐳 Step 2: The Dockerfile
Section titled “🐳 Step 2: The Dockerfile”Create a Dockerfile to containerize the server. We expose port 8000 for the SSE stream.
# Use a lightweight Python runtimeFROM python:3.11-slim
# Prevent Python from buffering stdout/stderrENV PYTHONUNBUFFERED=1
WORKDIR /app
# Install dependenciesRUN pip install --no-cache-dir fastmcp requests uvicorn
# Copy the server codeCOPY server.py .
# Expose the MCP SSE portEXPOSE 8000
# Ensure your container has network access (e.g. via NordLayer)# Run the serverCMD ["python", "server.py"]🤖 Step 3: The AutoGen Agent
Section titled “🤖 Step 3: The AutoGen Agent”Create agent.py. This script configures the AutoGen agents and connects them to the MCP server defined in the mcps list.
import asynciofrom autogen import AssistantAgent, UserProxyAgent, register_functionfrom mcp import ClientSession, StdioServerParametersfrom mcp.client.sse import sse_client
# Configuration for MCP Serversmcps = ["http://localhost:8000/sse"]
# Configuration for the LLMllm_config = { "config_list": [{"model": "gpt-4-turbo", "api_key": "YOUR_OPENAI_KEY"}], "temperature": 0}
async def run_autogen_session(): # 1. Iterate through MCP servers and connect # In a real app, you might manage multiple sessions. # Here we demonstrate connecting to the Mainframe bridge.
mcp_url = mcps[0] print(f"🔌 Connecting to MCP Server at {mcp_url}...")
async with sse_client(mcp_url) as streams: async with ClientSession(streams[0], streams[1]) as session: await session.initialize()
# 2. Discover Tools tools = await session.list_tools() print(f"🛠️ Found {len(tools.tools)} Mainframe Tools:") for tool in tools.tools: print(f" - {tool.name}: {tool.description}")
# 3. Define Agents # The 'UserProxy' acts as the executor (admin) mainframe_admin = UserProxyAgent( name="Mainframe_Admin", human_input_mode="NEVER", max_consecutive_auto_reply=10, code_execution_config={"work_dir": "coding", "use_docker": False} )
# The 'Assistant' acts as the planner (analyst) analyst = AssistantAgent( name="Operations_Analyst", llm_config=llm_config, system_message=""" You are a Mainframe Operations Analyst. Your goal is to submit a JCL job and ensure it finishes with 'CC 0000'. Use the available tools. """ )
# 4. Bridge MCP Tools to AutoGen # We map the MCP tool calls to AutoGen's register_function dynamically # or explicitly as shown below for clarity.
async def call_submit_job(jcl_content: str) -> str: result = await session.call_tool("submit_jcl_job", arguments={"jcl_content": jcl_content}) return result.content[0].text
async def call_check_status(job_id: str) -> str: result = await session.call_tool("check_job_status", arguments={"job_id": job_id}) return result.content[0].text
# Register the wrappers register_function( call_submit_job, caller=analyst, executor=mainframe_admin, name="submit_jcl_job", description="Submits JCL to the Mainframe." )
register_function( call_check_status, caller=analyst, executor=mainframe_admin, name="check_job_status", description="Checks status of a Job ID." )
# 5. Start the conversation print("\n🚀 Starting AutoGen Workflow...\n") await mainframe_admin.a_initiate_chat( analyst, message="Submit the 'NIGHTLY_UPDATE' JCL job and verify success." )
if __name__ == "__main__": asyncio.run(run_autogen_session())🛡️ Quality Assurance
Section titled “🛡️ Quality Assurance”- Status: ✅ Verified
- Environment: Python 3.11
- Auditor: AgentRetrofit CI/CD
Transparency: This page may contain affiliate links.