Interfaces — MCP-First Surface
Interfaces
Seção intitulada “Interfaces”Tese (canonical, pós-ADR-002):
- Primary product surface = MCP server + MCP Apps em Open WebUI. Telas operacionais nascem dentro do chat host; não há admin Next.js standalone até pós-v1.0.
- MCP Apps (ext-apps spec, jan/2026) são HTML+JS inline no chat — substituem 80+ telas CRUD de ERP tradicional por ~12 components contextuais.
- REST/OpenAPI (
apps/api) é interface para sistemas e Nível-4 critical commands (TOTP co-presence).- All interfaces call
packages/app-services. No interface bypasses the domain kernel.- Critical commands (crypto-deletion, role change, SNGPC prod, recall, key rotation) não são MCP tools — vivem em
apps/apiREST com TOTP.
Conversation-first, não ChatGPT-first. canna-oss aceita comandos vindos de Claude, ChatGPT, Cursor, Open WebUI ou qualquer cliente MCP. Open WebUI é o sidecar default (deployed por padrão); REST permanece acessível para emergência e integrações tradicionais.
Arquitetura de Camadas
Seção intitulada “Arquitetura de Camadas” Domain Kernel (packages/domain) ↑ pura, zero side effects │ App Services (packages/app-services) ↑ loads stream → decide → append → project │ ┌─────────────────┬─────────────────┬─────────────────┐ │ │ │ │ MCP Server REST/OpenAPI Worker / Jobs (no admin (apps/mcp) (apps/api) (apps/worker) Next.js — │ │ │ ADR-002) │ │ │ ▼ ▼ ▼ MCP Apps Federation, SNGPC, PDF, (packages/ contábil, Email, BSPO, ui-apps) jurídico, Reports │ Nível-4 (TOTP) ▼ Open WebUI sidecar (Claude / ChatGPT / Cursor consume same MCP)Regra invariante: toda interface chama packages/app-services. Nenhuma interface escreve direto no event store, no read model ou em qualquer aggregate. Se você está pensando “para esta interface vou pular o app-service”, a arquitetura está errada.
Conversation-First ≠ ChatGPT-First
Seção intitulada “Conversation-First ≠ ChatGPT-First”| ChatGPT-first | Conversation-first |
|---|---|
| Produto depende do ChatGPT como porta principal | Produto aceita comandos conversacionais vindos de qualquer cliente MCP |
| Falha do ChatGPT = associação parada | Falha de qualquer agente externo = associação opera pela UI |
| Customização presa ao OpenAI | Cliente pode trocar de agente (Claude, ChatGPT, Cursor, agente próprio) sem reescrever produto |
canna-oss é conversation-first. ChatGPT (ou Claude, ou Cursor) é um dos clientes, não a porta.
Sem Admin Next.js (ADR-002)
Seção intitulada “Sem Admin Next.js (ADR-002)”Em revisão de produto de 2026-06-08, Gabriel descartou o admin Next.js standalone. A operação de uma associação de cannabis cabe naturalmente em fluxo conversacional: “Maria pediu 10g do CBD-FS” → agente abre DispensationFormApp inline → dispensador confirma → PendingAction → RT aprova no chat → 3 eventos atômicos no event store. Construir esse mesmo fluxo em admin Next.js exige mais código sem entregar mais valor.
Toda interação humana acontece em uma destas três superfícies:
- MCP Apps inline em Open WebUI (canal default) — forms, cards, timelines, approval flows renderizados dentro do chat. Cobre dispensação, busca de membro, traceability, pendências, KPIs, BSPO/RIPD review, e tudo o que era admin operacional.
- REST/OpenAPI (
apps/api) — Nível-4 critical commands com TOTP (crypto-deletion, role change, SNGPC prod submit, recall, key rotation) + integrações tradicionais (federation agents, contábil, jurídico). - Emergency CLI/curl —
apps/apiREST acessível via curl/Postman caso Open WebUI saia do ar. Operações de emergência (backup, restore, recovery) ficam aqui.
Por papel (via Open WebUI groups + OAuth scopes → MCP tool filtering)
Seção intitulada “Por papel (via Open WebUI groups + OAuth scopes → MCP tool filtering)”Cada role vê tools/apps filtrados pelo RBAC do app-services. Não há “tela por papel” como em ERP tradicional — há conjunto de tools/apps disponíveis no chat por papel:
| Papel | MCP scope | Tools/Apps disponíveis |
|---|---|---|
| Dispensador | canna:dispensador | get_member_quota, list_available_lots, draft_dispensation, request_record_dispensation (cria PendingAction) → MemberQuotaCardApp, DispensationFormApp |
| Responsável Técnico | canna:rt | + approval tools (approve_pending_action, release_lot, quarantine_lot), list_sngpc_pending, BSPO review → adicionalmente InventoryLotPickerApp, BspoReviewApp |
| DPO / Encarregado | canna:dpo | LGPD: list_consent_requests, request_crypto_delete_member (PendingAction Nível-4 → TOTP no apps/api), RIPD review → LgpdRequestsApp, RipdReviewApp |
| Diretoria | canna:diretoria | Approval Nível-3, dashboards, reports → KpiDashboardApp, monthly board report prompts |
| Auditor | canna:auditor | Read-only Level 1 — generate_traceability_report, audit log, event search → TraceabilityTimelineApp, AuditTimelineApp |
| Federation | canna:federation | Multi-tenant read-only com tenant switching |
Critical commands fora do MCP (Nível 4)
Seção intitulada “Critical commands fora do MCP (Nível 4)”Estes NÃO são tools MCP. Vivem em apps/api REST com TOTP + DPO/Admin co-presence:
POST /v1/admin/crypto-delete-member/:id(LGPD Art. 18 IV)POST /v1/admin/change-user-rolePOST /v1/admin/disable-2faPOST /v1/admin/rotate-site-kekPOST /v1/admin/submit-sngpc-productionPOST /v1/admin/change-quotaPOST /v1/admin/recall-lot
MCP App pode iniciar o fluxo (criar PendingAction tipo Nível4Request), mas a execução final exige TOTP no endpoint REST diretamente. Sem chat-only-autonomy para essas operações.
MCP Server — Primary Product Surface
Seção intitulada “MCP Server — Primary Product Surface”Model Context Protocol é o padrão aberto para conectar aplicações de IA a sistemas externos (descrito como “USB-C para aplicações de IA”). Suporte em Claude, ChatGPT, VS Code, Cursor — build once, integrate everywhere.
A tese comercial:
Uma associação pode operar o canna-oss pelo agente de IA que já usa — respeitando RBAC, OAuth, auditoria e aprovação humana nas ações críticas.
Primitivas MCP
Seção intitulada “Primitivas MCP”O MCP tem três primitivas; cada uma mapeia para um conceito do canna-oss:
| Primitiva MCP | No canna-oss |
|---|---|
| Resources (contexto/dados read-only) | Read models projetados — KPIs, quota, lotes, traces |
| Tools (funções executáveis) | Commands do app-service, com níveis de risco |
| Prompts (workflows guiados) | Playbooks: preparar relatório mensal, investigar discrepância, montar dossier ANVISA |
Catálogo MCP Proposto
Seção intitulada “Catálogo MCP Proposto”Resources: canna://reports/kpi/current canna://inventory/available-lots canna://members/{id}/quota-summary canna://dispensations/{id}/trace canna://regulatory-assumptions canna://sngpc/pending canna://compliance/gaps
Tools: search_member get_member_quota list_available_lots draft_dispensation ← Nível 2: draft, não executa request_dispensation_approval ← Nível 3: pede aprovação humana generate_traceability_report generate_kpi_report list_sngpc_pending explain_compliance_gap
Prompts: prepare_monthly_board_report investigate_inventory_discrepancy prepare_anvisa_dossier_section review_sngpc_failuresMCP Apps — Telas Contextuais dentro do Agente
Seção intitulada “MCP Apps — Telas Contextuais dentro do Agente”MCP Apps é a extensão do MCP que permite o servidor entregar componentes UI interativos renderizados dentro da conversa do host (Claude, Open WebUI, ChatGPT). Forms, dashboards, tabelas, gráficos, fluxo de aprovação — inline no chat.
Para canna-oss isso muda o cálculo: várias telas operacionais que seriam construídas no admin tradicional nascem dentro do próprio agente.
Telas operacionais que migram para MCP Apps
Seção intitulada “Telas operacionais que migram para MCP Apps”| Tela tradicional | MCP App |
|---|---|
| Dispensação assistida | DispensationReviewApp |
| Busca operacional de membro | MemberQuotaCardApp |
| Rastreabilidade de lote | TraceabilityTimelineApp |
| Dashboard mensal | KpiDashboardApp |
| Aprovação de PendingAction | PendingActionApprovalApp |
| Picker de lote disponível (FIFO) | InventoryLotPickerApp |
| Investigação de discrepância | InventoryDiscrepancyApp |
| Resumo SNGPC pendente | SngpcPendingApp |
Pacote compartilhado
Seção intitulada “Pacote compartilhado”packages/ui-apps/ ├── DispensationReviewApp ├── TraceabilityTimelineApp ├── KpiDashboardApp ├── PendingActionApprovalApp ├── InventoryLotPickerApp ├── MemberQuotaCardApp ├── InventoryDiscrepancyApp └── SngpcPendingAppComponentes em formato compatível com MCP Apps, reaproveitáveis também dentro do Minimum Canonical Admin (mesmo código, dois hosts).
Padrão “MCP App + PendingAction” (escrita)
Seção intitulada “Padrão “MCP App + PendingAction” (escrita)”1. Agente entende intenção do usuário2. MCP Tool retorna pending_action_id + MCP App renderizado3. MCP App mostra: diff (estado antes/depois), risco, eventos que serão emitidos4. Usuário confirma dentro do app (clique do humano, não do LLM)5. App-service materializa PendingAction6. Approver autorizado (mesma ou outra pessoa, dependendo de role) aprova — via MCP App ou Admin UI7. Domain emits DispensationRecorded + MemberQuotaConsumed + LotQuantityDeducted (single atomic append, cf. ADR-001)8. Audit log registra approver, host, tool, payloadHost compatibility — pragmatismo
Seção intitulada “Host compatibility — pragmatismo”| Host | Status MCP Apps |
|---|---|
| Claude (web/desktop) | Suporte primeiro-class esperado |
| Open WebUI v0.6.31+ | MCP nativo; MCP Apps UI ainda em verificação por feature |
| ChatGPT | Suporte parcial/crescente |
| Cursor / VS Code | Suporte MCP Tools; Apps em evolução |
Não basear roadmap inteiro em MCP Apps até v0.5+. v0.3–v0.4 usam MCP Tools + Resources (já estável); MCP Apps entra como aceleração quando hosts amadurecerem.
Níveis de Risco MCP
Seção intitulada “Níveis de Risco MCP”Não toda ferramenta vira tool MCP. Cada tool é classificada em 4 níveis:
| Nível | Descrição | Exemplos | Quando habilita |
|---|---|---|---|
| 1 — Read-only | Consulta sem efeito | get_inventory_summary, get_member_quota_summary, list_pending_reports, get_traceability_report, explain_domain_event | v0.3 — primeiro round MCP |
| 2 — Draft | Prepara sem executar; humano confirma | draft_dispensation, draft_kpi_report, draft_anvisa_dossier, draft_inventory_adjustment | v0.4 |
| 3 — Escrita operacional | Cria PendingAction; requer RBAC + confirmação na UI | request_record_dispensation, request_release_lot, request_submit_report | v0.5 |
| 4 — Alto risco | Não exposto via MCP no v1.0 — exige tela humana, justificativa, dupla aprovação | execute_crypto_deletion, change_user_role, disable_2fa, delete_or_rotate_keys, submit_sngpc_production, change_quota, recall_lot | nunca via agente sem UI co-presente |
Regra: MCP é interface de agente, não backend. Nenhuma tool MCP escreve direto no banco. Nenhuma tool bypassa RBAC. Nenhuma tool chama Drizzle direto para mutação.
Fluxo de Two-Step Approval (Comandos Críticos)
Seção intitulada “Fluxo de Two-Step Approval (Comandos Críticos)”Para qualquer comando que altere estado regulatório, o fluxo MCP é em duas etapas:
1. Agent calls request_record_dispensation(member_id, lot_id, quantity_g) → MCP retorna pending_action_id
2. Humano abre Admin UI → ações pendentes → revisa diff (quota antes/depois, lote antes/depois) → confirma ou rejeita
3. Sistema emite DispensationRecorded + MemberQuotaConsumed + LotQuantityDeducted (mesmo append no event store; cf. ADR-001) → registra approver na payload do evento
4. Agent recebe notification(action_id, status, event_id)Isso evita a armadilha clássica de deixar o LLM “clicar em produção”. Side effects assíncronos (SNGPC XML, PDF, email) seguem cf. boundary sync/async definido em ADR-001.
REST / OpenAPI API — Interface de Sistemas
Seção intitulada “REST / OpenAPI API — Interface de Sistemas”REST/OpenAPI existe para integrações tradicionais (federação FACT, contábil, jurídico, sistemas externos) e para hosts que falam OpenAPI mas ainda não MCP nativo (incluindo Open WebUI Tools).
POST /v1/commands/dispensationsGET /v1/reports/:idGET /v1/inventory/lotsPOST /v1/members/importPOST /v1/webhooks/sngpc-callbackOpenAPI spec gerada automaticamente (/openapi.json) — Open WebUI pode ingerir como tools. Para hosts OpenAPI-only, a bridge mcpo expõe tools MCP como servidor OpenAPI (“MCP-to-OpenAPI proxy”). Resultado: um único conjunto canônico de commands, três pontes (MCP, REST nativo, OpenAPI via mcpo).
Mesma regra: REST handler chama app-services, nunca toca event store ou Drizzle direto.
Open WebUI — Cockpit Agentic Opcional
Seção intitulada “Open WebUI — Cockpit Agentic Opcional”“canna-oss AI Workbench — powered by Open WebUI”. Open WebUI já resolve coisas que não devemos construir agora: chat UI, gestão de usuários/grupos por papel, modelos locais (Ollama) + cloud, RAG sobre docs da associação, tools (MCP/OpenAPI/Python), pipelines.
Como integra
Seção intitulada “Como integra”Open WebUI ↓ MCP / OpenAPI (mcpo bridge se necessário)canna-oss interface layer (MCP server + REST/OpenAPI) ↓ app-servicesDomain Kernel / Emmett ↓Event Store / Read Models- canna-oss expõe MCP Server + OpenAPI Server
- Open WebUI consome esses servers como tools
- Grupos/permissões do Open WebUI mapeiam para roles do canna-oss (via OAuth scopes)
- Modelo (Claude/Sonnet/Llama local) escolhido por tenant ou usuário
Boundary estrito
Seção intitulada “Boundary estrito”| Open WebUI controla | canna-oss controla |
|---|---|
| Chat UI + histórico de conversa | Source of truth regulatório |
| Modelo + temperatura + system prompt | Auth canônica (TOTP no Admin) |
| RAG sobre docs gerais da associação | RBAC + audit + PendingAction |
| Renderização de MCP Apps | Domain Kernel + Event Store |
Riscos a evitar
Seção intitulada “Riscos a evitar”- Não usar Workspace Tools (Python arbitrário) — execução de código no servidor; doc oficial alerta que operadores comuns não devem ter essa permissão
- Não tratar Open WebUI como fonte de verdade de usuário/RBAC — RBAC vive no canna-oss app-services, OAuth é apenas tradutor
- Não embedar/forkar dentro do produto — licença Open WebUI exige preservar branding (cf. README oficial)
- Não rodar regra de negócio no Open WebUI — apenas consumir tools
Deploy sidecar (compose)
Seção intitulada “Deploy sidecar (compose)”services: canna-api: # Fastify + REST/OpenAPI canna-worker: # BullMQ (SNGPC, PDF, email) canna-mcp: # MCP server (tools + apps) canna-openapi-bridge: # mcpo (apenas se host não fala MCP) canna-admin: # Minimum Canonical Admin (Next.js) open-webui: # opcional, sidecar postgres: redis: minio:Canna Copilot — Chat Interno (postponed)
Seção intitulada “Canna Copilot — Chat Interno (postponed)”Versão integrada do Open WebUI (ou implementação própria) dentro do próprio admin. Usa o mesmo MCP server. Postponed — entra depois que MCP write-with-approval (v0.5) está estável e MCP Apps tem suporte sólido nos hosts. Antes disso é distração.
Autenticação / Autorização
Seção intitulada “Autenticação / Autorização”| Interface | Auth |
|---|---|
| Web Admin UI | TOTP + sessão JWT |
| MCP Server (remoto) | OAuth 2.1 (cf. MCP Authorization Spec) — agente age em nome de usuário humano, com escopo limitado |
| REST API | API keys por integração + escopo + IP allowlist por tenant |
| Worker / Jobs | Service account interno, sem exposição externa |
Cada interface tem seu próprio mecanismo. Domínio é único.
Identity Provider — decisão postponed
Seção intitulada “Identity Provider — decisão postponed”A pergunta “quem é o IdP?” (canna-oss próprio, Open WebUI, ou IdP externo como Keycloak/Zitadel/Authentik) fica em aberto até v0.5+. Postura faseada:
| Fase | Auth |
|---|---|
| v0.2 | Admin auth próprio simples — JWT + TOTP. Sem OAuth ainda. |
| v0.3 | canna-oss emite tokens com escopo para MCP/OpenAPI (próprio IdP simples). Open WebUI usa esses tokens. |
| v0.5+ | ADR-002 (futuro) avalia OIDC provider self-hosted se federação/agentes externos crescerem. Não introduzir Keycloak cedo — é um rinoceronte na sala. |
Premissa: identidade vive no canna-oss até existir necessidade real de delegação multi-sistema.
Roadmap de Interfaces (pós-ADR-002)
Seção intitulada “Roadmap de Interfaces (pós-ADR-002)”| Versão | Interface | Capability |
|---|---|---|
| v0.2.0a/b | Domain kernel + event-store | DONE — Emmett in-mem + Postgres validado, ADR-001 spike gate PASSED. Sem interface ainda. |
| v0.2.1 | MCP server + MCP Apps + Open WebUI + REST/OpenAPI (sem admin Next.js) | apps/mcp Tools Nível 1+2+3, MCP Apps (MemberQuotaCardApp, TraceabilityTimelineApp, DispensationFormApp), apps/api Fastify (commands + Nível-4 REST com TOTP), Open WebUI sidecar OBRIGATÓRIO consumindo MCP nativo, OAuth 2.1 scopes → roles. |
| v0.3 | Pilot expansion | LGPD hardening (crypto-deletion via Tool Nível 3 + TOTP), CSV import, MCP Apps adicionais (InventoryLotPickerApp, MemberSearchApp, SngpcPendingApp, KpiDashboardApp), Auditor + Federation read-only roles. |
| v0.4 | Sandbox Dossier Ready | Dossier template via draft_anvisa_dossier_section, BSPO trimestral, RIPD via RipdReviewApp, DPO view completa (LgpdRequestsApp). |
| v0.5 | Regulatory Adapters | SNGPC + SNCR real, retry/DLQ, SngpcPendingApp, REST API pública v1 estável. |
| v1.0 | Full backend + Agent marketplace | Cultivation + Processing + Lab + CPC 29 + multi-tenant + billing. Federação multi-associação via 1 agente. Canna Copilot embutido reusando mesmos MCP tools/apps. |
Tools Nível 4 (crypto-deletion, role change, recall, SNGPC prod submit, quota change, key rotation, disable 2FA) ficam fora do MCP. Vivem em apps/api REST com TOTP + DPO/Admin co-presence — nunca em admin Next.js (que não existe).
Mensagem Comercial
Seção intitulada “Mensagem Comercial”“Você opera o canna-oss pelo agente de IA que sua associação já usa — Claude, ChatGPT, Open WebUI, Cursor. Telas operacionais nascem dentro do chat via MCP Apps inline; busca de membro, dispensação, traceability, KPIs, aprovação — tudo no fluxo conversacional. Ações críticas (crypto-deletion, recall de lote, submissão SNGPC produção) exigem TOTP via REST direta, com auditoria event-sourced.”
Isso só é verdade se a regra invariante for cumprida em código: toda interface chama packages/app-services; nenhuma interface bypassa o domain kernel; admin Next.js não existe.
Referências
Seção intitulada “Referências”- Model Context Protocol — Specification
- MCP Authorization (OAuth 2.1)
- MCP Apps — ext-apps — UI interativa dentro do chat
- MCP Apps blog post — “Bringing UI Capabilities To MCP Clients”
- Open WebUI — cockpit agentic opcional
- mcpo — MCP-to-OpenAPI proxy
- ADR-001 — Domain Kernel com Emmett — sync vs async boundary
- AGENTS.md — regras operacionais