junobuild-mcp-server
# junobuild-mcp-server
> **Unofficial** MCP server for [Juno](https://juno.build). Not affiliated with or endorsed by the Juno team.
Manage satellites, hosting, serverless functions, changes and more through any MCP-compatible client. Includes a built-in documentation tool to access Juno's official guides and references.
## Features
- **19 tools** across 6 domains — CLI coverage for identity, config, hosting, functions, changes, and documentation
- **Progress streaming** — long-running operations (deploy, publish, upgrade) emit real-time progress updates via MCP `notifications/progress`
- **Log streaming** — `streamLogs: true` mirrors raw stdout/stderr lines as MCP `notifications/message` events, independent of progress
- **Automatic retry** — network-dependent operations can retry on transient failures with exponential backoff
- **CLI binary caching** — resolves `juno` binary path once, eliminating npx overhead on every call
- **CLI version check** — verifies installed `@junobuild/cli` meets the minimum supported version on first call
- **Structured error parsing** — common CLI failures (auth, network, missing config) surface as actionable messages
- **Config file writing** — `juno_config_init` can write config files directly to disk
- **Auth verification** — `juno_auth_status` wraps `juno whoami` for read-only identity checks
- **Docs caching** — documentation responses backed by an LRU cache (50 entries, 1 h TTL)
- **Tunable limits** — character limit, default timeout, and network timeout overridable via env vars
## Client Setup
Choose your AI coding agent below for specific setup instructions.
<details>
<summary>
### Claude Code
</summary>
**CLI (recommended):**
```bash
claude mcp add junobuild npx -y junobuild-mcp-server
```
**Config file:**
| Scope | Location |
| ------- | -------------------- |
| User | `~/.claude/mcp.json` |
| Project | `.mcp.json` |
```json
{
"mcpServers": {
"junobuild": {
"command": "npx",
"args": ["-y", "junobuild-mcp-server"]
}
}
}
```
</details>
<details>
<summary>
### Codex
</summary>
**CLI:**
```bash
codex mcp add junobuild -- npx -y junobuild-mcp-server
```
**Config file:**
| Scope | Location |
| ------- | ---------------------- |
| Global | `~/.codex/config.toml` |
| Project | `.codex/config.toml` |
```toml
[mcp_servers.junobuild]
command = "npx"
args = ["-y", "junobuild-mcp-server"]
```
</details>
<details>
<summary>
### OpenCode
</summary>
**Config file:**
| Scope | Location |
| --------- | ----------------------------------------- |
| User | `~/.opencode/opencode.json` (Linux/macOS) |
| Workspace | `opencode.json` (project root) |
```json
{
"mcpServers": {
"junobuild": {
"command": "npx",
"args": ["-y", "junobuild-mcp-server"]
}
}
}
```
</details>
<details>
<summary>
### Factory Droid
</summary>
**CLI:**
```bash
droid mcp add junobuild npx -y junobuild-mcp-server
```
**Config file:**
| Scope | Location |
| ------- | --------------------- |
| User | `~/.factory/mcp.json` |
| Project | `.factory/mcp.json` |
```json
{
"mcpServers": {
"junobuild": {
"type": "stdio",
"command": "npx",
"args": ["-y", "junobuild-mcp-server"]
}
}
}
```
</details>
<details>
<summary>
### Antigravity
</summary>
Uses a **Powers** system with custom configuration.
**Config file:**
| Scope | Location |
| --------- | ---------------------------------------- |
| Workspace | `.antigravity/powers/` or project config |
Add the MCP server configuration to your Power's `mcp.json`:
```json
{
"mcpServers": {
"junobuild": {
"command": "npx",
"args": ["-y", "junobuild-mcp-server"]
}
}
}
```
**Note:** See [Antigravity MCP documentation](https://antigravity.codes/blog/antigravity-mcp-tutorial) for full Power setup.
</details>
<details>
<summary>
### Cursor
</summary>
**Config file:**
| Scope | Location |
| ------- | -------------------- |
| User | `~/.cursor/mcp.json` |
| Project | `.cursor/mcp.json` |
```json
{
"mcpServers": {
"junobuild": {
"command": "npx",
"args": ["-y", "junobuild-mcp-server"]
}
}
}
```
</details>
<details>
<summary>
### Amp Code
</summary>
**CLI:**
```bash
amp mcp add junobuild -- npx -y junobuild-mcp-server
```
**Config file:**
| Scope | Location |
| --------- | ------------------------------------------- |
| User | `~/.config/amp/settings.json` (macOS/Linux) |
| Workspace | `.amp/settings.json` |
```json
{
"amp.mcpServers": {
"junobuild": {
"command": "npx",
"args": ["-y", "junobuild-mcp-server"]
}
}
}
```
**Note:** Workspace MCP servers require approval via `amp mcp approve <server-name>`.
</details>
<details>
<summary>
### VSCode
</summary>
**Config file:**
| Scope | Location |
| --------- | -------------------------------------- |
| User | `~/.config/Code/User/mcp.json` (Linux) |
| Workspace | `.vscode/mcp.json` |
```json
{
"servers": {
"junobuild": {
"type": "stdio",
"command": "npx",
"args": ["-y", "junobuild-mcp-server"]
}
}
}
```
</details>
<details>
<summary>
### Windsurf
</summary>
**Config file:**
| Scope | Location |
| ----- | ------------------------------------- |
| User | `~/.codeium/windsurf/mcp_config.json` |
```json
{
"mcpServers": {
"junobuild": {
"command": "npx",
"args": ["-y", "junobuild-mcp-server"]
}
}
}
```
</details>
<details>
<summary>
### Kiro
</summary>
**Config file:**
| Scope | Location |
| --------- | --------------------------- |
| User | `~/.kiro/settings/mcp.json` |
| Workspace | `.kiro/settings/mcp.json` |
```json
{
"mcpServers": {
"junobuild": {
"command": "npx",
"args": ["-y", "junobuild-mcp-server"]
}
}
}
```
</details>
<details>
<summary>
### Kilo Code
</summary>
**Config file:**
| Scope | Location |
| ------- | ----------------------------------- |
| User | `~/.config/Kilo Code/User/mcp.json` |
| Project | `.vscode/mcp.json` |
```json
{
"servers": {
"junobuild": {
"command": "npx",
"args": ["-y", "junobuild-mcp-server"]
}
}
}
```
</details>
<details>
<summary>
### Cline
</summary>
**Config file:**
| Scope | Location |
| ----- | ----------------------------------------- |
| User | `cline_mcp_settings.json` (in config dir) |
```json
{
"mcpServers": {
"junobuild": {
"command": "npx",
"args": ["-y", "junobuild-mcp-server"]
}
}
}
```
</details>
---
## Protocol Versions
The server builds against the **2026-07-28** protocol revision (`@modelcontextprotocol/server@2`) and serves **both protocol eras from one toolset**: 2025-era clients (e.g. Claude Desktop mid-2026) still negotiate via `initialize`; 2026-07-28 clients via `server/discover`. No flag needed — era detection is automatic per request.
Features we deliberately **do not** adopt (deprecated or out of scope for a CLI wrapper):
- **Roots** and **Sampling** — the server is a tool runner; input is explicit tool parameters and MRTR (`input_required`) elicitation, not implicit sampling.
- **`logging/setLevel`** (2026-era) — log gating is per-request `_meta.logLevel`; 2025-era sessions still get `logging/setLevel` via the SDK.
- **HTTP+SSE endpoint** — the transport is Streamable HTTP with JSON responses; the deprecated SSE-across-connections mode is not served.
MRTR: `juno_login` asks for the credentials-encryption passphrase via `input_required` (the model answers the embedded form); 2025-era clients get the same flow via the SDK's legacy shim.
## Authenticate the Juno CLI
The server wraps [`@junobuild/cli`](https://juno.build/docs/reference/cli), which must be installed and authenticated:
```bash
npm i -g @junobuild/cli
juno login
```
For non-interactive environments (CI, headless), set the `JUNO_TOKEN` environment variable instead of running `juno login`. Tools that touch Juno state additionally accept `mode` and `profile` parameters to select an environment and identity per call.
## Environment Variables
For non-interactive environments (CI, headless), authenticate using environment variables:
```bash
export JUNO_TOKEN="your-juno-token"
```
### HTTP Mode
The server defaults to stdio. Set `JUNO_MCP_TRANSPORT=http` to serve over Streamable HTTP instead (default port `3000`, bound to `127.0.0.1`; override with `JUNO_MCP_PORT`):
```bash
JUNO_MCP_TRANSPORT=http JUNO_MCP_PORT=3100 node dist/main.js
```
The HTTP mode is stateless and serves both protocol eras from the same toolset as stdio: 2026-07-28 clients negotiate via `server/discover` (modern requests must send the `Mcp-Method`/`Mcp-Name` headers), 2025-era clients via `initialize`. Portable to any web client or load balancer.
Smoke test with curl:
```bash
curl -X POST http://127.0.0.1:3000/mcp \
-H "Mcp-Method: server/discover" \
-H "Mcp-Name: curl" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"server/discover","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{},"io.modelcontextprotocol/clientInfo":{"name":"curl","version":"0"}}}}'
```
> **Security:** HTTP mode binds to localhost only and is unauthenticated — a local dev mode. Do not expose it to the network or pair it with a public tunnel without adding an auth layer (OAuth / reverse-proxy auth).
### Server Tuning
Override defaults to tune resource limits without rebuilding. Values must be positive integers; invalid values fall back to defaults.
| Variable | Default | Description |
| -------------------------- | --------- | -------------------------------------------------------------------- |
| `JUNO_MCP_CHAR_LIMIT` | `25000` | Max characters returned in a single tool response (truncates beyond) |
| `JUNO_MCP_TIMEOUT` | `120000` | Default subprocess timeout in milliseconds |
| `JUNO_MCP_NETWORK_TIMEOUT` | `300000` | Timeout for network-bound operations (deploy, publish, upgrade) in ms |
| `JUNO_MCP_DEBUG` | `false` | When `true`, logs internal errors to stderr (silent catches, notifications) |
| `JUNO_MCP_STATE_SECRET` | random | HMAC key (>=32 bytes) for MRTR `requestState`; set to survive restarts (default per-process random invalidates in-flight flows) |
**Note:** The `juno_create_project` tool does NOT use the interactive `create-juno` CLI. Instead it:
1. Scaffolds a Vite project (React, Next.js, Svelte, Angular, or Vue)
2. Creates a `juno.config.ts` file
This allows fully non-interactive project creation.
### Documentation Access
The `juno_docs` tool fetches documentation directly from the [GitHub repo](https://github.com/junobuild/docs/tree/main/docs), with responses cached for 1 hour:
```
juno_docs({ topic: "build_datastore" }) → Datastore guide
juno_docs({ topic: "build_authentication" }) → Authentication overview
juno_docs({ topic: "reference_cli" }) → CLI reference
juno_docs({ topic: "guides_local_development" }) → Local development guide
```
Topic keys use underscore naming matching folder hierarchy: `build_<feature>`, `reference_cli_<command>`, `guides_<framework>`. Full enumeration of all 159 topics lives in [`src/schemas/docs.ts`](./src/schemas/docs.ts) (`TOPICS` map).
## Tools
| Domain | Tools |
| ------------- | -------------------------------------------------------------------------------------------------- |
| **Identity** | `juno_version`, `juno_login`, `juno_run`, `juno_status`, `juno_auth_status` |
| **Config** | `juno_config_init`, `juno_config_apply`, `juno_create_project` |
| **Hosting** | `juno_hosting_deploy`, `juno_hosting_clear`, `juno_hosting_prune` |
| **Functions** | `juno_functions_build`, `juno_functions_eject`, `juno_functions_publish`, `juno_functions_upgrade` |
| **Changes** | `juno_changes_list`, `juno_changes_apply`, `juno_changes_reject` |
| **Docs** | `juno_docs` |
## Key Parameters
Several tools support optional parameters for enhanced reliability and UX:
| Parameter | Type | Tools | Description |
| ----------- | -------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `retry` | `boolean` | deploy, publish, upgrade | Retry on transient network failures with exponential backoff when enabled. Attempts are set by `maxRetries` |
| `maxRetries`| `number` | deploy, publish, upgrade | Maximum retry attempts when `retry` is enabled (0-10, default 3; backoff 1s → 2s → 4s capped at 10s) |
| `batch` | `number` | deploy, prune | Files processed per batch (deploy default 50, prune default 100). For `deploy`, capped at the detected `source`-dir file count when found (juno.config `source`), so small projects don't waste 50-way parallelism |
| `progress` | `boolean` | deploy, publish, upgrade | Stream real-time progress updates during long-running operations (build status + upload batch progress) |
| `streamLogs`| `boolean` | deploy, publish, upgrade | Stream raw stdout/stderr lines as MCP `notifications/message` events. Independent from `progress` |
| `writeFile` | `boolean` | `juno_config_init` | Write the config file directly to disk instead of returning text for preview |
## Prerequisites
- **Node.js** >= 20
- **@junobuild/cli** `>= 0.15.0` — installed and authenticated (not needed for `juno_version` or `juno_docs`). Minimum version enforced on first call via `checkCliVersion` (`src/constants.ts` `MIN_CLI_VERSION`). Bypass with `JUNO_SKIP_VERSION_CHECK=true`.
- Juno project with `juno.config.ts/js/json` (for config/hosting operations)
## Development
```bash
npm run build # Compile TypeScript to dist/
npm run dev # Watch mode (development)
npm run start # Run compiled dist/main.js
npm run clean # Remove dist/
npm test # Run unit tests
npm run test:coverage # Run tests with coverage report (v8 provider)
```
### Coverage thresholds
The suite enforces the following minimum coverage (configured in `vitest.config.ts`):
- Lines: 80%
- Statements: 80%
- Functions: 80%
- Branches: 75%
Coverage reports are written to `coverage/` (html, lcov, json, plus text summary).
## Publishing
```bash
npm run changeset # Create a changeset (version bump + changelog entry)
npm run version # Apply changesets → bump version
npm run release # Publish to npm
```
## Architecture
The server is a thin wrapper around the Juno CLI (`@junobuild/cli`): every tool
builds a command + flags, spawns the CLI via `child_process`, and formats the
result. Long-running tools (deploy, publish, upgrade) support three execution
strategies — simple, retry, and streaming (progress + log notifications).
**Transports** (chosen at startup via `JUNO_MCP_TRANSPORT`):
- **stdio** (default) — one process per client over stdin/stdout
- **Streamable HTTP** (`JUNO_MCP_TRANSPORT=http`, port 3000 / `JUNO_MCP_PORT`,
127.0.0.1) — Streamable HTTP endpoint, many clients per process
Both serve both protocol eras from the same code: 2025-era clients via
`initialize`, 2026-07-28 clients via `server/discover`. Build file is
`src/main.ts` (entry, transport pick); `src/index.ts` is a side-effect-free
`buildServer()` factory. Auth via `juno_login` (MRTR passphrase flow) uses
HMAC-signed request state.
Key design decisions are documented as [ADRs in `docs/adr/`](./docs/adr/README.md):
- [ADR-001 — Wrap the Juno CLI instead of the API](./docs/adr/001-wrap-cli-not-api.md)
- [ADR-002 — Execution strategy pattern (simple / retry / streaming)](./docs/adr/002-execution-strategies.md)
- [ADR-003 — Context capability system](./docs/adr/003-context-capabilities.md)
- [ADR-004 — Docs caching strategy](./docs/adr/004-docs-caching.md)
- [ADR-005 — SDK v2 stateless migration (2026-07-28 spec)](./docs/adr/005-sdk-v2-stateless.md)
## License
MIT
TDQS
Scored across 18 tools
Each tool targets a distinct resource and action. The domain prefixes (auth, changes, config, etc.) clearly separate concerns, and within each domain, tools like apply, list, reject are unambiguous.
Tools follow a consistent juno_<domain>_<action> pattern, with occasional noun-only names (juno_docs, juno_status) and both singular and plural forms. Minor variations exist but the pattern is clear.
18 tools cover the main aspects of Juno satellite management (auth, changes, config, functions, hosting, etc.) without being overwhelming. The count feels well-scoped for the domain.
The tool set covers core workflows: authentication, config management, changes (apply, list, reject), functions lifecycle, hosting operations, and status checks. Missing are direct user/datastore CRUD or config viewing, but these are out of scope for a CLI-focused MCP.