npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@montageai/sdk

v0.3.1

Published

Montage SDK — call the Montage API from any JS/TS app and render generated UI artifacts.

Downloads

263

Readme

@montageai/sdk

The Montage SDK turns any LLM into a UI-rendering agent. Add montage_generate to your tool registry, hand the resulting HTML to the SDK's <HtmlBlock> (or mount the bundled HTML yourself), and your model can produce dashboards, charts, reports, forms, and full mini-applications instead of plain text.

The SDK is API-driven — every render goes through the Montage rendering service. The package contains:

  • A typed createMontageTools() factory that calls POST /v1/generate
  • Framework adapters for Mastra, LangChain, and the Vercel AI SDK
  • A React <HtmlBlock> component that mounts self-contained bundled HTML and executes the artifact's inline scripts
  • Agent-host primitives — createMontageAdapter() and bindMontageCapabilityBridge() — for routing explicit artifact capability calls to host functions

Install

pnpm add @montageai/sdk
# or
npm install @montageai/sdk

react and react-dom are optional peer dependencies — only required if you use the @montageai/sdk/react entry point.

Quick start

Get an API key from https://usemontage.ai, then:

createMontageTools() sends your API key as a Bearer token and should run in trusted server-side code: API routes, workers, server actions, or agent runtimes. Browser apps should call your server and render the returned HTML with <HtmlBlock>.

import Anthropic from "@anthropic-ai/sdk";
import { createMontageTools } from "@montageai/sdk";

const client = new Anthropic();
const montage = createMontageTools({ apiKey: process.env.MONTAGE_API_KEY! });

const response = await client.messages.create({
  model: "claude-opus-4-7",
  max_tokens: 4096,
  tools: montage.anthropic(),
  messages: [
    { role: "user", content: "Show me a Q4 revenue dashboard" },
  ],
});

for (const block of response.content) {
  if (block.type === "tool_use" && block.name === "montage_generate") {
    const result = await montage.execute(block.input as Parameters<typeof montage.execute>[0]);
    console.log(result.html); // ready-to-render HTML
  }
}

montage.execute({ prompt, dataInfo, outputQuality?, designSystem? }) returns { id, html, creditsUsed }.

Use prompt as a product-level render brief, not an internal source format or low-level layout blueprint. A good brief names the goal, audience, workflow, entities, required interactions, starting state, constraints, and anti-goals. For import/upload workflows, say the artifact needs a real file picker and include expected file types and fields in dataInfo.

Design systems

Pass a partial designSystem to brand the output. Pixel values are RGB hex; the server fills in the rest from the default Montage system and inlines the resulting CSS in the bundled artifact.

const result = await montage.execute({
  prompt: "Show me a brand-aligned project status page",
  dataInfo: '{"projects":[...]}',
  designSystem: {
    label: "Acme",
    theme: "dark",
    palette: "Modern",
    typography: "Inter",
    colors: {
      primary: "#FF6A00",
      background: "#0A0E1A",
    },
  },
});

You can also bake defaults into the toolkit:

const montage = createMontageTools({
  apiKey: process.env.MONTAGE_API_KEY!,
  defaults: {
    outputQuality: "default",
    designSystem: { theme: "dark", palette: "Notion" },
  },
});

Framework integrations

The integrations namespace wraps the same execute() function in the shape each framework expects. You provide your own zod instance — no version conflict.

import { z } from "zod";
import { createMontageTools, integrations } from "@montageai/sdk";
import { createMontageAiSdkTool } from "@montageai/sdk/ai-sdk";
import { createMontageMastraTool } from "@montageai/sdk/mastra";

const toolkit = createMontageTools({ apiKey: process.env.MONTAGE_API_KEY! });

// Mastra: { id, description, inputSchema, execute }
const mastraTool = integrations.mastra(toolkit, z);
const directMastraTool = createMontageMastraTool(toolkit, z);

// LangChain: { name, description, schema, func }
const langchainTool = integrations.langchain(toolkit, z);

// Vercel AI SDK: { description, inputSchema, parameters, execute }
const aiTool = integrations.vercelAi(toolkit, z);
const directAiTool = createMontageAiSdkTool(toolkit, z);

// Generic JSON-schema definition
const rawTool = integrations.raw(toolkit);

For Vercel AI SDK, pass the direct adapter into tool(...):

import { tool } from "ai";
import { z } from "zod";
import { createMontageTools } from "@montageai/sdk";
import { createMontageAiSdkTool } from "@montageai/sdk/ai-sdk";

const toolkit = createMontageTools({ apiKey: process.env.MONTAGE_API_KEY! });

export const tools = {
  montage_generate: tool(createMontageAiSdkTool(toolkit, z)),
};

For Mastra, register the direct adapter with your agent's tool set:

import { z } from "zod";
import { createMontageTools } from "@montageai/sdk";
import { createMontageMastraTool } from "@montageai/sdk/mastra";

const toolkit = createMontageTools({ apiKey: process.env.MONTAGE_API_KEY! });
const montageGenerate = createMontageMastraTool(toolkit, z);

Rendering generated HTML in React

import { HtmlBlock } from "@montageai/sdk/react";

function Output({ result }: { result: { html: string } }) {
  return <HtmlBlock html={result.html} />;
}

<HtmlBlock> sets the bundled HTML into the host element and executes its inline scripts. Theme CSS, component CSS, event delegation, state updates, and DOM updates are owned by the artifact itself.

import { HtmlBlock } from "@montageai/sdk/react";
import { createMontageAdapter } from "@montageai/sdk";

const adapter = createMontageAdapter({
  agent: { id: "ops", name: "Ops Agent" },
  capabilities: [
    {
      name: "fetchEmails",
      effect: "query",
      description: "Fetch recent email summaries.",
      availability: "adapter",
    },
  ],
  async invokeCapability(request) {
    if (request.name === "fetchEmails") {
      return fetchEmails(request.args?.[0]);
    }
    throw new Error(`Unknown capability: ${request.name}`);
  },
});

<HtmlBlock
  html={result.html}
  adapter={adapter}
/>

Capability adapter

Artifacts call host capabilities through the generated artifact bridge. The SDK's only runtime hook is installing that bridge. Built-in artifact runtime behavior is owned by generated artifacts and the Montage API; the SDK only routes capabilities you explicitly register on the adapter.

import {
  createMontageAdapter,
  bindMontageCapabilityBridge,
} from "@montageai/sdk";

const adapter = createMontageAdapter({
  agent: { id: "ops", name: "Ops Agent" },
  capabilities: [
    {
      name: "fetchEmails",
      effect: "query",
      description: "Fetch recent email summaries.",
      availability: "adapter",
    },
  ],
  async invokeCapability(request) {
    if (request.name === "fetchEmails") {
      return fetchEmails(request.args?.[0]);
    }
    throw new Error(`Unknown capability: ${request.name}`);
  },
});

const cleanup = bindMontageCapabilityBridge({ adapter });

Error handling

API failures surface as MontageApiError (network / non-2xx / non-JSON response). Validation problems inside the SDK surface as MontageError with a typed code.

import { MontageApiError, MontageError } from "@montageai/sdk";

try {
  await montage.execute({ prompt: "...", dataInfo: "{}" });
} catch (error) {
  if (error instanceof MontageApiError) {
    console.error(`API ${error.status} (${error.code}):`, error.message);
  } else if (error instanceof MontageError) {
    console.error(`SDK ${error.code}:`, error.message);
  }
}

The Montage API returns errors as { success: false, error: { code, message } }. The SDK reads the nested error envelope and exposes code / message directly on the thrown MontageApiError.

License

MIT