MCP2Delphi
Delphi VCL bridge for exposing forms, controls, diagnostics, and tools through the Model Context Protocol.
- Active · last change 11-2-2026
- ★ 1 on GitHub
README
MCP2Delphi
MCP2Delphi is a Delphi/VCL bridge for the Model Context Protocol. It lets existing Delphi applications expose tools, resources, prompts, form state, and selected IDE automation features to local AI agents.
The project focuses on pragmatic integration with existing Delphi software: drop a component on a VCL form, start a local MCP endpoint, and let an MCP client call the exposed tools.
Status
MCP2Delphi is under active development. The runtime VCL bridge is the most stable part of the project. The Delphi IDE automation package is powerful but more experimental because it depends on ToolsAPI behavior inside RAD Studio.
Verified locally on 2026-11-01 with RAD Studio 12.x / ToolsAPI 23.0:
- Runtime package sources (
MCP2Delphi.dpk), Win32 and Win64: compiled with DCC32/DCC64, no errors or warnings. - Design-time package sources (
MCP2DelphiDesign.dpk), Win32: compiled with DCC32, no errors or warnings. - VCL example, Win32 and Win64: built and exercised through its HTTP endpoint.
- Per platform: 41 HTTP/mouse-preview checks and 11 runtime regressions passed.
- Version-tool extension: Win32/Win64 builds and 23 runtime checks per platform passed (12 new version-tool checks plus the 11 existing regressions).
- Native preview window creation, transparent/no-activate styles, focus, removal, color metadata, and actual VCL button clicks were checked.
- UTF-8/CRLF and Git whitespace checks passed.
Additional verification on 2026-11-02 for source version 2026.11.02.1:
- 64 instance-tool checks and all 28 existing runtime checks passed on each of Win32 and Win64, including authenticated HTTP and main-thread dispatch.
- Runtime packages and example applications built for both platforms; the Win32 design-time package and ordinary diagnostic application also built.
- All ten builds completed without errors or warnings. UTF-8/CRLF and Git whitespace checks passed.
These are source-build and example-runtime results. Loading the updated package into a running IDE, multiple-monitor/DPI configurations, and elevated hosts need separate interactive acceptance. Other Delphi versions are not yet verified.
Read the installed bridge version
Every TMcpServer automatically registers the read-only mcp_get_version
tool. It requires no arguments, UI thread, mouse permission, Git installation,
or additional registration. The existing endpoint token protection applies.
Call it through the authenticated MCP connection:
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"mcp_get_version","arguments":{}}}The MCP text content contains this JSON (the server values come from the host):
{
"library": "MCP2Delphi",
"library_version": "2026.11.02.1",
"source_date": "2026-11-02",
"version_scheme": "date.sequence",
"server": {"name": "delphi-mcp", "version": "0.1.0"}
}library_version identifies the bridge sources compiled into the running host.
server.version remains the application's configurable ServerVersion and
must not be used to determine the bridge source revision. On a machine without
Git, inspect CMcp2DelphiVersion and CMcp2DelphiSourceDate near the top of
Mcp.Server.pas to identify a source copy. Rebuild the host/package to update
its runtime result. The version uses year.month.day.sequence; maintainers
must increment the sequence (or date) for each distributed source revision.
The identifier is a maintained release marker, not an automatic file hash or
a check against the latest remote repository. Older bridges without this tool
will report an unknown tool until rebuilt with these sources.
Embedded help umlauts are represented by Unicode code points in the Pascal
constants, so copying the bridge into a host built with an ANSI codepage does
not corrupt them. Markdown files registered through AddFile must be UTF-8;
MCP HTTP responses explicitly use UTF-8. After upgrading these sources, rebuild
the host/package and restart the host to replace previously compiled texts.
What It Provides
- Indy-based local HTTP MCP endpoint on
/mcp - JSON-RPC support for
initialize,tools/list,tools/call,resources/list,resources/read,prompts/list, andprompts/get - VCL main-thread execution for handlers that touch UI controls
TMcpFormBridgecomponent for drop-in VCL form integration- RTTI and attribute based tool/control discovery
- Explicit instance tools for data modules and other application objects
- Typed Delphi argument/result marshalling with server-owned tool lifetimes
- Local token protection for JSON-RPC
POST /mcp - Browser status and monitoring page on
GET /andGET /mcp - Optional Delphi IDE package with ToolsAPI-based IDE automation
Repository Layout
MCP2Delphi.dproj Runtime package project
MCP2Delphi.dpk Runtime package
MCP2DelphiDesign.dproj Design-time package project
MCP2DelphiDesign.dpk Design-time package
Mcp.Server.pas Indy HTTP MCP server
Mcp.FormBridge.pas Drop-in VCL form bridge
Mcp.Attributes.pas MCP attributes for explicit discovery
Mcp.ToolRegistry.pas Tool registry and dispatch
Mcp.Types.pas JSON helpers and tool definitions
Mcp.IdeBridge.pas Delphi IDE automation bridge
Docs/ Diagrams and screenshots
Icons/ Component and project icons
TestProjects/IdeMcpDiagnostics/ Repeatable IDE diagnostics project
examples/SimpleVclFormBridge/ Minimal runtime VCL exampleDependencies and build requirements are listed in DEPENDENCIES.md.
Installation
Open the package projects in RAD Studio:
- Build
MCP2Delphi.dprojforWin32. - Build
MCP2Delphi.dprojforWin64if your application is 64-bit. - Build
MCP2DelphiDesign.dprojforWin32. - Install the design-time package in the Delphi IDE if you want the component palette entry and IDE MCP server.
RAD Studio uses the Win32 design-time package. Runtime packages are available for Win32 and Win64.
Build order:
MCP2Delphi Win32
MCP2Delphi Win64
MCP2DelphiDesign Win32Quickstart: VCL Form Bridge
Place TMcpFormBridge on a VCL form.
Defaults:
AutoStart = TrueAutoCaption = TrueDiscoveryMode = mdRtti
At runtime the bridge uses the process-wide GlobalMcpServer, registers the
standard form tools, starts the local MCP endpoint, and appends the endpoint URL
to the form caption.
Default tools:
get_form_stateclose_formset_captionlist_controlsget_control_valueset_control_valueget_form_valuesset_form_values
Supported control value properties:
TextCheckedValueItemIndex
Mouse Tools and Markdown Help
Every server also registers mouse_targets, mouse_hit_test, mouse_click,
help_list, and help_read. These use only Delphi/VCL/RTL and the Windows API.
No other project, service, external source folder, or additional binary is
required at runtime. The factory editor is a development tool only.
Start with help_list, then help_read with {"id":"mouse-help"}. The same
Markdown documents are exposed as resources under mcp2delphi://help/.
Applications can register their own help with Server.Help.AddText(...) or
Server.Help.AddFile(...); agents pass document IDs, never arbitrary paths.
The built-in README and dependency help are snapshots shipped in Mcp.Types.pas.
Mouse coordinates are physical desktop coordinates. Clicks are restricted to
enabled windows of this host process, which must be in the foreground.
Use Server.MouseEnabled := false to disable clicks and
Server.Mouse.ExcludeWindow(HWND) to protect host permission windows.
mouse_click accepts x, y, optional button (left, right, middle),
and optional count (1 or 2). No automatic retry is performed.
Before each click request, native concentric water rings expand for about
240 ms: left orange (#FF9800), right blue (#2196F3), middle violet (#AB47BC).
The overlay is input-transparent and never activates. It is removed before
rechecking the same target and submitting input. Double clicks share one
preview. Permission changes during the preview cancel the action; preview
failures prevent the click. The log records preview_color and preview_ms.
Ring size follows the target window DPI (as reported by GetDpiForWindow).
The HTML status page displays the last 200 MCP click attempts and refreshes
every two seconds. /status.json exposes the same in-memory history as
mouseClicks. Status GET requests, including this history, remain readable
without a token. Manual clicks are not recorded. sent confirms Windows input
submission, not application success. See ROADMAP.md
for limits, DPI behavior, failure handling, and the help API.
Manual Runtime Usage
uses
Mcp.Server, Mcp.FormBridge;
procedure TForm1.FormCreate(Sender: TObject);
begin
FMcpServer := GlobalMcpServer;
FMcpServer.ServerName := 'my-app';
FMcpBridge := TMcpFormBridge.Create(Self);
FMcpBridge.Server := FMcpServer;
FMcpBridge.Form := Self;
FMcpBridge.AutoRegister;
FMcpServer.Start;
FMcpBridge.ApplyMcpCaption;
end;Application-specific tools can also be registered directly:
FMcpServer.RegisterTool(
'refresh_data',
'Refresh application data.',
[],
[],
ToolRefreshData,
true);Use RunInMainThread = true for handlers that touch VCL controls.
Attribute Based Usage
Attribute discovery is for explicit MCP surfaces. Set the bridge to
mdAttributes:
McpBridge.DiscoveryMode := mdAttributes;Add RTTI for methods and fields you want the bridge to discover:
{$RTTI EXPLICIT METHODS([vcPublic, vcPublished]) FIELDS([vcPublic, vcPublished])}Then annotate form members:
uses
Mcp.Attributes;
type
TForm1 = class(TForm)
public
[McpTool('run_update', 'Update ausführen', '', 'script')]
function RunUpdate(const Arguments: TJSONObject): TJSONValue;
[McpResourceList]
function ListResources: TJSONArray;
[McpResourceRead]
function ReadResource(const Uri: string): TJSONObject;
published
[McpControl('script')]
MemoScript: TMemo;
[McpControl('dicke')]
EditDicke: TEdit;
end;Register everything in one call:
McpBridge.AutoRegister;RTTI-Only Usage
For quick automation of an existing form:
McpBridge.DiscoveryMode := mdRtti;
McpBridge.AutoRegister;Controls are published by their component names. A component named EditDicke
is addressed as:
{"name":"EditDicke"}Methods with an Mcp prefix become tools:
function McpRunUpdate(const Arguments: TJSONObject): TJSONValue;becomes:
run_updateInstance Tools from Data Modules and Other Objects
Mcp.FormBridge can expose explicitly attributed methods of any registered
TObject class, including TDataModule descendants. Methods may use normal
Delphi parameters instead of a JSON wrapper. The marshaller is included in
Mcp.FormBridge; no extra unit or package reference is needed.
Enable extended method RTTI in the unit declaring the attributed methods:
{$RTTI EXPLICIT METHODS([vcPublic, vcPublished])}
// On an application-owned data module:
[McpTool('scale', 'Multiply a value by a factor', 'Value,Factor')]
function Scale(Value: Double; Factor: Double = 1): Double;Register its class and a resolver during unit initialization. The application owns the instance and must clear its variable when freeing it:
initialization
McpRegisterInstanceTools(TCalculationModule,
function: TObject
begin
Result := CurrentCalculationModule;
end,
'calc_');This example exposes calc_scale; call it with:
{"Value":12.5,"Factor":2}For methods with pointer/class parameters, the optional fourth registration
argument can explicitly name parameters that should receive nil (for example,
'Context'). These parameters are omitted from the schema and cannot be supplied
by clients. Other unsupported parameter types are rejected.
TMcpFormBridge.AutoRegister registers instance tools regardless of
DiscoveryMode. Applications without a form bridge can instead call
McpRegisterInstanceToolsOnServer(Server) before Server.Start.
Registration is idempotent per server. Tools belong to the server and remain
available after individual form bridges are destroyed. Each server has its own
adapters. A resolver is called on the main thread for every valid invocation;
nil produces a module-not-open error, and the returned object's class is checked.
The resolver must return a live application-owned instance until the call ends.
Register all classes on the main thread before registering instance tools on any server. Later class registrations are rejected; reconnecting a client alone does not add classes. A registered class without discoverable attributed methods raises an error (also check its method RTTI directives). Overloads retain the exact RTTI method selected during registration, so separate tool names can expose separate overloads. Duplicate class/prefix registrations and collisions with existing tool names fail; a failed server registration rolls back its tools. Inherited attributed methods are included.
Argument and result rules:
- JSON keys exactly match Delphi parameter names, including case.
- Strings, signed/unsigned integers, floating point types and
Booleanare supported. Integer ranges and JSON value types are checked before invocation. ANSI/short string conversion follows Delphi's codepage and length semantics. - Every normal scalar parameter is required, even if its declaration has a
Delphi default value. RTTI does not supply declaration defaults. Missing,
null, duplicate and unknown arguments are rejected; no implicit zero/false values are substituted. In the example,Factormust be sent explicitly. var/out, records, arrays, chars and enums other thanBooleanare rejected. Pointer/class parameters require the explicit namednilopt-in above.TDateTimecurrently uses its numeric Delphi representation, not ISO text.- Scalar results become
{"result": value}. Procedures and JSON handlers returningnilproduce{"success": true}. Non-finite numeric results fail. - Classic
(const Arguments: TJSONObject): TJSONValueinstance handlers remain supported, using the attribute's schema and required fields. Returned JSON is transferred to the bridge; return a newly allocated value. - Existing tools reflected from the form itself keep their JSON-handler API.
The library source marker for this extension is 2026.11.02.1. Rebuild and
restart the host to use it. Tests are part of TestProjects/IdeMcpDiagnostics;
see its README for the MCP_INSTANCE_TESTS build and test scenarios.
Connecting an MCP Client
Runtime servers default to port 8765. The IDE server defaults to port 8776.
If a port is occupied, the server tries the next ten ports.
Example endpoint:
http://127.0.0.1:8765/mcpOpen the endpoint in a browser to see the status page:
http://127.0.0.1:8765/The status page shows the active endpoint, server version, registered tools/resources/prompts, monitoring data, and a PowerShell example for the first JSON-RPC call.
GET /status.json returns the same status and monitoring information as JSON.
Local Authorization
By default, JSON-RPC calls to POST /mcp require a local token header.
Browser status requests with GET /, GET /mcp, and GET /status.json stay
readable without a token.
On startup, TMcpServer creates a per-process token file below:
%LOCALAPPDATA%\MCP2Delphi\ServersClients send the token as:
X-MCP2Delphi-Token: <token>RequireAuthorization=false should only be used for explicit diagnostics or
isolated test runs. MCP2Delphi intentionally uses a custom header because Indy
can raise a debugger exception for unsupported Authorization schemes such as
Bearer before application code can handle the request.
MCP Protocol Compatibility
The active runtime path is JSON-RPC over HTTP POST /mcp.
Supported legacy flow:
initializetools/listtools/callresources/listresources/readprompts/listprompts/getnotifications/initialized
initialize currently reports MCP protocol version 2024-11-05.
For the MCP 2026-07-28 line, the server also accepts server/discover and
selected stateless-style calls with MCP-Protocol-Version, MCP-Method, and
MCP-Name headers. This is a compatibility path and does not replace the
established JSON-RPC flow yet.
Delphi IDE Package
MCP2DelphiDesign.dproj registers TMcpFormBridge on the MCP2Delphi
component palette page and starts an IDE-local MCP server inside bds.exe.
The IDE server:
- binds to
127.0.0.1 - uses
/mcp - defaults to port
8776 - publishes its endpoint under
HKCU\Software\MCP2Delphi\IDE - exposes ToolsAPI-based IDE automation tools
Examples of IDE tools:
ide_pingide_statuside_open_fileide_close_fileide_build_projectide_get_diagnosticside_debug_statusdebug_startdebug_stopdebug_add_breakpointdebug_get_callstackdebug_evaluate_expression
Some debugger commands are intentionally limited by the local ToolsAPI version.
For example, debug_pause and debug_step_out are registered but currently
return supported=false.
IDE-MCP also exposes guidance for agents:
- Resource
mcp2delphi://ide/how-to-control-delphi - Resource
mcp2delphi://ide/debug-workflow - Prompt
delphi-ide-control-guide
Local Discovery
The active IDE endpoint is published at:
HKCU\Software\MCP2Delphi\IDEAll runtime MCP servers additionally publish shared discovery entries at:
HKCU\Software\MCP2Delphi\Servers\<ProcessId>_<ActivePort>Relevant values include Active, Url, BindHost, ConfiguredPort,
ActivePort, ProcessId, ProcessName, ServerName,
RequiresAuthorization, StartedAt, and UpdatedAt.
Tools should prefer the published Url and fall back to probing the configured
port range only when discovery is missing or stale.
Diagnostics Project
TestProjects/IdeMcpDiagnostics contains a small repeatable diagnostics
project for IDE build and debugger workflows.
External diagnostics:
powershell -ExecutionPolicy Bypass -File TestProjects\IdeMcpDiagnostics\Run-IdeMcpDiagnostics.ps1Diagnostics through a running Delphi IDE:
powershell -ExecutionPolicy Bypass -File TestProjects\IdeMcpDiagnostics\Run-IdeMcpDiagnosticsViaIde.ps1Debugger workflow:
powershell -ExecutionPolicy Bypass -File TestProjects\IdeMcpDiagnostics\Run-IdeMcpDebugWorkflow.ps1Examples
examples/SimpleVclFormBridge contains a small VCL application that starts the
runtime MCP server, attaches TMcpFormBridge, exposes the default form/control
tools, and registers one custom echo_message tool.
Build it from a RAD Studio command prompt:
msbuild examples\SimpleVclFormBridge\SimpleVclFormBridge.dproj /t:Build /p:Config=Debug /p:Platform=Win64Documentation
- DEPENDENCIES.md: build and runtime dependencies
- ROADMAP.md: public development direction
- examples/SimpleVclFormBridge: minimal runtime VCL example
- GITHUB_PREP_AUDIT.md: first public-preparation audit
- Docs/MCP2Delphi_DataFlow.svg: data-flow diagram
License
MCP2Delphi is released under the MIT License. See LICENSE.

