# Engineering code tools (TW-306 / TW-307 / TW-308)

Engineering MCP code tools run on `api.lucos.com` as thin adapters over the **existing** Lucos RAG proxy. They do **not** create a new code index or Qdrant ingest pipeline.

## Path

```text
ChatGPT / Cursor
  → business-mcp.lucos.com tools/call  (execute-on-gateway; full body POST)
  → POST /api/v1/tools/{code_search|get_file|get_file_lines}  (Bearer JWT)
  → requireAuthBearer
  → requireToolAccess(tool)   // policies/engineering/*
  → requireQueryableRepo
  → RAG adapter → POST {RAG_QUERY_SERVICE_URL}/api/v1/search/
  → secret filter (tool redaction) + tool_audit_logs
  → response (citations / chunk hydration)
```

Same upstream as SaaS `POST /api/v1/search` (`RAG_UPSTREAM.search`). Tool RBAC + queryable-repo are the Engineering MCP gates (not SaaS subscription/model plan gates on the IDE search route).

**MCP note:** Business Metrics tools use authorize-then-local (keys-only authz POST). Engineering tools use **execute-on-gateway** — a single full-body POST — because the gateway owns the RAG adapter, redaction, and audit. Do not re-run RAG inside `business-mcp.lucos.com`.

## Engineering vs Business separation

| Concern | Engineering (`code_search` / `get_file*`) | Business Metrics |
| --- | --- | --- |
| Policy dir | `policies/engineering/` | `policies/business-metrics/` |
| Kill switches / roles | Separate files; tools default **disabled** | Separate files; tools default **disabled** |
| Data store | Existing **code** Qdrant embeddings via RAG | AdCenter / RO SQL / `lucos_business_catalog` |
| Credentials | Lucos user JWT + trusted RAG headers only | Never reused for code tools |
| Forbidden for code tools | AdCenter level-1 keys, business RO DB users | — |

Business Metrics connectors must never receive Engineering-only identities for code retrieval. Engineering code tools must never receive AdCenter level-1 keys or business RO database users.

## Tools

### `code_search` (TW-306 / TW-307)

Request (MCP-shaped):

```json
{
  "query": "where is auth middleware?",
  "repository": "github:org/repo",
  "top_k": 10,
  "environment": "staging"
}
```

`repository` is mapped to `repo_id` for the queryable-repo gate and RAG body (`question` + `repo_id` + optional `options.top_k` per retrieval HLD §7.1).

Response citation contract under `data.citations[]`:

| Field | Type | Notes |
| --- | --- | --- |
| `path` | string \| null | File path |
| `start_line` | number \| null | Inclusive |
| `end_line` | number \| null | Inclusive |
| `commit` | string \| null | Commit SHA when present |
| `snippet` | string \| null | Secret-filtered text |
| `score` | number \| null | Retrieval score |
| `symbol` | string \| null | Symbol name when present |
| `repo_id` | string \| null | Repository id |
| `source_type` | string \| null | Optional (`code` / `docs` / …) |

Snippets pass through shared secret-pattern redaction (API keys, Bearer tokens, PEM private keys, URL secret query params) before ChatGPT sees them. `redactions_applied` records metadata only (never secret values).

### `get_file` / `get_file_lines` (TW-308)

RAG has **no** dedicated file/blob API. These tools hydrate **indexed chunks** via the same `/api/v1/search/` path, then filter by `path` (and line range for `get_file_lines`).

| Tool | Args | Hydration |
| --- | --- | --- |
| `get_file` | `repository`, `path`, `commit?` | `hydration: "partial_chunks"` — concatenated matching chunks ordered by `start_line` |
| `get_file_lines` | `repository`, `path`, `start_line`, `end_line`, `commit?` | `hydration: "chunk"` — chunks overlapping the requested line range |

Zero path matches → HTTP 200 with `result_count: 0` and empty `content` (not a fabricated file). Byte/row caps come from `policies/engineering/redaction.json`.

## Enablement

Production policy defaults keep tools **disabled**:

- `policies/engineering/kill-switches.json` → `tools.*.enabled.staging/prod = false`
- Staging fixtures enable them for tests only

MCP local flags (business-mcp): `LUCOS_TOOL_ENABLE_CODE_SEARCH`, `LUCOS_TOOL_ENABLE_GET_FILE`, `LUCOS_TOOL_ENABLE_GET_FILE_LINES` (plus `LUCOS_POLICY_ENABLED=true`). Live gateway calls need `LUCOS_BROKER_MOCK_ALLOW=false` and a real Bearer JWT; gateway still requires engineering role + kill-switch enablement.

## Related tickets

- TW-306 — thin adapter (Done)
- TW-307 — `code_search` secret filter + citation contract + MCP surface
- TW-308 — `get_file` / `get_file_lines` chunk hydration (as RAG supports)
- TW-292 / TW-293 / TW-294 — tool RBAC, audit, redaction foundation
