Catalog · How the catalog works
RadAIBridge
- ★ 1 on GitHub
Anyone may press Interesting, signed in or not. It helps others find this project.
README
RAD AI Bridge
⚠️ This entire project was designed and written by Claude Code
Every line of it — the Delphi Open Tools API plugin, the MCP server, the installer, these docs — was designed and implemented by Claude Code, Anthropic's agentic coding tool. It was built by an AI, using the very bridge it was building, driving a live RAD Studio IDE.
It is not a toy. It compiles cleanly, it has been exercised end to end against a running IDE, and the design decisions in it were made for real reasons that are documented where they were made. But you should know what you are installing: an AI-authored design-time package that loads into your IDE. Read the source before you install it, as you would with any third-party package. It is MIT licensed and comes with no warranty.
It has been tested by its author on exactly one machine, against RAD Studio 13 (Delphi 37.0) on Windows 11. Bug reports are genuinely welcome.
Lets an AI coding agent (Claude Code, Cursor, Cline, Copilot agent mode — anything that speaks MCP) drive a running RAD Studio IDE: read and write live editor buffers, manage project files, build with structured error output, drive the debugger, and inspect or edit the FMX/VCL form Designer's component tree.
Not a code generator that writes files and hopes. It talks to the IDE you already have open, through the Open Tools API, so the agent sees exactly what you see — the same buffers, the same project, the same debug session.
????????????????????????????????????????????? stdio ?????????????????????????????????????????? TCP/JSON ????????????????????????????????????????????????????????????
??? Your agent ??? ?????????????????????????????? ??? MCP server ??? ???????????????????????????????????? ??? RadAiBridge.bpl ???
??? ??? ??? (Node.js) ??? loopback ??? inside RAD Studio???
????????????????????????????????????????????? ?????????????????????????????????????????? ????????????????????????????????????????????????????????????Two pieces:
IdePlugin/— a Delphi Open Tools API package (RadAiBridge.bpl) that loads into RAD Studio and runs a small JSON-RPC server on a loopback TCP socket. No UI, no menu entry.McpServer/— a Node.js MCP server launched over stdio. It reads the plugin's published port and forwards MCP tool calls to it.
Windows only, because RAD Studio is.
Version support
| Tested on | RAD Studio 13 (Delphi 37.0), Windows 11 |
| Minimum | 36.0 — enforced by the installer, but not tested. 36.0 is the oldest release that has the ToolsAPI interfaces this uses, so it should compile; nobody has actually tried it. If you run it on 36.0, please open an issue saying whether it worked. |
| Older versions | Will not compile. The plugin uses ToolsAPI interfaces (IOTAProjectCreator190 among others) that do not exist in earlier releases. The installer refuses them with an explanation rather than dumping compiler errors. |
| Community Edition | Unverified. CE may not permit installing design-time packages. If you try it, please report what happens. |
Only one RAD Studio instance is discoverable at a time.
Installation
Before you start
You need:
- RAD Studio / Delphi, any edition that includes the command-line compiler
(
dcc32.exe) anddesignide. The installer finds it for you. - Node.js 18 or newer — nodejs.org, take the LTS build. Tick "Add to PATH" during setup (it is on by default).
- An MCP-capable AI agent, e.g. Claude Code, Claude Desktop, Cursor, Cline, Windsurf, or VS Code with Copilot agent mode.
You do not need Administrator rights, Git Bash, WSL, or any Delphi knowledge.
Step 1 — Get the files
If you have Git:
git clone https://github.com/AdriaanBoshoff/RadAIBridge.git
cd RadAIBridgeIf you do not: click Code → Download ZIP on GitHub, then extract it somewhere
permanent (for example C:\Tools\RadAIBridge). Do not run it from inside the ZIP,
and avoid a OneDrive-synced folder.
If you downloaded the ZIP, Windows marks the files as "from the internet" and PowerShell will refuse to run them. Unblock them once:
Get-ChildItem -Recurse | Unblock-File
Step 2 — Run the installer
Open PowerShell in the folder you just created (Shift + right-click the folder → Open PowerShell window here), and run:
powershell -ExecutionPolicy Bypass -File .\install.ps1Why
-ExecutionPolicy Bypass? Windows blocks PowerShell scripts by default. This allows just this one run, and changes no settings on your machine. If you would rather not,Set-ExecutionPolicy -Scope CurrentUser RemoteSignedonce, and afterwards.\install.ps1works on its own.
The installer walks through seven steps and tells you what it is doing at each one:
[1/7] Looking for RAD Studio finds your install, asks which if several
[2/7] Checking Node.js verifies version 18+
[3/7] Making sure RAD Studio is closed asks before closing anything
[4/7] Compiling the IDE plugin (Win32) runs dcc32
[5/7] Registering the package writes to HKCU, no admin needed
[6/7] Building the MCP server npm install + npm run build
[7/7] Starting RAD Studio waits until the bridge reports inA successful run ends with the live port and the exact config to paste into your agent:
Bridge is live: {"port":49452,"pid":45112,"version":"1"}
Installed.It will offer to close RAD Studio. It has to: a .bpl that a running IDE has
mapped cannot be safely replaced. Save your work before answering yes.
Useful switches:
| Switch | Effect |
|---|---|
-BdsVersion 37.0 |
Pick a RAD Studio version without being asked |
-SkipMcpServer |
Build only the IDE plugin |
-NoStart |
Do not launch RAD Studio at the end |
-CloseIde |
Close a running IDE without asking (unattended installs) |
Step 3 — Connect your agent
The installer prints a ready-made config block. For Claude Code, put this in
.mcp.json in your project folder:
{
"mcpServers": {
"rad-ai-bridge": {
"command": "node",
"args": ["C:/Users/you/Documents/GitHub/RadAIBridge/McpServer/dist/index.js"]
}
}
}CONNECTING.md has step-by-step config for Claude Code, Claude Desktop, Cursor, VS Code / Copilot, Cline, Roo Code, Windsurf, Continue, Zed, and any other MCP client, plus troubleshooting.
Two rules worth knowing now:
- Start RAD Studio before your agent. The MCP server locates the IDE through a file that only exists while RAD Studio is running.
- In JSON, write
C:\\Users\\...orC:/Users/...— a single backslash is an escape character and will break the path.
Step 4 — Install the agent skill (recommended)
skills/rad-ai-bridge/SKILL.md teaches the agent how to use these tools well —
tool ordering, batching, and how to avoid the IDE dialogs that block every call.
For Claude Code:
Copy-Item -Recurse -Force .\skills\rad-ai-bridge $env:USERPROFILE\.claude\skills\See skills/README.md for other agents.
Step 5 — Check it works
Open a project in RAD Studio, then ask your agent something like "what project is
open in RAD Studio?". It should answer using getProjectInfo.
If not, test the plugin directly, bypassing the agent entirely:
node .\IdePlugin\tools\call.js getProjectInfoIf that works, the plugin is fine and the problem is your agent's MCP config — see CONNECTING.md. If it does not, the plugin did not load: in RAD Studio check Component → Install Packages for RAD AI Bridge.
Uninstalling
powershell -ExecutionPolicy Bypass -File .\uninstall.ps1Unregisters the package from every RAD Studio version and removes the discovery
file. Add -DeleteBuildOutput to also delete compiled output. Your copy of the
repository is left alone — delete the folder yourself.
Updating
git pull
powershell -ExecutionPolicy Bypass -File .\install.ps1Tool reference
43 tools:
| Area | Tools |
|---|---|
| Editor | getEditorContent, getEditorLines, setEditorContent, applyEdit, openFile, saveFile, listOpenFiles |
| Project | getProjectInfo, openProject, addFileToProject, removeFileFromProject, setProjectPlatform, listBuildConfigurations, listProjectOptions, getProjectOption, setProjectOption |
| Creation | createProject, createUnit, createForm, addUsesUnit |
| Build | compileProject |
| Designer | getFormTree, addComponent, deleteComponent, selectComponent, getComponentProperties, setComponentProperty, setComponentProperties, setComponentEvent |
| Debugger | runProject, stepOver, stepInto, stepOut, runToCursor, terminateProcess, addBreakpoint, removeBreakpoint, removeAllBreakpoints, listBreakpoints, getCallStack, evaluateExpression |
| Visual | captureScreenshot |
| Diagnostics | listIdeActions |
captureScreenshot is the one worth knowing about
Every other tool describes the application structurally — a component tree, a property value, a compiler message. None of that tells an agent whether the UI actually looks right: controls overlapping, text clipped, a layout that collapses at a different size, a form that is blank because an exception ate the constructor.
captureScreenshot returns real pixels as an image the agent can see:
target: "app"— the program running under the debugger. This is how an agent verifies its own UI work instead of assuming it from the component tree.target: "ide"— RAD Studio itself, which is how an agent reads a modal dialog that is blocking every other call.
It uses PrintWindow with PW_RENDERFULLCONTENT, so the window does not need to
be focused or unobscured, and FMX's GPU-composited rendering captures correctly
rather than coming back black.
McpServer/src/index.ts carries the authoritative list with full parameter
descriptions.
Developing the bridge itself
Rebuild loop
A .bpl cannot hot-reload, so every plugin change needs a full IDE restart:
.\IdePlugin\rebuild.ps1Compiles, closes the IDE, deploys, restarts, and waits until the bridge reports in.
rebuild.sh is the same thing for Git Bash/WSL, if you prefer it — but nothing in
this project requires bash.
Never copy over a deployed .bpl while an IDE has it mapped. The copy appears
to succeed but leaves an image the next IDE start silently fails to load — no error
dialog, the package simply never appears in the process. Both rebuild scripts close
the IDE first to make that impossible. To check whether it loaded:
(Get-Process bds).Modules | Where-Object ModuleName -like '*RadAi*'Talking to the plugin without an agent
IdePlugin/tools/call.js drives the RPC socket directly. An MCP client usually
cannot be made to reconnect on demand, so without this, every plugin change would
need an agent restart just to exercise one tool.
node .\IdePlugin\tools\call.js getProjectInfo
node .\IdePlugin\tools\call.js addBreakpoint 'filePath=C:\src\MainFormU.pas' line=74
node .\IdePlugin\tools\call.js getCallStack maxFrames=8Parameters are key=value, parsed as JSON where that succeeds and kept as plain
strings otherwise — so Windows paths need no escaping.
When a call hangs
.\IdePlugin\tools\dismiss-ide-modal.ps1 # report what is showing
.\IdePlugin\tools\dismiss-ide-modal.ps1 -Button No # click a buttonSecurity
Worth understanding before you install something that can write to your source tree.
What the plugin exposes. It listens on a TCP socket bound to 127.0.0.1
only, on an OS-assigned ephemeral port. It is not reachable from your network,
and binding is not configurable. The port is written to
%APPDATA%\RadAiBridge\bridge.json so the MCP server can find it.
There is no authentication. Any process running as you on your machine can connect to that port and drive your IDE — read and write editor buffers, change project files, compile, and start your program under the debugger. On a normal single-user development machine that is the same trust boundary as your shell and your editor's own plugins. On a shared or multi-user machine, understand that anything you are logged in as can use it. Do not run this on a machine where you would not also hand out shell access.
What your agent can do. The tool surface is deliberately powerful — that is
the point of the project. An agent with this connected can modify and overwrite
your source, and run code. Use version control, and commit before letting an
agent work unsupervised. setEditorContent replaces whole files; there is no
undo beyond the IDE's own.
The plugin loads into your IDE process. It is a design-time package, so it
has the same access to your machine as RAD Studio itself. It was written by an
AI (see the top of this file) and reviewed by one person. Read
IdePlugin/src/ before installing it — it is about 4,000 lines and the socket
code is all in RadAiBridge.Json.Rpc.pas.
Known limitations
- Any modal dialog in the IDE blocks every bridge call. Tool handlers run on the
IDE main thread, so while a dialog is up, calls queue until it is dismissed. They
fail after 120s with a message naming the likely cause rather than hanging
forever. Common culprits: "Source has been modified. Rebuild?", third-party
wizards that prompt on component creation (CnPack's component-name dialog is a
frequent one), and unsaved project groups. Routing work through a posted window
message instead of
TThread.Synchronizedoes not avoid this — a modal's own message loop does not dispatch the posted work. An agent can at least see what is blocking it:captureScreenshotwithtarget: "ide"is registered raw rather than marshalled, and its code path is pure Win32 —EnumWindows,PrintWindow, GDI, WIC — with no ToolsAPI call in it, so there is nothing in it for a modal to block. (target: "app"does need one ToolsAPI lookup to find the debugged process, so that variant will stall behind a modal.) This is an architectural property of the code rather than something measured against every dialog the IDE can raise. - One IDE instance at a time. The discovery file holds a single port; a second instance overwrites it. Shutdown is at least PID-checked, so an instance closing will not delete a newer instance's entry.
- The plugin is Win32 only.
bds.exeis a 32-bit process, so design-time packages must match it. This has no bearing on what platforms your projects target. compileProjectshells out tomsbuildviarsvars.batrather than using the IDE's internal message view, whose API is thinly documented. Clean structured errors, slightly slower than an in-process build. It runs off the main thread so the IDE stays responsive, and fullmsbuildoutput is returned only on request (includeRawOutput: true) or when a failure could not be parsed.runToCursordepends on the editor's current caret position, which the bridge does not set for you.
What is missing
Being specific about the gaps is more useful than a feature list. These are the things an agent will reach for and not find:
- No project-wide search. There is no "find this symbol across the project".
An agent has to open files it already knows about. In practice, use ordinary
filesystem grep for discovery and the bridge for anything that needs the live
IDE — but remember unsaved buffers will not be on disk (see
saveFile). - No symbol navigation. No go-to-definition, no find-references, no type hierarchy. The IDE knows all of this; none of it is exposed yet. This is probably the single highest-value addition.
- No way to interact with the running app.
captureScreenshotcan see the program, but nothing can click a button or type into it, so an agent cannot exercise a UI flow end to end on its own. - No test integration. No test discovery, no run-and-report for DUnit/DUnitX.
- Designer tools act on whatever form is currently open. They are stateful in a way the rest of the API is not, which makes them the easiest part to misuse.
- No
gitor version-control awareness. Deliberate — that is the host agent's job, not the IDE plugin's.
Contributions welcome. Notes for anyone extending this, below, covers the
non-obvious parts of the Open Tools API that cost the most time to work out.
Notes for anyone extending this
A few things cost real time to work out. They are commented in the source, but are worth repeating:
IOTAProjectCreator.GetFileNamemust return the.dpr, never the.dproj. The IDE resolves the project-type handler from that extension, and a.dprojmatches nothing — the nil result is then dereferenced, giving an access violation insidedelphicoreide*.bplwith no hint as to the cause.GetFrameworkTypemust return exactly'FMX'or'VCL'.'FireMonkey'is accepted and silently stored as a third, meaningless framework, after which the IDE warns that your units are incompatible with the project.IOTAModule.Save(ChangeName, ForceSave)has no "prompt" parameter.ForceSave = Trueis what suppresses the "Save changes to X?" dialog.IOTAThread.CallHeadersandGetCallPosare one-based. Indexing from 0 trips an assertion inside the debug kernel (item.src,DBKIMPL.CPP) which raises a modal error dialog — which then blocks the bridge, so the visible symptom is a hang that points nowhere near the indexing.IOTAEditActionsis implemented by the edit buffer, not byIOTAEditor, so castingModule.CurrentEditorto it can never succeed. Run and stepping go throughINTAServices.ActionListinstead, which needs no focused editor. The action names are undocumented and have changed between releases — uselistIdeActionsto discover them rather than guessing.

