wnd-mcp lets an AI agent work mainframe (3270) and IBM i (5250) sessions the way a person does: read the screen, type into fields, press keys, run your tested procedures. It speaks the Model Context Protocol (MCP), so it works with Claude Desktop, Claude Code, Cursor, VS Code, Copilot Studio, LangChain, n8n and any other MCP client.
Unlike a screen-scraping robot pointed at a terminal, the agent works under your organization’s rules, whatever it decides. Read-only unless you say otherwise. Password fields never typed into. Card numbers and other sensitive values never reach the agent. Only the connections you list. Every action in the audit log. A sandbox that plays recordings, so you can try an agent before it goes near production.
wnd-mcp is installed with WND Terminal, next to the app (C:\Program Files\WND Terminal\wnd-mcp.exe, /Applications/WND Terminal.app/Contents/MacOS/wnd-mcp, /usr/bin/wnd-mcp). It works the sessions in WND Terminal on the same computer, through the automation API, so WND Terminal has to be open.
Setting it up
Claude Desktop. Settings > Developer > Edit Config, and add:
{
"mcpServers": {
"wnd-terminal": { "command": "C:\\Program Files\\WND Terminal\\wnd-mcp.exe" }
}
}
On a Mac the command is /Applications/WND Terminal.app/Contents/MacOS/wnd-mcp. Restart Claude Desktop, open WND Terminal, and ask: "What’s the status of customer 12345678 in Test CICS?"
Claude Code, Cursor, VS Code. The same entry in .mcp.json (Claude Code), .cursor/mcp.json or VS Code’s MCP settings.
LangChain and other frameworks. Start wnd-mcp as a stdio MCP server.
What the agent can do
On a small screen, swipe the table to read all columns.
| Tool | What it does |
|---|---|
sessions_list |
The open sessions it may use: short name, name, host type. |
session_open |
Opens a saved connection by name (only those in AgentConnections). |
session_close |
Closes a session it opened. |
screen_read |
The screen with numbered rows, the cursor, the input fields with their labels, and what it typed that hasn’t gone yet. |
screen_find |
Where text is on the screen. |
screen_wait |
Waits for text, or for the host to free the keyboard. |
field_put |
Types into an input field by row and column. Held until a key is pressed. Empty text takes it back. |
key_press |
Enter, PF1 to PF24, PA1 to PA3, Clear, PageUp, PageDown, Help, with what was typed. Judged first (below). Returns the new screen. |
code_lookup |
What an abend, CICS abend, TSO message, SQLCODE or IBM i message means, from the built-in reference. |
flow_... |
Your flows (below), with typed inputs and named outputs. |
The rules
Typing is held back until the agent presses a key. Then the key and everything typed for it are judged by the same rules as Ask WND. A command on a command line is read-only only if it’s on the list of known read-only commands (LISTCAT, SDSF ST, DSPJOBLOG, WRKSPLF ...). Typing into a data field is a change. A function key is judged by what the screen says it does, so PF3=Exit is fine and PF5=Update isn’t. Anything not known to only display or move around counts as a change.
What happens to a change is AgentActionsMode:
On a small screen, swipe the table to read all columns.
| Mode | What happens |
|---|---|
readonly (the default) |
Refused. The agent is told why and can take its typing back. |
ask |
The person at the computer sees "Claude Desktop wants to type "12345678" at row 6 column 18 and press Enter in Test CICS", with why it could change data, and chooses Allow once or Don’t allow. No answer in five minutes is no. |
allow |
Done, and recorded in the audit log. |
Always, whatever the mode:
- Password fields are never typed into, and their contents are blank to programs.
- Sensitive values are tokens: card numbers (
[CARD 1]), Social Security numbers, e-mail addresses, long account numbers, passwords in commands, on top of your MaskPatterns. The same value is the same token for the whole conversation, so the agent can still say "the card on file is the same as last month’s". It can’t type a token back. - Connections: only those in AgentConnections (all when it’s empty).
- Limits: AgentMaxSessions sessions opened at once (2), AgentKeysPerMinute keys a minute (60).
- AllowAgents = false, or AllowAutomation = false, turns agents off.
Flows, your tested procedures as tools
Read-only rules stop an agent typing a customer number into an inquiry screen, because it can’t know that field only searches. A flow says so, once, written by someone who knows the screen. It’s a WND Terminal macro with a header, saved as a .wndflow file in Documents/WND Terminal macros/Flows, or in a folder in AgentFlowFolders for everyone:
#! name: customer-lookup
#! description: Looks up a customer by their 8-digit number: name, status and balance.
#! input customer "The 8-digit customer number" pattern [0-9]{8}
#! output name "The customer's name"
#! output status "ACTIVE, CLOSED or HOLD"
#! output balance "The balance, as the screen shows it"
#! writes: no
wait "CUSTOMER INQUIRY"
move 6 18
type {customer}
press Enter
wait "STATUS:"
read name 8 10 30
read status 9 10 10
read balance 10 10 20
The agent sees a tool flow_customer_lookup with a customer input that must be 8 digits, and gets name, status and balance back (masked like everything else). writes: no flows run in every mode, and each key in them is still checked. A key the screen says could change data stops the flow. writes: yes flows follow AgentActionsMode like any change.
The sandbox
wnd-mcp --sandbox "recordings\" --flows "examples\mcp"
With --sandbox (a recording, or a folder of them), every session the agent opens is a replay host playing a recording (see the replay host), named after the file. Nothing reaches a real host. The right keys move through the recording. A wrong one shows the same screen with "REPLAY: expected PF3, got Enter". Record a person doing the task once (Session recording), then let the agent practice on it as often as you like. --strict also checks what was typed.
The audit log
Each tool call is an agent.tool event (the tool, the session and how long it took, never the screen’s text). Refusals are agent.refused with the reason. Questions to the person are agent.approval_requested, then agent.approved or agent.denied. Flows are agent.flow. The program itself connects and disconnects as automation.attach and automation.detach, named "wnd-mcp (AI agent)". On the gateway, agents connecting and leaving are agent.connect and agent.disconnect.
On the desktop, sessions are recorded as your RecordSessions policy says. To keep a recording of everything agents do, record the connections in AgentConnections. On the gateway every agent session is recorded (below).
Settings
On a small screen, swipe the table to read all columns.
| Setting | What it does |
|---|---|
| AllowAgents = false | Turns agents off. |
| AgentActionsMode | readonly (default), ask or allow. |
| AgentConnections | Connection names agents may use (* and ? allowed). Empty: any. |
| AgentFlowFolders | Folders of flows for everyone. |
| AgentMaxSessions | Sessions one agent may open at once (2). |
| AgentKeysPerMinute | Keys one agent may send a minute (60). |
On the gateway
WND Terminal in a browser (the gateway, see WND Terminal in a browser) has the same server built in, at https://<gateway>/mcp. Agents connect to it over HTTP, so nothing runs on anyone’s computer. Claude, Copilot Studio, UiPath, n8n and other agents that run in the cloud use it this way. The tools and the rules are the ones above. What differs is who the agent is, who approves its changes, and where its sessions run.
It’s off until you turn it on in the gateway’s configuration:
[mcp]
enabled = true
mode = "ask"
approvers_group = "WND Approvers"
AllowAgents = false in the policy turns it off again. The policy’s AgentActionsMode, AgentConnections, AgentFlowFolders, AgentMaxSessions and AgentKeysPerMinute hold here too. When both mode and AgentActionsMode are set, the stricter one wins.
Who the agent works for
Every request carries a token in the Authorization: Bearer header. There are two kinds.
A person’s token. The token your identity provider gives the person when they sign in to the agent: an ID token for the gateway’s client ID, or an access token for an audience you list in audiences (such as api://wnd-gateway). The gateway checks it the way it checks a sign-in: the provider’s signature, the issuer, the audience, the expiry, allowed_domains and required_groups. The agent then works as that person. It sees their sessions (with roaming sessions, the ones they have open in their browser too), it counts against their limits, PassTicket sign-on signs it on as them, and the audit log has its actions under their name.
A service account. A program that works on its own, with no person behind it. Make its token with the gateway:
wnd-gateway new-agent-token claims-bot
That prints the token, for the agent, and the lines for the configuration. The gateway keeps only the token’s SHA-256, so it can’t be shown again.
[mcp.service_accounts.claims-bot]
token_sha256 = "3f1c...e9"
connections = ["Claims (CICS)"]
flows_folder = "/srv/wnd/flows/claims"
mode = "readonly"
A service account opens only its connections (and only those AgentConnections allows too). Its tools include the flows in its flows_folder and in AgentFlowFolders. Its own mode can be stricter than the gateway’s, never less strict, and sandbox_only = true keeps it in the sandbox. Its sessions are its own: no person sees them in their browser.
In an agent’s MCP settings, the server is the URL with the header. For Claude Code (.mcp.json):
{
"mcpServers": {
"wnd-gateway": {
"type": "http",
"url": "https://terminal.bank.example/mcp",
"headers": { "Authorization": "Bearer ${WND_AGENT_TOKEN}" }
}
}
}
How it talks
MCP’s Streamable HTTP transport, protocol 2025-06-18 and earlier. The agent POSTs JSON-RPC messages to /mcp and gets JSON back. initialize starts an MCP session, and its answer’s Mcp-Session-Id header goes on every request after it. DELETE /mcp with that header ends it, and it ends by itself after 30 minutes without a request. GET /mcp answers 405, since the gateway sends nothing unasked. A request from another web site’s page (an Origin header that isn’t the gateway’s) is refused.
When the MCP session ends, the sessions the agent opened close. One the person attached in their browser stays open, as theirs.
Approvals
With mode = "ask", a change waits for a person. It goes to the Approvals page, https://<gateway>/approvals, which shows people in approvers_group the agent, who it works for, the session, what it wants to do in words ("Claude Desktop wants to type "12345678" at row 6 column 18 and press Enter"), why that could change data, and the screen as it is now with sensitive values hidden. They choose Approve or Deny. Without approvers_group, each person approves their own agent’s changes on that page, as they would at their desk. A service account’s changes need approvers_group.
No answer within approval_timeout_seconds (300) is no. The agent’s tool call waits until then, so give the agent a timeout at least that long, or set a shorter one here.
The audit log has agent.approval_requested, then agent.approved or agent.denied with the approver’s name in approver. A change nobody answered is agent.denied with no approver.
Recordings and Your open sessions
Every session an agent opens through the gateway is recorded, whatever RecordSessions says. The recording says which agent opened it and for whom, and it’s in Session recordings like any other. A person’s agent sessions show in their Your open sessions with an AI agent badge and the agent’s name. Attach one to watch what the agent does, or to take over.
The sandbox
[mcp]
enabled = true
sandbox_only = true
sandbox_folder = "/srv/wnd/sandbox"
With sandbox_only, every session an agent opens plays a recording (.wndrec) from sandbox_folder on a replay host, never a real host. Flows (.wndflow) in the folder are tools too. The replay hosts run on the gateway’s own computer, and only the sandbox session that started one can reach it. To keep only some agents in the sandbox, give their service accounts sandbox_only = true instead.
Settings
On a small screen, swipe the table to read all columns.
Setting in [mcp] |
Default | What it does |
|---|---|---|
enabled |
false |
Agents may connect at /mcp. |
mode |
"readonly" |
readonly, ask or allow. With AgentActionsMode set too, the stricter one wins. |
approvers_group |
none | The group whose members approve changes at /approvals. None: each person approves their own agent’s changes. |
approval_timeout_seconds |
300 |
How long a change waits for an answer (1 to 3600). No answer is no. |
sandbox_only |
false |
Every session agents open plays a recording. |
sandbox_folder |
none | The recordings (and flows) the sandbox plays. |
audiences |
none | Audiences accepted in people’s tokens besides sign_in.oidc.client_id. |
[mcp.service_accounts.NAME] |
none | token_sha256 (required), connections, flows_folder, mode, sandbox_only. |