Services
API MCP
MCP Server V2 Reference

MCP Server (Model Context Protocol V2)

Il servizio MCP è l'access plane governato di Vitruvyan: valida contratti, applica guardrail, effettua dispatch e registra audit. Non orchestra cognizione, non possiede memoria, non interpreta intent.

Versione corrente: V2 — capability-based, RBAC via JWT, domini isolati. L'API legacy (/tools, /execute) è mantenuta per backward compatibility ma non riceve nuove feature.


Architettura V2

Principi invarianti

PrincipioDettaglio
ThinOgni handler < 250 righe, nessuna LLM call, nessuna business logic
StatelessNessuno stato cross-request nel processo MCP
Non-orchestratoreLangGraph resta il cognitive orchestrator; MCP non sceglie strategie
Non-owner di memoriaMCP non crea né gestisce collection Qdrant. Le collection sono pre-provisioniate dall'init script o dai Sacred Orders
Side effects esplicitiOgni capability dichiara `side_effects: NONE

Domini

dev        → Read-only: KB, codebase, architettura, pattern
dev-write  → Write: file su whitelist, session context (EXPERIMENTAL)
core       → Tool legacy + capability core

I domini sono abilitati via MCP_ENABLED_DOMAINS (default: core,dev,dev-write).


Capability V2

Endpoint

MetodoPathDescrizione
GET/healthHealth check (Redis, timestamp)
GET/v2/capabilitiesLista tutte le capability registrate
POST/v2/executeEsegue una capability per nome

Payload /v2/execute:

{
  "capability": "dev.search_kb",
  "arguments": { "query": "MCP access plane" },
  "mode": "sync"
}

Capability dev (read-only)

NomeDescrizione
dev.get_architecture_contextBoundary rules e invarianti MCP/LangGraph/Sacred Orders
dev.get_coding_standardsGuardrail di sviluppo per AI coding agents
dev.get_graph_structureShape del pipeline LangGraph e pattern di estensione
dev.get_infrastructure_contextPorte, container, reti VPS
dev.get_existing_capabilitiesRegistry capability corrente (filtrabile per dominio)
dev.search_codebaseRicerca testuale bounded sui path ammessi
dev.open_fileSlice di file (max 120 righe, path whitelist)
dev.describe_componentContesto strutturato per un componente Vitruvyan noto
dev.search_kbRicerca semantica su vitruvyan_kb (Qdrant + fallback file index)
dev.get_patternSkeleton + convenzioni per un tipo di componente (esplicito)
dev.validate_changeCheck statici deterministici su file modificati
dev.get_coding_contextAggregazione arch + standards + KB (component_type esplicito se pattern)
dev.get_dependantsFile che importano o referenziano un simbolo dato
dev.get_session_context[EXPERIMENTAL] Sessioni recenti da vitruvyan_dev_sessions

Capability kb

NomeDescrizione
kb.askRAG diretto su vitruvyan_kb: embed query → Qdrant → gpt-4.1 → risposta con sources. Supporta history per follow-up.

Esempio:

{
  "capability": "kb.ask",
  "arguments": { "query": "Come funzionano i Sacred Orders?" }
}

Response:

{
  "status": "ok",
  "answer": "I Sacred Orders sono...",
  "sources": [{ "url": "/system-core/sacred-orders", "title": "Sacred Orders", "score": 0.91 }]
}

kb.ask usa gpt-4.1 per la sintesi (vs gpt-4o-mini usato da /kb/ask su api_graph).
La collection vitruvyan_kb viene aggiornata automaticamente via GitHub Action ad ogni push su master → vedi KB Auto-Ingest.


Capability dev-write

NomeDescrizione
dev.write_fileSovrascrive/appende file su whitelist (services/, docs/, infrastructure/)
dev.create_fileCrea nuovo file (fallisce se già esiste)
dev.apply_patchSearch/replace esatto su file esistente (match unico obbligatorio)
dev.save_session_context[EXPERIMENTAL] Persiste contesto sessione in Qdrant

Capability in dettaglio

dev.get_pattern

Restituisce uno skeleton reale + convenzioni per un tipo di componente Vitruvyan. component_type è obbligatorio e deve essere esplicito — nessuna inferenza automatica.

Tipi supportati: listener, sacred_order, capability, handler, graph_node, adapter, contract

{ "capability": "dev.get_pattern", "arguments": { "component_type": "sacred_order" } }

Tech debt noto: PATTERN_SOURCES è un indice statico in codice. La migrazione verso vitruvyan_kb_dev come source of truth è pianificata.


dev.validate_change

Check statici deterministici: nessuna LLM, nessuna valutazione semantica.

Regole attive:

IDPathVerifica
THIN_HANDLERservices/api_mcp/v2/File < 250 righe
NO_LLM_IMPORTservices/api_mcp/Assenza import OpenAI/Anthropic/LangChain
NO_DIRECT_DBservices/api_mcp/Assenza import psycopg/asyncpg/sqlalchemy
FROZEN_DATACLASSvitruvyan_core/contracts/frozen=True su ogni @dataclass
SIDE_EFFECT_DECLAREDservices/api_mcp/v2/side_effects presente se CapabilityContract
NO_PATH_TRAVERSALservices/api_mcp/Assenza .. non contestualizzata

Output: static_result: no_violations | violations_detected + disclaimer esplicito. Un risultato no_violations non garantisce correttezza architetturale.


dev.get_coding_context

Aggrega in una chiamata: architettura, coding standards, KB results, session context recenti.

  • Nessuna inferenza automatica: se serve il pattern di un componente, passare component_type esplicitamente.
  • Errori espliciti: le sub-call fallite compaiono in partial_results[], non vengono silenziate.
{
  "capability": "dev.get_coding_context",
  "arguments": {
    "task": "aggiungere un Sacred Order per Horizon Engine",
    "component_type": "sacred_order"
  }
}

dev.save_session_context / dev.get_session_context — EXPERIMENTAL

Persistono/recuperano il contesto di sessioni di sviluppo in vitruvyan_dev_sessions (Qdrant).

Vincoli architetturali:

  • MCP non crea la collection a runtime. Se non è pre-provisionata, le capability restituiscono non_liquet.
  • La collection deve essere dichiarata nell'init script o gestita da un Sacred Order dedicato.
  • La governance del dato (lifecycle, scadenza, dedup) è di responsabilità esterna a MCP.
{
  "capability": "dev.save_session_context",
  "arguments": {
    "task": "migrazione KB a Qdrant",
    "decisions": ["usato nomic-embed-text-v1.5", "collection tier ORDER"],
    "files_modified": ["dev_context.py", "ingest_kb.py"],
    "tech_debt": ["PATTERN_SOURCES da migrare a KB"],
    "next_steps": ["governance collection dev_sessions"]
  }
}

Policy e sicurezza

RBAC (JWT)

Se il caller presenta un JWT Keycloak, i ruoli vengono estratti e applicati:

DominioRuolo richiesto
devvitruvyan_mcp_read o vitruvyan_mcp_write
dev-writevitruvyan_mcp_write
corevitruvyan_mcp_read o vitruvyan_mcp_write

Callers senza JWT (env-based, es. Claude Code locale) bypassano il controllo ruoli per backward compatibility.

dry_run

dev-write è in dry_run=True se il caller non ha vitruvyan_mcp_write nel JWT. Il bridge stdio usa VITRUVYAN_MCP_DRY_RUN=false per abilitare le write nel contesto di sviluppo locale.

Path whitelist (write)

Le capability write accettano solo path sotto: services/, docs/, infrastructure/. Path assoluti e traversal (..) sono bloccati prima della risoluzione.

Hop limit e recursion guard

  • Max hops configurabile via MCP_V2_MAX_HOPS (default: 4).
  • Chiamate graph-originate non possono tornare su capability routes_to: ["langgraph"].

Bridge stdio (Claude Desktop / Codex)

Il bridge services/api_mcp/bridges/claude_desktop_stdio.py espone MCP V2 come server MCP stdio-compatible.

Ogni capability dev.* e dev-write.* diventa un tool con nome dev__<capability> (es. dev__search_kb).

Configurazione Claude Desktop (.mcp.json locale, non in repo):

{
  "mcpServers": {
    "vitruvyan-dev": {
      "command": "python3",
      "args": ["/path/to/services/api_mcp/bridges/claude_desktop_stdio.py"],
      "env": {
        "VITRUVYAN_MCP_URL": "http://localhost:9020",
        "VITRUVYAN_MCP_BRIDGE_DOMAINS": "dev,dev-write",
        "VITRUVYAN_MCP_DRY_RUN": "false",
        "VITRUVYAN_MCP_ACTOR": "claude-code"
      }
    }
  }
}

Template per Codex CLI: services/api_mcp/bridges/codex_mcp_config.toml


KB ingestion

Il tool services/api_mcp/tools/ingest_kb.py indicizza la KB in vitruvyan_kb_dev:

python3 services/api_mcp/tools/ingest_kb.py [--dry-run] [--clear]
  • Engine: nomic-ai/nomic-embed-text-v1.5 (768 dim, Cosine)
  • Prefissi nomic: search_document: al save, search_query: alla query
  • Sorgenti indicizzate: docs/, README.md, vitruvyan_core/contracts/, vitruvyan_core/core/governance|cognitive|orchestration, services/api_mcp/docs/
  • Collection Qdrant: vitruvyan_kb_dev (tier ORDER, owner MCP Dev)

Configurazione (env)

VariabileDefaultDescrizione
MCP_ENABLED_DOMAINScore,dev,dev-writeDomini capability abilitati
MCP_V2_MAX_HOPS4Limite hop anti-recursion
MCP_DEV_REPO_ROOTauto-detectRoot repo per file ops
MCP_DEV_ALLOWED_ROOTSvedi codiceDirectory ammesse per search/open
MCP_KB_BACKENDqdrantBackend KB (qdrant o file_index)
QDRANT_URLhttp://core_qdrant:6333URL Qdrant interno
EMBEDDING_URLhttp://embedding:8010URL embedding service
KEYCLOAK_URLURL Keycloak per validazione JWT

Aggiungere una capability (workflow)

  1. Implementa l'handler in services/api_mcp/v2/dev_context.py (read) o dev_write.py (write) o un nuovo modulo thin.
  2. Aggiungi il CapabilityContract in registry.py_dev_capabilities() o _dev_write_capabilities().
  3. Registra il dispatch in handlers.pyexecute_internal_capability().
  4. Dichiara side_effects espliciti. Se write → audit_level="strict".
  5. Ogni handler deve restare < 250 righe. Se supera → split in due moduli.
  6. Nessuna LLM call, nessun DB diretto, nessuna inferenza su linguaggio naturale nei handler.
  7. Rebuild: docker compose -f infrastructure/docker/docker-compose.yml up -d --build mcp

Non-scope (confini che MCP non deve attraversare)

  • Non orchestra cognizione: non chiama LangGraph direttamente, non sceglie strategie
  • Non interpreta intent: component_type e qualsiasi routing deve essere esplicito nel payload
  • Non possiede memoria: non crea collection Qdrant, non gestisce lifecycle di dati cross-sessione
  • Non contiene policy semantica: le regole di validate_change sono check statici, non architetturali
  • Non espone DB: nessun handler accede direttamente a PostgreSQL; usa agent o Sacred Orders