For AI agents: the complete documentation index is available at https://scriptedalchemy.github.io/agent-bundle/llms.txt, the full documentation bundle is available at https://scriptedalchemy.github.io/agent-bundle/llms-full.txt, and this page is available as Markdown at https://scriptedalchemy.github.io/agent-bundle/guide/start/quick-start.md.
Skip to main content
  • English
  • Quick start

    This walkthrough uses the MCP starter. It adds one tool without a server factory, registration array, custom transport, or second build configuration. The example needs no agent account.

    Install Node.js 22.19 or later and choose a commit whose Package preview workflow succeeded. Use that commit's immutable preview SHA below, not an npm package selected only by the unqualified agent-bundle name.

    Scaffold a project

    Replace <preview-sha> with that commit SHA:

    AB_SHA='<preview-sha>'
    npx "https://pkg.pr.new/ScriptedAlchemy/agent-bundle/create-agent-bundle@${AB_SHA}" \
      my-plugin --template mcp-server --targets portable,claude,codex
    cd my-plugin
    npm install
    npm run check

    Naming both the directory and template selects the scripted path. The preview scaffolder chooses the compiler/runtime pair from the same commit. Commit the generated lockfile; later clean checkouts can use npm ci. The installation guide explains preview selection and the separately versioned compiler/runtime pairing used by released scaffolders.

    Templates

    TemplateUse it for
    minimalStatic Skills. No MCP server or React runtime is required.
    mcp-serverConventional MCP tools with route/projection tests. The current starter also demonstrates an optional library export and an artifact script.
    cli-toolA standalone routed CLI, with a script and library example.

    The routed templates intentionally pin one known-good React and React DOM release so generated projects start reproducibly and a fresh install cannot select an incompatible peer pair.

    The scaffolder offers every target the compiler builds: amp, portable, claude, codex, and cursor. One combination is refused, amp with this MCP starter, because Amp's skill-scoped MCP contract rejects the starter's compiler-owned local status server (amp.mcp.generated-local). Project creation says so and names the templates Amp can carry, so the refusal arrives before the project exists rather than at its first build. Scaffold minimal or cli-tool for an Amp project, or author a remote or globally resolvable command server beside exactly one Skill. Adding a native target also does not imply support for that host in the live-development proxy. See host installation.

    Add your first tool

    The starter already has a status server with a report-status tool. Add src/mcp/status/tools/hello.tsx beside it:

    import { Agent } from '@agent-bundle/runtime';
    import { defineTool } from 'agent-bundle/routes';
    import { z } from 'zod';
    
    export default defineTool({
      description: 'Return a greeting without changing anything.',
      annotations: { readOnlyHint: true },
      inputSchema: z.object({ name: z.string().min(1) }).strict(),
      resultSchema: z.object({ message: z.string() }).strict(),
    }, async (input) => {
      const result = { message: `Hello, ${input.name}.` };
      return (
        <Agent.Result value={result}>
          <Agent.Text>{result.message}</Agent.Text>
        </Agent.Result>
      );
    });

    The path declares the hello tool on the status server; its framework route ID is tool:status/hello. value is the structured result, while the children describe its agent-facing presentation. Keep the result JSON-compatible and describe its actual shape with resultSchema.

    Do not add this tool to agent-bundle.config.ts or call registerTool. Adding the route file is the registration. Your domain implementation can live outside the route directory and be imported normally; it does not need another operation registry.

    Build, or work interactively

    npm run dev -- --open

    In Workbench's Application tree, select the hello tool on status, enter the input, and invoke it:

    { "name": "Ada" }

    The rendered document should say Hello, Ada. and its structured result should contain {"message":"Hello, Ada."}. Trace shows invocations, Problems shows build diagnostics, and Advanced holds lower-level inspection. A normal route invocation is not proof that an external host has installed or called the plugin.

    Edit the greeting and let the rebuild complete before invoking it again. An invalid edit keeps the last good build available with diagnostics; previous output is not evidence that the new source compiled. Workbench does not need to repeat a mutation automatically to refresh a view.

    For a one-off build instead of the dev server:

    npm run build

    Test the route

    Add tests/route-unit/hello.test.ts:

    import { expect, it } from '@rstest/core';
    import { renderRoute } from 'agent-bundle/test';
    
    it('returns the greeting as structured data', async () => {
      const rendered = await renderRoute('tool:status/hello', {
        input: { name: 'Ada' },
      });
      expect(rendered.result).toEqual({ message: 'Hello, Ada.' });
    });

    Run the ordinary test command:

    npm test

    In the MCP starter, npm test runs every test pool the project ships, the plain module tests, the route-unit pool, and the in-memory MCP projection pool, each as its own labeled run, so a route that stops rendering fails it even while the domain tests stay green. npm run check adds build and typecheck in front of it for the complete starter gate; npm run test:routes is the focused route loop. More proof levels, including real MCP processes and browser Apps, are covered in testing.

    The generated .agent-bundle/routes.d.ts must be included in the TypeScript project consuming route/provider/App types. It is generated, not an authored registry. For a standalone typecheck from a clean tree or after adding/renaming routes, refresh it first:

    npm run validate
    npm run typecheck

    An old declaration file merely existing is not a freshness check. The starter's full check already puts generation ahead of typechecking.

    Reuse the tool as a CLI command

    Add src/mcp/status/tools/hello.cli.ts:

    import type { CliProjectionConfig } from 'agent-bundle/routes';
    
    export const config = {
      command: ['hello'],
    } satisfies CliProjectionConfig;

    This is a projection of the sibling tool, not another tool or handler. Rebuild, then run the artifact's generated executable:

    npm run build
    node artifact/bin/my-plugin.mjs hello --name Ada

    The same inputSchema, route implementation, and result are used. No extra src/cli/hello.ts is needed. Use src/cli/ for a genuinely independent CLI workflow.

    Automatic flags support a bounded schema grammar. A rich nested/union schema is not guaranteed to support this named projection; do not copy or weaken the tool schema to make flags work. See package entries for the supported grammar and the existing bulk MCP-command JSON-input path.

    Or write the config by hand

    In an existing package, install a matched framework/runtime pair and the rendering/schema dependencies used by your code. A conventional route does not require a mcp.servers entry:

    import { 
    const defineConfig: (config: AgentBundleConfig | ConfigFactory) => AgentBundleConfig | ConfigFactory
    defineConfig
    } from 'agent-bundle/config';
    export default
    function defineConfig(config: AgentBundleConfig | ConfigFactory): AgentBundleConfig | ConfigFactory
    defineConfig
    ({
    AgentBundleConfig.plugin: AgentBundlePluginConfig
    plugin
    : {
    AgentBundlePluginConfig.name: string
    name
    : 'my-plugin',
    AgentBundlePluginConfig.description?: string | undefined
    description
    : 'Project tools for an agent.' },
    AgentBundleConfig.targets?: string[] | undefined
    targets
    : ['portable', 'claude', 'codex'],
    });

    Keep the version in package.json. Omitted targets select only portable. Custom local, prebuilt, and remote servers remain explicit modes; do not combine a handwritten server and generated routes under one name and rely on silent precedence.

    Inspect what the compiler decided

    Run these from a project where the intended compiler is already installed:

    npx --no-install agent-bundle inspect --routes
    npx --no-install agent-bundle validate
    npx --no-install agent-bundle validate --artifact artifact

    The first two read the authored project. The last checks the built composite artifact without needing its source. Use the route ID to connect source, Workbench, and test output.

    Install the result

    Read the generated artifact/INSTALL.md. It contains installation commands for the selected hosts and the plugin's actual names. From this developer project, the installed compiler can also perform an explicit installation:

    npx --no-install agent-bundle install claude --from artifact --scope user

    This is a host mutation, not part of build or dev. Choose the host and scope intentionally. Amp's native plugin lives in a nested directory; the framework installer resolves that from the composite root. Follow the generated instructions rather than assuming identical native install roots across hosts.

    For npm delivery, use the generated npm root and prepack gate. Consumers can follow the delivered INSTALL.md or use a package-bound installer the plugin explicitly supplies. They should not need to fetch an unrelated npm package to install it.

    Next steps

    Project structure shows how tools, CLI projections, hooks, providers, state, Skills, and browser Apps fit together. The MCP App example shows an interactive view over a real tool result; hooks explains when to use a plain handler versus a semantic event route.