Skip to main content
Glama
anythink-cloud

Anythink-MCP

Official
README.md
<picture>
  <source media="(prefers-color-scheme: dark)" srcset="assets/anythink-logo-dark.svg">
  <img alt="Anythink" src="assets/anythink-logo.svg" height="40">
</picture>

# Anythink CLI

The official command-line interface for [Anythink](https://anythink.cloud) — the headless backend platform for developers and founders. Manage your projects, entities, data, workflows, users, files, and payments without leaving the terminal.

[![NuGet](https://img.shields.io/nuget/v/anythink-mcp?logo=nuget&label=anythink-mcp)](https://www.nuget.org/packages/anythink-mcp)
[![Release](https://img.shields.io/github/v/release/anythink-cloud/anythink-cli?logo=github&label=release)](https://github.com/anythink-cloud/anythink-cli/releases/latest)
[![Homebrew](https://img.shields.io/badge/homebrew-anythink--cloud%2Ftap-F9A825?logo=homebrew&logoColor=white)](https://github.com/anythink-cloud/homebrew-tap)
[![MCP Registry](https://img.shields.io/badge/MCP_registry-cloud.anythink%2Fanythink-0098FF)](https://registry.modelcontextprotocol.io)
[![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)

```
   ░███                             ░██    ░██        ░██           ░██
  ░██░██                            ░██    ░██                      ░██
 ░██  ░██  ░████████  ░██    ░██ ░████████ ░████████  ░██░████████  ░██    ░██
░█████████ ░██    ░██ ░██    ░██    ░██    ░██    ░██ ░██░██    ░██ ░██   ░██
░██    ░██ ░██    ░██ ░██    ░██    ░██    ░██    ░██ ░██░██    ░██ ░███████
░██    ░██ ░██    ░██ ░██   ░███    ░██    ░██    ░██ ░██░██    ░██ ░██   ░██
░██    ░██ ░██    ░██  ░█████░██     ░████ ░██    ░██ ░██░██    ░██ ░██    ░██
                             ░██
                       ░███████
```

---

## Contents

- [Installation](#installation)
- [Getting started](#getting-started)
- [Command reference](#command-reference)
  - [signup / login / logout](#signup--login--logout)
  - [accounts](#accounts)
  - [projects](#projects)
  - [config](#config)
  - [entities](#entities)
  - [fields](#fields)
  - [data](#data)
  - [search](#search)
  - [workflows](#workflows)
  - [users](#users)
  - [files](#files)
  - [email](#email)
  - [roles](#roles)
  - [api-keys](#api-keys)
  - [menus](#menus)
  - [charts](#charts)
  - [dashboards](#dashboards)
  - [settings](#settings)
  - [integrations](#integrations)
  - [pay](#pay)
  - [oauth](#oauth)
  - [api](#api)
  - [docs](#docs)
  - [migrate](#migrate)
  - [plans](#plans)
- [MCP server](#mcp-server)
- [Contributing](#contributing)
- [License](#license)

---

## Installation

Both the `anythink` CLI and the `anythink-mcp` server are distributed together. The quickest way to get both is Homebrew.

### Homebrew (macOS / Linux) — recommended

```bash
brew install anythink-cloud/tap/anythink
```

This installs **both** commands onto your `PATH`:

- `anythink` — the CLI
- `anythink-mcp` — the MCP server (see [MCP server](#mcp-server))

Or tap first, then install:

```bash
brew tap anythink-cloud/tap
brew install anythink
```

Update to the latest release:

```bash
brew upgrade anythink
```

Uninstall:

```bash
brew uninstall anythink
```

### macOS / Linux — download binary

Grab the latest release for your platform from the [Releases](https://github.com/anythink-cloud/anythink-cli/releases/latest) page:

| Platform              | Binary                 |
| --------------------- | ---------------------- |
| macOS (Apple Silicon) | `anythink-osx-arm64`   |
| macOS (Intel)         | `anythink-osx-x64`     |
| Linux (x86_64)        | `anythink-linux-x64`   |
| Linux (ARM64)         | `anythink-linux-arm64` |

```bash
# Example — macOS Apple Silicon
curl -Lo anythink https://github.com/anythink-cloud/anythink-cli/releases/latest/download/anythink-osx-arm64
chmod +x anythink
sudo mv anythink /usr/local/bin/
```

The MCP server ships as a matching `anythink-mcp-<platform>` binary on the same release — download and install it the same way (e.g. `anythink-mcp-osx-arm64`).

Verify the download against `checksums.txt` in the release assets:

```bash
sha256sum -c checksums.txt --ignore-missing
```

### .NET global tool

If you have the [.NET 8 SDK](https://dotnet.microsoft.com/download) installed:

```bash
dotnet tool install --global anythink-cli
```

### Build from source

```bash
git clone https://github.com/anythink-cloud/anythink-cli
cd anythink-cli
dotnet build
dotnet run --project src/AnythinkCli.csproj -- --help
```

---

## Getting started

```bash
# 1. Create an account (or log in if you already have one)
anythink signup

# 2. Create a billing account
anythink accounts create --name "My Company"

# 3. Create a project
anythink projects create "My App" --region lon1

# 4. Connect to the project
anythink projects use <project-id>

# 5. Start building
anythink entities list
anythink workflows list
```

Your credentials and project profiles are stored in `~/.anythink/config.json`. You can manage multiple projects by running `projects use` to switch between them.

---

## Command reference

### signup / login / logout

```
anythink signup                        Create a new Anythink account
anythink login                         Log in to the platform
anythink logout                        Remove saved credentials for a project profile
```

`signup` and `login` are interactive — they prompt for email and password and walk you through connecting to a billing account and project on first run.

---

### accounts

Manage billing accounts. A billing account is the container for one or more projects and holds your subscription and payment details.

```
anythink accounts list                 List your billing accounts
anythink accounts create               Create a new billing account
anythink accounts use <id>             Set the active billing account
```

**Examples**

```bash
anythink accounts create --name "Acme Ltd" --email billing@acme.com
anythink accounts use a1b2c3d4
```

---

### projects

Create and manage Anythink projects. Each project is an isolated backend instance with its own database, auth, files, and workflows.

```
anythink projects list                 List projects in the active billing account
anythink projects create <name>        Create a new project
anythink projects use <id>             Connect to a project (sets it as the active profile)
anythink projects delete <id>          Delete a project
```

**Options — `projects create`**

| Flag            | Description                     |
| --------------- | ------------------------------- |
| `--region <id>` | Deployment region (e.g. `lon1`) |
| `--plan <id>`   | Plan ID (see `anythink plans`)  |

**Examples**

```bash
anythink projects create "My App" --region lon1
anythink projects use a1b2c3d4
anythink projects delete a1b2c3d4 --yes
```

---

### config

View and manage saved CLI profiles.

```
anythink config show                   List all profiles and platform settings
anythink config use <profile>          Set the active project profile
anythink config remove <profile>       Remove a profile
```

Profiles are named by project alias or ID and stored in `~/.anythink/config.json`.

---

### entities

Manage entities (database tables) in the active project.

```
anythink entities list                 List all entities
anythink entities get <name>           Get entity details and fields
anythink entities create <name>        Create a new entity
anythink entities update <name>        Update entity settings
anythink entities delete <name>        Delete an entity and all its data
```

**Options — `entities create`**

| Flag         | Description                                |
| ------------ | ------------------------------------------ |
| `--rls`      | Enable row-level security                  |
| `--public`   | Make the entity publicly readable          |
| `--lock`     | Lock new records (prevent direct creation) |
| `--junction` | Mark as a junction (many-to-many) table    |

**Examples**

```bash
anythink entities create orders --rls
anythink entities get customers
anythink entities delete temp_data --yes
```

---

### fields

Manage fields on an entity. Fields map directly to database columns.

```
anythink fields list <entity>          List fields on an entity
anythink fields add <entity> <name>    Add a field
anythink fields delete <entity> <id>   Delete a field
```

**Options — `fields add`**

| Flag                | Description                                                                       |
| ------------------- | --------------------------------------------------------------------------------- |
| `--type <type>`     | Field type: `varchar`, `text`, `int`, `float`, `bool`, `datetime`, `json`, `uuid` |
| `--required`        | Mark the field as required                                                        |
| `--unique`          | Enforce a unique constraint                                                       |
| `--indexed`         | Add a database index                                                              |
| `--default <value>` | Default value                                                                     |

**Examples**

```bash
anythink fields list customers
anythink fields add customers email --type varchar --unique --required
anythink fields add products price --type float --required
anythink fields delete customers 1234 --yes
```

---

### data

CRUD operations on entity records.

```
anythink data list <entity>            List records
anythink data get <entity> <id>        Get a single record by ID
anythink data create <entity>          Create a new record
anythink data update <entity> <id>     Update a record
anythink data delete <entity> <id>     Delete a record
anythink data export <entity> <file>   Export records to CSV, JSON or JSONL
anythink data import <entity> <file>   Create records from CSV, JSON or JSONL
```

**Options — `data list`**

| Flag              | Description                                                                        |
| ----------------- | ---------------------------------------------------------------------------------- |
| `--limit <n>`     | Records per page (default: 20)                                                     |
| `--page <n>`      | Page number (default: 1)                                                           |
| `--filter <expr>` | Field filters — JSON (`{"status":"draft","total":{"gte":10}}`) or `field=value` pairs (`status=draft&total=GTE:10`). See below. |
| `--json`          | Output raw JSON instead of table                                                   |
| `--all`           | Stream all pages as sequential JSON objects (requires `--json`, constant memory)    |

**Filter operators (JSON form)** — `{"field": value}` matches exactly, `{"field": [a, b]}` matches any, `{"field": null}` matches empty. For anything else use an operator object, e.g. `{"price": {"gte": 10, "lt": 100}}`:

| Operator                       | Meaning                     | `field=value` form |
| ------------------------------ | --------------------------- | ------------------ |
| `eq` / `ne`                    | Equal / not equal           | `x=v` / `x=!v`     |
| `gt` `gte` `lt` `lte`          | Comparisons                 | `x=GT:v` …         |
| `contains` / `not_contains`    | Case-insensitive substring  | `x=C:v` / `x=NC:v` |
| `starts_with` / `ends_with`    | Case-insensitive prefix/suffix | `x=SW:v` / `x=EW:v` |
| `in`                           | Any of a list               | `x=IN:a,b`         |
| `null: true` / `null: false`   | Empty / not empty           | `x=NULL:` / `x=NNULL:` |
| `exists: true` / `exists: false` | Has / lacks related records | `x=EXISTS:` / `x=NOT_EXISTS:` |

**Options — `data create` / `data update`**

| Flag            | Description                 |
| --------------- | --------------------------- |
| `--data <json>` | JSON object of field values |

**Examples**

```bash
anythink data list blog_posts --limit 10
anythink data get blog_posts 42
anythink data create blog_posts --data '{"title":"Hello World","status":"draft"}'
anythink data update blog_posts 42 --data '{"status":"approved"}'
anythink data delete blog_posts 42 --yes
```

**Export and import** — `data export` streams records page by page to a file; `data import` creates one record per row. Always run an import with `--dry-run` first: it validates every row and sends nothing.

```bash
anythink data export customers customers.csv
anythink data export orders orders.jsonl --filter 'status=paid' --fields id,total
anythink data import customers customers.csv --dry-run
anythink data import customers customers.csv --errors rejected.csv --yes
```

| Flag (`export`)       | Description |
| --------------------- | ----------- |
| `--format <fmt>`      | `csv`, `json` or `jsonl`. Default: from the extension (`.csv`, `.json`, `.jsonl`, `.ndjson`). `-` as the file writes to stdout (needs `--format`) |
| `--filter <expr>`     | Same syntax as `data list --filter` |
| `--fields a,b`        | Columns to export, in order. CSV defaults to the entity's fields |
| `--page-size <n>`     | Records per request (default 200, max 1000) |
| `--force`             | Overwrite an existing file. Without it an existing file is never touched. The file is written to a temporary name and renamed on success, so a failed export never leaves a partial file |
| `--no-formula-guard`  | CSV only: see below |

| Flag (`import`)       | Description |
| --------------------- | ----------- |
| `--format <fmt>`      | `csv`, `json` (an array of objects) or `jsonl`. Default: from the extension, else the first character (`[` or `{`) |
| `--dry-run`           | Validate and report; nothing is sent |
| `--concurrency <n>`   | Parallel creates (default 4, max 16) |
| `--errors <file>`     | Write skipped and failed rows, with an `_error` column or property, so they can be fixed and re-imported |
| `--ignore-unknown`    | Drop columns that aren't fields on the entity instead of rejecting the row |
| `--yes`               | Skip the confirmation prompt. Required when not running interactively (CI, scripts, agents), otherwise the import refuses before writing anything |

How values are handled:

- **CSV is RFC 4180**: cells containing a comma, quote or line break are quoted, quotes are doubled, and quoted cells can span lines. Objects, arrays, JSON fields and relations are written as compact JSON text.
- **Formula guard (export)**: CSV text starting with `=`, `+`, `-`, `@`, tab or carriage return is prefixed with `'` so spreadsheets don't run it as a formula. Numbers are never changed. This includes phone numbers such as `+44 20 7946 0000` and any text with a leading `+` or `-`. The guard is one-way: importing the file keeps the `'` unless the file was exported with `--no-formula-guard`.
- **Types follow the entity's fields.** Text keeps its exact characters (`00123` stays `00123`); integers and decimals are parsed with `.` as the decimal separator (`1,5` is rejected, never guessed); booleans accept `true/false`, `1/0` and `yes/no`; dates must be ISO 8601 (`2025-03-31`, `2025-03-31T09:30:00Z`; no offset means UTC); JSON fields must be valid JSON.
- **An empty CSV cell is sent as `null`.** In JSON and JSONL input an empty string stays an empty string.
- **Bad rows are skipped, never sent.** They are reported with a row number (CSV: record number, so the header is row 1; JSONL: line number; JSON: position in the array) and counted as *skipped*. Rows the server rejects are counted as *failed*. The exit code is non-zero if any row was skipped or failed.
- **Retries**: `400`, `409` and `422` are never retried, so a create is not repeated. See *Uncertain failures* below for what is retried.
- **System columns are ignored on import**: `id`, `created_at`, `updated_at`, `tenant_id` and `locked` are never sent, and the import says which it ignored. Importing an export back into the same project therefore creates duplicates with new ids and timestamps; it does not update the originals.
- **One-to-many collections and secret fields are skipped on import** (the import lists them), and one-to-many columns are left out of an export unless you name them in `--fields`. Many-to-many, file and user columns are copied as ids, which only mean something inside the same project; the import warns once per column.
- **Empty boolean cells** are sent as `null` rather than `false`.
- **Uncertain failures**: only `429`/`503` responses and requests that never reached the server (DNS, connection or TLS failures) are retried. If a request times out or the connection drops after sending, the row is reported as `UNCERTAIN: may have been created`, in the errors file too; check the project before re-importing it. Rate-limit waits pause every worker together and are retried for over a minute before giving up.
- **Ctrl+C** stops reading the file, finishes the rows already queued and prints a partial summary (exit code 1). An interrupted export removes its temporary file.
- `data import` and `data export` read and write local files, so they are not available through the hosted (HTTP) MCP server.

Not supported yet: updating or upserting existing records by key, looking up relations by a natural key (use the related record's id), and file uploads.

---

### search

Full-text search across your entities, plus index lifecycle management.

```
anythink search query <text>                          Run a search
anythink search similar <entity> <id>                 Find similar documents
anythink search rehydrate [<entity>]                  Rebuild the search index (admin)
anythink search purge [<entity>]                      Wipe the search index (admin)
anythink search audit <entity>                        Compare configured public-searchable fields
                                                       with what public search actually returns
```

**Options — `search query`**

| Flag                  | Description                                                                            |
| --------------------- | -------------------------------------------------------------------------------------- |
| `--entities <list>`   | Comma-separated entity names. Default: all indexed entities.                           |
| `--filter <expr>`     | Filter expression, e.g. `"status=published AND category=news"`. Supports `_geoRadius`. |
| `--sort <list>`       | Comma-separated sort fields, e.g. `"created_at:desc,id:asc"`.                          |
| `--facet <fields>`    | Comma-separated fields to compute facet counts on.                                     |
| `--highlight`         | Highlight matched terms in results.                                                    |
| `--page N`            | Page number (default: 1).                                                              |
| `--limit N`           | Results per page (1-100, default: 20).                                                 |
| `--public`            | Use the unauthenticated `/search/public` endpoint (only public-marked fields).         |
| `--json`              | Print the raw response JSON.                                                           |

**Index lifecycle**

`rehydrate` and `purge` are admin operations on the search index:

- `search rehydrate` — rebuilds the index from the database (no data loss; just resyncs)
- `search purge` — deletes the index (run `rehydrate` after to repopulate)

Both confirm by default; pass `-y` / `--yes` to skip the prompt for automation.

**`search audit` — public-search data leak check**

Compares what the entity's schema *says* should be public-searchable (fields with `publicly_searchable=true` and the entity's own `is_public=true`) against what `/search/public` actually returns. Any field appearing in public results that isn't on the allowlist is reported as a leak.

Exits with code 1 if a leak is detected — useful for CI/CD.

**Examples**

```bash
# Browse everything
anythink search query "*"

# Filtered search with sorting
anythink search query "anythink" --filter "status=published" --sort "created_at:desc"

# Compare what public visitors see vs what's in the database
anythink search audit posts
anythink search audit users --query "alice" --sample 10

# Reindex after a schema change
anythink search rehydrate posts
anythink search rehydrate --yes        # everything (admin)

# Geo search (radius in metres)
anythink search query "*" --filter "_geoRadius(51.5074,-0.1278,5000)"
```

---

### workflows

Manage automation workflows. A workflow can have several triggers: a cron schedule, an entity event, an API route, or a manual run.

```
anythink workflows list                List all workflows (--json for a compact summary)
anythink workflows get <id>            Get workflow details and steps (--json for the full definition)
anythink workflows create <name>       Create a new workflow
anythink workflows update <id>         Rename a workflow or change its description
anythink workflows enable <id>         Enable a workflow
anythink workflows disable <id>        Disable a workflow
anythink workflows trigger <id>        Manually trigger a workflow
anythink workflows delete <id>         Delete a workflow
```

**Trigger types — `workflows create --trigger <type>`** (not case-sensitive; default `Manual`)

| Type     | Fires                                 | Required flag          | Other flags                          |
| -------- | ------------------------------------- | ---------------------- | ------------------------------------ |
| `Manual` | When run by hand, on an entity        | `--entity <name>`      |                                      |
| `Event`  | When an event happens, such as a record being created | `--entity <name>` for the `Entity...` events | `--event <event>`, `--filter <json>` |
| `Timed`  | On a cron schedule                    | `--cron <expr>`        |                                      |
| `Api`    | When its API route is called          | `--api-route <route>`  |                                      |

`--event` (not case-sensitive) is `EntityCreated` (default), `EntityUpdated`, `EntityDeleted`, `UserRegistered`, `UserInvited`, `SubscriptionCreated`, `SubscriptionActivated`, `SubscriptionExpired`, `PaymentCreated`, `PaymentSucceeded`, `PaymentFailed`, `PaymentMethodCaptured`, `PaymentMethodCaptureFailed`, `PaymentMethodRemoved` or `PushActionTaken`; only the three `Entity...` events need `--entity`. A trigger missing its required flag is rejected before anything is sent, and a flag that doesn't apply to the chosen type is ignored with a warning.

**Other options — `workflows create`**

| Flag                    | Description                                       |
| ----------------------- | ------------------------------------------------- |
| `--description <text>`  | Workflow description                              |
| `--enabled`             | Enable the workflow straight away                 |
| `--filter-file <path>`  | Read the `Event` filter JSON from a file          |

**Examples**

```bash
anythink workflows create daily-sync --trigger Timed --cron "0 6 * * *"
anythink workflows create on-post --trigger Event --entity blog_posts --event EntityUpdated
anythink workflows create import-hook --trigger Api --api-route hooks/import
anythink workflows create review-posts --entity blog_posts
anythink workflows trigger 76
anythink workflows disable 83
```

---

### users

Manage users in the active project.

```
anythink users list                    List all users
anythink users me                      Show the currently authenticated user
anythink users get <id>                Get a user by ID
anythink users invite <email> <first> <last>   Create a user and send an invitation email
anythink users delete <id>             Delete a user
```

**Options — `users invite`**

| Flag             | Description                   |
| ---------------- | ----------------------------- |
| `--role-id <id>` | Assign a role to the new user |

**Examples**

```bash
anythink users list
anythink users invite alice@example.com Alice Smith --role-id 3
anythink users delete 42 --yes
```

---

### files

Manage uploaded files in the active project.

```
anythink files list                    List uploaded files
anythink files get <id>                Get file metadata by ID
anythink files upload <path>           Upload a file
anythink files delete <id>             Delete a file
```

**Options — `files list`**

| Flag          | Description                  |
| ------------- | ---------------------------- |
| `--page <n>`  | Page number                  |
| `--limit <n>` | Files per page (default: 25) |

**Options — `files upload`**

| Flag       | Description                       |
| ---------- | --------------------------------- |
| `--public` | Make the file publicly accessible |

**Examples**

```bash
anythink files list
anythink files upload logo.png --public
anythink files upload export.csv
anythink files delete 12 --yes
```

---

### email

View and edit the project's transactional email templates (confirmation, invite, recovery and so on) and the HTML shell that wraps every email's body. Email commands need the project's email permissions; the API enforces them for whoever is signed in.

```
anythink email templates list                      List the project's email templates
anythink email templates show <type>               Show a template's subject and content
anythink email templates update <type>             Change a template's subject and/or content
anythink email preview                             Render an unsaved draft and print the HTML
anythink email shell show                          Show the shell HTML (custom or platform default)
anythink email shell update                        Save new shell HTML, or reset it
```

**Options — `email templates show`**

| Flag         | Description                                              |
| ------------ | -------------------------------------------------------- |
| `--rendered` | Print the rendered HTML (with sample data) instead of the source |

**Options — `email templates update`**

| Flag                    | Description                                                           |
| ----------------------- | --------------------------------------------------------------------- |
| `--subject <text>`      | New subject line                                                      |
| `--content <path>`      | File with the new content (use `-` to read stdin)                     |
| `--content-text <html>` | The new content, passed inline (use this or `--content`, not both)    |

Pass at least one of the subject or the content. Whatever you leave out keeps its current value. Empty content is refused.

**Options — `email preview`** (renders on the server and saves nothing)

| Flag                    | Description                                              |
| ----------------------- | -------------------------------------------------------- |
| `--subject <text>`      | Subject to render (default: `Preview`)                   |
| `--content <path>`      | File with the content (use `-` for stdin)                |
| `--content-text <html>` | The content, passed inline                               |
| `--wrapper <path>`      | Optional shell HTML to render against (use `-` for stdin)|
| `--wrapper-text <html>` | Optional shell HTML, passed inline                       |

**Options — `email shell update`** (pass exactly one)

| Flag                | Description                                           |
| ------------------- | ----------------------------------------------------- |
| `--html <path>`     | File with the new shell HTML (use `-` for stdin)      |
| `--html-text <html>`| The new shell HTML, passed inline                     |
| `--reset`           | Go back to the platform default shell                 |

HTML is limited to 1,000,000 characters. The shell and template commands print raw HTML, so you can redirect it to a file. Through the MCP server the file options are not offered, so agents pass the HTML inline with `content_text`, `wrapper_text` and `html_text`.

**Examples**

```bash
anythink email templates list
anythink email templates show confirmation --rendered > confirmation.html
anythink email templates update confirmation --subject "Welcome aboard"
anythink email templates update confirmation --content ./confirmation.html
cat confirmation.html | anythink email templates update confirmation --content -
anythink email preview --subject "Hi" --content ./draft.html --wrapper ./shell.html
anythink email shell show > shell.html
anythink email shell update --html ./shell.html
anythink email shell update --reset
```

---

### roles

Manage roles in the active project. Roles control what authenticated users can access.

```
anythink roles list                    List all roles
anythink roles create <name>           Create a new role
anythink roles delete <id>             Delete a role
```

**Options — `roles create`**

| Flag                   | Description                            |
| ---------------------- | -------------------------------------- |
| `--description <text>` | Human-readable description of the role |

**Examples**

```bash
anythink roles list
anythink roles create editor --description "Can edit content"
anythink roles delete 5 --yes
```

---

### api-keys

Issue and manage API keys for non-interactive access (CI pipelines, scripts, integrations). Each key is scoped to a permission set, has an expiry, and is tied to the user that created it.

The raw key is shown **once** on creation and never retrievable — save it immediately or use `--save-as` to write it directly into a CLI profile.

```
anythink api-keys list                              List your API keys
anythink api-keys create <name> --permissions ...   Create a new key
anythink api-keys revoke <id>                       Revoke a key
```

**Options — `api-keys create`**

| Flag                    | Description                                                                  |
| ----------------------- | ---------------------------------------------------------------------------- |
| `--permissions <list>`  | Required. Comma-separated permission names, e.g. `data:read,data:create`     |
| `--expires-in <days>`   | Days until expiry (default: 90, max: 365)                                    |
| `--no-expiry-cap`       | Allow `--expires-in` greater than 365 days                                   |
| `--save-as <profile>`   | Save the new key directly to a CLI profile instead of printing it            |
| `--json`                | Print the response as JSON to stdout (the key is in this output — handle carefully) |
| `-y, --yes`             | Skip the confirmation prompt                                                 |

**Output behaviour**

By default, the success message goes to **stdout** and the raw key goes to **stderr** on its own line. This makes it easy to capture only the key:

```bash
anythink api-keys create ci-deploy --permissions data:read --yes 2> key.txt
```

If the server drops any of the requested permissions because the current user does not hold them, the CLI surfaces a loud warning so you do not end up with a quietly under-scoped key.

**Examples**

```bash
# Create a 90-day key for CI
anythink api-keys create github-actions --permissions "data:read,data:create" --yes 2> key.txt

# Create a key and save it directly into a profile (key never echoes)
anythink api-keys create scraper --permissions data:read --save-as scraper-bot --yes
anythink --profile scraper-bot data list posts

# Revoke a key
anythink api-keys revoke 42 --yes
```

---

### menus

Manage dashboard sidebar menus in the active project. Menus control what entities appear in the Anythink dashboard and how they are grouped.

```
anythink menus list                                        List all menus with tree structure
anythink menus get <menu_id> [--json]                      Show one menu (and its role) with its items and child items
anythink menus create <name> <role_id>                     Create a menu shown to a role
anythink menus update <menu_id> [--name <text>] [--role <id>]
                                                           Rename a menu or change its role
anythink menus delete <menu_id> [--yes]                    Delete a menu and all of its items
anythink menus add-item <menu_id> <entity>                 Add an entity to a dashboard menu
anythink menus update-item <menu_id> <item_id> [options]   Change an item's name, icon, link or parent
anythink menus remove-item <menu_id> <item_id> [--yes]     Remove an item, along with its child items
anythink menus reorder-items <menu_id> <item_ids>          Set the order of items that share a parent
anythink menus reorder <menu_ids>                          Set the order of menus
```

**Options — `menus add-item`**

| Flag              | Description                                          |
| ----------------- | ---------------------------------------------------- |
| `--icon <name>`   | Lucide icon name (e.g. `MessageCircle`, `Target`)    |
| `--name <text>`   | Display name (defaults to entity name, title-cased)  |
| `--parent <id>`   | Parent menu item ID for nesting under a group        |

**Options — `menus update-item`** (only the fields you pass change)

| Flag              | Description                                                |
| ----------------- | ---------------------------------------------------------- |
| `--name <text>`   | New display name                                           |
| `--icon <name>`   | New Lucide icon name                                       |
| `--entity <name>` | Point the item at an entity's page (instead of `--href`)   |
| `--href <path>`   | Point the item at any path (instead of `--entity`)         |
| `--parent <id>`   | Parent item ID to nest under; `0` moves it to the top level |

`reorder-items` and `reorder` take comma-separated IDs in the order you want them (`301,299,300`). The items you name take the first places within their group; items you leave out follow in their current order, and `reorder-items` needs all the items to share one parent. Locked items (the built-in ones) can't be changed, removed or moved; they keep their place, and the items between them reuse their own position numbers (they are only renumbered when two of them tie).

`add-item` and `update-item --entity` look the entity up first (system entities count), and stop only if it doesn't exist; if the lookup itself fails (for example, no permission), the item is saved and a warning says the entity couldn't be checked. Moving an item to a new parent with `update-item --parent` puts it last among its new siblings.

Removing an item also removes its direct child items. The command says so, and refuses when those children are locked or have items of their own.

A role is shown only its first menu, so `create` (and `update --role`) warns when the role already has one. `delete` removes the menu's locked built-in items with it, and says when the role is left with no menu.

**Examples**

```bash
# List all menus and their items
anythink menus list

# Show menu 250 with the item IDs you need for the commands below
anythink menus get 250

# Add "Check-ins" under the Profiles group (parent 168) in admin menu (250)
anythink menus add-item 250 check_ins --icon MessageCircle --parent 168

# Add a top-level menu item
anythink menus add-item 250 badges --icon Award

# Rename an item and give it another icon
anythink menus update-item 250 299 --name "Achievements" --icon Trophy

# Remove an item
anythink menus remove-item 250 299 --yes

# Put items 301, 299 and 300 first, in that order
anythink menus reorder-items 250 301,299,300
```

---

### charts

Build and manage the charts shown on dashboards in the active project. Every command takes `--json`, which prints a compact result with the ids the next step needs. In the MCP server each command is a tool of the same name (`charts_create`, `charts_preview` and so on).

```
anythink charts list [--entity <name>]            List charts, newest first
anythink charts get <id>                          Show a chart's configuration
anythink charts create <name> [options]           Create a chart
anythink charts update <id> [options]             Change a chart; options you leave out keep their value
anythink charts delete <id> [--yes]               Delete a chart
anythink charts preview [options]                 Show the data a configuration would draw, without saving it
anythink charts platform-metrics                  List the usage metrics a platform chart can plot
```

**Options — `charts create`, `charts update` and `charts preview`**

| Flag                         | Description                                                                                  |
| ---------------------------- | -------------------------------------------------------------------------------------------- |
| `--entity <name>`            | Entity whose records the chart plots                                                         |
| `--type <type>`              | `column` (bar chart), `line`, `pie`, `area`, `stat`, `gauge` or `funnel`                     |
| `--group-by <field>`         | Field for the x axis, or the slices of a pie                                                 |
| `--interval <size>`          | Bucket a date `--group-by`: `hour`, `day`, `week`, `month`, `quarter` or `year`               |
| `--measure <field>`          | Numeric field to aggregate (needed unless `--agg` is `count`)                                |
| `--agg <how>`                | `count` (default), `sum`, `avg`, `min` or `max`                                              |
| `--stack-by <field>`         | Field that splits each bar or point into a second breakdown                                  |
| `--filter <f:op:value>`      | Filter such as `status:eq:published`. Operators: `eq ne gt gte lt lte contains in exists not_exists`. Repeat for several fields; a chart keeps one filter per field |
| `--timeframe <preset>`       | `all`, `24h`, `7d`, `30d`, `90d`, `365d` or `custom` (with `--from` and `--to`)              |
| `--limit <n>`, `--sort <asc\|desc>`, `--cumulative <bool>` | Row limit, sort order and running total                       |
| `--target <n>`, `--target-mode <goal\|warning>` | A goal or warning level on a stat or gauge                              |
| `--compare <bool>`, `--compare-days <n>`, `--compare-overlay <bool>` | Compare with the previous period                         |
| `--source <entity\|platform\|quota>` | Where the data comes from. Platform charts use `--platform-metric` (see `charts platform-metrics`), quota charts use `--quota-metric` |
| `--config <json>`            | Anything else, as a JSON object, e.g. `{"funnelStages":[{"label":"Signed up"}]}` for a funnel. Typed options win over it |
| `--rows <n>`                 | `charts preview` only: most rows to show (default 50)                                        |

A missing or unknown value is refused before anything is sent, with a message naming it. Check a chart with `charts preview` before `charts create`: it takes the same options and shows what the chart would draw.

**Examples**

```bash
# What would a pie of orders by status show?
anythink charts preview --entity orders --type pie --group-by status

# Save it, then a revenue chart with a filter
anythink charts create "Orders by status" --entity orders --type pie --group-by status
anythink charts create "UK revenue per month" --entity orders --type column --group-by created_at \
  --interval month --measure total --agg sum --filter region:eq:uk --timeframe 365d

# A usage chart from the platform metrics
anythink charts create "Workflow runs" --source platform --platform-metric workflow_runs --type line

# Change one thing
anythink charts update 12 --timeframe 30d
```

---

### dashboards

Build and manage dashboards. A dashboard is a set of widgets (charts, lists, notes and so on) laid out on a 12-column grid. Every command takes `--json`.

```
anythink dashboards list                                 List the dashboards you can see
anythink dashboards get <id>                             Show a dashboard with its widgets and their positions
anythink dashboards mine                                 Show your landing dashboard, or the project default
anythink dashboards create <name> [options]              Create a dashboard
anythink dashboards update <id> [options]                Rename it, change who can see it, or replace its widgets and layout
anythink dashboards delete <id> [--yes]                  Delete a dashboard and its widgets (the charts are kept)
anythink dashboards add-chart <dashboard-id> <chart-id>  Add a chart as a new widget
anythink dashboards remove-widget <dashboard-id> <widget-id>  Remove a widget
anythink dashboards data <id> [--widget <id>]            Show the data behind the widgets
anythink dashboards widget-preview --type <type>         Show the data a widget would draw, without saving it
anythink dashboards set-home <id>                        Make it your landing dashboard
anythink dashboards promote-to-default <id> [--yes]      Copy it over the project default (administrators only)
```

`add-chart` and `remove-widget` read the dashboard, change only that widget, and write the rest back as it was.

**Options**

| Command / flag                              | Description                                                                          |
| ------------------------------------------- | ------------------------------------------------------------------------------------ |
| `create --chart <id>`                       | Put a chart on the new dashboard. Repeat for several                                 |
| `create --description`, `--shared`, `--allow-shared-edit`, `--home`, `--default` | Description, who can see or edit it, and whether it is your landing or the project default dashboard |
| `create`/`update --config <json>`           | Other settings as a JSON object: `widgets` (each with `type`, `title` and settings) and `layout`. On `update`, `widgets` replaces the whole list, so include every widget to keep, with its `id` |
| `update --name`, `--description`, `--shared <bool>`, `--allow-shared-edit <bool>` | The fields to change; the rest are left alone |
| `add-chart --title <text>`                  | Widget title (defaults to the chart's name)                                          |
| `add-chart --column`, `--row`, `--width`, `--height` | Position and size on the grid (default width 4, height 3, placed below the existing widgets). Leave them all out and the dashboard places the widget itself |
| `data --widget <id>`, `--rows <n>`          | Only these widgets; most rows to show per widget (default 20)                        |
| `widget-preview --type`, `--chart`, `--config`, `--rows` | Widget type (`chart`, `list`, `markdown`, ...), the chart to show, or the widget's own settings as JSON |

**Examples**

```bash
# A dashboard with two charts already on it
anythink dashboards create Sales --chart 12 --chart 14

# Add a third, half the width of the grid
anythink dashboards add-chart 3 15 --width 6

# See what is on it, then take a widget off
anythink dashboards get 3
anythink dashboards remove-widget 3 41

# The numbers behind it
anythink dashboards data 3 --json
```

---

### settings

View and change project settings in the active project, including the allowed application URLs that browsers may call the API from (CORS).

```
anythink settings get [--json]                   Show all project settings
anythink settings set <key> <value> [--yes]     Set a single project setting
anythink settings cors list                      List allowed application URLs
anythink settings cors add <url> [--yes]         Add an allowed origin
anythink settings cors remove <url>              Remove an allowed origin
```

**Keys — `settings set`**

| Key                            | Value                                     |
| ------------------------------ | ----------------------------------------- |
| `name`, `description`          | Text                                      |
| `require_email_confirmation`   | `true` / `false`                          |
| `allow_registrations`          | `true` / `false`                          |
| `default_role_id`              | Role ID for newly registered users        |
| `enable_group_rls`             | `true` / `false`                          |
| `payment_success_url`, `payment_cancel_url` | URL                          |
| `app_engagement_trial_enabled` | `true` / `false`                          |
| `app_engagement_trial_days`    | Number of days                            |
| `ai_mode`                      | `platform` or `byok`                      |
| `ai_byok_provider`, `ai_default_model` | Text                              |
| `google_maps_key`              | Text                                      |

Origins must be `http`/`https` with a host and optional port, with no path, query or fragment; a trailing `/` is stripped. A wildcard such as `https://*.example.com` is only safe on a domain you control, so wildcards under shared hosting domains (`vercel.app`, `github.io`, …) or a bare TLD are refused unless you pass `--yes`.

Some changes widen who can sign up: `default_role_id` pointing at an administrator role is refused unless you pass `--yes`, and `allow_registrations true` and `require_email_confirmation false` ask for confirmation (pass `--yes` when running non-interactively).

`cors add` and `cors remove` clear the project's CORS cache, so the change applies straight away. Matching is case-insensitive and adding a URL that is already present does nothing. Anythink's own domains and `localhost` are always allowed and don't need adding.

**Examples**

```bash
# Allow a deployed front end to call the API
anythink settings cors add https://my-app.vercel.app

# Allow every subdomain of a domain you own
anythink settings cors add "https://*.example.com"

# Remove an origin
anythink settings cors remove https://my-app.vercel.app

# Let users sign up on their own
anythink settings set allow_registrations true
```

---

### integrations

Manage integrations — both the catalog of available providers (Claude, OpenAI, Slack, Google, etc.) and the active connections that hold credentials for them.

```
anythink integrations list                                  List available providers
anythink integrations get <provider>                        Show details and operations for one provider
anythink integrations connections list [--provider <p>]     List your active connections

anythink integrations connect <provider>                    Create an API-key connection (Claude, OpenAI, etc.)
anythink integrations oauth status <provider>               Show OAuth client setup status
anythink integrations oauth configure <provider>            Set the OAuth client ID + secret
anythink integrations oauth connect <provider>              Connect via the browser OAuth flow

anythink integrations test <connection-id>                  Test a connection
anythink integrations enable <connection-id>                Enable a connection
anythink integrations disable <connection-id>               Disable a connection
anythink integrations disconnect <connection-id>            Delete a connection

anythink integrations execute <provider> <operation>        Run an operation on a connected provider
```

**API-key providers — `integrations connect`**

| Flag                 | Description                                                                              |
| -------------------- | ---------------------------------------------------------------------------------------- |
| `--api-key <key>`    | API key for the provider. If omitted, you'll be prompted (input is hidden).              |
| `--name <name>`      | Friendly name for this connection (default: `<provider> connection`)                    |
| `--user-connection`  | Make this a user-scoped connection (only the current user sees it). Default: tenant-wide. |

**OAuth providers — `integrations oauth connect`**

The CLI starts a local HTTP listener on `http://localhost:8745/callback`, opens your browser to the provider's authorisation URL, and exchanges the returned code for a connection — no copy/paste of auth codes required.

| Flag                 | Description                                                              |
| -------------------- | ------------------------------------------------------------------------ |
| `--name <name>`      | Friendly name for this connection                                       |
| `--user-connection`  | Make this a user-scoped connection                                       |
| `--port <n>`         | Local callback port (default: `8745`)                                    |
| `--no-open`          | Don't try to open the browser — just print the URL                       |
| `--timeout <secs>`   | How long to wait for the callback (default: `300`)                       |

OAuth credentials need to be set up once per provider before you can connect:

```bash
anythink integrations oauth configure slack          # prompts for client_id + secret (hidden)
anythink integrations oauth connect slack --name main
```

**Running operations — `integrations execute`**

| Flag                | Description                                                                         |
| ------------------- | ----------------------------------------------------------------------------------- |
| `--input <k=v>`     | Input parameter as `key=value`. Repeatable.                                         |
| `--inputs <json>`   | All inputs as a JSON object.                                                        |
| `--json`            | Print the full JSON response (default: just the `content` field if present).        |

**Examples**

```bash
# Browse what's available
anythink integrations list
anythink integrations get claude

# API-key flow (Claude, OpenAI)
anythink integrations connect claude --name "main"
anythink integrations execute claude generate-text --input "prompt=Tell me a haiku"

# OAuth flow (Slack, Google, GitHub)
anythink integrations oauth configure slack
anythink integrations oauth connect slack --name main

# Manage connections
anythink integrations connections list
anythink integrations test <connection-id>
anythink integrations disable <connection-id>
anythink integrations disconnect <connection-id> --yes
```

---

### pay

Manage **AnythinkPay** — Stripe Connect, Apple in-app purchases, payments, subscription plans, and live subscriptions.

```
anythink pay status                    Show Stripe Connect account status
anythink pay connect                   Set up a Stripe Connect account and start onboarding
anythink pay setup                     Guided setup: Stripe Connect, Apple IAP, and a first plan
anythink pay payments                  List recent payments
anythink pay methods                   List saved payment methods
anythink pay entitlement               Show the current user's access / trial entitlement
anythink pay payment-options           Show available payment providers for a platform/storefront

anythink pay trial status|enable|disable          Manage the app engagement trial

anythink pay apple credentials set                Set Apple IAP credentials (.p8 from a file)
anythink pay apple credentials show               Show Apple IAP credentials (identifiers masked)
anythink pay apple credentials notification-url   Print the URL to register in App Store Connect
anythink pay apple verify                         Verify an Apple transaction (testing)

anythink pay plans list|get|create|update|delete  Manage subscription plans

anythink pay subscriptions list|get|events        Inspect subscriptions and history
anythink pay subscriptions cancel|resume          Standard lifecycle actions
anythink pay subscriptions delete|force-expire|relink|resync   Admin recovery (project admin)

anythink pay offers list|get|create|update        Manage promo and referral offers
anythink pay offers pause|activate                Change an offer's status
anythink pay offers delete                        Permanently delete an offer, its codes and redemption records
anythink pay offers codes|add-code|redemptions    Inspect and extend an offer
anythink pay offers user-code                     Look up a user's personal referral code
```

Commands that cancel, delete, expire, relink or pause (`pay plans delete`, `pay subscriptions cancel|delete|force-expire|relink`, `pay offers pause|delete`) ask for confirmation. Pass `-y`/`--yes` to skip the prompt; in a non-interactive shell they refuse to run without it.

`pay plans update` only changes the fields you pass: omitted flags keep the plan's current currency, interval, type and active state. Use `--active` or `--inactive` to change availability.

**Options — `pay payments`**

| Flag          | Description                     |
| ------------- | ------------------------------- |
| `--page <n>`  | Page number                     |
| `--limit <n>` | Payments per page (default: 25) |

`pay connect` is interactive — it prompts for business type, country, and contact email, creates a Stripe Connect account, then opens the Stripe onboarding URL in your browser. `pay setup` chains Stripe Connect, Apple IAP credentials, and a first plan; each step is optional.

Subscription plans can carry an `--apple-product-id` (and optional `--apple-subscription-group-id`) so one plan covers both Stripe and Apple. `pay apple credentials set` reads the App Store Connect `.p8` private key from a file and stores it encrypted — it is never printed or logged.

**Required permissions**

| Command surface | Permission |
| --- | --- |
| Plan / subscription reads, entitlement, payment-options | `anythink_subscription_plans:read` |
| Plan writes | `anythink_subscription_plans:create` / `:update` / `:delete` |
| Payment reads/writes | `anythink_payments:read` / `:create` |
| Apple credentials, admin recovery (`delete`/`force-expire`/`relink`/`resync`) | project administrator |

**Examples**

```bash
anythink pay setup
anythink pay plans create --plan-name monthly --name Monthly --amount 9.99 --currency gbp --interval month --apple-product-id example_monthly
anythink pay apple credentials set --issuer-id <uuid> --key-id <id> --bundle-id com.example.app --private-key-file ./AuthKey.p8
anythink pay apple verify --signed-transaction <JWS>
anythink pay subscriptions events <subId>
anythink pay entitlement
```

---

### oauth

Configure OAuth social sign-in providers for the active project.

```
anythink oauth google status           Show Google OAuth configuration status
anythink oauth google configure        Set Google OAuth client ID and secret
```

Google OAuth lets your project's users sign in with their Google account. You'll need a Google Cloud project with the OAuth 2.0 credentials created — see the [Google Cloud Console](https://console.cloud.google.com/apis/credentials).

Set the authorised redirect URI in your Google Cloud credentials to:

```
https://api.my.anythink.cloud/org/<your-org-id>/auth/v1/google/callback
```

**Examples**

```bash
anythink oauth google status
anythink oauth google configure
```

---

### api

List all API endpoints available for the active project — both platform routes and the dynamically generated REST routes for your entities.

```
anythink api                           List all endpoints
anythink api --json                    Output as JSON (useful for AI tooling)
```

---

### docs

Print the full CLI reference.

```
anythink docs                          Print reference as markdown
anythink docs --json                   Print reference as JSON (for AI/tooling consumption)
```

---

### migrate

Copy the entity schema (entities + fields) from one project profile to another. Useful for promoting a schema from staging to production.

```
anythink migrate --from <profile> --to <profile>
```

**Options**

| Flag               | Description                                        |
| ------------------ | -------------------------------------------------- |
| `--from <profile>` | Source profile name (required)                     |
| `--to <profile>`   | Destination profile name (required)                |
| `--dry-run`        | Show what would be migrated without making changes |

**Examples**

```bash
anythink migrate --from my-app-staging --to my-app-prod
anythink migrate --from my-app-staging --to my-app-prod --dry-run
```

---

### plans

List available Anythink plans.

```
anythink plans                         List plans
anythink plans --json                  Output as JSON
```

---

## MCP server

The Anythink MCP server exposes the platform to AI assistants (Claude, Cursor, etc.) via the [Model Context Protocol](https://modelcontextprotocol.io).

### Install

No install needed — the recommended way is to run it on demand with `npx`:

```bash
npx -y @anythink-cloud/mcp
```

Prefer a native binary on your `PATH`? Any of:

```bash
# Homebrew (bundled with the CLI — see Installation above)
brew install anythink-cloud/tap/anythink

# .NET global tool (requires the .NET 8 SDK)
dotnet tool install -g anythink-mcp

# Or download the anythink-mcp-<platform> binary from the Releases page
```

### Configure

[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=anythink&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBhbnl0aGluay1jbG91ZC9tY3AiXX0%3D)
[![Install in VS Code](https://img.shields.io/badge/Install-VS_Code-007ACC?logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=anythink&config=%7B%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40anythink-cloud%2Fmcp%22%5D%7D)

For **Claude Code**, register it in one command:

```bash
claude mcp add anythink -- npx -y @anythink-cloud/mcp
```

Or add it to your MCP client config manually (e.g. `.mcp.json`):

```json
{
  "mcpServers": {
    "anythink": {
      "command": "npx",
      "args": ["-y", "@anythink-cloud/mcp"]
    }
  }
}
```

To pin a profile, add it to `args`: `["-y", "@anythink-cloud/mcp", "--profile", "my-project"]`

Works in any MCP client. Most use the same `mcpServers` JSON shown above — just add it to the client's config file:

| Client | Config file |
| --- | --- |
| Claude Code | `claude mcp add anythink -- npx -y @anythink-cloud/mcp` (or `.mcp.json`) |
| Claude Desktop | `claude_desktop_config.json` (Settings → Developer → Edit Config) |
| Cursor | `~/.cursor/mcp.json` (or the **Add to Cursor** button above) |
| VS Code | `.vscode/mcp.json` (or the **Install in VS Code** button above) |
| Cline | `cline_mcp_settings.json` (MCP Servers → Configure) |
| Windsurf | `~/.codeium/windsurf/mcp_config.json` |

A couple of clients use a different config shape:

<details>
<summary><strong>Continue</strong> (YAML — <code>mcpServers</code> is a list)</summary>

```yaml
mcpServers:
  - name: anythink
    command: npx
    args:
      - -y
      - "@anythink-cloud/mcp"
```
</details>

<details>
<summary><strong>Zed</strong> (uses <code>context_servers</code>, not <code>mcpServers</code>)</summary>

```json
{
  "context_servers": {
    "anythink": {
      "source": "custom",
      "command": "npx",
      "args": ["-y", "@anythink-cloud/mcp"]
    }
  }
}
```
</details>

(Using a native binary instead of `npx`? Use `"command": "anythink-mcp"` with no `args`.)

Once connected, run the `login` tool, then `accounts_use` / `projects_use` to pick your working context.

### Available tools

The MCP server provides dedicated tools for authentication, account/project management, and configuration — plus a generic `cli` tool that can run any CLI command:

| Tool | Description |
| --- | --- |
| `signup` | Create a new Anythink account |
| `login` | Log in with email and password |
| `login_direct` | Store credentials directly (org ID + API key or JWT) |
| `logout` | Remove a saved profile |
| `config_show` | List all profiles |
| `config_use` | Switch active profile |
| `config_remove` | Remove a profile |
| `accounts_list` | List billing accounts |
| `accounts_create` | Create a billing account |
| `accounts_use` | Set the active billing account |
| `projects_list` | List projects |
| `projects_create` | Create a project |
| `projects_use` | Connect to a project |
| `projects_delete` | Delete a project |
| `cli` | Run any CLI command (entities, data, workflows, roles, etc.) |

The hosted MCP server (`anythink-mcp --hosted`) has no sign-in or profile tools. Its `accounts_list`, `accounts_create`, `plans`, `projects_create` and `projects_delete` tools run as the signed-in user and appear only when the user grants account access; see the [MCP server docs](mcp/README.md#account-tools).

---

## Contributing

### Prerequisites

- [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8)
- An Anythink account (free tier works)

### Setup

```bash
git clone https://github.com/anythink-cloud/anythink-cli
cd anythink-cli
dotnet build
```

### Running locally

```bash
dotnet run --project src/AnythinkCli.csproj -- --help
dotnet run --project src/AnythinkCli.csproj -- projects list
dotnet run --project src/AnythinkCli.csproj -- entities list
```


### Releases

Releases are automated via GitHub Actions. Push a version tag to trigger a build:

```bash
git tag v1.2.0
git push origin v1.2.0
```

The workflow builds self-contained binaries for macOS (arm64, x64) and Linux (x64, arm64), computes SHA256 checksums, and publishes them as a GitHub release.

### Project structure

```
anythink-cli/
├── src/                        # CLI source
│   ├── Commands/               # Command implementations (signup, login, etc)
│   ├── Config/                 # CliConfig.cs, Profile, ConfigService
│   ├── Models/                 # ApiModels.cs, BillingModels.cs
│   ├── Client/                 # HttpApiClient.cs, AnythinkClient.cs, BillingClient.cs
│   ├── Output/                 # Renderer.cs (Spectre.Console helpers)
│   └── Program.cs              # Application entry point & .env loader
├── mcp/                        # MCP server source
│   ├── Tools/                  # MCP tool implementations
│   ├── McpClientFactory.cs     # Auth + client resolution
│   └── Program.cs              # MCP server entry point
├── tests/                      # CLI unit tests
├── mcp-tests/                  # MCP unit tests
├── AnythinkCli.sln             # Solution file
└── .gitignore
```

---

## License

MIT — see [LICENSE](LICENSE). This covers the Anythink CLI and MCP server source in this repository; it does not grant rights to the Anythink platform, APIs, or services, which are governed by separate terms at [anythink.cloud](https://anythink.cloud).

---

Built with [Spectre.Console](https://spectreconsole.net) · Powered by [Anythink](https://anythink.cloud)

TDQS

C2.8/5.0

Scored across 102 tools

Disambiguation3/5

Many tools are clearly scoped by resource and action, but the 102-tool surface creates overlap: `cli`, `fetch`, and `api` can all be used for API access, while `integrations_connect` vs `integrations_oauth_connect` and several workflow helper tools require careful selection. Descriptions help, but the sheer number increases misselection risk.

Naming Consistency4/5

Names predominantly follow a consistent snake_case resource_action pattern (e.g., `entities_create`, `fields_update`, `workflows_step_add`). A few bare commands like `fetch`, `docs`, `api`, `cli`, `login`, `logout`, and `signup` are minor deviations from that pattern.

Tool Count1/5

With 102 tools, this far exceeds the normal 3-15 range and the 50+ extreme-mismatch threshold. A generic `cli` and `fetch` already cover broad functionality, so many individual tools are over-provisioned rather than essential.

Completeness4/5

The surface covers most domain lifecycle areas: auth, billing, projects, entities, fields, data, files, search, workflows, integrations, secrets, roles, users, API keys, and payments. Some resource-specific gaps remain (e.g., user update, menu item management), but the generic `cli`/`fetch` tools provide workarounds.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive