Build an Extension
An Extension lives in its own repository. A typical repository contains an Extension manifest, a browser entry module, an optional provider backend, and deployment configuration for the provider’s chosen platform.
Use the Typeroll Extension starter as a GitHub template to get a working frontend, local host, provider example, manifest tooling, tests, and CI.
Prerequisites
Section titled “Prerequisites”- Node.js 22 or later;
- a Typeroll organization and a site where you have admin permission;
- an organization-scoped API key;
- HTTPS origins for production assets and provider endpoints.
In Typeroll, open Developer → Extensions, register a lowercase namespaced Extension ID, and copy the client secret when the Extension uses admin SSO. The secret is shown once and must remain server-side.
An Extension ID belongs to one developer Organization on a Typeroll host;
registering an ID that another Organization holds is refused with 409. Note
the developer_org_id of your Extension (returned on registration and by
read_developer_extension): your provider backend must check that every
Typeroll token it accepts carries this value in its developer_org_id claim
as well as your Extension ID in aud. See
Bind every token to your developer organization.
If you build from the Extension starter, add this check to its provider token
verification.
Development workflow
Section titled “Development workflow”- Add
typeroll-extension.jsonto the repository root. - Implement a browser module that exports
mount(element, props, context). - Build the frontend into immutable JavaScript and CSS assets.
- Put the exact SHA-256 asset hashes and public HTTPS URLs in the manifest.
- Validate and upload a draft.
- Install the draft on a development site owned by the same Typeroll organization and approve its requested scopes.
- Publish a private or unlisted version, or submit a public version for review.
The @typeroll/mcp-server package includes the typeroll developer CLI:
export TYPEROLL_API_URL="https://your-admin.example.com"export TYPEROLL_API_KEY="your organization-scoped API key"
npx --package @typeroll/mcp-server typeroll extension validatenpx --package @typeroll/mcp-server typeroll extension push --draftnpx --package @typeroll/mcp-server typeroll extension install --site your-site-id \ --config extension-config.jsonnpx --package @typeroll/mcp-server typeroll extension configure --site your-site-id \ --installation your-installation-id --config extension-config.jsonnpx --package @typeroll/mcp-server typeroll extension promote 1.0.0Local validation is a fast shape check. The portal remains authoritative for schema compatibility, trusted origins, permissions, configuration, and asset hash verification.
extension configure merges the schema-defined values in the JSON file into
the current installation config and queues a production deploy by default.
Omitted values, including masked secrets, are preserved. Use --no-deploy
only when applying several changes, then trigger one deploy after the last
update. The installation ID is returned by extension install and is also
shown under Settings → Extensions.
Manifest v3 replaces the old gateway transport with a direct api contract.
Provider requests must go straight from the browser to the provider backend;
do not add a Typeroll relay or a customer Cloudflare Pages Function.
For a backend-free lead tool, first create the receiving form in Typeroll,
declare it under the component’s form_bindings, and request forms:submit.
The form ID must match on the installation’s site. Its fields and post-submit
email or webhook actions remain managed in the ordinary Forms admin.
Draft and review versions can only be installed on sites owned by the
Extension’s developer organization. Other organizations can only install a
published version. A private Extension is installable by the organizations in
allowed_org_ids and on the sites in allowed_site_ids. A site id is unique
only within its organization, so name another organization’s site as
{org_id}/{site_id}; a bare site id matches only a site of the developer
organization itself. Typeroll refuses any other entry form. With the CLI, pass
--site {org_id}/{site_id} to extension install and it adds that entry; a
bare --site adds a bare id. You may change distribution while every saved
version is still a draft; Typeroll updates those draft manifests and hashes
together. Once any version has been published or submitted for review,
distribution is locked.
Develop with MCP tools
Section titled “Develop with MCP tools”The same developer API is available to agents as MCP tools when the MCP
connection uses an organization-scoped key: list_developer_extensions,
read_developer_extension, update_developer_extension,
save_extension_version, publish_extension_version,
set_extension_version_lifecycle and list_developer_extension_installations.
Over REST these are the /api/developer/extensions/** routes the CLI calls,
authenticated with Authorization: Bearer and an organization-scoped key; a
site-scoped key is refused. Registering an Extension and rotating its client
secret return the client_secret once, so they are done in the portal or the
CLI and never through MCP, where the secret would land in the agent’s
conversation. Publishing a release makes it available to every compatible
installation, so publish only after review.
Manage installations from the API and MCP
Section titled “Manage installations from the API and MCP”Everything a site administrator can do under Settings → Extensions is also
available with a site administrator API key (an owned Site, a site-scoped key
or an admin share) and through MCP. Paths are relative to
/api/v1/sites/{siteId}/extensions.
| Action | MCP tool | REST route |
|---|---|---|
| List and read installations | list_extension_installations, read_extension_installation |
GET /, GET /{installationId} |
| Install | install_extension |
POST / |
| Update configuration | update_extension_installation_config |
PATCH /{installationId} with config |
| Activate a pending release | activate_extension_release |
PATCH /{installationId} with version |
| Enable or disable | set_extension_installation_status |
PATCH /{installationId} with status |
| Uninstall | uninstall_extension |
DELETE /{installationId} |
| Diagnostics | read_extension_diagnostics |
GET /{installationId}/diagnostics |
| Pair the token issuer | pair_extension_issuer |
POST /{installationId}/pair |
| Open an admin page | launch_extension_admin_page |
POST /{installationId}/launch |
| Call an approved native admin API | call_extension_admin |
POST /{installationId}/admin-request |
Notes:
install_extensiongrants only thegranted_scopesyou pass; each must be requested by the manifest. Install, enable, disable and uninstall do not deploy. Deploy afterwards to publish the change.- The server credential is rotated in the portal (Settings → Extensions),
which shows the new
tri_…credential once. It is not available through the API or MCP, so a new credential never lands in an agent’s conversation or a log. launch_extension_admin_pagereturns a single-use launch code with thelaunch_urland theformfields to POST there beforeexpires_at, for example from a browser automation tool. The provider sees the caller asapi-key:{prefix}, and the page’sminimum_permissionapplies. Approved native admin pages are called directly withcall_extension_admininstead.- Installation credentials cannot use these routes.
Add the component to a page
Section titled “Add the component to a page”After installation, the component appears in the editor’s block picker. In HTML mode, use the provisioned block ID displayed under Settings → Extensions:
<x-extension block="extension--install-abc--quote" props='{"heading":"Your quote"}'/>This is an authoring directive, not a second script runtime. Preview and build replace it with the same inert mount shell used by a visual-editor block.
Versioning rules
Section titled “Versioning rules”Published versions are immutable. Never replace asset bytes at a URL while reusing the same version and hashes. Release a new semantic version, upload it, and let Typeroll select it automatically for compatible installations.
An installation is a timeless connection to the Extension ID. Its approved scopes never expand automatically: a new release can declare another scope, but it cannot use that scope until a site administrator grants it separately. Keep component IDs, props, configuration, and provider data backward compatible. Use a new Extension ID for a deliberately breaking product.
If none of the published releases can run with the current runtime and stored configuration, Typeroll marks the Extension unavailable and omits it from the site build. Other pages and Extensions continue to build normally.
Continue with the frontend runtime and recipient-link contract.