Metadata-Version: 2.4
Name: codrspot-processor-mcp
Version: 0.1.0
Summary: Local MCP server exposing codepreproc's code-context tools to Claude Code
Author-email: alexlqi <alexlqi@gmail.com>
License: Copyright (c) 2026 alexlqi (alexlqi@gmail.com)
        
        All rights reserved.
        
        Redistribution and use of this software, in source or binary form, with or
        without accompanying documentation, is permitted provided that:
        
        1. The software is redistributed unmodified and in its entirety (as-is),
           retaining this license and all copyright notices.
        2. No person or entity may modify, create derivative works from, decompile,
           reverse-engineer, or otherwise alter the functionality of this software,
           in whole or in part, without prior written consent from the copyright
           holder.
        3. This license text is included, unaltered, with every copy or substantial
           portion of the software that is redistributed.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
        FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
        IN THE SOFTWARE.
        
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: Microsoft :: Windows
Classifier: License :: Other/Proprietary License
Requires-Python: <3.13,>=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: anyio
Requires-Dist: python-dotenv
Requires-Dist: bm25s
Requires-Dist: filelock
Requires-Dist: gitpython
Requires-Dist: httpx
Requires-Dist: mcp
Requires-Dist: numpy
Requires-Dist: openai
Requires-Dist: pydantic>=2
Requires-Dist: pyyaml
Requires-Dist: qdrant-client[fastembed]>=1.10.0
Requires-Dist: sentence-transformers
Requires-Dist: torch
Requires-Dist: tree-sitter
Requires-Dist: tree-sitter-languages
Requires-Dist: watchdog
Requires-Dist: xxhash
Requires-Dist: pyahocorasick
Requires-Dist: zstandard
Dynamic: license-file

# codepreproc

Servidor MCP local en Python para preprocesar contexto de repos de codigo antes de enviarlo a un agente como Claude Code.

## Que hace

`codepreproc` indexa uno o mas repositorios locales, resuelve el proyecto activo a partir del registro o de los roots enviados por el cliente MCP, y expone tools para:

### Gestion de proyectos e indice

- `list_projects` — lista proyectos configurados y estado del indice
- `switch_project` — fija el proyecto activo para la sesion
- `reindex` — corre reindex full o incremental
- `project_status` — devuelve estado git + indice

### Semantic patch pipeline

- `analyze_request` — ejecuta el pipeline completo: intent → retrieval → rerank → graph walk → target locator → planner → synthesizer → merger → materializer → validator → `SemanticExecutionPack`
- `preview_semantic_plan` — recupera el `SemanticEditPlan` cacheado por `task_id`
- `preview_patch` — devuelve los patches materializados como unified diffs
- `validate_patch` — resume el resultado de validacion estructural
- `disambiguate_region` — reanuda un task ambiguo eligiendo un `region_id` concreto
- `apply_patch` — aplica los patches con `git apply` y restaura CRLF si el archivo original lo usaba

### Filesystem reorg pipeline

- `analyze_filesystem_reorg` — genera un plan de moves/renames del arbol del repo
- `preview_filesystem_plan` — recupera el plan de filesystem cacheado
- `apply_filesystem_plan` — ejecuta los moves/renames del plan cacheado

### Busqueda de contexto y generacion de documentos

- `search_context` — semantic search hibrido (dense + BM25 + reranking): devuelve chunks con file_path, symbol, signature, score y body
- `generate_document` — recupera contexto, expande el grafo de dependencias, formatea invariantes y sintetiza un archivo Markdown con LLM; escribe el resultado en `output_path`

### Politica LLM y costos

- `usage_report` — resume costo/uso LLM acumulado por proveedor
- `set_llm_policy` — override por sesion de la politica de routing LLM del proyecto

### Snippet assembly (Fase 4)

- `list_snippets` — lista los snippets disponibles en la biblioteca, filtrables por framework, language o layer
- `assemble_from_snippets` — pipeline de dos fases: (1) modelo ligero resuelve intent → selecciona snippets → instancia variables → define scope; (2) modelo de capacidad alta integra los snippets en los archivos target respetando constraints DDD

## Requisitos

- Python 3.12
- Qdrant disponible en `http://127.0.0.1:6333`
- Un endpoint LLM compatible con OpenAI disponible en `http://127.0.0.1:8080/v1`

Los valores por defecto se toman de `registry.yaml` y pueden sobreescribirse con variables de entorno.

## Creacion e instalacion

Desde la raiz del proyecto:

```powershell
python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install --upgrade pip
python -m pip install -e .
```

Tambien queda disponible el entrypoint `codepreproc-mcp`.

## Puesta en marcha

Puedes iniciar el servidor MCP por stdio de cualquiera de estas dos formas:

```powershell
.\.venv\Scripts\python.exe -m codepreproc
```

```powershell
.\.venv\Scripts\codepreproc-mcp.exe
```

## Precarga manual de embeddings

Si quieres descargar un modelo de embeddings antes de arrancar el MCP, puedes usar este script:

```powershell
powershell -ExecutionPolicy Bypass -File .\scripts\preload_embedding.ps1
```

Por defecto precarga `Qwen/Qwen3-Embedding-0.6B` en `cuda:0` para dejarlo en cache con la misma GPU que usa el MCP durante `reindex`.

Si quieres precargar otro modelo:

```powershell
powershell -ExecutionPolicy Bypass -File .\scripts\preload_embedding.ps1 -Model "sentence-transformers/all-MiniLM-L6-v2"
```

Si quieres forzar otro device:

```powershell
powershell -ExecutionPolicy Bypass -File .\scripts\preload_embedding.ps1 -Device "cuda:0"
```

## Configuracion del registro de proyectos

Por defecto el servidor carga el registro desde:

```text
%USERPROFILE%\.codepreproc\registry.yaml
```

Ejemplo:

```yaml
defaults:
  embedding_model: sentence-transformers/all-MiniLM-L6-v2
  reranker_model: BAAI/bge-reranker-v2-m3
  llm_endpoint: http://127.0.0.1:8080/v1
  llm_model: qwen2.5-coder-7b
  qdrant_url: http://127.0.0.1:6333
  qdrant_grpc: 127.0.0.1:6334
  mcp_action_timeout_seconds: 300
  mcp_action_heartbeat_seconds: 15
  chunking:
    max_chunk_chars: 2000
    overlap_lines: 0
    max_file_size_kb: 50

projects:
  wallmart:
    root: D:\repos\challenge_one\wallmart
    languages: [typescript, tsx, javascript]
    qdrant_collection: wallmart_code
    branch_aware: false
    project_context: |
      Proyecto wallmart.
      App web orientada a e-commerce.
    ignore:
      - node_modules
      - dist
      - build
      - .git
```

Notas:

- El `project_id` es la clave del proyecto, por ejemplo `wallmart`.
- `root` debe ser una ruta absoluta al repo local.
- Las `languages` soportadas actualmente son: `python`, `typescript`, `tsx`, `javascript`, `go`, `rust`, `yaml`, `markdown`.
- `mcp_action_timeout_seconds` define el timeout por falta de avance relevante por tool.
- `mcp_action_heartbeat_seconds` define cada cuánto se emite heartbeat mientras una tool larga sigue viva.
- `CODEPREPROC_MCP_CONNECTION_VERBOSITY` controla el logging de ciclo de vida MCP: `off`, `basic`, `verbose`. Por defecto usa `basic`.
- Si tienes mas de un proyecto configurado, conviene pasar `project` explicito en las llamadas MCP.

## Configuracion del MCP en Claude Code

Una vez instalado el paquete, registra este servidor en la configuracion MCP de Claude Code:

```json
{
  "mcpServers": {
    "codepreproc": {
      "command": "C:\\Users\\<usuario>\\.codepreproc\\.venv\\Scripts\\python.exe",
      "args": ["-m", "codepreproc"]
    }
  }
}
```

Si prefieres usar el ejecutable del entrypoint:

```json
{
  "mcpServers": {
    "codepreproc": {
      "command": "C:\\Users\\<usuario>\\.codepreproc\\.venv\\Scripts\\codepreproc-mcp.exe"
    }
  }
}
```

Reemplaza la ruta por la ubicacion real de tu entorno virtual.

## Logging de conexion MCP

- El servidor escribe eventos de ciclo de vida MCP en `%USERPROFILE%\.codepreproc\logs\mcp_server.log` con prefijo `mcp_lifecycle`.
- `CODEPREPROC_MCP_CONNECTION_VERBOSITY=basic` registra transiciones principales: apertura, inicializacion, cierre y fallos relevantes.
- `CODEPREPROC_MCP_CONNECTION_VERBOSITY=verbose` agrega metadatos extra como capabilities, soporte de roots, tiempos de inicializacion y conteos de requests al cerrar.
- En transporte `stdio`, una "reconexion" significa una nueva sesion/proceso que vuelve a ejecutar `initialize`; no hay reanudacion de socket.
- Los eventos posteriores a `initialize` tambien intentan reflejarse al cliente mediante `codepreproc.mcp.lifecycle`, pero ese espejo es best-effort.
- Si la conexion falla antes de completar `initialize` o el transporte se cae abruptamente, revisa `mcp_server.log`: esa es la fuente de verdad.

## Flujo recomendado de uso en Claude Code

1. Registra el repo en `%USERPROFILE%\.codepreproc\registry.yaml`.
2. Inicia o deja configurado el servidor MCP en Claude Code.
3. Ejecuta `list_projects` para confirmar que Claude Code ve el proyecto.
4. Ejecuta `reindex` con `{"project":"wallmart","full":true}` la primera vez.
5. Ejecuta `project_status` para validar `last_indexed_sha` y revisar si hay drift.
6. Ejecuta `analyze_request` con un prompt concreto y, si aplica, consulta `preview_patch` con el `task_id` devuelto.
7. Si el cambio es mover o renombrar archivos o directorios, usa `analyze_filesystem_reorg`, revisa `preview_filesystem_plan` y luego aplica con `apply_filesystem_plan`.
8. Para explorar el repo o generar documentacion, usa `search_context` o `generate_document` directamente — no requieren un region objetivo y producen su resultado en una sola llamada.
9. Para generar codigo DDD nuevo a partir de plantillas (NestJS, Flutter, FastAPI), usa `assemble_from_snippets` con un prompt y el framework objetivo.

## Flujo de generate_document

`generate_document` sigue este pipeline (`VERIFICADO` en codigo):

```
prompt + output_path
  → HybridRetriever (dense + BM25)
  → Reranker (cross-encoder, top_k ≤ 30)
  → GraphWalker (expande dependencias a depth configurable)
  → _format_doc_context (agrupa por paquete, extrae invariantes: UPPERCASE_CONSTANTS, thresholds, exports)
  → router.chat(task_type="document_generation", schema=None)
  → write_text(output_path)
  → { success, file_path, bytes_written, chunks_used, llm_usage }
```

Notas:
- `output_path` puede ser absoluto o relativo al `root` del proyecto.
- El directorio padre se crea automaticamente si no existe.
- El LLM recibe un system prompt que exige secciones estructuradas: vision general, tabla de componentes, flujo ASCII, secciones por componente, contratos, dependencias y entry/exit points.
- Usar cuando no existe una region de codigo objetivo. Para modificar codigo existente, preferir `analyze_request`.

## Progreso y timeout

- Las tools ahora emiten progreso por `notifications/progress` cuando el cliente envía `progressToken`, y duplican el estado con `notifications/message`.
- `reindex` y `analyze_request` reportan etapas visibles como `health_check`, `git_sync`, `chunk_files`, `embed_batches`, `qdrant_upsert`, `planner` y `validate`.
- Si una acción pasa mas de `mcp_action_timeout_seconds` sin cambio relevante, falla con `error=action_timed_out` y devuelve la etapa donde se quedó.
- Los heartbeats no reinician el timeout; solo sirven para indicar que la acción sigue viva.

## Estado del índice

- `project_status` ahora devuelve `index_state` con uno de estos valores: `ready`, `building`, `invalid`.
- Cuando un incremental falla después de tocar el índice activo, el estado pasa a `invalid` y el siguiente flujo semántico fuerza `full reindex` antes de recuperar contexto.
- `last_index_error` incluye `code`, `stage` y `message` cuando el índice quedó inválido.

Ejemplos:

```json
{
  "project": "wallmart",
  "full": true
}
```

```json
{
  "project": "wallmart",
  "prompt": "Explicame la arquitectura del proyecto y los puntos de entrada principales"
}
```

## Variables de entorno utiles

- `CODEPREPROC_HOME`
- `CODEPREPROC_REGISTRY_PATH`
- `CODEPREPROC_INDEXES_DIR`
- `CODEPREPROC_LOGS_DIR`
- `CODEPREPROC_LLM_ENDPOINT`
- `CODEPREPROC_LLM_MODEL`
- `CODEPREPROC_MCP_CONNECTION_VERBOSITY`
- `CODEPREPROC_DEBUG`

## Preflight del servidor standalone y Docker

Este flujo verifica la frontera HTTP que ya existe entre `codepreproc_client`
y `codepreproc_server`: `/health`, `/v1/mint`, `/v1/promote` y
`/v1/lease_world_model`. Los modulos temporales que todavia importan codigo
del servidor desde `codepreproc_client.layer1_business.api_client` quedan fuera
de este preflight hasta que se cambien por llamadas HTTP reales.

### Local standalone

1. Configura PostgreSQL y exporta `CODEPREPROC_PG_DSN`.
2. Crea el schema:

```powershell
.\.venv\Scripts\codepreproc.exe db-init
```

3. Inserta una licencia de prueba:

```powershell
.\.venv\Scripts\codepreproc.exe license-add --license-id preflight-license --api-key preflight-api-key --tier pro --max-seats 5 --max-projects 20 --scope promote --scope lease
```

4. Arranca el servidor:

```powershell
$env:CODEPREPROC_JWT_SIGNING_KEY = "replace-with-a-long-stable-secret"
$env:CODEPREPROC_SERVER_PORT = "8443"
.\.venv\Scripts\codepreproc-server.exe
```

5. En otra terminal, ejecuta el preflight:

```powershell
.\.venv\Scripts\python.exe scripts\preflight_server_api.py --base-url http://127.0.0.1:8443
```

### Docker

1. Arranca solo PostgreSQL:

```powershell
docker compose up -d postgres
```

2. Crea schema y licencia desde la imagen del servidor:

```powershell
docker compose run --rm server codepreproc db-init
docker compose run --rm server codepreproc license-add --license-id preflight-license --api-key preflight-api-key --tier pro --max-seats 5 --max-projects 20 --scope promote --scope lease
```

3. Arranca el API:

```powershell
docker compose up -d server
```

4. Ejecuta el preflight contra Docker:

```powershell
.\.venv\Scripts\python.exe scripts\preflight_server_api.py --base-url http://127.0.0.1:8443
```

Para remoto, copia la imagen/compose/env al host Docker, cambia
`CODEPREPROC_JWT_SIGNING_KEY` por un secreto real, repite el seed de licencia
en el Postgres remoto y ejecuta el mismo preflight apuntando a la URL remota
antes de cambiar clientes reales.

## Observaciones

- El proyecto debe existir en `registry.yaml`; la implementacion actual no acepta un `path` arbitrario como argumento de tool.
- Si el cliente MCP envia `roots`, el servidor puede resolver el proyecto automaticamente cuando ese root cae dentro de un `root` registrado.
- `analyze_request` no solo recupera contexto: con la implementacion actual tambien intenta construir un execution pack y generar un patch validable.
- `analyze_request` solo cubre cambios dentro de archivos existentes. Si el prompt implica mover o renombrar archivos o directorios, o reorganizar el arbol del repo, el servidor devuelve `failure.code=OUT_OF_SCOPE` y recomienda usar `analyze_filesystem_reorg`. `target_locator` opera sobre regiones de codigo dentro de archivos, no sobre el filesystem.
- `analyze_filesystem_reorg` genera un plan de moves/renames, lo guarda en memoria de sesion con snapshot del arbol actual y valida consistencia antes de permitir `apply_filesystem_plan`.
- El flujo de filesystem solo mueve o renombra paths. No reescribe imports ni divide contenido entre archivos; si el cambio requiere eso, hay que combinarlo despues con el flujo semantico normal.
