# @aigentyc/mcp

> Model Context Protocol server for the Aigentyc platform. Lets Claude Code, Cursor, Windsurf, Claude Desktop, and any MCP-compatible agent drive an Aigentyc project end-to-end: add documents, configure the chat agent, build custom tools — and scaffold or embed the front-end chat widget (`@aigentyc/chat-sdk`) — all from one conversation. The output is a working chat experience on the user's site.

## Zero-to-chat in one conversation

```
You:    "Add my docs/ folder, set the system prompt to be terse and helpful,
         and scaffold a Next.js chat app at ./my-app."

Claude: aigentyc_get_started        → "kb empty, no system prompt"
        files_upload({ paths: [...] }) → 14 docs ingested
        config_update({ patch: { systemPrompt: "..." } })
        aigentyc_get_started        → "snippetReady: true"
        chat_widget_scaffold({ destination: "./my-app", template: "next" })
        → ✓ done. cd my-app && npm install && npm run dev
```

## End-to-end recipe

1. **Discover state** — `aigentyc_get_started` returns project status + prioritised `nextSteps`. Always call this first in a new conversation.
2. **Add content** — pick the right ingest tool: `files_upload` (local files), `documents_create_from_text` (raw text), `extract_from_urls` (batch URLs), `link_sources_create` (crawl a website).
3. **Tune the chat** — `config_update` for the system prompt + chat model, `personas_upsert` for audience-specific tone, `tools_create` for custom REST/JS actions exposed to chat.
4. **Embed** — three options:
   - **`chat_widget_setup`** — confirms readiness, returns paste-ready snippet + install commands. Use when user has an app already.
   - **`chat_widget_scaffold`** — runs `npm create aigentyc-chat@latest <dir>` to bootstrap a fresh Vite or Next.js starter wired to the project. For greenfield apps.
   - **`chat_widget_get_snippet`** — just the snippet, no readiness check. For when you've already verified setup.

## Install

```bash
npx @aigentyc/mcp login \
  --api-key tyco_pk_XXXX \
  --project-id proj_XXXX
```

`login` verifies the key against `/api/auth/api-keys/verify` and writes `~/.aigentyc/config.json` with `0600` perms. The server refuses to start if perms are wider.

**Dev-only flag**: pass `--allow-insecure` to permit plaintext HTTP against non-loopback hosts. Never use this against production.

## Wire into your agent

### Claude Desktop / Claude Code

`~/Library/Application Support/Claude/claude_desktop_config.json` (macOS):

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

### Cursor

Settings → MCP → add server:

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

Restart the client. The new tools appear under the `aigentyc` namespace.

## Commands

```
aigentyc-mcp serve      Start the stdio MCP server (default)
aigentyc-mcp login      Save + verify an API key profile
aigentyc-mcp logout     Remove a profile
aigentyc-mcp doctor     Verify config + transport + clock skew + reachability
```

## Tools (86 total, 20 domains)

- **embed (E2E entry points)** — aigentyc_get_started, chat_widget_setup, chat_widget_get_snippet, chat_widget_scaffold
- **documents** — list, get, delete, create_from_text, merge, versions
- **files** — list, get, upload (path-based), delete, reprocess, versions, bulk_audience
- **extract** — from_urls (jobified for api-key)
- **link_sources** — list, get, create, update, delete, list_items, update_item, delete_item
- **page_questions** — list, set_manual, auto_generate (jobified), delete_page
- **data_stores** — full CRUD + bulk_upsert + import + export + scan_website (jobified)
- **tools** (custom-tool CRUD) — list, get, create, update, delete, execute_dry_run
- **flows** — list, get, create, update, delete
- **golden_answers** — list, create, update, delete + ai_improve + ai_generate_variations
- **corrections** — list, create, update_status
- **personas** — list, upsert, delete
- **config** — get (secrets redacted for api-key), update (secret writes rejected)
- **backups** — list, create (jobified), restore (jobified), download, import, delete
- **analytics** — overview, sessions, session_timeline, comments
- **branches** — list
- **search** — kb_search (read-only authoring aid)
- **jobs** — status, list, wait

## Async job pattern

Long-running ops (backup create/restore, extract, data-store scan, page-questions auto-generate) return `{ jobId, status: "queued" }`. Poll with `jobs_wait`:

```
extract_from_urls({ urls: [...] })
  → { jobId: "abc-123", status: "queued" }
jobs_wait({ jobId: "abc-123" })
  → blocks until terminal; returns { status: "completed", result: {...} }
```

Concurrency cap: 3 active jobs per project.

## Security

- **Project-scoped keys**: a key for project A cannot read/write project B (403).
- **Per-key rate limits**: 300 reads/min, 60 writes/min. 429 with `Retry-After` over the limit.
- **Secrets**: `config.get` redacts `openaiApiKey` + `customHttpHeaders` to `***` for api-key callers. `config.update` rejects writes to those fields with 403. Backup downloads (single + ZIP) deep-redact secrets.
- **Custom tool code**: `tools.create` rejects `transformCode` / `executeCode` containing `process.env`. Use `apiConfig.headers` with template placeholders for secrets.
- **Destructive ops** (`*.delete`, `backups.restore`): require `confirm: true`.
- **Path uploads**: `files.upload` refuses paths outside `$CWD` / `$HOME`, refuses non-regular files, caps 50MB/file, 500MB/batch.
- **URL inputs**: `extract.from_urls` + `link_sources.create` reject RFC1918 / loopback / cloud-metadata hosts.
- **Audit log**: every api-key request is logged server-side (`api_key_audit_log` table) with `keyId`, `projectId`, `route`, `method`, `status`, `latencyMs`, `requestId`. Reads sampled at 10%; writes 100%.

## Recipes

### Vibe-coder one-shot — docs to embedded chat in 60 seconds

```
1. aigentyc_get_started()
2. files_upload({ paths: ["docs/**/*.md"], indexAsDocuments: true })
3. config_update({ patch: { systemPrompt: "You are the support agent for ACME. Cite sources from docs." } })
4. chat_widget_scaffold({ destination: "./acme-chat", template: "next", confirm: true })
5. → cd acme-chat && npm install && npm run dev
```

### Add a markdown KB from local files

```
files_upload({ paths: ["docs/intro.md", "docs/api.md"], indexAsDocuments: true })
```

The MCP reads each file (text formats only — `.md`, `.txt`, `.json`, `.csv`, `.html`, …), uploads metadata to `uploaded_files`, then chunks + embeds + indexes via `documents/create`. After ingest, `chat_widget_setup` returns paste-ready snippet.

### Crawl a website + dedupe before adding more docs

```
1. link_sources_create({ sourceUrl: "https://example.com", sourceType: "website" })
2. jobs_wait({ jobId: ... }) — wait for crawl to finish
3. search_kb_search({ query: "billing FAQ" })  // confirm it indexed
```

### Build a custom tool end-to-end

```
1. tools_create({
     name: "submitForm",
     toolType: "rest_api",
     apiConfig: { method: "POST", url: "...", body: "name={{name}}" },
     inputSchema: [{ name: "name", type: "string", required: true }],
   })
2. tools_execute_dry_run({ toolId, input: { name: "Test" } })
   // verify output before exposing to chat
```

### Update system prompt

```
config_update({ patch: { systemPrompt: "You are the support agent for ACME..." } })
```

(Cannot update `openaiApiKey` over api-key — use the dashboard for secrets.)

## Troubleshooting

- **404 on login** — auth-service may be on a different origin in dev. `login` falls back to dashboard ping. Use `--base-url http://localhost:3000` for local Docker.
- **Tool calls hang** — confirm `aigentyc-mcp doctor` passes. Most failures are wrong base-url, expired key, or clock skew (>60s breaks auth).
- **Tool created but UI doesn't show it** — fully restart Claude Desktop / Cursor. Server-side caches invalidate on every write; client-side router caches don't.
- **Empty fields on tool call** — required string fields with `min(1)` get rejected by Zod, prompting the LLM to gather real values from the user. If a tool fires with empty inputs, the field wasn't marked required at creation.

## Versioning

Server (`@aigentyc/mcp` on npm) and platform (`app.aigentyc.com`) version independently. The platform maintains backward compatibility with older MCP releases — endpoints aren't broken without deprecation.
