Skip to content

MCP-KittoX: the MCP server

Kittox Enterprise feature

MCP-KittoX is part of the Kittoˣ Enterprise edition and ships together with KIDEx. It uses the same OnGuard license file (%CSIDL_COMMON_DOCUMENTS%\Ethea\KIDEX\Registration.ini) — a single registration unlocks both. See the Feature Matrix for the full comparison with the Open-Source edition.

MCP-KittoX is a standalone executable (MCPKittoX.exe) that exposes the functionality of KIDEx to AI agents — Claude Desktop, Claude Code, Codex, LM Studio and any other client compatible with the Model Context Protocol.

While KIDEx remains the human-facing visual IDE, MCP-KittoX is the AI-facing design tool: agents can scaffold new applications, reverse- engineer Models from a database, generate Views and Layouts, validate metadata, and refresh translation files — all conversationally, without leaving the agent.

Why use it

  • Fast onboarding: an agent can create a complete Kittox app scaffold ("scaffold an app named MyApp under D:\Dev with FireDAC, JWT auth and all 4 deployment modes") without you opening RAD Studio or KIDEx.
  • Assisted maintenance: ask the agent to validate the project, refresh the .po translation files, or propagate database schema changes back into the Model YAML files.
  • Enterprise differentiator: pair the visual IDE with an AI tool — the same way a developer pairs an IDE with an LLM-powered code assistant.

Quick start

After installing KIDEx Enterprise (which deploys MCPKittoX.exe to the same Bin\ folder as KIDEX.exe) and registering the OnGuard license, wire your MCP client:

Claude Desktop / Codex (STDIO transport)

%APPDATA%\Claude\claude_desktop_config.json (Windows):

json
{
  "mcpServers": {
    "kittox": {
      "command": "C:\\Program Files\\Ethea\\KIDEX\\Bin\\MCPKittoX.exe",
      "args": ["--stdio", "--workspace=D:\\Dev\\KittoXProjects"]
    }
  }
}

Restart Claude Desktop. The agent will discover all the tools registered by the server (currently 29 — see the Feature Matrix below) and use them autonomously when you ask for Kittox development tasks.

Test the connection

MCPKittoX.exe --version

prints MCP-KittoX 4.0.7 and exits with code 0. From a JSON-RPC client (or MCPJam Inspector), invoke meta_version to verify the license check passes:

json
{
  "name": "MCP-KittoX",
  "version": "4.0.7",
  "build_date": "2026-05-07",
  "mcp_spec": "2025-06-18",
  "kittox_version": "4.0.7",
  "license_status": "(Trial version. Expiration days: 30)"
}

Conversational example: scaffold + reverse-engineer Models

A typical end-to-end interaction once the MCP server is wired:

You"Scaffold a new Kittox app named Northwind2 under D:\Dev\Examples, then point me at the SQL Server Northwind database and generate Models for every table."

Agent

  1. Calls project_create_app (project_name Northwind2, template Basic). The wizard's defaults kick in: Auth: TextFile with the demo FileAuthenticator.txt (admin/admin), JWT envelope, AccessControl: Null.
  2. Asks you to edit Home\Metadata\Config.yaml so Databases.Main points at your SQL Server (or you tell the agent how it's reachable and it edits the file via your IDE).
  3. Calls project_open on the freshly-generated .kproj.
  4. Calls models_create_from_db with dry_run: true and shows you the proposed action tree — typically N add_model actions and a few hundred add_field / add_reference_field sub-actions.
  5. After your OK, calls models_create_from_db again with dry_run: false — this time the tool executes the actions and writes the YAML files to Home\Metadata\Models\. Returns applied: true and a summary.
  6. Calls menu_generate_main_menuMainMenu.yaml is updated with one View: Build AutoList / Model: <Name> entry per Model under a top-level Folder: Menu. The Folder: User shipped with the template (Logout / ChangePassword) is preserved.
  7. Suggests the next step (open the project in KIDEx or RAD Studio, customize the auto-generated Views or the menu, or ask the agent to drill into specific files using models_read / views_read).

The whole exchange runs without you opening RAD Studio or KIDEx — the agent uses MCP-KittoX's tools the same way it would use a filesystem or a shell tool, and the resulting Models/ is identical to what the Model Wizard would have written if you'd driven it visually.

Architecture

AspectImplementation
LibraryMCPConnect (delphi-blocks, MIT) — attribute-driven, multi-transport
SerializationNeon (MIT) — RTTI-based JSON, snake_case field naming
LoggingLogify (MIT) — meta-logging facade
Transport (current)STDIO (Claude Desktop, Codex)
Transport (planned)Indy HTTP (LM Studio, web-based clients)
MCP spec2025-06-18
Naming conventionsnake_case for tool args/results, plural scope for collections (models_list), singular-typed scope for typed creators (view_grid_create)
License gateOnGuard, shared with KIDEx; every tool method calls EnsureLicensed first; unlicensed → EKXLicenseError (EJRPCException) → JSON-RPC error visible to client

The server is a standalone executable, not embedded in your Kittox runtime nor inside KIDEx. Agents talk to it; KIDEx continues to be the human visual IDE. Both share a common headless layer so that — for instance — the models_create_from_db tool produces a Models/ folder byte-identical to what the Model Wizard writes when driven manually.

Feature Matrix

The following table tracks the implementation status of each MCP tool. Tools are organised by scope: collections use plural names (e.g. models, views) for browse/CRUD operations; typed creators use singular per-controller scopes (e.g. view_grid, view_chart) so the tool surface can grow additively without breaking changes.

Implemented (Phases 1 → 4)

ScopeToolDescriptionStatus
metameta_versionServer identity, build date, MCP spec, license status✅ Done
metameta_capabilitiesRegistered tool scopes + runtime feature flags (readonly, allow-update, allow-delete, workspace root)✅ Done
metameta_list_metadata_templatesList the YAML templates KIDEx uses as design-time defaults✅ Done
projectproject_openOpen a Kittox project (.kproj file or Home/ folder)✅ Done
projectproject_infoSnapshot of the currently-open project✅ Done
projectproject_list_appsList the application configs (Config.yaml variants)✅ Done
projectproject_closeClose the currently-open project✅ Done
projectproject_create_appGenerate a new app from a template (Empty / Basic), with full parametrization: DB drivers, auth + JWT envelope, access control, server settings, deployment modes (Standalone / Desktop / ISAPI / Apache), language, charset, theme. Default Auth: TextFile ships with a ready-to-use FileAuthenticator.txt so the generated app authenticates without a users table✅ Done
modelsmodels_listList all Models in the active project. Each call refreshes the catalog from disk so external edits to YAML files since project_open are picked up. Returns name, physical_name, display_label, plural_display_label, field_count, is_large per entry✅ Done
modelsmodels_readRead a Model YAML by name (case-insensitive lookup). Returns name (canonical casing), file_name (absolute path), content (raw YAML byte-identical to disk — comments and formatting preserved)✅ Done
modelsmodels_create_from_dbReverse-engineer Models from a database connection (the headless equivalent of the Model Wizard inside KIDEx). Reads the live schema, diffs it against the open project's Models/, and returns the proposed action tree. Defaults to dry_run: true (preview only); pass dry_run: false to commit. Output is byte-identical to what the visual Model Wizard would write. Auto-populates each Model field's DisplayLabel from the database's native column comment when present (MSSQL extended property MS_Description, PostgreSQL pg_description, Firebird RDB$DESCRIPTION, MySQL COLUMN_COMMENT, Oracle USER_COL_COMMENTS). Accepts an optional field_descriptions array — a list of {model_name, field_name, display_label, hint} overrides — for the case where the agent has descriptions in a non-DB source (CSV export, glossary, prior YAML); override wins on every non-empty property, DB-fetched descriptions are preserved for the rest✅ Done
modelsmodels_deleteDelete a Model YAML by name. Two-step safety: confirm=false (default) returns a no-op preview confirming the file exists; confirm=true executes the delete and requires the server to be started with --allow-delete. Lookup is case-insensitive. Inbound references (other Models with Reference(name), Views with Model: name) are left dangling — the agent is responsible for inspecting and cleaning them up with the read tools beforehand if needed✅ Done
modelsmodels_updateApply a list of granular operations to a Model's YAML tree and persist. Operations are {path, op, value} records applied in order, where op is 'set' (sets a node at the slash-separated path, creating missing intermediates) or 'delete' (removes a node). Two-step safety: confirm=false (default) returns a no-op preview; confirm=true executes the patch and requires the server to be started with --allow-update. Comments and original formatting of the YAML file are not preserved across the save (the tree is re-serialized)✅ Done
viewsviews_listList all Views in the active project. Same disk-refresh semantics as models_list. Returns name, display_label, controller_type, image_name per entry✅ Done
viewsviews_readRead a View YAML by name (case-insensitive). Same response shape as models_read✅ Done
viewsviews_deleteDelete a View YAML by name. Same two-step confirm=false/true + --allow-delete pattern as models_delete. Inbound references from other Views (typically MainMenu entries) are left dangling✅ Done
viewsviews_updateApply a list of granular operations to a View's YAML tree and persist. Same {path, op, value} shape and confirm / --allow-update semantics as models_update✅ Done
viewsviews_controllersDiscovery — list every controller type currently registered in the running MCPKittoX.exe binary, i.e. every value an agent can write after Controller: in a view YAML. Returns name (the registry key, e.g. 'List', 'Form', 'BorderPanel') and class_name (the underlying Delphi class) for each entry, sorted alphabetically. The list reflects the units linked in the running binary: any Enterprise add-on (Chart, Calendar, GoogleMap, Dashboard) registered via its own initialization section appears here automatically✅ Done
view_gridview_grid_createScaffold a data grid View (Type: Data with Controller: [List](List)) from a Model of the open project — the headless equivalent of KIDEx's Create DataView… context action. Output is byte-identical to the visual DataView wizard: a MainTable referencing the Model with every field as a column, a recursively-built detail-table block per detail reference, and a default FreeSearch filter over the text fields (both delegate to the framework's TKAutoListViewBuilder). model_name (required) selects the Model; view_name (optional) is the persistent file name, defaulting to the Model's plural name. Non-destructive: refuses to overwrite an existing View and reports the existing path instead — enabled by default, no --allow flag needed✅ Done
layoutslayouts_listList all Layouts in the active project (the YAML files under Home/Metadata/Views/Layouts/). Same disk-refresh semantics as models_list. Returns name, is_form_layout, is_grid_layout per entry✅ Done
layoutslayouts_readRead a Layout YAML by name (case-insensitive). Same response shape as models_read (name, file_name, content)✅ Done
layoutslayouts_deleteDelete a Layout YAML by name. Same two-step confirm=false/true + --allow-delete pattern as models_delete✅ Done
layoutslayouts_updateApply a list of granular operations to a Layout's YAML tree and persist. Same {path, op, value} shape and confirm / --allow-update semantics as models_update✅ Done
resourcesresources_listList static resources under the open project's Home/Resources/ (app) and/or the framework's shipped Home/Resources/ (system). Two-tier lookup mirrors the runtime /res/* precedence: each entry carries a source: 'app' | 'system' discriminator. Optional filters: subpath (e.g. 'icons/outlined'), pattern glob ('*.svg'), include_app / include_system, recursive. Returns path (forward-slashed, relative), source, size_bytes, mime_type per entry. Filesystem is enumerated live on every call✅ Done
resourcesresources_readRead a single static resource by forward-slashed relative path. App takes precedence over system, mirroring the runtime resolver. Text resources (text/*, JSON, XML, JS, SVG, YAML) are returned as UTF-8 in content; binaries as base64 in content_base64. Files above 1 MB return metadata only with content_too_large: true (clients can still fetch via the runtime's /res/<path> HTTP route). Path-traversal (.., drive letters, absolute) is rejected✅ Done
menumenu_generate_main_menuCreate or refresh the project's MainMenu.yaml (the TreeView referenced by the standard HomeView). Adds one inline View: Build AutoList / Model: <Name> entry under a top-level Folder: Menu for every Model in the project. Idempotent: when the file already exists, only the Models not yet referenced are appended (any hand-edited folders or entries are preserved, including the standard Folder: User with Logout / ChangePassword). When the file does not exist, the tool creates it from scratch with the standard scaffold. Single parameter file_name (default 'MainMenu')✅ Done
dbdb_list_connectionsList every database connection defined under Databases/ in the open project's Config.yaml. Returns name (the YAML key), driver ('FD' / 'DBX' / 'ADO') and display_label per entry. Credentials and connection-string sub-nodes (Password, User_Name, Server, ...) are not included✅ Done
dbdb_testTest a single database connection by opening it and immediately closing it. On success returns success: true with the driver name; on failure returns success: false with error_class + error_message captured structurally, so an agent can branch on the exception type (driver not deployed, server down, wrong credentials, OLEDB provider missing). The test goes through a standalone connection that does not pollute the runtime per-request connection pool. Lookup is case-insensitive✅ Done
dbdb_list_tablesEnumerate the tables exposed by a database connection via the framework's TEFDBInfo.Schema introspection — the same primitive the Model Wizard uses internally before diff-ing against existing Models. Opens a standalone connection, iterates Schema.Tables, returns a flat array of table names plus count. Optional include_views: Boolean (default false) merges DB views into the result (mirrors the use_views parameter of models_create_from_db). On connection failure the exception is propagated verbatim (class name + message). Use db_test first if you want a non-throwing probe✅ Done
dbdb_describe_tableDescribe a single database table via the framework's schema introspection (TEFDBInfo.Schema.FindTable) — columns with data_type (KittoX-normalized: String, Integer, Decimal, Date, DateTime, Boolean, Memo, Blob, ...), size, scale, nullable, is_pk, is_fk, native column description (when the DB exposes one); the ordered primary key column list; and the foreign keys (each with name, local columns, ref_table and ref_columns). Same primitive the Model Wizard reads to build the action tree for one table. Opens a standalone connection. On connection failure the exception is propagated verbatim. Both connection_name and table_name lookups are case-insensitive✅ Done
dbdb_introspectFull schema snapshot of a database connection — one db_describe_table-shaped entry per table the framework exposes, in declaration order. Composition of db_list_tables + db_describe_table over a single CreateDBInfo so the framework reads the metadata cursors only once (more efficient than calling db_describe_table N times). Optional include_views: Boolean (default false) extends the snapshot to DB views. Payload size grows linearly with the schema; on very large databases prefer iterating db_list_tables + db_describe_table to stream the output✅ Done
configconfig_readRead a single Config YAML by app name ('default' for Config.yaml, '<X>' for Config<X>.yaml / Config_<X>.yaml). Returns app_name, file_name, content (raw YAML, UTF-8, byte-identical to disk — no sanitization). Use project_list_apps first to discover the available app names✅ Done
configconfig_updateApply a list of granular operations ({path, op, value} with op = 'set' | 'delete') to a Config YAML and persist via the same TEFYAMLReader + TEFYAMLWriter pair KIDEx's Config Editor uses on Ctrl+S. confirm=false (default) is a no-op preview; confirm=true executes the patch and requires the server to be started with --allow-update. When the patched file is the active Config.yaml the runtime's in-memory config is invalidated so subsequent reads pick up the new state. Touches the most sensitive file in the project (DB credentials, auth/JWT keys) — the dual --allow-update + confirm=true gating exists for this reason. Comments and original formatting of the YAML are not preserved across save✅ Done
localelocale_list_languagesList every language declared under the open project's Home/Locale/ directory. Returns name (language code, e.g. 'it', 'en'), path (absolute directory), and po_count (number of .po files under <lang>/LC_MESSAGES/) per entry. Returns an empty list when Locale/ does not exist or contains no .po files. Sorted alphabetically by name✅ Done
localelocale_read_poRead a single .po file at <AppHome>/Locale/<language_name>/LC_MESSAGES/<domain>.po. Returns language_name, domain, file_name, content (raw .po text, UTF-8, byte-identical to disk). domain defaults to 'default' (KittoX uses a single domain)✅ Done
validatevalidate_configRun KIDEx's TConfigValidator headlessly against the open project's Config YAML for the requested app name. Same validator class the Config Editor invokes on the Validate Metadata button. Captures every info / warning / error log line emitted during the run (via a TEFLogEndpoint sink on TEFLogger.Instance, classifying messages by their / / source prefix) and returns per-tag counts plus the full message list. Use 'default' for Config.yaml, suffix for variants✅ Done
validatevalidate_modelsRun TModelValidator headlessly. Pass a model name (case-insensitive) to validate a single Model, empty string to validate every Model in the project. Same uniform result shape as validate_config: scope, name, file_name, per-tag counts, lines✅ Done
validatevalidate_viewsRun TViewValidator headlessly. Single view by name or empty for all. Same result shape as the other validate_* tools✅ Done
validatevalidate_layoutsRun TLayoutValidator headlessly. Single layout by name or empty for all. Same result shape✅ Done
validatevalidate_allOrchestrate the four validators (Config → Models → Views → Layouts) in sequence sharing a single log sink so the returned result aggregates info/warning/error counts and messages across all four. scope='all', name='', file_name=''✅ Done

Planned (Phase 5 and beyond)

ScopeToolDescriptionStatus
modelsmodels_generate_ddlForward-engineer CREATE/ALTER TABLE from a Model⏳ Todo
modelsmodels_apply_to_dbExecute generated DDL against the database (with two-step confirmation)⏳ Todo
modelsmodels_patch_nodeGranular edit of a single Model YAML node⏳ Todo
view_listview_list_createScaffold a List view from a Model⏳ Todo (future)
view_grouping_listview_grouping_list_createScaffold a GroupingList view⏳ Todo (future)
view_chartview_chart_createScaffold a ChartPanel view (bar/line/pie/doughnut)⏳ Todo (future)
view_calendarview_calendar_createScaffold a CalendarPanel view⏳ Todo (future)
view_googlemapview_googlemap_createScaffold a GoogleMap view⏳ Todo (future)
view_template_dataview_template_data_createScaffold a TemplateDataPanel view⏳ Todo (future)
localelocale_update_filesRun Update Locale Files headlessly: extract translatable strings from YAML metadata + Delphi sources, merge with existing .po files preserving translations⏳ Todo (Phase 3)

Safety: write operations are opt-in

By default MCPKittoX.exe exposes read tools only. Update operations require --allow-update on the command line; delete operations require --allow-delete. Delete tools further follow a two-step preview→confirm pattern: a first call with confirm: false returns the impact (would_delete, references_count, would_break: [...]); a second call with confirm: true actually executes, only if the preview is still in cache for the session.

Workspace sandboxing (--workspace=PATH) prevents path traversal outside an allowed root.

CLI flags

MCPKittoX.exe [options]

Transport:
  --stdio                 STDIO transport (default — for Claude Desktop, Codex)
  --http                  Indy HTTP transport (planned)
  --port=PORT             HTTP port (default 4000, ignored in --stdio)
  --bind=ADDRESS          HTTP bind address (default 127.0.0.1)

Project:
  --project=PATH          Project to open at startup (optional)
  --workspace=PATH        Sandbox root — projects must live underneath

Security:
  --api-key=KEY           API key required for HTTP transport
  --readonly              Disable all write tools (creates / updates / deletes)
  --allow-update          Enable *_update tools (off by default)
  --allow-delete          Enable *_delete tools (off by default)

Diagnostics:
  --log-file=PATH         Logify file destination
  --log-level=LEVEL       debug | info | warn | error (default info)
  --version               Print version and capabilities, exit

License status

When the server starts, the OnGuard license check runs. The result is:

  • printed to stderr as a one-line banner (visible when running interactively):
    [LICENSE] (Trial version. Expiration days: 30)
    [LICENSE] Software registered to "Carlo Barazzetta".
    [LICENSE] Unregistered version! You must acquire license from "support@ethea.it"
  • exposed in the JSON-RPC meta_version response under license_status (so an agent can read it and warn the user when expiration is approaching).

If the license is invalid, every tool method throws an EKXLicenseError that propagates through the JSON-RPC envelope as a structured error:

json
{"error":{"code":-32603,"message":"Unregistered version! You must acquire license from \"support@ethea.it\""},"id":2,"jsonrpc":"2.0"}

The server still answers initialize and tools/list so the client can show the tool catalog — but no tool can be invoked successfully until KIDEx is registered.

See also

Released under Apache License, Version 2.0.