
Eu pensei que construir um servidor MCP era a parte difícil. Não era.
No mês passado, publiquei promptbuilder-mcp — um servidor MCP que permite que Claude Desktop e Cursor puxem componentes de prompt diretamente do Prompt Builder, uma IDE de prompt baseada em componentes que estou construindo.
O lado do protocolo MCP levou um fim de semana. O problema de autenticação levou muito mais tempo e me ensinou mais. Isso é o que eu aprendi.
O que eu estava construindo
Prompt Builder permite que você monte prompts a partir de componentes reutilizáveis — personas, protocolos, formatos, templates — armazenados em um banco de dados Supabase. Os usuários podem navegar em um cofre público, criar componentes privados e compilar tudo em prompts estruturados.
A ideia com o servidor MCP era simples: em vez de abrir o navegador, um usuário deveria ser capaz de digitar "busque minhas personas do Prompt Builder" dentro do Claude Desktop e recebê-las de volta como resultados da ferramenta.
Ideia simples. A implementação teve um problema que eu não previ.
A suposição que quebrou tudo
Meu modelo mental inicial estava errado.
Eu assumi que o servidor MCP de alguma forma herdaria a sessão existente do usuário — que, porque o usuário estava logado no Prompt Builder em seu navegador, o servidor MCP rodando em sua máquina poderia simplesmente... conversar com a API e obter seus dados.
Não é assim que funciona.
O servidor MCP é um processo separado rodando via stdio na máquina do usuário. Ele não tem navegador. Ele não tem cookies. Ele não tem sessão. Quando faz uma requisição HTTP para minha API, está completamente não autenticado por padrão.
Isso se tornou óbvio imediatamente quando eu testei. O servidor se conectou bem. O registro da ferramenta funcionou. Mas cada requisição de dados retornou vazia — porque todas as minhas tabelas Supabase tinham a Segurança em Nível de Linha habilitada, e cada consulta estava escopo para auth.uid().
-- Esta política significava que requisições não autenticadas não retornavam linhas
CREATE POLICY "Usuários podem ler seus próprios componentes"
ON components FOR SELECT
USING (auth.uid() = user_id OR is_public = true);
Componentes públicos vieram bem. Componentes privados — o cofre próprio do usuário — retornaram nada. Sem erro. Apenas arrays vazios. Isso foi na verdade pior do que um erro porque levou um tempo para eu entender o porquê.
Por que eu não pude usar a autenticação do Supabase diretamente
A correção óbvia parecia ser: passar o JWT do Supabase do usuário para a configuração do servidor MCP.
O problema com isso é que os JWTs do Supabase expiram. Um usuário configuraria seu servidor MCP com um token, funcionaria por uma hora, então pararia silenciosamente de retornar dados privados novamente. Essa é uma experiência terrível. Você também estaria pedindo aos usuários para colar um JWT bruto em um arquivo de configuração, o que não é algo que você quer incentivar.
Eu precisava de algo feito sob medida para esse caso de uso — de longa duração, revogável, somente leitura, e não vinculado ao sistema de sessão.
Construindo o sistema de chaves de API
Eu construí uma tabela dedicada api_keys no Supabase:
CREATE TABLE api_keys (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(),
user_id uuid REFERENCES auth.users(id) ON DELETE CASCADE,
name text NOT NULL,
key_hash text UNIQUE NOT NULL,
key_prefix text NOT NULL,
scopes text[] DEFAULT '{}',
last_used_at timestamptz,
created_at timestamptz DEFAULT now(),
expires_at timestamptz,
is_active boolean DEFAULT true
);
O formato da chave é pb_ seguido por 32 caracteres hexadecimais aleatórios:
// utils/apiKeyHelper.js
export function generateRawKey() {
const array = new Uint8Array(16);
crypto.getRandomValues(array);
return "pb_" + Array.from(array)
.map((b) => b.toString(16).padStart(2, "0"))
.join("");
}
export async function hashKey(rawKey) {
const encoder = new TextEncoder();
const data =O desenvolvimento de servidores MCP pode facilitar a integração de IA em aplicações brasileiras. A superação de desafios de autenticação é crucial para garantir a segurança dos dados dos usuários. Isso pode impactar a forma como as empresas utilizam agentes de IA em seus serviços.
Noticias relacionadas

Por que agentes de codificação de IA precisam de uma espinha de tarefas
O artigo discute a necessidade de uma estrutura que permita que agentes de IA mantenham o contexto entre sessões de programação, evitando a repetição de decisões e tarefas. A solução proposta é o Shinobi, um servidor MCP que registra e recupera informações relevantes.
A liquidação atômica protege o comércio. Nada ainda protege a escolha do contraparte.
A liquidação atômica garante a segurança das transações, mas não aborda a seleção de contrapartes. Com a autonomia dos agentes de IA, a verificação de contrapartes se torna crítica, exigindo um diretório de contrapartes verificáveis.

MCP é uma Camada de Transporte Fingindo Ser um Cérebro
O artigo discute os problemas da explosão do MCP, destacando a falta de governança e roteamento orçamentário, resultando em loops infinitos e desperdício de créditos. A solução proposta é uma camada entre agentes e ferramentas para otimizar chamadas de API.
Gostou do conteudo?
Receba toda semana as principais novidades sobre WebMCP.