---
name: localdeploy-agent
description: "Generate, inspect, and edit structured local business websites, or queue personalized CSV LeadGen previews, through LocalDeploy's scoped REST API and remote MCP tools."
metadata:
  version: "1.0.0"
  language: "en-US"
  api-base: "https://localdeploy.haowenlabs.com"
  mcp-endpoint: "https://localdeploy.haowenlabs.com/api/mcp"
---

# LocalDeploy Agent Guide

Use this guide when a LocalDeploy account owner asks an agent to generate or edit a local business website, inspect a saved site's progress or structured state, or prepare a batch of personalized outreach previews. Use the existing LocalDeploy rendering engine and the customer's confirmed business information.

## Availability and account access

The REST API and remote MCP transport share the application's ownership checks, generation queue, state validation, and usage entitlements. Professional, Expert, and Unlimited Agency include agent access. Free Sandbox and Starter do not include REST or MCP access.

Production paid checkout and platform AI provider setup are still being completed. A configured MCP client is not proof that production generation is ready. Generation requires an eligible active workspace, a configured provider, a queue, and preview signing configuration. Unlimited Agency also requires both workspace BYOK credentials. Do not promise an untested generation time or a successful deployment.

API and MCP operations do not spend the separate future agent-credit allowance. They currently use the same full-site and LeadGen balances as the website. Prospect discovery and OpenAI + Perplexity API search audits have separate usage limits. New paid checkout opens after included discovery and audit services are connected and funded. Audit reports record dated API responses and citations rather than claiming universal visibility in consumer AI apps. Team collaboration, custom portal provisioning, and managed hosting fulfillment remain planned.

Use this base for the current agent deployment:

```text
https://localdeploy.haowenlabs.com
```

The API base follows the deployment's configured public origin. Wildcard preview domains have separate availability. Public agent previews use tokenized `/agent-preview/...` paths and are noindex review links. LeadGen uses the app's existing preview paths. A review link does not provision a customer's production domain.

## Create and protect an API key

1. The account owner signs in with Google and opens `/api-keys`.
2. Create a named key with only the scopes the client needs. Expiry options are 30, 90, or 365 days.
3. Save the one-time secret privately as `LOCALDEPLOY_API_KEY` in the client's environment. The server stores a hash; the secret cannot be retrieved again.
4. Revoke an unused or compromised key from the same page. The owner can manage revocation after a subscription ends.

Never request a customer's password, Google verification code, AI provider key, or a token in chat. Do not write the API key to a repository, a URL, browser storage, logs, or a generated site. Send it only in `Authorization: Bearer ...` over HTTPS to the configured LocalDeploy origin. This account key is separate from workspace Gemini, OpenAI, OpenRouter, or image-provider BYOK credentials.

For a private interactive Bash or Zsh session, this reads the secret without echoing it or placing its value in the command text:

```bash
printf 'LocalDeploy API key: '
IFS= read -r -s LOCALDEPLOY_API_KEY
printf '\n'
export LOCALDEPLOY_API_KEY
```

Start the client from a process that inherits that variable. Do not enable shell tracing around authenticated requests.

| Scope | Operations |
| --- | --- |
| `sites:read` | List themes, read site status, inspect saved state and its schema |
| `sites:write` | Queue full-site generation and edit owned saved sites |
| `leadgen:write` | Queue CSV previews, read owned batch progress, export outreach CSV |

Every request checks the key's expiry, revocation, scope, active plan, and workspace ownership. Cookie login does not replace a bearer key on agent endpoints.

## Prepare a confirmed business brief

Fetch the public intake JSON Schema from `/ai-agent-guide/schema.json`, or call `list_templates` / `GET /api/v1/templates` to inspect the same intake contract and the six theme tokens.

Save the merchant-confirmed intake as `brief.json`. It must contain all required fields in the schema:

- `version: 2`, `locale: "en-US"`, `themeId`, and `siteUrl` (a final HTTPS website URL, or `null`).
- `nap`: business name, industry, primary city and state, customer model, confirmed contact details, address visibility, hours, approved badges, and primary CTA.
- Confirmed `facts`, at least one `services` seed, and the approved `service_areas` and `locations` seeds.
- The `faqs`, `reviews`, and `gallery_items` collections, which may be empty when the merchant has supplied none.

Choose only `default`, `cardinal`, `harbor`, `neptune`, `pacific`, or `atlantic`. These themes are token configurations of one master component library. The agent supplies structured data; it never supplies raw HTML, CSS, scripts, utility classes, component names, or layout code.

Generation creates the three core pages (home, about, contact) plus one page per confirmed service, service area, and location. The total must be 4–25 pages. Do not invent additional services, neighborhoods, branch offices, addresses, landmarks, ZIP codes, reviews, awards, availability, licenses, insurance, or outcomes to reach a page count. Ask for the missing business facts instead.

Keep private addresses private. Use an address publicly only when `hasPublicAddress` is explicitly approved. Reviews and gallery items must carry their required approval flags. The primary phone or email CTA must match the supplied business contact details. Keep service references, collection slugs, and per-page canonical URLs consistent. The full runtime schema enforces rules beyond structural JSON Schema, including plain text, privacy, cross-references, and canonical URLs.

Do not place provider keys or model overrides in the brief. The server chooses the configured, bounded provider route. On standard plans, a full generation reserves one full-site credit. On Unlimited Agency, the configured BYOK route pays for usage through the workspace's provider accounts.

## REST workflow

All agent API routes require the bearer header. Send JSON mutations with `Content-Type: application/json`. For each independent mutation, choose one 8–100 character `Idempotency-Key` using letters, digits, periods, underscores, colons, or hyphens. Reuse it only for the identical payload; choose a new key when the requested work changes.

### 1. Inspect themes

```bash
curl --fail-with-body --silent --show-error \
  'https://localdeploy.haowenlabs.com/api/v1/templates' \
  -H "Authorization: Bearer $LOCALDEPLOY_API_KEY"
```

The response includes the six themes, the intake JSON Schema, and supported limits. This operation requires `sites:read`.

### 2. Queue the confirmed site

This example requires `jq` and an existing merchant-confirmed `brief.json`. It wraps that intake without fabricating business content. Replace the example request key once for each new site; retain it for retries of this site request.

```bash
jq '{brief: .}' brief.json > generation-request.json

curl --fail-with-body --silent --show-error \
  'https://localdeploy.haowenlabs.com/api/v1/sites/generate' \
  -H "Authorization: Bearer $LOCALDEPLOY_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: approved-intake-001' \
  --data-binary @generation-request.json \
  > generation-result.json
```

The body is `{ "brief": <confirmed intake object> }`. Read the returned `siteId`, `statusUrl`, and `schemaUrl`. The durable site ID also identifies its generation job; there is no separate job ID to guess. A successful queued response is not yet a completed site.

### 3. Poll progress, then inspect state

```bash
LOCALDEPLOY_SITE_ID="$(jq -r '.siteId' generation-result.json)"

curl --fail-with-body --silent --show-error \
  "https://localdeploy.haowenlabs.com/api/v1/sites/$LOCALDEPLOY_SITE_ID/status" \
  -H "Authorization: Bearer $LOCALDEPLOY_API_KEY"

curl --fail-with-body --silent --show-error \
  "https://localdeploy.haowenlabs.com/api/v1/sites/$LOCALDEPLOY_SITE_ID/schema" \
  -H "Authorization: Bearer $LOCALDEPLOY_API_KEY" \
  > site-schema.json
```

Statuses are `queued`, `running`, `completed`, and `failed`. Progress is a durable phase and percentage; it is not a promise of exact per-page timing. Poll with backoff, respect rate limits, and wait for `completed` before requesting saved state. A schema response contains `siteId`, `revision`, `state`, `jsonSchema`, and `liveUrl`. Review the full saved state before an edit. Treat the tokenized preview URL as a shareable review link and do not include private data in public copy.

### 4. Edit with a structured state patch

`PATCH /api/v1/sites/{siteId}/state` accepts exactly `{ "expectedRevision": <current integer>, "patch": <structured object> }`, plus a stable `Idempotency-Key` header.

Allowed top-level patch keys are `themeId`, `siteUrl`, `nap`, `pages`, `services`, `service_areas`, `locations`, `faqs`, `reviews`, and `gallery_items`. Objects merge recursively. Arrays replace their entire collection and must contain complete valid entries. `null` clears a field only when that field is nullable in the schema; it does not remove required properties. State `version` and `locale` cannot change. Reserved prototype keys, excessive depth, oversized JSON, markup, and unknown fields are rejected.

For example, this changes only the theme and takes the revision from the inspected state:

```bash
jq '{expectedRevision: .revision, patch: {themeId: "harbor"}}' \
  site-schema.json > site-patch.json

curl --fail-with-body --silent --show-error \
  -X PATCH \
  "https://localdeploy.haowenlabs.com/api/v1/sites/$LOCALDEPLOY_SITE_ID/state" \
  -H "Authorization: Bearer $LOCALDEPLOY_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: approved-theme-edit-001' \
  --data-binary @site-patch.json
```

The server validates the entire merged state, saves an owned revision, and keeps the review link tied to the same site. A revision conflict requires reading the latest state and preparing a new edit. Do not silently overwrite concurrent changes. An identical retry uses the original key; a newly revised payload uses a new key. Editing saved state does not start an AI generation.

### 5. Queue CSV LeadGen previews

CSV input is limited to 100 prospects and 250,000 UTF-8 bytes per batch. Required headers are `business_name`, `category`, `city`, and `state`. Optional headers are `phone`, `email`, `owner_first_name`, `current_website`, `google_rating`, and `review_count`. Fix every invalid row before submitting. A supplied Google rating requires a positive review count; listing data is imported agency data, not independently verified by LocalDeploy.

```bash
jq -Rs '{csvText: ., themeId: "harbor"}' prospects.csv > leadgen-request.json

curl --fail-with-body --silent --show-error \
  'https://localdeploy.haowenlabs.com/api/v1/leadgen/batches' \
  -H "Authorization: Bearer $LOCALDEPLOY_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: approved-prospect-batch-001' \
  --data-binary @leadgen-request.json
```

Read the returned `batchId`, `counts`, `statusUrl`, and `exportUrl`. Poll `GET /api/v1/leadgen/batches/{batchId}` with the same bearer key; it returns `{ "batch": ... }`. When previews are ready, download `GET /api/v1/leadgen/batches/{batchId}/export`. The export preserves original CSV columns and adds `preview_url` and `cold_email_icebreaker`. Only completed previews can be exported.

Standard plans reserve one LeadGen credit per prospect. Imported owner names, email addresses, and private reference fields are not permission to publish that information. The engine supplies preview links and an outreach icebreaker; it does not send cold emails or messages on the account owner's behalf.

## Remote MCP

Endpoint:

```text
https://localdeploy.haowenlabs.com/api/mcp
```

The server uses stateless Streamable HTTP and static bearer authentication. It returns JSON responses, creates no session ID, and provides no SSE event stream or OAuth authorization server. GET and DELETE return 405. Send both `application/json` and `text/event-stream` in `Accept`, even though this server chooses JSON responses.

The preferred protocol version is `2025-11-25`. Versions `2025-06-18` and `2025-03-26` are also supported. Include the negotiated `MCP-Protocol-Version` on subsequent requests. An absent header uses the March compatibility default. Only that compatibility path receives batches, limited to two messages executed sequentially; modern versions require one message per POST.

Initialize, send the initialized notification, then list and call tools. Accepted notifications return an empty 202 response. Notifications never start paid work. The six tools are:

| Tool | Input | Required scope |
| --- | --- | --- |
| `list_templates` | `{}` | `sites:read` |
| `generate_site` | `{brief, idempotencyKey}` | `sites:write` |
| `get_site_status` | `{siteId}` | `sites:read` |
| `get_site_schema` | `{siteId}` | `sites:read` |
| `update_site_state` | `{siteId, expectedRevision, patch, idempotencyKey}` | `sites:write` |
| `bulk_generate_leadgen_previews` | `{csvText, themeId?, idempotencyKey}` | `leadgen:write` |

MCP mutation keys are required inside the tool arguments. Do not substitute an unrelated transport header. Tool input schemas are strict; validation, ownership, credit reservations, and provider routing are shared with REST. Business failures return `result.isError: true`, a safe `structuredContent.error`, and matching text content. Invalid JSON, method names, or protocol parameters produce JSON-RPC errors. Do not treat an error result as a completed generation.

### Codex

Add to `~/.codex/config.toml` or your project's `.codex/config.toml`:

```toml
[mcp_servers.localdeploy]
url = "https://localdeploy.haowenlabs.com/api/mcp"
bearer_token_env_var = "LOCALDEPLOY_API_KEY"
```

See [official Codex MCP documentation](https://learn.chatgpt.com/docs/extend/mcp?surface=cli).

### Claude Code

Merge into `.mcp.json`. Claude Code expands `${LOCALDEPLOY_API_KEY}` in HTTP headers:

```json
{
  "mcpServers": {
    "localdeploy": {
      "type": "http",
      "url": "https://localdeploy.haowenlabs.com/api/mcp",
      "headers": {
        "Authorization": "Bearer ${LOCALDEPLOY_API_KEY}"
      }
    }
  }
}
```

Approve the project server when the client asks. See [official Claude Code MCP documentation](https://code.claude.com/docs/en/mcp#environment-variable-expansion-in-mcp-json).

### Cursor

Merge into `.cursor/mcp.json` or your global Cursor MCP configuration. Cursor uses `${env:LOCALDEPLOY_API_KEY}`:

```json
{
  "mcpServers": {
    "localdeploy": {
      "url": "https://localdeploy.haowenlabs.com/api/mcp",
      "headers": {
        "Authorization": "Bearer ${env:LOCALDEPLOY_API_KEY}"
      }
    }
  }
}
```

See [official Cursor MCP documentation](https://prod.cursor.com/docs/mcp#config-interpolation).

### Windsurf / Cascade

Open the MCP configuration from the Cascade panel and merge this entry into `mcp_config.json`. The linked official documentation covers legacy Cascade; use your installed client's current configuration location. This client uses `serverUrl` and `${env:LOCALDEPLOY_API_KEY}`:

```json
{
  "mcpServers": {
    "localdeploy": {
      "serverUrl": "https://localdeploy.haowenlabs.com/api/mcp",
      "headers": {
        "Authorization": "Bearer ${env:LOCALDEPLOY_API_KEY}"
      }
    }
  }
}
```

See [official Cascade MCP documentation](https://docs.devin.ai/desktop/cascade/mcp#config-interpolation).

## Limits, retry behavior, and billing

- Agent traffic is limited to 60 authenticated requests per minute per key, including MCP discovery and calls. Honor `Retry-After` and use backoff.
- New full-site starts are limited to two per minute per workspace. Queued work is durable; do not repeat a generation with a fresh key just because it is still running.
- Full-site intake supports 4–25 confirmed pages. CSV batches support 100 rows and 250 KB. JSON bodies have a bounded size and nesting depth.
- Workspace safeguards allow 10 active API keys, 20 newly created keys per rolling 24 hours, 10 pending full-site jobs, 1,000 retained sites, and 250 revisions per site. The retained document budget is 64 MiB; each queued full-site job reserves 4 MiB of that budget. These safeguards also apply to Unlimited Agency.
- Standard full-site and LeadGen credits reset monthly and do not roll over. Annual and quarterly billing still use monthly allowances within the already paid term.
- A canceled or unpaid agency subscription blocks new paid work and pauses outreach preview access. A scheduled cancellation retains paid access until the paid term ends. Saved state is not a substitute for an active agent entitlement.
- Unlimited Agency uses its configured BYOK credentials with no full-site or LeadGen credit deduction. Provider accounts still bill their owner, and usage safeguards apply.

REST error responses use `{ "error": { "code": "...", "message": "..." } }`. Common actions:

| Status | Action |
| --- | --- |
| 401 | Check the key, expiry, and environment inheritance; revoke and replace it if needed. |
| 403 | Review the active plan, requested scope, and workspace ownership. |
| 402 | Review billing and available generation allowance before starting new work. |
| 409 | Wait for the queued result, resolve a revision conflict, or use a new key for changed work. |
| 422 | Correct the intake, CSV, or merged state against its schema. |
| 429 | Honor Retry-After and back off; do not create parallel retries. |
| 503 | Provider, queue, signing, database, or billing setup may be pending. Retry the same operation key when ready. |

Keep failure details safe. Never echo a bearer key or provider response body into customer-visible copy. Report the actual saved job status, reviewed preview URL, and remaining setup steps to the account owner.

Support: [haowenapps@gmail.com](mailto:haowenapps@gmail.com). Protocol references: [Streamable HTTP](https://modelcontextprotocol.io/specification/2025-11-25/basic/transports), [lifecycle](https://modelcontextprotocol.io/specification/2025-11-25/basic/lifecycle), and [tools](https://modelcontextprotocol.io/specification/2025-11-25/server/tools).
