# mog.md — Complete Documentation > mog.md is the package manager and marketplace for AI agent skills. > CLI tool: npm install -g mogmd > API base: https://api.mog.md --- # Documentation URL: https://mog.md/docs mog.md is the **agent network**. It is the place where AI agents discover businesses and services, open structured communication sessions, invoke tools, and settle payments — all through a single API. mog also distributes versioned [SKILL.md](https://agentskills.io/specification) packages and runnable MCP server packages, serving as the package manager for AI agent skills across Cursor, Claude Code, Codex, Gemini CLI, and Windsurf. ## Two ways to use mog ### 1. Package marketplace Install skills, rules, and MCP servers with the CLI — like `npm` for agent intelligence. ```sh title="terminal" npx mogmd@latest setup mog install acme/react-testing-skill --auto-buy ``` Already on mog.md? Use **Install CLI** for a one-liner with `--token`. For CI/agents, set `MOG_TOKEN` and run `npx mogmd@latest setup --json`. ### 2. Agent network Your agent connects to mog and can discover, message, and pay any business on the platform — programmatically, in real time. ```typescript title="sdk" import { MogClient } from '@mog/sdk' const mog = new MogClient({ token: process.env.MOG_TOKEN! }) // Discover a verified travel service const { services } = await mog.discover({ tool: 'search_flights', verified: true }) // Open a session and have a structured conversation const { session } = await mog.openSession({ vendor: 'acme', slug: 'travel-agent', intent: 'book_travel', }) await mog.send(session.id, { type: 'quote.request', payload: { destination: 'Tokyo', budgetCents: 150000 }, }) // Or call a tool directly (metered, pay-per-call) await mog.callTool('acme', 'pdf-agent', { tool: 'pdf_to_json', input: { url: '...' } }) ``` See [Agent network](/docs/agent-network) for the full guide, or jump straight to the [SDK reference](/docs/sdk). ## Key concepts ### Service cards Every business on mog publishes a **service card** — a machine-readable record of what the business can do, which protocol it speaks, how to reach it, and how it settles payments. Agents use service cards to discover and connect to businesses. ### Sessions and messages Agents open **sessions** with services through mog. Sessions carry structured **message envelopes** — intents, quotes, tool calls, checkout events, receipts — normalized across protocols. Mog relays, logs, and meters every message. ### Trust metrics Mog continuously probes registered services and computes **trust metrics**: uptime, success rate, response latency, and verified business identity. Agents can sort and filter by trust to choose reliable counterparties. ### Packages A mog package is a versioned `.zip` archive. Each package has a `mog.yaml` manifest declaring its name, version, type, supported targets, and install paths. Package types are `skill`, `rule`, `bundle`, `template`, and `mcp`. ### Targets Packages declare which agent environments they support: `cursor`, `claude-code`, `codex`, `gemini-cli`, `windsurf`, `openclaw`, or `generic`. The CLI auto-detects your environment and installs to the appropriate path. ### Entitlements When you purchase a package (free or paid), you receive an entitlement checked server-side before a signed download URL is issued. Entitlements persist indefinitely unless revoked. ### Spend policies API tokens can be attached to a spend policy that enforces per-purchase limits, daily/monthly caps, vendor allowlists, and blocked package types. When a purchase would exceed a limit, the API returns HTTP 402 with an `approvalUrl` for human review. ### Organizations Organizations let teams share a wallet, spend policies, and private packages under a single account. Members can purchase on behalf of the org wallet. ### The lockfile Every install writes to `mog.lock.json` in your project root, recording the exact version, SHA-256 hash, install path, and entitlement ID. --- # Agent network URL: https://mog.md/docs/agent-network The mog agent network lets any AI agent discover businesses, open structured sessions, exchange messages, invoke tools, and settle payments — all through a single REST API or the `@mog/sdk` TypeScript client. ## What the network does mog sits between your agent and every service or vendor on the platform. It provides: | Layer | What it does | |-------|-------------| | **Registry** | Searchable directory of service cards — endpoint, protocol, capabilities, pricing, trust | | **Sessions** | Durable connections between a buyer agent and a seller service | | **Message relay** | Normalized envelopes (intents, quotes, tool calls, receipts) relayed and logged | | **Protocol gateway** | MCP, Stripe ACP, and raw HTTPS adapters so mog normalizes different provider interfaces | | **Metering** | Pay-per-call wallet billing with usage records | | **Trust engine** | Automated health probes, uptime, success rate, latency metrics, verified identity | ## How an agent uses mog ### Step 1 — Discover Search for live services by capability, tool name, protocol, settlement method, or trust score. ```typescript const { services } = await mog.discover({ tool: 'search_flights', settlement: 'stripe_mpp', verified: true, sort: 'trusted', }) ``` Each service includes a **service card**: ```json { "vendor": "acme", "slug": "travel-agent", "serviceCard": { "protocol": "mcp", "transport": "streamable_http", "endpoint": "https://api.acme.com/agent", "toolNames": ["search_flights", "book_flight"], "settlementMethods": ["stripe_mpp"], "perCallCents": 5, "status": "active" }, "trust": { "totalCalls": 12400, "successRate": "99.20", "avgResponseMs": 340, "uptimePct": "99.95", "vendorVerified": true } } ``` ### Step 2 — Open a session Sessions are durable connections. When your agent opens a session, mog resolves the service card, creates a record, and optionally relays an initial `intent.open` message. ```typescript const { session } = await mog.openSession({ vendor: 'acme', slug: 'travel-agent', intent: 'book_travel', context: { destination: 'Tokyo', budgetCents: 150000 }, }) ``` ### Step 3 — Exchange messages Send and receive structured messages through the session. Mog normalizes everything into a common envelope: ```typescript await mog.send(session.id, { type: 'quote.request', payload: { destination: 'NRT', dates: '2026-04-01/2026-04-10' }, }) const { messages } = await mog.history(session.id) ``` ### Step 4 — Call tools directly (metered) For simple tool invocations, skip sessions and call a tool directly. Mog deducts the per-call cost from your wallet. ```typescript const result = await mog.callTool('acme', 'pdf-agent', { tool: 'pdf_to_json', input: { url: 'https://example.com/invoice.pdf' }, maxCostCents: 10, }) ``` ### Step 5 — Close the session ```typescript await mog.closeSession(session.id) ``` ## Message types Every message in a session has a `type` field from the Mog conversation protocol: | Type | Direction | Purpose | |------|-----------|---------| | `intent.open` | buyer → seller | Initial request with context | | `intent.update` | buyer → seller | Modify the request | | `quote.request` | buyer → seller | Ask for pricing | | `quote.response` | seller → buyer | Return pricing | | `tool.call` | buyer → seller | Invoke a specific tool | | `tool.result` | seller → buyer | Return tool output | | `tool.error` | seller → buyer | Tool execution failed | | `checkout.required` | seller → buyer | Payment is needed to proceed | | `checkout.initiated` | buyer → seller | Checkout started | | `checkout.completed` | buyer → seller | Payment confirmed | | `checkout.canceled` | buyer → seller | Payment canceled | | `artifact.ready` | seller → buyer | Deliverable is available | | `approval.required` | seller → buyer | Human approval needed | | `approval.granted` | buyer → seller | Human approved | | `approval.denied` | buyer → seller | Human denied | | `status.update` | either | Progress or error update | | `receipt.issued` | seller → buyer | Transaction receipt | | `session.close` | either | Close the session | | `dispute.opened` | buyer → seller | Dispute raised | ## Service protocols Mog supports multiple provider protocols through adapters: | Protocol | Transport | Use case | |----------|-----------|----------| | `mcp` | `streamable_http`, `sse` | MCP-compliant tool servers | | `https` | `streamable_http`, `jsonrpc` | Generic REST/JSON-RPC APIs | | `acp` | `streamable_http` | Stripe Agentic Commerce Protocol | When your agent opens a session, mog picks the correct adapter based on the service card and translates messages automatically. ## Trust and verification Mog runs automated health probes against every registered service endpoint and computes rolling metrics: - **Uptime %** — percentage of healthy probes over the last 7 days - **Success rate** — percentage of metered calls that returned without error - **Average response time** — mean latency in milliseconds - **Verified identity** — vendor completed GitHub org or domain verification Use these in discovery to filter for reliable services: ```typescript await mog.discover({ verified: true, sort: 'trusted' }) ``` ## Settlement Mog does not replace Stripe. It binds payment events to sessions and service calls: - **Wallet** — pre-funded balance for frictionless metered calls - **Stripe MPP** — machine payment protocol for delegated enterprise spend - **Stripe ACP** — agentic commerce protocol for seller-scoped checkout - **Free** — no payment required Vendors declare which settlement methods they support in their service card. The buyer agent chooses one when opening a session. ## Vendor control plane Vendors manage their agent presence from the [Agent network dashboard](/dashboard/agent-network): - **Inbox** — open sessions targeting your services - **Session logs** — full message history for any session - **Service health** — latest probe results and uptime - **Service registration** — endpoint, protocol, transport, pricing, capabilities, agent card ## Next steps - [SDK reference](/docs/sdk) — install `@mog/sdk` and see every method - [Live services](/docs/services) — register a service and set metered pricing - [API reference](/docs/api) — full REST endpoint documentation - [Selling on mog](/docs/selling) — publish packages and register services --- # For AI agents URL: https://mog.md/docs/agents mog is built for agents. The CLI supports headless authentication, every command returns structured JSON, spend policies let agents purchase autonomously within limits, and the full documentation is available as plain text at well-known URLs. ## Machine-readable documentation mog serves its entire documentation corpus in agent-friendly plain-text formats at two well-known URLs. | URL | Description | |-----|-------------| | [`https://mog.md/llms.txt`](https://mog.md/llms.txt) | Short overview, integration facts, REST API index, and links to per-page `.mdx` sources | | [`https://mog.md/llms-full.txt`](https://mog.md/llms-full.txt) | Every documentation page concatenated into a single file — the complete reference | Individual doc pages are also available as raw Markdown at `https://mog.md/docs/.mdx`. ### Using llms.txt in agent systems If your agent framework supports tool-use documentation or context injection, point it at `llms.txt` for a compact summary or `llms-full.txt` for the full corpus: ```typescript const docs = await fetch('https://mog.md/llms-full.txt').then(r => r.text()) ``` The `llms.txt` format follows the [llms.txt proposal](https://llmstxt.org/) — a growing convention for making websites machine-readable to language models. ## Headless authentication mog uses the **device code flow** (RFC 8628) specifically because it works in headless environments — CI runners, Docker containers, SSH sessions, and agent runtimes where no browser is available on the machine. ```sh mog auth --json ``` ```json { "ok": true, "command": "auth", "data": { "userCode": "XKCD-7Z4B", "verificationUrl": "https://mog.md/device", "expiresIn": 900 } } ``` The agent displays (or logs) the code and URL, then the CLI polls automatically until a human approves from any browser. No redirect URI or callback server is required. ### API tokens For long-running agents or CI, generate a scoped API token from the [dashboard](/dashboard/settings) instead of using the device flow. Set it as an environment variable: ```sh export MOG_TOKEN="mog_tok_..." ``` The CLI and SDK both read `MOG_TOKEN` automatically. Tokens can be scoped to specific permissions: | Scope | Allows | |-------|--------| | `read` | Search, browse listings, view entitlements | | `purchase` | Buy packages, open network sessions, call tools | | `download` | Retrieve signed download URLs | | `sell` | Vendor operations, inbox, service health | ## Structured CLI output Every CLI command supports `--json` for machine-readable output. Agents should always use this flag. ```sh mog search "react testing" --json mog install acme/react-testing-skill --json mog ls --json ``` All JSON responses share a consistent envelope: ```json { "ok": true, "command": "search", "data": { "results": [...], "total": 3 } } ``` On failure: ```json { "ok": false, "command": "install", "error": "Package not found" } ``` ### Exit codes | Code | Meaning | |------|---------| | `0` | Success | | `1` | Error | | `2` | Approval required — `approvalUrl` is included in the JSON output for a human to review | Exit code 2 is the key signal for agents: the operation was blocked by a spend policy or price limit, and a human must approve via the returned URL. ## Autonomous purchasing Agents can purchase and install packages without human intervention using `--auto-buy`: ```sh mog install acme/premium-skill --auto-buy --json ``` Add `--max-price ` to cap how much the agent can spend per package: ```sh mog install acme/expensive-skill --auto-buy --max-price 500 --json ``` If the price exceeds the limit, the CLI exits with code 2 and returns an `approvalUrl`. ### Spend policies For finer control, attach a **spend policy** to the agent's API token. Spend policies enforce: - **Per-purchase limits** — maximum cost for a single transaction - **Daily and monthly caps** — rolling spend ceilings - **Vendor allowlists** — restrict purchases to approved vendors - **Blocked package types** — prevent certain package types entirely When a purchase would exceed a policy limit, the API returns HTTP 402 with an `approvalUrl` for human review. This gives agents autonomy within safe boundaries. See [Spend policies](/docs/spend-policies) for setup instructions. ## Preflight (dry run) Before committing to an install, agents can preview exactly what would happen: ```sh mog install acme/react-testing-skill --preflight --json ``` ```json { "ok": true, "command": "install", "data": { "package": "acme/react-testing-skill@1.2.0", "target": "cursor", "installPath": "/my-project/.cursor/skills/react-testing-skill/", "sha256": "a3f8c2d1...", "price": "Free" } } ``` This lets agents make informed decisions about whether to proceed. ## SDK for programmatic access For agents that need deeper integration — service discovery, sessions, tool calls, and payments — use the TypeScript SDK: ```sh npm install @mog/sdk ``` ```typescript import { MogClient } from '@mog/sdk' const mog = new MogClient({ token: process.env.MOG_TOKEN! }) const results = await mog.search({ q: 'pdf conversion', type: 'skill' }) const { session } = await mog.openSession({ vendor: 'acme', slug: 'travel-agent', intent: 'book_travel', }) const result = await mog.callTool('acme', 'pdf-agent', { tool: 'pdf_to_json', input: { url: 'https://example.com/doc.pdf' }, maxCostCents: 10, }) ``` See [@mog/sdk](/docs/sdk) for the full reference. ## Agent workflow summary A typical autonomous agent workflow: 1. **Authenticate** — set `MOG_TOKEN` or run the device code flow 2. **Search** — `mog search --json` or `mog.search()` to find packages/services 3. **Preflight** — `mog install --preflight --json` to check before committing 4. **Install** — `mog install --auto-buy --max-price 500 --json` 5. **Wire** — `mog install --wire` to auto-configure the agent's editor 6. **Use** — the installed skill/MCP server is now available in the agent's context For agent network interactions (sessions, tool calls, payments), use the SDK directly. --- # REST API reference URL: https://mog.md/docs/api The mog REST API is available at `https://api.mog.md`. All endpoints are under `/v1/`. Requests and responses are JSON unless otherwise noted. ## Base URL ```sh https://api.mog.md ``` ## Authentication Protected endpoints require a Bearer token in the `Authorization` header: ```sh Authorization: Bearer ``` Tokens are issued via the [device code flow](/docs/authentication) or retrieved from your dashboard. Different endpoints require different scopes: | Scope | Required for | |---|---| | `read` | Entitlements, reviews | | `purchase` | Purchases | | `download` | Download URLs | | `sell` | Vendor operations, uploads | ## Errors Errors return a JSON body with a `message` field: ```json { "message": "Listing not found" } ``` | Status | Meaning | |---|---| | `400` | Bad request / validation error | | `401` | Missing or invalid token | | `402` | Payment / approval required | | `403` | Insufficient token scope | | `404` | Resource not found | | `422` | Unprocessable entity | | `429` | Rate limit exceeded | | `500` | Internal server error | --- ## Health `GET /health` Returns API health status. No authentication required. ```json // All services healthy — HTTP 200 { "ok": true, "version": "0.1.6", "status": "healthy" } // Degraded — HTTP 503 { "ok": false, "version": "0.1.6", "status": "degraded" } ``` When `status` is `"degraded"`, the HTTP status code is `503`. Use this endpoint for liveness/readiness probes in your deployment platform. --- ## Authentication endpoints ### Start device flow `POST /v1/auth/device/start` Initiates a device code flow. **Response:** ```json { "deviceCode": "internal-device-code", "userCode": "XKCD-7Z4B", "verificationUri": "https://mog.md/device", "expiresIn": 900, "interval": 5 } ``` ### Poll device flow `POST /v1/auth/device/poll` Poll for approval. Call every `interval` seconds. **Request body:** ```json { "deviceCode": "internal-device-code" } ``` **Response:** ```json // Still waiting { "status": "authorization_pending" } // Code expired { "status": "expired" } // Approved — store this token { "status": "approved", "token": "mog_...", "tokenType": "Bearer", "expiresIn": 31536000 } ``` ### Approve device code `POST /v1/auth/device/approve` — Auth: Bearer token **Request body:** ```json { "userCode": "XKCD-7Z4B" } ``` **Response:** ```json { "ok": true } ``` ### Revoke token `POST /v1/auth/token/revoke` — Auth: Bearer token ```json { "ok": true } ``` ### List API tokens `GET /v1/auth/tokens` — Auth: Bearer token Returns all active tokens for the current user. ```json { "tokens": [ { "id": "uuid", "name": "CLI device token", "scopes": ["read", "purchase", "download"], "policyId": null, "policyName": null, "lastUsedAt": "2026-01-15T10:00:00.000Z", "expiresAt": null, "revokedAt": null, "createdAt": "2026-01-01T00:00:00.000Z" } ] } ``` ### Revoke token by ID `DELETE /v1/auth/tokens/:id` — Auth: Bearer token ```json { "ok": true } ``` --- ## Search `GET /v1/search` Search packages. No authentication required. **Query parameters:** | Parameter | Type | Description | |---|---|---| | `q` | string | Full-text search query | | `type` | `skill` \| `rule` \| `bundle` \| `template` \| `mcp` | Filter by package type | | `target` | `cursor` \| `claude-code` \| `codex` \| `gemini-cli` \| `windsurf` \| `generic` | Filter by agent target | | `sort` | `popular` \| `recent` \| `rated` \| `price_asc` \| `price_desc` \| `trusted` | Sort order (default: `popular`). `trusted` ranks by trust metrics. | | `page` | number | Page number (default: 1, ignored when `cursor` is set) | | `per_page` | number | Results per page (1–50, default: 20) | | `free` | boolean | Only free packages | | `tool` | string | Filter by MCP tool name (GIN index) | | `tags` | string | Comma-separated tag filter | | `live` | boolean | Only listings with a registered service endpoint | | `protocol` | `mcp` \| `a2a` \| `https` \| `acp` | Filter by service protocol | | `settlement` | string | Filter by settlement method (e.g. `stripe_mpp`) | | `verified` | boolean | Only verified vendors | | `cursor` | string | Cursor from a previous response for efficient keyset pagination | **Response:** ```json { "results": [ { "id": "uuid", "vendorSlug": "acme", "slug": "router-eval", "title": "Router Eval Skill", "description": "...", "type": "skill", "tags": ["react", "testing"], "targets": ["cursor", "claude-code"], "priceCents": 0, "currency": "usd", "latestVersion": "1.0.0", "installCount": 42, "mogRating": "4.8", "vendorName": "Acme Corp", "vendorVerified": false } ], "total": 1, "page": 1, "perPage": 20, "nextCursor": null } ``` When paginating with `cursor`, pass the `nextCursor` value from the previous response as the `cursor` query parameter. When `cursor` is used, `total` and `page` are `null` — only `nextCursor` and `perPage` are set. --- ## Listings ### Get listing `GET /v1/listings/:vendor/:slug` Get a single listing by vendor slug and package slug. No authentication required. ### Get releases `GET /v1/listings/:vendor/:slug/releases` ```json { "releases": [ { "id": "uuid", "version": "1.1.0", "archiveSha256": "a3f8...", "publishedAt": "2026-01-15T10:00:00.000Z" } ] } ``` --- ## Reviews ### Get reviews `GET /v1/listings/:vendor/:slug/reviews` ```json { "reviews": [ { "id": "uuid", "userId": "uuid", "rating": 5, "body": "Excellent skill, saved me hours.", "createdAt": "2026-01-10T08:00:00.000Z" } ], "rating": 4.8, "ratingCount": 12 } ``` ### Create or update review `POST /v1/listings/:vendor/:slug/reviews` — Auth: read scope **Request body:** ```json { "rating": 5, // required: 1–5 "body": "Great skill!" // optional: max 2000 chars } ``` ### Vote on review `POST /v1/listings/:vendor/:slug/reviews/:id/vote` — Auth: read scope **Request body:** ```json { "helpful": true } ``` ```json { "ok": true } ``` --- ## Purchases & entitlements ### Purchase a listing `POST /v1/purchases` — Auth: purchase scope **Request body:** ```json { "listingId": "uuid", // required "releaseId": "uuid", // optional: defaults to latest published release "maxPriceCents": 1000, // optional: spend ceiling "useWallet": false, // optional: deduct from wallet balance instead of card "orgSlug": "my-org", // optional: use org wallet instead of personal wallet "channel": "api" // optional: "api" (default) or "web" } ``` **Response (one of four shapes):** ```json // Purchased (free or wallet) { "status": "purchased", "entitlementId": "uuid", "orderId": "uuid", "amountCents": 500, "walletBalanceCents": 4500 // only present for wallet purchases } // Already owned { "status": "already_owned", "entitlementId": "uuid" } // Approval required — HTTP 402 { "status": "approval_required", "approvalUrl": "https://mog.md/purchases/approve?listing=...", "reason": "Price (1500¢) exceeds your policy limit (1000¢)" } // Insufficient wallet balance — HTTP 402 { "status": "insufficient_balance", "balanceCents": 200, "requiredCents": 500 } ``` ### List entitlements `GET /v1/entitlements` — Auth: read scope ```json { "entitlements": [ { "id": "uuid", "listingId": "uuid", "releaseId": "uuid", "vendorSlug": "acme", "listingSlug": "router-eval", "listingTitle": "Router Eval Skill", "version": "1.0.0", "grantedAt": "2026-01-15T10:00:00.000Z" } ] } ``` ### Check entitlement `GET /v1/entitlements/:listingId` — Auth: read scope ```json // Owned — HTTP 200 { "owned": true, "entitlement": { "...": "..." } } // Not owned — HTTP 404 { "owned": false } ``` ### List orders `GET /v1/orders` — Auth: read scope Returns the current user's order history. Supports `?paymentIntentId=` query param to look up a specific order by Stripe payment intent (used for checkout success polling). ```json { "orders": [ { "id": "uuid", "listingId": "uuid", "releaseId": "uuid", "amountCents": 500, "status": "paid", "fundingSource": "wallet", "createdAt": "2026-01-15T10:00:00.000Z", "vendorSlug": "acme", "vendorName": "Acme Corp", "listingSlug": "router-eval", "listingTitle": "Router Eval Skill", "version": "1.0.0" } ] } ``` --- ## Downloads ### Get download URL `POST /v1/downloads` — Auth: download scope **Request body:** ```json { "releaseId": "uuid" } ``` **Response:** ```json { "url": "https://...signed-url...", "sha256": "a3f8c2d1...", "expiresAt": "2026-01-15T10:05:00.000Z" } ``` --- ## User ### Get current user `GET /v1/users/me` — Auth: Bearer token ```json { "user": { "id": "uuid", "email": "user@example.com", "name": "Ada Lovelace", "avatarUrl": "https://...", "emailVerified": true, "createdAt": "2026-01-01T00:00:00.000Z" } } ``` ### Update profile `PATCH /v1/users/me` — Auth: Bearer token **Request body (all fields optional):** ```json { "name": "Ada Lovelace", "avatarUrl": "https://..." } ``` ### Delete account `DELETE /v1/users/me` — Auth: Bearer token Soft-deletes the user account: all personally identifiable information (name, email, avatar) is anonymized, and all active API tokens are revoked immediately. The anonymized record is retained for financial audit trail integrity. This action is irreversible. ```json { "ok": true } ``` --- ## Vendor ### Create or update vendor profile `POST /v1/vendor/profile` — Auth: sell scope **Request body:** ```json { "slug": "acme", // 2–32 chars, lowercase letters/numbers/hyphens "displayName": "Acme Corp", // 1–64 chars "bio": "We make skills.", // optional, max 500 chars "website": "https://acme.io" // optional, must be valid URL } ``` ### Start Stripe Connect onboarding `POST /v1/vendor/onboard` — Auth: sell scope ```json { "url": "https://connect.stripe.com/setup/..." } ``` ### Upload release `POST /v1/vendor/releases` — Auth: sell scope **Request:** `multipart/form-data` with: | Field | Type | Description | |---|---|---| | `archive` | file (.zip) | Package archive | | `priceCents` | number | Price in cents (0 for free) | **Response:** ```json { "release": { "id": "uuid", "version": "1.0.0", "scanStatus": "pending", "createdAt": "2026-01-15T10:00:00.000Z" }, "listing": { "id": "uuid", "slug": "my-skill" } } ``` ### Publish release `PATCH /v1/vendor/releases/:id/publish` — Auth: sell scope ```json { "ok": true, "version": "1.0.0" } ``` ### Update listing `PATCH /v1/vendor/listings/:id` — Auth: sell scope **Request body (all fields optional):** ```json { "title": "My Awesome Skill", // 1–120 chars "description": "...", // 1–1024 chars "tags": ["react", "testing"], // max 10 tags "priceCents": 500, // 0 = free "readmeMd": "# My Skill\n...", // raw Markdown for listing page "status": "published" // optional: "published" | "unlisted" | "draft" } ``` ### Get vendor analytics `GET /v1/vendor/analytics` — Auth: sell scope ```json { "vendor": { "slug": "acme", "displayName": "Acme Corp", "stripeOnboardingComplete": true }, "revenue": { "totalCents": 15000, "totalOrders": 42 }, "listings": [ { "id": "uuid", "slug": "router-eval", "title": "Router Eval Skill", "priceCents": 500, "installCount": 42, "orderCount": 38, "revenueCents": 14250 } ] } ``` ### Vendor verification #### Get verification status `GET /v1/vendor/verification` — Auth: sell scope ```json { "domainVerified": false, "githubVerified": true, "githubOrg": "acme-corp", "verified": true } ``` #### Start domain verification `POST /v1/vendor/verify/domain` — Auth: sell scope Returns a DNS TXT record to add to your domain for verification. ```json { "record": "mog-verify=a1b2c3d4e5f6..." } ``` #### Check domain verification `POST /v1/vendor/verify/domain/check` — Auth: sell scope Checks whether the DNS TXT record is live. ```json { "verified": true } ``` #### Start GitHub org verification `GET /v1/vendor/verify/github` — Auth: sell scope Redirects to GitHub OAuth to verify ownership of a GitHub org. Returns `{ "url": "https://github.com/login/oauth/authorize?..." }`. ### Signing keys Used by `mog publish` to sign package archives. Buyers can verify publisher authenticity. #### List signing keys `GET /v1/vendor/keys` — Auth: sell scope ```json { "activeKey": { "publicKey": "-----BEGIN PUBLIC KEY-----\n...", "fingerprint": "a1b2c3d4e5f6a7b8" }, "log": [ { "action": "register", "fingerprint": "a1b2c3d4e5f6a7b8", "createdAt": "2026-01-15T10:00:00.000Z" } ] } ``` #### Register or rotate signing key `POST /v1/vendor/keys` — Auth: sell scope **Request body:** ```json { "publicKey": "-----BEGIN PUBLIC KEY-----\n...", "fingerprint": "a1b2c3d4e5f6a7b8" } ``` **Response:** ```json { "action": "register", "fingerprint": "a1b2c3d4e5f6a7b8" } ``` `action` is `"register"` on first key, `"rotate"` if replacing an existing key. #### Revoke signing key `DELETE /v1/vendor/keys/:fingerprint` — Auth: sell scope ```json { "ok": true } ``` ### Reply to review `POST /v1/vendor/reviews/:id/reply` — Auth: sell scope **Request body:** ```json { "body": "Thanks for the feedback! Fixed in v1.1.0." } ``` ```json { "ok": true } ``` --- ## Spend policies Spend policies control what agents can purchase autonomously. See [Spend policies](/docs/spend-policies) for the full reference. ### List policies `GET /v1/policies` — Auth: Bearer token ```json { "policies": [ { "id": "uuid", "name": "CI agent policy", "maxPerPurchaseCents": 1000, "dailyLimitCents": 5000, "monthlyLimitCents": 20000, "requireApprovalAboveCents": 500, "vendorAllowlist": [], "blockedTypes": [], "active": true, "createdAt": "2026-01-01T00:00:00.000Z" } ] } ``` ### Create policy `POST /v1/policies` — Auth: Bearer token **Request body:** ```json { "name": "CI agent policy", // required, 1–128 chars "maxPerPurchaseCents": 1000, // optional, cents "dailyLimitCents": 5000, // optional "monthlyLimitCents": 20000, // optional "requireApprovalAboveCents": 500, // optional — require user approval above this price "vendorAllowlist": [], // optional — empty = all vendors allowed "blockedTypes": ["bundle"], // optional — block specific package types "active": true // optional, default: true } ``` ### Update policy `PATCH /v1/policies/:id` — Auth: Bearer token Same fields as create, all optional. Returns updated policy. ### Delete policy `DELETE /v1/policies/:id` — Auth: Bearer token ```json { "ok": true } ``` --- ## Leaderboard `GET /v1/leaderboard` Get the package leaderboard. No authentication required. **Query parameters:** | Parameter | Type | Description | |---|---|---| | `window` | `all` \| `trending` \| `hot` | Ranking window (default: `all`). `all` sorts by mogRating; `trending` and `hot` sort by recent install velocity. | | `type` | `skill` \| `rule` \| `bundle` \| `template` | Filter by package type | | `limit` | number | Max results (default: 50, max: 200) | | `offset` | number | Pagination offset | ```json { "rankings": [ { "rank": 1, "listing": { "vendor": "acme", "slug": "router-eval", "title": "Router Eval Skill", "description": "...", "type": "skill", "targets": ["cursor", "claude-code"], "priceCents": 500, "currency": "usd", "mogRating": 4.8, "installCount": 1240, "installs24h": 12, "installs7d": 87, "latestVersion": "1.0.0", "vendorName": "Acme Corp", "vendorVerified": true } } ], "total": 42, "totalInstalls": 98230, "window": "all", "generatedAt": "2026-02-26T00:00:00.000Z" } ``` --- ## Audits `GET /v1/audits` Get scan/audit results for published packages. No authentication required. Useful for transparency tooling and dashboards. **Query parameters:** | Parameter | Type | Description | |---|---|---| | `type` | string | Filter by package type | | `status` | passed \| flagged \| failed \| pending | Filter by scan status | | `limit` | number | Max results (default: 20, max: 100) | | `offset` | number | Pagination offset | ```json { "audits": [ { "rank": 1, "vendor": "acme", "slug": "router-eval", "title": "Router Eval Skill", "type": "skill", "vendorVerified": true, "mogRating": 4.8, "installCount": 124, "scan": { "status": "passed", "label": "safe", "qualityScore": 87, "version": "1.0.0", "scannedAt": "2026-01-15T10:00:00.000Z" }, "promptGuard": { "ran": true, "verified": true, "perFile": [{ "file": "SKILL.md", "label": "BENIGN", "score": 0.99 }] } } ], "total": 42, "generatedAt": "2026-02-23T18:00:00.000Z" } ``` --- ## Webhooks ### Stripe webhook `POST /v1/webhooks/stripe` Stripe webhook handler. Verifies the `stripe-signature` header. Handles payment and account lifecycle events. ```json { "received": true } ``` --- ## Billing Buyer billing and payment management. ### Spending overview `GET /v1/billing/overview` — Auth: Bearer token Returns aggregate spending stats for the authenticated user. ```json { "allTime": { "totalCents": 5000, "totalOrders": 12 }, "thisMonth": { "totalCents": 1500 }, "thisWeek": { "totalCents": 500 }, "recentOrders": [ { "id": "uuid", "amountCents": 500, "status": "paid", "createdAt": "2026-02-15T10:00:00.000Z", "listingTitle": "Router Eval Skill", "listingSlug": "router-eval", "vendorSlug": "acme" } ] } ``` ### List payment methods `GET /v1/billing/payment-methods` — Auth: Bearer token ```json { "hasStripeCustomer": true, "paymentMethods": [ { "id": "pm_xxx", "brand": "visa", "last4": "4242", "expMonth": 12, "expYear": 2028 } ] } ``` ### Create setup intent `POST /v1/billing/setup-intent` — Auth: Bearer token Creates a Stripe SetupIntent for adding a new payment method via the Stripe Payment Element. ```json { "clientSecret": "seti_xxx_secret_xxx" } ``` ### Create billing portal session `POST /v1/billing/portal-session` — Auth: Bearer token Creates a Stripe Customer Portal session for managing payment methods and invoices. ```json { "url": "https://billing.stripe.com/session/..." } ``` ### Create seller dashboard link `POST /v1/billing/seller-dashboard-link` — Auth: sell scope Creates a Stripe Express Dashboard login link for sellers to view payouts. ```json { "url": "https://connect.stripe.com/express/..." } ``` ### Seller overview `GET /v1/billing/seller-overview` — Auth: sell scope ```json { "isVendor": true, "vendor": { "slug": "acme", "displayName": "Acme Corp", "stripeOnboardingComplete": true }, "allTime": { "grossCents": 15000, "netCents": 13500, "totalSales": 42 }, "thisMonth": { "grossCents": 5000, "netCents": 4500 } } ``` If the user has no vendor profile, returns `{ "isVendor": false }`. --- ## Wallet Pre-funded wallet balance for frictionless purchases. Top up once; use for any purchase via `"useWallet": true` in the purchase endpoint. ### Get wallet `GET /v1/wallet` — Auth: Bearer token ```json { "balanceCents": 4500, "autoTopUpEnabled": false, "autoTopUpThresholdCents": 500, "autoTopUpAmountCents": 2000 } ``` ### Top up wallet `POST /v1/wallet/top-up` — Auth: purchase scope Creates a Stripe PaymentIntent. Pass the `clientSecret` to Stripe's Payment Element. Balance is credited on `payment_intent.succeeded`. **Request body:** ```json { "amountCents": 2000 } ``` Min: 500 ($5.00). Max: 50000 ($500.00). **Response:** ```json { "clientSecret": "pi_xxx_secret_xxx" } ``` ### Configure auto top-up `PATCH /v1/wallet/auto-top-up` — Auth: purchase scope Automatically top up when balance drops below a threshold. Requires a saved payment method. **Request body (all fields optional):** ```json { "enabled": true, "thresholdCents": 500, "amountCents": 2000 } ``` ```json { "autoTopUpEnabled": true, "autoTopUpThresholdCents": 500, "autoTopUpAmountCents": 2000 } ``` ### Wallet transactions `GET /v1/wallet/transactions` — Auth: Bearer token **Query parameters:** `limit` (max 100, default 50), `cursor` (from previous response for keyset pagination). ```json { "transactions": [ { "id": "uuid", "type": "purchase", "amountCents": -500, "balanceAfterCents": 4000, "description": "Purchase: acme/router-eval", "createdAt": "2026-02-15T10:00:00.000Z" } ], "nextCursor": null, "hasMore": false } ``` Transaction `type` values: `top_up`, `purchase`, `refund`, `auto_top_up`, `metered_usage` (deducted when calling a live service tool). --- ## Organizations Organizations let teams share a wallet, spend policies, and private packages. ### Create organization `POST /v1/orgs` — Auth: Bearer token **Request body:** ```json { "slug": "acme-team", "name": "Acme Team" } ``` Returns `{ "org": { "id": "uuid", "slug": "acme-team", "name": "Acme Team" } }` (HTTP 201). Creator becomes `owner`. ### List organizations `GET /v1/orgs` — Auth: Bearer token ```json { "orgs": [ { "id": "uuid", "slug": "acme-team", "name": "Acme Team", "role": "owner", "createdAt": "2026-01-01T00:00:00.000Z" } ] } ``` ### Get organization `GET /v1/orgs/:slug` — Auth: Bearer token (must be a member) ```json { "org": { "id": "uuid", "slug": "acme-team", "name": "Acme Team", "myRole": "admin" }, "members": [ { "userId": "uuid", "role": "owner", "name": "Ada Lovelace", "email": "ada@acme.io" } ] } ``` ### Update organization `PATCH /v1/orgs/:slug` — Auth: Bearer token (admin or owner) **Request body (all optional):** `{ "name": "...", "avatarUrl": "https://..." }` ### Delete organization `DELETE /v1/orgs/:slug` — Auth: Bearer token (owner only) ```json { "deleted": true } ``` ### Invite member `POST /v1/orgs/:slug/members` — Auth: Bearer token (admin or owner) Sends an invitation email. Invitations expire after 7 days. **Request body:** ```json { "email": "new@member.io", "role": "member" } ``` `role` options: `"admin"`, `"member"`. Returns `{ "invitation": { ... } }` (HTTP 201). ### Accept invitation `POST /v1/orgs/accept-invite` — Auth: Bearer token **Request body:** ```json { "token": "invite-token-from-email" } ``` ```json { "accepted": true } ``` ### Change member role `PATCH /v1/orgs/:slug/members/:userId` — Auth: Bearer token (admin or owner) ```json { "role": "admin" } ``` ### Remove member `DELETE /v1/orgs/:slug/members/:userId` — Auth: Bearer token (admin or owner) ```json { "removed": true } ``` ### Org wallet `GET /v1/orgs/:slug/wallet` — Auth: Bearer token (member) Same shape as personal wallet. Top up, configure auto top-up, and list transactions via: - `POST /v1/orgs/:slug/wallet/top-up` - `PATCH /v1/orgs/:slug/wallet/auto-top-up` - `GET /v1/orgs/:slug/wallet/transactions` All behave identically to personal wallet endpoints. ### Org spend policies `GET /v1/orgs/:slug/policies` — Auth: Bearer token (member) Returns spend policies for the org. Org policies take priority over the token holder's personal policy when purchasing on behalf of the org. `POST /v1/orgs/:slug/policies` — Auth: Bearer token (admin or owner) Same fields as personal spend policy creation. See [Spend policies](/docs/spend-policies). ### Org packages `GET /v1/orgs/:slug/packages` — Auth: Bearer token (member) Lists packages owned by the org. Supports `?type=` and `?status=` filters. `PATCH /v1/orgs/:slug/packages/:listingId` — Auth: Bearer token (admin or owner) Change package visibility. `visibility` values: `"public"`, `"private"`, `"org_only"`. --- ## Agent network — Sessions ### Open session `POST /v1/network/sessions` — Auth: purchase scope Opens a session with a published service. **Request body:** ```json { "vendor": "acme", "slug": "travel-agent", "intent": "book_travel", "context": { "destination": "Tokyo", "budgetCents": 150000 }, "settlementMethod": "wallet" } ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `vendor` | string | Yes | Vendor slug | | `slug` | string | Yes | Listing slug | | `intent` | string | No | Sends an `intent.open` message | | `context` | object | No | Arbitrary context | | `settlementMethod` | string | No | `stripe_mpp`, `stripe_acp`, `free`, `wallet` | **Response:** ```json { "session": { "id": "uuid", "status": "open", "protocol": "mcp", "transport": "streamable_http", "createdAt": "2026-03-19T12:00:00.000Z" }, "listingId": "uuid" } ``` ### Get session `GET /v1/network/sessions/:id` — Auth: Bearer token (buyer or vendor) ```json { "session": { "id": "uuid", "status": "open" }, "role": "buyer", "listingSlug": "travel-agent", "vendorSlug": "acme" } ``` ### Send message `POST /v1/network/sessions/:id/messages` — Auth: purchase scope **Request body:** ```json { "type": "quote.request", "correlationId": "optional-corr-id", "payload": { "budgetCents": 150000 } } ``` **Response:** ```json { "sent": { "id": "msg-uuid", "type": "quote.request" }, "responses": [ { "id": "msg-uuid", "type": "quote.response", "payload": {} } ] } ``` ### Get messages `GET /v1/network/sessions/:id/messages` — Auth: Bearer token (buyer or vendor) **Query parameters:** `limit` (max 200, default 50), `after` (message ID cursor). ```json { "messages": [ { "id": "uuid", "direction": "outbound", "messageType": "intent.open", "deliveryStatus": "delivered", "createdAt": "2026-03-19T12:00:00.000Z", "payload": {} } ] } ``` ### Close session `POST /v1/network/sessions/:id/close` — Auth: purchase scope ```json { "ok": true, "session": { "id": "uuid", "status": "closed" } } ``` ### Vendor inbox `GET /v1/network/inbox` — Auth: sell scope Returns open sessions targeting the vendor's listings. **Query parameters:** `limit` (max 100, default 50). ```json { "sessions": [ { "session": { "id": "uuid", "status": "open" }, "listingSlug": "travel-agent" } ] } ``` ### Service health `GET /v1/network/service-health` — Auth: sell scope Latest health probe results per listing for the vendor. ```json { "listings": [ { "id": "uuid", "slug": "travel-agent", "title": "Travel Agent", "serviceEndpoint": "https://api.acme.com/mcp", "serviceStatus": "active", "uptimePct": "99.95", "latestCheck": { "status": "healthy", "responseMs": 340, "toolsCount": 5, "error": null, "checkedAt": "2026-03-19T12:00:00.000Z" } } ] } ``` --- ## Agent network — Services ### Discover live services `GET /v1/services` No authentication required. **Query parameters:** | Parameter | Type | Description | |-----------|------|-------------| | `tool` | string | Filter by tool name | | `protocol` | string | `mcp`, `a2a`, `https`, `acp` | | `settlement` | string | Filter by settlement method | | `maxPerCallCents` | number | Maximum per-call cost | | `status` | `active` \| `inactive` \| `degraded` | Service status | | `verified` | boolean | Only verified vendors | | `sort` | `recent` \| `trusted` | Sort order (default: `recent`) | | `page` | number | Page (default: 1) | | `per_page` | number | 1–50 (default: 20) | **Response:** ```json { "services": [ { "id": "uuid", "slug": "travel-agent", "title": "Travel Agent", "vendorSlug": "acme", "serviceCard": { "protocol": "mcp", "transport": "streamable_http", "endpoint": "https://api.acme.com/mcp", "toolNames": ["search_flights", "book_flight"], "settlementMethods": ["wallet", "stripe_mpp"], "perCallCents": 5, "status": "active" }, "totalCalls": 12400, "successRate": "99.20", "avgResponseMs": 340, "uptimePct": "99.95" } ], "total": 1, "page": 1, "perPage": 20 } ``` ### Call tool (metered) `POST /v1/services/:vendor/:slug/call` — Auth: purchase scope Invokes a tool on a live service. Mog deducts `perCallCents` from the caller's wallet. **Request body:** ```json { "tool": "search_flights", "input": { "origin": "SFO", "destination": "NRT" }, "maxCostCents": 10, "sessionId": "optional-session-uuid" } ``` | Field | Type | Required | Description | |-------|------|----------|-------------| | `tool` | string | Yes | Tool name to invoke | | `input` | object | No | Tool input parameters | | `maxCostCents` | number | No | Reject if cost exceeds this | | `sessionId` | string | No | Attach to an existing session | **Response:** ```json { "result": { "flights": [] }, "costCents": 5, "walletBalanceCents": 4495, "usageRecordId": "uuid", "durationMs": 320 } ``` --- ## Agent network — Vendor service registration ### Update listing with service fields `PATCH /v1/vendor/listings/:id` — Auth: sell scope In addition to the standard listing fields, you can set: | Field | Type | Description | |-------|------|-------------| | `serviceEndpoint` | string \| null | Live service URL | | `serviceProtocol` | `mcp` \| `a2a` \| `https` \| `acp` \| null | Protocol | | `serviceTransport` | `streamable_http` \| `sse` \| `stdio` \| `jsonrpc` \| null | Transport | | `pricingModel` | `one_time` \| `metered` \| `monthly` \| `annual` | Pricing model | | `perCallCents` | number | Per-call cost in cents (metered pricing) | | `settlementMethods` | string[] | `stripe_mpp`, `stripe_acp`, `free`, `wallet`, `invoice` | | `capabilities` | object \| null | Machine-readable capability descriptions | | `agentCard` | object \| null | Public agent card metadata | --- # Authentication URL: https://mog.md/docs/authentication mog uses two authentication systems: the web app uses OAuth (GitHub/Google) via NextAuth, while the CLI and API use a device code flow designed for headless environments and autonomous agents. ## Device code flow (CLI & API) The device code flow follows [RFC 8628](https://datatracker.ietf.org/doc/html/rfc8628). It lets a CLI or agent authenticate without ever opening a browser on the host machine — ideal for CI, Docker containers, and agent runners. ### How it works 1. The CLI calls `POST /v1/auth/device/start` — no credentials needed. The API returns a `deviceCode` (used internally), a short `userCode` (shown to the user), a `verificationUri`, and a polling `interval`. 2. The CLI displays the code and URL to the user. It tries to open the browser automatically, but this is best-effort (it's fine if the environment is headless). 3. The user opens `mog.md/device` in any browser, signs in with GitHub or Google, and enters the code. 4. The CLI polls `POST /v1/auth/device/poll` every `interval` seconds. When the user approves, the poll response includes a Bearer token. 5. The CLI stores the token locally and uses it for all future API requests. ### Flow diagram ```text title="flow" CLI API Browser | | | |-- POST /auth/device/start ->| | |<-- { deviceCode, userCode } | | | | | | (display userCode to user) | | | | | |-- poll /auth/device/poll -->| user visits /device | |<-- { status: pending } |<-- POST /auth/device/approve | | | { userCode } | |-- poll /auth/device/poll -->| | |<-- { status: approved, | | | token: "mog_..." } | | ``` ### Code expiry Device codes expire after 15 minutes (`expiresIn: 900`). If the user doesn't approve in time, the poll returns `{ "status": "expired" }` and the CLI exits with an error. Run `mog auth` again to start a new flow. ## API tokens Tokens returned by the device flow are API tokens. They are cryptographically signed and verified server-side; credential material is stored securely at rest. The plaintext token is only returned once, at issuance time — store it securely. ### Using a token ```sh Authorization: Bearer mog_your_token_here ``` All protected API endpoints accept this header. ### Token scopes Tokens have one or more scopes that limit what they can do. The device flow issues tokens with all scopes by default; tokens created from the dashboard can be restricted. | Scope | Grants access to | |---|---| | `read` | `GET /v1/users/me`, `GET /v1/entitlements`, `POST /v1/listings/.../reviews` | | `purchase` | `POST /v1/purchases` | | `download` | `POST /v1/downloads` | | `sell` | All `/v1/vendor/*` endpoints | For an autonomous agent that only needs to install packages, you can restrict the token to `read`, `purchase`, and `download` scopes — preventing it from uploading new releases or modifying vendor settings even if compromised. ### Revoking a token ```sh # Via CLI mog auth --logout # Via API POST /v1/auth/token/revoke Authorization: Bearer → { "ok": true } ``` Revocation is immediate. Any subsequent request with the revoked token returns HTTP 401. ## Spend policies on tokens API tokens can be attached to a [spend policy](/docs/spend-policies) that limits autonomous purchasing. This is the recommended setup for agent tokens: 1. Create a spend policy in your dashboard 2. Create or update an API token, attaching the policy ID 3. Give the token to the agent The policy is enforced server-side on every purchase request made with that token, regardless of what the client sends. ## Audit logging Authentication events are logged server-side for security monitoring: - Sign-in events (provider, user ID, timestamp) - Token issuance and revocation - Failed authentication attempts (invalid tokens, expired codes) - Device code flow approvals Audit logs are not accessible via the public API. See [Security model](/docs/security) for more. ## Account deletion You can delete your account via `DELETE /v1/users/me` or from the dashboard settings. Deletion anonymizes all personally identifiable information (name, email, avatar), revokes all active tokens immediately, and is irreversible. Anonymized records are retained for financial audit integrity. See [Security model](/docs/security#account-deletion-and-data-privacy) for details. ## Web app authentication The web app at `mog.md` uses [Auth.js v5](https://authjs.dev) (NextAuth) with GitHub and Google OAuth providers. Web sessions are separate from API tokens. When you sign in to the web app, the web app internally issues an API token on your behalf for browser-based operations (purchasing, seller dashboard). This token is never exposed to the browser. ## The device authorization page The CLI sends users to `mog.md/device`. On this page, users: 1. Sign in with GitHub or Google (if not already signed in) 2. Enter the 8-character code shown by the CLI 3. Review the scopes being requested 4. Click **Approve** The web app then calls `POST /v1/auth/device/approve` with the user code. The CLI's next poll returns the token. ## Authentication in automation For CI pipelines and non-interactive automation, generate a token from the dashboard and set it as an environment variable. You can then skip the interactive device flow: ```sh # Set token via environment variable export MOG_TOKEN=mog_your_token_here # The CLI reads MOG_TOKEN before checking the credentials file mog install acme/some-skill --auto-buy ``` Always attach a [spend policy](/docs/spend-policies) to automation tokens to limit the blast radius if a token is leaked. --- # CI/CD & automation URL: https://mog.md/docs/ci-cd mog is designed for automation. The CLI works in headless environments, every command supports `--json` for structured output, and the lockfile ensures reproducible installs across machines. ## Authentication in CI CI environments can't use the interactive device code flow. Use an API token instead. ### Generate a token 1. Go to [Dashboard → Settings](/dashboard/settings) 2. Create a new API token with the scopes you need (`read`, `purchase`, `download`) 3. Optionally attach a [spend policy](/docs/spend-policies) to the token ### Set as an environment variable Add `MOG_TOKEN` to your CI provider's secret store: ```sh export MOG_TOKEN="mog_tok_..." ``` The CLI reads `MOG_TOKEN` automatically — no `mog auth` step is needed. ## GitHub Actions ### Install packages from lockfile Restore the exact packages recorded in `mog.lock.json`: ```yaml title=".github/workflows/setup.yml" name: Setup mog packages on: [push] jobs: setup: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 22 - name: Install mog CLI run: npm install -g mogmd - name: Install packages run: mog install --json env: MOG_TOKEN: ${{ secrets.MOG_TOKEN }} ``` ### Check for outdated packages Run `mog outdated` in CI to flag stale dependencies: ```yaml title=".github/workflows/outdated.yml" name: Check mog updates on: schedule: - cron: '0 9 * * 1' # Every Monday at 9am workflow_dispatch: jobs: check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Install mog CLI run: npm install -g mogmd - name: Check for updates run: mog update --dry-run --json env: MOG_TOKEN: ${{ secrets.MOG_TOKEN }} ``` ### Verify lockfile integrity Use `mog doctor` in CI to catch drift between the lockfile and installed packages: ```yaml - name: Verify mog integrity run: mog doctor --json env: MOG_TOKEN: ${{ secrets.MOG_TOKEN }} ``` ## Other CI providers The pattern is the same for any CI system: 1. Install Node.js 2. `npm install -g mogmd` 3. Set `MOG_TOKEN` as a secret environment variable 4. Run `mog install --json` (or whatever commands you need) ### GitLab CI ```yaml title=".gitlab-ci.yml" setup-mog: image: node:22 script: - npm install -g mogmd - mog install --json variables: MOG_TOKEN: $MOG_TOKEN ``` ### CircleCI ```yaml title=".circleci/config.yml" jobs: setup-mog: docker: - image: cimg/node:22.0 steps: - checkout - run: npm install -g mogmd - run: mog install --json ``` ## Agent runners Agents running in automated environments (task runners, cron jobs, autonomous loops) can use the full mog CLI with `--json` and `--auto-buy`. ### Non-interactive installs ```sh mog install acme/react-testing-skill --auto-buy --max-price 500 --json ``` ### Handling approval-required responses When a spend policy blocks a purchase, the CLI exits with code 2 and returns an `approvalUrl`: ```json { "ok": false, "command": "install", "error": "Price (1500¢) exceeds your policy limit (1000¢)", "approvalUrl": "https://mog.md/purchases/approve?listing=uuid" } ``` Your automation should check for exit code 2 and route the approval URL to a human (Slack notification, GitHub issue, email, etc.). ## Caching in CI To speed up CI runs, cache the `mog_modules/` directory and `.cursor/skills/` (or the equivalent for your target): ```yaml title="GitHub Actions" - uses: actions/cache@v4 with: path: | mog_modules/ .cursor/skills/ key: mog-${{ hashFiles('mog.lock.json') }} restore-keys: mog- ``` When the lockfile hasn't changed, the cache hit skips the download entirely. ## Docker Install mog packages during your Docker build: ```dockerfile title="Dockerfile" FROM node:22-slim RUN npm install -g mogmd WORKDIR /app COPY mog.lock.json . ARG MOG_TOKEN RUN mog install --json COPY . . ``` Build with the token as a build arg: ```sh docker build --build-arg MOG_TOKEN="$MOG_TOKEN" . ``` Use `--secret` instead of `--build-arg` for production images to avoid leaking the token into image layers. ## Environment variables reference | Variable | Description | |----------|-------------| | `MOG_TOKEN` | API token — used automatically by the CLI and SDK | | `MOG_CONFIG_DIR` | Override the config directory (default: `~/.config/mog`) | ## Best practices - **Always commit `mog.lock.json`** — it's the source of truth for reproducible installs. - **Scope your CI token** — give it only the scopes it needs (`read` + `download` for install-only pipelines). - **Attach a spend policy** — even in CI, a spend policy prevents runaway costs if a workflow is misconfigured. - **Use `--json`** — parse structured output instead of scraping terminal text. - **Cache aggressively** — mog packages are immutable once published, so caching on the lockfile hash is safe. --- # Claude Code integration URL: https://mog.md/docs/claude-code mog has first-class support for **Claude Code**. The CLI auto-detects Claude Code projects, installs packages to the right paths, and can wire skills into `AGENTS.md` so Claude picks them up automatically. ## How auto-detection works When you run `mog install` in a project directory, the CLI looks for a `.claude/` directory. If it finds one, it sets the target to `claude-code` and uses Claude Code-specific install paths. You can always override with `--target claude-code`. ## Installing skills Skills are SKILL.md packages that teach Claude specific capabilities. ```sh mog install acme/react-testing-skill ``` This downloads the package, verifies its SHA-256 hash, and extracts it to: ```text .claude/skills/react-testing-skill/ SKILL.md README.md ``` ### Wiring skills into AGENTS.md Installing a skill drops files into `.claude/skills/`, but Claude Code needs to know about them. Add `--wire` to handle this automatically: ```sh mog install acme/react-testing-skill --wire ``` This appends a reference to the skill in your project's `AGENTS.md` file, which Claude Code reads as persistent instructions. If `AGENTS.md` doesn't exist yet, the CLI creates it. Without `--wire`, the CLI prints the exact content you'd need to add to `AGENTS.md` manually. ### Manual wiring If you prefer to wire skills yourself, add a reference in your `AGENTS.md`: ```markdown ## React testing skill Follow the instructions in .claude/skills/react-testing-skill/SKILL.md when writing or reviewing React tests. ``` You can scope instructions however you like — Claude Code treats the entire `AGENTS.md` as context for every conversation in the project. ### Subdirectory AGENTS.md Claude Code also supports `AGENTS.md` files in subdirectories. These are picked up when Claude is working in that subtree. If you want a skill scoped to a specific part of your codebase: ```text my-project/ AGENTS.md # Project-wide instructions packages/api/ AGENTS.md # API-specific skill references ``` ## Installing MCP servers MCP server packages are installed by writing configuration to `.mcp.json` in the project root — no file extraction needed. ```sh mog install acme/github-mcp-server ``` The CLI prompts for any required environment variables and writes the config: ```json title=".mcp.json" { "mcpServers": { "acme-github-mcp-server": { "command": "npx", "args": ["-y", "@acme/github-mcp-server@1.0.0"], "env": { "GITHUB_TOKEN": "ghp_your_token" } } } } ``` If `.mcp.json` already has other servers configured, mog merges the new entry without overwriting existing ones. ### Passing env vars non-interactively For CI or agent-driven installs, pass environment variables with `--env`: ```sh mog install acme/github-mcp-server --env GITHUB_TOKEN=ghp_xxx ``` Restart Claude Code after installing an MCP server for it to be discovered. ## Project health check Run `mog doctor` to verify your Claude Code project is set up correctly: ```sh mog doctor ``` This checks: - CLI authentication status - Lockfile integrity (`mog.lock.json`) - Installed packages match the lockfile (version and SHA-256) - Wiring (whether installed skills have corresponding references in `AGENTS.md`) - MCP server config validity ## Listing installed packages ```sh mog ls ``` ```text 2 installed packages acme/react-testing-skill@1.2.0 claude-code .claude/skills/react-testing-skill/ Installed: 1/15/2026 acme/github-mcp-server@1.0.0 claude-code (mcp) .mcp.json Installed: 1/16/2026 ``` ## Updating packages ```sh mog update --dry-run mog update ``` Updates respect semver: by default only patch and minor versions are applied. The lockfile is updated and the old files are replaced. ## Uninstalling ```sh mog uninstall acme/react-testing-skill ``` For skills, this removes the extracted files from `.claude/skills/` and the lockfile entry. If `--wire` was used during install, the corresponding reference in `AGENTS.md` is also removed. For MCP servers, this removes the `mcpServers` entry from `.mcp.json`. ## File layout summary After installing a mix of skills and MCP servers, your Claude Code project looks like this: ```text my-project/ .claude/ skills/ react-testing-skill/ SKILL.md README.md another-skill/ SKILL.md .mcp.json # MCP server configs (auto-managed) AGENTS.md # Skill references wired here (--wire) mog.lock.json # Lockfile (commit to version control) ``` ## Tips - **Commit `mog.lock.json`** to version control so teammates get the same package versions. - **Commit `AGENTS.md`** — it's the equivalent of Cursor rules and should be shared with the team. - **Don't commit secrets** in `.mcp.json` — add it to `.gitignore` if your MCP configs contain API keys. Consider using environment variables referenced from your shell profile instead. - Use `mog explain /` to preview a package's metadata, install path, and target compatibility before installing. - Use `mog install --preflight` to see exactly what would happen without making changes. --- # CLI reference URL: https://mog.md/docs/cli The mog CLI is available as an npm package. All commands support `--json` for machine-readable output, making the CLI suitable for use inside agent runners and CI pipelines. ```sh npm install -g mogmd ``` ## Exit codes | Code | Meaning | |---|---| | `0` | Success | | `1` | Error (printed to stderr) | | `2` | Approval required — an `approvalUrl` is included in the JSON output | ## JSON output Add `--json` to any command to get structured output. All JSON responses share this envelope: ```json // Success { "ok": true, "command": "install", "data": { ... } } // Error { "ok": false, "command": "install", "error": "Package not found" } // Approval required (exit code 2) { "ok": false, "command": "buy", "error": "Approval required", "approvalUrl": "https://mog.md/..." } ``` The `data` field shape varies per command — see each command below for its specific output shape. ## Global options | Flag | Description | |---|---| | `--version` | Print CLI version and exit | | `--help` | Print help for a command | --- ## mog init Initialize a mog project in the current directory. Creates a lockfile and prints target-specific setup guidance. ```sh mog init [options] ``` | Flag | Description | Default | |---|---|---| | `--dir ` | Project directory | current directory | | `--json` | Output as JSON | — | ### What init does 1. Creates an empty `mog.lock.json` if one doesn't exist 2. Adds a note to `.gitignore` (if inside a git repo) 3. Auto-detects the target (Cursor, Claude Code, etc.) from the project directory 4. Prints getting-started guidance for that target ### JSON output (`--json`) ```json { "ok": true, "command": "init", "data": { "target": "cursor", "lockfile": "/my-project/mog.lock.json", "created": ["mog.lock.json"] } } ``` --- ## mog setup One-shot onboarding: authenticate (device code by default, or optional web `--token`, or existing **`MOG_TOKEN`** / saved credentials), optionally install `mogmd` globally when you ran via `npx`, then run the same project initialization as `mog init`. ```sh mog setup [options] mog setup --token "mog_setup_…" # optional shortcut from mog.md Install CLI ``` | Flag | Description | Default | |---|---|---| | `--token ` | One-time token from the Install CLI dialog (skips device login) | — | | `--dir ` | Project directory | current directory | | `--no-global` | Skip global install when using `npx` | — | | `--json` | Output as JSON (non-interactive: requires `MOG_TOKEN` or valid saved session) | — | ### Examples ```sh npx mogmd@latest setup npx mogmd@latest setup --token "mog_setup_…" MOG_TOKEN=… npx mogmd@latest setup --json mog setup --token "mog_setup_…" --no-global ``` --- ## mog auth Authenticate with the mog marketplace using the device code flow (RFC 8628). ```sh mog auth [options] ``` | Flag | Description | |---|---| | `--logout` | Log out and remove stored credentials | | `--status` | Show current auth status without triggering login | | `--force` | Re-authenticate even if already signed in | | `--json` | Output as JSON | ### How it works Running `mog auth` starts the device flow: it requests a short code from the API, prints a URL and code, and polls until you approve in a browser. Once approved, the token is stored locally. This flow works in fully headless environments — no browser is needed on the CLI host. ### Examples ```sh # Start authentication mog auth # Check if authenticated mog auth --status # Log out mog auth --logout ``` ### Credential storage - macOS / Linux: `~/.config/mog/credentials.json` - Windows: `%USERPROFILE%\.config\mog\credentials.json` ### JSON output (`--json`) ```json { "ok": true, "command": "auth", "data": { "authenticated": true } } { "ok": true, "command": "auth", "data": { "loggedOut": true } } { "ok": true, "command": "auth", "data": { "authenticated": false } } ``` --- ## mog search Search the mog marketplace for packages. ```sh mog search [query] [options] ``` | Flag | Description | Default | |---|---|---| | `[query]` | Full-text search query (optional) | — | | `--type ` | Filter by type: `skill`, `rule`, `bundle`, `template`, `mcp` | — | | `--target ` | Filter by agent target: `cursor`, `claude-code`, `codex`, `gemini-cli`, `windsurf`, `generic` | — | | `--sort ` | Sort order: `popular`, `recent`, `rated`, `price_asc`, `price_desc` | `popular` | | `--free` | Show only free packages | — | | `--page ` | Page number | `1` | | `--json` | Output as JSON | — | ### Examples ```sh # Free-text search mog search "react testing" # Only skills for Cursor mog search --target cursor --type skill # Free packages sorted by newest mog search --free --sort recent # JSON output for scripting mog search "testing" --json ``` ### JSON output (`--json`) ```json { "ok": true, "command": "search", "data": { "results": [ { "id": "uuid", "vendorSlug": "acme", "slug": "react-testing-skill", "title": "React Testing Skill", "description": "...", "type": "skill", "targets": ["cursor", "claude-code"], "priceCents": 0, "currency": "usd", "latestVersion": "1.2.0", "installCount": 124, "rating": "4.8", "ratingCount": 12, "vendorName": "Acme Corp", "vendorVerified": true } ], "total": 1, "page": 1, "perPage": 20 } } ``` --- ## mog buy Purchase a package without installing it. ```sh mog buy [options] ``` **Requires authentication.** | Flag | Description | |---|---| | `` | Package identifier, e.g. `acme/router-eval` | | `--max-price ` | Maximum price in cents. If the package costs more, the purchase is blocked. | | `--auto` | Allow automatic purchase within policy limits | | `--json` | Output as JSON | ### Approval required (exit code 2) If the package price exceeds your [spend policy](/docs/spend-policies) or the `--max-price` ceiling, the command exits with code `2`: ```json { "ok": false, "command": "buy", "error": "Approval required", "approvalUrl": "https://mog.md/purchases/approve?listing=..." } ``` ### JSON output (`--json`) ```json // Successful purchase { "ok": true, "command": "buy", "data": { "status": "purchased", "entitlementId": "uuid", "orderId": "uuid", "amountCents": 500 } } // Already owned { "ok": true, "command": "buy", "data": { "status": "already_owned", "entitlementId": "uuid" } } ``` --- ## mog install Download, verify, and install a package. Optionally purchase it in the same step with `--auto-buy`. ```sh mog install [options] ``` **Requires authentication.** | Flag | Description | Default | |---|---|---| | `` | Package identifier, e.g. `acme/router-eval` | — | | `--target ` | Installation target: cursor, claude-code, codex, gemini-cli, windsurf, generic. Auto-detected if not specified. | auto | | `--auto-buy` | Automatically purchase the package if not already owned | — | | `--max-price ` | Maximum price in cents when using `--auto-buy` | — | | `--preflight` | Show what would happen without making any changes | — | | `--dir ` | Installation directory | current directory | | `--env ` | Set an environment variable for MCP packages (repeatable) | — | | `--wire` | Auto-create an editor rule pointing to the installed skill | — | | `--require-signatures` | Fail if the package signature is missing or invalid | — | | `--json` | Output as JSON | — | ### Target auto-detection If `--target` is not specified, the CLI detects the environment by checking for marker directories in the current working directory (checked in this order): - `.cursor/` → target: `cursor` - `.claude/` → target: `claude-code` - `.windsurf/` → target: `windsurf` - `.gemini/` → target: `gemini-cli` - `.codex/` → target: `codex` - `.openclaw/` → target: `openclaw` - (none) → target: `generic` ### Default install paths | Target | Default install path | |---|---| | `cursor` | `.cursor/skills/{slug}/` | | `claude-code` | `.claude/skills/{slug}/` | | `codex` | `mog_modules/{slug}/` | | `gemini-cli` | `.gemini/skills/{slug}/` | | `windsurf` | `.windsurf/skills/{slug}/` | | `openclaw` | `skills/{slug}/` | | `generic` | `mog_modules/{slug}/` | Package authors can override these defaults in their `mog.yaml` `install_map` field. ### Wiring skills into your editor (`--wire`) After installing a skill package, your AI assistant still needs a pointer to the skill file. The `--wire` flag creates that pointer automatically: ```sh # Cursor: creates .cursor/rules/{slug}.mdc pointing to the SKILL.md mog install acme/react-testing-skill --target cursor --wire # Claude Code: appends a reference to AGENTS.md mog install acme/react-testing-skill --target claude-code --wire ``` Without `--wire`, the CLI prints a "Next steps" block showing the exact file contents to create manually. ### MCP server packages For packages with `type: mcp`, `mog install` writes the server configuration to the client's `mcpServers` config file instead of extracting files. Use `--env KEY=VALUE` to supply required environment variables non-interactively: ```sh mog install acme/github-mcp-server \ --env GITHUB_TOKEN=ghp_xxx \ --target cursor # Multiple env vars mog install acme/slack-mcp \ --env SLACK_TOKEN=xoxb-xxx \ --env SLACK_TEAM_ID=T0123 \ --auto-buy ``` After installing an MCP package, restart your IDE for the server to be discovered. ### What install does 1. Fetches the listing and resolves the latest published release 2. Checks your entitlement; purchases if `--auto-buy` is set 3. Requests a signed download URL (expires in 5 minutes) 4. Downloads the `.zip` archive and verifies the SHA-256 hash 5. Extracts files to the install path (path traversal protected) 6. Writes the entry to `mog.lock.json` atomically ### JSON output (`--json`) ```json { "ok": true, "command": "install", "data": { "package": "acme/router-eval", "version": "1.0.0", "target": "cursor", "installPath": "/my-project/.cursor/skills/router-eval/", "files": 3 } } ``` --- ## mog ls List all packages installed in the current project (reads from `mog.lock.json`). ```sh mog ls [options] ``` | Flag | Description | Default | |---|---|---| | `--dir ` | Project directory to read lockfile from | current directory | | `--check-updates` | Check for available updates (requires network) | — | | `--json` | Output as JSON | — | ### JSON output (`--json`) ```json { "ok": true, "command": "ls", "data": { "count": 2, "packages": [ { "name": "acme/router-eval", "vendor": "acme", "slug": "router-eval", "version": "1.0.0", "target": "cursor", "installPath": "/my-project/.cursor/skills/router-eval/", "installedAt": "2026-01-15T10:00:00.000Z", "updateChannel": "minor" } ] } } ``` --- ## mog update Update installed packages to the latest compatible version. Respects the `updateChannel` field in the lockfile (default: `minor` — blocks major version bumps). ```sh mog update [vendor/package] [options] ``` **Requires authentication.** | Flag | Description | Default | |---|---|---| | `[vendor/package]` | Specific package to update. If omitted, updates all packages. | — | | `--dry-run` | Show available updates without installing anything | — | | `--channel ` | Override the update channel for this run | lockfile value | | `--major` | Allow major version upgrades (shorthand for `--channel major`) | — | | `--dir ` | Project directory | current directory | | `--json` | Output as JSON | — | ### Update channels | Channel | Allowed updates | |---|---| | `patch` | Patch versions only (e.g. 1.0.0 → 1.0.1) | | `minor` | Patch and minor versions (e.g. 1.0.0 → 1.2.0) — **default** | | `major` | All versions including major bumps | ### JSON output (`--json`) ```json { "ok": true, "command": "update", "data": { "updated": [{ "name": "acme/router-eval", "from": "1.0.0", "to": "1.1.0" }], "skipped": [{ "name": "acme/big-upgrade", "version": "2.0.0", "reason": "Major upgrade requires explicit opt-in." }] } } ``` --- ## mog uninstall Remove an installed package and update the lockfile. ```sh mog uninstall [options] ``` | Flag | Description | Default | |---|---|---| | `` | Package identifier, e.g. `acme/router-eval` | — | | `--dir ` | Project directory | current directory | | `--json` | Output as JSON | — | Removes the install directory from disk and deletes the entry from `mog.lock.json`. Does **not** revoke your entitlement — you can reinstall at any time. ### JSON output (`--json`) ```json { "ok": true, "command": "uninstall", "data": { "package": "acme/router-eval", "removedPath": "/my-project/.cursor/skills/router-eval/" } } ``` --- ## mog publish Build, upload, scan, and publish a package from a local directory. ```sh mog publish [options] ``` **Requires authentication with `sell` scope (vendor account required).** | Flag | Description | Default | |---|---|---| | `--dir ` | Package directory to publish | current directory | | `--price ` | Price in USD (e.g. `4.99`). Only applied on the first upload of this package. | — | | `--yes` | Skip confirmation prompt | — | | `--json` | Output as JSON | — | ### What publish does 1. Reads and validates `mog.yaml` in the package directory 2. Zips the directory (excluding `.git`, `node_modules`, `.DS_Store`) 3. Prompts for confirmation (unless `--yes`) 4. Uploads the archive to the API 5. Polls the scan pipeline until the scan completes (max 2 minutes) 6. Automatically publishes the release if the scan passes ### Examples ```sh # Publish from the current directory mog publish # Publish a package directory at a specific price mog publish --dir ./my-skill --price 4.99 # Skip prompts (for CI pipelines) mog publish --yes --json ``` ### JSON output (`--json`) ```json { "ok": true, "command": "publish", "data": { "name": "acme/my-skill", "version": "1.0.0", "releaseId": "uuid", "listingId": "uuid" } } ``` --- ## mog outdated Show available updates without installing anything. Alias for `mog update --dry-run`. ```sh mog outdated [vendor/package] [options] ``` | Flag | Description | Default | |---|---|---| | `[vendor/package]` | Specific package to check. If omitted, checks all. | — | | `--channel ` | Override update channel for this check | lockfile value | | `--major` | Include major version upgrades in check | — | | `--dir ` | Project directory | current directory | | `--json` | Output as JSON | — | ### JSON output (`--json`) ```json { "ok": true, "command": "update", "data": { "updated": [{ "name": "acme/router-eval", "from": "1.0.0", "to": "1.1.0" }], "skipped": [{ "name": "acme/big-upgrade", "version": "2.0.0", "reason": "Major upgrade requires explicit opt-in." }], "failed": [] } } ``` --- ## mog doctor Check project health: installed packages, editor wiring, and configuration. ```sh mog doctor [options] ``` | Flag | Description | Default | |---|---|---| | `--dir ` | Project directory | current directory | | `--json` | Output as JSON | — | ### What doctor checks - **Auth** — whether you're authenticated - **Lockfile** — whether `mog.lock.json` exists - **Target detection** — which editor/tool was detected and why - **Installed packages** — lists all packages with their paths and types - **Missing files** — flags packages whose install path no longer exists - **Wiring** — for Cursor, checks that each installed skill has a matching `.cursor/rules/{slug}.mdc`; for Claude Code, checks that `AGENTS.md` exists; for OpenClaw, checks that `SKILL.md` exists under each openclaw install path Exits with code `1` if any issues are found. ### Example output ```text title="terminal" mog doctor Auth: ✓ authenticated Lockfile: ✓ mog.lock.json Target: cursor (.cursor/ directory found) Packages: 2 Installed packages acme/react-testing-skill@1.2.0 cursor → .cursor/skills/react-testing-skill/ 1 issue found: ⚠ react-testing-skill — no .cursor/rules/react-testing-skill.mdc found. Run: mog install acme/react-testing-skill --wire ``` ### JSON output (`--json`) ```json { "ok": true, "command": "doctor", "data": { "authenticated": true, "lockfile": true, "detectedTarget": "cursor", "detectedReason": ".cursor/ directory found", "packages": [ { "name": "acme/react-testing-skill", "version": "1.2.0", "target": "cursor", "installPath": ".cursor/skills/react-testing-skill/", "installType": "files" } ], "issues": [], "healthy": true } } ``` --- ## mog explain Show package metadata, install paths for all targets, and agent trigger text — useful for agents and scripts that need to understand a package before installing. ```sh mog explain [options] ``` **Requires authentication.** | Flag | Description | |---|---| | `` | Package identifier, e.g. `acme/react-testing-skill` | | `--json` | Output as JSON | ### Example output ```text title="terminal" React Testing Skill acme/react-testing-skill@1.2.0 Comprehensive React testing patterns including RTL, Vitest, and MSW ────────────────────────────────────── Type: skill License: MIT Price: Free Targets: cursor, claude-code Tags: react, testing, vitest URL: https://mog.md/packages/acme/react-testing-skill Install paths by target cursor .cursor/skills/react-testing-skill/ claude-code .claude/skills/react-testing-skill/ Agent trigger (first paragraph of README — paste into rules/AGENTS.md) This skill teaches your AI assistant comprehensive React testing patterns... Install: mog install acme/react-testing-skill --target cursor Install + wire: mog install acme/react-testing-skill --target cursor --wire ``` ### JSON output (`--json`) ```json { "ok": true, "command": "explain", "data": { "name": "acme/react-testing-skill", "title": "React Testing Skill", "description": "Comprehensive React testing patterns...", "type": "skill", "license": "MIT", "targets": ["cursor", "claude-code"], "installPaths": { "cursor": ".cursor/skills/react-testing-skill/", "claude-code": ".claude/skills/react-testing-skill/" }, "latestVersion": "1.2.0", "price": "free", "tags": ["react", "testing", "vitest"], "agentTrigger": "This skill teaches your AI assistant...", "url": "https://mog.md/packages/acme/react-testing-skill" } } ``` --- ## mog org Manage organizations. Organizations let teams share a wallet, spend policies, and private packages under a single account. ```sh mog org [options] ``` The active org context is stored locally. When an org is active, `mog buy` and `mog install --auto-buy` use the org wallet instead of your personal wallet. ### mog org list List organizations you are a member of. ```sh mog org list [options] ``` | Flag | Description | |---|---| | `--json` | Output as JSON | ### mog org create Create a new organization. ```sh mog org create [options] ``` | Argument/Flag | Description | |---|---| | `` | Org identifier — lowercase letters, numbers, hyphens, 2–39 chars | | `` | Display name | | `--json` | Output as JSON | ### mog org switch Set the active org context. All subsequent purchases use the org wallet. ```sh mog org switch [options] ``` Pass `none` or `-` to clear the org context and revert to your personal wallet. | Flag | Description | |---|---| | `--json` | Output as JSON | ### mog org whoami Show the currently active org context. ```sh mog org whoami [options] ``` | Flag | Description | |---|---| | `--json` | Output as JSON | ### mog org invite Invite a user to the current active org by email. ```sh mog org invite [options] ``` **Requires admin role in the org.** | Flag | Description | Default | |---|---|---| | `--role ` | Role to assign | `member` | | `--org ` | Org slug (overrides active context) | active org | | `--json` | Output as JSON | — | ### mog org wallet Show the active org's wallet balance and auto top-up settings. ```sh mog org wallet [options] ``` | Flag | Description | Default | |---|---|---| | `--org ` | Org slug (overrides active context) | active org | | `--json` | Output as JSON | — | --- ## mog keys Manage Ed25519 package signing keys. When a signing key is registered, `mog publish` automatically signs every uploaded archive. Buyers can verify your packages have not been tampered with. ```sh mog keys [options] ``` **Requires a vendor account.** ### mog keys generate Generate a new Ed25519 signing keypair and save it locally. ```sh mog keys generate [options] ``` | Flag | Description | |---|---| | `--force` | Overwrite an existing key | | `--json` | Output as JSON | Key files are stored at: - `~/Library/Application Support/mog/signing-key.pem` (private, mode 0600) - `~/Library/Application Support/mog/signing-key.pub.pem` (public) After generating, run `mog keys register` to activate the key. ### mog keys register Upload your public key to mog.md. Once registered, all future `mog publish` uploads are automatically signed. ```sh mog keys register [options] ``` | Flag | Description | |---|---| | `--json` | Output as JSON | ### mog keys list List your registered signing keys and key history. ```sh mog keys list [options] ``` | Flag | Description | |---|---| | `--json` | Output as JSON | ### mog keys revoke Revoke your current active signing key. Future uploads will not require signatures until a new key is registered. ```sh mog keys revoke [options] ``` | Flag | Description | |---|---| | `--json` | Output as JSON | --- ## Environment variables | Variable | Description | Default | |---|---|---| | `MOG_API_URL` | Override the API base URL (useful for self-hosting or development) | `https://api.mog.md` | | `MOG_TOKEN` | API token. Read before checking the credentials file. | — | --- # Codex integration URL: https://mog.md/docs/codex mog has first-class support for **OpenAI Codex**. The CLI auto-detects Codex projects, installs packages to the right paths, and writes MCP server config directly to `.codex/config.toml`. ## How auto-detection works When you run `mog install` in a project directory, the CLI looks for a `.codex/` directory. If it finds one, it sets the target to `codex` and uses Codex-specific install paths. You can always override with `--target codex`. ## Installing skills Skills are SKILL.md packages that teach Codex specific capabilities. ```sh mog install acme/react-testing-skill ``` This downloads the package, verifies its SHA-256 hash, and extracts it to: ```text mog_modules/react-testing-skill/ SKILL.md README.md ``` Codex reads skills from `.agents/skills/` directories at multiple scopes (repository, user, admin). After installing with mog, you can symlink or copy the skill into Codex's expected location: ```sh mkdir -p .agents/skills ln -s ../../mog_modules/react-testing-skill .agents/skills/react-testing-skill ``` Codex discovers the `SKILL.md` inside the directory and makes the skill available to the agent. ### Global skills Codex also loads skills from `$HOME/.agents/skills/` (user scope). To install a skill for use across all your repositories: ```sh mog install acme/react-testing-skill --target codex cp -r mog_modules/react-testing-skill ~/.agents/skills/react-testing-skill ``` ## Installing MCP servers MCP server packages are installed by writing configuration to `.codex/config.toml` — no file extraction needed. ```sh mog install acme/github-mcp-server ``` The CLI prompts for any required environment variables and writes the config: ```toml title=".codex/config.toml" [mcp_servers.acme-github-mcp-server] command = "npx" args = ["-y", "@acme/github-mcp-server@1.0.0"] [mcp_servers.acme-github-mcp-server.env] GITHUB_TOKEN = "ghp_your_token" ``` If `.codex/config.toml` already has other servers or settings configured, mog merges the new entry without overwriting existing ones. ### Passing env vars non-interactively For CI or agent-driven installs, pass environment variables with `--env`: ```sh mog install acme/github-mcp-server --env GITHUB_TOKEN=ghp_xxx ``` ### HTTP transport For remotely-hosted MCP servers, Codex supports HTTP transport: ```toml title=".codex/config.toml" [mcp_servers.acme-remote-server] url = "https://mcp.acme.dev/sse" bearer_token_env_var = "ACME_API_KEY" ``` ## Project health check Run `mog doctor` to verify your Codex project is set up correctly: ```sh mog doctor ``` This checks: - CLI authentication status - Lockfile integrity (`mog.lock.json`) - Installed packages match the lockfile (version and SHA-256) - MCP server config validity in `.codex/config.toml` ## Listing installed packages ```sh mog ls ``` ```text 2 installed packages acme/react-testing-skill@1.2.0 codex mog_modules/react-testing-skill/ Installed: 1/15/2026 acme/github-mcp-server@1.0.0 codex (mcp) .codex/config.toml Installed: 1/16/2026 ``` ## Updating packages ```sh mog update --dry-run mog update ``` Updates respect semver: by default only patch and minor versions are applied. The lockfile is updated and the old files are replaced. ## Uninstalling ```sh mog uninstall acme/react-testing-skill ``` For skills, this removes the extracted files from `mog_modules/` and the lockfile entry. You'll need to remove any symlinks in `.agents/skills/` manually. For MCP servers, this removes the `mcp_servers` entry from `.codex/config.toml`. ## File layout summary After installing a mix of skills and MCP servers, your Codex project looks like this: ```text my-project/ .codex/ config.toml # MCP server configs (auto-managed) .agents/ skills/ react-testing-skill -> ../../mog_modules/react-testing-skill mog_modules/ react-testing-skill/ SKILL.md README.md mog.lock.json # Lockfile (commit to version control) ``` ## Tips - **Commit `mog.lock.json`** to version control so teammates get the same package versions. - **Don't commit secrets** in `.codex/config.toml` — use environment variable references instead of hardcoded API keys. - Codex supports **profiles** in `config.toml` for switching between named configurations. You can have different MCP server sets for different workflows. - Use `mog explain /` to preview a package's metadata, install path, and target compatibility before installing. - Use `mog install --preflight` to see exactly what would happen without making changes. --- # Cursor integration URL: https://mog.md/docs/cursor mog has first-class support for **Cursor**. The CLI auto-detects Cursor projects, installs packages to the right paths, and can wire skills into Cursor's rule system so your AI assistant picks them up automatically. ## How auto-detection works When you run `mog install` in a project directory, the CLI looks for a `.cursor/` directory. If it finds one, it sets the target to `cursor` and uses Cursor-specific install paths. You can always override with `--target cursor`. ## Installing skills Skills are SKILL.md packages that teach your AI assistant specific capabilities. ```sh mog install acme/react-testing-skill ``` This downloads the package, verifies its SHA-256 hash, and extracts it to: ```text .cursor/skills/react-testing-skill/ SKILL.md README.md ``` ### Wiring skills into Cursor rules Installing a skill drops the files into `.cursor/skills/`, but Cursor's agent needs a **rule** that points to the skill. Add `--wire` to create this automatically: ```sh mog install acme/react-testing-skill --wire ``` This creates a `.cursor/rules/react-testing-skill.mdc` file that references the skill, making it available to Cursor's AI assistant. The generated rule follows Cursor's MDC format and includes the skill's content so the agent can use it immediately. Without `--wire`, the CLI prints the rule content you'd need to add manually. ### Manual wiring If you prefer to wire skills yourself, create a `.cursor/rules/.mdc` file: ```markdown --- description: React testing patterns including RTL, Vitest, and MSW globs: alwaysApply: false --- Follow the instructions in .cursor/skills/react-testing-skill/SKILL.md ``` Set `alwaysApply: true` if you want the skill active on every prompt, or use `globs` to scope it to specific file patterns. ## Installing MCP servers MCP server packages are installed by writing configuration to `.cursor/mcp.json` — no file extraction needed. ```sh mog install acme/github-mcp-server ``` The CLI prompts for any required environment variables and writes the config: ```json title=".cursor/mcp.json" { "mcpServers": { "acme-github-mcp-server": { "command": "npx", "args": ["-y", "@acme/github-mcp-server@1.0.0"], "env": { "GITHUB_TOKEN": "ghp_your_token" } } } } ``` If `.cursor/mcp.json` already has other servers configured, mog merges the new entry without overwriting existing ones. ### Passing env vars non-interactively For CI or agent-driven installs, pass environment variables with `--env`: ```sh mog install acme/github-mcp-server --env GITHUB_TOKEN=ghp_xxx ``` Restart Cursor after installing an MCP server for it to be discovered. ## Installing rules Rule packages install directly to `.cursor/rules/`: ```sh mog install acme/typescript-standards ``` ```text .cursor/rules/typescript-standards.mdc ``` Rule packages with `type: rule` in their `mog.yaml` use a different default install path than skills, targeting the rules directory directly. ## Project health check Run `mog doctor` to verify your Cursor project is set up correctly: ```sh mog doctor ``` This checks: - CLI authentication status - Lockfile integrity (`mog.lock.json`) - Installed packages match the lockfile (version and SHA-256) - Wiring (whether installed skills have corresponding `.cursor/rules/*.mdc` entries) - MCP server config validity ## Listing installed packages ```sh mog ls ``` ```text 2 installed packages acme/react-testing-skill@1.2.0 cursor .cursor/skills/react-testing-skill/ Installed: 1/15/2026 acme/github-mcp-server@1.0.0 cursor (mcp) .cursor/mcp.json Installed: 1/16/2026 ``` ## Updating packages ```sh mog update --dry-run mog update ``` Updates respect semver: by default only patch and minor versions are applied. The lockfile is updated and the old files are replaced. ## Uninstalling ```sh mog uninstall acme/react-testing-skill ``` For skills, this removes the extracted files from `.cursor/skills/` and the lockfile entry. If `--wire` was used during install, the corresponding `.cursor/rules/*.mdc` file is also removed. For MCP servers, this removes the `mcpServers` entry from `.cursor/mcp.json`. ## File layout summary After installing a mix of skills, rules, and MCP servers, your Cursor project looks like this: ```text my-project/ .cursor/ mcp.json # MCP server configs (auto-managed) skills/ react-testing-skill/ SKILL.md README.md another-skill/ SKILL.md rules/ react-testing-skill.mdc # Wired skill reference (--wire) typescript-standards.mdc # Installed rule package my-custom-rule.mdc # Your own rules (untouched by mog) mog.lock.json # Lockfile (commit to version control) ``` ## Tips - **Commit `mog.lock.json`** to version control so teammates get the same package versions. - **Don't commit secrets** in `.cursor/mcp.json` — add it to `.gitignore` if your MCP configs contain API keys. Consider using environment variables referenced from your shell profile instead. - Use `mog explain /` to preview a package's metadata, install path, and target compatibility before installing. - Use `mog install --preflight` to see exactly what would happen without making changes. --- # Use cases URL: https://mog.md/docs/examples mog connects two worlds: a **package marketplace** where you install curated skills and MCP servers, and an **agent network** where agents discover and transact with live services. Here are common patterns for both. ## Equip a coding agent with best practices Install a skill that teaches your AI assistant how to write tests the way your team does: ```sh mog install acme/react-testing-skill --wire ``` The `--wire` flag ensures the skill is active in your editor immediately — no manual config. The agent now follows the patterns in the skill whenever it writes or reviews React tests. **Why this matters:** Instead of pasting guidelines into every prompt, the skill is always available as context. Update the package when your patterns change, and every developer on the team gets the new version via `mog update`. ## Standardize tooling across a team Use an organization to share a wallet and approved packages: ```sh mog org create my-team "My Team" mog org invite alice@company.io --role member mog org invite bob@company.io --role admin ``` Set up a spend policy so every team member's agent can install packages autonomously within limits: ```json { "maxPerPurchaseCents": 1000, "dailyLimitCents": 5000, "vendorAllowlist": ["trusted-vendor", "internal-tools"], "blockedTypes": [] } ``` New team members run `mog org switch my-team && mog install` and get the same packages, same versions, billed to the team wallet. ## Add an MCP server to your project Give your AI assistant access to external tools — a database, an API, a browser — by installing an MCP server package: ```sh mog install acme/postgres-mcp-server --env DATABASE_URL=postgres://... ``` One command. The CLI writes the correct config to `.cursor/mcp.json`, `.mcp.json`, `.gemini/settings.json`, `.codex/config.toml`, `~/.openclaw/openclaw.json` (`mcp.servers`), or Windsurf’s global MCP file depending on your target. Restart the editor (or OpenClaw gateway) and the tools are available. ## Build an autonomous purchasing agent An agent that discovers, evaluates, and installs skills on its own: ```typescript import { execSync } from 'child_process' const query = 'kubernetes deployment patterns' const searchResult = JSON.parse( execSync(`mog search "${query}" --target cursor --json`).toString() ) for (const pkg of searchResult.data.results) { if (pkg.price === 'free' || pkg.priceCents <= 500) { execSync(`mog install ${pkg.name} --auto-buy --max-price 500 --wire --json`) } } ``` With a spend policy attached to the token, the agent can never exceed its budget — even if the code has a bug. ## Connect an agent to live business services Use the SDK to let your agent discover and interact with services on the mog network: ```typescript import { MogClient } from '@mog/sdk' const mog = new MogClient({ token: process.env.MOG_TOKEN! }) // Find a verified service that can convert PDFs const { services } = await mog.discover({ tool: 'pdf_to_json', verified: true, sort: 'trusted', }) // Call the tool directly (metered, pay-per-call from wallet) const result = await mog.callTool(services[0].vendor, services[0].slug, { tool: 'pdf_to_json', input: { url: 'https://example.com/invoice.pdf' }, maxCostCents: 25, }) ``` The agent doesn't need to know the service's internal API. mog handles discovery, authentication, metering, and settlement. ## Multi-turn agent-to-business sessions For complex interactions — booking travel, negotiating quotes, completing multi-step workflows — open a session: ```typescript const { session } = await mog.openSession({ vendor: 'acme', slug: 'travel-agent', intent: 'book_travel', context: { destination: 'Tokyo', budgetCents: 150000 }, }) // Request a quote await mog.send(session.id, { type: 'quote.request', payload: { dates: '2026-04-01/2026-04-10', travelers: 2 }, }) // Wait for the vendor's response const { messages } = await mog.history(session.id) // If a checkout is required, handle it const { found, payload } = await mog.checkout(session.id) if (found) { console.log('Complete payment at:', payload.checkoutUrl) } ``` Sessions carry structured messages — intents, quotes, tool calls, checkout events, receipts — so both sides can parse and act on them programmatically. ## Keep CI in sync with the lockfile Add mog to your CI pipeline so every build has the right packages: ```yaml title=".github/workflows/setup.yml" - name: Install mog packages run: | npm install -g mogmd mog install --json env: MOG_TOKEN: ${{ secrets.MOG_TOKEN }} ``` The lockfile (`mog.lock.json`) pins exact versions and SHA-256 hashes. If someone adds a package locally and pushes the updated lockfile, CI installs the same thing. See [CI/CD & automation](/docs/ci-cd) for the full guide. ## Publish and monetize a skill Turn your expertise into a distributable package: ```yaml title="mog.yaml" name: my-org/nextjs-performance version: 1.0.0 type: skill description: Next.js performance optimization patterns — RSC, streaming, caching, image optimization. targets: - cursor - claude-code - codex - gemini-cli - windsurf - generic license: MIT ``` ```sh mog publish --dir ./my-skill --price 4.99 ``` The scan pipeline validates your package, and once approved it's live on the marketplace. Set your own price, and mog handles Stripe payouts via Connect. See [Selling on mog](/docs/selling) for the full seller guide. ## Distribute a premium MCP server Package a hosted MCP server with subscription billing: ```yaml title="mog.yaml" name: my-org/analytics-mcp version: 1.0.0 type: mcp description: Real-time analytics MCP server — query dashboards, generate reports, set alerts. targets: - cursor - claude-code - codex - gemini-cli - windsurf - generic mcp: transport: http url: "https://mcp.my-org.dev/analytics" headers: Authorization: "Bearer {env:ANALYTICS_API_KEY}" env: - name: ANALYTICS_API_KEY description: "API key from my-org.dev dashboard" required: true secret: true ``` Users subscribe monthly or annually, and the MCP config is installed with a single command. You handle the server; mog handles distribution, billing, and authentication. See [MCP Servers](/docs/mcp) and [Subscriptions](/docs/subscriptions) for details. --- # Gemini CLI integration URL: https://mog.md/docs/gemini-cli mog has first-class support for **Google Gemini CLI**. The CLI auto-detects Gemini CLI projects, installs skill packages to `.gemini/skills/`, and writes MCP server config directly to `.gemini/settings.json`. ## How auto-detection works When you run `mog install` in a project directory, the CLI looks for a `.gemini/` directory. If it finds one, it sets the target to `gemini-cli` and uses Gemini CLI-specific install paths. You can always override with `--target gemini-cli`. ## Installing skills Skills are SKILL.md packages that extend Gemini's capabilities within your project. ```sh mog install acme/react-testing-skill ``` This downloads the package, verifies its SHA-256 hash, and extracts it to: ```text .gemini/skills/react-testing-skill/ SKILL.md README.md ``` Gemini CLI picks up skills from the `.gemini/` directory in your project, making them available to the agent immediately. ## Installing MCP servers MCP server packages are installed by writing configuration to `.gemini/settings.json` — no file extraction needed. ```sh mog install acme/github-mcp-server ``` The CLI prompts for any required environment variables and writes the config: ```json title=".gemini/settings.json" { "mcpServers": { "acme-github-mcp-server": { "command": "npx", "args": ["-y", "@acme/github-mcp-server@1.0.0"], "env": { "GITHUB_TOKEN": "ghp_your_token" } } } } ``` If `.gemini/settings.json` already has other servers or settings configured, mog merges the new `mcpServers` entry without overwriting existing ones. ### User-level settings Gemini CLI also reads from `~/.gemini/settings.json` for user-level configuration. Project-level settings in `.gemini/settings.json` take precedence. Use `--target gemini-cli` with mog to install to the project scope. ### Passing env vars non-interactively For CI or agent-driven installs, pass environment variables with `--env`: ```sh mog install acme/github-mcp-server --env GITHUB_TOKEN=ghp_xxx ``` ### Supported transports Gemini CLI supports **stdio**, **SSE**, and **Streamable HTTP** transports for MCP servers. mog writes the correct config for each transport type based on the package's `mog.yaml` manifest. ## Project health check Run `mog doctor` to verify your Gemini CLI project is set up correctly: ```sh mog doctor ``` This checks: - CLI authentication status - Lockfile integrity (`mog.lock.json`) - Installed packages match the lockfile (version and SHA-256) - MCP server config validity in `.gemini/settings.json` ## Listing installed packages ```sh mog ls ``` ```text 2 installed packages acme/react-testing-skill@1.2.0 gemini-cli .gemini/skills/react-testing-skill/ Installed: 1/15/2026 acme/github-mcp-server@1.0.0 gemini-cli (mcp) .gemini/settings.json Installed: 1/16/2026 ``` ## Updating packages ```sh mog update --dry-run mog update ``` Updates respect semver: by default only patch and minor versions are applied. The lockfile is updated and the old files are replaced. ## Uninstalling ```sh mog uninstall acme/react-testing-skill ``` For skills, this removes the extracted files from `.gemini/skills/` and the lockfile entry. For MCP servers, this removes the `mcpServers` entry from `.gemini/settings.json`. ## File layout summary After installing a mix of skills and MCP servers, your Gemini CLI project looks like this: ```text my-project/ .gemini/ settings.json # MCP server configs (auto-managed) skills/ react-testing-skill/ SKILL.md README.md another-skill/ SKILL.md mog.lock.json # Lockfile (commit to version control) ``` ## Tips - **Commit `mog.lock.json`** to version control so teammates get the same package versions. - **Don't commit secrets** in `.gemini/settings.json` — add it to `.gitignore` if your MCP configs contain API keys. - You can use `gemini mcp add` to add MCP servers manually, or let mog handle it for packages from the marketplace. - Use `mog explain /` to preview a package's metadata, install path, and target compatibility before installing. - Use `mog install --preflight` to see exactly what would happen without making changes. --- # MCP Servers URL: https://mog.md/docs/mcp mog.md supports distributing **MCP (Model Context Protocol) servers** as a first-class package type. When you install an MCP server package, the CLI automatically writes the correct configuration to your AI tool — no manual JSON editing required. ## What is an MCP server? MCP servers are programs that extend AI agents with external tools, resources, and data sources. They communicate with AI tools via JSON-RPC 2.0 over stdio or HTTP. Common examples: GitHub integration, database access, Slack, Notion, custom APIs. ## Install an MCP server ```sh # Auto-detects your AI tool from the project directory mog install acme/github-mcp-server --auto-buy # Specify target explicitly mog install acme/github-mcp-server --target cursor # Pass required env vars non-interactively (for CI / headless) mog install acme/github-mcp-server --env GITHUB_TOKEN=ghp_xxx --auto-buy ``` On install the CLI: 1. Downloads and SHA-256 verifies the package archive 2. Prompts for any required environment variables (or reads them from `--env`) 3. Writes the server entry to the correct config file for your AI tool (`mcpServers` for most clients; OpenClaw uses nested `mcp.servers` in `~/.openclaw/openclaw.json`) 4. Updates `mog.lock.json` 5. Prints a reminder to restart your IDE (or restart the OpenClaw gateway for `openclaw` target) ## Supported clients and config files | Target | Config file written | Scope | |--------|---------------------|-------| | `cursor` | `.cursor/mcp.json` | project | | `claude-code` | `.mcp.json` | project | | `codex` | `.codex/config.toml` | project | | `gemini-cli` | `.gemini/settings.json` | project | | `windsurf` | `~/.codeium/windsurf/mcp_config.json` | global | | `openclaw` | `~/.openclaw/openclaw.json` (`mcp.servers`) | global | | `generic` | `.mcp.json` | project | Target is auto-detected from marker directories (`.cursor/`, `.claude/`, `.windsurf/`, `.gemini/`, `.codex/`, `.openclaw/`) in the current working directory. Use `--target` to override. ## Uninstall an MCP server ```sh mog uninstall acme/github-mcp-server ``` Removes the `mcpServers` entry from the client config and deletes the lockfile entry. Restart your IDE after uninstalling. ## Publishing an MCP server ### Package structure ```text your-mcp-server/ mog.yaml # Required README.md # Required CHANGELOG.md # Optional src/ index.ts # Your MCP server source package.json tsconfig.json ``` ### mog.yaml for MCP packages The `type` must be `mcp` and a `mcp` block is required: ```yaml title="mog.yaml" name: acme/github-mcp-server version: 1.0.0 type: mcp description: MCP server for GitHub — browse repos, create issues, manage PRs. targets: - cursor - claude-code - codex - gemini-cli - windsurf - generic mcp: transport: stdio # stdio (local subprocess) or http (remote URL) command: npx # executable (npx, node, python, python3, uvx, docker) args: - "-y" - "@acme/github-mcp-server@{version}" # {version} is replaced at install time env: - name: GITHUB_TOKEN description: "GitHub personal access token with repo scope" required: true secret: true - name: GITHUB_ORG description: "Default GitHub organization (optional)" required: false secret: false license: MIT readme: README.md ``` ### mcp field reference | Field | Type | Required | Description | |-------|------|----------|-------------| | `transport` | `stdio` \| `http` | Yes | How the AI tool connects to the server | | `command` | string | For stdio | Executable to run (`npx`, `node`, `python`, `python3`, `uvx`, `docker`) | | `args` | string[] | No | Arguments passed to `command`. Use `{version}` as a placeholder. | | `env` | EnvVar[] | No | Environment variables the server requires | | `url` | string | For http | Server URL (http transport only) | | `headers` | object | No | HTTP headers (http transport only, e.g. Authorization) | ### EnvVar fields | Field | Type | Default | Description | |-------|------|---------|-------------| | `name` | string | — | Env var name (uppercase, e.g. `GITHUB_TOKEN`) | | `description` | string | — | Shown to users at install time | | `required` | boolean | `true` | If true, install fails if value not provided | | `secret` | boolean | `false` | Marks as sensitive (shown as `****` in previews) | ### HTTP transport example For remotely-hosted MCP servers: ```yaml title="mog.yaml" mcp: transport: http url: "https://mcp.acme.dev/github" headers: Authorization: "Bearer {env:ACME_API_KEY}" env: - name: ACME_API_KEY description: "API key from acme.dev dashboard" required: true secret: true ``` ### Allowed commands For security, only these executables are accepted in `mcp.command`: `npx`, `node`, `python`, `python3`, `uvx`, `uv`, `docker`, `bunx`, `bun` Packages with other commands will fail the scan pipeline. ### Allowed file types MCP packages may include source code files in addition to Markdown content: `.ts`, `.tsx`, `.js`, `.mjs`, `.cjs`, `.py`, `.pyi`, `.toml`, `.lock`, `.sh`, `.env.example`, `.gitignore`, `.npmignore`, `.md`, `.yaml`, `.yml`, `.txt`, `.json`, `.png`, `.jpg`, `.svg` ### Publish ```sh mog publish --dir ./my-mcp-server --price 4.99 ``` The scan pipeline validates the `mcp` block, checks that `command` is in the approved list, and scans for shell injection patterns in `args`. ## What the installed config looks like After `mog install acme/github-mcp-server --target cursor`, the CLI writes to `.cursor/mcp.json`: ```json title=".cursor/mcp.json" { "mcpServers": { "acme-github-mcp-server": { "command": "npx", "args": ["-y", "@acme/github-mcp-server@1.0.0"], "env": { "GITHUB_TOKEN": "ghp_your_token" } } } } ``` For Codex (`.codex/config.toml`): ```toml title=".codex/config.toml" [mcp_servers.acme-github-mcp-server] command = "npx" args = ["-y", "@acme/github-mcp-server@1.0.0"] [mcp_servers.acme-github-mcp-server.env] GITHUB_TOKEN = "ghp_your_token" ``` Restart your IDE after any config change for the MCP server to be discovered. ## Lockfile tracking MCP installs are recorded in `mog.lock.json` with `installType: "mcp-config"`: ```json title="mog.lock.json (excerpt)" { "packages": { "acme/github-mcp-server": { "version": "1.0.0", "target": "cursor", "installType": "mcp-config", "mcpConfigPaths": ["/my-project/.cursor/mcp.json"], "archiveSha256": "a3f8c2d1..." } } } ``` ## Premium MCP servers Some MCP servers require a subscription for access. These are hosted, managed services — zero installation on your machine, and the vendor handles uptime and authentication. ### Subscribe ```sh # Subscribe with monthly billing (default) mog subscribe acme/premium-mcp # Subscribe with annual billing (save up to 20%) mog subscribe acme/premium-mcp --interval annual # Subscribe on behalf of an org mog subscribe acme/premium-mcp --org my-company ``` After subscribing, the CLI prints an `mog install` command to write the MCP config for your AI tool. ### Cancel ```sh # Cancel at end of current billing period (you keep access until then) mog unsubscribe acme/premium-mcp # Cancel immediately (access revoked now) mog unsubscribe acme/premium-mcp --immediate ``` ### What happens when a subscription expires? - **stdio MCPs**: The existing `mcpServers` config entry stays in place after expiry — your AI tool will still try to launch the process. The next `mog install` or `mog subscribe` will fail until you reactivate. This is intentional graceful degradation per the MCP stdio spec. - **HTTP MCPs**: Access may be revoked at the server level, depending on the vendor's implementation. ### Compliance mog follows the [MCP Protocol specification](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports) for both `stdio` and Streamable HTTP transports. Premium HTTP MCP servers use OAuth 2.1 (with PKCE) for authorization per the [MCP Authorization spec](https://modelcontextprotocol.io/specification/2025-11-25/basic/authorization). See [Subscriptions](/docs/subscriptions) for the full billing guide. --- # OpenClaw integration URL: https://mog.md/docs/openclaw [OpenClaw](https://openclaws.io/) loads skills from workspace `skills/` directories and configures MCP servers in `~/.openclaw/openclaw.json`. mog has a first-class **`openclaw`** target so installs land where OpenClaw expects them. ## Quickstart Prerequisites: [mog CLI installed and authenticated](/docs/quickstart). ### 1. Mark the project (auto-detection) Create an empty `.openclaw/` directory at your project root so `mog install` picks the OpenClaw target automatically: ```sh mkdir -p .openclaw ``` Or skip this and pass `--target openclaw` on every install. ### 2. Install a skill ```sh mog install acme/react-testing-skill ``` With `.openclaw/` present, the CLI uses target `openclaw` and extracts to `skills/react-testing-skill/` (workspace skills). OpenClaw discovers `SKILL.md` there — **no symlinks and no `--wire`**. Explicit target: ```sh mog install acme/react-testing-skill --target openclaw ``` ### 3. Verify and use ```sh openclaw skills list ``` Ask your agent to follow the skill, e.g. “write tests for this component using RTL and Vitest”. --- ## Installing skills Skills install to `skills/{slug}/` by default (OpenClaw workspace skills, high precedence). ```sh mog install acme/react-testing-skill --target openclaw ``` ### Override path (package authors) In `mog.yaml` you can override per target: ```yaml title="mog.yaml" install_map: openclaw: skills/{slug}/ ``` ### Global skills OpenClaw also loads from `~/.openclaw/skills/`. To copy a mog-installed skill globally after installing with `--target openclaw`: ```sh cp -r skills/react-testing-skill ~/.openclaw/skills/react-testing-skill ``` --- ## Configuring MCP servers MCP entries live under **`mcp.servers`** in `~/.openclaw/openclaw.json` (not a top-level `mcpServers` key). mog writes that shape for you: ```sh mog install acme/github-mcp-server --target openclaw ``` The CLI merges into `mcp.servers` and preserves the rest of your config. If your file is **JSON5** (comments, trailing commas), `JSON.parse` may fail — convert that section to strict JSON or add the server manually using the shape below. Example equivalent config: ```json title="~/.openclaw/openclaw.json" { "mcp": { "servers": { "acme-github-mcp-server": { "command": "npx", "args": ["-y", "@acme/github-mcp-server@1.0.0"], "transport": "stdio", "env": { "GITHUB_TOKEN": "ghp_your_token" } } } } } ``` Restart the gateway so the server is picked up: ```sh openclaw gateway restart ``` Verify: ```sh openclaw mcp list ``` ### HTTP/SSE transport ```json title="~/.openclaw/openclaw.json" { "mcp": { "servers": { "acme-remote-server": { "url": "https://mcp.acme.dev/sse", "headers": { "Authorization": "Bearer your_api_key" } } } } } ``` --- ## Skill configuration in openclaw.json Toggle skills or inject env via `skills` in `~/.openclaw/openclaw.json` (see [OpenClaw skills config](https://docs.openclaw.ai/tools/skills-config)): ```json5 title="~/.openclaw/openclaw.json" { "skills": { "entries": { "react-testing-skill": { "enabled": true } } } } ``` With API keys: ```json5 title="~/.openclaw/openclaw.json" { "skills": { "entries": { "react-testing-skill": { "enabled": true, "env": { "SOME_API_KEY": "your_key" } } } } } ``` --- ## Managing packages ```sh mog ls # list installed packages mog update --dry-run # check for updates mog update # apply updates mog uninstall acme/react-testing-skill # remove a package ``` After MCP changes, restart the gateway if tools do not appear. --- ## Project health check ```sh mog doctor ``` Checks auth, lockfile, install paths, and for OpenClaw file installs that `SKILL.md` exists under the recorded path. --- ## File layout summary ```text my-project/ .openclaw/ # optional — enables auto target detection skills/ react-testing-skill/ SKILL.md README.md another-skill/ SKILL.md mog.lock.json ``` MCP config is global: ```text ~/.openclaw/openclaw.json ``` --- ## Tips - **Commit `mog.lock.json`** for reproducible installs; commit `skills/` if you want skills in-repo. - **Auto-detection order** — if `.cursor/`, `.claude/`, etc. exist, those targets win before `.openclaw/`. Use `--target openclaw` when you need OpenClaw explicitly. - **Skills hot-reload** — with OpenClaw’s watcher enabled, updates under `skills/` are picked up on the next agent turn. - Use `mog explain /` and `mog install --preflight` before installing. - Browse [ClawHub](https://clawhub.com/) for OpenClaw-native skills, or [mog.md](https://mog.md) for cross-platform packages. --- # Organizations URL: https://mog.md/docs/organizations Organizations let teams share a wallet, spend policies, and private packages under a single account. Members purchase on behalf of the org wallet, and admins control spending with org-level policies. ## Create an organization ### Via CLI ```sh mog org create acme-team "Acme Team" ``` | Argument | Description | |----------|-------------| | `` | Org identifier — lowercase letters, numbers, hyphens, 2–39 chars | | `` | Display name | The creator becomes the org **owner**. ### Via API ```sh POST https://api.mog.md/v1/orgs Authorization: Bearer Content-Type: application/json { "slug": "acme-team", "name": "Acme Team" } ``` ## Switch org context Once an org is active, `mog buy` and `mog install --auto-buy` use the org wallet instead of your personal wallet. ```sh # Activate an org mog org switch acme-team # Check current context mog org whoami # Clear org context (revert to personal wallet) mog org switch none ``` ## Invite members **Requires admin or owner role.** ```sh mog org invite alice@acme.io --role member mog org invite bob@acme.io --role admin ``` Invitations are sent by email and expire after 7 days. ### Via API ```sh POST https://api.mog.md/v1/orgs/acme-team/members Authorization: Bearer Content-Type: application/json { "email": "alice@acme.io", "role": "member" } ``` ### Accept an invitation When a user receives an invitation email, they click the link to accept. Programmatically: ```sh POST https://api.mog.md/v1/orgs/accept-invite Authorization: Bearer Content-Type: application/json { "token": "invite-token-from-email" } ``` ## Roles | Role | Permissions | |------|-------------| | **owner** | Full control — manage members, policies, billing, packages, delete the org | | **admin** | Manage members (invite, remove, change roles), manage policies, manage packages | | **member** | Purchase using the org wallet, view org packages and policies | ### Change a member's role **Requires admin or owner role.** ```sh PATCH https://api.mog.md/v1/orgs/acme-team/members/:userId Authorization: Bearer Content-Type: application/json { "role": "admin" } ``` ### Remove a member ```sh DELETE https://api.mog.md/v1/orgs/acme-team/members/:userId Authorization: Bearer ``` ## Org wallet Each organization has its own wallet, separate from personal wallets. When the org context is active, all purchases are deducted from the org wallet. ```sh # View org wallet balance mog org wallet ``` ### Top up the org wallet Top up via the [Dashboard → Organizations](/dashboard) or the API: ```sh POST https://api.mog.md/v1/orgs/acme-team/wallet/top-up Authorization: Bearer Content-Type: application/json { "amountCents": 10000 } ``` ### Auto top-up Configure the org wallet to automatically refill when the balance drops below a threshold: ```sh PATCH https://api.mog.md/v1/orgs/acme-team/wallet/auto-top-up Authorization: Bearer Content-Type: application/json { "enabled": true, "thresholdCents": 2000, "topUpAmountCents": 10000 } ``` ### Transaction history ```sh GET https://api.mog.md/v1/orgs/acme-team/wallet/transactions Authorization: Bearer ``` ## Org spend policies Org-level spend policies override the individual token holder's personal policy when purchasing on behalf of the org. This lets admins define a single corporate policy without requiring each member to configure their own. ### Create an org policy **Requires admin or owner role.** ```sh POST https://api.mog.md/v1/orgs/acme-team/policies Authorization: Bearer Content-Type: application/json { "name": "Engineering team", "maxPerPurchaseCents": 1000, "dailyLimitCents": 5000, "monthlyLimitCents": 20000, "requireApprovalAboveCents": 500, "vendorAllowlist": ["trusted-org", "verified-vendor"], "blockedTypes": [], "active": true } ``` See [Spend policies](/docs/spend-policies) for full field reference and the approval workflow. ## Private packages Organizations can publish packages with restricted visibility: | Visibility | Who can access | |------------|---------------| | `public` | Anyone | | `org_only` | Only org members | | `private` | Only the publisher | Change visibility for an org package: ```sh PATCH https://api.mog.md/v1/orgs/acme-team/packages/:listingId Authorization: Bearer Content-Type: application/json { "visibility": "org_only" } ``` This is useful for internal skills and proprietary MCP servers that should only be available to your team. ## Common workflows ### Onboard a new team member 1. Invite them: `mog org invite new@member.io --role member` 2. They accept the invitation from their email 3. They switch to the org: `mog org switch acme-team` 4. They install packages — purchases use the org wallet automatically ### Set up an agent with org access 1. Generate an API token from the dashboard with `purchase` + `download` scopes 2. Attach the org's spend policy to the token 3. Set `MOG_TOKEN` in the agent's environment 4. The agent's purchases are billed to the org wallet and governed by the org policy ### Audit spending View the org's transaction history to see who purchased what: ```sh GET https://api.mog.md/v1/orgs/acme-team/wallet/transactions ``` Each transaction records the user, package, amount, and timestamp. --- # Package format URL: https://mog.md/docs/packages A mog package is a `.zip` archive containing a manifest, a README, and your content files. This page documents everything you need to create and publish a valid package. ## Directory structure ```text title="directory" your-package/ mog.yaml # Required — distribution manifest README.md # Required — displayed on the listing page CHANGELOG.md # Optional — version history content/ SKILL.md # Your main content (standard agentskills.io format) reference.md # Additional content files assets/ diagram.png # Images are supported ``` The archive can have any top-level directory name — the CLI strips it during extraction. The important thing is that `mog.yaml` and `README.md` exist at the root level of that top-level directory. ## mog.yaml schema `mog.yaml` is the package manifest. Every field is validated on upload. The scan worker will reject the release if `mog.yaml` is missing or invalid. ```yaml title="mog.yaml" name: acme/router-eval # vendor/slug — see naming rules below version: 1.0.0 # semver (major.minor.patch) type: skill # skill | rule | bundle | template description: > Comprehensive router evaluation patterns for React applications. Works with React Router v6 and TanStack Router. targets: - cursor - claude-code - generic install_map: # optional — override default install paths cursor: .cursor/skills/{slug}/ claude-code: .claude/skills/{slug}/ entrypoint: content/SKILL.md # optional — primary file for agent consumption requires: # optional — tool requirements tools: - react-router license: MIT # optional, defaults to MIT readme: README.md # optional — path to readme (default: README.md) ``` ### Field reference | Field | Type | Required | Description | |---|---|---|---| | `name` | string | Yes | Package identifier in `vendor/slug` format. Max 128 chars. | | `version` | string | Yes | Semantic version in `major.minor.patch` format. | | `type` | enum | Yes | `skill`, `rule`, `bundle`, `template`, or `mcp`. | | `description` | string | Yes | Short description. 1–1024 chars. Shown in search results. | | `targets` | array | Yes | At least one of: `cursor`, `claude-code`, `codex`, `gemini-cli`, `windsurf`, `openclaw`, `generic`. Use `generic` as the catch-all for any unlisted agent runtime. | | `install_map` | object | No | Override the default install path per target. Use `{slug}` as a placeholder. | | `entrypoint` | string | No | Path to the primary file, relative to the archive root. | | `requires.tools` | string[] | No | Tool names this package requires. Informational only in v0. | | `license` | string | No | SPDX license identifier. Defaults to `MIT`. | ### Naming rules - Format: `vendor/package-name` - Both parts: lowercase letters, numbers, and hyphens only - No dots, underscores, or uppercase letters - Examples: `acme/react-testing-skill`, `my-org/gpt4o-rules` ## Package types | Type | Description | |---|---| | `skill` | A SKILL.md file following the [agentskills.io specification](https://agentskills.io/specification). Teaches an agent a specific capability or workflow. | | `rule` | Configuration rules for an agent environment (e.g. Cursor rules, Claude instructions). | | `bundle` | A collection of multiple skills or rules packaged together. | | `template` | A starter template or scaffold that agents can use to initialize a project. | | `mcp` | A runnable MCP (Model Context Protocol) server. Installed by writing config to the client's MCP config (e.g. `mcpServers` in JSON clients, or `mcp.servers` for OpenClaw) rather than extracting files. See [MCP Servers](/docs/mcp). | ## Allowed file extensions (scan) The upload scan applies **different allowlists** by package type so content-only packages stay tight while MCP packages can include source and config files. ### `skill`, `rule`, `bundle`, `template` These types are content-focused. Allowed extensions include Markdown, YAML, JSON, plain text, and common images. Executable or unexpected extensions cause the scan to fail. Text-like files are scanned for accidental secrets; images are not. | Extension | Notes | |---|---| | `.md` | Scanned for secrets | | `.yaml`, `.yml` | Scanned for secrets | | `.json` | Scanned for secrets | | `.txt` | Scanned for secrets | | `.png`, `.jpg`, `.svg` | Images — not scanned for secrets | Extensions such as `.js`, `.sh`, `.py`, and `.exe` are **not** allowed for these package types. ### `mcp` MCP packages may include additional file types needed for runnable servers and tooling (for example TypeScript, JavaScript, Python, shell scripts, and lockfiles). See [MCP Servers](/docs/mcp#allowed-file-types) for the full MCP allowlist. ## Install targets and paths | Target | Detection | Default install path | |---|---|---| | `cursor` | `.cursor/` directory exists | `.cursor/skills/{slug}/` | | `claude-code` | `.claude/` directory exists | `.claude/skills/{slug}/` | | `codex` | `.codex/` directory exists | `mog_modules/{slug}/` | | `gemini-cli` | `.gemini/` directory exists | `.gemini/skills/{slug}/` | | `windsurf` | `.windsurf/` directory exists | `.windsurf/skills/{slug}/` | | `openclaw` | `.openclaw/` directory exists | `skills/{slug}/` | | `generic` | fallback | `mog_modules/{slug}/` | To override the path for a specific target: ```yaml title="mog.yaml" install_map: cursor: .cursor/rules/{slug}/ # install to rules/ instead of skills/ claude-code: .claude/memory/{slug}/ gemini-cli: .gemini/rules/{slug}/ ``` MCP packages (`type: mcp`) do not use `install_map` — their install location is always a client config file. See [MCP Servers](/docs/mcp) for the full `mcp` field reference. ## The lockfile (mog.lock.json) Every `mog install` or `mog update` writes to `mog.lock.json` in your project root. Commit this file to version control — it makes your installs fully reproducible. ```json title="mog.lock.json" { "version": 1, "lockfileVersion": "1.0.0", "generatedAt": "2026-01-15T10:00:00.000Z", "packages": { "acme/router-eval": { "name": "acme/router-eval", "vendor": "acme", "slug": "router-eval", "version": "1.0.0", "listingId": "uuid", "releaseId": "uuid", "entitlementId": "uuid", "installedAt": "2026-01-15T10:00:00.000Z", "target": "cursor", "installPath": "/my-project/.cursor/skills/router-eval/", "archiveSha256": "a3f8c2d1...", "updateChannel": "minor", "files": [ { "path": "content/SKILL.md", "sha256": "b1c9d2e3...", "size": 4096 } ] } } } ``` ## Creating a package 1. Create a directory with your content files 2. Write `mog.yaml` with the required fields 3. Write a helpful `README.md` (shown on the listing page) 4. Zip the directory: `zip -r my-skill-1.0.0.zip my-skill/` 5. Upload via the seller dashboard or the API 6. Wait for the scan to pass, then publish See the [seller guide](/docs/selling) for a full walkthrough including Stripe Connect setup and pricing. --- # Quickstart URL: https://mog.md/docs/quickstart ## Fastest path — one command from the terminal In your project directory, run: ```sh npx mogmd@latest setup ``` The CLI starts **device login** (same flow as `mog auth`): it prints a short code and **https://mog.md/device**, opens your browser when possible, then waits until you approve. After you’re signed in, it saves credentials, installs `mogmd` globally when you used `npx`, and creates `mog.lock.json` (same as `mog init`). Then try: ```sh mog search "react testing" ``` ## Shortcut — token from the website If you’re already signed in on **mog.md**, open **Install CLI** on the home page and copy the command — it includes a one-time `--token`: ```sh npx mogmd@latest setup --token "mog_setup_…" ``` This skips the device-code step and exchanges the token immediately. ## CI, agents, and non-interactive use Set **`MOG_TOKEN`** (from the [dashboard](/dashboard/settings) or a prior login) and run setup in JSON mode so the CLI never waits for a browser: ```sh export MOG_TOKEN="…" npx mogmd@latest setup --json ``` Without `MOG_TOKEN`, `mog setup --json` exits with an error — use a token or run setup interactively without `--json`. --- ## Manual install (global CLI) Prefer a global install or you’re not using `npx` for setup: ### Step 1 — Install the CLI mog is published to npm: ```sh npm install -g mogmd ``` Verify: ```sh mog --version # 0.1.6 ``` ### Step 2 — Authenticate mog uses a device code flow (RFC 8628) so you can sign in from any machine with a browser, even when the CLI runs headless. ```sh mog auth ``` The CLI prints a short code and URL: ```text title="terminal" To authenticate, visit: https://mog.md/device Enter code: XKCD-7Z4B Waiting for approval... ``` Open **mog.md/device** (the CLI tries to open it automatically), sign in with GitHub or Google, and enter the code. The CLI polls until approved: ```text title="terminal" ✓ Authenticated! ✓ You are now signed in to mog.md ``` Your token is stored in: - macOS / Linux: `~/.config/mog/credentials.json` - Windows: `%USERPROFILE%\.config\mog\credentials.json` If **`MOG_TOKEN`** is set, the CLI uses it for API calls (and `mog auth --status` reports it). Env takes precedence over the file. Check auth any time: ```sh mog auth --status ``` ### Step 3 — Initialize the project ```sh mog init ``` --- ## Step 1 — Search for a skill ```sh mog search "react testing" # 3 results # acme/react-testing-skill@1.2.0 Free # skill cursor, claude-code by Acme Corp ✓ # Comprehensive React testing patterns including RTL, Vitest, and MSW # Install with: mog install / ``` Filter your search: ```sh # Only free packages mog search --free # Only skills compatible with Cursor mog search --target cursor # Sort by newest mog search "testing" --sort recent # Get JSON output (for scripting) mog search "testing" --json ``` ## Step 2 — Install a package ### Free packages ```sh mog install acme/react-testing-skill ``` The CLI auto-detects your environment by looking for marker directories (`.cursor/`, `.claude/`, `.windsurf/`, `.gemini/`, `.codex/`, `.openclaw/`) and installs to the right location. Use `--target` to override. ### Wire the skill into your editor Installing drops files into the right directory, but your AI assistant still needs to be told about them. Add `--wire` to handle this automatically: ```sh mog install acme/react-testing-skill --wire ``` For Cursor, this creates a `.cursor/rules/{slug}.mdc` rule that points to the skill. For Claude Code, it appends a reference to `AGENTS.md`. Without `--wire`, the CLI prints the exact content you'd need to add manually. ### Paid packages For paid packages, purchase first then install: ```sh # Buy first mog buy acme/premium-skill # Then install mog install acme/premium-skill ``` Or combine both steps with `--auto-buy`: ```sh mog install acme/premium-skill --auto-buy ``` Add `--max-price ` to set a ceiling. If the package costs more, the purchase is blocked and an approval URL is returned: ```sh mog install acme/expensive-skill --auto-buy --max-price 500 ``` ### Preflight (dry run) See exactly what would happen before committing: ```sh mog install acme/react-testing-skill --preflight # Preflight plan: # Package: acme/react-testing-skill@1.2.0 # Target: cursor # Install to: /my-project/.cursor/skills/react-testing-skill/ # SHA-256: a3f8... # Price: Free ``` ## Step 3 — Manage installed packages ### List installed ```sh mog ls # 2 installed packages # acme/react-testing-skill@1.2.0 cursor # /my-project/.cursor/skills/react-testing-skill/ # Installed: 1/15/2026 ``` ### Update ```sh # Check for updates (dry run) mog update --dry-run # Apply updates (patch and minor only by default) mog update ``` ### Uninstall ```sh mog uninstall acme/react-testing-skill ``` ## Alternative path: Agent network quickstart If you're building an agent that needs to discover businesses and call tools programmatically — rather than installing packages — use the `@mog/sdk` instead of the CLI. ### Step 1 — Get a token Generate an API token from your [dashboard](/dashboard/settings) with `read` and `purchase` scopes, or authenticate via the device code flow and export `MOG_TOKEN`. ### Step 2 — Install the SDK ```sh npm install @mog/sdk ``` ### Step 3 — Discover and call a service ```typescript import { MogClient } from '@mog/sdk' const mog = new MogClient({ token: process.env.MOG_TOKEN! }) // Find a verified service that can search flights const { services } = await mog.discover({ tool: 'search_flights', verified: true, sort: 'trusted', }) // Call a tool directly (metered, deducted from wallet) const result = await mog.callTool('acme', 'travel-agent', { tool: 'search_flights', input: { origin: 'SFO', destination: 'NRT' }, maxCostCents: 10, }) ``` ### Step 4 — Open a session for multi-turn conversations ```typescript const { session } = await mog.openSession({ vendor: 'acme', slug: 'travel-agent', intent: 'book_travel', context: { destination: 'Tokyo', budgetCents: 150000 }, }) await mog.send(session.id, { type: 'quote.request', payload: { dates: '2026-04-01/2026-04-10' }, }) const { messages } = await mog.history(session.id) ``` See [Agent network](/docs/agent-network) for the full guide and [SDK reference](/docs/sdk) for every method. ## Useful commands ```sh mog doctor # check project health and wiring mog explain acme/my-skill # view package metadata and install paths mog ls --check-updates # list installed packages and check for updates ``` ## Next steps - [Full CLI reference](/docs/cli) — all commands, flags, and exit codes - [Agent network](/docs/agent-network) — discover, message, and pay any business - [SDK reference](/docs/sdk) — TypeScript client for the agent network API - [MCP servers](/docs/mcp) — install and auto-configure MCP server packages - [Spend policies](/docs/spend-policies) — set up safe autonomous purchasing for agents - [Package format](/docs/packages) — publish your own skills - [Selling on mog](/docs/selling) — monetize your work --- # @mog/sdk URL: https://mog.md/docs/sdk `@mog/sdk` is the official TypeScript client for the Mog agent network API. It wraps every REST endpoint into a typed, ergonomic interface that works from any Node.js, Deno, or Bun runtime. ## Install The SDK is a workspace package in the mog monorepo. For external use, import it directly: ```typescript import { MogClient } from '@mog/sdk' ``` ## Initialize ```typescript const mog = new MogClient({ token: process.env.MOG_TOKEN!, baseUrl: 'https://api.mog.md', // default }) ``` | Option | Type | Default | Description | |--------|------|---------|-------------| | `token` | `string` | — | Bearer token (JWT or API token) with appropriate scopes | | `baseUrl` | `string` | `https://api.mog.md` | API base URL | ## Discovery ### `discover(params?)` Search for live services with registered endpoints. ```typescript const { services, total } = await mog.discover({ tool: 'search_flights', protocol: 'mcp', settlement: 'stripe_mpp', verified: true, sort: 'trusted', // 'recent' | 'trusted' page: 1, per_page: 20, }) ``` | Parameter | Type | Description | |-----------|------|-------------| | `tool` | `string` | Filter by tool name (GIN index) | | `protocol` | `string` | `mcp`, `a2a`, `https`, `acp` | | `settlement` | `string` | `stripe_mpp`, `stripe_acp`, `free`, `wallet` | | `maxPerCallCents` | `number` | Maximum per-call cost | | `status` | `string` | `active`, `inactive`, `degraded` | | `verified` | `boolean` | Vendor identity verified | | `sort` | `string` | `recent` or `trusted` | ### `search(params?)` Full-text search across all packages and services. ```typescript const results = await mog.search({ q: 'react testing', type: 'skill', sort: 'popular', live: true, }) ``` ### `serviceCard(vendor, slug)` Fetch just the service card for a listing. ```typescript const card = await mog.serviceCard('acme', 'travel-agent') ``` ### `listingDetail(vendor, slug)` Full listing payload (readme, pricing, trust metrics, service card). ```typescript const detail = await mog.listingDetail('acme', 'travel-agent') ``` ## Sessions ### `openSession(body)` Open a session with a published service. Requires `purchase` scope. ```typescript const { session, listingId } = await mog.openSession({ vendor: 'acme', slug: 'travel-agent', intent: 'book_travel', context: { destination: 'Tokyo' }, settlementMethod: 'wallet', }) ``` | Field | Type | Description | |-------|------|-------------| | `vendor` | `string` | Vendor slug | | `slug` | `string` | Listing slug | | `intent` | `string?` | Initial intent (sends an `intent.open` message) | | `context` | `object?` | Arbitrary context attached to the session | | `settlementMethod` | `string?` | `stripe_mpp`, `stripe_acp`, `free`, `wallet` | ### `getSession(sessionId)` ```typescript const { session, role, listingSlug, vendorSlug } = await mog.getSession(id) // role is 'buyer' or 'vendor' ``` ### `send(sessionId, body)` Send a protocol message. Requires `purchase` scope. ```typescript const { sent, responses } = await mog.send(session.id, { type: 'quote.request', payload: { budgetCents: 150000 }, correlationId: 'my-corr-id', // optional }) ``` ### `history(sessionId, opts?)` Fetch message history for a session. ```typescript const { messages } = await mog.history(session.id, { limit: 100, after: lastMessageId, // cursor-based pagination }) ``` ### `subscribe(sessionId, opts?)` Poll for new messages. Returns an async generator. ```typescript const controller = new AbortController() for await (const { messages } of mog.subscribe(session.id, { pollMs: 2000, signal: controller.signal, })) { console.log('New state:', messages.length, 'messages') } ``` Pass `signal` from an `AbortController` to stop polling. ### `closeSession(sessionId)` ```typescript await mog.closeSession(session.id) ``` ## Tool calls (metered) ### `callTool(vendor, slug, body)` Execute a tool directly. Mog deducts the per-call cost from your wallet. ```typescript const result = await mog.callTool('acme', 'pdf-agent', { tool: 'pdf_to_json', input: { url: 'https://example.com/doc.pdf' }, maxCostCents: 10, sessionId: session.id, // optional: attach to an existing session }) ``` ## Checkout ### `checkout(sessionId)` Scans message history for a `checkout.required` message and returns its payload. ```typescript const { found, payload } = await mog.checkout(session.id) if (found) { // payload.checkoutUrl or payload.clientSecret } ``` ## Wallet ### `wallet()` Get your wallet balance and auto top-up settings. ```typescript const wallet = await mog.wallet() ``` ## Vendor methods These require a token with `sell` scope. ### `vendorInbox(opts?)` Open sessions targeting your listings. ```typescript const { sessions } = await mog.vendorInbox({ limit: 50 }) ``` ### `vendorServiceHealth()` Latest health probe per listing. ```typescript const { listings } = await mog.vendorServiceHealth() for (const l of listings) { console.log(l.slug, l.serviceStatus, l.latestCheck?.status) } ``` ## Error handling All methods throw `MogApiError` on non-2xx responses: ```typescript import { MogApiError } from '@mog/sdk' try { await mog.callTool('acme', 'tool', { tool: 'x', input: {} }) } catch (e) { if (e instanceof MogApiError) { console.error(e.status, e.message, e.body) } } ``` ## Token scopes | Scope | Required for | |-------|-------------| | `read` | `search`, `serviceCard`, `listingDetail`, `getSession`, `history`, `wallet` | | `purchase` | `openSession`, `send`, `callTool`, `closeSession` | | `sell` | `vendorInbox`, `vendorServiceHealth` | --- # Security model URL: https://mog.md/docs/security mog distributes code that runs inside AI agent environments. We take package security seriously. This page describes every layer of protection. ## Upload scan pipeline Every uploaded release is processed asynchronously before it can be published. The scan runs in an isolated worker process. Releases are validated for required structure and manifest correctness, file types are checked against rules that depend on package type (see [Package format](/docs/packages#allowed-file-extensions-scan)), artifacts are fingerprinted for integrity, and text content is analyzed for accidental secret exposure and other policy violations. Scan outcomes are reflected in the release record and seller dashboard. We do not publish exact detection rules or thresholds publicly — doing so would make them easier to circumvent. If a problem is found, the seller is notified with an appropriate category (not the raw matched content). ## SHA-256 integrity verification Every package archive is SHA-256 hashed on upload and the hash is stored immutably in the release record. When a user installs a package, the CLI: 1. Requests a signed download URL from the API (requires an active entitlement) 2. Downloads the archive 3. Computes the SHA-256 of the downloaded bytes 4. Compares against the hash stored in the release record 5. Aborts with an error if they don't match This prevents tampering in transit. Even if an attacker intercepted the download, the hash mismatch would be caught before any files are written to disk. ## Signed download URLs Package archives are stored in private cloud storage with no public access. Download URLs are cryptographically signed with a 5-minute expiry. To get a download URL, a request must: 1. Present a valid Bearer token with the `download` scope 2. Have an active (non-revoked) entitlement for the listing ## Path traversal protection During installation, each file path from the zip archive is resolved against the install base directory. If the resolved path escapes the base directory (a "path traversal" attempt), the install fails immediately: ```text title="error" Path traversal detected: ../../etc/passwd ``` ## Atomic lockfile writes If the lockfile write fails after extraction, the extracted files are removed to leave a clean state. This prevents a partially installed package from being treated as installed. ## Authentication security - **Device code flow (RFC 8628):** No passwords. Authentication happens in a browser with your OAuth provider (GitHub or Google). The CLI never sees your OAuth credentials. - **Tokens:** API tokens are hashed (SHA-256) before storage. The plaintext token is only returned once, at issuance time. - **Spend policies:** Enforced server-side, not just in the CLI. See [Spend policies](/docs/spend-policies). - **OAuth state signing:** The GitHub OAuth state parameter is HMAC-signed to prevent CSRF and state-fixation attacks during the OAuth callback flow. - **Hashed invitation tokens:** Organization invitation tokens are hashed before storage, preventing token extraction from database access alone. ## Backend-for-frontend (BFF) pattern The web application uses a BFF architecture where API tokens are never exposed to the browser. When you sign in via the web, the server issues an internal token on your behalf and proxies all API requests server-side. This means: - Your API token never appears in browser JavaScript, cookies, or local storage - All authenticated web requests flow through server-side proxy routes - Even if an XSS vulnerability were exploited, no API token would be exfiltrable from the client ## Audit logging Authentication events are logged server-side for security monitoring and incident response: - Sign-in events (provider, user, timestamp) - Token issuance and revocation - Failed authentication attempts - Device code flow approvals Audit logs are retained for compliance and are not accessible via the public API. ## Rate limiting All API endpoints are rate-limited using a tiered system. Stricter tiers apply to authentication, financial operations, and uploads; public catalog endpoints use moderate limits; a global baseline applies per IP. When a limit is exceeded, the API returns HTTP `429` with a `Retry-After` header. Exact limits may be adjusted without notice and are not published per route. ## Financial operation safety - **Idempotency keys:** Wallet top-up and payment operations use idempotency keys to prevent duplicate charges from retried requests. - **Price range validation:** Payment intents enforce minimum and maximum amount constraints server-side. - **Transfer tracking:** Vendor payouts track transfer status with automatic retry for transient failures. ## Transport security All API and web traffic is served over TLS 1.2 or higher. HTTP Strict Transport Security (HSTS) is enforced on all production domains, preventing downgrade attacks. ## Web application security The web application sets comprehensive security headers on all responses: - **Content Security Policy (CSP):** Strict policy that blocks inline scripts and restricts resource origins. Only allowlisted domains (Stripe, analytics) can load external scripts. - **X-Content-Type-Options:** `nosniff` — prevents MIME type sniffing - **X-Frame-Options:** `DENY` — prevents clickjacking via iframe embedding - **Referrer-Policy:** Restricts referrer information sent to external sites State-changing API endpoints are protected against CSRF. All user-supplied content is escaped before rendering. ## Account deletion and data privacy Users can delete their account via `DELETE /v1/users/me` or from the dashboard. Account deletion: - Soft-deletes the user record (preserving referential integrity for orders and reviews) - Anonymizes all personally identifiable information (name, email, avatar) - Revokes all active API tokens immediately - Is irreversible — deleted accounts cannot be recovered This complies with GDPR right-to-erasure requirements. Anonymized records are retained for financial audit trails. ## Data retention Expired and unused data is cleaned up automatically: - Expired device authorization codes are purged - Stale session data is rotated - Anonymized records are retained only as long as required for financial compliance ## Dependency management Dependencies across the API, web app, and CLI are monitored for known vulnerabilities. Critical vulnerabilities in direct dependencies are patched within 7 days of disclosure. ## Data at rest The database and all package storage use encryption at rest. Sensitive fields (API token hashes, credentials) are never stored in plaintext. ## Reporting security issues If you discover a security vulnerability, please report it privately by emailing [security@mog.md](mailto:security@mog.md). Do not open a public GitHub issue for security vulnerabilities. --- # Selling on mog URL: https://mog.md/docs/selling Anyone can sell on mog.md. You set the price, we handle payments via Stripe Connect, and you get paid. mog takes a 10% platform fee on paid packages; free packages have no fees. In addition to selling downloadable packages, you can register **live service endpoints** — turning your listing into a callable API that agents can discover and invoke through mog. See [Live services](/docs/services) for the full guide. ## Overview 1. **Sign in** to mog.md with GitHub or Google 2. **Create a vendor profile** — choose your vendor slug (used in package names) 3. **Connect Stripe** — complete Stripe Connect onboarding to receive payouts 4. **Upload a release** — zip your package and upload it 5. **Wait for the scan** — automated security scan runs (usually under 30s) 6. **Publish** — make your listing live in the marketplace ## Creating a vendor profile Visit the Seller Dashboard and create your vendor profile. Your vendor slug becomes the namespace for all your packages: ```sh # If your vendor slug is "acme": acme/router-eval acme/react-testing-skill acme/typescript-rules ``` ### Vendor slug rules - 2–32 characters - Lowercase letters, numbers, and hyphens only - Must be unique across the marketplace - Cannot be changed after creation (choose carefully) ## Stripe Connect onboarding To receive payouts for paid packages, you need to complete Stripe Connect onboarding. From the seller dashboard, click **Connect Stripe**. You'll be redirected to Stripe to provide your business or personal details. Stripe handles: - Identity verification (KYC) - Bank account or debit card for payouts - Tax forms (1099 in the US) ## Creating a package ```sh # 1. Create your package directory mkdir my-skill && cd my-skill # 2. Write your content cat > content/SKILL.md << 'EOF' # My Skill ... EOF # 3. Write the manifest cat > mog.yaml << 'EOF' name: acme/my-skill version: 1.0.0 type: skill description: "A helpful skill for..." targets: - cursor - claude-code license: MIT EOF # 4. Write a README (shown on listing page) echo "# My Skill\n\nDescription..." > README.md # 5. Zip it up cd .. zip -r my-skill-1.0.0.zip my-skill/ ``` ## Uploading a release From the Seller Dashboard, drag and drop your `.zip` file, or use the API directly: ```sh curl -X POST https://api.mog.md/v1/vendor/releases \ -H "Authorization: Bearer " \ -F "archive=@my-skill-1.0.0.zip" ``` ## The scan pipeline | Status | Meaning | |---|---| | `pending` | Upload received, scan not yet started | | `scanning` | Scan in progress | | `passed` | Scan passed — release can be published | | `failed` | Scan found issues — details shown in dashboard | ## Publishing a release Once the scan passes, publish via the dashboard or via API: ```sh curl -X PATCH https://api.mog.md/v1/vendor/releases//publish \ -H "Authorization: Bearer " ``` ## Updating listing metadata ```sh curl -X PATCH https://api.mog.md/v1/vendor/listings/ \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "title": "My Updated Skill Title", "description": "Updated description...", "tags": ["react", "testing", "rtl"], "priceCents": 500, "readmeMd": "# My Skill\n\nUpdated README content..." }' ``` ## Pricing | priceCents | Display price | |---|---| | `0` | Free | | `99` | $0.99 | | `500` | $5.00 | | `1000` | $10.00 | | `4900` | $49.00 | mog charges a **10% platform fee**. A $5.00 package earns you $4.50 per sale. ## Analytics ```sh GET https://api.mog.md/v1/vendor/analytics Authorization: Bearer ``` ## Versioning best practices - **Patch** (1.0.0 → 1.0.1): Bug fixes, typos - **Minor** (1.0.0 → 1.1.0): New sections, expanded content — backwards compatible - **Major** (1.0.0 → 2.0.0): Breaking changes, major rewrites ## FAQs ### Can I publish free packages without connecting Stripe? Yes. Stripe Connect is only required for paid packages. ### Can I change my price after publishing? Yes. You can update `priceCents` at any time. The new price applies immediately to new purchases; existing entitlements are not affected. ### Can I take a package down? Yes. You can change a listing's status to `unlisted` to hide it from search while keeping it accessible to existing buyers. ### What happens if my scan fails? The release stays in `failed` status and cannot be published. Fix the issues and upload a new release. ## Subscription pricing for MCP servers For premium MCP servers, you can enable subscription billing — monthly, annual, or both. Subscribers are billed automatically, and payouts arrive in your Stripe account after each successful invoice. ### Enable subscription pricing In the Seller Dashboard, open a listing's edit form and select a **Pricing model**: - **One-time**: Single payment, permanent access (default for all package types) - **Monthly subscription**: Recurring monthly billing - **Annual subscription**: Recurring annual billing (typically offered at a discount) You can set both monthly and annual prices — buyers choose their preferred interval when subscribing. ### Minimum and maximum prices | Interval | Minimum | Maximum | |----------|---------|---------| | Monthly | $0.99 | $500.00 | | Annual | $0.99 | $5,000.00 | ### Platform fees | Transaction type | mog fee | |-----------------|---------| | One-time purchase | **10%** | | Monthly subscription | **15%** | | Annual subscription | **15%** | Fees are automatically deducted from each payment via Stripe Connect destination charges. You receive 85% of every subscription invoice, paid out automatically to your connected Stripe account. ### How payouts work mog uses [Stripe Connect destination charges](https://docs.stripe.com/connect/destination-charges). When a subscriber pays, Stripe splits the funds automatically: 1. The full charge appears on the subscriber's card statement as `mog.md` 2. After each successful invoice, Stripe transfers 85% to your connected Stripe account 3. mog retains 15% as a platform fee ### Subscription MRR dashboard The Seller Dashboard shows your **Monthly Recurring Revenue (MRR)** — the sum of all active subscription amounts converted to monthly equivalents, after the 15% fee. ### How can I change subscription prices? Existing Stripe Prices are immutable — subscribers keep their current price. To offer a new price, update the listing price in the dashboard. New subscribers will see the updated price; existing subscribers are unaffected. ### Can I offer both one-time and subscription pricing? Not on the same listing. A listing has a single `pricingModel`. Create separate listings if you want both. ### What happens if I delist a subscription listing? Existing subscriptions continue until canceled. New subscribers cannot subscribe. You can cancel subscriptions in bulk via the Stripe dashboard. ## Registering a live service Beyond selling downloadable packages, you can register a **live service endpoint** on any listing. This turns your listing into a callable API that agents can discover, open sessions with, and invoke tools on — all through mog. ### Quick setup 1. **From the dashboard:** Go to **Agent network → Service registration**, pick a listing, and fill in the endpoint URL, protocol, transport, and pricing. 2. **From the API:** `PATCH /v1/vendor/listings/:id` with `serviceEndpoint`, `serviceProtocol`, `serviceTransport`, `pricingModel: "metered"`, and `perCallCents`. ### What happens next - Mog starts **health-checking** your endpoint automatically (every 5–15 minutes) - Your listing appears in `GET /v1/services` with a `serviceCard` block - Agents can open sessions (`POST /v1/network/sessions`) or call tools directly (`POST /v1/services/:vendor/:slug/call`) - Every metered call deducts from the caller's wallet and creates a usage record ### Manage your services The **Agent network** section of the dashboard gives you: - **Inbox** — open sessions targeting your services - **Session logs** — full message history for any session - **Service health** — latest probe results, uptime, and errors - **Service registration** — endpoint, protocol, pricing, capabilities, and agent card See [Live services](/docs/services) for the full reference. --- # Live services URL: https://mog.md/docs/services Live services turn mog listings into callable API endpoints. Instead of just distributing a package, you register a live URL that agents can invoke through mog's relay — with automatic metering, health monitoring, and trust scoring. ## How it works 1. **Publish a listing** as usual (or reuse an existing one) 2. **Register a service endpoint** — the URL where your MCP server or API is running 3. **Set a per-call price** — mog deducts from the caller's wallet on every invocation 4. **Mog probes your endpoint** automatically and computes trust metrics Agents discover your service via `GET /v1/services` or `mog.discover()`, open sessions, and call your tools — all through mog. ## Registering a service ### From the dashboard Go to **Agent network → Service registration** in your dashboard. Select a listing and fill in: - **Service endpoint URL** — e.g. `https://api.acme.com/mcp` - **Protocol** — `mcp`, `a2a`, `https`, or `acp` - **Transport** — `streamable_http`, `sse`, `stdio`, or `jsonrpc` - **Pricing model** — `metered` for pay-per-call - **Per-call price** — cost in cents per invocation - **Settlement methods** — which payment methods you accept - **Capabilities** — JSON describing what your service can do - **Agent card** — optional public metadata for agent discovery ### From the API ```sh curl -X PATCH https://api.mog.md/v1/vendor/listings/ \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "serviceEndpoint": "https://api.acme.com/mcp", "serviceProtocol": "mcp", "serviceTransport": "streamable_http", "pricingModel": "metered", "perCallCents": 5, "settlementMethods": ["wallet", "stripe_mpp"], "capabilities": { "search_flights": "Search for flights by route and date", "book_flight": "Book a flight and return confirmation" } }' ``` ## How agents call your service ### Direct tool call (metered) ```typescript const result = await mog.callTool('acme', 'travel-agent', { tool: 'search_flights', input: { origin: 'SFO', destination: 'NRT', date: '2026-04-01' }, maxCostCents: 10, }) ``` When this happens: 1. Mog resolves the service card for `acme/travel-agent` 2. Validates the caller's wallet balance against the per-call cost 3. Translates the request into the correct protocol (e.g. MCP `tools/call`) 4. Sends the request to your endpoint 5. Records a `usage_record` with timing, cost, and success/failure 6. Deducts from the caller's wallet and creates a `metered_usage` transaction 7. Returns the tool result to the caller ### Session-based calls Agents can also call tools within a session: ```typescript const { session } = await mog.openSession({ vendor: 'acme', slug: 'travel-agent', intent: 'book_travel', }) await mog.send(session.id, { type: 'tool.call', payload: { tool: 'search_flights', input: { destination: 'NRT' } }, }) ``` ## Pricing | Field | Description | |-------|-------------| | `pricingModel` | Set to `metered` for pay-per-call | | `perCallCents` | Cost per invocation in cents (e.g. `5` = $0.05) | Callers can set `maxCostCents` to cap what they're willing to pay. If the listing's per-call price exceeds the cap, the call is rejected with HTTP 422. ## Health monitoring Once you register an endpoint, mog automatically probes it every 5–15 minutes: - **MCP endpoints** — sends a `tools/list` JSON-RPC request and checks for a valid response - **HTTPS endpoints** — sends a GET and checks for 2xx - **ACP endpoints** — sends a GET and checks for 2xx or 405 Probe results determine your service status: | Status | Condition | |--------|-----------| | `active` | ≥3 of the last 5 probes healthy | | `degraded` | 1–2 of the last 5 probes healthy | | `inactive` | 0 healthy probes, or no endpoint registered | ## Trust metrics Mog computes rolling trust metrics hourly from your usage records and health probes: - **Total calls** — lifetime invocations - **Success rate** — % of calls that returned without error - **Average response time** — mean latency in ms - **Uptime %** — percentage of healthy probes over the last 7 days These metrics appear in search results, listing detail, and the SDK's `discover()` response. Agents can filter and sort by trust. ## Endpoint requirements Your service endpoint must: - Accept HTTP POST requests - Respond within 30 seconds (mog's relay timeout) - Return valid JSON - For MCP: support the [Streamable HTTP transport](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http) ## Dashboard The **Agent network** section of the vendor dashboard shows: - **Inbox** — open sessions from buyer agents - **Session logs** — full message history per session - **Service health** — latest probes, uptime, and errors - **Service registration** — manage endpoint, protocol, pricing ## Next steps - [Agent network overview](/docs/agent-network) - [SDK reference](/docs/sdk) — `callTool`, `discover`, `openSession` - [Selling on mog](/docs/selling) — publish packages and register services - [API reference](/docs/api) — full REST endpoint docs --- # Spend policies URL: https://mog.md/docs/spend-policies Spend policies let you define exactly how much an agent token is allowed to spend autonomously — with per-purchase limits, daily and monthly caps, vendor allowlists, and blocked package types. When a purchase would exceed a policy limit, the API returns HTTP 402 with an `approvalUrl` for human review. ## Why spend policies? mog is designed for autonomous agents. An agent running inside Cursor or Claude Code can call `mog install --auto-buy` without any human in the loop. Spend policies make this safe by letting you define guardrails that are enforced server-side — not just checked by CLI flags. Even if a compromised agent tries to override the CLI flags, the server will reject purchases that violate the policy attached to the token. ## Policy fields | Field | Type | Default | Description | |---|---|---|---| | `maxPerPurchaseCents` | number | `1000` | Maximum price in cents for a single purchase. Packages above this price trigger an approval flow. | | `dailyLimitCents` | number | `5000` | Maximum total spend per calendar day. | | `monthlyLimitCents` | number | `20000` | Maximum total spend per calendar month. | | `requireApprovalAboveCents` | number | `500` | Any single purchase above this price requires explicit human approval, even if it's within the `maxPerPurchaseCents` limit. | | `vendorAllowlist` | string[] | `[]` | If non-empty, only vendors in this list can be purchased autonomously. | | `blockedTypes` | string[] | `[]` | Package types that are always blocked. E.g. `["bundle"]` to prevent purchasing bundles. | | `active` | boolean | `true` | Whether this policy is currently enforced. | ## Creating a policy Policies are managed from your account dashboard. You can create multiple policies with different names, then attach specific policies to specific API tokens. ### Example: conservative agent policy ```json { "name": "CI agent", "maxPerPurchaseCents": 500, "dailyLimitCents": 2000, "monthlyLimitCents": 10000, "requireApprovalAboveCents": 100, "vendorAllowlist": ["trusted-org", "verified-vendor"], "blockedTypes": ["bundle", "template"], "active": true } ``` With this policy, the agent token can only: - Purchase packages from `trusted-org` or `verified-vendor` - Buy packages costing $1.00 or less without approval - Spend up to $20.00 per day and $100.00 per month - Never purchase bundles or templates ### Example: open policy for personal use ```json { "name": "personal", "maxPerPurchaseCents": 5000, "dailyLimitCents": 20000, "monthlyLimitCents": 100000, "requireApprovalAboveCents": 2500, "vendorAllowlist": [], "blockedTypes": [], "active": true } ``` ## Attaching a policy to a token When you generate an API token (or during the device code flow), you can attach a spend policy. The policy is then enforced for every purchase made with that token. A token without an attached policy has no spend restrictions — it can purchase any published listing. Use this for personal tokens only; always attach a policy to tokens used by autonomous agents. ## The approval flow When a purchase is blocked by policy, the API returns HTTP 402 with an `approvalUrl`: ```json // HTTP 402 { "status": "approval_required", "approvalUrl": "https://mog.md/purchases/approve?listing=uuid", "reason": "Price (1500¢) exceeds your policy limit (1000¢)" } ``` The CLI exits with code `2` and prints the URL. In `--json` mode: ```json { "ok": false, "command": "install", "error": "Price (1500¢) exceeds your policy limit (1000¢)", "approvalUrl": "https://mog.md/purchases/approve?listing=uuid" } ``` ### Human approval workflow 1. Agent runs `mog install vendor/pkg --auto-buy` 2. Purchase blocked → CLI exits with code 2, prints `approvalUrl` 3. Agent notifies a human (e.g. posts the URL to Slack, creates a GitHub issue) 4. Human visits the `approvalUrl`, reviews the package, and approves 5. Agent re-runs the install command (the purchase now succeeds) ## Organization spend policies Organizations can have their own spend policies that apply automatically when any member purchases on behalf of the org wallet. **Key behavior:** The org policy takes priority over the API token holder's personal policy. If a purchase is made with an `orgSlug` set (or via `mog org switch`), the org's spend policy is used instead of the token's attached policy. Create and manage org policies via `POST /v1/orgs/:slug/policies` (admin or owner only). The policy fields are identical to personal spend policies. If no org policy is configured, the individual token holder's policy applies. This lets org admins define a single corporate spend policy without requiring each member to configure their own token. ## Metered service calls Spend policies also govern wallet deductions from metered service calls (`mog.callTool()` or `POST /v1/services/:vendor/:slug/call`). When an agent calls a metered tool, the per-call cost is deducted from the wallet — and daily/monthly caps are checked against the cumulative wallet spend, including both package purchases and metered usage. The `vendorAllowlist` applies to metered calls as well: if the tool's vendor is not in the allowlist, the call is rejected. ## Policy enforcement logic The server checks policies in this order on every purchase and metered call: 1. **Blocked types:** If `listing.type` is in `policy.blockedTypes` → 402 2. **Vendor allowlist:** If `vendorAllowlist` is non-empty and `listing.vendorSlug` is not in the list → 402 3. **Price ceiling:** If `listing.priceCents` exceeds the effective max → 402 ## Using spend policies in agent code Here's how a well-behaved agent handles the approval flow: ```typescript import { execSync } from 'child_process' function installSkill(pkg: string, maxPriceCents: number) { try { const result = JSON.parse( execSync(`mog install ${pkg} --auto-buy --max-price ${maxPriceCents} --json`).toString() ) console.log('Installed:', result.data.version) } catch (err: any) { const output = JSON.parse(err.stdout?.toString() ?? '{}') if (output.approvalUrl) { // Signal to the human in the loop notifyHuman(`mog install blocked. Approve at: ${output.approvalUrl}`) } else { throw err } } } ``` --- # Subscriptions URL: https://mog.md/docs/subscriptions Some MCP servers on mog.md are **premium** — they require a subscription for access. Subscriptions are billed monthly or annually via Stripe, and you can cancel anytime. ## Subscribe to a premium MCP server ### Via CLI ```sh # Subscribe with monthly billing mog subscribe vendor/mcp-server # Subscribe with annual billing (usually cheaper) mog subscribe vendor/mcp-server --interval annual # Subscribe on behalf of an organization mog subscribe vendor/mcp-server --org my-org # Non-interactive (skip confirmation prompt) mog subscribe vendor/mcp-server --auto ``` After a successful subscription, follow the on-screen instructions to install the MCP server config with `mog install`. ### Via the web 1. Browse to the listing page (e.g. `mog.md/packages/vendor/mcp-server`) 2. Select **Monthly** or **Annual** billing 3. Click **Subscribe** 4. Complete payment via the Stripe checkout 5. Use the **Install** button or run `mog install vendor/mcp-server` ## Cancel a subscription ### Via CLI ```sh # Cancel gracefully — access continues until the end of the current billing period mog unsubscribe vendor/mcp-server # Cancel immediately — access is revoked now mog unsubscribe vendor/mcp-server --immediate ``` ### Via the web 1. Go to [Dashboard → Subscriptions](/dashboard/subscriptions) 2. Click **Cancel** on the subscription 3. Your access continues until the end of the current period 4. To undo, click **Resume** before the period ends ## Resume a canceled subscription If you've scheduled a cancellation but changed your mind: ```sh # Resume from CLI (re-subscribe) mog subscribe vendor/mcp-server ``` Or click **Resume** in the Subscriptions dashboard before the period ends. ## Payment failure handling If a payment fails on renewal: 1. Your subscription moves to `past_due` status 2. You **keep access** until the end of your current billing period (`expiresAt`) 3. Stripe automatically retries payment up to 4 times over ~3 weeks (Smart Retries) 4. If all retries fail, Stripe cancels the subscription and access is revoked 5. Update your payment method in the [Stripe Customer Portal](/dashboard/billing) to avoid losing access ## Manage payment methods Click **Manage payment methods** in [Dashboard → Subscriptions](/dashboard/subscriptions) to open the Stripe Customer Portal where you can: - Add or replace payment methods - View upcoming invoices - Download past receipts ## Subscription statuses | Status | Meaning | |--------|---------| | `active` | Paid and access granted | | `trialing` | In free trial period (if offered) | | `past_due` | Payment failed, retrying — access still active until period end | | `incomplete` | Awaiting payment confirmation (SCA / 3D Secure) | | `paused` | Manually paused by vendor | | `canceled` | Subscription ended, access revoked | ## Spend policies Subscriptions respect your [spend policies](/docs/spend-policies). If a subscription price exceeds your policy limit, you'll receive an `approval_required` response. Contact your account admin to increase your limit or whitelist the vendor. ## For AI agents Agents can subscribe autonomously using the CLI: ```sh # Fully non-interactive subscription mog subscribe vendor/mcp-server --interval monthly --auto ``` If the subscription requires SCA (3D Secure), the CLI prints a URL for the human to complete payment. After confirmation, polling detects the activation automatically. Agents can also use the API directly: ```sh # Create subscription POST https://api.mog.md/v1/subscriptions Authorization: Bearer Content-Type: application/json { "listingId": "", "interval": "month" } # List subscriptions GET https://api.mog.md/v1/subscriptions Authorization: Bearer # Cancel subscription DELETE https://api.mog.md/v1/subscriptions/ Authorization: Bearer ``` ## For vendors See [Selling on mog → Subscription pricing](/docs/selling#subscription-pricing-for-mcp-servers) for how to enable subscription billing on your listings, set prices, and understand payouts. --- # Troubleshooting URL: https://mog.md/docs/troubleshooting ## Authentication ### "401 Unauthorized" on every command Your token may be expired or revoked. Re-authenticate: ```sh mog auth ``` Or check your current status: ```sh mog auth --status ``` If you're using `MOG_TOKEN` in an environment variable, verify it's set and valid: ```sh echo $MOG_TOKEN ``` ### Device code flow times out The device code expires after 15 minutes. If you didn't approve in time, run `mog auth` again to get a fresh code. If you're behind a corporate proxy or firewall that blocks `mog.md`, the polling may fail silently. Check your network and try again. ### "403 Forbidden — insufficient scope" Your token doesn't have the required scope for the operation. Common mismatches: | Operation | Required scope | |-----------|---------------| | `mog search`, `mog ls` | `read` | | `mog buy`, `mog install --auto-buy` | `purchase` | | `mog install` (download step) | `download` | | `mog publish`, vendor operations | `sell` | Generate a new token with the right scopes from [Dashboard → Settings](/dashboard/settings). ## Installation ### "Package not found" Check the exact coordinates (case-sensitive, `vendor/slug` format): ```sh mog search "package name" ``` Verify the vendor and slug match what's listed on `mog.md`. ### "Target not detected" The CLI auto-detects your editor by looking for marker directories (`.cursor/`, `.claude/`, `.windsurf/`, `.gemini/`, `.codex/`, `.openclaw/`). If none are found, it falls back to `generic`. To fix, either create the marker directory or specify the target explicitly: ```sh mog install acme/my-skill --target cursor ``` ### Installed files are in the wrong location Check which target was auto-detected: ```sh mog ls --json ``` Look at the `target` and `installPath` fields. If they're wrong, uninstall and reinstall with `--target`: ```sh mog uninstall acme/my-skill mog install acme/my-skill --target cursor ``` ### "SHA-256 mismatch" The downloaded archive doesn't match the hash recorded on the server. This could indicate a corrupted download or a tampered package. Try again: ```sh mog uninstall acme/my-skill mog install acme/my-skill ``` If the error persists, report the package to `support@mog.md`. ## MCP servers ### MCP server not showing up in my editor After installing an MCP server with mog, you must **restart your editor** for it to discover the new config. This applies to all editors — Cursor, Claude Code, Gemini CLI, Windsurf, and Codex. ### "Config file not found" during MCP install The CLI needs the target config file to exist (or its parent directory). For Cursor, ensure `.cursor/` exists. For Codex, ensure `.codex/` exists. Running `mog init` creates the necessary scaffolding. ### MCP server starts but tools aren't available Check that the server's dependencies are installed. For `npx`-based servers, ensure Node.js is on your PATH. For Python servers (`uvx`, `python3`), ensure the Python environment is set up. Test the server manually: ```sh npx -y @acme/github-mcp-server@1.0.0 ``` If it crashes, the issue is with the server package, not mog. ### Environment variables not being passed Verify the env vars are in the MCP config file. For Cursor, check `.cursor/mcp.json`. For Codex, check `.codex/config.toml`. If you installed non-interactively, make sure you passed all required env vars with `--env`. ## Purchases & billing ### "402 — approval required" Your spend policy blocked the purchase. The response includes an `approvalUrl`: ```json { "status": "approval_required", "approvalUrl": "https://mog.md/purchases/approve?listing=uuid", "reason": "Price (1500¢) exceeds your policy limit (1000¢)" } ``` Either: - Visit the `approvalUrl` to approve manually - Ask your org admin to increase the spend policy limit - Use a token without a spend policy (personal use only) ### "402 — insufficient balance" Your wallet balance is too low. Top up: 1. Go to [Dashboard → Billing](/dashboard/billing) 2. Add funds to your wallet 3. Retry the purchase Or enable auto top-up so this doesn't happen again. See [Wallet & billing](/docs/wallet). ### Purchase succeeded but package didn't install The purchase and install are separate steps. If `mog buy` succeeded but `mog install` failed, your entitlement is saved — you won't be charged again. Run `mog install` to retry the download and extraction. ## Lockfile ### "Lockfile integrity check failed" `mog doctor` reports that installed files don't match the lockfile hashes. This can happen if files were manually edited or corrupted. Reinstall to restore integrity: ```sh mog uninstall acme/my-skill mog install acme/my-skill ``` ### Merge conflicts in mog.lock.json After resolving git merge conflicts, run `mog install` to ensure the lockfile and installed packages are consistent. The CLI reconciles any mismatches. ### "Lockfile not found" Run `mog init` to create the lockfile: ```sh mog init ``` Then run `mog install` for each package you need. ## Wiring ### Skill installed but agent doesn't use it Installing a skill extracts files, but your editor's AI still needs to be told about them. Use `--wire` to create the appropriate config: ```sh mog install acme/my-skill --wire ``` For Cursor, this creates a `.cursor/rules/.mdc` file. For Claude Code, it appends to `AGENTS.md`. Without wiring, the skill sits in the directory but isn't referenced. ### "Wire already exists" If you reinstall with `--wire` and a rule/reference already exists, the CLI skips the wiring step to avoid duplicates. To force a rewire, delete the existing rule file and reinstall with `--wire`. ## Updates ### "No updates available" but the listing page shows a newer version Check which update channel you're on. By default, `mog update` only applies **patch and minor** updates. If the new version is a major bump, you need to install it explicitly: ```sh mog install acme/my-skill@2.0.0 ``` ### Update breaks something Roll back by installing the previous version explicitly: ```sh mog install acme/my-skill@1.2.0 ``` The lockfile records the exact version, so you can always restore a known-good state. ## Still stuck? Run the full diagnostic: ```sh mog doctor --json ``` This checks authentication, lockfile integrity, package hashes, wiring, and MCP config in one pass. If the issue isn't covered here, reach out at `support@mog.md` with the `mog doctor --json` output. --- # Verification & Ratings URL: https://mog.md/docs/verification ## How verification works Every package published to mog.md goes through an automated multi-agent verification pipeline before it becomes available to buyers. This happens as soon as a seller uploads a release — no package is ever published without passing verification. The pipeline runs three specialized checks in parallel: 1. **File validation** — confirms the package has the required structure, valid `mog.yaml`, no forbidden file types, no path traversal tricks, and is within size limits. 2. **Security scanning** — checks all text files for secrets, prompt injection attempts, obfuscation techniques, and suspicious URLs. An LLM-powered second pass provides a deeper classification of each file's content. 3. **Quality analysis** — scores the package on how well-written, complete, and useful it is, using both structural heuristics and an LLM review of the README and skill instructions. ### Outcomes | Result | Meaning | |--------|---------| | **Passed** | Package cleared all checks and is published. | | **Failed** | Package contains a critical issue (missing required files, detected secrets, confirmed malicious content). The seller is notified with a reason. | | **Flagged** | Package is unusual enough to warrant human review before publishing. This can happen if the security agent is uncertain or the quality score is very low. Sellers are notified and typical review time is under 48 hours. | ## What we check for We check for the following general categories. We deliberately do not publish the exact patterns and thresholds we use — doing so would make them easier to circumvent. - **File integrity**: required files present, valid YAML schema, no executable or unexpected file types - **Secrets**: API keys, tokens, and private credentials accidentally included in content - **Prompt injection**: instructions designed to override or manipulate AI agent behavior - **Social engineering**: content that tries to get an AI agent to take harmful actions - **Obfuscation**: encoded or hidden content that obscures the package's true purpose - **Quality**: completeness, clarity, and usefulness of the skill instructions ## The mog rating Every published package gets a **mog rating** — a score from **0.0 to 5.0** that gives buyers and agents a quick signal of how good a package is. ### How it's computed The mog rating combines four weighted signals: | Signal | Weight | Description | |--------|--------|-------------| | Quality analysis | **40%** | The automated quality agent's score, based on README structure, instruction clarity, specificity, and formatting. | | User reviews | **35%** | The average of star ratings (1–5) left by verified buyers. New packages start with a neutral prior of 3.0, smoothed toward the true average as reviews accumulate. | | Install velocity | **15%** | How many times the package has been installed in the last 30 days, log-scaled so big numbers don't dominate. | | Completeness | **10%** | Whether all optional metadata is filled in: long description, multiple targets, tags, license, install map. | The rating is recomputed nightly for all packages, so it reflects recent install trends and new reviews automatically. ### Rating scale | Score | Meaning | |-------|---------| | 4.5 – 5.0 | **Excellent** — well-written, widely used, highly reviewed | | 3.5 – 4.4 | **Good** — solid package worth using | | 2.5 – 3.4 | **Average** — functional but may have room to improve | | 1.0 – 2.4 | **Below average** — consider reading reviews before installing | | 0.0 – 0.9 | **Poor** — significant quality issues | | — | **No rating yet** — package is new or hasn't been reviewed | ## How to improve your rating The most impactful things you can do: 1. **Write a detailed README.md** — include what the skill does, when to use it, and usage examples with code blocks. 2. **Write specific instructions** — your skill instructions should be concrete and actionable, not vague. Tell the agent exactly what to do and when. 3. **Support multiple targets** — packages that work across Cursor, Claude Code, Codex, and Generic get a higher completeness score. 4. **Fill all metadata fields** — complete your `mog.yaml` with a long description, all applicable targets, license, and install map. 5. **Add tags** in your listing description to improve discoverability. ## Flagged packages If your package is flagged for review, you will receive an email notification. While under review, the package is not publicly visible. **Common reasons packages are flagged:** - The security scanner found content that looks unusual but isn't definitively malicious (e.g., instructions that resemble prompt injection patterns but may be legitimate) - The quality score was very low on first submission **Review timeline:** We aim to complete manual reviews within 48 hours. If your package is approved, it will be published automatically and you will be notified. **If you believe a flag is incorrect:** Reply to the notification email with context about why the flagged content is legitimate. Our team will re-review. ## For agents If you're an AI agent making autonomous purchasing decisions, use the `mogRating` field from the API to inform your choices: ```json GET /v1/listings/vendor/package-slug { "mogRating": "4.2", "mogRatingBreakdown": { "qualityComponent": 4.5, "userRatingComponent": 3.8, "installVelocityComponent": 4.1, "completenessComponent": 5.0 }, "installCount": 1250, ... } ``` **Recommended thresholds:** - `mogRating >= 3.5` — generally safe and useful for autonomous installation - `mogRating >= 4.0` — high confidence in quality and safety - `mogRating < 2.0` — consider requiring human approval before installing The `mogRatingBreakdown` shows the contribution of each component, which can help you decide whether to trust a rating for your specific use case (e.g., if install velocity matters less for your workflow, weight `qualityComponent` more heavily in your logic). ## Vendor identity verification Beyond package verification, mog verifies the identity of vendors themselves. Verified vendors get a badge on their listings and higher trust scores in discovery results. ### Verification methods | Method | How it works | |--------|-------------| | **GitHub org** | Vendor authenticates with GitHub and proves ownership of a GitHub organization. Mog verifies via OAuth. | | **Domain** | Vendor adds a DNS TXT record (`mog-verify=...`) to their domain. Mog checks for the record on demand. | A vendor is marked **verified** if either method succeeds. Verification status is surfaced in: - Search results (`vendorVerified: true`) - Listing detail pages - Service cards in the agent network - The `discover()` SDK method (filterable with `verified: true`) ### Verify from the API ```sh # Start GitHub org verification (redirects to GitHub OAuth) GET /v1/vendor/verify/github # Start domain verification (returns a TXT record to add) POST /v1/vendor/verify/domain # Check if the DNS record is live POST /v1/vendor/verify/domain/check # Check current verification status GET /v1/vendor/verification ``` ## Service trust engine For vendors who register [live service endpoints](/docs/services), mog runs an automated trust engine that continuously evaluates service reliability. This is separate from the package mog rating — it measures operational quality, not content quality. ### How it works 1. **Health probes** — Mog probes every registered service endpoint every 5–15 minutes using the appropriate protocol (MCP `tools/list`, HTTPS GET, or ACP GET). 2. **Usage metrics** — Every metered tool call records success/failure, latency, and duration. 3. **Rolling aggregation** — A background job computes rolling metrics hourly from probes and usage records. ### Trust metrics | Metric | Description | |--------|-------------| | **Total calls** | Lifetime invocations through mog | | **Success rate** | Percentage of metered calls that returned without error | | **Average response time** | Mean latency in milliseconds | | **P95 response time** | 95th percentile latency | | **Uptime %** | Percentage of healthy probes over the last 7 days | | **Verified identity** | Whether the vendor completed GitHub org or domain verification | ### Service status Probes determine the service's real-time status: | Status | Condition | |--------|-----------| | `active` | ≥3 of the last 5 probes healthy | | `degraded` | 1–2 of the last 5 probes healthy | | `inactive` | 0 healthy probes, or no endpoint registered | ### Using trust in discovery Agents can filter and sort by trust metrics to choose reliable counterparties: ```typescript const { services } = await mog.discover({ verified: true, sort: 'trusted', }) ``` Trust metrics appear in every service card returned by the API: ```json { "trust": { "totalCalls": 12400, "successRate": "99.20", "avgResponseMs": 340, "uptimePct": "99.95", "vendorVerified": true } } ``` See [Agent network](/docs/agent-network) and [Live services](/docs/services) for more on how trust integrates with discovery and sessions. --- # Wallet & billing URL: https://mog.md/docs/wallet mog uses a **pre-funded wallet** for frictionless purchases. Top up once, then buy any package or pay for metered tool calls without a checkout step for each transaction. For agents, the wallet enables fully autonomous purchasing — no payment prompts in the loop. ## How the wallet works 1. You **top up** your wallet with a one-time payment via Stripe 2. When you purchase a package (`mog buy` or `mog install --auto-buy`), the price is **deducted** from your balance 3. When you call a metered tool via the agent network, the per-call cost is deducted from your balance 4. Optionally, **auto top-up** refills the wallet when your balance drops below a threshold Free packages don't deduct anything. The wallet is used only when `"useWallet": true` is passed in the purchase API, or when the CLI uses `--auto-buy`. ## Check your balance ### Via CLI ```sh mog auth --status ``` The status output includes your current wallet balance. ### Via API ```sh GET https://api.mog.md/v1/wallet Authorization: Bearer ``` ```json { "balanceCents": 5000, "currency": "usd", "autoTopUp": { "enabled": true, "thresholdCents": 1000, "topUpAmountCents": 5000 } } ``` ## Top up your wallet ### Via the web 1. Go to [Dashboard → Billing](/dashboard/billing) 2. Enter a top-up amount 3. Complete payment via Stripe ### Via API ```sh POST https://api.mog.md/v1/wallet/top-up Authorization: Bearer Content-Type: application/json { "amountCents": 5000 } ``` Returns a Stripe `clientSecret` to confirm the payment: ```json { "clientSecret": "pi_xxx_secret_xxx" } ``` Pass this to Stripe's Payment Element or `confirmCardPayment`. Your balance is credited once the payment succeeds. ## Auto top-up Configure your wallet to automatically refill when the balance drops below a threshold. This is essential for agents that need to purchase autonomously without running out of funds. ### Enable auto top-up ```sh PATCH https://api.mog.md/v1/wallet/auto-top-up Authorization: Bearer Content-Type: application/json { "enabled": true, "thresholdCents": 1000, "topUpAmountCents": 5000 } ``` With this config, whenever your balance drops below $10.00, the wallet automatically charges your saved payment method for $50.00. ### Disable auto top-up ```sh PATCH https://api.mog.md/v1/wallet/auto-top-up Authorization: Bearer Content-Type: application/json { "enabled": false } ``` ### Requirements Auto top-up requires a saved payment method. Add one in the [Stripe Customer Portal](/dashboard/billing) (click **Manage payment methods**). ## Transaction history View all wallet debits and credits: ```sh GET https://api.mog.md/v1/wallet/transactions?limit=50 Authorization: Bearer ``` ```json { "transactions": [ { "id": "uuid", "type": "purchase", "amountCents": -500, "balanceAfterCents": 4500, "description": "acme/react-testing-skill@1.2.0", "createdAt": "2026-01-15T10:00:00.000Z" }, { "id": "uuid", "type": "top_up", "amountCents": 5000, "balanceAfterCents": 5000, "description": "Wallet top-up", "createdAt": "2026-01-14T09:00:00.000Z" } ], "cursor": "next-page-cursor" } ``` Use `cursor` from the response to paginate through older transactions. ## Insufficient balance If a purchase would exceed your wallet balance, the API returns HTTP 402: ```json { "status": "insufficient_balance", "balanceCents": 200, "requiredCents": 500 } ``` The CLI prints a clear message and exits with code 1. Top up your wallet and retry. If auto top-up is enabled, the wallet refills first and the purchase succeeds in a single step. ## Managing payment methods Click **Manage payment methods** in [Dashboard → Billing](/dashboard/billing) to open the Stripe Customer Portal. From there you can: - Add or replace credit/debit cards - View upcoming invoices - Download past receipts - Update billing details ## Organization wallets Each organization has its own separate wallet. When the org context is active (`mog org switch acme-team`), all purchases are deducted from the org wallet. See [Organizations](/docs/organizations) for details on org wallet management, top-ups, and spend policies. ## Wallet + spend policies The wallet and [spend policies](/docs/spend-policies) work together: 1. **Spend policy** checks whether the purchase is allowed (price limit, vendor allowlist, daily/monthly caps) 2. If allowed, the **wallet** deducts the amount 3. If the policy blocks it, the purchase fails with an `approvalUrl` — no wallet deduction This means an agent with a well-configured spend policy and an auto-topped wallet can purchase safely and autonomously. ## For agents The recommended setup for autonomous agents: 1. **Create an API token** with `purchase` + `download` scopes 2. **Attach a spend policy** to the token with appropriate limits 3. **Top up the wallet** with enough balance for expected usage 4. **Enable auto top-up** so the agent never runs dry 5. **Set `MOG_TOKEN`** in the agent's environment The agent can then run `mog install --auto-buy --json` freely within the policy guardrails. --- # Windsurf integration URL: https://mog.md/docs/windsurf mog has first-class support for **Windsurf** (by Codeium). The CLI auto-detects Windsurf projects, installs skill packages to `.windsurf/skills/`, and writes MCP server config to Windsurf's global config file. ## How auto-detection works When you run `mog install` in a project directory, the CLI looks for a `.windsurf/` directory. If it finds one, it sets the target to `windsurf` and uses Windsurf-specific install paths. You can always override with `--target windsurf`. ## Installing skills Skills are SKILL.md packages that teach Windsurf's Cascade AI specific capabilities. ```sh mog install acme/react-testing-skill ``` This downloads the package, verifies its SHA-256 hash, and extracts it to: ```text .windsurf/skills/react-testing-skill/ SKILL.md README.md ``` ## Installing MCP servers MCP server packages are configured by writing to Windsurf's **global** MCP config file — unlike other targets, this is not project-scoped. ```sh mog install acme/github-mcp-server ``` The CLI prompts for any required environment variables and writes the config: ```json title="~/.codeium/windsurf/mcp_config.json" { "mcpServers": { "acme-github-mcp-server": { "command": "npx", "args": ["-y", "@acme/github-mcp-server@1.0.0"], "env": { "GITHUB_TOKEN": "ghp_your_token" } } } } ``` If `mcp_config.json` already has other servers configured, mog merges the new entry without overwriting existing ones. ### Global scope Windsurf's MCP config is global (`~/.codeium/windsurf/mcp_config.json`), meaning MCP servers installed via mog are available across all your Windsurf projects. This differs from Cursor and Claude Code where MCP config is per-project. ### Accessing MCP settings in Windsurf You can also open the MCP config from within Windsurf: - **Command Palette:** `Cmd+Shift+P` (macOS) or `Ctrl+Shift+P` (Windows/Linux), then search "Windsurf: Configure MCP Servers" - **Cascade toolbar:** Click the hammer icon and select **Configure** - **Settings:** Open Windsurf Settings and search for "MCP" ### Passing env vars non-interactively For CI or agent-driven installs, pass environment variables with `--env`: ```sh mog install acme/github-mcp-server --env GITHUB_TOKEN=ghp_xxx ``` ### Supported transports Windsurf supports **stdio**, **Streamable HTTP**, and **SSE** transports for MCP servers. For HTTP servers, use `serverUrl` or `url` fields instead of `command` and `args`. ### Tool limits Cascade has a limit of 100 total MCP tools active at any given time. If you have many MCP servers installed, you can toggle individual server tools on or off through Windsurf's MCP settings page. Restart Windsurf after installing an MCP server for it to be discovered. ## Project health check Run `mog doctor` to verify your Windsurf project is set up correctly: ```sh mog doctor ``` This checks: - CLI authentication status - Lockfile integrity (`mog.lock.json`) - Installed packages match the lockfile (version and SHA-256) - MCP server config validity ## Listing installed packages ```sh mog ls ``` ```text 2 installed packages acme/react-testing-skill@1.2.0 windsurf .windsurf/skills/react-testing-skill/ Installed: 1/15/2026 acme/github-mcp-server@1.0.0 windsurf (mcp) ~/.codeium/windsurf/mcp_config.json Installed: 1/16/2026 ``` ## Updating packages ```sh mog update --dry-run mog update ``` Updates respect semver: by default only patch and minor versions are applied. The lockfile is updated and the old files are replaced. ## Uninstalling ```sh mog uninstall acme/react-testing-skill ``` For skills, this removes the extracted files from `.windsurf/skills/` and the lockfile entry. For MCP servers, this removes the `mcpServers` entry from `~/.codeium/windsurf/mcp_config.json`. ## File layout summary After installing skills and MCP servers: ```text my-project/ .windsurf/ skills/ react-testing-skill/ SKILL.md README.md another-skill/ SKILL.md mog.lock.json # Lockfile (commit to version control) ~/.codeium/windsurf/ mcp_config.json # Global MCP server configs ``` ## Tips - **Commit `mog.lock.json`** to version control so teammates get the same package versions. - **MCP config is global** — be aware that installing or uninstalling MCP servers affects all Windsurf projects on your machine. - Windsurf has a built-in **MCP Marketplace** accessible from the Cascade panel. mog complements this with its own cross-platform marketplace and CLI-driven workflow. - Use `mog explain /` to preview a package's metadata, install path, and target compatibility before installing. - Use `mog install --preflight` to see exactly what would happen without making changes.