Skip to main content
Glama
README.md
# Quaestio MCP Server

O Quaestio é um servidor [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) para análise, resolução e verificação de questões. Ele expõe ferramentas MCP para que um host compatível possa enviar perguntas, anexos e materiais de estudo e receber resultados estruturados, rastreáveis e conservadores.

O servidor não é uma interface de usuário nem um modelo de linguagem. Ele é a camada MCP que organiza o contrato de entrada, chama os componentes configurados, valida as respostas e devolve uma decisão estruturada ao cliente.

## O que é MCP neste projeto

MCP é um protocolo aberto para conectar aplicações host a servidores que oferecem ferramentas e dados de forma padronizada. No Quaestio:

```text
host MCP / cliente MCP
          │
          │ transporte stdio + JSON-RPC
          ▼
Quaestio MCP Server
          │
          ├── ferramentas de resolução e verificação
          ├── parsing, OCR e PDF
          ├── materiais de estudo e busca semântica
          ├── análise e execução controlada de código
          └── políticas de confiabilidade e auditoria
```

O MCP Server atualmente expõe a primitiva `tools`. Ele não publica `resources`, `resource templates` ou `prompts` como primitivas MCP separadas. Materiais, OCR, PDFs e capacidades do servidor são acessados por ferramentas.

Referências de protocolo utilizadas:

- [MCP — documentação oficial](https://modelcontextprotocol.io/);
- [especificação MCP 2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28/changelog);
- [descoberta do servidor](https://modelcontextprotocol.io/specification/2026-07-28/server/discover);
- [especificação de ferramentas](https://modelcontextprotocol.io/specification/2026-07-28/server/tools);
- [especificação de stdio](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio);
- [Python SDK oficial](https://github.com/modelcontextprotocol/python-sdk);
- [servidores de referência oficiais](https://github.com/modelcontextprotocol/servers).

## Capacidades

- resolver questões de múltipla escolha e abertas;
- processar perguntas com imagens inline;
- executar consenso entre dois backends LLM configuráveis;
- preparar perguntas não inglesas para os modelos configurados;
- preservar alternativas, índices, fórmulas, código e anexos;
- verificar estruturalmente e, quando configurado, semanticamente uma proposta;
- aplicar verificação matemática determinística e simbólica opcional;
- adicionar e pesquisar materiais de estudo locais;
- usar embeddings semânticos com fallback para TF-IDF;
- extrair texto de imagens com Tesseract;
- extrair e interpretar texto de PDFs;
- analisar código sem executá-lo;
- compilar/verificar sintaxe sem executar o código;
- executar Python ou JavaScript somente em sandbox Docker;
- avaliar lotes com gabarito e calcular métricas;
- retornar um `trace` das etapas executadas.

## Princípios de confiabilidade

O servidor foi projetado para falhar de forma explícita quando não há evidência suficiente.

- ausência de backend ou proposta válida resulta em `needs_review`;
- discordância entre os modelos não é resolvida silenciosamente;
- verificação semântica não é tratada como prova determinística;
- `verified` é reservado para evidência confiável, como verificações matemáticas determinísticas;
- a confiança declarada por um modelo é limitada pelo servidor;
- entradas, anexos, contexto e materiais recuperados são tratados como dados não confiáveis, nunca como instruções do sistema;
- falhas de provedores externos são convertidas em avisos e estados estruturados;
- o servidor não deve ser usado para considerar uma resposta de LLM como garantia de correção.

## Arquitetura interna

```text
tools/call
   │
   ▼
MCP boundary
   │  valida argumentos e serializa resultado
   ▼
QuaestioService
   ├── classificação
   ├── recuperação de materiais
   ├── preparação linguística/OCR
   ├── solver determinístico ou LLM
   ├── consenso
   ├── verificação estrutural/semântica
   └── avaliação e trace
```

Os principais componentes internos são:

- `models.py`: contratos canônicos e estados públicos;
- `mcp_server.py`: registro, despacho e transporte MCP;
- `service.py`: orquestração do pipeline;
- `backends.py`: backends determinísticos, LLM, tradução e consenso;
- `verification.py`: validações estruturais e matemáticas;
- `semantic_verifier.py`: revisão semântica independente opcional;
- `knowledge.py` e `embeddings.py`: base local e recuperação semântica;
- `ocr.py` e `pdf.py`: extração local de conteúdo;
- `sandbox.py`: execução controlada de código em Docker.

## Transporte e ciclo MCP

O transporte principal é `stdio`, adequado para servidores locais. O host inicia o processo e conversa com ele por `stdin` e `stdout`; cada mensagem é JSON-RPC. Logs de inicialização são enviados para `stderr` para não corromper o canal MCP.

O servidor implementa os fluxos modernos:

1. `server/discover` — descoberta da versão, identidade, capacidades e instruções;
2. `tools/list` — descoberta determinística das ferramentas, schemas e cache;
3. `tools/call` — execução de uma ferramenta com resultado estruturado.

Quando o pacote oficial `mcp` está instalado, o servidor utiliza o SDK moderno com transporte `stdio`. Sem o pacote, utiliza a implementação stdio mínima incluída no projeto. Os dois caminhos registram o mesmo conjunto de ferramentas e seguem o contrato moderno.
Cada ferramenta declara `inputSchema` e `outputSchema`; o caminho stdio mínimo também valida argumentos antes de executar o handler.

O servidor não inicia uma porta HTTP. Streamable HTTP permanece fora do escopo desta versão.

## Instalação

Requisitos:

- Python 3.11 ou superior;
- `pip`;
- credenciais de um endpoint LLM compatível com a API de chat da OpenAI para resolução assistida;
- Tesseract, somente para OCR local;
- Docker e imagens locais, somente para `run_code`;
- `pypdf`, somente para extração de PDFs.

Instalação básica:

```powershell
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e ".[dev]"
```

Extras opcionais:

```powershell
pip install -e ".[sdk]"   # Python SDK oficial do MCP
pip install -e ".[math]"  # SymPy
pip install -e ".[pdf]"   # pypdf
```

## Configuração

Copie `.env.example` para `.env` e preencha somente os provedores que deseja utilizar. O `.env` não deve ser versionado nem compartilhado.

### Resolução LLM

```env
QUAESTIO_LLM_BASE_URL=https://integrate.api.nvidia.com/v1
QUAESTIO_LLM_API_KEY=...
QUAESTIO_LLM_MODEL=...
QUAESTIO_LLM_TIMEOUT_SECONDS=45
```

Esse é o backend principal. Se o segundo backend estiver totalmente configurado, o Quaestio executa consenso:

```env
QUAESTIO_SECONDARY_LLM_BASE_URL=https://integrate.api.nvidia.com/v1
QUAESTIO_SECONDARY_LLM_API_KEY=...
QUAESTIO_SECONDARY_LLM_MODEL=...
```

Sem backend, o servidor continua disponível, mas questões que não puderem ser resolvidas deterministicamente retornam `needs_review`.

### Preparação linguística

```env
QUAESTIO_TRANSLATION_MODE=auto
QUAESTIO_TRANSLATION_TARGET_LANGUAGE=en
QUAESTIO_TRANSLATOR_BASE_URL=https://integrate.api.nvidia.com/v1
QUAESTIO_TRANSLATOR_API_KEY=...
QUAESTIO_TRANSLATOR_MODEL=...
QUAESTIO_TRANSLATOR_TIMEOUT_SECONDS=30
QUAESTIO_TRANSLATION_OCR=auto
QUAESTIO_TRANSLATION_OCR_LANGUAGE=por+eng
```

Modos disponíveis:

- `never`: nunca traduz;
- `auto`: traduz quando a pergunta não estiver em inglês;
- `required`: exige o tradutor quando a tradução for necessária.

A imagem original não é alterada. Quando há OCR, o texto reconhecido pode ser usado como contexto auxiliar, mas a imagem continua sendo enviada como evidência visual.

### Busca semântica

```env
QUAESTIO_KNOWLEDGE_BASE_PATH=./data/knowledge.json
QUAESTIO_EMBEDDING_BASE_URL=https://integrate.api.nvidia.com/v1
QUAESTIO_EMBEDDING_API_KEY=...
QUAESTIO_EMBEDDING_MODEL=...
QUAESTIO_EMBEDDING_TIMEOUT_SECONDS=30
```

Embeddings são opcionais. Quando indisponíveis, a base local usa TF-IDF. A base armazena materiais e vetores localmente; não adicione conteúdo que não possa ser persistido nesse arquivo.

### Verificação semântica independente

```env
QUAESTIO_VERIFIER_LLM_BASE_URL=https://integrate.api.nvidia.com/v1
QUAESTIO_VERIFIER_LLM_API_KEY=...
QUAESTIO_VERIFIER_LLM_MODEL=...
QUAESTIO_VERIFIER_LLM_TIMEOUT_SECONDS=45
```

Esse backend deve ser separado do solver quando a independência da revisão for importante. Ele retorna `supports`, `contradicts` ou `uncertain`; não transforma uma resposta de LLM em `verified`.

### Recursos locais opcionais

```env
QUAESTIO_TESSERACT_PATH=
QUAESTIO_DOCKER_PATH=
QUAESTIO_SANDBOX_PYTHON_IMAGE=python:3.12-slim
```

O Docker sandbox não baixa imagens automaticamente. As imagens precisam existir localmente.

## Como iniciar o servidor

Após a instalação editável:

```powershell
quaestio
```

Sem instalação editável:

```powershell
$env:PYTHONPATH = "src"
python -m quaestio.mcp_server
```

O processo parece ficar aguardando entrada porque o transporte `stdio` é dirigido pelo cliente MCP. Isso é o comportamento esperado.

## Configuração em um cliente MCP

Um host MCP precisa iniciar o comando do servidor como subprocesso. Exemplo genérico para Windows:

```json
{
  "mcpServers": {
    "quaestio": {
      "command": "C:\\caminho\\para\\Quaestio\\.venv\\Scripts\\quaestio.exe"
    }
  }
}
```

Alternativamente, usando Python:

```json
{
  "mcpServers": {
    "quaestio": {
      "command": "C:\\caminho\\para\\Quaestio\\.venv\\Scripts\\python.exe",
      "args": ["-m", "quaestio.mcp_server"],
      "env": {
        "PYTHONPATH": "C:\\caminho\\para\\Quaestio\\src"
      }
    }
  }
}
```

As variáveis de ambiente podem ser fornecidas pelo `.env` local ou pela configuração do host. Prefira o mecanismo de segredos do host quando disponível e nunca inclua chaves reais no repositório.

## Ferramentas MCP

### Resolução e verificação

| Ferramenta | Uso |
| --- | --- |
| `solve_question` | Resolve uma questão e retorna resposta, status, confiança, fontes, verificações e trace. |
| `solve_questions_batch` | Resolve até 500 questões preservando seus IDs. |
| `verify_answer` | Verifica consistência estrutural de uma proposta com a pergunta e suas opções. |
| `verify_answer_semantically` | Solicita revisão a um verificador LLM independente, quando configurado. |
| `classify_question` | Classifica tipo, disciplina e tópico. |
| `evaluate_questions` | Resolve questões com gabarito e retorna métricas de avaliação. |

### Materiais e recuperação

| Ferramenta | Uso |
| --- | --- |
| `add_study_material` | Adiciona texto autorizado à base local. |
| `search_study_material` | Busca materiais relevantes por TF-IDF ou embeddings. |

### Parsing, OCR e documentos

| Ferramenta | Uso |
| --- | --- |
| `parse_questions` | Converte texto numerado em questões canônicas. |
| `solve_text` | Faz parsing e resolução de um bloco de texto. |
| `extract_questions_from_image` | Extrai questões de imagens por backend visual configurado. |
| `ocr_image` | Executa OCR local com Tesseract, sem persistir a imagem. |
| `ocr_parse_image` | Executa OCR e transforma o resultado em questões. |
| `extract_pdf_text` | Extrai texto de um PDF inline usando `pypdf`. |
| `extract_questions_from_pdf` | Extrai texto do PDF e cria questões canônicas. |

Para processamento visual e OCR, a entrada precisa conter uma imagem inline em base64. Referências URI são aceitas no contrato canônico, mas o fluxo atual de OCR e envio multimodal utiliza os bytes inline.

### Código

| Ferramenta | Uso |
| --- | --- |
| `analyze_code` | Analisa código estaticamente sem executar. |
| `compile_code` | Verifica sintaxe/compilação sem executar. |
| `run_code` | Executa somente Python ou JavaScript em Docker sem rede e com limites de recursos. |

`run_code` não executa código no host. Se Docker, imagem ou linguagem não estiverem disponíveis, retorna um estado estruturado de indisponibilidade.

### Diagnóstico

| Ferramenta | Uso |
| --- | --- |
| `server_capabilities` | Expõe capacidades e a política de confiabilidade do servidor. |

## Contrato de entrada

Uma questão canônica pode ser enviada assim:

```json
{
  "question": "Qual é a capital do Brasil?",
  "options": ["Rio de Janeiro", "Brasília", "São Paulo"],
  "question_id": "q-001",
  "context": "Questão de geografia.",
  "attachments": []
}
```

Campos principais:

- `question`: texto obrigatório;
- `options`: lista opcional com pelo menos duas alternativas únicas;
- `question_id`: identificador preservado em lotes;
- `context`: contexto adicional ou material recuperado;
- `attachments`: imagens ou documentos, normalmente com `mime_type` e `data_base64`;
- `expected_answer` e `expected_option_index`: somente para avaliação com gabarito, não para orientar o solver.

## Contrato de saída

Uma resposta contém, entre outros campos:

```json
{
  "question_type": "multiple_choice",
  "answer": "Brasília",
  "option_index": 1,
  "confidence": 0.75,
  "status": "answered",
  "method": "consensus",
  "verification": {
    "status": "answered",
    "verified": false,
    "semantic": {
      "status": "supports",
      "confidence": 0.91
    }
  },
  "sources": [],
  "warnings": [],
  "trace": []
}
```

### Status da resposta

- `verified`: evidência determinística suficiente;
- `answered`: uma proposta foi produzida, mas não há prova determinística;
- `needs_review`: faltou consenso, evidência ou validação;
- `error`: falha no pipeline.

O campo `correct` só é preenchido quando o cliente fornece um gabarito por `expected_answer` ou `expected_option_index`.

## Exemplo de chamada MCP

Depois de `server/discover`, o cliente pode chamar:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": {"name": "example-client", "version": "1.0.0"},
      "io.modelcontextprotocol/clientCapabilities": {}
    },
    "name": "solve_question",
    "arguments": {
      "question": "Qual é a capital do Brasil?",
      "options": ["Rio de Janeiro", "Brasília", "São Paulo"]
    }
  }
}
```

O resultado MCP inclui conteúdo textual serializado e `structuredContent` para clientes que suportam resultados estruturados.

## Desenvolvimento e validação

Execute a suíte automatizada com:

```powershell
pytest -q
```

Os testes unitários devem ser executados sem depender de chamadas reais aos provedores. Smoke tests contra APIs externas devem ser explícitos, usando credenciais locais e questões autorizadas.

Para validar os endpoints configurados, execute o smoke test opt-in:

```powershell
quaestio-smoke --require-all --json
```

`quaestio-smoke` aplica internamente, no próprio processo, um teto fixo de 40 requisições por minuto. Essa proteção não é lida pelo servidor MCP e não limita o uso normal dos backends.

O dataset sintético de 30 questões pode ser avaliado com:

```powershell
quaestio-evaluate data/evaluation/benchmark-v1.jsonl --output benchmark-report.json
```

Ele inclui matemática, engenharia de software e categorias de controle; o gabarito é usado somente para medir o resultado e não é enviado ao solver.

No relatório, `needs_review` representa uma abstenção por evidência insuficiente ou divergência entre modelos. Essas ocorrências ficam fora de `incorrect` e reduzem apenas a `coverage`.

Documentação técnica relacionada:

- [especificação e plano de preparação multilíngue](docs/SPEC-TRANSLATION-PIPELINE.md) / [plano](docs/PLAN-TRANSLATION-PIPELINE.md);
- [especificação de isolamento de testes](docs/SPEC-TEST-ISOLATION.md) / [plano](docs/PLAN-TEST-ISOLATION.md);
- [especificação de smoke test NIM](docs/SPEC-NIM-SMOKE-TEST.md) / [plano](docs/PLAN-NIM-SMOKE-TEST.md);
- [especificação de avaliação multimodal](docs/SPEC-MULTILINGUAL-MULTIMODAL-EVALUATION.md) / [plano](docs/PLAN-MULTILINGUAL-MULTIMODAL-EVALUATION.md);
- [especificação de embeddings](docs/SPEC-EMBEDDING-QUERY-PASSAGE.md) / [plano](docs/PLAN-EMBEDDING-QUERY-PASSAGE.md);
- [especificação do verificador multimodal](docs/SPEC-SEMANTIC-VERIFIER-MULTIMODAL.md) / [plano](docs/PLAN-SEMANTIC-VERIFIER-MULTIMODAL.md);
- [especificação de benchmark e confiança](docs/SPEC-BENCHMARK-CONFIDENCE.md) / [plano](docs/PLAN-BENCHMARK-CONFIDENCE.md).

## Limites atuais

- transporte público HTTP ainda não está implementado;
- o servidor não expõe resources ou prompts MCP;
- o verificador semântico aceita imagens inline; URIs externas, PDFs e vídeo ainda não são enviados nessa etapa;
- o índice de embeddings exige reindexação quando o modelo configurado é trocado;
- OCR e extração de PDF dependem de instalações locais opcionais;
- consenso e revisão semântica reduzem risco, mas não substituem gabarito, prova formal ou revisão humana.