Start Here
Verify Your Extension
Use three layers of verification for a new extension:
- CLI substrate verification.
- Direct API action verification.
- MCP tool discovery and call verification.
The CLI check proves the extension system foundation. API and MCP checks prove the extension is usable inside a running install after registration, enablement, scope grants, and exposure.
Human Path
Run the local smoke test first:
php app/tests/verify-extension-system-foundation.php
For a hello-world extension, register the extension from the Extensions admin surface and grant content.read. Then call the action over /api/v1/x/{vendor}/... with a caller that holds content.read.
AI Path
An AI coding agent can run the CLI test from the repository and report failures against the local files. It can also prepare API or MCP requests for an operator-supplied local install.
An installed MCP client can verify only runtime-visible behavior. It can list and call tools exposed by registered actions, but it cannot author extension PHP files or grant itself scopes.
Verification
Complete verification in this order:
- Run the CLI smoke test locally.
- Confirm the extension is registered, enabled, and granted the required scope.
- Call the extension action through
/api/v1/x/{vendor}/.... - Confirm the action appears in MCP
tools/listfor a scoped caller. - Call the action through MCP
tools/call.
If an earlier layer fails, fix that layer before interpreting later API or MCP results.
Scopes
The hello-world guide uses content.read. Verification needs that scope in two places:
- the extension's granted scopes must include
content.read, - the API or MCP caller must hold
content.read.
If either gate is missing, the action should not be callable.
Artifacts
The main local verification artifact is:
app/tests/verify-extension-system-foundation.php
That test creates an isolated SQLite database in the system temp directory, configures a local dev bearer token, boots MyronCMS, and verifies the extension foundation.
What The CLI Test Proves
verify-extension-system-foundation.php checks:
- extension grant and load-error tables exist,
- the sample manifest parses,
- vendor mismatches are rejected,
- unknown manifest scopes are rejected,
- valid extension actions resolve,
- invalid URI/domain/schema actions are rejected,
- the sample extension can be registered and granted,
- the loader mounts the sample admin route,
- sample migrations create prefixed tables,
- the sample action dispatches with a
content.readtoken, - non-prefixed migration SQL is rejected,
- bootstrap exceptions are recorded as load errors,
- the Extensions rail section appears for administrators and is hidden from non-administrators.
The expected output is:
Extension system foundation verification passed.
API Verification
Use the direct API path after the extension is registered, enabled, and granted:
curl -sS \
-H "Authorization: Bearer ${MYRON_TOKEN}" \
"https://example.test/api/v1/x/my_vendor/hello"
The token must resolve to a caller with content.read. In local development, MyronCMS can accept MYRON_AI_DEV_BEARER_TOKEN when not in production mode; production installs should use an AI integration token or another supported authenticated caller path.
A successful response uses the action envelope:
{
"ok": true,
"result": {
"message": "Hello from my_vendor extension",
"siteType": "BIZ"
},
"error": null
}
Additional envelope fields such as actionId and auditEventId may also be present.
MCP Verification
Use MCP after the same runtime conditions are true:
- extension is registered,
- extension is enabled,
- extension is granted required scopes,
- action metadata has
exposeToMcp: true, - MCP caller holds
content.read.
Send tools/list to /mcp with the caller's Authorization header. For the hello-world tutorial, the default normalized tool name is:
x_my_vendor_hello_hello_get
Then call it with an empty argument object:
{
"jsonrpc": "2.0",
"id": "hello-1",
"method": "tools/call",
"params": {
"name": "x_my_vendor_hello_hello_get",
"arguments": {}
}
}
The MCP server delegates the call through the same action dispatcher used by /api/v1/....
Failure Modes
| Symptom | Likely cause | Check |
|---|---|---|
auth_required | Missing bearer token or session caller. | Send Authorization: Bearer ... or use an authenticated session path. |
auth_invalid | Token does not match an active integration, deployment token, or local dev token. | Verify token source and environment mode. |
scope_insufficient | Caller lacks the action's required scope. | Grant or use a caller with content.read. |
action_not_found | No registered action matches method and URI. | Check extension registration, enablement, loader status, URI, and method. |
Tool missing from tools/list | Action is not exposed or caller lacks scope. | Check exposeToMcp:true and caller scopes. |
| Manifest rejected | Invalid JSON, vendor mismatch, missing name/version, or unknown scope. | Check manifest.json against ExtensionManifest.php. |
| Loader skips extension | Extension is unregistered or disabled. | Check the Extensions admin surface. |
| Load error recorded | Bootstrap, migration, or manifest failure. | Check Installed Extensions load error details. |
| Migration rejected | SQL touched a non-{vendor}_* table. | Keep extension storage isolated. |
| Empty schema rejected | Action metadata used [] for input or output schema. | Use object schemas, even for no-input actions. |
Safety Boundary
Do not weaken verification to make a failing extension pass. If the failure requires new runtime behavior, stop and route the work through Evaluate and Contract before expanding the SDK.