tutorials

Call an RPG Program on IBM i from .NET Using an MCP Server

ByQuentin DESTRADE

Illustration for the article

Detailed content of the article:Call an RPG Program on IBM i from .NET Using an MCP Server

Analyze and call an IBM i RPG program from .NET through an MCP server connected to Claude Desktop using NTi Data Provider.

In the first two episodes, we connected Claude to IBM i and gave it the ability to query and update a DB2 for i database.

This article is part of a series on using an AI agent with IBM i through the Model Context Protocol:

In this article, we are going to analyze the source code of an IBM i RPG program and call it from .NET through Claude Desktop using NTi data provider.

Architecture of the .NET MCP Server Connected to IBM i

We start from the episode 2 project, unchanged.
We create a new RPG folder and add the RPGTools.cs class to it.

The program.cs therefore becomes:

// … code
.WithTools<TranslogTools>();
.WithTools<RPGTools>();

IBM i RPG Program Example: CALCPRIX

CALCPRIX is a free-format RPG program compiled in the TLOG library. It encapsulates the pricing logic of Translog, the company we covered in the previous episode.

Current pricing rules:

  • Base rate: $10 + $2/kg
  • PREMIUM customer: 10% discount
  • PROSPECT customer: 5% surcharge
  • STANDARD customer: no discount or surcharge
  • Weight > 10,000 kg: rejected
  • Amount exceeds customer credit limit: rejected

Program parameters:

Parameter IBM i Type Direction Description
P_SHIPID CHAR(10) Input Shipment identifier
P_PRIX PACKED(11:2) Output Calculated rate
P_MSG CHAR(50) Output Success or rejection reason

Analyze an IBM i RPG Program with an AI Agent

Part 1 - Thomas Discovers CALCPRIX

Thomas is a .NET developer who just joined Translog.
He's been told there is an RPG program somewhere in the TLOG library that handles pricing calculations. His job is to integrate it into a new .NET application, that's all he knows.

He has no access to documentation, since there isn't any. And Thomas doesn't really know RPG, he doesn't know what parameters the program expects, what it returns, or what logic applies.

He opens Claude Desktop and types:

πŸ’¬ Thomas's Prompt
" Analyze the RPG program CALCPRIX in the TLOG library and explain how it works. "

DB2 for i Dashboard generated by Claude Desktop via a .NET MCP server

Claude calls the already defined ReadRpgSource tool and retrieves the source code lines of the RPG program. It analyzes them and responds directly: business logic explanation, description of input/output parameters with their IBM i types etc.

Thomas didn't open a single 5250 screen. He didn't need to reach out to an RPG expert or look up any documentation.

1. ReadRpgSource()

The tool used by Thomas runs a SQL query on the QRPGLESRC source file on the IBM i to retrieve the source code lines of the RPG program. Claude receives the code exactly as a developer would read it in an editor.

[McpServerTool]
[Description()]
public string ReadRpgSource(
    [Description("Library name")] string library,
    [Description("RPG program name")] string program)
    {
        var sql = _conn.Query($@"
        SELECT SRCDTA
        FROM {library.ToUpper()}.QRPGLESRC
        ORDER BY SRCSEQ");

        if (!sql.Any())
            return $"Program {program} not found in {library}";

        return string.Join(Environment.NewLine, sql);
    }

The QRPGLESRC source file used in this example contains only a single member.
A simple SQL query is therefore enough to retrieve the program lines in order and reconstruct the full source code.

As long as an RPG program can be read from SQL, Claude can do much more than explain its signature.

For instance it can identify bad practices, spot uninitialized variables or duplicated code blocks in an existing program. It can also convert legacy column-based RPG into FREE RPG while explaining the changes, or generate technical documentation for an undocumented program.

Pricing logic and business rules of the CALCPRIX RPG program on IBM i

Most IBM i teams have hundreds of programs across their libraries. This tool gives any developer, regardless of their RPG knowledge level, immediate access to their business logic.

This approach is especially valuable in migration or modernization projects. Rather than rewriting blindly, you can first analyze and understand the existing business rules, then decide what to keep and what to refactor.

Call an IBM i RPG Program from .NET

Part 2 - Sylvie and the Pricing Update

Upper management at Translog just decided to revise their pricing structure. The per-kilogram rate is moving from $2/kg to $3/kg, effective immediately. A colleague of Thomas has already updated the rule in the CALCPRIX RPG program.

What remains now is to recalculate the rates for shipments already in progress.

Sylvie is a sales manager at Translog, we met her in the previous article. She has no idea what an RPG program is, has no access to ACS, and has no reason to care.

She opens Claude Desktop:

πŸ’¬ Sylvie's Prompt
β€œ The TRANSLOG pricing structure has changed. Recalculate the rate for shipment SHP-100007 ”.

Claude proceeds in two steps. It first calls GetShipmentsByStatus to list the relevant shipment and presents Sylvie with a summary of the current rates.

After confirmation, it calls the CalculateTranslogShipmentRate tool for the selected shipment. Each call triggers CALCPRIX on the IBM i, which applies the new pricing schedule and updates AMOUNT directly in the database.

Example 1 - SHP-100007, Batifroid SAS, PREMIUM, 1,900 kg

Claude displays the shipment details, reminds Sylvie of the pricing rules applicable to the PREMIUM segment, and asks for confirmation before calling the program.

Shipment details and rate update confirmation via the CALCPRIX RPG program

Sylvie confirms.
The CALCPRIX RPG program is then called, the 10% discount is applied and the rate goes from $2,800 to $5,139.

Updated rate for a shipment after calling the CALCPRIX RPG program

The update is immediately visible in ACS.

Updated rate in the DB2 for i SHIPMENTS table

Example 2 - SHP-100008, Nordbat, STANDARD, 3,100 kg

Same process.
STANDARD segment, no discount or surcharge. The rate goes from $4,400 to $9,310.

Updated rate in the DB2 for i SHIPMENTS table

Example 3 - SHP-100012, DELIVERED status

Sylvie asks to update the rate for SHP-100012. Claude checks the shipment, notices the DELIVERED status, and refuses to call the program.

Rate update refused for a DELIVERED shipment

πŸ’‘The rule is defined in the tool description: the rate of an already completed delivery is final and cannot be changed.
Claude cannot do anything, it respects the business constraints it has been given.

1. CalculateTranslogShipmentRate()

This tool was implemented by Thomas, the .NET developer.
After analyzing CALCPRIX through ReadRpgSource, he was able to understand the program logic and identify its parameters. This allowed him to configure the tool with the necessary business rules (prior confirmation required, DELIVERED status locked, etc.) to ensure the program is used correctly from Claude.

The logic runs in three steps: build the parameter list matching the program signature exactly, call the program, and read the outputs:

[McpServerTool]
[Description(@"
    Calculate the rate for a shipment through the CALCPRIX RPG program on the IBM i.
    This program reads the weight from SHIPMENTS, the customer segment from CUSTOMERS,
    applies the Translog pricing rules and updates the AMOUNT field.
    IMPORTANT: this tool modifies data on the IBM i.
    Before calling it, you MUST:
   1. Show the user the SHIPMENT_ID and the name of the customer involved.
   2. Remind the rules: PREMIUM -10%, PROSPECT +5%, max weight 10,000kg.
   3. Ask for explicit confirmation before calling the program.
   BUSINESS RULE:
   Shipments with DELIVERED status must never be recalculated.
   The rate of an already completed delivery is final and cannot be changed.

   Only call the program after receiving clear approval.")]

public string CalculateTranslogShipmentRate(
    [Description("Shipment identifier (e.g. SHP-100003)")] string shipmentId)
{
    var parms = new List
    {
        new NTiProgramParameter(shipmentId, 10).AsInput(),  
        new NTiProgramParameter(0m, 11, 2).AsOutput(),              
        new NTiProgramParameter("", 50).AsOutput()
    };

    _conn.CallProgram("TLOG", "CALCPRIX", parms);

    var prix = parms[1].GetPackedDecimal(11, 2);
    var msg = parms[2].GetString().Trim();

    if (msg == "OK")
        return $"Rate successfully calculated : {prix:C} - AMOUNT updated for {shipmentId}";
    else
        return $"Error : {msg}";
}

One NTiProgramParameter is created per parameter expected by the program, in the same order as the RPG signature.

The types must match exactly those defined on the IBM i side: CHAR(10) for the input SHIPMENT_ID, PACKED(11:2) for the output rate, CHAR(50) for the return message.

A single line is enough to call the program:

_conn.CallProgram("TLOG", "CALCPRIX", parms);

NTi opens a session on the IBM i and runs CALCPRIX in its native environment. After the call, the outputs are read directly from the parameters:

var prix = parms[1].GetPackedDecimal(11, 2);
var msg  = parms[2].GetString().Trim();

Conclusion

To call an RPG program from .NET with NTi is straightforward: declare the parameters, call the program, and read the outputs.

In this example, Claude was able to:

  • read the RPG source code directly from the IBM i
  • understand the business logic of the program
  • call the program to update shipment rates

Most IBM i systems already have hundreds of RPG programs that implement business-specific rules: core processes, custom calculations, and years of accumulated know-how. With an MCP server, these programs can be analyzed, documented and called directly without rewriting them.

This also opens the door for .NET developers to work with an IBM i system without having to master every technical detail upfront, provided of course that appropriate tools and security rules are defined. And in many cases, this is a far more realistic path to modernize a system than starting from scratch.


Quentin Destrade