Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Catalog · How the catalog works
Anything · Lazarus or Delphi
Random projectRandom project

MCP2Delphi

Delphi VCL bridge for exposing forms, controls, diagnostics, and tools through the Model Context Protocol.

View on GitHub

Member rating

No ratings yet.

Sign in to rate this project.

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:

json
{"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):

json
{
  "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, and prompts/get
  • VCL main-thread execution for handlers that touch UI controls
  • TMcpFormBridge component 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 / and GET /mcp
  • Optional Delphi IDE package with ToolsAPI-based IDE automation

Repository Layout

text
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 example

Dependencies and build requirements are listed in DEPENDENCIES.md.

Installation

Open the package projects in RAD Studio:

  1. Build MCP2Delphi.dproj for Win32.
  2. Build MCP2Delphi.dproj for Win64 if your application is 64-bit.
  3. Build MCP2DelphiDesign.dproj for Win32.
  4. 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:

text
MCP2Delphi Win32
MCP2Delphi Win64
MCP2DelphiDesign Win32

Quickstart: VCL Form Bridge

Place TMcpFormBridge on a VCL form.

Defaults:

  • AutoStart = True
  • AutoCaption = True
  • DiscoveryMode = 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_state
  • close_form
  • set_caption
  • list_controls
  • get_control_value
  • set_control_value
  • get_form_values
  • set_form_values

Supported control value properties:

  • Text
  • Checked
  • Value
  • ItemIndex

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

pascal
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:

pascal
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:

pascal
McpBridge.DiscoveryMode := mdAttributes;

Add RTTI for methods and fields you want the bridge to discover:

pascal
{$RTTI EXPLICIT METHODS([vcPublic, vcPublished]) FIELDS([vcPublic, vcPublished])}

Then annotate form members:

pascal
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:

pascal
McpBridge.AutoRegister;

RTTI-Only Usage

For quick automation of an existing form:

pascal
McpBridge.DiscoveryMode := mdRtti;
McpBridge.AutoRegister;

Controls are published by their component names. A component named EditDicke is addressed as:

json
{"name":"EditDicke"}

Methods with an Mcp prefix become tools:

pascal
function McpRunUpdate(const Arguments: TJSONObject): TJSONValue;

becomes:

text
run_update

Instance 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:

pascal
{$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:

pascal
initialization
   McpRegisterInstanceTools(TCalculationModule,
      function: TObject
      begin
         Result := CurrentCalculationModule;
      end,
      'calc_');

This example exposes calc_scale; call it with:

json
{"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 Boolean are 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, Factor must be sent explicitly.
  • var/out, records, arrays, chars and enums other than Boolean are rejected. Pointer/class parameters require the explicit named nil opt-in above. TDateTime currently uses its numeric Delphi representation, not ISO text.
  • Scalar results become {"result": value}. Procedures and JSON handlers returning nil produce {"success": true}. Non-finite numeric results fail.
  • Classic (const Arguments: TJSONObject): TJSONValue instance 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:

text
http://127.0.0.1:8765/mcp

Open the endpoint in a browser to see the status page:

text
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:

text
%LOCALAPPDATA%\MCP2Delphi\Servers

Clients send the token as:

text
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:

  • initialize
  • tools/list
  • tools/call
  • resources/list
  • resources/read
  • prompts/list
  • prompts/get
  • notifications/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_ping
  • ide_status
  • ide_open_file
  • ide_close_file
  • ide_build_project
  • ide_get_diagnostics
  • ide_debug_status
  • debug_start
  • debug_stop
  • debug_add_breakpoint
  • debug_get_callstack
  • debug_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:

text
HKCU\Software\MCP2Delphi\IDE

All runtime MCP servers additionally publish shared discovery entries at:

text
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:

text
powershell -ExecutionPolicy Bypass -File TestProjects\IdeMcpDiagnostics\Run-IdeMcpDiagnostics.ps1

Diagnostics through a running Delphi IDE:

text
powershell -ExecutionPolicy Bypass -File TestProjects\IdeMcpDiagnostics\Run-IdeMcpDiagnosticsViaIde.ps1

Debugger workflow:

text
powershell -ExecutionPolicy Bypass -File TestProjects\IdeMcpDiagnostics\Run-IdeMcpDebugWorkflow.ps1

Examples

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:

text
msbuild examples\SimpleVclFormBridge\SimpleVclFormBridge.dproj /t:Build /p:Config=Debug /p:Platform=Win64

Documentation

License

MCP2Delphi is released under the MIT License. See LICENSE.