MCP server
npx -y @quello/mcp
Nothing to install and nothing to run yourself: your editor spawns it.
Why there are two routes
quello writes every pick to .quello/picks.json, and the plugins write a section into AGENTS.md
telling your agent to read it. That reaches every editor that reads an instructions file — and does
nothing in the ones that do not.
The MCP server is the other way in. The picks arrive as tools, so the agent is told they exist when it connects rather than having to be pointed at a file, and it gets them phrased for reading instead of as raw JSON.
Both routes are live at once and neither needs the other. The picks file stays the source of truth; this reads it.
Setup
The server speaks MCP over stdio. Register it once, wherever your editor keeps its MCP config:
{
"mcpServers": {
"quello": { "command": "npx", "args": ["-y", "@quello/mcp"] }
}
}
Claude Code takes it in one line:
claude mcp add quello -- npx -y @quello/mcp
Then start your dev server as usual, pick a few elements, and ask about PICK 2.
Tools
list_picks | every pick, one line each — element, source file, note |
get_pick | one pick by number, every recorded field |
resolve_picks | the picks that carry a note, in id order, as a work list |
list_picks takes three optional arguments:
detail | summary (default) is one line per pick; full is every field of every pick |
page | keep only picks whose page url or title contains this, case-insensitive — "/settings" |
withNotes | keep only picks carrying a note |
Each call re-reads the picks file. You go on picking while the agent works, so a cached answer would be the picks from a minute ago.
What a tool answers with
list_picks gives the agent a line per pick, source location first:
/app/.quello/picks.json · updated 2026-09-03T10:00:00.000Z
3 picks:
PICK 1 · <button class="cta"> · src/components/BuyButton.vue:12 (BuyButton) · "Buy now"
PICK 2 · <aside class="sidebar"> · src/Sidebar.svelte:3:5 (Sidebar) · "Filters" · note: make this sticky
PICK 3 · #footer
get_pick expands one of them into every recorded field — the same information as the
pick object, as labelled lines rather than JSON, because it is a third of
the tokens and puts the fields an agent acts on at the top.
resolve_picks is the MCP form of resolving the picks: the
notes as a numbered plan, in id order, each with the source to open.
Nothing here writes
All three tools are read-only, and there is no fourth one that changes anything.
The picks file belongs to quello — you clear it from the toolbar — and ids never shift, because
PICK 2 is a label you say out loud. A tool that could renumber or delete picks would be a tool
that could invalidate what you just said.
Resources
quello://picks | the whole picks file, as raw JSON |
quello://picks/{id} | one pick, as raw JSON — quello://picks/2 is PICK 2 |
For @-mentioning the picks into a chat. The JSON is byte-for-byte what .quello/picks.json holds,
so anything written against the file format works unchanged against these.
The template also enumerates: resources/list returns one entry per pick that currently exists —
quello://picks/1, quello://picks/2, … each named PICK <n> and summarised — so a client can
offer them individually instead of asking you to fill in the {id} by hand.
Prompts
Two show up in your editor's slash-command menu, both arriving with the picks already in them rather than with instructions to go and fetch them:
resolve-picks | work through every pick that carries a note |
explain-pick | locate one pick in the codebase and explain it — takes id |
Finding the picks
An editor launches an MCP server from whichever directory it happens to be in, so the working
directory is a hint rather than an answer. With no flags, the server climbs from it looking for an
existing .quello/picks.json first, then for a project root (package.json or .git).
An existing picks file wins over a nearer package.json, which is what a monorepo needs: every
level has a manifest, but only the app you are picking in has picks.
Pin it explicitly when that guess is wrong:
{
"mcpServers": {
"quello": {
"command": "npx",
"args": ["-y", "@quello/mcp", "--root", "/path/to/app"]
}
}
}
Options
--root <dir> | project root to read picks from — default: the nearest one found |
--picks-file <f> | picks file, absolute or relative to the root — default .quello/picks.json |
-h, --help | show help |
-v, --version | print the version |
QUELLO_ROOT and QUELLO_PICKS_FILE do the same, for a config where an env var is easier to set
than an argument.
Output goes to stderr
The startup banner — the root it chose, the picks file it found — goes to stderr, where your editor's MCP log will show it:
quello mcp stdio
root /path/to/app (discovered)
picks /path/to/app/.quello/picks.json
stdout carries the protocol and nothing else. A stray line on it would land in the middle of a message and desynchronise the client.
As a library
The server is importable too, for a process that would rather host it than spawn one:
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import { createQuelloMcpServer } from '@quello/mcp'
const server = createQuelloMcpServer({ picksPath: '/app/.quello/picks.json' })
await server.connect(new StdioServerTransport())
It returns the SDK's McpServer with everything registered on it, so any transport the SDK ships
works — StreamableHTTPServerTransport included, if you ever want to reach the picks over HTTP
rather than over a pipe.
The tool handlers are exported on their own as well — listPicks, getPick, resolvePicks, each
taking a { picksPath } context — for reading picks with no protocol in the way.
It writes nothing into your project
Unlike the plugins and the CLI, this server does not create AGENTS.md and does not touch
.gitignore. It is the alternative to those, and a server asked to read a repository has no
business editing it.
If you want both routes, install a plugin as usual — it writes the agent file — and register this alongside it.
Protocol
stdio transport, JSON-RPC 2.0 in newline-delimited JSON.
The protocol itself belongs to @modelcontextprotocol/sdk,
the official implementation: the envelope, the handshake, version negotiation, the transport, and the
JSON Schema clients see — which it generates from the zod schemas each tool declares, and validates
arguments against before a handler runs. Conformance therefore tracks the spec through a dependency
bump rather than through quello.
This is the one quello package with a third-party dependency. @quello/core remains
dependency-free, and nothing here reaches the browser.
isError: true with the reason as text, rather
than as a JSON-RPC error — that is the SDK's behaviour, and it is deliberate: the agent reads the
message and corrects itself instead of the call blowing up. A pick number that does not exist, an
argument that fails validation and an unknown tool name all arrive that way.