# klaridian — full documentation > Generate a stateless, instrumented MCP server from your OpenAPI or Swagger spec, in TypeScript or Python. Every documentation page follows, each under its title and canonical URL. --- # Getting Started Source: https://klaridian.dev/docs > What klaridian is, how it fits together, and where to go next. klaridian turns an OpenAPI (or Swagger 2.0) spec into a stateless [Model Context Protocol](https://modelcontextprotocol.io) server — in TypeScript or Python, with observability and tool curation wired in from the start. You run it a handful of times per project, review the plain output, and ship it. ## Your first server The fastest path is `npx` — no install step: ```bash npx klaridian generate --spec ./api.yaml --out ./my-server --plugin otel cd my-server && npm install && npm start ``` Prefer a permanent install, or a native binary with no Node.js? See [Installation](/docs/how-to/installation) for npm, PyPI, Homebrew, and prebuilt binaries. ## How the pieces fit klaridian is a CLI with three verbs, one per stage of the lifecycle: - **`generate`** — read the spec, emit the server. Everything structural is decided here: the [target language](/docs/how-to/target-language), which operations become tools ([curation](/docs/how-to/curation)), the [architecture](/docs/how-to/code-mode), the [transport](/docs/how-to/transports), [auth](/docs/how-to/oauth), and any observability [plugins](/docs/how-to/plugins/otel). - **`start`** — run a generated server locally, in either language. See [Running the server](/docs/how-to/running-the-server). - **`deploy`** — emit the artifacts a hosting platform needs (Docker, Cloudflare Workers, or Fly.io). See [Deploy](/docs/how-to/deploy). New to the flags? [`klaridian init`](/docs/how-to/init) asks a few questions and writes a [configuration file](/docs/how-to/config-file), then prints the exact `generate` command to run. ## What you get - One MCP tool per operation in your spec, with names matching your `operationId`s exactly — or just two tools for large specs with [code-mode](/docs/how-to/code-mode) - A stateless server in TypeScript (default) or Python (`--language python`), with identical tools, annotations, and observability across both - OpenTelemetry tracing and product-analytics events wired at generation time, if you pass a `--plugin` - A real `LICENSE` by default, and plain readable source you can audit before trusting it with credentials Got a Swagger 2.0 spec? Pass it the same way — klaridian detects it and converts it to OpenAPI 3.0 before generating. klaridian is a CLI today. There's no library mode yet (no `import`/`require`) — that's tracked separately, not built. ## Next steps - [Curating the tool surface](/docs/how-to/curation) — control which operations become tools - [Code-mode architecture](/docs/how-to/code-mode) — for large specs - [Deploy](/docs/how-to/deploy) — ship to Docker, Cloudflare, or Fly - [CLI reference](/docs/reference/cli-reference) — every flag - [Plugins: OpenTelemetry](/docs/how-to/plugins/otel) · [PostHog](/docs/how-to/plugins/posthog) --- # Code-mode architecture Source: https://klaridian.dev/docs/how-to/code-mode > For large APIs—a typed client and two tools instead of one tool per operation. ## The problem it solves By default, klaridian makes one MCP tool per OpenAPI operation. That's fine for small specs. On a large one—dozens or hundreds of operations—it produces a bloated tool list that costs agents context and makes them more likely to pick the wrong tool. ## What code-mode generates instead ```bash npx klaridian generate --spec ./api.yaml --out ./my-server \ --architecture code-mode \ --base-url https://api.example.com ``` Instead of one tool per operation, you get exactly two tools: - **`search_docs`**—look up a function's signature and purpose before writing code against it. - **`execute_code`**—run TypeScript against a typed, validated client. One function per operation, generated from your spec. ## Why a sandboxed subprocess Code passed to `execute_code` runs in an isolated **Deno subprocess**, not inside the server's own process. The sandbox only allows: - Network access to the target API's host—nothing else - Reading the generated client's own files—nothing else - No file writes, no subprocess spawning, no arbitrary file reads These boundaries are tested directly, not just declared: a cross-host request is blocked, a file write attempt is blocked, and reading outside the client's directory is blocked. ## Why this design Independent benchmarks compared three approaches for letting an agent call a large API: a typed client + sandboxed execution (what klaridian does), a "dynamic" set of generic lookup/invoke tools, and Cloudflare's isolate-based code mode. The typed-client approach won clearly—the other two sometimes gave wrong answers with no sign anything was wrong. ## Things to know - `--base-url` must be an absolute URL. The sandbox's network permission is fixed at generation time, so there's no way to fall back if it's missing. - Plugins (`--plugin otel`, `--plugin posthog`) aren't supported with code-mode yet—there's no per-operation hook to attach them to in the collapsed `execute_code` tool. - You pick one architecture per server. `tools` and `code-mode` don't mix in a single generation. --- # Configuration file Source: https://klaridian.dev/docs/how-to/config-file > Set default flag values for klaridian generate in a file you check in. ## Why this matters Most teams run `klaridian generate` the same way every time: the same license, the same transport, the same plugin. Repeating those flags on every command is noise, and it's easy to forget one. A configuration file holds the defaults so each command stays short. The file is a defaults layer, not a source of truth. A flag you pass on the command line always wins over the file, and the file always wins over the built-in default. ## Use a configuration file Create `klaridian.config.json` in the directory you run the command from: ```json { "license": "apache-2.0", "transport": "streamable-http", "port": 8080, "plugin": ["otel"], "pluginConfig": ["otel.serviceName=my-server"] } ``` Then run `generate` without those flags: ```bash npx klaridian generate --spec ./api.yaml --out ./my-server ``` klaridian finds the file automatically and reports which one it used. ## Point to a specific file Pass `--config` to use a file with a different name or location: ```bash npx klaridian generate --spec ./api.yaml --out ./my-server --config ./ci/klaridian.prod.json ``` When you pass `--config`, the file must exist and contain a JSON object. A missing or malformed file fails the command with a clear error instead of falling back to the defaults. ## Keys Use the same names as the command's flags, in camelCase: `baseUrl` for `--base-url`, `oauthIssuer` for `--oauth-issuer`. `plugin` and `pluginConfig` take arrays. Run `klaridian generate --help` for the full list, or see the [CLI reference](/docs/reference/cli-reference). An unknown key produces a warning and is ignored, so a typo such as `frce` for `force` doesn't pass unnoticed. `--spec` and `--out` are required and can't come from the file. The command needs both before it reads the file. ## Precedence For each flag, klaridian uses the first value it finds: 1. The flag you passed on the command line. 2. The value in the file. 3. The built-in default. For example, with `"license": "apache-2.0"` in the file, `generate` produces an Apache 2.0 license by default, but `--license mit` on the command line still wins. --- # Curating the tool surface Source: https://klaridian.dev/docs/how-to/curation > Control which OpenAPI operations become MCP tools. ## Why curate An OpenAPI spec built for humans is generous—hundreds of small, separate endpoints. Agents pay a real cost for every tool they see: more context, more chances to pick the wrong one. Converting every operation into a tool, 1:1, can leave agents with a bloated, confusing tool list. Curation lets you decide what agents actually see. ## By tag Most specs group operations with OpenAPI tags. Use these to include or exclude by tag: ```bash npx klaridian generate --spec ./api.yaml --out ./my-server \ --exclude-tags internal,admin ``` ```bash npx klaridian generate --spec ./api.yaml --out ./my-server \ --include-tags public ``` ## By operation ID Exclude specific operations regardless of tag: ```bash npx klaridian generate --spec ./api.yaml --out ./my-server \ --exclude-operation-ids deleteAccount,purgeData ``` ## By path or method Some specs don't use tags at all. `--include-paths`, `--exclude-paths`, `--include-methods`, and `--exclude-methods` work without them—they match on the operation's URL path (regex) or HTTP method: ```bash npx klaridian generate --spec ./api.yaml --out ./my-server \ --exclude-paths "^/internal/" \ --exclude-methods delete ``` Path/method filters and tag filters can combine—an operation must pass both to be included. ## From the spec, with `x-klaridian` The filters above are things _you_ decide at generate time. Sometimes the API author is better placed to decide—and wants those decisions to travel with the spec. klaridian reads an `x-klaridian` extension on any operation for exactly that. ### Hide an operation Set `expose: false` to keep an operation out of the generated tool surface entirely—useful for internal or maintenance endpoints that should never become agent tools: ```yaml paths: /admin/reindex: post: operationId: reindexCatalog x-klaridian: expose: false # never generated as a tool ``` An operation with no `x-klaridian`, or without `expose`, is exposed as usual (fail-open). This composes with the flag-based filters above: an operation is generated only if it survives both. ### Tune the tool annotations Every generated tool carries MCP annotation hints (`readOnlyHint`, `destructiveHint`, `openWorldHint`) that tell an agent how risky a tool is. By default klaridian derives them from the HTTP method: GET is read-only, DELETE is destructive, POST and PATCH are writes. When the method isn't the whole story—a `POST /calls` that spends money, or a `POST /search` that changes nothing—the author can state the truth directly: ```yaml paths: /calls: post: operationId: startCall x-klaridian: destructive: true # a POST that really does something irreversible openWorld: true /search: post: operationId: search x-klaridian: readOnly: true # a POST that only reads ``` Each hint is optional and overrides the method-derived default **for that hint alone**—anything you leave out keeps its default. Recognised keys: `readOnly`, `destructive`, `openWorld`, `expose`, and `title`. ### Set the tool title By default a tool's display title is the operation's `summary`, falling back to a humanized version of its `operationId` (`listBooks` → "List Books"). Set `title` on `x-klaridian` to override both: ```yaml paths: /books/{id}: delete: operationId: deleteBook summary: Delete a book x-klaridian: destructive: true title: Remove a book from the catalog # wins over the summary ``` Title precedence is `x-klaridian.title` → the OpenAPI `summary` → the humanized `operationId`. The tool's `name` (what the agent calls) is always the `operationId`—only the human-facing title changes. A ready-to-generate example lives at [`examples/annotated/openapi.json`](https://github.com/klaridian/klaridian/blob/main/examples/annotated/openapi.json) in the repository. ## Flags or `x-klaridian`: When to use which The flags and the `x-klaridian` extension aren't two ways to do the same thing—they answer to different people at different times. - **Flags are the generator's decision, made at generate time.** They live in your command (or your [`klaridian.config.json`](/docs/how-to/config-file)), apply to one build, and don't travel with the spec. Reach for them when the choice is yours as the person running klaridian: "for this server, only expose the `public` tags," or "skip everything under `/internal/`." Flags also cover coarse curation—by tag, path, or method—that `x-klaridian` can't express. - **`x-klaridian` is the API author's decision, and it travels with the spec.** It's versioned alongside the contract, so every consumer generating from that spec inherits it. Reach for it when the knowledge belongs to whoever owns the API: a `POST /calls` that spends money is `destructive`, `/admin/reindex` should never become a tool (`expose: false`), and a raw `operationId` deserves a human `title`. A consumer shouldn't have to rediscover any of that through flags. The two compose. An operation is generated only if it survives both layers, so `expose: false` in the spec and `--exclude-operation-ids` on the command line both hide an operation—the difference is intent. `expose: false` says "this is never a tool, for anyone"; `--exclude-operation-ids` says "not in this build." Use the spec for durable, author-owned truth; use flags for the choices that change from one generation to the next. ## Interactively Prefer to pick tags by hand instead of writing flags? Use `--interactive`: ```bash npx klaridian generate --spec ./api.yaml --out ./my-server --interactive ``` This prompts you for which tags to include before generating. It needs a real terminal—it fails with a clear error in CI or scripts, instead of silently generating with no tools. --- # Deploy Source: https://klaridian.dev/docs/how-to/deploy > Emit deploy artifacts for a generated server with klaridian deploy. `klaridian deploy` takes a server you already generated and emits the files a hosting platform needs to run it. It follows an **emit + shell-out** model: klaridian writes the platform's native configuration (a portable `Dockerfile` for `--target docker`) and you hand them to that platform's own CLI. klaridian never reimplements deploy infrastructure. Deploy reconfigures nothing about the server itself — every structural decision (spec, transport, port, plugins, auth) was made at generation time. It only makes sense for a **streamable-http** server: a `stdio` server has no network endpoint to expose, so `deploy` refuses one. ## Docker (the portable baseline) ```bash klaridian deploy ./my-server --target docker ``` This writes a `Dockerfile` and `.dockerignore` into the project. The Dockerfile is vendor-neutral — it runs on Fly, Render, Railway, Cloud Run, or a self-hosted box. It's an ephemeral build input, not a maintained part of your generated project. - **TypeScript projects** get a multi-stage build: `npm run build` produces a self-contained bundle, and the runtime image carries only that bundle on a slim Node base. - **Python projects** get a slim Python image that installs `requirements.txt` and runs `server.py`. Build and run it locally: ```bash docker build -t my-server ./my-server docker run -p 3000:3000 -e KLARIDIAN_BASE_URL=https://api.example.com my-server ``` ## Cloudflare Workers (the edge target) ```bash klaridian deploy ./my-server --target cloudflare ``` This writes a `worker.ts` entry and a `wrangler.toml` manifest. The Worker reuses the same server factory the local server uses — the MCP SDK exposes a web-standard `fetch` handler, so the generated server runs on Cloudflare's edge runtime unchanged. Validate it with no account needed, then deploy: ```bash cd ./my-server npx wrangler deploy --dry-run # compiles the Worker locally, no login # set KLARIDIAN_BASE_URL in wrangler.toml, then: npx wrangler deploy ``` `wrangler.toml` presets `KLARIDIAN_ALLOWED_HOSTS` to `.workers.dev` — add your custom domain if you use one. This target is **TypeScript-only**: Cloudflare Workers runs JavaScript, so a Python project (or a `code-mode` server, which spawns a Deno sandbox) is refused — use `--target docker` for those. ## Fly.io (one-command container deploy) ```bash klaridian deploy ./my-server --target fly ``` This writes the Docker artifacts plus a `fly.toml`. Fly builds and runs the emitted `Dockerfile`, so this works for **both** TypeScript and Python projects. Deploy with Fly's CLI: ```bash cd ./my-server fly launch --copy-config --no-deploy # claims a unique app name, updates fly.toml fly secrets set KLARIDIAN_BASE_URL=https://api.example.com fly deploy ``` `fly.toml` presets `KLARIDIAN_ALLOWED_HOSTS` to `.fly.dev`, sets `internal_port` to the generated port, `force_https`, and scale-to-zero (`min_machines_running = 0`) so an idle server costs nothing. Update the host if you attach a custom domain. ## Reaching the server once it's deployed The generated server reads its runtime configuration from the environment (see [Transports](/docs/how-to/transports) for the full table). Two matter most in a container: - `KLARIDIAN_BIND_HOST=0.0.0.0` — already set in the emitted Dockerfile, so the server binds all interfaces instead of loopback. - `KLARIDIAN_ALLOWED_HOSTS` — **set this at deploy time to your public hostname** (for example `myapp.fly.dev`). Without it, requests routed through that hostname are rejected with `403 Invalid Host`. The platform injects `PORT`; the server honors it automatically. ## Options | Flag | What it does | | --- | --- | | `--target ` | Which target to emit for: `docker`, `cloudflare`, or `fly`. | | `--out ` | Where to write the artifacts. Defaults to the project directory. | | `--force` | Overwrite existing artifacts instead of refusing. | | `--json` | Print a single machine-readable JSON result instead of human-readable lines. | --- # Onboarding wizard Source: https://klaridian.dev/docs/how-to/init > Use klaridian init to scaffold a klaridian.config.json before your first generate. ## Why this matters `klaridian generate` has many flags. The first time you run it, choosing them one by one on the command line is easy to get wrong. `klaridian init` asks a short series of questions and writes the answers to a [configuration file](/docs/how-to/config-file) that `generate` reads on every later run. `init` writes the file and nothing else. It doesn't generate a server. When it finishes, it prints the exact `generate` command to run next. ## Run the wizard ```bash npx klaridian init ``` The wizard asks for: - The OpenAPI spec path or URL. - The output directory for the generated server. - The observability plugins to enable, if any. - The license for the generated server. - The transport for the generated server. It writes `klaridian.config.json` in the current directory, then prints the next command: ```text ✅ Wrote /path/to/klaridian.config.json Next: run `klaridian generate --spec ./api.yaml --out ./my-server` (klaridian.config.json is picked up automatically) ``` Run that command. `generate` finds the file and takes the plugin, license, and transport values from it. ## Skip a prompt with a flag Pass a flag and the wizard doesn't ask that question: ```bash npx klaridian init --spec ./api.yaml --license apache-2.0 ``` This still prompts for the output directory, plugins, and transport. The rule is the same one `generate` uses for the configuration file: an explicit flag wins, and the wizard fills the rest. ## Run without prompts Pass every field the wizard would ask for and it writes the file without prompting, which is what you want in a script or a container: ```bash npx klaridian init \ --spec ./api.yaml \ --generate-out ./my-server \ --plugin otel \ --license mit \ --transport stdio ``` `--spec` and `--generate-out` are required in this mode. Without a terminal to prompt and without those flags, the command fails with a clear message instead of guessing. Use `--json` for a machine-readable result. `--json` is always non-interactive, so pass the fields as flags. ## Flags | Flag | What it does | |---|---| | `--out ` | Where to write the config file. Defaults to `./klaridian.config.json`. | | `--generate-out ` | The output directory for `generate`, written as the file's `out` field. This is different from `--out`, which is where the config file itself goes. | | `--force` | Overwrite the config file if it already exists. | | `--spec`, `--plugin`, `--license`, `--transport` | Set the matching field and skip its prompt. Same names and values as the `generate` flags. | See the [CLI reference](/docs/reference/cli-reference) for the full list. ## What the file can't hold yet `generate` still needs `--spec` and `--out` on the command line even when a configuration file is present, so the "Next" command includes them. The file records your choices for `plugin`, `license`, and `transport`. See [Configuration file](/docs/how-to/config-file) for how precedence works. --- # Installation Source: https://klaridian.dev/docs/how-to/installation > Install the klaridian CLI from npm, PyPI, or Homebrew, or download a prebuilt binary. klaridian is a single CLI, published on every major channel. Each channel delivers the same generator, so pick whichever fits your toolchain. ## npm / npx (Node.js) Because klaridian is a generator you typically run a handful of times per project, the lightest option is `npx` — it runs the latest version without installing anything: ```bash npx klaridian generate --spec ./api.yaml --out ./my-server --plugin otel ``` If you reach for it often, install the `klaridian` command globally instead: ```bash npm install -g klaridian ``` Both run on Node.js. If you'd rather not depend on Node, use the PyPI or Homebrew channels below — they ship a self-contained native binary. ## PyPI (native binary, no Node.js) ```bash pip install klaridian ``` `uv` and `pipx` work too: ```bash uv tool install klaridian pipx install klaridian ``` This package ships a **prebuilt native binary** — no Node.js, no virtualenv, nothing to compile. It's the same CLI published to npm, compiled to a standalone executable and distributed as a platform-specific wheel (the pattern [ruff](https://pypi.org/project/ruff/) and [uv](https://pypi.org/project/uv/) use). ## Homebrew (macOS and Linux, native binary) ```bash brew tap klaridian/klaridian brew install klaridian ``` The tap registers klaridian's formula repository once; after that, `brew install klaridian` (and later `brew upgrade klaridian`) works by short name. The formula downloads the prebuilt binary from the GitHub Release — it doesn't depend on Node.js and doesn't build from source, so the install is instant. ## Direct binary download Every [GitHub Release](https://github.com/klaridian/klaridian/releases/latest) attaches one bare binary per platform. Download the one for your system, mark it executable, and run it: ```bash curl -fsSL -o klaridian \ https://github.com/klaridian/klaridian/releases/latest/download/klaridian-darwin-arm64 chmod +x klaridian ./klaridian --version ``` Swap the asset name for your platform: | Platform | Asset | | --- | --- | | macOS (Apple Silicon) | `klaridian-darwin-arm64` | | macOS (Intel) | `klaridian-darwin-x64` | | Linux (arm64) | `klaridian-linux-arm64` | | Linux (x64) | `klaridian-linux-x64` | | Windows (x64) | `klaridian-windows-x64.exe` | ## Which channel should I pick? - Already on Node.js? Run it with **`npx`**, or install globally with **npm**. - Want a zero-dependency binary in a Python or mixed toolchain? Use **PyPI**. - On macOS or Linux and managing tools with Homebrew? Use **Homebrew**. - Pinning a specific version in CI, or air-gapped? Use the **direct binary download**. The PyPI, Homebrew, and direct-download binaries are compiled with `bun --compile` and produce byte-identical output to the Node build, so the generated servers are the same whichever channel you install from. ## Verify the install ```bash klaridian --version ``` ## Next steps - [Getting started](/docs) — generate your first server - [Curating the tool surface](/docs/how-to/curation) - [CLI reference](/docs/reference/cli-reference) — every flag --- # JSON output for agents Source: https://klaridian.dev/docs/how-to/json-output > Drive klaridian from an agent or script with --json, structured results, and stable error codes. Every klaridian command prints friendly, human-readable progress by default. When an agent or a script runs klaridian, pass `--json` to get one machine-readable value on stdout instead — no emojis to scrape, no prose to pattern-match. ## What --json does `--json` changes the output contract, not the behavior: - Exactly one JSON value is written to stdout. Nothing else goes there. - Step-by-step progress is suppressed (as if `--quiet` were set). - On failure, the error is a JSON object on stdout too, and the process exits non-zero. ```bash klaridian generate --spec ./api.yaml --out ./my-server \ --base-url https://api.example.com --plugin otel \ --plugin-config otel.serviceName=my-server --json ``` `--json` is available on `generate`, `init`, `deploy`, `start`, and the `plugins` / `licenses` listings. ## A successful generate ```json { "success": true, "outputDir": "/abs/path/to/my-server", "toolCount": 24, "curatedFromTotal": null, "transport": "stdio", "port": null, "architecture": "tools", "language": "typescript", "license": "MIT", "plugins": ["otel"], "nextSteps": "cd /abs/path/to/my-server && npm install && npm run build && npm start", "warnings": [] } ``` `toolCount` is the number of MCP tools emitted. `curatedFromTotal` is the number of operations before curation (or `null` when nothing was filtered). `warnings` holds any non-fatal notices — the same messages a human would see on stderr, so an agent never has to read stderr to know something was off. ## A failure Every failure is the same shape, whatever the command: ```json { "success": false, "error": "Plugin \"otel\" is missing required config: serviceName. Provide via --plugin-config otel.=.", "stage": "validate-plugin", "code": "VALIDATE_PLUGIN", "warnings": [] } ``` - `code` is a stable, machine-readable identifier. Branch on it. It's `UPPER_SNAKE_CASE` and it won't change when the wording of `error` does. - `stage` is the same value in lowercase-hyphen form (`validate-plugin`), naming the step that failed. - `error` is the human message. Read it for logs or to show a person, but don't pattern-match it in code — that's what `code` is for. The process also exits non-zero on failure, so a script can check the exit status before it even parses the JSON. ### Error codes you'll see Codes map one-to-one to the stage that failed. Common ones from `generate`: | Code | When | |---|---| | `VALIDATE_LANGUAGE` | `--language` isn't `typescript` or `python`, or an unsupported language/architecture combination | | `VALIDATE_PLUGIN` | An unknown `--plugin`, or a plugin missing required `--plugin-config` | | `VALIDATE_TRANSPORT` | An unsupported `--transport` | | `VALIDATE_PORT` | An invalid `--port` | | `VALIDATE_CURATION` | A curation flag (`--include-tags`, `--exclude-tags`, …) that selects nothing or conflicts | | `VALIDATE_OAUTH` | An incomplete or inconsistent `--oauth-*` set | | `VALIDATE_LICENSE` | An unknown `--license` | | `CHECK_OUTPUT_DIR` | `--out` exists and is non-empty, and `--force` wasn't passed | | `CONFIG_FILE` | The configuration file is missing, malformed, or unreadable | | `EMIT` | Generation failed while writing the server | | `UNEXPECTED` | A genuinely unforeseen error — treat it as a bug worth reporting | New stages may be added over time, so treat the list as open: match the codes you handle and fall back on `UNEXPECTED` for the rest. Because `code` is always the upper-case, underscored form of `stage`, you can derive one from the other if you only ever read one field. ## Why the split An agent driving klaridian in a chain needs to answer two questions without guessing: did it work, and if not, what kind of failure was it. `success` answers the first; `code` answers the second without ever string-matching English prose that might be reworded in the next release. The human-readable default stays exactly as it was — `--json` is purely additive. --- # Licensing Source: https://klaridian.dev/docs/how-to/licensing > Every generated server ships with a real license, by default. ## Why this matters An MCP server runs with real credentials, next to an agent that decides on its own when to call it. That's a bigger trust ask than a normal API a human calls deliberately. Shipping a server with no license attached is a real gap in that trust—so klaridian sets one by default instead of leaving it blank. ## Default ```bash npx klaridian generate --spec ./api.yaml --out ./my-server ``` This ships MIT by default: a real `LICENSE` file, and `"license": "MIT"` in `package.json`. ## Choosing a different license ```bash npx klaridian generate --spec ./api.yaml --out ./my-server --license apache-2.0 ``` Options: `mit` (default), `apache-2.0`, or `none`. Choosing `none` prints a warning—it's allowed, but you're opting out of something klaridian considers important. ## Setting the copyright holder ```bash npx klaridian generate --spec ./api.yaml --out ./my-server --author "Jane Doe" ``` Defaults to your git `user.name`. Falls back to "the project author" if that isn't set either. --- # Publishing to the MCP Registry Source: https://klaridian.dev/docs/how-to/mcp-registry > Give your server a reverse-DNS name for the official MCP Registry. ## What this does The [official MCP Registry](https://modelcontextprotocol.io) expects servers to identify themselves with a reverse-DNS-style name, like `io.github.you/server-name`. Setting `--registry-name` at generation time writes that name into the generated `server.json` and into `package.json`'s `mcpName` field. ```bash npx klaridian generate --spec ./api.yaml --out ./my-server \ --registry-name io.github.yourname/your-server ``` ## What this doesn't do `--registry-name` only sets the name in the generated files. It doesn't publish anything—actually submitting your server to the registry is a separate step you do yourself, using the registry's own tools. --- # OAuth 2.1 Source: https://klaridian.dev/docs/how-to/oauth > Protect a remote server with an external identity provider. ## What this is (and isn't) klaridian can generate a server that checks OAuth bearer tokens before running any tool call. It does **not** generate an OAuth server—that stays with your identity provider (Auth0, WorkOS, or similar). klaridian's generated server only ever validates tokens; it never issues them. This works with both target languages (`--language typescript`, the default, and `--language python`) and only with `--transport streamable-http`. A `stdio` server takes its credentials from the environment, not from inbound tokens, so OAuth doesn't apply there. ## Set it up ```bash npx klaridian generate --spec ./api.yaml --out ./my-server \ --transport streamable-http \ --oauth-issuer https://your-idp.example.com \ --oauth-audience https://mcp.yourcompany.com/mcp ``` - **`--oauth-issuer`**—your identity provider's issuer URL. - **`--oauth-audience`**—the exact URL this server will be reachable at. Tokens issued for a different audience are rejected. This is required whenever you set `--oauth-issuer`. ## Optional flags - **`--oauth-jwks-uri`**—where to fetch your IdP's signing keys. Usually you don't need to set this: klaridian resolves it automatically from your issuer's OIDC discovery document. - **`--oauth-required-scopes`**—a comma-separated list of scopes every tool call must carry. Leave this unset if any valid token should be enough. ## What you still need to do Your identity provider—not klaridian—handles user login, consent, and issuing tokens. klaridian's job stops at generating a server that correctly validates whatever token it receives. ## Language notes Both target languages validate tokens the same way—JWKS-backed signature, expiry, issuer, and audience (RFC 8707) checks, an RFC 9728 metadata document, and required-scope enforcement: - **TypeScript** uses the `jose` library and the SDK's bearer-auth helpers. - **Python** uses `PyJWT` (installed as `pyjwt[crypto]`). The generated project adds an `auth.py` module and pins the dependency only when you enable OAuth. Both read the same environment variables at runtime, so one build can point at different identity providers per deployment: `KLARIDIAN_OAUTH_ISSUER`, `KLARIDIAN_OAUTH_JWKS_URI`, `KLARIDIAN_OAUTH_AUDIENCE`, and `KLARIDIAN_OAUTH_REQUIRED_SCOPES` (comma-separated). The values you pass at generation time become the defaults. --- # Amplitude Source: https://klaridian.dev/docs/how-to/plugins/amplitude > See which tools agents actually use, in Amplitude. ## Enable it ```bash npx klaridian generate --spec ./api.yaml --out ./my-server --plugin amplitude ``` Every tool call sends an Amplitude event with the tool name, how long it took, and whether it succeeded. This tells you which tools get used—OpenTelemetry tells you if a call is slow or broken, but not whether anyone's calling it. ## Configure it ```bash AMPLITUDE_API_KEY=... \ AMPLITUDE_SERVER_ZONE=US \ node dist/src/index.js ``` `AMPLITUDE_API_KEY` is your Amplitude project API key and is required. `AMPLITUDE_SERVER_ZONE` picks the data region—`US` or `EU`—and defaults to the value you chose at generation time (`US` unless you set it otherwise). ## Why this is a separate plugin from OTel Tracing has one open standard—OpenTelemetry—so one `otel` plugin works with every backend. Product analytics doesn't have that: PostHog, Amplitude, and Mixpanel each need their own integration. `amplitude` works the same way as `posthog` and `mixpanel`. ## One plugin at a time Today you can pick one plugin per server—`otel`, or one of the analytics plugins, not both together. Combining an engineering plugin and a product plugin on the same server is planned, not built yet. ## Python and TypeScript The `amplitude` plugin supports both target languages. With `--language python` it ships a vendored `instrumentation/amplitude.py` built on the Amplitude Python SDK; the default TypeScript target ships `src/instrumentation/amplitude.ts` on `@amplitude/analytics-node`. Both wrap tool dispatch the same way and read the same `AMPLITUDE_API_KEY` and `AMPLITUDE_SERVER_ZONE` environment variables. --- # Mixpanel Source: https://klaridian.dev/docs/how-to/plugins/mixpanel > See which tools agents actually use, in Mixpanel. ## Enable it ```bash npx klaridian generate --spec ./api.yaml --out ./my-server --plugin mixpanel ``` Every tool call sends a Mixpanel event with the tool name, how long it took, and whether it succeeded. This tells you which tools get used—OpenTelemetry tells you if a call is slow or broken, but not whether anyone's calling it. ## Configure it ```bash MIXPANEL_TOKEN=... \ node dist/src/index.js ``` `MIXPANEL_TOKEN` is your Mixpanel project token and is the only required setting. ## Why this is a separate plugin from OTel Tracing has one open standard—OpenTelemetry—so one `otel` plugin works with every backend. Product analytics doesn't have that: PostHog, Amplitude, and Mixpanel each need their own integration. `mixpanel` works the same way as `posthog` and `amplitude`. ## One plugin at a time Today you can pick one plugin per server—`otel`, or one of the analytics plugins, not both together. Combining an engineering plugin and a product plugin on the same server is planned, not built yet. ## No flush on exit needed Unlike PostHog and Amplitude, the Mixpanel plugin adds no shutdown flush handler. The Mixpanel SDK sends each event over HTTP immediately rather than batching client-side, so there's no in-memory queue to lose when a short-lived server exits. This is a real behavior difference, not an omission. ## Python and TypeScript The `mixpanel` plugin supports both target languages. With `--language python` it ships a vendored `instrumentation/mixpanel.py` built on the Mixpanel Python SDK; the default TypeScript target ships `src/instrumentation/mixpanel.ts` on the `mixpanel-node` package. Both wrap tool dispatch the same way and read the same `MIXPANEL_TOKEN` environment variable. --- # OpenTelemetry Source: https://klaridian.dev/docs/how-to/plugins/otel > Trace every tool call without writing instrumentation code. ## Enable it ```bash npx klaridian generate --spec ./api.yaml --out ./my-server --plugin otel ``` Every tool call gets wrapped in a trace span automatically. You don't write any tracing code. ## How traces are sent Traces always go through the standard `OTLPTraceExporter`, and diagnostic logs go to `stderr`, never `stdout`. This matters: writing to `stdout` would corrupt the server's communication with its client. ## Joining the caller's trace When an MCP client sends W3C trace context in the request `_meta` (the `traceparent`, `tracestate`, and `baggage` keys, per the MCP specification), the generated server continues that trace. Each tool-call span becomes a child of the caller's span instead of a disconnected root, so a single distributed trace spans the client, the generated server, and the upstream API it calls. You don't configure anything for this. The server registers the W3C trace-context and baggage propagators and extracts the parent context from every request that carries one. A request without trace context still produces a normal root span. ## Point it at your backend The generated server reads standard OpenTelemetry environment variables—no klaridian-specific config: ```bash OTEL_EXPORTER_OTLP_ENDPOINT=https://otlp.your-backend.example \ OTEL_EXPORTER_OTLP_HEADERS="api-key=..." \ node dist/src/index.js ``` This works with Datadog, Grafana Tempo, Honeycomb, or any backend that accepts standard OTLP. --- # PostHog Source: https://klaridian.dev/docs/how-to/plugins/posthog > See which tools agents actually use. ## Enable it ```bash npx klaridian generate --spec ./api.yaml --out ./my-server --plugin posthog ``` Every tool call sends a PostHog event with the tool name, how long it took, and whether it succeeded. This tells you which tools get used—OpenTelemetry tells you if a call is slow or broken, but not whether anyone's calling it. ## Configure it ```bash POSTHOG_API_KEY=phc_... \ POSTHOG_HOST=https://app.posthog.com \ node dist/src/index.js ``` ## Why this is a separate plugin from OTel Tracing has one open standard—OpenTelemetry—so one `otel` plugin works with every backend. Product analytics doesn't have that: PostHog, Amplitude, and Mixpanel each need their own integration. `posthog` is the first; `amplitude` and `mixpanel` work the same way. ## One plugin at a time Today you can pick one plugin per server—`otel`, or one of the analytics plugins, not both together. Combining an engineering plugin and a product plugin on the same server is planned, not built yet. ## Using FastMCP instead? If you're building with Python's FastMCP directly rather than generating with klaridian, there's a standalone [`PostHogMiddleware`](https://github.com/klaridian/klaridian/tree/main/packages/python-posthog-middleware) you can add with `mcp.add_middleware(PostHogMiddleware(...))`. --- # Running the server Source: https://klaridian.dev/docs/how-to/running-the-server > The fastest path to a running server, and the lifecycle behind it. ## Quick start ```bash # Generate, install, and build in one step npx klaridian generate --spec ./api.yaml --out ./my-server --base-url https://api.example.com --install # Run it — and every time you restart cd my-server && npm start ``` That's the common path for most people. `klaridian start ./my-server` works the same as `npm start` above, if you'd rather run it from outside the project directory. Everything below explains what's happening under the hood — read on if you're wiring this into CI, want to review the generated project before installing anything, or are curious why `--install` and `klaridian start` don't do the same thing. Generating a Python server (`--language python`)? The lifecycle is the same three steps, but the prepare and run commands are Python's — see [Python](#python) below. `klaridian start` launches either language. ## The lifecycle A klaridian project moves through three steps, at three different frequencies, with one hard rule: **running the server must never touch the network.** | Step | What it does | How often | Touches the network? | |---|---|---|---| | **Generate** | `klaridian generate` — decides everything about the server (spec, curation, architecture, plugins, transport, auth) and writes the project | Once per project (or again when a real decision changes) | No, unless you pass `--install` | | **Prepare** | TypeScript: `npm install && npm run build`; Python: `python -m venv .venv && pip install -r requirements.txt` — turns the written project into a runnable form | Once per generate, until you generate again | Yes — installing dependencies | | **Run** | `klaridian start` (or the language's own `npm start` / `python server.py`) — starts the server | Every restart, every deploy | Never | The table's Prepare and Run commands are the TypeScript ones by default; the [Python](#python) section below shows the venv/pip equivalents. Everything else — the three steps, the frequencies, and the network rule — is identical across both languages. `--install` (used in the quick start above) runs the prepare step automatically right after generate finishes, so you go from spec to a ready-to-run project in one command instead of three. It's opt-in — a bare `generate` still does nothing but write files, which matters if you're scripting this, running it in CI, or want to look at the generated code before installing anything. `--install` is a TypeScript-only convenience today; for a Python project, run the prepare step by hand (see [Python](#python)). Without `--install`, do it by hand: ```bash npx klaridian generate --spec ./api.yaml --out ./my-server --base-url https://api.example.com cd my-server && npm install && npm run build && npm start ``` Either way, once the project is built, restarting it is always just `npm start` (or `klaridian start`) — never `npm install` or `npm run build` again, because the build already produced a single self-contained `dist/server.bundle.js`. This is also why `klaridian start` refuses to run install/build for you (see below): it's designed to be safe to call on every restart, and a step that touches the network can't be part of that. ## `klaridian start` `klaridian start [dir]` is a thin convenience wrapper around `npm start`, for when it's easier to remember one command than "which directory, and which script": ```bash npx klaridian start ./my-server ``` It takes **no generation flags** — no `--spec`, `--architecture`, `--plugin`, `--language`, or anything else. Everything those flags would configure is already baked into `./my-server` by the `generate` that produced it. If you want a different architecture, a different plugin, a different language, or a different spec, run `klaridian generate` again (optionally into the same `--out` with `--force`) — don't look for a flag on `start`, there isn't one and there won't be. `start` launches whichever language the project was generated in: a TypeScript project runs through `npm start`, a Python project through the project's own `.venv` interpreter on `server.py`. You don't tell it which — it reads the project. Either way it passes no transport or port flags: those were chosen at generation time and are baked into the project, so a bare launch reproduces the generated server exactly. Two checks run before handing off to the server: - **Is this a klaridian project?** `start` looks for a `package.json` with a `start` script and a `server.json` (TypeScript), or a `pyproject.toml` and a `server.py` (Python) — the pairs only `generate` emits. If neither matches, it fails with a clear message instead of a confusing runtime error. - **Has it been prepared?** For TypeScript, `start` checks that the built entry (`dist/server.bundle.js` by default) exists; if not, it tells you to run `npm install && npm run build` (or generate again with `--install`). For Python, it checks that the project's `.venv` exists; if not, it points you at the `python -m venv .venv && … && pip install -r requirements.txt` steps `generate` printed. Either way it fails with an actionable message rather than a generic `MODULE_NOT_FOUND` or `ModuleNotFoundError`. `start` deliberately never runs the prepare step itself — see the network rule above. Once those pass, `start` hands stdin/stdout/stderr straight to the generated server (inherited I/O) — this matters for `stdio`-transport servers, where nothing may sit between the MCP client and the server on that stream. ## Python A Python project (`--language python`) follows the same three steps, with Python's own prepare and run commands. Generate it, prepare it once, then run it — the same generate-once, run-many shape as TypeScript: ```bash # Generate (writes files only — no network, same as TypeScript) npx klaridian generate --spec ./api.yaml --out ./my-server --base-url https://api.example.com --language python # Prepare, once (the venv + pip equivalent of npm install && npm run build) cd my-server python -m venv .venv && . .venv/bin/activate pip install -r requirements.txt # Run — and every restart klaridian start . ``` `klaridian start` launches the Python server through the project's own `.venv` interpreter, so activating the virtual environment first isn't required for `start` — it finds `.venv` on its own. If you'd rather run it directly, `python server.py` (with the venv active) does the same thing. Two things are TypeScript-only for now, and `generate` tells you so rather than silently doing nothing: - **`--install`.** The Python prepare step (create the venv, `pip install`) is a manual step today — run the three prepare commands above. `klaridian start` still refuses to run them for you, exactly as it refuses `npm install` for TypeScript: preparing touches the network, and running must not. - **`--architecture code-mode` and OAuth (`--oauth-*`).** Not yet supported for Python — see [Target language](/docs/how-to/target-language) for the current parity list. ## Configuring a running server Everything that varies per environment — base URL, auth tokens, plugin credentials, bind host — is read from environment variables by the generated server itself, not passed as a flag to `start` or `generate`. See the relevant how-to page ([OAuth](/docs/how-to/oauth), [plugins](/docs/how-to/plugins), [transports](/docs/how-to/transports)) for which variables apply to your setup. --- # Target language Source: https://klaridian.dev/docs/how-to/target-language > Generate the server in TypeScript (default) or Python. klaridian generates the MCP server in TypeScript by default. Pass `--language python` to generate a Python server instead. Both languages produce the same tools, the same annotations, and the same observability behavior from the same OpenAPI spec—the choice is about the runtime you want to deploy and maintain. ## TypeScript (the default) ```bash npx klaridian generate --spec ./api.yaml --out ./my-server ``` The generated project uses the official `@modelcontextprotocol/server` SDK. Run it with `npm install && npm run build && npm start`, or let klaridian prepare it for you with `--install`. ## Python ```bash npx klaridian generate --spec ./api.yaml --out ./my-server --language python ``` The generated project uses the official `mcp` Python SDK. It ships with a `requirements.txt`, a `pyproject.toml`, and a `server.py` entry point. Set it up and run it with: ```bash cd ./my-server python -m venv .venv && . .venv/bin/activate pip install -r requirements.txt export KLARIDIAN_BASE_URL=https://api.example.com python server.py ``` Once the virtual environment is prepared, `klaridian start ./my-server` launches the Python server too—it finds the project's `.venv` and runs `server.py` for you, the same single command that starts a TypeScript server. For the network transport, add the flags to both the generate command and the run command: ```bash npx klaridian generate --spec ./api.yaml --out ./my-server \ --language python --transport streamable-http --port 3000 python server.py --transport streamable-http --port 3000 ``` ## What's the same across both languages - **Tools.** One tool per OpenAPI operation, with identical names and input schemas. - **Output schemas.** When an operation's success response is a JSON object, the tool advertises a matching `outputSchema` and returns `structuredContent` alongside the text result. Identical in both languages. See [Output schemas](#output-schemas) below. - **Annotations.** Read-only, destructive, idempotent, and open-world hints are computed the same way and appear the same way on the wire. - **Curation.** `--include-tags`, `--exclude-tags`, path and method filters all work the same—they act on the spec before either language emits. - **Plugins.** The `otel`, `posthog`, `amplitude`, and `mixpanel` plugins all support both languages. Each ships as readable, vendored instrumentation source in the language you chose. - **Environment contract.** Both servers read `KLARIDIAN_BASE_URL` for the upstream host and `KLARIDIAN_AUTH_TOKEN` for a Bearer token. - **Conformance.** An unknown tool returns a JSON-RPC `-32602` protocol error; invalid arguments return a tool-error result the model can read and react to. - **OAuth.** `--oauth-*` generates a resource server that validates bearer tokens (JWKS signature, expiry, issuer, audience, required scopes) on `--transport streamable-http`. See [OAuth 2.1](/docs/how-to/oauth). ## What the Python target doesn't support yet These are TypeScript-only for now: - **`--architecture code-mode`.** The Python code-mode target is planned separately. - **`--install`.** The Python prepare step (virtual environment plus `pip install`) is planned separately. Follow the printed next steps to set the project up by hand. klaridian fails with a clear message if you combine `--language python` with one of these, rather than generating a server that silently drops the feature. ## Output schemas When an OpenAPI operation declares a **JSON object** success response, klaridian advertises it as the tool's `outputSchema` and the generated handler returns `structuredContent` (the parsed response body) next to the usual text result. A client can then consume a typed, structured result instead of re-parsing text. This works the same in TypeScript and Python, from the same spec. klaridian reads the response schema from the spec itself—including resolving `$ref`s into `components.schemas`—so you get the rich, named shape the API author wrote, not a guess. **When a tool gets an `outputSchema`:** the operation's success response (preferring `200`, then `201`, then any other `2xx`, then `default`) has an `application/json` body whose schema is a JSON object. **When it doesn't** (the tool stays text-only, exactly as before): - the success body is an array, a primitive, or a top-level `oneOf`/`anyOf`/`allOf` (ambiguous to honour faithfully); - the operation has no JSON success body (for example a `204 No Content` or a binary download); - the operation declares no success response schema at all. This is deliberate. The MCP spec requires an `outputSchema` root to be an object, and the TypeScript SDK validates a successful result's `structuredContent` against the advertised schema. klaridian only advertises a schema it can faithfully honour: on a successful call the handler attaches the parsed body; on an error response it returns a tool error (no structured content expected); and if a response body isn't valid JSON, it falls back to a plain text result. You get precise output typing where the spec supports it, and no spurious validation failures where it doesn't. --- # Transports Source: https://klaridian.dev/docs/how-to/transports > stdio vs. streamable-http, and when to use each. ## stdio (the default) ```bash npx klaridian generate --spec ./api.yaml --out ./my-server ``` The generated server talks to its client over standard input/output. This is what most MCP clients (Claude Desktop, Claude Code, and others) expect when they spawn a server as a local process. Use this unless you have a reason not to. ## streamable-http ```bash npx klaridian generate --spec ./api.yaml --out ./my-server \ --transport streamable-http --port 3000 ``` The server listens on a network port instead. Use this when the server needs to run somewhere other than the client's own machine—for example, behind OAuth (see [OAuth 2.1](/docs/how-to/oauth)). This requires `streamable-http`—it doesn't work with `stdio`. ### Deploying behind a public host The `--port` you pass at generation time is only the default. The generated streamable-http server reads three environment variables at runtime, so one build runs unchanged across environments: | Variable | What it does | Default | | --- | --- | --- | | `PORT` | The port to listen on. Takes precedence over `KLARIDIAN_PORT` and the generated default. Most platforms (Cloud Run, Render, Railway, Heroku) inject this automatically. | the `--port` value | | `KLARIDIAN_BIND_HOST` | The network interface to bind. Set to `0.0.0.0` inside a container or PaaS so the server accepts traffic from outside its own loopback. | `127.0.0.1` | | `KLARIDIAN_ALLOWED_HOSTS` | Comma-separated hostnames allowed in the `Host` header. By default only localhost is accepted (per the MCP spec's DNS-rebinding protection). When the server is reached through a public hostname—`myapp.fly.dev`, `name.workers.dev`, a custom domain—add it here, or every request is rejected with `403 Invalid Host`. | localhost only | For example, deploying to a host that serves `myapp.fly.dev` on the platform's injected port: ```bash PORT=8080 \ KLARIDIAN_BIND_HOST=0.0.0.0 \ KLARIDIAN_ALLOWED_HOSTS=myapp.fly.dev \ npm start ``` Leaving `KLARIDIAN_ALLOWED_HOSTS` unset keeps the secure localhost-only default, so local runs need no configuration. Only the hostnames you list are accepted—an unlisted `Host` still gets a `403`. ## Which one should I pick? Start with `stdio`. Switch to `streamable-http` only when you need remote access or OAuth. --- # CLI reference Source: https://klaridian.dev/docs/reference/cli-reference > Every flag for the klaridian CLI, generated from the real commands. {/* GENERATED FILE -- do not hand-edit. Produced by packages/cli/scripts/generate-cli-docs.mjs from the live commander.js Command. Run `npm run docs:gen` (packages/cli) after changing any flag, then commit the result. CI fails the build if this file doesn't match what the generator produces from the current code. */} ## klaridian generate Generate an MCP server from an OpenAPI spec (via openapi-mcp-generator), optionally instrumented with one or more observability plugins ### Required | Flag | What it does | |---|---| | `--spec ` | Path to the OpenAPI spec (JSON or YAML) | | `--out ` | Output directory for the generated server | ### Basics | Flag | What it does | |---|---| | `--name ` | Name for the generated server (default: derived from the spec's info.title) | | `--base-url ` | Override the API base URL (required if the spec's servers[] is relative/missing) | | `--server-description ` | Short human-readable description for the emitted server.json (distinct from individual tool descriptions) | | `--force` | Overwrite --out even if it already exists and is non-empty (default: refuse, to avoid silently destroying unrelated files) | | `--json` | Print a single machine-readable JSON result to stdout instead of human-readable progress lines on stderr (success or failure, always exactly one JSON value, exit code still reflects success) | | `--quiet` | Suppress step-by-step progress messages; still prints warnings, errors, and the final summary/next-steps line | ### Lifecycle See [Lifecycle](/docs/how-to/running-the-server) for the full guide. | Flag | What it does | |---|---| | `--install` | After generating, also run `npm install --no-audit --no-fund` and `npm run build` in --out (skips the manual step normally printed in "Next"). The generated project still needs `npm start` or `klaridian start` to actually run it. | ### Configuration See [Configuration](/docs/how-to/config-file) for the full guide. | Flag | What it does | |---|---| | `--config ` | Path to a klaridian.config.json file providing default values for other flags (overridden by any flag explicitly passed on the command line). Auto-discovered in the current directory if present. | ### Curation See [Curation](/docs/how-to/curation) for the full guide. | Flag | What it does | |---|---| | `--include-tags ` | Only include operations with at least one of these OpenAPI tags (comma-separated) | | `--exclude-tags ` | Exclude operations with any of these OpenAPI tags (comma-separated) | | `--exclude-operation-ids ` | Exclude these specific operationIds regardless of tags (comma-separated) | | `--include-paths ` | Only include operations whose path matches at least one of these regex patterns (comma-separated). Works even when the spec has zero OpenAPI tags, composes with --include-tags (both must pass). | | `--exclude-paths ` | Exclude operations whose path matches any of these regex patterns (comma-separated) | | `--include-methods ` | Only include operations using one of these HTTP methods (comma-separated, for example get,post) | | `--exclude-methods ` | Exclude operations using any of these HTTP methods (comma-separated) | | `--interactive` | Prompt for which tags to include before generating. Requires an interactive terminal, fails loudly if stdin is not a TTY (for example, running in CI or under an agent) instead of silently accepting empty input. | ### Architecture See [Architecture](/docs/how-to/code-mode) for the full guide. | Flag | What it does | |---|---| | `--architecture ` | tools (default) emits one MCP tool per OpenAPI operation; code-mode emits a single execute_code tool backed by a typed client, run in a Deno-sandboxed subprocess, for large APIs where one-tool-per-operation is the wrong default. Requires an absolute --base-url (or an absolute server URL in the spec). | ### Target language See [Target language](/docs/how-to/target-language) for the full guide. | Flag | What it does | |---|---| | `--language ` | Target language for the generated server: typescript (default) or python | ### Plugins See [Plugins](/docs/how-to/plugins) for the full guide. | Flag | What it does | |---|---| | `--plugin ` | Observability plugin to enable, repeatable (available: otel, posthog, amplitude, mixpanel) | | `--plugin-config ` | Plugin config in <pluginId>.<key>=<value> form, repeatable | ### Licensing See [Licensing](/docs/how-to/licensing) for the full guide. | Flag | What it does | |---|---| | `--license ` | License for the generated server: mit, apache-2.0, none. Defaults to `mit`. | | `--author ` | Author/copyright holder name for the generated LICENSE file (default: your git user.name, or "the project author" if unset) | ### Transport See [Transport](/docs/how-to/transports) for the full guide. | Flag | What it does | |---|---| | `--transport ` | Transport for the generated server: stdio (default) or streamable-http | | `--port ` | Port for the generated server when --transport is streamable-http (default: 3000) | ### OAuth See [OAuth](/docs/how-to/oauth) for the full guide. | Flag | What it does | |---|---| | `--oauth-issuer ` | OAuth 2.1 issuer URL of the external Authorization Server (IdP) protecting this server. Requires --transport streamable-http. The generated server acts ONLY as a resource server (RFC 9728 PRM, bearer-token/audience validation), never as an authorization server. | | `--oauth-jwks-uri ` | JWKS URI to fetch the IdP's signing keys from. When omitted, resolved automatically from --oauth-issuer's OIDC discovery document (<issuer>/.well-known/openid-configuration) at generation time. | | `--oauth-audience ` | Expected token audience (RFC 8707), the canonical URI this server will be reachable at, for example https://mcp.example.com/mcp. Required with --oauth-issuer; tokens not bound to this exact value are rejected. | | `--oauth-required-scopes ` | Comma-separated OAuth scopes required on every tool call (default: none beyond token validity) | ### MCP Registry See [MCP Registry](/docs/how-to/mcp-registry) for the full guide. | Flag | What it does | |---|---| | `--registry-name ` | Reverse-DNS name for the official MCP Registry, for example io.github.<you>/<server>. When set, the emitted server.json and package.json mcpName use it. | ## klaridian init Interactive wizard that scaffolds a klaridian.config.json for `klaridian generate` (writes the file only — it does not generate a server) ### Options | Flag | What it does | |---|---| | `--out ` | Where to write the config file (default: ./klaridian.config.json in the current directory) | | `--force` | Overwrite the config file even if it already exists (default: refuse, to avoid silently replacing one you meant to keep) | | `--json` | Print a single machine-readable JSON result to stdout instead of human-readable progress on stderr. Implies non-interactive: every wizard answer must come from a flag. | | `--quiet` | Suppress step-by-step progress messages; still prints warnings, errors, and the final next-steps line | ### Wizard fields See [Wizard fields](/docs/how-to/init) for the full guide. | Flag | What it does | |---|---| | `--spec ` | OpenAPI spec path or URL (skips that prompt when passed) | | `--generate-out ` | Output directory `klaridian generate` should write the server to — the config file's `out` field, distinct from this command's own --out (skips that prompt when passed) | | `--plugin ` | Observability plugin to enable, repeatable (available: otel, posthog, amplitude, mixpanel); skips that prompt when passed | | `--license ` | License for the generated server: mit, apache-2.0, none (skips that prompt when passed). Defaults to `mit`. | | `--transport ` | Transport for the generated server: stdio or streamable-http (skips that prompt when passed). Defaults to `stdio`. | ## klaridian start Launch a server previously produced by `klaridian generate` — runs it in place (npm start for a TypeScript project, the .venv interpreter on server.py for a Python one). Generates and configures nothing; pass every generation flag (--spec, --language, --architecture, --plugin, ...) to `generate` instead, once, when you create or regenerate the project. ### Options See [Options](/docs/how-to/running-the-server) for the full guide. | Flag | What it does | |---|---| | `--json` | If a pre-launch check fails (missing/unbuilt project), print a single JSON error object to stdout instead of a human message. Has no effect once the server itself starts — from that point the server owns stdout. | ## klaridian deploy Emit deploy artifacts for a project previously produced by `klaridian generate`. Uses the emit + shell-out model: klaridian writes the platform's native config (a portable Dockerfile for --target docker) rather than reimplementing deploy infrastructure. Reconfigures nothing about the server itself — every structural decision was made at generation time. Requires a streamable-http project (a stdio server has nothing to expose). ### Options See [Options](/docs/how-to/deploy) for the full guide. | Flag | What it does | |---|---| | `--target ` | Deploy target to emit artifacts for. Supported: docker, cloudflare, fly. Defaults to `docker`. | | `--out ` | Directory to write the artifacts into (default: the project directory itself). | | `--force` | Overwrite existing artifacts (Dockerfile/.dockerignore) instead of refusing. | | `--json` | Print a single machine-readable JSON result to stdout instead of human-readable lines. | ## klaridian plugins list List every available observability plugin (id and name) ### Options | Flag | What it does | |---|---| | `--json` | Print the list as a single JSON object (`{ plugins: [...] }`) to stdout instead of aligned text | ## klaridian licenses list List every supported license id for the generated server ### Options | Flag | What it does | |---|---| | `--json` | Print the list as a single JSON object (`{ licenses: [...] }`) to stdout instead of aligned text |