Source: https://www.hype-stack.dev/docs/cli/mcp

# MCP Server

The CLI ships an MCP server. Point your editor at it and the agent can search the catalog, check what your license
covers, scaffold a project, install packs, boot the databases, and validate a pack you are writing, without you
switching to a terminal.

It is the same binary you already run. `hype-stack mcp` speaks JSON-RPC on stdin and stdout instead of talking to a
human, which is all an MCP host needs.

## Install

The fastest way is the **Install MCP** button on the [MCP page](/mcp). Pick your editor. Cursor and VS Code install from
a link their own app opens, and when you are signed in the dialog creates an API key for that editor and bakes it in, so
the editor comes up signed in. The other editors get the command below, ready to copy.

From a terminal it is one command. It asks which editors, opens the browser once, and does the rest.

```bash
npx @hype-stack/cli@latest mcp install
```

What happens, in order:

1. **Pick editors.** A checklist of Cursor, Codex, Claude Code, Claude Desktop and VS Code (Copilot). Pass
   `--editor cursor,codex` to skip the prompt.
2. **Approve in the browser.** The page creates an API key named after the editors and this machine, for example
   "Cursor + Claude Code on maciej-mbp", with the expiry you pick (the default is never, which means it lasts until you
   revoke it). The key is listed on the [API keys](/api-keys) page from that moment.
3. **Configs are written.** Global configs get the key in their `env` block. Project configs get committed, so for those
   the key is saved to the CLI's own store instead and the file stays portable; the server reads both.
4. **The server is started once, the way each editor will start it,** and the command prints the version, the tool
   count, and who it is signed in as. If that fails, it fails here with the reason, not in the editor.

Then restart the editor. Hosts read their MCP config at startup, not while running.

There is no way to skip the sign-in. An install always ends with a key that works, so the editor never sits there
answering `auth_required`. Running it again reuses the key already in the config if it is still valid, and mints a new
one if it has been revoked. To repeat the launch test later, for example after a Node upgrade:

```bash
npx @hype-stack/cli@latest mcp check --editor cursor
```

**Install globally**

A per-project config can only exist once the project does, which means it can never be the thing that creates one.
Install globally and `create_application` works from an empty folder. Project scope is for repos where you want the
server committed alongside the code.

### Flags

| Flag                 | What it does                                                                                                             |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `--editor <editors>` | Any of `cursor`, `codex`, `claude`, `claude-desktop`, `copilot`, comma-separated or repeated. Prompted for when omitted. |
| `--scope <scope>`    | `global` or `project`. Defaults to global where the editor supports it.                                                  |
| `--cwd <path>`       | Project root for `--scope project`.                                                                                      |
| `--token <key>`      | Use this API key instead of creating one in the browser. For machines with no browser.                                   |
| `--print`            | Print the editor-native JSON or TOML block instead of writing a file.                                                    |
| `--no-check`         | Write the file and stop. Skips the launch that verifies the server starts.                                               |

`mcp check` takes `--editor`, `--scope`, and `--cwd` with the same meanings, and launches whatever is in the file right
now rather than what a fresh install would write.

`create` also wires the server into the new project for you when the editor supports project scope, so a project
scaffolded from the CLI comes with the tools already attached.

### Config by hand

Each editor wants the same server entry in a slightly different place.

| Editor (`--editor`)               | Global file                                                               | Project file         | Key           |
| --------------------------------- | ------------------------------------------------------------------------- | -------------------- | ------------- |
| Cursor (`cursor`)                 | `~/.cursor/mcp.json`                                                      | `.cursor/mcp.json`   | `mcpServers`  |
| Codex (`codex`)                   | `~/.codex/config.toml`                                                    | `.codex/config.toml` | `mcp_servers` |
| Claude Code (`claude`)            | `~/.claude.json`                                                          | `.mcp.json`          | `mcpServers`  |
| Claude Desktop (`claude-desktop`) | `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) | none                 | `mcpServers`  |
| VS Code / Copilot (`copilot`)     | none, the user file moves between releases                                | `.vscode/mcp.json`   | `servers`     |

T3 Code is not in that table because it has no config of its own. It spawns the provider CLIs, so the entry belongs in
whichever file the provider reads: `.mcp.json` for Claude, `.cursor/mcp.json` for the Cursor CLI.
`create --editor t3code` writes both for you. Codex uses TOML instead of JSON, but supports both the shared global file
and a project file for trusted projects. OpenCode and Windsurf get editor rules from `create` but are not supported by
this installer yet; add the entry by hand from the snippet below.

The entry itself:

```json
{
  "mcpServers": {
    "hype-stack": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@hype-stack/cli@latest", "mcp"]
    }
  }
}
```

VS Code is the outlier: same entry, but the top-level key is `servers`.

Codex uses the equivalent TOML form:

```toml
[mcp_servers.hype-stack]
command = "npx"
args = ["-y", "@hype-stack/cli@latest", "mcp"]
```

That is the portable form, and it is what `mcp install` writes for project scope, since that file gets committed and a
teammate's Node is somewhere else. For global scope it writes something longer: the absolute path to the `npx` next to
the Node that ran the install, plus a `PATH` in the env block that contains it. An app opened from the Dock or a Windows
shortcut never loads your shell profile, so its `PATH` has no nvm, fnm, volta, or Homebrew in it, and a bare `npx` fails
with `spawn npx ENOENT` before the server gets a chance to run. Cursor resolves your shell environment on its own, which
is why it tends to work when the others do not. If you paste the portable form into a global file by hand, expect that
failure in Claude Desktop.

Claude Code has its own one-liner if you prefer it:

```bash
claude mcp add -s user hype-stack -- npx -y @hype-stack/cli@latest mcp
```

## Authentication

Free packs need nothing. Paid packs need a credential, and the server has no terminal to log you in from, so it reads
one of two places:

1. **`HYPE_STACK_TOKEN` in the server's env block.** This is what `mcp install` writes: the API key it created for the
   editor in the browser. Revocable on its own from the [API keys](/api-keys) page.
2. **The token in the CLI's store.** What `mcp install` writes for project-scoped configs, and what
   `npx @hype-stack/cli login` saves for the terminal.

For a machine with no browser, mint a key elsewhere and hand it over:

```bash
npx @hype-stack/cli@latest mcp install --editor cursor --token hsk_...
```

Which produces:

```json
{
  "mcpServers": {
    "hype-stack": {
      "type": "stdio",
      "command": "npx",
      "args": ["-y", "@hype-stack/cli@latest", "mcp"],
      "env": { "HYPE_STACK_TOKEN": "hsk_..." }
    }
  }
}
```

An env var set on the process still wins over the saved login, so a key in the config always takes precedence.

**A key in a config file is plain text**

Fine in `~/.cursor/mcp.json`, risky in a `.mcp.json` you commit. For project scope, prefer logging in, or reference a
secret your editor resolves at launch. Keys are revocable from the [API keys](/api-keys) page if one leaks.

Call `auth_status` any time you want to know who the server thinks you are.

## Tools

### `search_catalog`

Read-only. Find packs and templates.

| Argument   | Type                          | Notes                                           |
| ---------- | ----------------------------- | ----------------------------------------------- |
| `query`    | string                        | Matched against name, display name, description |
| `kind`     | `pack` \| `template` \| `all` | Default `all`                                   |
| `category` | string                        | Packs only: `starter`, `layout`, `feature`      |
| `tier`     | `free` \| `paid` \| `all`     | Default `all`                                   |

### `plan_install`

Read-only. Resolves transitive dependencies, drops packs you already have, and checks entitlements. This is the tool
that lets an agent say "you don't own this" before an install starts rather than half way through.

| Argument | Type     | Notes                                           |
| -------- | -------- | ----------------------------------------------- |
| `packs`  | string[] | Required                                        |
| `cwd`    | string   | Defaults to the workspace the server started in |

### `create_application`

Scaffolds a new app: clone, editor rules, agent skills, dependency install, first commit, `.env` files. It never starts
Docker or migrates. The `followUp` says to call `setup_project` next, or lists the manual commands.

| Argument                                                   | Type              | Notes                                                                                                 |
| ---------------------------------------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------- |
| `name`                                                     | string            | Required. Folder and package name                                                                     |
| `directory`                                                | string            | Parent folder                                                                                         |
| `editors`                                                  | string[]          | Any of `cursor`, `t3code`, `claude`, `codex`, `copilot`, `opencode`, `windsurf`. Defaults to `cursor` |
| `theme`, `adminTheme`, `mobileTheme`, `extensionTheme`     | string            | Color theme per app. The others default to `theme`                                                    |
| `radius`, `adminRadius`, `mobileRadius`, `extensionRadius` | string            | Corner radius per app, as a CSS length                                                                |
| `mode`                                                     | `light` \| `dark` | Color mode the app boots in                                                                           |

### `add_packs`

Installs packs into an existing project. Catalog packs, community packs, or both in one call.

| Argument     | Type                  | Notes                                                                                      |
| ------------ | --------------------- | ------------------------------------------------------------------------------------------ |
| `packs`      | string[]              | Catalog packs. Suffix a layout pack with `@frontend` or `@admin`                           |
| `community`  | string[]              | Community pack sources: a directory, `github:user/repo#ref`, `npm:@scope/pack`, `@ns/pack` |
| `cwd`        | string                | Project directory                                                                          |
| `onConflict` | `keep` \| `overwrite` | Default `keep`                                                                             |

At least one of `packs` or `community` is required; an empty call comes back as `input_required`.

### `apply_template`

Installs a template: starter, layout, fixed packs, and frontend overrides.

| Argument     | Type                     | Notes                                                            |
| ------------ | ------------------------ | ---------------------------------------------------------------- |
| `templateId` | string                   | Required. Use `search_catalog` to find one                       |
| `cwd`        | string                   | Project directory                                                |
| `variants`   | Record\<string, string\> | Slot overrides, e.g. `{ "starter-saas": "starter-saas-workos" }` |
| `packs`      | string[]                 | Extra packs on top of the template                               |
| `onConflict` | `keep` \| `overwrite`    | Default `keep`                                                   |

### `setup_project`

The one tool that touches infrastructure. Starts Docker in `apps/backend` (remapping busy ports), waits for Postgres,
runs `prisma migrate dev`, and mirrors the schema into the test database. Idempotent: calling it after every `add_packs`
or `apply_template` is the intended rhythm, and a second call on a finished project changes nothing. The server tells
the agent to ask you before the first run in a session.

| Argument        | Type    | Notes                                                   |
| --------------- | ------- | ------------------------------------------------------- |
| `cwd`           | string  | Project directory                                       |
| `testSetup`     | boolean | Also prepare the isolated test database. Default `true` |
| `migrationName` | string  | Name for the migration it creates. Default `setup`      |

### `inspect_stack`

Read-only. `stack.json` plus the detected workspace layout: installed packs and where each app lives. Takes an optional
`cwd`.

### `env_status`

Read-only. Which env vars your installed packs still need. It reports; it does not fill them in. Handing secrets to a
tool call is worse than typing them, so filling them in stays with `hype-stack onboard`. Takes an optional `cwd`.

### `auth_status`

Read-only, no arguments. Who the server is authenticated as and where the token came from. When the answer is nobody, it
returns the login command and the API keys URL.

### `pack_authoring_guide`

Read-only. The conventions for writing a [community pack](/docs/packs-templates/build-your-own): required manifest
fields, the file strategies, the wiring fields, the rules `validate_pack` enforces, and the mistakes that fail silently.
Pass `cwd` inside a project and the guide uses that project's real path templates and installed packs. Call it before
writing a manifest; an agent that guesses the format writes one that installs cleanly and ships nothing.

### `validate_pack`

Read-only. Runs the same checks as `hype-stack community validate` on a pack directory and returns `errors` and
`warnings` with the field each one points at. Never fails the call for an invalid pack; `valid: false` is the answer.

| Argument    | Type   | Notes                                        |
| ----------- | ------ | -------------------------------------------- |
| `directory` | string | Required. The pack root, absolute if you can |

## What the server recommends

The server states its defaults up front so the agent does not have to guess, and tells it to name the choices it made
before any tool writes files. Every project needs exactly one starter and one layout.

| Decision | Default                     | Unless                                                                                                                         |
| -------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| Starter  | `starter-saas-betterauth`   | You want WorkOS or enterprise SSO (`starter-saas-workos`), or a free single-user app with no teams (`starter-auth-betterauth`) |
| Billing  | `pack-billing-stripe`       | You want a merchant of record handling tax (`pack-billing-lemonsqueezy` or `pack-billing-polar`)                               |
| Layout   | none, it is a visual choice | Always yours to pick                                                                                                           |

`search_catalog` marks the recommended pack in each family, and `plan_install` lists any decision your plan still leaves
open (a missing starter, two layouts, a non-default variant) under `decisionsNeeded`.

## When a tool fails

The server cannot prompt, so anything that would have been a question comes back as a structured failure with a
`reason`. Your agent should read that field and tell you what to do.

| `reason`         | What it means                                     | Fix                                                      |
| ---------------- | ------------------------------------------------- | -------------------------------------------------------- |
| `auth_required`  | A paid pack, with no credential                   | Run `npx @hype-stack/cli@latest mcp install` again       |
| `not_owned`      | Authenticated, but your org has no license for it | Buy it. The result carries the purchase URL              |
| `not_a_project`  | No `stack.json` in the target directory           | `create_application` first, or pass the right `cwd`      |
| `conflicts`      | Files already exist                               | Retry with `onConflict: "overwrite"` once you've decided |
| `input_required` | A step needed an answer that has no flag          | Run the equivalent CLI command in your terminal          |
| `failed`         | Something genuinely broke                         | Read `message` and the `logs` array                      |

Every result carries a `logs` array: the diagnostics the CLI would have printed in your terminal, captured for the
duration of that one call.

**Nothing runs behind your back**

Scaffolding and installing never start Docker, never run a migration, and never overwrite a file you have without being
told to. Infrastructure lives in one tool, `setup_project`, which the agent calls on its own and is told to ask you
about first. Anything else that needs a human answer comes back in `followUp` as a command for you to run.

## Troubleshooting

**The editor says the server failed to start.** Run `npx @hype-stack/cli@latest mcp check --editor <editor>`. It
launches the entry from that editor's config file with the environment a Dock-launched app has, and prints the server's
own output when the handshake fails. The usual causes, in order:

1. `spawn npx ENOENT`: the config has a bare `npx` in a global file and the app cannot find Node. Re-run `mcp install`
   for that editor; it writes the absolute path and a `PATH` that works.
2. A timeout on the first launch: `npx -y` has to download the package once. Run the check again, or run
   `npx -y @hype-stack/cli --version` in a terminal to warm the cache.
3. Something printed on stdout. `npx -y @hype-stack/cli@latest mcp` in a terminal should sit silently waiting for input.
   Anything else on stdout is the bug; every log, banner, and spinner is routed to stderr in server mode.

**Tools do not show up.** Restart the editor. MCP config is read at startup, not watched.

**The tools are there but installs come back `auth_required`.** The server is running without a working key, usually
because the key was revoked or the config was edited by hand. Run `npx @hype-stack/cli@latest mcp install` again for
that editor; it notices the dead key and creates a new one. `mcp check` prints what the server is currently signed in
as.

**`create_application` is missing.** You are on a project-scoped config. Reinstall with `--scope global`.

**The editor shows eight tools.** That is an older CLI that `npx` cached. Run `npx -y @hype-stack/cli@latest --version`
once to refresh it and restart the editor; the current server registers eleven.

## Next

Install a pack the normal way with [`compose`](/docs/cli/add-pack), or fill in env vars with
[`onboard`](/docs/cli/onboard).

Wondering what the server can reach on your machine, or what we log? That is all on the
[security page](/docs/getting-started/security).
