Configuration
Every qrtl.config.ts option, the package.json fallbacks, and the qrtlPlugin() Astro integration options.
A plugin is configured in one file: qrtl.config.ts in the project root. It holds everything
about the plugin itself — identity, visual style, auth mode, MCP servers, widget security and the
deploy target. The two other files play supporting roles:
package.json— the npm manifest. Every identity field (name, version, description, …) is read from here unlessqrtl.config.tssets it:qrtl.config.tstakes precedence,package.jsonis the fallback.astro.config.mjs— Astro-host setup only: theqrtlPlugin()integration,output: "server"and an adapter. It contains nothing plugin-specific.
qrtl.config.ts
Author the config with a typed defineQrtlConfig({...}) default export:
import { defineQrtlConfig } from "@quartal/plugin";
export default defineQrtlConfig({
title: "My Plugin",
description: "What the plugin does, in one sentence.",
style: {
logo: "https://cdn.example.com/logo.png",
icons: [{ src: "https://cdn.example.com/icon.png", mimeType: "image/png", sizes: ["128x128"] }],
},
auth: "quartal-hub",
deploy: { org: "my-org", app: "my-plugin" },
});
The same options can also be written as qrtl.config.json (plain JSON, no defineQrtlConfig
wrapper), or as qrtl.config.mjs / qrtl.config.js. The first file found wins, in that order:
.json, .ts, .mjs, .js. A config file that exists but fails to parse or import aborts the
build with an error — fix the file rather than expecting defaults.
Identity
Every field in this group falls back to the package.json field of the same name.
| Option | Type | Purpose (and default) |
|---|---|---|
name |
string |
Identifying plugin name, e.g. @my-org/my-plugin (package.json#name). |
title |
string |
End-user-friendly title shown in docs and MCP clients (derived from the name). |
description |
string |
Short description (package.json#description). |
version |
string |
Plugin version (package.json#version). |
license |
string |
License identifier, e.g. MIT (package.json#license). |
homepage |
string |
Primary public URL (package.json#homepage). |
author |
string or object |
npm’s string shorthand "Name <email> (url)" or { name, email?, url? } (package.json#author). |
repository |
string or object |
Repository URL, or { type?, url, directory? } — directory is the plugin’s folder inside a monorepo (package.json#repository). |
keywords |
string[] |
Search keywords (package.json#keywords). |
style
Visual elements for the built-in docs site and plugin listings.
| Option | Type | Purpose |
|---|---|---|
style.logo |
string |
Logo URL for the docs front page (at least 300px wide). Defaults to the Quartal logo. |
style.skin |
string |
Bootstrap skin CSS URL (CDN), injected into the docs site shell. |
style.icons |
array | Icons in the MCP icon schema: { src, mimeType?, sizes?, theme? }. Icon bytes are served from /icons/{index} on the plugin’s own host. |
auth
The authentication mode of the whole plugin — it selects how the server app is built, for both the REST API and the MCP server:
"anon"(default) — no authentication."quartal-hub"— OAuth2 / OIDC JWT bearer authentication via Quartal Hub, zero-config (fixed test-environment scope, audience and issuer; onlyOAUTH_ISSUERis overridable). Tools receive aQuartalPluginContextas their second parameter."custom"— the same JWT bearer authentication against your own OAuth2 / OIDC server (Auth0, Microsoft Entra ID, Keycloak, …), configured entirely with environment variables:OAUTH_ISSUER(required),OAUTH_AUDIENCE/OAUTH_RESOURCE(at least one),OAUTH_SCOPE,OAUTH_JWKS_URI,OAUTH_TOKEN_URL,OAUTH_CLIENT_ID.
Widget pages and their assets stay unauthenticated (the sandboxed widget iframe carries
no credentials); auth is enforced on /api/* and /mcp. See
Authentication for the full reference including Auth0 and
Microsoft Entra ID recipes.
Changing auth requires a dev-server restart in astro dev — the config file is watched, so the
restart happens automatically when you save it.
mcp
MCP server options. Omit it entirely for the default: one MCP server at /mcp exposing every
tool. Set mcp: false to disable the MCP server.
| Option | Type | Purpose |
|---|---|---|
mcp.name |
string |
MCP server name override. Defaults to the last segment of the plugin name, e.g. my-plugin for @my-org/my-plugin. |
mcp.servers |
record | Named MCP servers (multi-server mode), keyed by server name ([a-z0-9_-]+). |
Each entry in mcp.servers is one server:
| Option | Type | Purpose |
|---|---|---|
servers.<name>.tools |
string[] |
Tool class names (from src/tools/) this server exposes. Omitted on a local server = all tool classes. Not allowed together with external. |
servers.<name>.external |
object | Declares the server as external: { url, headers? }. It is only emitted into the generated mcp.json; clients connect to the URL directly. Mutually exclusive with tools. |
servers.<name>.description |
string |
What the server exposes (shown in the plugin overview and docs). |
In multi-server mode each local server is mounted at /mcp/<name>; the server named main is
also served at /mcp. Prompts are served on main (or the first local server); each widget is
served by the server that owns its tool.
deploy
Deployment target metadata used by deploy tooling: { org?: string, app?: string } — the Quartal
Hub organization and application the plugin publishes to.
widgets
Content Security Policy for the sandboxed widget iframes, plus per-widget display names.
| Option | Type | Purpose |
|---|---|---|
widgets.csp |
object | CSP applied to every widget (see the domain lists below). |
widgets.entries |
record | Per-widget overrides keyed by tool id: { name?, csp? }. |
A CSP object lists the external domains a widget may use:
| Field | CSP directive |
|---|---|
connectDomains |
connect-src (fetch, WebSocket, …) |
resourceDomains |
scripts, styles, images and other subresources |
frameDomains |
frame-src (nested iframes) |
baseUriDomains |
document base URIs |
astro.config.mjs
In Astro config, you need to define qrtlPluginas integration, on-demand rendering (output: "server") and an adapter:
import { defineConfig } from "astro/config";
import node from "@astrojs/node";
import qrtlPlugin from "@quartal/plugin/astro";
export default defineConfig({
output: "server",
adapter: node({ mode: "standalone" }),
integrations: [qrtlPlugin()],
});
qrtlPlugin() options:
| Option | Type | Purpose |
|---|---|---|
devToolbar |
boolean |
Show the Astro dev toolbar in astro dev. We hide it by default because typically is just on the way when debugging widgets inside MCPJam etc. |