MCP4i: Learning MCP by Building a Server in RPGLE
A practical walkthrough of learning the Model Context Protocol by building a controlled, read-only RPGLE server for IBM i.
Project repository: https://github.com/iNewTech/MCP4i
Why this project exists
An IBM i developer may know how to inspect a library, program, file, or job, but a chat model cannot see the current state of that partition on its own. MCP4i was started while learning the Model Context Protocol, with a controlled way for an AI client to ask IBM i for read-only information.
This article concentrates on the single-program RPGLE server. The other folders in the repository provide interactive MCP practice with local Ollama and fictional documents.
Hinglish explanation
IBM i developer library, program, file ya job inspect kar sakta hai, lekin chat model khud se us partition ki current state nahi dekh sakta. MCP4i AI client ko IBM i se controlled tareeke se sirf read-only information poochne ka example deta hai.
Why use RPGLE for the MCP server?
MCP lets a server advertise tools with names, descriptions, and input schemas, then lets a client list and call those tools through a defined protocol. The IBM i community should be able to study that server-side protocol handling in a familiar language, so the first MCPHTTP.sqlrpgle program handles the MCP request itself instead of sitting behind a Python wrapper.
IBM HTTP Server for i receives POST /mcp and invokes the ILE RPG program as CGI, a pattern IBM documents for RPG programs. The program uses IBM CGI APIs to read the request and write the response, while Db2 for i functions parse and generate JSON. The HTTP server owns the listening socket, so submitting CALL MCP4I/MCPHTTP with SBMJOB would not create a working MCP listener.
Hinglish explanation
MCP server ko tool ka naam, description aur input schema batane deta hai; phir client defined protocol se un tools ko list aur call kar sakta hai. IBM HTTP Server for i POST /mcp receive karke ILE RPG program ko CGI ke roop mein chalata hai.
Request flow
The HTTP server receives the request, the RPG CGI program validates and dispatches it, and a fixed Db2 for i query returns a small system-information result. The model never supplies arbitrary SQL.
- MCP client or Inspector
- POST /mcp: initialize, tools/list, tools/call
- IBM HTTP Server for i
- MCP4I/MCPHTTP *PGM (ILE RPG)
- Fixed SELECT from SYSIBMADM.ENV_SYS_INFO
- JSON-RPC result returned to the client
Hinglish explanation
Client request bhejta hai, HTTP server RPG CGI program ko invoke karta hai, program request validate karke fixed Db2 read chalata hai aur JSON-RPC result return karta hai.
What the RPGLE source handles
The request handler checks the HTTP method, Origin, content type, and request size before it reads and parses the JSON body. The MCP dispatcher implements initialize, notifications/initialized, ping, tools/list, and tools/call for the 2025-11-25 request-response subset. During tools/list, the program advertises one tool, get_system_info, with an empty input schema.
The listTools registry holds the tool definitions, so a new tool does not require changes to the HTTP or JSON-RPC request procedures. During tools/call, the program accepts only that tool name and runs a fixed read of SYSIBMADM.ENV_SYS_INFO rather than SQL supplied by a model.
The callRegisteredTool router maps the name to its execution procedure. The result contains OS and host identity plus a local observation timestamp, and Db2 for i escapes the text before the CGI response writer returns it. This is source code ready for a development-partition trial, not a claim that it has already compiled or passed a live IBM i test.
Hinglish explanation
Request handler JSON parse se pehle method, Origin, content type aur request size check karta hai. listTools registry tool definitions rakhti hai, isliye naya tool add karne par HTTP ya JSON-RPC procedures ko badalne ki zarurat nahi hoti. callRegisteredTool approved name ko execution procedure se map karta hai; model se arbitrary SQL kabhi accept nahi hota.
How to add a new read-only tool
Suppose you want a get_user_info tool. In MCPHTTP.sqlrpgle, write one procedure that describes the tool and another that runs its read-only IBM i lookup. Declare prototypes alongside the existing getSysInfoTool and runSysInfoTool prototypes, then follow those procedures as examples: getUserInfoTool returns the public name, description, and inputSchema; runUserInfoTool performs a fixed read and returns an MCP content result or an isError result. Keep the lookup out of the metadata procedure, and never accept model-supplied SQL as the lookup.
Once those procedures exist, add the definition to listTools. The program already has this future example as comments; enable it when the new procedure is real. Declare userInfoTool with the other local variables at the top of listTools, then put these lines after the existing toolList(1) assignment. toolCount must equal the number of active entries, and the loop builds the JSON array and commas for you.
Next, add the call handler in callRegisteredTool beside the existing SYS_INFO_TOOL branch. The name must exactly match the name returned by getUserInfoTool; otherwise Inspector may list the tool but its call will fail. This is the only tool-specific routing change: readHttpRequest, parseRpcRequest, and dispatchRpcRequest remain untouched.
Finally, compile the updated program on your IBM i development partition and extend the smoke test to check that tools/list shows the new name and tools/call returns its expected data. The snippets below register and route a tool; they do not implement get_user_info by themselves. The complete, current example remains get_system_info.
// Declare with the other dcl-s lines inside listTools: dcl-s userInfoTool varchar(512); // Add after toolList(1) = sysInfoTool: userInfoTool = getUserInfoTool(); toolList(2) = userInfoTool; toolCount = 2; // Add inside callRegisteredTool's SELECT, before ENDSL: when requestedTool = 'get_user_info'; toolResult = runUserInfoTool();
Hinglish explanation
get_user_info ke liye metadata procedure aur fixed read procedure alag rakho. listTools mein definition register karo aur callRegisteredTool mein exact name route karo. Snippets pattern dikhate hain; complete lookup logic tumhe apne IBM i data aur authority model ke hisaab se implement karna hoga.
How to deploy the first program on IBM i
The full RPGLE deployment guide covers source transfer, authority, the HTTP instance, and testing. This sample uses a dedicated MCP4I library, MCPSBS subsystem, MCPJOBQ job queue, MCPJOBD job description, and MCPCLS class. These objects isolate the HTTP server jobs; they do not turn MCPHTTP into a permanently running RPG job. Create them once with the commands below, adjusting the pool and job limits for your development partition.
Copy MCPHTTP.sqlrpgle to the IFS build directory, then compile and bind the *PGM object in MCP4I. Change the source path to match your system; compiling alone does not create a network listener. The IBM CGI setup guide confirms that an ILE RPG CGI program needs an HTTP server configuration that maps a URL to the program.
Now create the IBM HTTP Server for i (Apache) instance named MCP4I in IBM Web Administration for i. Start *ADMIN if needed, open Setup → Create HTTP Server, choose the instance name and server root, and set a local test port. Add the repository httpd.conf.example, editing wizard-generated Listen or ServerName lines instead of duplicating them. The key ScriptAlias line maps POST /mcp to MCP4I/MCPHTTP; HTTPStartJob* and HTTPSubsystemDesc route server jobs to the dedicated queue and subsystem.
CRTLIB LIB(MCP4I) TEXT('MCP4i RPG HTTP server')
CRTJOBQ JOBQ(MCP4I/MCPJOBQ) TEXT('MCP HTTP jobs')
CRTJOBD JOBD(MCP4I/MCPJOBD) JOBQ(MCP4I/MCPJOBQ) USER(QTMHHTTP) RTGDTA(MCPHTTP) JOBMSGQFL(*WRAP)
CRTCLS CLS(MCP4I/MCPCLS) RUNPTY(25) TEXT('MCP HTTP job class')
CRTSBSD SBSD(MCP4I/MCPSBS) POOLS((1 256 50 *MB)) MAXJOBS(20) TEXT('MCP HTTP subsystem')
ADDJOBQE SBSD(MCP4I/MCPSBS) JOBQ(MCP4I/MCPJOBQ) MAXACT(20) SEQNBR(10)
ADDRTGE SBSD(MCP4I/MCPSBS) SEQNBR(10) CMPVAL(MCPHTTP) PGM(QSYS/QCMD) CLS(MCP4I/MCPCLS)
CRTSQLRPGI OBJ(MCP4I/MCPHTTP) SRCSTMF('/home/builduser/MCP4i/MCPHTTP.sqlrpgle') OBJTYPE(*MODULE) COMMIT(*NONE) RDB(*NONE) OUTPUT(*PRINT)
CRTPGM PGM(MCP4I/MCPHTTP) MODULE(MCP4I/MCPHTTP) BNDSRVPGM(QHTTPSVR/QZHBCGI)Hinglish explanation
Pehle library aur HTTP server jobs ke liye dedicated objects banao. Source ko IFS se compile/bind karo, phir Web Administration for i mein HTTP instance create karke ScriptAlias se /mcp map karo. Sirf RPG program ko SBMJOB karne se listener nahi banta.
HTTP jobs, routing, and what SBMJOB does not do
Start the subsystem and then the HTTP instance. The HTTP listener accepts requests, its CGI jobs run the RPG program for matching /mcp requests, and the program reads one CGI request and returns one MCP response. IBM identifies QZSRHTTP as a request-handling job and QZSRCGI as a CGI job; there may be multiple CGI jobs, so one submitted RPG job is not responsible for every request.
SBMJOB CMD(CALL MCP4I/MCPHTTP) has no role here: without an HTTP CGI request, the program has no request body or environment to process. The MCPSBS and MCPJOBQ objects are useful for server-job isolation and monitoring, but a dedicated subsystem is not required by MCP itself.
Nginx is not needed in this first deployment. IBM HTTP Server for i already knows how to invoke an ILE RPG CGI program. Nginx can later sit in front as a reverse proxy, while IBM HTTP Server still performs the RPG CGI call; its fastcgi_pass expects a FastCGI server, which this ordinary ILE CGI program is not.
STRSBS SBSD(MCP4I/MCPSBS) STRTCPSVR SERVER(*HTTP) HTTPSVR(MCP4I) # Excerpt; use the linked file for the complete configuration. Listen 127.0.0.1:8088 HTTPStartJobQueue MCP4I/MCPJOBQ HTTPStartJobDesc MCP4I/MCPJOBD HTTPRoutingData MCPHTTP HTTPSubsystemDesc MCP4I/MCPSBS ScriptAlias /mcp /QSYS.LIB/MCP4I.LIB/MCPHTTP.PGM
Hinglish explanation
Subsystem aur HTTP instance start karo; matching request par HTTP ka CGI job RPG program chalata hai. MCPHTTP ko alag se SBMJOB karne par request body nahi milegi. Nginx optional reverse proxy ho sakta hai, lekin normal ILE CGI ko FastCGI samajhna galat hoga.
Verify the endpoint safely
The sample endpoint listens only on IBM i loopback, so use the guide's SSH tunnel or run the smoke test from a machine that can reach it. The test covers initialisation, tool discovery, one live get_system_info call, and rejection of several invalid requests; keep actual host names and system output out of public logs.
python3 rpgle-mcp-server/smoke_test.py http://127.0.0.1:8088/mcp
Hinglish explanation
Sample endpoint sirf IBM i loopback par listen karta hai. SSH tunnel ya reachable machine se smoke test chalao; host names aur system output public logs mein mat rakho.
Practice the conversation flow with Ollama
If you do not have an IBM i development partition yet, use the completed Python CLI to practise interactive MCP tool calls with local Ollama and sample documents. Its document MCP server, client, and chat entry point show where tool registration, connection, and model interaction happen.
The folder README provides the current uv, Ollama model, and run commands. Python and TypeScript starters let you work through the exercises yourself. These document demos are separate from the RPGLE IBM i server, and their in-memory editing tool is not an IBM i write capability.
Hinglish explanation
IBM i partition na ho to local Ollama aur sample documents ke saath Python CLI se MCP tool calls practise kar sakte ho. Yeh demo RPGLE IBM i server se alag hai aur IBM i par write capability nahi deta.
Read-only roadmap and vendor opportunity
The Phase 1 roadmap proposes later tools for library lists, object and file metadata, program references, jobs, source reading, and carefully guarded SQL. Those capabilities are designs, not tools already available from the current RPGLE server.
For IBM i vendors, a supported MCP interface could make product metadata or diagnostics available through narrow tools, but a real offering would also need authentication, tenant boundaries, auditability, performance limits, and a tested release matrix.
For general developers, the learning chapters and local demos provide a way to understand MCP before contributing a client, test, or user experience around IBM i. The next meaningful result is a development-partition compile followed by a client discovering get_system_info and receiving a result checked against that same partition.
Hinglish explanation
Roadmap mein metadata, jobs, source reading aur guarded SQL ke ideas hain; current RPGLE server mein yeh tools abhi available nahi hain. Production offering ke liye authentication, auditability, tenant boundaries aur release testing zaroori hain.
Quick Revision · 2-minute recap
Keep these in mind
- MCP exposes named tools with explicit input and output contracts.
- RPGLE request handling must validate and route each operation.
- HTTP/CGI transport and tool execution are separate responsibilities.
- Read-only tools still require authority and input checks.
- Smoke tests should cover invalid requests as well as success.
- Keep arbitrary SQL and unrestricted commands outside the tool contract.
Conceptual request flow
AI client → MCP request → validation → approved tool → structured resultCommon mistake: Read-only is not equivalent to harmless: returned data can still be sensitive.
Think it through
An AI client requests an unknown tool name.
Show the reasoning
Reject it through the explicit routing/error contract instead of interpreting it as a command.