LangWizard MCP

Saudações.

Apresento a vocês o meu projeto LangWizard MCP (LW-MCP), um software simples e pontual que oferece um servidor MCP para armazenamento de documentos MarkDown (.md).

Pré-requisitos (constam em outros artigos aqui do blog):

  • Instalação do Linux (Debian ou Alpine);
  • Internet no servidor (sua VPS ou host);
  • Docker CE instalado;

1 – Sobre LangWizard MCP

O LZ-MCP é um software de gerenciamento de arquivos MarkDown para acesso via WEB (HTTP/HTTPs) e MCP (Model Context Protocol).

Vou explicar alguns conceitos, problemas, soluções e como ao final o LangWizard MCP oferece alternativas e soluções.

1.1 – Instruções para Agentes de IA

Quando trabalhamos com agentes de IA temos alguns problemas chatos:

  • Onde ficam os prompts?
  • Onde ficam as especificações (Spec-Driven Development — SDD) do sistema?
  • Onde ficam as SKILLs com habilidades e tutoriais específicos para os agentes?

A resposta mais ingênua é: Na pasta do projeto no seu notebook (e mais tarde no GIT).

1.2 – O problema do MONOREPO

Para cada novo projeto nós criamos as specs, baixamos as skills, criamos os prompts e agentes e depois de algumas horas temos um sistema pronto o suficiente para a IA pilotar (Claude Code, Antigravity, OpenCode, Codex, etc).

Esse tipo de prática é a melhor que existe para sistemas MONOREPO – uma (mono) pasta de projeto (repositório) que contem o software inteiro: Froentend, backend, bibliotecas, testes, assets (imagens, ícones, css), specs, documentações, etc.

O MONOREPO tem um ponto fraco: Consumo de TOKENS progressivo e instabilidade, ambos aumentam com o crescimento do código e da lógica.

Chega em um ponto que somente modelos caros (Claude OPUS, GPT Pro) conseguem tocar sem estragar uma coisa para cada outra coisa arrumada. Fazer uma pergunta pode drenar seus créditos diários pois a janela de contexto é saturada de inclusões de arquivos.

1.3 – Arquitetura de micro-serviço

Quando um software cresce muito, o melhor desenho para continuar é dividi-lo em pedaços que se encaixam na hora do build (compilação) e deploy.

Divisões:

  • Por biblioteca: As funções e procedimentos mais simples são transformados em bibliotecas, cada biblioteca vira um projeto separado
    • Exemplos: “lib-crypto-enterprise”, “lib-license-sdk”, “lib-schemas”;
    • Projeto principal: Apenas inclui as bibliotecas como dependências;
  • Por responsabilidade: O backend (software que roda no servidor) é separado do frontend (software que roda no cliente/navegador/smartphone);
    • Backend;
    • Frontend;
    • Banco de dados;
    • APIs externas;
  • Por funcionalidade: As partes que sobram são divididos em serviços que se comunicam internamente para prover autenticação, CRUD, eventos, etc:
    • Por canais: APIs internas, HTTP, JRCP, gRCP;
    • Por mensageria: NATS, RabbitMQ, Kafka;
    • Por storage: Criar objeto em banco (SQL, NoSQL) ou armazenador (S3);
    • Por claim check: Comunicar identificador por evento PUB/SUB (Redis/Valkey, NATS, Postgres, MongoDB) entre serviços distribuidos.

Em todos os casos, o problema surge agora:

Qual a fonte de verdade das especificações se todos os projetos de bibliotecas e serviços precisaram compartilhar especificações?

Especificações, skills e prompts vão se repetir em vários projetos, o projeto A que precisa ser comunicar com os projetos B e C precisam ter 3 especificações A,B,C para não errar.

Não vale responder “A IA lê o código fonte e aprende” pois isso é exatamente o que queremos evitar para não explodir a janela de contexto do modelo e PRINCIPALMENTE, permitir que o agente de IA toque o projeto sozinho.

1.4 – Contexto na nuvem

Para resolver o problema de duplicação e descasamento de contextos (specs, skills, prompts) existem sistemas que centralizam na nuvem esses arquivos, principais sistemas:

  • Context7: https://context7.com/, um dos melhores repositórios de Skills do mundo;
  • King Context;
  • GitMCP: Converte repositórios GibHub em documentação por acesso MCP;
  • MCPDoc: Dos mesmos criadores do LangChain, focado extração de arquivos llms.txt;
  • Docmancer: Opção self-hosted para ingestão de documentações;
  • ContextQMD: Obter documentação remota e importar para RAG local;
  • Outros sistemas: Procure em https://mcp.directory/servers?q=skills;

O objetivo de todos eles é o mesmo: Armazenar de maneira centralizada as informações de um projeto para guiar agentes de IA.

1.5 – LangWizard MCP como servidor de contexto

O LangWizard MCP é uma das alternativas simplistas e direta com implementação imediata e sem dependências chatas.

Seu diferença é ser um único software capaz de prover muitos servidores MCP de contexto na mesma URL de base.

Com esse design, você pode espalhar cada arquivo (documentação, skill e prompt) em servidores MCP específicos para cada finalidade mas no mesmo sistema por meio de MCP Server Multi-Tenant.

Após criar o primeiro servidor MCP você já pode entregá-lo ao seu agente.

Pequenos agentes de IA usando modelos baratos podem fazer um ótimo trabalho pontual em micro-serviços.

2 – Implementando o LW-MCP

O sistema roda usando 3 containers isolados que compartilham o mesmo volume (/data) onde ficam todas as configurações (arquivos JSON) e recursos (arquivos MarkDown).

2.1 – Preparativos

Você precisará de 3 endereços diferentes configurados no seu DNS.

Exemplo de endereços:

  • ADMIN: mcp-adm.dominio.com para administrar os servidores MCP;
    • Controle administrativo para criação de servidores MCP (tenant), cada servidor tem os seguintes recursos:
      • raw (file): Arquivo usado via tools do protocolo MCP (filesystem MCP);
      • resource (skill): Arquivo usado via context do protocolo MCP;
      • prompt: Arquivo usado via prompts do protocolo MCP.
    • MCP ADMIN: Possui MCP para administrar o servidor por meio de agentes;
  • MCP: mcp-srv.dominio.com para o servidor MCP;
    • Site principal de acesso aos servidores MCP;
    • MCP Index: Servidor MCP (/mcp) com índice de todos os projetos e arquivos;
    • MCP Tenant: Cada projeto (tenant) tem seu MCP em /nome-projeto/mcp para receber a conexão do MCP Client. Por padrão o acesso aberto a todos, o administrador pode configurar a chave de leitura para fechar o projeto e a chave de escrita para permitir alteração de recursos por meio de tools especiais;
  • SITE: mcp-web.dominio.com para o site de navegação aberta nos arquivos dos servidores;
    • Site com índice de todos os servidores;
    • Navegação e download dos arquivos MarkDown.

As URLs finais são (exemplos);

FQDN (Nome de DNS)Variável ENVImagem OCI (Docker)
mcp-adm.dominio.comLWADMIN_URLlangwizard-mcp-admin
mcp-srv.dominio.comLWSERVER_URLlangwizard-mcp-server
mcp-web.dominio.comLWSITE_URLlangwizard-mcp-site

2.2 – Volume

Volume para armazenamento dos arquivos e configs:

  • /data: Diretório dentro do container;
  • /storage/langwizard-mcp: Diretório no HOST.
Bash
# Diretorio de dados persistentes:
DATADIR=/storage/langwizard-mcp;
mkdir -p $DATADIR;

Todos os containers são replicáveies, ou seja, crie quantos precisar para aguentar a demanda dos clientes, bastando que em cada servidor (HOST nó do cluster) tenham os mesmos arquivos na pasta de volume (sincronize via rsync, Ceph, Gluster, etc…).

2.3 – Rede Docker

Rede Docker para os containers (network_public):

Bash
# Rede de containers
docker network create network_public \
    -d bridge \
    -o com.docker.network.bridge.name=br-net-public \
    -o com.docker.network.driver.mtu=1500 \
    -o com.docker.network.bridge.gateway_mode_ipv4=nat-unprotected \
    --subnet 10.249.0.0/16 \
    --gateway 10.249.255.254;

2.4 – Container de administração

Vamos criar o container responsável por administrar a criação de projetos MCP.

Personalize as variáveis antes de aplicar. Script:

Bash
# Senha mestre de administracao (usuario hard-coded 'admin')
    ADMIN_PASSWORD="tulipa@123";

# Enderecos dos containers
    LWADMIN_URL="mcp-adm.dominio.com";
    LWSERVER_URL="mcp-srv.dominio.com";
    LWSITE_URL="mcp-web.dominio.com";

# Nome do container e imagem
    NAME="langwizard-mcp-admin";
    IMAGE="tmsoftbrasil/langwizard-mcp-admin:latest";

# Baixar imagem atualizada
    docker pull $IMAGE;

# Criar container
    # Remover atual
    docker rm -f $NAME 2>/dev/null;
    # Rodar:
    docker run \
        -d --restart=always \
        --name $NAME -h $LOCAL.intranet.br \
        --read-only \
        \
        --cpus=2 \
        --memory 1g --memory-swap 1g --memory-reservation 128m \
        \
        --network network_public \
        -p 37000:8000 \
        \
        -v /storage/langwizard-mcp:/data \
        \
        -e ADMIN_PASSWORD="$ADMIN_PASSWORD" \
        -e DATA_DIR=/data \
        -e LOG_LEVEL=INFO \
        \
        -e LWADMIN_URL=https://$LWADMIN_URL \
        -e LWSERVER_URL=https://$LWSERVER_URL \
        -e LWSITE_URL=https://$LWSITE_URL \
        \
        --label "traefik.enable=true" \
        --label "traefik.http.routers.$NAME.rule=Host(\`$LWADMIN_URL\`)" \
        --label "traefik.http.routers.$NAME.entrypoints=websecure" \
        --label "traefik.http.routers.$NAME.tls=true" \
        --label "traefik.http.routers.$NAME.tls.certresolver=letsencrypt" \
        --label "traefik.http.services.$NAME.loadbalancer.server.port=8000" \
        \
        $IMAGE \
            uvicorn app.main:app --host "0.0.0.0" --port "8000";

# Visualizar URL de acesso administrativo
    echo;
    echo "Acesso:";
    echo "   Administracao...:  https://$LWADMIN_URL";
    echo;
    echo;

2.5 – Container de servidores MCP

Esse container contem apenas o servidor MCP multi-tenant baseado nos dados armazenados no volume.

Edite as variáveis antes de aplicar, script:

Bash
# Enderecos dos containers
    LWADMIN_URL="mcp-adm.dominio.com";
    LWSERVER_URL="mcp-srv.dominio.com";
    LWSITE_URL="mcp-web.dominio.com";

# Nome do container e imagem
    NAME="langwizard-mcp-server";
    IMAGE="tmsoftbrasil/langwizard-mcp-server:latest";

# Baixar imagem atualizada
    docker pull $IMAGE;

# Criar container
    # Remover atual
    docker rm -f $NAME 2>/dev/null;
    # Rodar:
    docker run \
        -d --restart=always \
        --name $NAME -h $NAME.intranet.br \
        --read-only \
        \
        --cpus=2 \
        --memory 1g --memory-swap 1g --memory-reservation 128m \
        \
        --network network_public \
        -p 37001:8001 \
        \
        -v /storage/langwizard-mcp:/data \
        \
        -e DATA_DIR=/data \
        -e LOG_LEVEL=INFO \
        \
        -e LWADMIN_URL=https://$LWADMIN_URL \
        -e LWSERVER_URL=https://$LWSERVER_URL \
        -e LWSITE_URL=https://$LWSITE_URL \
        \
        --label "traefik.enable=true" \
        --label "traefik.http.routers.$NAME.rule=Host(\`$LWSERVER_URL\`)" \
        --label "traefik.http.routers.$NAME.entrypoints=websecure" \
        --label "traefik.http.routers.$NAME.tls=true" \
        --label "traefik.http.routers.$NAME.tls.certresolver=letsencrypt" \
        --label "traefik.http.services.$NAME.loadbalancer.server.port=8001" \
        \
        $IMAGE \
            uvicorn app.main:app --host "0.0.0.0" --port "8001";

# Visualizar URL de acesso MCP
    echo;
    echo "Acesso:";
    echo "   MCP Index Server..:  https://$LWSERVER_URL/mcp";
    echo "   MCP Tenant Server.:  https://$LWSERVER_URL/nome_projeto_aqui/mcp";
    echo;
    echo;

2.6 – Container do site com os projetos

Esse container é opcional, ele fornece um site para que os usuários naveguem visualmente pelos servidores MCP e conheçam o conteúdo como se fosse uma WIKI.

Script:

Bash
# Enderecos dos containers
    LWADMIN_URL="mcp-adm.dominio.com";
    LWSERVER_URL="mcp-srv.dominio.com";
    LWSITE_URL="mcp-web.dominio.com";

# Nome do container e imagem
    NAME="langwizard-mcp-site";
    IMAGE="tmsoftbrasil/langwizard-mcp-site:latest";

# Baixar imagem atualizada
    docker pull $IMAGE;

# Criar container
    # Remover atual
    docker rm -f $NAME 2>/dev/null;
    # Rodar:
    docker run \
        -d --restart=always \
        --name $NAME -h $NAME.intranet.br \
        --read-only \
        \
        --cpus=2 \
        --memory 1g --memory-swap 1g --memory-reservation 128m \
        \
        --network network_public \
        -p 37002:8002 \
        \
        -v /storage/langwizard-mcp:/data \
        \
        -e DATA_DIR=/data \
        -e LOG_LEVEL=INFO \
        \
        -e LWADMIN_URL=https://$LWADMIN_URL \
        -e LWSERVER_URL=https://$LWSERVER_URL \
        -e LWSITE_URL=https://$LWSITE_URL \
        \
        --label "traefik.enable=true" \
        --label "traefik.http.routers.$NAME.rule=Host(\`$LWSITE_URL\`)" \
        --label "traefik.http.routers.$NAME.entrypoints=websecure" \
        --label "traefik.http.routers.$NAME.tls=true" \
        --label "traefik.http.routers.$NAME.tls.certresolver=letsencrypt" \
        --label "traefik.http.services.$NAME.loadbalancer.server.port=8002" \
        \
        $IMAGE \
            uvicorn app.main:app --host "0.0.0.0" --port "8002";

# Visualizar URL de acesso MCP
    echo;
    echo "Acesso:";
    echo "   Site LangWizard MCP..:  https://$LWSITE_URL/mcp";
    echo;
    echo;

.

3 – Usando o LW-MCP

Acesse a URL do container de administração (LWADMIN_URL), faça login (admin / senha_definida).

Crie um novo servidor MCP, adicione alguns arquivos MarkDown em cada tipo de recurso.

Teste a URL do servidor MCP no MCP Inspector (https://blog.patrickbrandao.com/mcp-inspector/).

.

Eu acho a sua falta de fé perturbadora.
Darth Vader, O Império Contra-Ataca

Terminamos por hoje!

Patrick Brandão, patrickbrandao@gmail.com