> ## Documentation Index
> Fetch the complete documentation index at: https://docs.writerzroom.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Corpus API and MCP

> Manage tenant-private reference documents and deploy the read-only curated vertical corpus MCP service.

WriterzRoom has two deliberately different corpus access paths:

| Path                     | Scope                                                                      | Intended caller                                        |
| ------------------------ | -------------------------------------------------------------------------- | ------------------------------------------------------ |
| Authenticated Corpus API | Shared curated chunks plus only the authenticated user's private documents | WriterzRoom users and their server-side integrations   |
| Curated Corpus MCP       | Shared curated chunks only; read-only and never includes private uploads   | Approved agents and services with Cloud Run IAM access |

Retrieval covers all ten vertical IDs: `education`, `enterprise_operations`, `entertainment`, `fintech`, `healthcare`, `healthcare_legal`, `legal`, `political`, `real_estate`, and `saas_tech`.

<Warning>
  Retrieval relevance is not proof of factual correctness. Check source authority, publication date, context, and the underlying document before relying on a result.
</Warning>

## Private Corpus API

All routes below use `https://api.writerzroom.com/api` and a user API key. Ownership is resolved from that credential; clients cannot supply or override an owner ID.

### Upload a document

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl -X POST https://api.writerzroom.com/api/corpus/documents \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "vertical": "enterprise_operations",
    "source_title": "Approved operating model",
    "source_url": "https://intranet.example/operating-model",
    "text": "The full reference text, at least 100 characters..."
  }'
```

The response returns a content-derived `document_id`, the stored chunk count, and `scope: private`. Text is capped at 500,000 characters per request.

### List, inspect, search, and delete

| Method   | Endpoint                          | Purpose                                                                      |
| -------- | --------------------------------- | ---------------------------------------------------------------------------- |
| `GET`    | `/corpus/documents`               | List the caller's private documents                                          |
| `GET`    | `/corpus/documents/stats`         | Count the caller's private documents and chunks                              |
| `POST`   | `/corpus/search`                  | Search curated material plus the caller's private documents; `top_k` is 1–50 |
| `DELETE` | `/corpus/documents/{document_id}` | Delete only the caller's matching private chunks                             |

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "query": "What approval sequence does the operating model require?",
  "vertical": "enterprise_operations",
  "top_k": 10
}
```

The product's private-corpus controls provide the same upload, list, search, statistics, and delete operations. Shared ingestion routes (`/corpus/ingest`, `/corpus/ingest/document`, `/corpus/stats`, and `/corpus/vertical/{vertical}`) are administrator-only and should not be exposed to end users.

## Curated Corpus MCP

The MCP process exposes three tools:

| Tool                    | Behavior                                                                             |
| ----------------------- | ------------------------------------------------------------------------------------ |
| `search_curated_corpus` | Hybrid dense and lexical search with reciprocal-rank fusion; `top_k` is capped at 20 |
| `list_curated_corpus`   | Supported verticals and aggregate curated coverage; excludes private counts          |
| `corpus_capabilities`   | Read-only boundary, retrieval methods, vertical IDs, and explicit non-claims         |

The MCP calls corpus search without a user ID. The store then admits only rows whose owner is null. This is the enforced tenant boundary, not a client option.

<Info>
  The service code and deployment configuration are included in the repository, but this documentation does not assert that your environment has deployed it. The following steps are required before first use.
</Info>

## Operator Deployment

The deployment uses `Dockerfile.corpus-mcp` and `cloudbuild.corpus-mcp.yaml`. It runs separately from the secret-free verification MCP because corpus retrieval needs database and Voyage embedding credentials.

<Steps>
  <Step title="Create the dedicated runtime identity">
    Create `writerzroom-corpus-mcp@agentic-writer.iam.gserviceaccount.com`. Do not reuse the main application runtime identity.
  </Step>

  <Step title="Grant least-privilege secret access">
    Grant that identity Secret Manager accessor on **only** `database-url` and `voyage-api-key`. Grant Cloud SQL connectivity only as required by the production database path. Do not grant project-wide Secret Manager access.
  </Step>

  <Step title="Verify private networking">
    Confirm the `writerzroom-connector` Serverless VPC Access connector exists in `us-central1` and can reach the database. The deployment sends only private ranges through it.
  </Step>

  <Step title="Build and deploy">
    From the repository root, run `gcloud builds submit --config cloudbuild.corpus-mcp.yaml --project agentic-writer`. The configuration keeps the service private with `--no-allow-unauthenticated`.
  </Step>

  <Step title="Authorize callers explicitly">
    Grant `roles/run.invoker` on `writerzroom-corpus-mcp` only to the service accounts that should call it. MCP clients must send a Google-signed identity token whose audience is the deployed Cloud Run service URL.
  </Step>

  <Step title="Smoke-test the boundary">
    Call `corpus_capabilities`, then `list_curated_corpus`, then a scoped search. Confirm `curated_only: true`, `includes_private_documents: false`, all ten verticals, and no private document titles or counts.
  </Step>
</Steps>

## Required Owner Actions

* Confirm the dedicated service account exists and its IAM bindings are no broader than documented.
* Confirm `database-url` and `voyage-api-key` contain production-ready values and that the existing 1,536-dimension corpus index remains compatible with `voyage-large-2`.
* Confirm the VPC connector and database route from Cloud Run.
* Choose and authorize each MCP caller identity; the service must remain private.
* Deploy and perform the curated-only boundary smoke test before advertising the MCP as available.

<CardGroup cols={2}>
  <Card title="Source Quality" icon="badge-check" href="/architecture/source-quality">
    Understand scoring, citations, and the limits of retrieval.
  </Card>

  <Card title="API Authentication" icon="key" href="/api/authentication">
    Create and protect user API keys for private corpus access.
  </Card>
</CardGroup>
