This is the hands-on follow-up to our post on open-sourcing the agent skills and tools. Here you will stand up Malloy Publisher, point an agent at it, and watch it answer data questions against a Malloy model.
Set it up
There are two ways in, and they differ mostly in how much you set up by hand. One command builds a package around a data file of your own and writes the agent MCP connection to your local Publisher, so there is nothing left to wire up. The bundled examples take one extra command to connect an agent to your local Publisher, but they give you a complete model that is documented throughout.
Start from your own data
One command writes a Malloy package around your file: the directory of model files, data and a manifest file that Publisher serves. Alongside it come a Publisher config and the agent wiring - an .mcp.json pointing at the local Publisher MCP endpoint (MCP is the protocol agents use to call tools), agent instructions in AGENTS.md and CLAUDE.md, and the Malloy skills as files in .claude/skills/.
Start your agent from that directory and the malloy_* tools are already there, with the skills alongside them. Two things to know: .mcp.json is only read by a session that started in the directory, and your agent asks you to trust the workspace the first time you open it - until you answer, the tools connect but refuse every call.
# use a new directory: config lands here, the package in ./sales
mkdir my-data && cd my-data
# writes the package, server config, .mcp.json and skills
# keep @latest, and the extra -- so npm forwards --data
npm create @malloy-publisher/malloy-package@latest sales -- --data ~/orders.csv
# serves the package, watching for model edits
npm start--data takes a CSV, Parquet, JSON or Excel file at any path, resolved from wherever you run the command, and copies it into the package rather than moving it.
The agent is wired already, so ask it to:
- Answer a question about what is actually in the file.
- Build the model out - define measures, add joins and document fields as it goes, which is what makes the next question easier to ask.
- Build an HTML data app over it. Publisher serves a package's
public/directory as-is, so you can look at the result onlocalhost:4000before it goes anywhere near production.
Or start from the bundled examples
Three packages ship ready to run: storefront, a complete semantic model over a fictional ecommerce business (customers, products, orders and regions); governed-analytics, which demonstrates runtime parameters and row-level access; and html-data-app, a SaaS-subscriptions dashboard of plain HTML files that Publisher serves as-is, with no bundler or build step. All DuckDB-backed, no credentials required.
One command, and nothing of your own to prepare. This is the path the rest of the post uses:
# --host keeps it on your machine; Publisher has no auth of its own
npx @malloy-publisher/server --port 4000 --host 127.0.0.1Open localhost:4000/examples/storefront to see what Publisher serves: the model's sources and views, a visual query builder for drilling into one without writing Malloy, and storefront.malloynb, a notebook of markdown and live query cells. Click Pages for an HTML data app that ships inside the package, versioned with the semantic model it queries - ready to serve as it stands, or to embed in something else.
Then point your agent at the MCP endpoint. In Claude Code that is one command:
# -s user registers it for every directory, not just this one
# started the server mid-session? run /mcp and Reconnect
claude mcp add --transport http malloy http://localhost:4040/mcp -s userOther clients take the same endpoint through a config file:
{
"mcpServers": {
"malloy": {
"type": "http",
"url": "http://localhost:4040/mcp"
}
}
}Now ask it something: how jeans sales have been trending, or which categories bring in the most revenue - a question that finds a measure called total_sales only because the modeler documented it as revenue.
Beyond the tutorial
Everything above runs on defaults. Three things you are likely to want next, each a small change.
Ranking by meaning instead of by words. Retrieval matches keywords out of the box. Set EMBEDDING_API_KEY and it ranks by meaning instead, so synonyms and snake_case names match; a provider failure falls back to keywords rather than erroring. To keep everything on your own machine, point EMBEDDING_API_BASE at an Ollama or vLLM server and set EMBEDDING_MODEL, since the default names an OpenAI model. The configuration reference has the rest.
A real warehouse instead of a local file. A file is the quickest thing to demonstrate, but a package is just Malloy: point its model at a connection your config defines and the same setup serves BigQuery, Snowflake, Postgres, Trino or MySQL. The connection docs have the config.
More than one source. --data seeds from a single file. If your data is spread across several, drop the others into the package directory and ask the agent to add sources for them - the bundled storefront package is four sources over four files, if you want to see the shape to aim for.
What's next
- Later in this series we dig into modeling, including bringing over an existing LookML project.
- Write a skill for your team's patterns and send a PR via the contributor guide.
- Tell us how it goes: join the Malloy community Slack, open an issue, and tell us where it shines and where it falls short.
An agent that finds the right fields before it writes anything is the difference between a confident guesser and something you can trust with a real question.