Skip to main content
Glama
README.md
# Mediagraph CLI

A single binary that exposes the entire [Mediagraph](https://www.mediagraph.io) API to AI agents and shells. Ships as both a CLI (`mediagraph <tool>`) and an MCP server (`mediagraph serve`) — same code path, same auth, same output shape.

> **About Mediagraph:** a digital asset management (DAM) platform for organizing, sharing, and AI-tagging media at scale. Learn more at [www.mediagraph.io](https://www.mediagraph.io).

Built for agent workflows: every tool call returns JSON on stdout, errors on stderr with stable codes, and global flags handle the boring stuff (auth, pagination, retries, dry-runs, polling).

## Install

```bash
npm install -g @mediagraph/cli     # ships the `mediagraph` command
```

## Authentication

### Interactive (developer machines)

```bash
mediagraph auth login        # opens a browser, completes OAuth, persists tokens
mediagraph auth status       # {authenticated, organization, user, token}
```

Tokens are stored encrypted at `~/.mediagraph/tokens.enc` and refreshed automatically.

### Headless (CI, sandboxes, agents)

Use a Personal Access Token. Set both env vars:

```bash
export MEDIAGRAPH_PAT="<token>"
export MEDIAGRAPH_ORGANIZATION_ID="<numeric org id>"
mediagraph auth status       # → {authenticated: true, mode: "pat", ...}
```

Generate a PAT in Mediagraph → Profile → Personal Access Tokens, or via `mediagraph create_personal_access_token --name "ci"`.

## CLI usage

```bash
mediagraph <tool> [flags]              # invoke any tool, prints JSON
mediagraph <tool> --help               # show flags for a tool
mediagraph list-tools [--brief]        # every tool, JSON
mediagraph search-tools "<query>"      # ranked keyword search over the registry
mediagraph skills [name|list|all]      # focused Markdown recipes for agents
mediagraph skill                       # full bundled agent onboarding guide
mediagraph sync ...                    # continuous folder sync (see below)
mediagraph serve                       # start the MCP server on stdio
mediagraph auth login | logout | status
```

### Tool flags

Every tool's flags are derived from its JSON Schema:

```bash
# Flag form
mediagraph search_assets --q "tag_text:nature" --per_page 5
mediagraph create_bulk_job --asset_ids 12,34,56 --tag_names sunset --tag_mode add

# Or pass the whole input as JSON
mediagraph search_assets --json '{"q":"tag_text:nature","per_page":5}'
```

Type coercion: numbers, booleans (`--flag` / `--no-flag`), arrays (comma-separated, repeated, or JSON), objects (JSON only).

### Global flags

These work with any tool:

| Flag | Purpose |
| --- | --- |
| `--all` | Auto-paginate `list_*` tools until exhausted |
| `--limit N` | Cap total rows when paginating (default 10000) |
| `--dry-run` | Print the HTTP call instead of executing — safe preview for mutations |
| `--wait` | After a `create_*`, poll the sibling status tool until terminal |
| `--wait-timeout SEC` | Cap `--wait` duration (default 600) |
| `--envelope` | Wrap stdout in `{ok, tool, data, meta:{duration_ms, ...}}` |
| `--brief` | Trim `list-tools` descriptions to one line |

Examples:

```bash
# Get all assets matching a query, capped at 500
mediagraph search_assets --q "tag_text:nature" --all --limit 500

# Preview a destructive op
mediagraph delete_asset --id 42 --dry-run

# Block until a bulk job finishes
mediagraph create_bulk_job --asset_ids 1,2,3 --tag_names sunset --tag_mode add --wait
```

## Output contract

- **stdout** — JSON only (always parseable). With `--envelope`, wrapped in `{ok, tool, data, meta}`.
- **stderr** — structured error envelope: `{ok: false, code, error, hint?, context?}`.
- **exit code** — `0` success, `1` runtime/tool/network, `2` argument parse error, `3` auth required.

Stable error codes: `AUTH_REQUIRED`, `BAD_ARGS`, `UNKNOWN_COMMAND`, `UNKNOWN_TOOL`, `NOT_FOUND`, `RUN_LOCKED`, `NETWORK`, `RATE_LIMITED`, `TOOL_ERROR`, `CONFIG_ERROR`, `INTERNAL`.

The client honors `Retry-After` on 429/503 (delta-seconds and HTTP-date forms), caps backoff at 60s, and surfaces `X-PAT-Disabled` as a structured auth error.

## Search syntax

The `q` parameter on `search_assets` accepts advanced operators:

| Form | Example | Meaning |
| --- | --- | --- |
| Term | `dog` | Match across all searchable fields (cross_fields) |
| Phrase | `"red barn"` | Both terms in same field, in order |
| Exclude | `NOT dog`, `-dog` | Exclude matches |
| Combine | `dog AND cat`, `dog OR cat` | Boolean ops |
| Field | `tag_text:nature`, `filename.keyword:IMG.jpg` | Field-scoped |
| Wildcard | `tag_text:part*`, `tag_text:?artial` | `*` any chars, `?` one char |
| Existence | `tag_text:**` / `NOT tag_text:**` | Has any value / has no value |
| Group | `(dog OR cat) AND ext:jpg` | Parenthesized |

Common fields: `tag_text`, `filename.keyword`, `description`, `title`, `ext`, `creator_text`, `copyright`, `city`, `state`, `country`.

## Continuous folder sync

Mirror a remote storage folder to a local directory (or vice versa) and keep them in sync on a schedule. Resilient to crashes and reboots: every run is idempotent, state persists at `~/.mediagraph/sync/<name>/state.json`, and in-flight ops are resumed on the next run.

Three modes: **download** (pull-only — auto-fetch new assets and new `data_version_number` bumps; metadata-only changes do NOT re-download), **upload** (push-only — hash + skip unchanged, mirror folder structure), **two-way** (conflicts land as `<file>.conflict-v<N>` next to the local file).

```bash
mediagraph sync init my-pull --mode download \
  --storage-folder-id 42 --local-path ~/Pictures/mediagraph \
  --frequency hourly
mediagraph sync run my-pull       # one-shot reconciliation; safe to repeat
mediagraph sync install my-pull   # registers a launchd job (macOS)
mediagraph sync status my-pull    # JSON summary of last run
```

Harness options (the `run` command is the same in all cases):
- **OS scheduler (recommended)**: `mediagraph sync install <name>` writes a launchd plist on macOS. Survives reboots, captures logs.
- **Coding-agent loop**: in Claude Code, `/loop 1h mediagraph sync run <name>`.
- **Long-running watcher**: `mediagraph sync watch <name>` for low latency without a cron.
- **Manual**: just run `mediagraph sync run <name>` whenever.

## Discovering tools

The CLI ships ~157 tools. Don't load them all — search:

```bash
mediagraph skills                      # focused guide index
mediagraph skills search               # asset search and inspection recipes
mediagraph search-tools "rename file" --limit 5
mediagraph search-tools "watermark"
mediagraph create_bulk_job --help     # one tool, full schema
```

Tool groups: assets, search & filters, collections / lightboxes / storage folders, tags & taxonomies, tag imports, rights & sharing, custom meta fields, bulk jobs & uploads, rename presets, meta downloads (background CSV export), workflows, comments, notifications, webhooks, admin (user groups, invites, PATs, organization budget).

## Use as an MCP server

For Claude Desktop and other MCP clients:

```json
{
  "mcpServers": {
    "mediagraph": {
      "command": "npx",
      "args": ["@mediagraph/cli", "serve"]
    }
  }
}
```

Or one-click: download the latest [`mediagraph-mcp.mcpb`](https://github.com/mediagraph-io/mediagraph-mcp/releases/latest/download/mediagraph-mcp.mcpb) bundle from [Releases](https://github.com/mediagraph-io/mediagraph-mcp/releases).

The MCP server exposes the same tools and a few resources:
- `mediagraph://asset/{id}` — asset details
- `mediagraph://collection/{id}` — collection with assets
- `mediagraph://lightbox/{id}` — lightbox with assets
- `mediagraph://search?q={query}` — search results

It also includes an interactive visual gallery (`search_assets_visual`) for thumbnail browsing, inline editing, ratings, tagging, and bulk downloads inside Claude Desktop.

## Environment

| Variable | Default | Purpose |
| --- | --- | --- |
| `MEDIAGRAPH_PAT` | — | Personal Access Token (headless auth) |
| `MEDIAGRAPH_ORGANIZATION_ID` | — | Organization id (required with PAT) |
| `MEDIAGRAPH_API_URL` | `https://api.mediagraph.io` | API host |
| `MEDIAGRAPH_OAUTH_URL` | `https://mediagraph.io` | OAuth host |
| `MEDIAGRAPH_CLIENT_ID` | *(bundled)* | OAuth client id (custom apps) |
| `MEDIAGRAPH_CLIENT_SECRET` | — | OAuth client secret (confidential clients) |
| `MEDIAGRAPH_REDIRECT_PORT` | `52584` | Local OAuth callback port |
| `MEDIAGRAPH_SYNC_ROOT` | `~/.mediagraph/sync` | Override sync state directory |

## Agent guides

`mediagraph skills` prints focused Markdown guides for agents: search, organize, metadata, ingest, bulk jobs/imports, sharing, workflows, and admin. `mediagraph skill` prints the full bundled `SKILL.md` onboarding guide.

## Security

- Tokens encrypted at `~/.mediagraph/tokens.enc`
- OAuth uses PKCE for public clients
- PAT auth uses HTTP Basic + `OrganizationId` header (matches Mediagraph server-side path)
- Access tokens auto-refreshed before expiration
- No secrets logged or exposed in errors

## Development

```bash
git clone https://github.com/mediagraph-io/mediagraph-mcp.git
cd mediagraph-mcp
npm install
npm run build       # tsup bundle to dist/
npm test            # vitest, ~110 tests
npm run typecheck
```

Run the local build:

```bash
node dist/index.js auth status
node dist/index.js search_assets --q "test" --per_page 5
```

Test with the MCP inspector:

```bash
npx @modelcontextprotocol/inspector node dist/index.js serve
```

## License

MIT — see [LICENSE](LICENSE).

## Support

- [Mediagraph](https://www.mediagraph.io) — product info, pricing, demos
- [API Documentation](https://docs.mediagraph.io)
- [GitHub Issues](https://github.com/mediagraph/mediagraph-mcp/issues)

TDQS

C2.5/5.0

Scored across 276 tools

Disambiguation2/5

With 276 tools, many have overlapping or subtly different purposes (e.g., list_shares vs list_share_links, ignore_asset_unidentified_faces vs ignore_asset_face_toggle, get_recent_tag_events vs get_tag_events), making misselection likely. The detailed descriptions help, but the sheer volume and near-duplicate operations create significant ambiguity.

Naming Consistency4/5

The overwhelming majority follow a consistent verb_noun snake_case pattern (list_*, get_*, create_*, update_*, delete_*), which is predictable and readable. Minor deviations like whoami, reauthorize, can_upload, and explain_asset_search are few and do not undermine the overall pattern.

Tool Count1/5

276 tools is an extreme number for any MCP server, far exceeding the 50+ threshold. Even for a comprehensive DAM system, this is an unwieldy and poorly scoped tool surface that would overwhelm agents and require excessive context.

Completeness3/5

Many domains have solid CRUD coverage (assets, collections, lightboxes, tags, workflows, comments, webhooks), but notable gaps exist: storage folders have no update/delete, rights packages have no update/delete, crop presets lack update/delete, invites have no delete/revoke, and meta imports/ingestions are read-only. Workflow steps also lack a reject action, and notifications have no mark-as-read.

Maintenance

ActivityInactive
ResponsivenessNo issues