canli-validation-mcp

Valide um backtest antes de confiar nele: índice de Sharpe deflacionado, overfitting de backtest (CSCV), verificações de evidência em papel e amplitude por meio de uma API gratuita, cada uma retornando um recibo recomputável. Também lê o histórico financeiro reportado pelas empresas a partir de arquivos da SEC. Execute com npx -y canli-validation-mcp.

Documentação

canli-validation-mcp

Um servidor MCP (Model Context Protocol) sobre a API de validação gratuita e com chave do canlicapital.com. Ele fornece a um agente de codificação nove ferramentas: emitir uma chave gratuita, executar os cinco validadores (Sharpe deflacionado, CSCV de sobreajuste, conformidade com evidência de artigo, teto de amplitude, duração mínima do histórico), buscar um recibo armazenado, ler o status do serviço e ler o histórico financeiro reportado de uma empresa a partir de arquivos da SEC. Cada ferramenta retorna o envelope completo da API como texto de resultado, seja sucesso ou erro, para que o agente não veja um número sem as frases ao lado que explicam o que o número não estabelece.

Este pacote é publicado no npm como canli-validation-mcp. Também está listado no Registro Oficial de MCP (io.github.arhancanli/canli-validation-mcp) e no cursor.directory. Execute-o com npx, sem etapa de instalação, como mostrado abaixo. Uma cópia local só é necessária para desenvolver ou testar este pacote em si; veja "Cópia local" perto do final.

Este README descreve a versão em package.json. npx sem versão executa o lançamento mais recente do npm; npx -y canli-validation-mcp@<version> fixa uma versão específica.

O que a API é (e não é)

O motor é o produto. O serviço executa os números que você envia através da mesma aritmética de honestidade que o registro de artigos do próprio canlicapital.com usa em si mesmo e devolve um veredito que qualquer pessoa pode recalcular a partir do recibo. Ele não aceita dados de mercado, não assina recibos, não avalia uma estratégia e nunca viu sua fonte de dados, seus custos ou qualquer lookahead em como uma série foi construída. Veja docs/superpowers/specs/2026-09-05-developer-key-validation-api-design.md no repositório principal para o design completo.

Ferramentas

FerramentaChamadasChave necessária
get_keyPOST /api/v1/keysnão
validate_deflated_sharpePOST /api/v1/validate/deflated-sharpesim
validate_overfittingPOST /api/v1/validate/overfittingsim
validate_paper_evidencePOST /api/v1/validate/paper-evidencesim
validate_breadthPOST /api/v1/validate/breadthsim
validate_track_recordPOST /api/v1/validate/track-recordsim
get_receiptGET /api/v1/receipts/{id}não
service_statusGET /api/v1/validate/statusnão
company_financial_historyGET /company-data/{cik}.json (um ticker é resolvido através de GET /api/v1/company-tickers.json)não

validate_deflated_sharpe aceita exatamente uma de duas formas de entrada, nunca uma mistura de ambas:

  • os sete campos do contrato: observed_sharpe_annualized, observations, periods_per_year, skew, non_excess_kurtosis, effective_independent_trials, cross_trial_sharpe_sd_annualized;
  • ou uma série de retornos mais as tentativas por trás dela: returns, periods_per_year, effective_independent_trials, cross_trial_sharpe_sd_annualized.

Enviar campos de ambas as formas, ou de nenhuma, é rejeitado antes que qualquer requisição saia do processo; veja src/schemas.mjs.

company_financial_history é diferente das outras ferramentas: ela lê a referência de empresa pública no canlicapital.com, não a API de validação. Forneça um CIK (1 a 10 dígitos) para listar os históricos financeiros disponíveis de uma empresa, ou um CIK e um conceito us-gaap como Revenues para obter as observações, das mais recentes para as mais antigas (limit tem padrão de 40, máximo 200). Cada observação mantém seu accession de arquivamento, formulário, data de arquivamento e unidade, e o resultado carrega o SHA-256 da resposta original da SEC e a frase de limite do próprio registro: estes são valores contábeis como reportados à SEC, não preços de mercado, retornos ou uma recomendação. Empresas e conceitos fora do lançamento atual retornam um erro com os conceitos disponíveis listados.

Prompts, recursos e resultados estruturados

Clientes que mostram prompts de MCP oferecem dois fluxos de trabalho guiados: validate_backtest (Sharpe deflacionado, depois sobreajuste, depois o histórico necessário, reportado com o que cada número não estabelece) e track_record_needed. Dois recursos podem ser lidos: canli://limits, as frases de limite que cada resultado carrega, e canli://sources, os artigos por trás de cada validador e como cada um é verificado contra eles. Cada resultado de ferramenta carrega seu envelope tanto como texto quanto como structuredContent.

Contexto compacto (0.3.0)

Um agente paga por cada token que uma ferramenta retorna, incluindo espaços em branco que ele nunca lê. Desde 0.3.0 cada resultado é JSON minificado, e um histórico de empresa retorna suas observações como um cabeçalho columns e uma linha por observação, com uma unidade compartilhada por todas as linhas declarada uma única vez. Nenhum campo é removido: cada frase de limite, número de accession, formulário, data de arquivamento e hash de origem ainda está no resultado, e columns + rows reconstroem cada observação exatamente.

Medido com bench/token_cost.py em registros ao vivo (tokenizador: tiktoken o200k_base; outros tokenizadores dão contagens absolutas diferentes), 20 observações cada:

Registro0.2.0 (recuado)minificado0.3.0 (minificado, colunar)
Apple, StockholdersEquity2.2141.560 (−29,5%)1.060 (−52,1%)
Microsoft, CashAndCashEquivalentsAtCarryingValue2.2311.574 (−29,4%)1.065 (−52,3%)

As ferramentas de validação ganham apenas a minificação: o envelope service_status ao vivo mediu 593 tokens recuados e 475 minificados (−19,9%); suas frases de limite são mantidas palavra por palavra. Estas são medições destes resultados, não uma afirmação sobre qualquer outro servidor.

Mudança que quebra compatibilidade desde 0.2.0: history.observations agora é {unit?, columns, rows} em vez de um array de objetos.

Configuração

VariávelPadrãoSignificado
CANLI_API_BASEhttps://canlicapital.comOnde a API vive. Aponte para uma implantação de pré-visualização para testes.
CANLI_KEYnão definidoUma chave já emitida de POST /api/v1/keys. Quando definida, get_key não envia nenhuma requisição e reporta que a chave já está configurada; toda outra ferramenta a envia como Authorization: Bearer <key>.
CANLI_LOCALnão definido1 ou true executa os cinco validadores nesta máquina (modo local privado, abaixo): sem chave, sem rede, sem recibo.

Se CANLI_KEY não estiver definida e o modo local estiver desligado, chame get_key uma vez por sessão antes dos validadores. A chave que ela retorna vive apenas na memória deste processo durante a vida da sessão; ela não é gravada em disco.

Falhas HTTP e envelopes de erro da API são marcados como erros de ferramenta MCP enquanto preservam o envelope JSON completo. Uma validação bem-sucedida com um veredito negativo permanece um resultado normal. Requisições têm um prazo de 30 segundos cobrindo cabeçalhos e corpo, rejeitam redirecionamentos e nunca são repetidas automaticamente. Um timeout pode ocorrer depois que o serviço processou uma requisição; verifique o status do serviço antes de decidir enviar novamente. Corpos de resposta não-JSON e erros de rede brutos são omitidos dos erros de ferramenta.

Instalação

Sem etapa de instalação. npx busca o pacote publicado na primeira execução, então cada configuração de cliente abaixo apenas inicia npx -y canli-validation-mcp. Veja "Cópia local" perto do final para desenvolver ou testar este pacote em si em vez de executar o publicado.

Endpoint hospedado (sem instalação)

As mesmas ferramentas são servidas em https://canlicapital.com/mcp via MCP Streamable HTTP, para clientes que se conectam a uma URL em vez de iniciar um processo (conectores Claude.ai, ChatGPT, servidores remotos do Cursor). Nada para instalar, e sem Node.js na sua máquina.

claude mcp add --transport http canli https://canlicapital.com/mcp

Sem uma chave, as requisições rodam sob uma chave anônima compartilhada, então a cota diária de validação é compartilhada por todos os chamadores hospedados. Para sua própria cota, emita uma chave gratuita (veja /developers) e envie-a como um cabeçalho:

claude mcp add --transport http canli https://canlicapital.com/mcp --header "Authorization: Bearer $CANLI_KEY"

O endpoint é sem estado. Nele, get_key não emite nada e diz qual chave está em uso, porque uma chave emitida lá não alcançaria a próxima requisição. Um cabeçalho Authorization malformado é recusado em vez de substituído pela chave compartilhada.

Claude Desktop

Adicione a claude_desktop_config.json (Configurações, Desenvolvedor, Editar Config):

{
  "mcpServers": {
    "canli": {
      "command": "npx",
      "args": ["-y", "canli-validation-mcp"]
    }
  }
}

Reinicie o Claude Desktop depois. Adicione um objeto "env" com CANLI_API_BASE para apontar isto para uma implantação de pré-visualização em vez do padrão.

Claude Code

claude mcp add canli -- npx -y canli-validation-mcp

Execute claude mcp list para confirmar que está registrado, e claude mcp remove canli para removê-lo.

Modo local privado

Defina CANLI_LOCAL=1 e os cinco validadores rodam na sua máquina: nada sobre a série que você envia é mandado para canlicapital.com, nenhuma chave é necessária e nenhum recibo é armazenado. O cálculo é o da própria API, enviado byte por byte em src/local (um teste falha se houver divergência), então um resultado local é igual ao hospedado; ele não nomeia um id de recibo porque nenhum foi criado.

claude mcp add canli-local --env CANLI_LOCAL=1 -- npx -y canli-validation-mcp

get_receipt, service_status e company_financial_history ainda leem de canlicapital.com; eles não enviam séries. Na extensão do Claude Desktop, esta é a configuração "Modo local privado".

Cliente stdio genérico

Qualquer cliente MCP que possa iniciar um processo e falar stdio funcionará. Usando o SDK oficial diretamente, a partir do Node:

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";

const transport = new StdioClientTransport({
  command: "npx",
  args: ["-y", "canli-validation-mcp"],
  env: { ...process.env, CANLI_API_BASE: "https://canlicapital.com" },
});

const client = new Client({ name: "my-agent", version: "0.1.0" });
await client.connect(transport);

const { tools } = await client.listTools();
console.log(tools.map((t) => t.name));

const keyResult = await client.callTool({ name: "get_key", arguments: { label: "my-agent" } });
if (keyResult.isError) throw new Error("Key setup failed; inspect the error privately.");
// The session retains the issued key. Avoid printing its envelope into logs.

const result = await client.callTool({
  name: "validate_deflated_sharpe",
  arguments: {
    returns: [0.004, -0.002, 0.007, 0.001, -0.003, 0.005, 0.002, -0.001],
    periods_per_year: 252,
    effective_independent_trials: 30,
    cross_trial_sharpe_sd_annualized: 0.5,
  },
});
console.log(result.content[0].text); // the full envelope, including limits and receipt.url

await client.close();

O que um resultado não estabelece (linguagem de limite)

Cada envelope que este servidor retorna carrega estas frases, verbatim, da própria API (api/_lib/limits.js):

  • Este veredito é sobre a série exatamente como enviada. O serviço nunca viu a fonte de dados, seus custos, sobrevivência ou qualquer lookahead em como a série foi construída.
  • Uma probabilidade de Sharpe deflacionado ou sobreajuste acima ou abaixo de qualquer limite não é admissão a nada e não é uma previsão.
  • O recibo tem hash de conteúdo e é reproduzível a partir do núcleo de código aberto que ele nomeia. Ele não é assinado.
  • Cotas: 1000 validações por chave por dia UTC, 5 chaves por cliente por dia UTC, 1048576 bytes por requisição, 20000 observações por série, 200 variantes por matriz.

A descrição de cada ferramenta também declara uma destas frases, então um agente vê o limite antes de chamar a ferramenta, não apenas depois. Nenhuma ferramenta neste servidor remove limits ou receipt.url de uma resposta; o envelope completo é sempre o texto do resultado.

Cópia local

Necessária apenas para desenvolver ou testar este pacote em si, não para executar o publicado.

cd mcp
npm ci
node src/server.mjs

Aponte um cliente para a cópia em vez do npm iniciando node /absolute/path/to/meridian/mcp/src/server.mjs no lugar de npx -y canli-validation-mcp em qualquer configuração acima.

Testes

npm test
npm run test:package

Executa node --test sobre test/*.test.mjs: round-trips de esquema contra o OpenAPI da própria API e exemplos de manifest, um caso de sucesso, envelope de erro e cota-429 por ferramenta com chave (um fetch falso substitui a rede), uma verificação de que cada descrição de ferramenta carrega uma frase de limites, uma verificação de que essas frases não se desviaram de api/_lib/limits.js, uma verificação de que nenhum arquivo enviado contém um travessão, e um teste que inicia o binário real do servidor e realiza um handshake MCP real de tools/list e callTool via stdio contra um stub HTTP local, para que a fiação seja comprovada em vez de assumida.

test:package cria o tarball npm real, verifica sua lista exata de arquivos e licença, instala-o em um diretório temporário de consumidor e executa o teste stdio contra essa entrada instalada. A instalação de dependências contata o npm; as chamadas de ferramenta usam apenas o stub HTTP local. Ele não publica um pacote nem emite uma chave de API de produção.

Dependências

Apenas @modelcontextprotocol/sdk (fixado exato) e zod (fixado exato). Nenhuma outra dependência de runtime é adicionada, e nada neste pacote toca o package.json raiz do site, .vercelignore, api/, scripts/, js/ ou public/.