On this page5 sections
Project structure
An mcp-rune project has two halves: your server (the models, prompts, tools, and domain rules you write) and the framework (everything mcp-rune ships). The convention is to keep them clearly separated — your code lives under your-server/, mcp-rune’s lives under the published package. This guide is the map.
Your project
A simple-preset mcp-rune project looks like this — src/ holds the TypeScript you write, test/ ships one smoke test, and the project root holds package.json, tsconfig.json, .env.example, and a .gitignore:
What lives where:
src/models/— One file per model. Each model declares itsattributes(the source of truth) and itsapiblock (endpoint and convention). The framework derives field tables, validators, and JSON schemas from these. Theindex.tsaggregates every model into a singleMODEL_CLASSESmap; therune add modelcommand appends to it for you.src/prompts/— One file per prompt. Prompts group model fields intofieldGroupsand pick a strategy (stateless,hybrid, orstateful). See the Sections & Field Groups guide. Theindex.tsaggregates them into thepromptRegistry.src/config.ts— WiresMODEL_CLASSES+promptRegistryinto aToolRegistry. The simple preset installs a throwingProxyas theApiClientso CRUD tools fail with a clear “wirecreateApiClienthere” error. Swapping that line is how you point at a real backend.src/server.ts—StdioServerentry point. ImportsmcpConfigfromconfig.tsand callsserver.start().test/—vitestlives here. The bundledsmoke.test.tsassertspackage.jsondeclares the framework’s expected scripts; add real tests alongside it.
For larger projects you’ll grow two more directories: src/tools/ for bespoke BaseTool subclasses (most projects need zero — the polymorphic tools cover the common surface) and src/domain/ for declarative workflows, business rules, and knowledge entries the LLM can query via suggest_workflow, check_business_rules, and get_domain_context. The simple preset doesn’t scaffold them; the advanced preset and the bookshelf template do. See Tool creation and Domain knowledge for when to reach for each.
The advanced preset’s --transport both also scaffolds a second entry point at src/server-remote.ts (an HttpServer for OAuth-gated HTTP transport) alongside server.ts. Both share config.ts.
Try it — walk a fresh scaffold
Verified against rune CLI 0.11.0 · @mcp-rune/mcp-rune 0.107.0 · Node 24.
Scaffold a throwaway project in /tmp and inspect it. Every file, folder, and command line below is captured verbatim from a real run; the layout above describes what you’ll see.
1. Scaffold from scratch
cd /tmp
rune new bookshelf-tour --preset simple --models Book --yes --skip-mascot --no-install --no-git
Expected output:
Scaffolding bookshelf-tour (simple)…
│
◇ Wrote files to /tmp/bookshelf-tour
╭ Next steps ────────────────────────────────╮
│ ▸ cd bookshelf-tour │
│ ▸ npm install │
│ ▸ npm run start:local │
│ ▸ rune inspect (open MCP Inspector) │
│ │
│ Docs: https://github.com/mcp-rune/mcp-rune │
╰────────────────────────────────────────────╯
(The --yes --skip-mascot --no-install --no-git flags only exist to make the output reproducible for this tutorial. Drop them in real use to get the wizard, npm install, and git init automatically.)
2. Walk the tree
cd bookshelf-tour && tree -L 2 -I 'node_modules|.git'
Expected output:
.
├── package.json
├── README.md
├── src
│ ├── config.ts
│ ├── models
│ ├── prompts
│ └── server.ts
├── test
│ └── smoke.test.ts
└── tsconfig.json
5 directories, 6 files
3. List each folder the layout block named
ls src/models src/prompts
Expected output:
src/models:
book.ts index.ts
src/prompts:
book-prompt.ts index.ts
Two files per folder: one declaration per model (book.ts, plus a prompt that mirrors it), and one index.ts that aggregates every declaration into the registry the framework reads. rune add model Tag will append tag.ts + tag-prompt.ts to these folders and patch both index.ts files for you — no manual wiring.
4. Confirm the typecheck and smoke test pass before you change anything
npm install --no-audit --no-fund
npm run typecheck
npm run test
The typecheck prints nothing on success; the test prints 1 passed. Both run in well under a minute on a fresh machine. If either fails on a clean scaffold, file a bug against @mcp-rune/create — that’s the scaffold’s own contract, asserted by test/smoke.test.ts.
Observe: there’s no tools/ folder, no domain/ folder, no createApiClient factory. The simple preset is deliberately minimal — the polymorphic tools cover CRUD, the stub ApiClient makes CRUD attempts fail with a pointed error, and you grow the project from there by adding models with rune add model and wiring real services in config.ts.
The framework
The published mcp-rune package surfaces its capabilities through a flat list of subpath exports — one entry per concern, so you only pull in the surface you actually need. The authoritative list is the "exports" field in package.json; today:
Each entry is a stable seam: renaming or moving an internal file does not break consumers. See Subpath imports for per-subpath import examples.
Three things to know on first read.
The
api-extensions/*subpaths are opt-in. Importing the module gets you the types and services (SearchService, etc.), but the contributed MCP tools (search_records,model_action,get_filters_guide) only register when you also pass the extension toToolRegistry({ apiExtensions: {...} }). Pure-REST servers can omit them entirely. See API extensions and Authoring extensions.
coreno longer containsBaseModel. Earlier releases re-exported it there; today the model-domain layer lives behind themodelssubpath, andcoreis reserved for framework primitives (helpers, env, theApiClienttype definition). Scaffolded projects already import from the right place; if you have older code, swap@mcp-rune/mcp-rune/core→@mcp-rune/mcp-rune/modelsforBaseModel-related symbols.Internal vs public. The map above is the public surface. Internally the code is split across
src/core/,src/mcp/(the bulk —models/,model-layer/,data-layer/,analysis-layer/,prompts/,tools/,apps/,domain/, etc.),src/runtime/,src/extensions/,src/oauth2/, andsrc/db/. The mapping from subpath to internal folder is inpackage.json. Definition vs consumption explains why declaration and consumption sit in sibling folders insidesrc/mcp/.
Example: the bookshelf
The reference example (see the Quickstart guide to run it) keeps the structure minimal:
config.ts wires the model, prompt, and any custom tools into their registries; server.ts calls createServer(config) and starts the stdio transport. The whole example is ~150 lines.
Next
- Prompt Creation — declare a prompt with sections, field groups, and a strategy.
- Tool Creation — when (and when not) to write a custom tool.
- API configuration — point models at a real backend (REST, Rails, Elasticsearch).