Adapstory Docs
Plugins

Plugin quickstart

Zero to a running plugin in about 30 minutes.

This guide walks you from an empty directory to a signed plugin running in a tenant sandbox.

What you'll build

A minimal plugin that:

  • Registers one MCP tool (hello_learner) with the Plugin Gateway.
  • Consumes enrollment.completed.v1 from Kafka.
  • Logs its LLM token usage to the telemetry pipeline.

Prerequisites

  • docker and pnpm (or uv for Python plugins)
  • Publisher account with a Cosign signing key
  • adapstory CLI: curl -fsSL https://adapstory.com/cli/install | sh

If you don't have a publisher account yet, request one in #adapstory-plugins or via the admin portal. You'll get a signing key and a sandbox tenant to test in.

Steps

Scaffold the project

adapstory plugin new hello-learner --runtime python
cd hello-learner

You'll get:

hello-learner/
├── plugin.yaml          # manifest
├── pyproject.toml       # uv-managed deps
├── src/
│   └── hello_learner/
│       ├── __init__.py
│       ├── main.py      # FastAPI app
│       └── tools.py     # @mcp_tool handlers
├── tests/
└── Dockerfile

Declare the manifest

Open plugin.yaml and fill in the integration points:

apiVersion: adapstory.com/v1
kind: Plugin
metadata:
  name: hello-learner
  version: 0.1.0
  publisher: your-org
spec:
  runtime:
    image: registry.adapstory.com/your-org/hello-learner:0.1.0
    resources:
      requests: { cpu: 100m, memory: 256Mi }
      limits:   { cpu: 500m, memory: 512Mi }
  mcpTools:
    - name: hello_learner
      description: Greet a learner by name with an AI-generated message.
      endpoint: /mcp/hello
      schema: mcp/hello-learner.schema.json
  events:
    consumes: [enrollment.completed.v1]
  llm:
    gatewayBudget: 100000
    defaultModel: claude-haiku-4-5-20251001
  guardrails:
    content: [no-pii, education-safe]

The full field reference is here.

Implement the MCP tool

# src/hello_learner/tools.py
from adapstory_plugin_sdk import mcp_tool, LlmGateway

@mcp_tool(name="hello_learner")
async def hello_learner(
    learner_name: str,
    gateway: LlmGateway,
) -> dict:
    """Return a friendly, education-safe greeting."""
    response = await gateway.chat(
        model="claude-haiku-4-5-20251001",
        messages=[
            {"role": "system", "content": "You are an encouraging tutor."},
            {"role": "user",   "content": f"Say hi to {learner_name} in one short sentence."},
        ],
    )
    return {"message": response.text}
// src/tools.ts
import { mcpTool, type LlmGateway } from '@adapstory/plugin-sdk';

export const helloLearner = mcpTool({
  name: 'hello_learner',
  async handler({ learnerName }: { learnerName: string }, ctx: { gateway: LlmGateway }) {
    const response = await ctx.gateway.chat({
      model: 'claude-haiku-4-5-20251001',
      messages: [
        { role: 'system', content: 'You are an encouraging tutor.' },
        { role: 'user',   content: `Say hi to ${learnerName} in one short sentence.` },
      ],
    });
    return { message: response.text };
  },
});

The SDK injects LlmGatewaynever call model providers directly.

Run it locally

adapstory plugin dev

This spins up a dockerised sandbox with a mock Plugin Gateway and a mock tenant. Invoke your tool:

curl -XPOST http://localhost:8787/mcp/invoke \
  -H 'content-type: application/json' \
  -d '{"tool":"hello_learner","args":{"learnerName":"Alex"}}'

You should see a greeting — and a telemetry line showing the mock token spend.

Sign and publish

adapstory plugin build              # → registry.adapstory.com/your-org/hello-learner:0.1.0
adapstory plugin sign               # → Cosign signature + SBOM + SLSA provenance
adapstory plugin publish            # → BC-02 picks it up, verifies signature, makes it installable

That last step is fail-closed: unsigned images are rejected at admission.

Install into a tenant

adapstory plugin install hello-learner --tenant sandbox-tenant-1

Poll status until ACTIVE:

adapstory plugin status hello-learner --tenant sandbox-tenant-1 --watch

What you have now

  • A signed plugin image in the registry.
  • An active install in a sandbox tenant, visible in ArgoCD under plugin-sandbox-tenant-1-hello-learner.
  • Telemetry flowing: traces in Tempo, CPU profile in Pyroscope, logs in Loki.

Next steps

  • Manifest reference — every field and its meaning.
  • MCP tools — deep dive on schemas, streaming, and cancellation.
  • Lifecycle — how upgrades, rollbacks, and multi-tenant rollouts work.
  • Observability — make your plugin debuggable in production.

On this page