MyronCMS Developers Hub Docs sandbox review

Content Capabilities

Register A MIC Type

Register a MIC type when an extension needs reusable content that can be inserted into rich-text fields by token. The extension owns the resolver code and any backing storage. MyronCMS owns registration, discovery, and rich-text token resolution.

This tutorial registers a catalog MIC type for my_vendor.

Prerequisites

  • An extension package exists under app/extensions/my_vendor/.
  • manifest.json declares the extension identity and required scopes.
  • The extension can be registered, enabled, and granted content.read.
  • The resolver can read its backing content without crossing another extension's storage boundary.

Human Path

Create a resolver class:

<?php

declare(strict_types=1);

final class MyVendorCatalogMicResolver implements MicElementResolverInterface
{
    public function __construct(private readonly MyronExtensionSDK $sdk)
    {
    }

    public function resolve(string $id, array $context): ?string
    {
        if (!preg_match('/^mic_[a-f0-9]{16}$/', $id)) {
            return null;
        }

        $label = 'Catalog item ' . substr($id, -4);
        return '<article class="my-vendor-catalog-card" data-mic-id="' . myronEscape($id) . '">'
            . '<h3>' . myronEscape($label) . '</h3>'
            . '<p>Reusable extension content.</p>'
            . '</article>';
    }

    public function describe(): array
    {
        return [
            'slug' => 'x.my_vendor.catalog',
            'label' => 'Catalog Item',
            'description' => 'Reusable catalog block.',
            'icon' => 'box',
            'scopes' => [MyronApiScopes::CONTENT_READ],
            'bankSurface' => 'picker',
            'parentSurfaceUrl' => $this->sdk->buildAdminUrl('x.my_vendor.catalog'),
        ];
    }
}

Return it from bootstrap.php:

<?php

declare(strict_types=1);

require_once __DIR__ . '/MyVendorCatalogMicResolver.php';

return [
    'micElementTypes' => [
        'catalog' => new MyVendorCatalogMicResolver($sdk),
    ],
];

The bootstrap.php key is the local slug: catalog. The registry constructs the full extension type: x.my_vendor.catalog. The resolver descriptor must report that full slug.

Insert tokens using:

[mic-x.my_vendor.catalog-mic_0123456789abcdef]

AI Path

An AI coding agent can author the resolver file and bootstrap.php locally, then run verification. It should not invent runtime install automation, write directly to extension grant tables, or claim that an installed MCP client can create PHP files.

After a human operator registers and grants the extension, an AI client with content.read can discover loaded MIC descriptors through the content MIC type listing action. If that action is exposed through MCP for the caller, it appears in MCP tools/list.

Descriptor Fields

FieldRequiredUse
slugYesFully qualified type, such as x.my_vendor.catalog.
labelYesHuman-readable type label for UI and discovery.
descriptionYesShort explanation for pickers and AI clients.
iconYesSmall icon identifier for UI presentation.
scopesYesScope metadata required by this content type.
bankSurfaceYesOne of editor, picker, or none.
parentSurfaceUrlRequired for pickerAdmin URL where entries are managed.
adminUrlOptionalAdditional admin URL metadata.

Scopes

Use content.read for read-only insertion and discovery. If the resolver depends on write actions or admin configuration, document those separately in the extension action or admin-route docs. MIC type registration itself does not authorize separate writes.

Artifacts

Files:

  • app/extensions/my_vendor/MyVendorCatalogMicResolver.php
  • app/extensions/my_vendor/bootstrap.php
  • optional extension storage under {vendor}_*

Runtime:

  • MicElementRegistry::registerExtension('my_vendor', 'catalog', $resolver)
  • /api/v1/content/mics/types
  • [mic-x.my_vendor.catalog-mic_0123456789abcdef]

Safety Boundary

Do not pass a fully qualified x.* slug as the bootstrap.php key. The extension loader passes the vendor and local slug to the registry. The descriptor then confirms the fully qualified slug.

Do not return unsafe HTML. Resolver output should be deterministic, escaped where it includes data, and limited to the extension's documented content surface.

Verification

Run:

php app/tests/verify-mic-registry.php

Then verify the extension runtime state:

  1. The extension is registered, enabled, and granted content.read.
  2. knownTypes() contains x.my_vendor.catalog.
  3. /api/v1/content/mics/types returns the descriptor for a content.read caller.
  4. A token shaped like [mic-x.my_vendor.catalog-mic_0123456789abcdef] resolves in rich text.

Failure Modes

FailureWhat it meansSafe response
Mic extension vendor must be snake_case.Vendor is empty or not snake_case.Align directory, manifest, and vendor naming.
Extension mic slug must be the local slugbootstrap.php used x.my_vendor.catalog as the key.Use catalog as the key.
Mic resolver descriptor slug must match the registered slug.describe() returned the wrong slug.Return x.my_vendor.catalog.
Mic bankSurface must be editor, picker, or none.Descriptor used an unsupported surface.Choose one of the implemented values.
Picker mic types require parentSurfaceUrl.bankSurface is picker without a parent URL.Add a parent admin surface URL.
Duplicate type rejectedAnother resolver already registered the same slug.Choose a unique local slug.