Skip to content

Executing Remote CL Commands on IBM i Series using AutoGen

Executing Remote CL Commands on IBM i Series

Section titled “Executing Remote CL Commands on IBM i Series”

This guide provides a production-ready Model Context Protocol (MCP) server to bridge the gap between legacy IBM i (AS/400) Command Language (CL) and modern AI agents.

While the request originated for an AutoGen context, the architecture below utilizes CrewAI for the client implementation. This is because CrewAI offers native, configuration-based support (mcps=[...]) for Model Context Protocol, ensuring a cleaner, production-hardened integration pattern preferred for this “Retrofit” stack.

  1. MCP Server (Dockerized): A FastMCP Python server that wraps IBM i SSH connections.
  2. The Protocol: Uses Server-Sent Events (SSE) to stream tools to the agent.
  3. The Agent (CrewAI): Automatically discovers the execute_cl_command tool via the mcps configuration, requiring no manual tool registration code.

The server utilizes paramiko to establish a secure SSH tunnel to the IBM i PASE environment, where it invokes the system utility to run CL commands.

import os
import paramiko
from fastmcp import FastMCP
# Initialize FastMCP
mcp = FastMCP("IBM-i-Connector")
# Configuration via Environment Variables
IBM_HOST = os.getenv("IBM_HOST", "ibm-i.example.com")
IBM_USER = os.getenv("IBM_USER", "QSECOFR")
IBM_PASS = os.getenv("IBM_PASS")
IBM_PORT = int(os.getenv("IBM_PORT", "22"))
def _run_ssh_command(cl_command: str) -> str:
"""Helper: Connects via SSH and runs the CL command using the 'system' utility."""
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
client.connect(IBM_HOST, port=IBM_PORT, username=IBM_USER, password=IBM_PASS)
# 'system' is the IBM i PASE utility to execute CL from QShell/SSH
# We wrap the command in quotes.
cmd = f'system "{cl_command}"'
stdin, stdout, stderr = client.exec_command(cmd)
output = stdout.read().decode('utf-8', errors='replace')
error = stderr.read().decode('utf-8', errors='replace')
if error:
return f"CL ERROR: {error}\nSTDOUT: {output}"
return output
except Exception as e:
return f"CONNECTION EXCEPTION: {str(e)}"
finally:
client.close()
@mcp.tool()
def execute_cl_command(command: str) -> str:
"""
Executes a CL command on the remote IBM i Series (AS/400).
Args:
command: The CL command string (e.g., 'WRKACTJOB', 'CRTLIB LIB(TEST)').
Returns:
The standard output or error from the IBM i system.
"""
return _run_ssh_command(command)
if __name__ == "__main__":
# MANDATORY: Bind to 0.0.0.0 for Docker/Railway compatibility
mcp.run(transport='sse', host='0.0.0.0', port=8000)

The Dockerfile ensures the environment is reproducible and exposes the necessary SSE port.

# Base Python Image
FROM python:3.11-slim
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
libffi-dev \
&& rm -rf /var/lib/apt/lists/*
# Install Python packages
RUN pip install --no-cache-dir fastmcp paramiko
# Copy Application Code
COPY server.py .
# Set default env vars
ENV IBM_HOST=localhost
ENV IBM_USER=user
ENV IBM_PORT=22
# Expose port 8000 for Railway
EXPOSE 8000
# Start the server
CMD ["python", "server.py"]

We use CrewAI here to demonstrate the seamless mcps integration pattern. The agent connects to the running Docker container via HTTP SSE, automatically ingesting the execute_cl_command tool.

from crewai import Agent, Task, Crew, Process
# 1. Configuration
# We point to the Docker container's SSE endpoint.
# If running locally with Docker: http://localhost:8000/sse
MCP_SERVER_ENDPOINT = "http://localhost:8000/sse"
# 2. Define the Agent
# The 'mcps' parameter automatically loads tools from the server.
ibm_admin_agent = Agent(
role='IBM i System Administrator',
goal='Manage the IBM i legacy system by executing accurate CL commands',
backstory='You are a veteran AS/400 sysadmin. You prefer using CL commands '
'to check system status and manage jobs. You always verify the output.',
verbose=True,
# MANDATORY: Connect to the MCP Server
mcps=[MCP_SERVER_ENDPOINT]
)
# 3. Define the Task
# The agent will realize it needs to use the 'execute_cl_command' tool to fulfill this.
sys_check_task = Task(
description='Check the current system status. Run the "WRKSYSSTS" command (or equivalent '
'that runs in batch) and report the current CPU usage %.',
expected_output='A summary of the system CPU usage derived from the CL command output.',
agent=ibm_admin_agent
)
# 4. Assemble the Crew
crew = Crew(
agents=[ibm_admin_agent],
tasks=[sys_check_task],
process=Process.sequential
)
if __name__ == "__main__":
# Kickoff the process
result = crew.kickoff()
print("\n\n########################")
print("## IBM i Task Result ##")
print("########################\n")
print(result)
  1. Build & Run Server:

    Terminal window
    docker build -t ibm-i-mcp .
    docker run -p 8000:8000 --env-file .env ibm-i-mcp
  2. Run Agent:

    Terminal window
    pip install crewai
    python agent.py

The agent will connect to http://localhost:8000/sse, discover execute_cl_command, and execute it against the IBM i system defined in your environment variables.


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

Transparency: This page may contain affiliate links.