Chataway Developers
Getting started

Quickstart

Scaffold an app, run it against your local Chataway, call its tool from a chat and iterate — in about ten minutes.

At the end of this page you'll have an app running in your own copy of Chataway, marked DEV, with a tool the agent can call and a panel in the dock.

#Before you start

  • Chataway for Mac, running and signed in. Download it if you haven't.
  • Node.js 20 or newer.
  • Developer mode on: in Chataway open Settings → Developer and switch on Developer mode. This writes a local developer token that the CLI uses to talk to your running Chataway. It never leaves your Mac.

#1. Create the app

bash
npx create-chataway-app my-app

It asks four questions — app name, your publisher slug, the app id, a one-line description — and suggests answers for each. (Pass --yes to accept them all.)

? App name (My App)
? Publisher slug (chataway.co → Developer) (your-company) acme
? App id (com.acme.my-app)
? One-line description (My App for Chataway.)
✔ Created My App in my-app

The app id is permanent once you publish: reverse-DNS under a domain you own, like com.acme.my-app. The publisher slug is the one you'll create on chataway.co when you publish — any placeholder is fine for now.

bash
cd my-app
npm install

You get a working app:

my-app/
├── plugin.json        # the manifest: what the app is and may do
├── server/index.ts    # your remote MCP server — the app's tools
├── web/               # the panel's source (Vite + @chataway/apps/bridge)
│   ├── index.html
│   ├── main.ts
│   └── style.css
├── ui/                # the built panel (generated from web/)
├── assets/
│   ├── icon.png       # a placeholder 512×512 icon in your accent colour
│   └── mark.svg       # single-colour glyph for the dock
├── vite.config.ts
├── README.md          # becomes your store description
├── CHANGELOG.md
└── package.json

#2. Look at the manifest

Open plugin.json. The parts that matter now:

plugin.json (excerpt)
json
{
  "remote": {
    "mcpUrl": "https://mcp.acme.com/mcp",
    "domains": ["mcp.acme.com"]
  },
  "grants": ["files:receive", "host:media"],
  "contributes": {
    "tools": [
      {
        "id": "inspect_images",
        "name": "Inspect images",
        "description": "Report the size, dimensions and format of one or more images the user provides. …",
        "files": {
          "images": {
            "accept": ["image/png", "image/jpeg", "image/webp"],
            "multiple": true,
            "prepare": { "op": "resize", "width": 1024, "height": 1024, "fit": "contain", "format": "png" }
          }
        },
        "confirm": { "title": "Send {{count}} image(s) to My App?", "action": "Send" }
      }
    ]
  }
}
  • remote.mcpUrl is where your tools will live in production — an https URL you'll deploy to. During development, chataway dev overrides it with chataway.devMcpUrl from package.json (http://localhost:8787/mcp).
  • contributes.tools lists the tools Chataway may offer the agent. Only tools listed here are ever registered, even if your server has more. The description here is what the agent reads.
  • The example tool already uses a file param with prepare, and a confirm card. Your first tool explains each piece.

#3. Look at the server

server/index.ts is a normal MCP server over Streamable HTTP, built with the official SDK and @chataway/apps/server:

server/index.ts (excerpt)
ts
const app = createAppServer({ manifest });

app.tool('inspect_images', {
  input: {
    images: fileParam({ multiple: true, description: 'The images to inspect' }),
    detail: z.enum(['short', 'full']).optional(),
  },
  annotations: { readOnlyHint: true },
}, async ({ images }) => {
  const rows = images.map(f => ({ name: f.name, bytes: f.size, ...imageSize(f.bytes) }));
  return {
    text: `Inspected ${rows.length} image(s).`,
    json: { images: rows },
    card: card.notice({ title: `Inspected ${rows.length} image(s)`, body: /* a Markdown list */ '' }),
  };
});

await app.listen({ port: 8787 });

createAppServer checks your server against the manifest when it starts: it refuses to run if a declared tool has no implementation, or if you implement one the manifest doesn't declare.

#4. Run it in Chataway

bash
npm run dev
✔ plugin.json is valid (dev)
[server] [com.acme.my-app] MCP server on http://localhost:8787/mcp — tools: inspect_images
[ui] built in 180ms
✔ Linked My App (com.acme.my-app) into Chataway at http://localhost:2222 [DEV]
ℹ tools are served from http://localhost:8787/mcp (dev override of remote.mcpUrl)
ℹ Open Chataway → Apps → My App. Edits reload automatically. Ctrl-C to unlink.

npm run dev runs chataway dev, which:

  1. validates your folder (store-only rules are warnings here),
  2. starts your MCP server (npm run server) and the panel build in watch mode (npm run watch:ui),
  3. links the folder into your running Chataway as a DEV app, using the local developer token,
  4. re-validates and re-links whenever plugin.json changes, and streams the App inspector feed.

Press Ctrl+C to stop everything and unlink.

#5. Enable it in a project

In Chataway, open a project and go to Apps. My App is listed with a DEV badge. Switch it on.

Chataway shows the screen your users will see: your icon and name, and the sentences from permissions. Accept it. A new tab with your mark appears in the dock — that's your panel, with the Home and Activity views from the manifest and Chataway's own Settings view next to them.

#6. Call it from a chat

Start a new chat in that project — any provider works — attach an image or two, and ask:

What size are these images?

The agent picks inspect_images. Chataway asks whether the files may go to My App (the hand-off consent card, once per project), resizes them, then shows your confirm card: "Send 2 image(s) to My App?". Tap Send. Your notice card appears with the results, and the agent answers.

Open My App → Inspector to see the whole call: arguments, what was sent to your server, the raw response, timing.

#7. Iterate

  • Server code — edit server/index.ts; the server restarts on save. Ask again.
  • Manifest — edit a tool's description or add a tool; chataway dev re-validates and re-links. New chats see the change.
  • Panel — edit web/; it rebuilds into ui/ and the panel reloads. For fast UI work, npm run ui opens the panel in your browser against a mock host with a palette and view switcher.

#8. Check it against the store

bash
npm run validate

This builds the panel and runs chataway validate --store: exactly the checks the store runs on upload. When it passes and your server is deployed at remote.mcpUrl, you're ready to publish.

#Troubleshooting

"Chataway is not reachable". Chataway must be running. If it listens on a port other than 2222, pass --port: npx chataway dev --port 2323.

"Developer mode is off" / no developer token. Switch on Settings → Developer → Developer mode. The CLI reads the token from Chataway's data folder; pass --data-dir if you run Chataway with a custom one.

The agent doesn't see the tool. Start a new chat. Then check the Inspector: tools your server lists but the manifest doesn't declare are ignored, and declared tools your server doesn't list are skipped — both are logged.

The panel is blank. The panel runs in a sandbox with a strict Content Security Policy. Anything loaded from a host that isn't in remote.domains is blocked — bundle your assets into ui/. See Panels.