mcli - monday.com GraphQL CLI

A command-line interface for monday.com's GraphQL API with JSON output, LLM-native design, and semantic business-layer operations

MCLI is a command-line interface to monday.com's GraphQL API. It's a single static binary with no dependencies, designed for both human operators and LLM agents.

Key capabilities

  • JSON by default - all output is structured JSON (use --pretty for human-readable formatting)
  • Single binary - no runtime dependencies; build once, deploy anywhere
  • LLM-native - no interactive prompts on the read path; self-describing via mcli skill
  • Semantic layer - save domain-named queries/mutations to create a business-level API over boards
  • Escape hatch - raw mcli query / mcli mutation access for anything not covered by CLI commands
  • Webhooks & daemon - background process to receive and poll webhook events
  • Authentication - token stored securely in OS keychain (macOS Keychain, Linux Secret Service)

Installation

# From source (requires Go 1.26+)
go install github.com/arnon/mcli/cmd/mcli@latest

# Or build locally
git clone [email protected]:DaPulse/mcli.git
cd mcli
make build    # → bin/mcli

Quick start

# Authenticate (one-time, stores in OS keychain)
mcli auth login --token <your-monday-api-token>

# Verify
mcli me

# List your boards
mcli board list

# Get board structure
mcli board get 9832181507

# List items with decoded column values
mcli item list --board 9832181507

# Create an item with column values
mcli item create --board 9832181507 --name "Ship feature" \
  --col 'status={"label":"Working on it"}' \
  --col 'due_date={"date":"2026-06-01"}'

# Run a raw GraphQL query
mcli query 'query { me { id name } }'

Command reference

Authentication:

  • mcli auth login/logout/status

User:

  • mcli me - current user info

Workspaces & organization:

  • mcli workspace list/get/create/update/delete
  • mcli folder list/create/rename/delete

Boards:

  • mcli board list/get/create/rename/archive/delete
  • mcli board group list/create/rename/archive/delete
  • mcli board column list/create/rename/describe/delete

Items:

  • mcli item list/get/create/update/move/archive/delete

GraphQL (escape hatch):

  • mcli query '<graphql>' - run raw queries (inline, from file, or stdin)
  • mcli mutation '<graphql>' - run raw mutations
  • mcli query save/list/run/delete - manage saved queries
  • mcli mutation save/list/run/delete - manage saved mutations

Webhooks & events:

  • mcli daemon start/stop/status - background webhook receiver
  • mcli webhook create/list/delete/events - webhook registration
  • mcli notification list/count/ack - poll for webhook events

Utility:

  • mcli skill - print LLM skill document
  • mcli version - print version

Run mcli <command> --help for flags and detailed usage on any command.

Semantic layer for LLM agents

Save reusable queries and mutations as domain-named operations. LLMs then operate in business terms instead of board IDs and column IDs.

Pattern

  1. Set up boards and columns (one-time)
  2. Save domain-named queries/mutations that encode the board structure
  3. Agents call mcli query run <name> / mcli mutation run <name> with business-level variables

Example

Save a query that lists products from a specific board:

mcli query save list_products --query 'query($boardId: ID!) {
  boards(ids: [$boardId]) {
    items_page(limit: 100) {
      items { id name column_values { id text } }
    }
  }
}'

Run it with variables:

mcli query run list_products --var boardId=9832181507

Agents never need to know board IDs or column IDs — they call domain operations:

mcli query run list_products --var boardId=products_board
mcli mutation run create_order --var board=orders_board --var name="ORD-99" \
  --var cols='{"customer":"Acme Corp","status":{"label":"Draft"}}'
mcli mutation run update_order_status --var board=orders_board --var item=789 \
  --var cols='{"status":{"label":"Ordered"}}'

E-Commerce demo: products, inventory & orders

This demo shows how an LLM agent (or human) can use mcli's generic commands to:

  • Create boards with typed columns
  • Define a semantic layer of saved queries/mutations with business-domain names
  • Seed data using the structured item commands
  • Place an order using only the semantic layer (no board IDs in the "business logic")

Prerequisites

  • mcli auth login (or MONDAY_API_TOKEN set)
  • jq in PATH
  • Run the full demo: ./examples/ecommerce-demo.sh

Phase 1: Create boards

mcli board create --name "Products"  --kind public --empty   # → {"id":"..."}
mcli board create --name "Inventory" --kind public --empty
mcli board create --name "Orders"    --kind public --empty

Each board starts empty (no default columns/items).

Phase 2: Define columns

Products — item name is the product name; add SKU, Description, Price:

mcli board column create --board $PRODUCTS_BOARD --title "SKU"         --type text
mcli board column create --board $PRODUCTS_BOARD --title "Description" --type long_text
mcli board column create --board $PRODUCTS_BOARD --title "Price"       --type numbers

Inventory — item name is the SKU for quick lookup:

mcli board column create --board $INVENTORY_BOARD --title "SKU"      --type text
mcli board column create --board $INVENTORY_BOARD --title "Quantity"  --type numbers

Orders — item name is the order ID; subitems are order lines:

mcli board column create --board $ORDERS_BOARD --title "Customer" --type text
mcli board column create --board $ORDERS_BOARD --title "Status"   --type status \
  --defaults '{"labels":{"0":"Draft","1":"Ordered","2":"Shipped","3":"Delivered"}}'

Phase 3: Semantic layer

Saved queries and mutations give business-level names to operations. An LLM can call mcli mutation run create_order --var ... without knowing GraphQL:

Queries

NamePurpose
list_productsAll products with column values
get_inventoryFull inventory snapshot
list_ordersOrders with their line-item subitems
get_orderSingle order detail by item ID
mcli query save list_products --query \
  'query($boardId: ID!) { boards(ids: [$boardId]) { items_page(limit:100) { items { id name column_values { id text value } } } } }'

Mutations

NamePurpose
create_productAdd a product to the catalog
update_inventoryAdjust stock quantity
create_orderCreate a new order (starts as Draft)
add_order_lineAdd a line-item subitem to an order
update_order_statusTransition order status
mcli mutation save create_order --query \
  'mutation($board: ID!, $name: String!, $cols: JSON!) { create_item(board_id: $board, item_name: $name, column_values: $cols) { id } }'

Phase 4: Seed data

Using the structured item create command (more ergonomic for setup):

mcli item create --board $PRODUCTS_BOARD --name "Widget Pro" \
  --col "$PROD_SKU"='"WGT-001"' \
  --col "$PROD_PRICE"='"29.99"'

Or using the semantic layer:

mcli mutation run create_product \
  --var board=$PRODUCTS_BOARD \
  --var name="Widget Pro" \
  --var cols='{"sku":"WGT-001","price":"29.99"}'

Phase 5: Place an order

This is where the semantic layer shines - the agent writes natural JSON in --var and mcli handles the encoding automatically. monday.com's JSON scalar expects a stringified JSON value on the wire, but mcli detects variables declared as JSON in the query and re-encodes them transparently. No double-escaping needed.

# 1. Create order in Draft status
mcli mutation run create_order \
  --var board=$ORDERS_BOARD \
  --var name="ORD-1001" \
  --var cols='{"customer":"Acme Corp","status":{"label":"Draft"}}'

# 2. Add line items
mcli mutation run add_order_line \
  --var parent=$ORDER_ID \
  --var name="Widget Pro x2" \
  --var cols='{}'

mcli mutation run add_order_line \
  --var parent=$ORDER_ID \
  --var name="Doohickey x5" \
  --var cols='{}'

# 3. Confirm the order
mcli mutation run update_order_status \
  --var board=$ORDERS_BOARD \
  --var item=$ORDER_ID \
  --var cols='{"status":{"label":"Ordered"}}'

Phase 6: Verify

mcli query run list_products --var boardId=$PRODUCTS_BOARD --pretty
mcli query run get_order --var itemId="[$ORDER_ID]" --pretty

Key takeaways

  • Generic commands (board create, item create) handle setup
  • Saved queries/mutations create a domain-specific API layer
  • JSON coercion - variables declared as JSON in the query are auto-stringified, so --var cols='{"key":"val"}' just works without double-encoding
  • LLM agents can operate entirely through mcli mutation run <name> / mcli query run <name> without understanding monday.com internals or wire-format quirks
  • The semantic layer is project-local (.mcli/ directory) and version-controllable

Column values

Reading

Column values are automatically decoded to human-readable form (status labels become strings, dates become ISO format, etc.).

Writing

Pass monday's raw column-value JSON via --col <id>=<json>:

mcli item create --board 123 --name "Task" \
  --col 'status={"label":"Done"}' \
  --col 'date={"date":"2026-05-10"}' \
  --col 'priority={"label":"High"}'

Use mcli board column list --board <id> to discover column IDs, types, and settings.

Webhooks and daemon

mcli includes a background daemon that receives monday.com webhooks and stores them as an inbox for agents to poll.

Start the daemon

# Foreground — opens a Cloudflare Quick Tunnel for a public URL
mcli daemon start

# Or supply your own public URL
mcli daemon start --url https://your-server.example.com

The daemon:

  • Listens for webhook payloads on HTTP port (default 6780)
  • Exposes a Unix socket IPC for CLI commands
  • Opens a Cloudflare Quick Tunnel automatically (requires cloudflared in PATH)
  • Re-registers webhooks when the tunnel URL changes

Register webhooks

# Register for item creation events on a board
mcli webhook create --board 9832181507 --event create_item

# List registered webhooks
mcli webhook list

# List supported event types
mcli webhook events

# Remove a webhook
mcli webhook delete <webhook-id>

Poll notifications

# Check if there are unread events
mcli notification count

# List unread events
mcli notification list --unread

# Filter by board or event type
mcli notification list --board 9832181507 --event change_column_value

# Acknowledge (mark read)
mcli notification ack <event-id>
mcli notification ack --all

All notification/webhook commands require the daemon to be running.

LLM integration

mcli is purpose-built for LLM agents.

# Load the skill document into your LLM context
mcli skill

This outputs a concise, goal-oriented guide. The LLM discovers exact flags via mcli <command> --help as needed.

Authentication

Token resolution (first match wins):

  1. --token <t> flag
  2. MONDAY_API_TOKEN environment variable
  3. Stored credential in OS keychain (mcli auth login)

Credentials are stored securely in the OS keychain (macOS Keychain, Linux Secret Service) or an age-encrypted file. Never stored plaintext.

License

MIT