Start Today

← Documentation

Flow API and MCP

Flow API

Every saved screen flow is also a REST endpoint. Because a flow declares a typed In / Out pair and a single execute method, a multi-screen conversation collapses into one stateless JSON call: the caller never sees screens, AID keys or a session. This is how a converted program is consumed by other systems, as opposed to the Player, which is for a human clicking through screens.

All routes are relative to the backend's /api base:

Method and pathWhat it does
POST /applications/{app}/operations/{op}/flows/{ClassName}/executeRun the flow end to end and return its output
GET /applications/{app}/operations/{op}/flowsList the flows saved for that operation
GET / PUT /applications/{app}/operations/{op}/flows/{ClassName}Read or save the flow script; a save is lint- and compile-checked and rejected on errors
GET /openapi.yamlOpenAPI 3.0.3 document describing every flow and RPC program

Calling a flow

The request wraps the flow's inputs in an input object, keyed by the field names of the flow's In class. Nested fields use dotted paths, such as address.line1.

curl -X POST \
  http://localhost:8080/api/applications/demo/operations/login/flows/DemoFlow/execute \
  -H 'Content-Type: application/json' \
  -d '{ "input": { "userId": "USER001" } }'

The response carries the flow's Out fields under output; meta holds execution detail such as the steps that ran and any screen mismatch, and error is set instead of output when the flow fails.

{
  "output": { "errorMessage": "" },
  "meta":   { "steps": [ ... ] },
  "error":  null
}

Flow inputs and outputs are currently exchanged as strings, so every field in the generated schema is type: string. Numeric and date fields are still returned faithfully; convert on the caller side where it matters.

API Docs

Click API Docs in the sidebar for a browsable, try-it-out Swagger UI view of the same document inside the console. Flows are grouped by application and operation, and RPC invoke paths appear alongside them. Every Try it out call is sent as the signed-in user, so it works in the SaaS console and the OpenLegacy Platform, where the API requires sign-in. Swagger UI ships inside the console, so no internet access is needed.

The document is generated on demand and cached. It refreshes automatically when you save or delete a flow, change an operation, or regenerate code.

The backend also serves a bare Swagger page at its own /swagger. It loads Swagger UI from a public CDN and sends no credentials, so it only works on a backend without sign-in and with internet access; use API Docs everywhere else.

MCP

OL Next exposes a Model Context Protocol endpoint so an external agent such as Cursor, Claude Desktop or Claude Code can drive the conversion loop (create an application, import a catalog example, an AtomIQ operation or your own source, and generate), then play screens, record and generate flows, invoke RPC programs and bind live data, without opening the console. MCP covers that loop; it is not a full REST substitute.

The endpoint is POST /api/mcp (streamable HTTP, service identity ol-next). On connect the server sends short instructions (the application, operation and program/screen/flow model, the typical journeys and the main rules), which your client passes to the agent.

Authentication

DeploymentHow the client authenticates
On-premises, standaloneNo token for loopback callers. If a key is configured in Global Settings → MCP access, every caller sends it as x-api-key
SaaS / PlatformA Bearer Hub JWT, the same token as other /api/* calls. Add the server by its MCP URL, the API host followed by /next/api/mcp, not the console address. Clients discover OAuth at /next/.well-known/oauth-authorization-server on the API host, complete the Hub login, then attach the token automatically

A Hub account API key from Global Settings → API access, sent as x-api-key, also works and needs no interactive login.

Tools

Six tools cover the conversion loop, driving screens and saved flows. Every tool addresses applications and operations by name; application and operation names are slugs: lowercase letters, digits and hyphens, starting with a letter.

ToolWhat it does
catalogDiscover what OL Next holds: applications with their operations (kind, whether generated, saved flows). applicationName narrows to one application and adds its data source. show: "examples" lists the built-in samples, "generate-options" the conversion options, and "api" the callable REST endpoints (flows and RPC programs, with method, path, body key and input/output fields) plus the OpenAPI path. show: "datasources" lists the host connections, never credentials; with a CoreIQ connection it lists that endpoint's schemas, and with schema too its tables (at most 200, filtered by match). show: "atomiq" lists the connected AtomIQ's workspaces, and with workspace that workspace's operations and whether each is importable
operationSet up and convert in one call. Creates the application and operation if missing; source takes an example, your files, or an atomiq workspace operation or .atq export, and replaces the operation's sources (16 MB per call). generate: true or an options object converts them; for your own RPC program pass generate: {kind: "rpc"} on the first convert. delete: "operation" or "application" removes it permanently. dataSource binds the application to live data: {connection, schema} for SQL, {connection, files: {CICSFILE: "DATASET"}} for VSAM, or "sample"; a bind tests itself and, for CoreIQ, reports the writes the host allows. Programs then read and write the live host. Connections are created in the console
fileslist paths and sizes, read one file or a line range, write one source file. kind: source (default) or generated (read-only)
programWithout programName: the operation's RPC programs with their commarea schemas. With it: invoke that program with request and return its response and log. action: "map" renames fields, sets direction or hides them, the same as the console's schema editor
screenOpen a session on entryProgram, then fill fields and press aidKey (default ENTER); each returns the session id, the screen and whether it is done. close: true ends it. A field the map marks secret, such as a password, comes back with secret: true and no value. Close every session you open
flowrecord-start / record-stop on a session (save: true stores the flow in the same call), save, list, read, lint, run, delete. While recording, screen's paramFields become the flow's inputs and captureFields its outputs. generate lets AI draft a flow from the operation's screens and saves it when it lints clean, never replacing an existing flow; modify changes a saved flow from an instruction. Both can take a few minutes

Typical journeys

// Convert cousr01 and make a look-up-user API
catalog   { show: "examples" }
operation { applicationName: "demo", operationName: "cousr01", source: { example: "cousr01" }, generate: true }
screen    { applicationName: "demo", operationName: "cousr01", entryProgram: "COUSR01D" }
flow      { action: "record-start", sessionId }
screen    { sessionId, fields: { USERID: "ADMIN01" }, paramFields: ["USERID"], captureFields: ["FNAME"] }
flow      { action: "record-stop", sessionId, flowName: "LookupUserFlow", save: true }
flow      { action: "run", applicationName: "demo", operationName: "cousr01", flowName: "LookupUserFlow", input: { USERID: "ADMIN01" } }
// or let AI draft the flow instead of recording it
flow      { action: "generate", applicationName: "demo", operationName: "cousr01" }
catalog   { show: "api", applicationName: "demo" }

// Pull an operation from AtomIQ and convert it
catalog   { show: "atomiq" }
catalog   { show: "atomiq", workspace: "CardDemo" }
operation { applicationName: "demo", operationName: "cotrn02c",
            source: { atomiq: { workspace: "CardDemo", operation: "COTRN02C" } }, generate: true }

// Use live host data
catalog   { show: "datasources" }
catalog   { show: "datasources", connection: "CARDDEMO-DB2", schema: "CARDDEMO", match: "CUST" }
operation { applicationName: "carddemo", dataSource: { connection: "CARDDEMO-VSAM", files: { CUSTDAT: "<dataset name>" } } }

A failed program, screen step or flow comes back as a tool error whose text says what to call next. A screen session lives on the server instance that opened it and does not survive a redeploy; open it again afterwards.

Connecting a client

On-premises standalone, on the machine running the backend, no key is needed:

{ "mcpServers": { "ol-next": { "url": "http://localhost:8080/api/mcp" } } }

From anywhere else, generate a key in Global Settings → MCP access (it is shown once) and send it:

{ "mcpServers": { "ol-next": {
    "url": "https://your-console.example.com/api/mcp",
    "headers": { "x-api-key": "olmcp_..." } } } }

Until a key exists, /api/mcp answers local callers only; once one exists, every caller must send it.

For SaaS, use the API host followed by /next/api/mcp. The client follows OAuth discovery, opens the Hub sign-in in a browser, then calls the endpoint with the Hub Bearer token:

{ "mcpServers": { "ol-next": { "url": "https://<your-api-host>/next/api/mcp" } } }

Claude Code looks for the OAuth metadata only at the API host's root, where it is not served, and fails with Dynamic Client Registration rejected (HTTP 404). Point it at the metadata explicitly:

claude mcp add-json -s user ol-next '{
  "type": "http",
  "url": "https://<your-api-host>/next/api/mcp",
  "oauth": {
    "authServerMetadataUrl": "https://<your-api-host>/next/.well-known/oauth-authorization-server"
  }
}'

Then run /mcp, choose ol-next and Authenticate. If the server was added before without that setting, remove it first (claude mcp remove ol-next -s user).

Consume a converted program over REST, OpenAPI and API Docs, or drive the conversion loop from an AI agent over MCP.

Read more