KYTE-#325 PR B: MCP schema-management tools + schema scope#109
Merged
Conversation
…odels) — PR B
KYTE-#325 PR B. Lets a `schema`-scoped MCP token create and migrate data
models from Claude, where each change applies a real DDL migration via the
DataModel/ModelAttribute controllers in internal mode (mirrors the #322
SiteTools pattern).
- New `schema` scope in KyteMCPTokenController::VALID_SCOPES, separate from
`provision` (model-migration rights independent of site spin-up/tear-down).
- ModelTools write tools (all #[RequiresScope('schema')]):
create_model, add_attribute, update_attribute, rename_model;
remove_attribute (DROP COLUMN) and delete_model (DROP TABLE) behind a
required confirm_destructive flag.
Every caller-supplied model/attribute id is re-scoped to the token's
account before use; foreign ids are rejected.
- rename_model registers the app's model constants via Api::loadAppModels
first — DataModelController::update guards on defined($o->name), which the
HTTP pipeline satisfies at routing but the MCP path (routing-bypassed) does
not.
- Model-layer hardening surfaced by the partial MCP payloads:
* prepareModelDef reads optional flags/defaults defensively (no
undefined-property warning / null-to-strlen deprecation when a caller
omits protected/password/defaults/unsigned).
* loadAppModels skips rows with a missing/corrupt model_definition
instead of define()-ing a null model name, and no longer re-defines an
already-defined constant.
Tests: McpModelToolsTest extended with write coverage (create/add/update/
rename, decimal precision/scale reaching the physical column, destructive-op
confirm gating, FK-dependency block, and cross-account isolation), driving
real DDL against the test DB via a dedicated password-bearing app user.
PHPStan level 1 (php:8.2-cli, 512M) green; unit suite 256/256 green vs
MariaDB 10.5.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
KYTE-#325 — PR B (MCP schema-management tools)
Builds on PR A (#108). Lets a
schema-scoped MCP token create and migrate data models from Claude, where each change applies a real DDL migration viaDataModelController/ModelAttributeControllerin internal mode (mirrors the #322SiteToolspattern).New scope
schemaadded toKyteMCPTokenController::VALID_SCOPES, held separately fromprovision(model-migration rights independent of site spin-up/tear-down). Not hierarchical.New tools (
ModelTools, all#[RequiresScope('schema')])create_modeladd_attributeforeign_key_modelupdate_attributenamerequired (full column def rewritten)rename_modelremove_attributeconfirm_destructive=truedelete_modelconfirm_destructive=trueEvery caller-supplied model/attribute id is re-scoped to the token's account; foreign ids are rejected.
read_model/list_modelsalready existed.Why
rename_modelcallsloadAppModelsDataModelController::updateguards ondefined($o->name)— the model must be registered as a runtime constant. The HTTP pipeline does this viaApi::loadAppModelsat routing, but the MCP path bypasses routing, so the tool registers the app's models first (same asAppModelWrapperController).Model-layer hardening (surfaced by partial MCP payloads)
DataModelController::prepareModelDefreads optional flags/defaults defensively — no undefined-property warning / null-to-strlen deprecation when a caller omitsprotected/password/defaults/unsigned.Api::loadAppModelsskips rows with a missing/corruptmodel_definition(instead ofdefine()-ing a null name) and no longer re-defines an already-defined constant.Tests
McpModelToolsTestextended with write coverage: create / add / update / rename, decimal precision/scale reaching the physical column, destructive-op confirm gating, FK-dependency block, and cross-account isolation — driving real DDL against the test DB via a dedicated password-bearing app user (Api::dbappconnectrejects empty passwords).Verification
php:8.2-cli,-d memory_limit=512M) — green.Follow-ups (not in this PR)
schemaon dev token [FEATURE] Add option to enable module for existing, new, and inline JavaScript #8 once deployed to dev19.🤖 Generated with Claude Code