Introdução: o que você vai ter ao final deste guia

Imagine que você abre um chat com um assistente de IA e escreve: «Acesse a página de um concorrente, colete os nomes e preços de todos os produtos do catálogo e monte uma tabela». O assistente não responde «não tenho acesso à internet», mas realmente baixa a página, extrai os dados e entrega o resultado pronto. É exatamente isso que você vai construir ao seguir este guia até o fim. O elo entre o modelo de linguagem e a web será o seu próprio servidor MCP, escrito em Python.

Um aviso importante: não vamos analisar o Playwright MCP pronto nem outras soluções de prateleira. Sobre isso existem materiais separados no blog. Aqui a tarefa é outra: escrever um servidor do zero, para que você entenda cada linha, possa adicionar suas próprias ferramentas, conectar proxies móveis e adaptar a lógica a tarefas específicas. Uma solução própria é sempre mais flexível do que a de terceiros.

Para quem é este guia

  • Profissionais de marketing e donos de negócio que precisam coletar rapidamente preços, avaliações, descrições de produtos e conteúdo de concorrentes, sem encomendar um scraper a um desenvolvedor.
  • Afiliados e profissionais de arbitragem que monitoram ofertas, landing pages e criativos e querem delegar a rotina a um agente de IA.
  • Desenvolvedores que já ouviram falar do protocolo MCP, mas ainda não montaram seu próprio servidor e querem um template funcional.
  • Usuários de proxies móveis para quem é importante que as requisições do agente saiam pelos seus proxies, e não diretamente do IP residencial.

O que você precisa saber antes

O guia é voltado para iniciantes. Não é obrigatório ter experiência em programação, mas ajuda entender o que é o terminal e como abrir um arquivo em um editor de texto. Todo o código pode ser copiado inteiro, e cada parte dele é explicada em linguagem simples. Se você já programa em Python, há um bloco separado com recursos avançados mais perto do final do artigo.

Quanto tempo vai levar

Reserve 2-3 horas para a primeira passada. A instalação das ferramentas leva cerca de 30 minutos, um servidor MCP mínimo e funcional aparece em uma hora, e o tempo restante será gasto adicionando ferramentas de extração de dados, conectando o proxy e testando. Repetir tudo do zero em outro computador você conseguirá em 20-30 minutos.

Preparação prévia: ferramentas, acessos e requisitos de sistema

Antes de escrever código, verifique se você tem tudo o que precisa. Esta seção pode ser concluída em meia hora e vai evitar metade dos problemas típicos nas etapas seguintes.

Requisitos de sistema

  • Computador com Windows 10/11, macOS 12 ou superior, ou Linux (Ubuntu 22.04 ou superior). Tudo o que descrevemos funciona em qualquer um desses sistemas, as diferenças estão apenas nos caminhos dos arquivos.
  • No mínimo 4 GB de memória RAM e 1 GB de espaço livre em disco.
  • Acesso estável à internet.

O que instalar

  1. Python 3.11 ou superior. Em 2026, as versões atuais são a 3.12 e a 3.13. Baixe o instalador no site oficial do projeto Python. No Windows, na primeira tela do instalador, marque obrigatoriamente a opção Add python.exe to PATH, caso contrário o comando python não será encontrado no terminal. No macOS é mais prático instalar o Python via Homebrew com o comando brew install python. No Ubuntu, execute sudo apt install python3 python3-venv python3-pip.
  2. Editor de texto para código. Recomendamos o Visual Studio Code. É gratuito, destaca a sintaxe e mostra erros. Qualquer outro editor serve, até o Bloco de Notas, mas com o VS Code será mais confortável.
  3. Cliente MCP, ou seja, um aplicativo com agente de IA ao qual você vai conectar o servidor. A opção mais simples para iniciantes é o Claude Desktop. Também suportam MCP o editor Cursor, o VS Code com a extensão GitHub Copilot e várias outras ferramentas. Instale pelo menos um deles antes de começar.
  4. Node.js 20 ou superior. Ele não é necessário para o servidor em si, mas para o utilitário MCP Inspector, com o qual vamos depurar as ferramentas. Baixe o instalador da versão LTS no site oficial do Node.js e instale com as configurações padrão.

Acessos

Para a seção sobre proxy, você vai precisar dos dados do seu proxy móvel: host, porta, login e senha, além do link para trocar o endereço IP, se o seu plano suportar. Tudo isso está na área do cliente do provedor. Se você ainda não tem proxy, pode seguir o guia sem ele: o servidor funcionará diretamente e você adicionará o proxy depois com uma linha.

Backups

Vamos editar o arquivo de configuração do cliente MCP. Antes disso, copie-o para um local seguro, por exemplo na área de trabalho com a marcação «backup». Se algo der errado, basta devolver a cópia ao lugar. Guarde o código do servidor em uma pasta separada e, após cada etapa funcional, salve uma cópia do arquivo ou faça um commit no Git, se você souber usá-lo.

Dica: Crie no disco uma pasta separada com caminho curto, sem espaços e sem caracteres cirílicos, por exemplo C:/mcp-collector no Windows ou ~/mcp-collector no macOS e Linux. Espaços e letras acentuadas ou caracteres especiais nos caminhos frequentemente quebram a inicialização de servidores a partir de configurações, e você gastará uma hora procurando a causa.

Conceitos básicos: como funciona um servidor MCP e por que ele é útil para um agente de IA

Antes de escrever a primeira linha de código, vamos entender os termos. Sem isso, a instrução vai parecer um conjunto de feitiços mágicos; com isso, cada ação se torna lógica.

O que é MCP

MCP (Model Context Protocol) é um protocolo aberto que descreve como um modelo de linguagem se comunica com ferramentas externas. Antes do seu surgimento, cada serviço inventava sua própria forma de «dar mãos à IA». O MCP padronizou isso: se você escreveu um servidor seguindo o protocolo, qualquer cliente compatível vai entendê-lo, seja o Claude Desktop, o Cursor ou o seu próprio agente. Dá para comparar o MCP a uma porta USB: não importa o que você conecta, um pendrive ou um mouse, o conector é o mesmo.

Cliente e servidor

Na arquitetura MCP há dois participantes. O cliente é o aplicativo com IA que faz perguntas e chama ferramentas. O servidor MCP é o programa que fornece essas ferramentas. No nosso caso, o servidor será a habilidade de «acessar a internet e obter dados», e o cliente será o seu assistente de IA. O servidor é executado localmente no seu computador, e o cliente se comunica com ele diretamente.

Ferramentas, recursos e prompts

Um servidor MCP pode entregar ao cliente três tipos de entidades:

  • Ferramentas (tools) — funções que o modelo pode chamar: «baixe a página», «extraia todos os links», «troque o IP do proxy». Essa é a base do nosso guia.
  • Recursos (resources) — dados que o servidor disponibiliza para leitura, por exemplo o conteúdo de um arquivo de configurações ou o resultado da última coleta.
  • Prompts — modelos prontos de requisições que o usuário pode acionar com um único comando.

Para coleta de dados, as ferramentas bastam. Recursos e prompts serão abordados no bloco avançado.

Como o modelo entende o que chamar

Aqui há um detalhe importante. Quando o cliente se conecta ao servidor, ele solicita a lista de ferramentas com seus nomes, descrições e parâmetros. Essas descrições entram no contexto do modelo. Depois, o próprio modelo decide qual ferramenta chamar e com quais argumentos, apoiando-se justamente no texto da descrição. Por isso, as descrições das funções no nosso código não são formalidade, mas instrução para a IA. Quanto mais claramente você escrever o que a ferramenta faz e quando usá-la, mais preciso será o trabalho do agente.

Transporte: stdio e HTTP

Servidor e cliente precisam trocar mensagens de alguma forma. O protocolo prevê dois modos principais. O stdio — o cliente inicia seu script como processo filho e se comunica com ele pela entrada e saída padrão. É a opção mais simples para uso local, e é por ela que vamos começar. O Streamable HTTP — o servidor funciona como serviço web, ao qual o cliente se conecta por um endereço. Essa opção é necessária se o servidor ficar em uma máquina remota ou se vários clientes se conectarem a ele. Vamos abordá-la no bloco avançado.

⚠️ Atenção: No transporte stdio, toda a saída padrão do processo está ocupada por mensagens de serviço do protocolo. Se você escrever um print comum no código para depurar, o cliente receberá lixo em vez de uma resposta correta e encerrará a conexão. Mensagens de depuração só podem sair pelo fluxo de erros stderr. Memorize essa regra, ela vai economizar muito tempo.

Por que a coleta de dados via MCP é prática

Um scraper clássico é rígido: ele sabe coletar campos específicos de um site específico. Assim que o layout muda, o scraper quebra. A combinação «agente de IA mais servidor MCP» funciona de outra forma: o servidor fornece ferramentas universais (baixar, extrair texto, encontrar elementos por seletor), e o modelo entende por conta própria a estrutura da página e formula o resultado. Você ganha flexibilidade sem reescrever o código para cada nova fonte.

Passo 1: Criando o projeto e instalando as dependências

Objetivo da etapa: preparar um ambiente Python isolado e instalar as bibliotecas necessárias para o servidor MCP. Ao final do passo, você terá uma pasta de projeto com um ambiente virtual funcional.

Por que precisamos de um ambiente virtual

Um ambiente virtual é uma cópia separada do Python com suas próprias bibliotecas dentro da pasta do projeto. Ele é necessário para que o nosso servidor não entre em conflito com outros programas Python do computador, e para que o cliente MCP saiba exatamente qual interpretador iniciar. Sem ele, metade dos problemas do tipo «no meu terminal funciona, mas no cliente não» é garantida.

Instruções passo a passo

  1. Abra o terminal. No Windows pressione Win+R, digite powershell e pressione Enter. No macOS abra o aplicativo Terminal pelo Spotlight (Cmd+Espaço, depois digite Terminal). No Linux pressione Ctrl+Alt+T.
  2. Crie a pasta do projeto e entre nela. No Windows execute dois comandos: mkdir C:/mcp-collector, depois cd C:/mcp-collector. No macOS e Linux: mkdir ~/mcp-collector, depois cd ~/mcp-collector.
  3. Verifique a versão do Python com o comando python --version (no macOS e Linux pode ser necessário python3 --version). Você deve ver algo como Python 3.12.x. Se a versão for inferior à 3.11 ou o comando não for encontrado, volte à seção de preparação e reinstale o Python.
  4. Crie o ambiente virtual com o comando python -m venv .venv. Uma pasta oculta .venv aparecerá na pasta do projeto. Isso leva de 10 a 20 segundos.
  5. Ative o ambiente. No Windows, no PowerShell: .venv/Scripts/Activate.ps1. Se o PowerShell informar que a execução de scripts está proibida, execute o comando Set-ExecutionPolicy -Scope CurrentUser RemoteSigned, confirme com Y e repita a ativação. No macOS e Linux: source .venv/bin/activate. Após a ativação, aparecerá a marca (.venv) no início da linha do terminal.
  6. Atualize o gerenciador de pacotes: python -m pip install --upgrade pip.
  7. Instale as bibliotecas com um único comando: pip install "mcp[cli]" httpx beautifulsoup4. Aqui mcp é o SDK oficial Python do protocolo (em 2026, a linha atual é a 1.x), httpx é a biblioteca moderna para requisições HTTP com suporte a proxy, beautifulsoup4 é a ferramenta para analisar HTML. A instalação leva de 1 a 2 minutos.
  8. Crie um arquivo vazio server.py na pasta do projeto. No VS Code: abra a pasta por File, Open Folder, depois clique no ícone de novo arquivo no painel da esquerda e digite o nome.

O que significam essas bibliotecas

  • mcp assume todo o protocolo: registro de ferramentas, troca de mensagens, descrição de parâmetros. O módulo FastMCP dentro dele permite declarar uma ferramenta como uma função comum com um decorador.
  • httpx baixa as páginas. Diferente do antigo requests, ele suporta HTTP/2, assincronismo e configuração prática de proxy.
  • beautifulsoup4 transforma o HTML em uma árvore onde é fácil buscar elementos por tags e seletores CSS.

Dica: Memorize já o caminho completo para o interpretador dentro do ambiente virtual. No Windows é C:/mcp-collector/.venv/Scripts/python.exe, no macOS e Linux é /Users/nome/mcp-collector/.venv/bin/python (ou /home/nome/... no Linux). Ele será necessário ao conectar ao cliente. Para saber o caminho exato, use o comando where python no Windows ou which python no macOS e Linux com o ambiente ativado.

✅ Verificação: Execute o comando pip list. A lista deve conter os pacotes mcp, httpx e beautifulsoup4. Execute também python -c "import mcp, httpx, bs4; print('ok')" — a resposta deve ser a palavra ok sem erros.

Possíveis problemas

  • Comando python não encontrado. No Windows, reinstale o Python marcando Add to PATH. No macOS, use python3 em vez de python.
  • pip reclama de permissões. Provavelmente o ambiente não está ativado e você está instalando pacotes no Python do sistema. Verifique a marca (.venv) no início da linha.
  • Erro de compilação na instalação. Atualize o pip e tente novamente. Se não resolver, verifique se a versão do Python é 3.11 ou superior.

Passo 2: Escrevendo um servidor MCP mínimo com a primeira ferramenta

Objetivo da etapa: escrever um servidor MCP funcional com uma ferramenta que baixa uma página por endereço e retorna seu HTML. Essa é a base sobre a qual vamos acrescentar funções.

Código do servidor

Abra o arquivo server.py e cole o seguinte código inteiro:

import sys
import httpx
from mcp.server.fastmcp import FastMCP

mcp = FastMCP('web-collector')

HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36',
'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8',
}

def log(message: str) -> None:
print(message, file=sys.stderr)

@mcp.tool()
def fetch_page(url: str, max_chars: int = 20000) -> str:
'''Скачивает страницу по указанному URL и возвращает её HTML-код.
Используй, когда нужно посмотреть исходную разметку страницы.
Параметр max_chars ограничивает длину ответа, чтобы не переполнять контекст.'''
log(f'fetch_page: {url}')
with httpx.Client(headers=HEADERS, timeout=20.0, follow_redirects=True) as client:
response = client.get(url)
response.raise_for_status()
return response.text[:max_chars]

if __name__ == '__main__':
mcp.run()

Análise do código linha por linha

  1. FastMCP('web-collector') cria o objeto do servidor com o nome web-collector. Esse nome o cliente mostrará na lista de servidores conectados.
  2. HEADERS são os cabeçalhos que enviamos aos sites. Muitos sites retornam conteúdo incompleto ou erro se a requisição chega sem um User-Agent de navegador habitual. O cabeçalho Accept-Language indica que queremos a versão em russo da página.
  3. A função log escreve mensagens no stderr. É assim, e não com um print comum, porque o stdout está ocupado pelo protocolo. Essas mensagens você verá nos logs do cliente e no MCP Inspector.
  4. @mcp.tool() é o decorador que transforma uma função comum em ferramenta MCP. O SDK lê automaticamente o nome da função, os tipos dos parâmetros e a docstring, e monta a descrição para o modelo. O valor padrão max_chars = 20000 significa que o parâmetro é opcional.
  5. A docstring entre aspas triplas é o que a IA vai ler. Aqui explicamos o que a ferramenta faz e quando aplicá-la. Escreva essas descrições com detalhe e no idioma em que você conversa com o agente.
  6. httpx.Client com o parâmetro follow_redirects=True passa automaticamente pelos redirecionamentos, e timeout=20.0 impede que a requisição fique pendurada indefinidamente.
  7. raise_for_status() lança um erro se o site retornar código 4xx ou 5xx. O SDK vai capturá-lo e devolver ao cliente uma mensagem de erro compreensível em vez de silêncio.
  8. mcp.run() inicia o servidor com o transporte stdio por padrão. Ele ficará aguardando comandos do cliente.

Primeira verificação com o MCP Inspector

Iniciar o server.py diretamente não adianta: ele ficará aguardando mensagens do cliente e não mostrará nada. Para testar, usamos o MCP Inspector — uma interface web que simula o cliente e permite chamar as ferramentas manualmente.

  1. Confirme que o ambiente virtual está ativado e que você está na pasta do projeto.
  2. Execute o comando mcp dev server.py. Esse comando faz parte do pacote mcp com a extensão cli que você instalou. Na primeira execução, ele baixará o Inspector via npx, o que levará cerca de um minuto.
  3. No terminal aparecerá um endereço como http://localhost:6274 e, nas versões novas, um token de acesso. Abra o endereço no navegador (muitas vezes ele abre sozinho).
  4. No painel esquerdo do Inspector, verifique se o transporte selecionado é STDIO, o comando é python e os argumentos são server.py. Clique no botão Connect.
  5. O indicador de status ficará verde com a legenda Connected. Vá para a aba Tools no menu superior e clique em List Tools.
  6. Na lista aparecerá a ferramenta fetch_page com a descrição da docstring e dois parâmetros. Clique nela.
  7. No campo url, digite https://example.com, deixe o campo max_chars vazio ou digite 5000. Clique em Run Tool.
  8. À direita aparecerá o resultado: o código HTML da página, começando com a tag doctype. Embaixo, na aba com os logs do servidor, você verá a linha fetch_page: https://example.com.

✅ Verificação: o Inspector mostra o status Connected, na lista Tools há fetch_page, e a chamada com o endereço example.com retorna HTML sem erros. Se estiver assim, seu primeiro servidor MCP está funcionando.

Possíveis problemas

  • mcp dev diz que npx não foi encontrado. O Node.js não está instalado. Instale-o e reinicie o terminal.
  • O Inspector abriu, mas o Connect dá erro. Verifique se no campo de comando está indicado o python do ambiente ativado. Você pode digitar o caminho completo para o python.exe dentro de .venv.
  • Erro SyntaxError ao conectar. O código foi colado com perda de indentação. Em Python a indentação é obrigatória: o corpo das funções é deslocado em quatro espaços. Verifique o arquivo no editor.
  • A ferramenta retorna erro 403. O site não aceitou a requisição. Para o example.com isso não acontece, mas para sites reais voltaremos a esse ponto no passo sobre proxy.

Passo 3: Conectando o servidor MCP ao cliente de IA

Objetivo da etapa: registrar o servidor nas configurações do cliente de IA, para que o agente veja a sua ferramenta e possa chamá-la de um chat comum. Vamos abordar a conexão ao Claude Desktop como a opção mais comum e mostrar brevemente as alternativas.

Conexão ao Claude Desktop

  1. Abra o Claude Desktop. Vá para as configurações: no Windows pelo menu no canto superior esquerdo, item Settings; no macOS pelo menu Claude, item Settings.
  2. Vá para a aba Developer e clique no botão Edit Config. Será aberta a pasta com o arquivo claude_desktop_config.json. Se o arquivo não existir, o cliente o criará.
  3. Faça um backup desse arquivo, copiando-o para a área de trabalho.
  4. Abra o arquivo no VS Code ou em outro editor. Se o arquivo estiver vazio, cole o conteúdo inteiro. Se já houver outros servidores nele, adicione o seu bloco dentro do objeto mcpServers, separado por vírgula.
{
"mcpServers": {
"web-collector": {
"command": "C:/mcp-collector/.venv/Scripts/python.exe",
"args": ["C:/mcp-collector/server.py"]
}
}
}

No macOS e Linux, substitua os caminhos pelos seus, por exemplo /Users/ivan/mcp-collector/.venv/bin/python e /Users/ivan/mcp-collector/server.py. Observe: mesmo no Windows os caminhos estão escritos com barras normais. Assim é mais simples, porque barras invertidas no JSON precisam ser duplicadas, e o Windows entende as barras normais sem problemas.

  1. Salve o arquivo. Verifique se não há vírgulas extras após o último elemento e se todas as chaves estão fechadas. Uma vírgula a mais torna o JSON inválido, e o cliente ignorará a configuração silenciosamente.
  2. Feche totalmente o Claude Desktop e abra novamente. No Windows, fechar a janela não basta: clique com o botão direito no ícone da bandeja do sistema e escolha Quit. O cliente só lê a configuração na inicialização.
  3. Após abrir, vá para um novo chat. Abaixo do campo de entrada, encontre o ícone de ferramentas (símbolo de controles ou conector). Clique nele: na lista deve estar o servidor web-collector com uma ferramenta fetch_page.
  4. Escreva no chat: «Baixe a página https://example.com usando fetch_page e diga qual é o título dessa página». O cliente pedirá permissão para chamar a ferramenta. Clique em Allow ou Allow for this chat.
  5. Em alguns segundos o agente responderá que o título da página é Example Domain. Ele fez uma requisição real através do seu servidor.

Conexão ao Cursor e ao VS Code

No Cursor, abra Settings, seção MCP, clique em Add new global MCP server. Será aberto o arquivo mcp.json com a mesma estrutura do Claude Desktop. Cole o mesmo bloco e salve. No VS Code com Copilot, crie na raiz da pasta de trabalho o arquivo .vscode/mcp.json, onde em vez da chave mcpServers usa-se a chave servers, e dentro dela os mesmos command e args. Após salvar, aparecerá um botão Start acima do bloco do servidor. Em todos os clientes o princípio é o mesmo: indicar o comando de inicialização do interpretador e o caminho para o script.

Dica: Indique no command exatamente o python do ambiente virtual, e não apenas a palavra python. O cliente inicia o processo com seu próprio conjunto de variáveis de ambiente, e o comando python do sistema pode ser outra versão sem as bibliotecas instaladas. O caminho completo elimina esse problema de vez.

✅ Verificação: Na interface do cliente, o servidor web-collector está visível, o agente chama fetch_page quando solicitado e resume corretamente o conteúdo da página example.com. Nos logs do cliente (no Claude Desktop é a pasta logs ao lado da configuração, arquivo mcp-server-web-collector.log) aparece a linha fetch_page: https://example.com.

Possíveis problemas

  • O servidor não apareceu na lista. Verifique a validade do JSON: cole o conteúdo em qualquer validador de JSON online ou abra no VS Code, que vai sublinhar os erros. Confirme que o cliente foi totalmente reiniciado.
  • Há um indicador vermelho de erro ao lado do servidor. Abra o arquivo de log. Na maioria das vezes há um ModuleNotFoundError: o python indicado é o errado. Verifique o caminho no command.
  • O agente diz que não consegue acessar a internet. Ele não viu a ferramenta. Confirme que as ferramentas estão ativadas no painel de controles e peça explicitamente: «use a ferramenta fetch_page».
  • Erro spawn ENOENT. O caminho para o python ou para o server.py está incorreto. Copie o caminho do explorador de arquivos e substitua as barras invertidas por barras normais.

Passo 4: Adicionando ferramentas de extração de dados

Objetivo da etapa: ensinar o servidor a entregar, em vez de HTML bruto, dados úteis: texto limpo, lista de links e elementos por seletor CSS. Depois disso, o agente conseguirá coletar informação estruturada sem gastar contexto com a marcação.

Por que só o fetch_page não basta

O HTML de uma página real pesa centenas de kilobytes, e a maior parte são scripts, estilos e marcação de serviço. Se entregarmos tudo ao modelo de cada vez, ele logo esbarrará no limite de contexto, e você pagará por tokens extras. A estratégia correta é: o servidor faz a limpeza e a estruturação bruta, e o modelo trabalha com dados compactos. Por isso vamos adicionar três ferramentas especializadas.

Código atualizado

Substitua o conteúdo do server.py pela versão ampliada. A função fetch_page continua, mas a lógica comum de download foi extraída para uma função separada _get_html, que todas as ferramentas usam.

import sys
from urllib.parse import urljoin
import httpx
from bs4 import BeautifulSoup
from mcp.server.fastmcp import FastMCP

mcp = FastMCP('web-collector')

HEADERS = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36',
'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8',
}

def log(message: str) -> None:
print(message, file=sys.stderr)

def _get_html(url: str) -> str:
log(f'GET {url}')
with httpx.Client(headers=HEADERS, timeout=20.0, follow_redirects=True) as client:
response = client.get(url)
response.raise_for_status()
return response.text

def _clean(text: str) -> str:
return ' '.join(text.split())

@mcp.tool()
def fetch_page(url: str, max_chars: int = 20000) -> str:
'''Возвращает сырой HTML страницы. Используй только когда нужна именно разметка,
например чтобы подобрать CSS-селектор. Для чтения содержимого используй extract_text.'''
return _get_html(url)[:max_chars]

@mcp.tool()
def extract_text(url: str, max_chars: int = 15000) -> str:
'''Возвращает чистый текст страницы без скриптов, стилей и разметки.
Лучший выбор, когда нужно прочитать статью, описание товара или отзывы.'''
soup = BeautifulSoup(_get_html(url), 'html.parser')
for tag in soup(['script', 'style', 'noscript', 'svg', 'header', 'footer', 'nav']):
tag.decompose()
title = _clean(soup.title.get_text()) if soup.title else ''
body = _clean(soup.get_text(' '))
return f'Заголовок: {title}. Текст: {body}'[:max_chars]

@mcp.tool()
def extract_links(url: str, limit: int = 100, contains: str = '') -> list[dict]:
'''Возвращает список ссылок со страницы: текст ссылки и полный адрес.
Параметр contains фильтрует ссылки, в адресе которых есть указанная подстрока,
например /product/ или /catalog/.'''
soup = BeautifulSoup(_get_html(url), 'html.parser')
result = []
seen = set()
for a in soup.find_all('a', href=True):
full = urljoin(url, a['href'])
if full in seen or (contains and contains not in full):
continue
seen.add(full)
result.append({'text': _clean(a.get_text())[:120], 'url': full})
if len(result) >= limit:
break
return result

@mcp.tool()
def select_elements(url: str, css_selector: str, limit: int = 50) -> list[str]:
'''Находит на странице элементы по CSS-селектору и возвращает их текст.
Примеры селекторов: h2, .price, div.product-card, table tr.
Используй, когда нужны конкретные повторяющиеся блоки: цены, названия, строки таблицы.'''
soup = BeautifulSoup(_get_html(url), 'html.parser')
elements = soup.select(css_selector)[:limit]
return [_clean(el.get_text(' ')) for el in elements]

if __name__ == '__main__':
mcp.run()

O que cada ferramenta faz

  1. extract_text remove do documento scripts, estilos, cabeçalho, rodapé e menu, e junta o texto restante em uma linha com espaços simples. A função _clean, via split e join, elimina quebras e tabulações extras. No início da resposta é adicionado o título da página, para que o agente entenda imediatamente o que está vendo.
  2. extract_links coleta todas as tags a, transforma endereços relativos em absolutos com urljoin, remove duplicatas com o conjunto seen e permite filtrar links por substring. Assim o agente obtém em uma única chamada, por exemplo, todos os cards de produtos do catálogo.
  3. select_elements é a ferramenta mais poderosa. Ela recebe um seletor CSS e retorna o texto dos elementos encontrados. O agente pode primeiro olhar um trecho de HTML via fetch_page, entender que os preços estão na classe price, e então chamar select_elements com o seletor .price.

Repare nas docstrings: indicamos explicitamente ao modelo qual ferramenta escolher em cada situação. Isso melhora bastante a qualidade do trabalho do agente.

Como testar

  1. Execute mcp dev server.py e conecte no Inspector. Na lista Tools agora há quatro ferramentas.
  2. Chame extract_links com a url de qualquer site de notícias ou catálogo e o parâmetro contains igual a uma parte do endereço da seção. O resultado é uma lista de objetos com os campos text e url.
  3. Chame select_elements com o mesmo endereço e o seletor h2. Você obterá uma lista de títulos.
  4. Reinicie o Claude Desktop (não é preciso mudar a configuração, só o código mudou) e peça: «Colete da página inicial de tal site todos os títulos h2 e os links que levam à seção de notícias, e monte uma tabela».

Dica: Se você não sabe qual seletor usar, abra a página no navegador, pressione F12, escolha a ferramenta de seleção de elemento (ícone com seta no canto superior esquerdo do painel) e clique no bloco desejado. No código você verá a classe dele. Um seletor com ponto e nome da classe, por exemplo .product-title, geralmente funciona. Mais ainda: dá para simplesmente pedir ao agente: «baixe o HTML e escolha você mesmo o seletor para os preços».

✅ Verificação: As quatro ferramentas estão visíveis no Inspector e no cliente, extract_text retorna texto legível sem tags, extract_links retorna uma lista com endereços absolutos, e select_elements com o seletor h2 retorna os títulos.

Possíveis problemas

  • select_elements retorna lista vazia. Ou o seletor está errado, ou o conteúdo é carregado por JavaScript depois do carregamento da página. Verifique com fetch_page: se o HTML não tiver os dados necessários, o site os renderiza no lado do cliente. Para esses sites é preciso um motor de navegador, o que já é tema de outro artigo.
  • extract_text mostra caracteres estranhos. O site entrega uma codificação não padrão. Adicione após response.raise_for_status() a linha response.encoding = response.charset_encoding or 'utf-8'.
  • A resposta é cortada. Aumente o max_chars na chamada ou peça ao agente para solicitar a página em partes, por vários seletores.

Passo 5: Conectando proxies móveis e rotação de IP

Objetivo da etapa: direcionar todas as requisições do servidor MCP por um proxy móvel, adicionar uma ferramenta de troca de IP e de verificação do endereço atual. Depois disso, o agente trabalhará como um operador móvel, e não a partir do seu IP residencial ou corporativo.

Para que serve o proxy móvel na coleta de dados

Quando você coleta dados de um único endereço IP, os sites veem dezenas de requisições idênticas seguidas e começam a entregar captcha, conteúdo reduzido ou erro 429 «requisições demais». O proxy móvel resolve várias questões ao mesmo tempo. Primeiro, o endereço pertence a um operador móvel real, e esses endereços são compartilhados entre milhares de assinantes, então os sites os tratam com mais tolerância. Segundo, você pode trocar o IP por um link ou por temporizador, distribuindo a carga. Terceiro, você separa a atividade profissional do agente das suas sessões pessoais. Para o profissional de marketing, é também uma forma de ver o site como o vê um usuário móvel de uma região específica.

⚠️ Atenção: O proxy é uma ferramenta para o funcionamento estável e correto do coletor, e não para violar regras. Colete apenas dados publicamente acessíveis, respeite os termos de uso dos sites e o arquivo robots.txt, não crie carga excessiva e não colete dados pessoais sem base legal. A responsabilidade pelo uso da ferramenta é sua.

Instruções passo a passo

  1. Abra a área do cliente do seu provedor de proxies móveis e encontre os dados de conexão: host, porta, login, senha. Normalmente eles vêm em uma única linha no formato login:password@host:port. Copie ali também o link de troca de IP, se houver.
  2. No arquivo server.py, adicione no início, depois dos outros imports, a linha import os. Depois, abaixo do bloco HEADERS, adicione as configurações:
PROXY_URL = os.environ.get('MOBILE_PROXY_URL', '')
ROTATE_URL = os.environ.get('PROXY_ROTATE_URL', '')

def _client() -> httpx.Client:
kwargs = {'headers': HEADERS, 'timeout': 30.0, 'follow_redirects': True}
if PROXY_URL:
kwargs['proxy'] = PROXY_URL
return httpx.Client(**kwargs)
  1. Na função _get_html, substitua a linha com httpx.Client pela chamada _client(). Agora ela fica assim: with _client() as client. Todas as ferramentas passarão automaticamente pelo proxy.
  2. Adicione duas novas ferramentas antes da linha if __name__:
@mcp.tool()
def current_ip() -> str:
'''Показывает IP-адрес, с которого сервер сейчас выходит в интернет.
Используй, чтобы убедиться, что прокси подключён, или после смены IP.'''
with _client() as client:
return client.get('https://api.ipify.org').text.strip()

@mcp.tool()
def rotate_ip() -> str:
'''Запрашивает смену IP-адреса мобильного прокси через ссылку из личного кабинета.
Вызывай, если сайт начал отдавать ошибки 429 или капчу. После вызова подожди 5-10 секунд.'''
if not ROTATE_URL:
return 'Ссылка смены IP не настроена в переменной PROXY_ROTATE_URL'
response = httpx.get(ROTATE_URL, timeout=15.0)
log(f'rotate_ip: status {response.status_code}')
return f'Запрос смены IP отправлен, ответ прокси-сервиса: {response.status_code}'
  1. Passe os dados do proxy por variáveis de ambiente na configuração do cliente. De propósito, não colocamos login e senha no código, para não enviá-los acidentalmente a algum lugar junto com o arquivo. Abra o claude_desktop_config.json e complemente o bloco do servidor com a seção env:
{
"mcpServers": {
"web-collector": {
"command": "C:/mcp-collector/.venv/Scripts/python.exe",
"args": ["C:/mcp-collector/server.py"],
"env": {
"MOBILE_PROXY_URL": "http://login:password@proxy-host:port",
"PROXY_ROTATE_URL": "https://ссылка-смены-ip-из-кабинета"
}
}
}
}
  1. Substitua os valores reais no lugar de login, password, proxy-host e port. Se o provedor fornece proxy pelo protocolo SOCKS5, troque http:// por socks5:// e instale o pacote adicional com o comando pip install httpx[socks].
  2. Salve a configuração e reinicie o cliente totalmente.
  3. Peça ao agente: «Chame current_ip e diga qual é o nosso endereço. Depois chame rotate_ip, espere dez segundos e verifique o IP novamente». Os endereços devem ser diferentes.

Verificação com proxy pelo Inspector

O Inspector também consegue passar variáveis de ambiente. No painel esquerdo, expanda a seção Environment Variables, adicione MOBILE_PROXY_URL e PROXY_ROTATE_URL com seus valores, conecte e chame current_ip. A resposta deve coincidir com o IP que aparece na área do cliente do provedor.

Dica: Não chame rotate_ip antes de cada requisição. Na maioria dos provedores, a troca de IP leva alguns segundos, e requisições muito frequentes podem esbarrar no limite de trocas. A estratégia razoável é: trocar o endereço a cada 30-100 requisições ou apenas ao receber erros 429 e 403. É possível embutir essa lógica diretamente no _get_html, o que faremos no próximo passo.

✅ Verificação: A ferramenta current_ip retorna o endereço do proxy, e não o seu residencial. Após rotate_ip e uma pausa, o endereço muda. As ferramentas extract_text e extract_links continuam funcionando, e nos logs aparecem as linhas GET com os endereços das páginas.

Possíveis problemas

  • Erro 407 Proxy Authentication Required. Login ou senha incorretos, ou eles contêm caracteres especiais. Caracteres como @ ou : na senha precisam ser codificados: @ vira %40, : vira %3A.
  • Erro ConnectTimeout. Host ou porta incorretos, ou o seu IP não está na lista de permitidos na área do provedor, se o plano tiver essa vinculação.
  • current_ip mostra o seu próprio endereço. A variável de ambiente não chegou ao servidor. Verifique a grafia de MOBILE_PROXY_URL na configuração e confirme que o cliente foi reiniciado.
  • rotate_ip retorna status 429 ou mensagem de limite. Você está trocando o IP mais vezes do que o plano permite. Aumente o intervalo.

Passo 6: Tornando o servidor confiável: retentativas, atrasos, cache e limites

Objetivo da etapa: transformar o exemplo didático em uma ferramenta que não cai ao primeiro erro de rede, não bombardeia os sites com requisições e não estoura o contexto do modelo. Este é o último passo obrigatório antes do uso pleno.

O que adicionamos e por quê

  • Retentativas automáticas. Erros de rede acontecem. Em vez de devolver um erro imediatamente ao agente, tentaremos a requisição mais duas vezes com pausa.
  • Troca automática de IP em caso de bloqueio. Se o site responder 429 ou 403 e o link de rotação estiver configurado, o servidor troca o endereço sozinho e repete a requisição.
  • Atraso entre requisições. Um coletor educado não envia dezenas de requisições por segundo. Uma pausa de um a dois segundos reduz a carga no site e o risco de bloqueio.
  • Cache. O agente costuma solicitar a mesma página várias vezes com ferramentas diferentes. Um cache em memória por alguns minutos evita downloads repetidos.
  • Limite de tamanho. Não vamos baixar páginas maiores que alguns megabytes.

Código

Adicione no início do arquivo import time, e substitua a função _get_html por esta:

CACHE: dict[str, tuple[float, str]] = {}
CACHE_TTL = 300
REQUEST_DELAY = 1.5
MAX_BYTES = 3_000_000
_last_request = 0.0

def _get_html(url: str) -> str:
global _last_request
now = time.time()
cached = CACHE.get(url)
if cached and now - cached[0] < CACHE_TTL:
log(f'cache hit: {url}')
return cached[1]
last_error = None
for attempt in range(3):
wait = REQUEST_DELAY - (time.time() - _last_request)
if wait > 0:
time.sleep(wait)
try:
with _client() as client:
_last_request = time.time()
response = client.get(url)
if response.status_code in (403, 429) and ROTATE_URL:
log(f'status {response.status_code}, rotating ip')
httpx.get(ROTATE_URL, timeout=15.0)
time.sleep(8)
continue
response.raise_for_status()
if len(response.content) > MAX_BYTES:
raise ValueError(f'Страница слишком большая: {len(response.content)} байт')
html = response.text
CACHE[url] = (time.time(), html)
return html
except httpx.HTTPError as error:
last_error = error
log(f'attempt {attempt + 1} failed: {error}')
time.sleep(2 * (attempt + 1))
raise RuntimeError(f'Не удалось загрузить {url} после 3 попыток: {last_error}')

Como isso funciona

  1. O dicionário CACHE guarda, para cada endereço, o horário do download e o HTML. Se a página foi solicitada há menos de cinco minutos, retornamos a cópia salva, sem fazer requisição.
  2. Antes de cada requisição, calculamos quanto tempo passou desde a anterior e, se necessário, completamos a pausa até REQUEST_DELAY segundos.
  3. Ciclo de três tentativas. Em resposta 403 ou 429 com rotação configurada, o servidor troca o IP, espera oito segundos e tenta de novo. Em erros de rede, espera dois, quatro e seis segundos entre as tentativas.
  4. Se a página for maior que três megabytes, consideramos isso um erro: esses documentos não caberiam no contexto mesmo assim.
  5. Após três falhas, lançamos um erro compreensível com o endereço e o motivo. O agente receberá isso como texto e poderá avisar você ou tentar outro caminho.

Também recomendamos adicionar uma ferramenta para limpar o cache, para que o agente possa forçar a recarga de uma página:

@mcp.tool()
def clear_cache() -> str:
'''Очищает кэш загруженных страниц. Вызывай, если нужно получить свежую версию страницы.'''
count = len(CACHE)
CACHE.clear()
return f'Кэш очищен, удалено записей: {count}'

Dica: Vale a pena mover os valores de REQUEST_DELAY e CACHE_TTL para variáveis de ambiente, por analogia com o proxy, para alterá-los sem editar o código. Para monitoramento de preços, um atraso de dois a três segundos e cache de um minuto funcionam bem; para coleta de artigos, atraso de um segundo e cache de uma hora.

✅ Verificação: Chame extract_text para a mesma página duas vezes seguidas. Na segunda vez aparecerá a linha cache hit nos logs, e a resposta virá instantaneamente. Indique um domínio inexistente — em alguns segundos o agente receberá a mensagem «Не удалось загрузить... после 3 попыток», em vez de travar.

Possíveis problemas

  • NameError: ROTATE_URL não definido. A função _get_html está declarada acima do bloco com as configurações de proxy. Mova as configurações PROXY_URL e ROTATE_URL mais para cima no arquivo.
  • O agente reclama de lentidão. Isso é normal: os atrasos e a rotação de IP levam tempo. Se estiver com pressa, reduza REQUEST_DELAY para 0.5, mas lembre-se do risco de bloqueios.
  • A memória cresce. O cache guarda todas as páginas da sessão. Para sessões longas, adicione a limpeza de entradas mais antigas que o TTL a cada chamada ou limite o tamanho do dicionário.

Verificação do resultado: checklist do servidor MCP pronto

Passe pelo checklist e marque cada item. Se todos estiverem cumpridos, seu servidor MCP para coleta de dados está pronto para o trabalho real.

O que deve funcionar

  • O comando mcp dev server.py inicia sem erros, o Inspector conecta e mostra o status Connected.
  • Na lista de ferramentas estão presentes fetch_page, extract_text, extract_links, select_elements, current_ip, rotate_ip e clear_cache.
  • O servidor web-collector aparece no painel de ferramentas do cliente de IA sem indicador de erro.
  • O agente, a partir de um pedido em linguagem livre, escolhe sozinho a ferramenta adequada e a chama.
  • current_ip mostra o endereço do proxy móvel, e após rotate_ip o endereço muda.
  • Uma nova requisição da mesma página é entregue a partir do cache.
  • Um endereço inválido gera uma mensagem de erro compreensível, e não um travamento.

Teste complexo

  1. Escolha um site público com catálogo ou feed de artigos, cujos dados sejam permitidos para uso.
  2. Peça ao agente: «Abra a página inicial do site, encontre os links para a seção de catálogo, entre nos cinco primeiros cards, colete nome e preço e monte uma tabela com as colunas Nome, Preço, Link».
  3. Observe a cadeia de chamadas: o agente deve chamar extract_links com filtro, depois várias vezes select_elements ou extract_text, e no final montar a tabela.
  4. Confira algumas linhas manualmente, abrindo os cards no navegador. Os dados devem coincidir.

Indicadores de sucesso

A coleta de cinco cards leva no máximo 30-40 segundos, considerando os atrasos. Nos logs do cliente não há erros do tipo traceback. O agente não pergunta qual ferramenta usar, mas age sozinho. Se estiver assim, parabéns: você montou seu próprio servidor MCP e conectou o agente de IA à web.

Erros comuns ao criar um servidor MCP e como resolvê-los

Aqui estão reunidos os problemas que quase todo mundo enfrenta na primeira passada. O formato é: problema, causa, solução.

1. O servidor conecta no Inspector, mas não funciona no cliente

Causa: na configuração do cliente está indicado o python do sistema sem as bibliotecas instaladas ou o caminho para o arquivo está errado. Solução: informe o caminho completo para o python dentro do .venv e o caminho completo para o server.py, use barras normais e reinicie o cliente totalmente.

2. O cliente encerra a conexão logo após a inicialização

Causa: sobrou um print comum sem file=sys.stderr no código, e o fluxo de serviço stdout ficou poluído. Solução: substitua todos os print pela função log. Verifique também se as bibliotecas não escrevem no stdout: por exemplo, algumas barras de progresso fazem isso por padrão.

3. O agente não chama as ferramentas e responde com seu próprio conhecimento

Causa: as descrições das ferramentas são curtas ou vagas demais, e o modelo não entende quando aplicá-las. Solução: amplie as docstrings, adicione frases como «use quando...» e exemplos. Nas primeiras requisições, nomeie a ferramenta explicitamente.

4. Erro 403 ao baixar sites reais

Causa: o site não aceita requisições sem cabeçalhos de navegador ou vindas de um IP suspeito. Solução: verifique se os HEADERS estão sendo enviados, atualize o User-Agent para a versão atual de um navegador, conecte o proxy móvel e confirme que a rotação está funcionando.

5. select_elements retorna vazio mesmo com o seletor correto

Causa: os dados são carregados por JavaScript após o carregamento da página, e não estão no HTML original. Solução: verifique com fetch_page. Se os dados não estiverem lá, tente encontrar a API interna do site na aba Network do navegador: muitas vezes os cards chegam em formato JSON por um endereço separado, que pode ser solicitado diretamente com o mesmo extract_text.

6. Erro 407 ou ConnectTimeout ao trabalhar via proxy

Causa: credenciais incorretas, caracteres especiais não codificados na senha ou porta errada. Solução: copie novamente a linha de conexão da área do cliente, codifique os caracteres especiais, verifique o protocolo http ou socks5.

7. A configuração JSON não é aplicada

Causa: vírgula extra, aspas faltando ou barras invertidas nos caminhos. Solução: verifique o arquivo em um validador, substitua as barras invertidas por barras normais, confirme que não há vírgula após o último elemento.

8. O servidor funciona, mas os dados chegam em codificação errada

Causa: o site não indica a codificação nos cabeçalhos. Solução: defina response.encoding explicitamente ou use o atributo response.content com decodificação manual via decode('utf-8', errors='ignore').

Recursos adicionais: bloco para avançados

O servidor básico está pronto. Se você programa bem em Python e quer mais, aqui estão direções de evolução, cada uma delas realizável em uma noite.

Servidor remoto via Streamable HTTP

Para que o servidor funcione em uma máquina separada ou para que vários clientes se conectem a ele, substitua a última linha por mcp.run(transport='streamable-http'). Por padrão, o servidor subirá na porta 8000, e o endereço de conexão será http://endereco-da-maquina:8000/mcp. Na configuração do cliente, em vez de command e args, use a chave url com esse endereço. Nesse modo é possível escrever no stdout, mas é melhor manter o hábito de logar no stderr. Feche obrigatoriamente a porta para o mundo externo e adicione verificação de token no cabeçalho, caso o servidor esteja acessível fora da rede local.

Recursos e prompts

Um recurso com as configurações atuais ajudará o agente a entender o contexto de trabalho:

@mcp.resource('collector://settings')
def settings() -> str:
'''Текущие настройки сборщика.'''
return f'proxy: {"on" if PROXY_URL else "off"}, delay: {REQUEST_DELAY}, cache ttl: {CACHE_TTL}'

Um prompt define um cenário pronto que o usuário aciona com um único comando:

@mcp.prompt()
def price_monitor(url: str) -> str:
'''Сценарий мониторинга цен в каталоге.'''
return f'Открой {url}, собери ссылки на карточки товаров, зайди в каждую, вытащи название и цену и составь таблицу. Если увидишь ошибку 429, вызови rotate_ip и продолжи.'

Salvando resultados em arquivo

Adicione uma ferramenta save_csv que recebe uma lista de dicionários e um caminho de arquivo e grava os dados pelo módulo csv. O agente poderá não só coletar, mas também guardar os resultados em uma tabela que você abrirá no Excel. Limite o caminho de salvamento a uma única pasta, para que o agente não possa escrever em qualquer lugar do disco.

Assincronismo e coleta paralela

O FastMCP suporta funções assíncronas: declare a ferramenta com async def e use httpx.AsyncClient. Assim a ferramenta fetch_many poderá baixar dez páginas simultaneamente via asyncio.gather. Não se esqueça do semáforo que limita o número de requisições paralelas, e de que o atraso entre requisições, com paralelismo, deve ser calculado de outra forma.

Vários proxies e rotação inteligente

Se você tem vários proxies móveis para regiões diferentes, guarde-os em uma variável de ambiente como lista separada por vírgulas e adicione à ferramenta um parâmetro region. O servidor escolherá o proxy por região, e o agente poderá comparar preços que o site mostra a usuários de cidades diferentes. Essa é uma das tarefas mais demandadas por profissionais de marketing e arbitragem.

Empacotamento em Docker

Para rodar em um servidor, monte uma imagem baseada em python:3.12-slim, copie o server.py e o arquivo de dependências, instale os pacotes e defina o ponto de entrada com o transporte HTTP. Passe as variáveis de proxy na inicialização do contêiner, e não as incorpore na imagem.

⚠️ Atenção: Nunca publique código com logins, senhas e links de rotação em repositórios abertos. Mantenha-os apenas em variáveis de ambiente ou em um arquivo .env adicionado ao .gitignore. O vazamento do link de troca de IP permitirá que estranhos controlem o seu proxy.

FAQ: perguntas frequentes sobre a criação de um servidor MCP

É possível escrever um servidor MCP em outra linguagem que não Python?

Sim. Existem SDKs oficiais para TypeScript, Java, Kotlin, C# e outras linguagens. Os princípios são os mesmos: declarar ferramentas com descrições e iniciar o transporte. Python foi escolhido no guia pela simplicidade e pelo rico conjunto de bibliotecas para trabalhar com HTML.

É preciso ter plano pago do cliente de IA para trabalhar com MCP?

O Claude Desktop suporta servidores MCP locais mesmo no plano gratuito, mas com limites no número de mensagens. O Cursor e o VS Code também permitem conectar servidores. Verifique as condições atuais de cada cliente.

É obrigatório usar proxy?

Não, o servidor funciona diretamente também. O proxy é necessário quando o volume de requisições é notável, quando os sites são sensíveis à frequência de acessos ou quando é importante para você ver o conteúdo de uma região específica e de um IP móvel.

Como saber se as requisições realmente passam pelo proxy?

Chame a ferramenta current_ip e compare o endereço com o que aparece na área do cliente do provedor. Além disso, você pode pedir ao agente para carregar a página de um serviço de detecção de IP via extract_text.

Quantas ferramentas podem ser adicionadas a um servidor?

Tecnicamente quase não há limites, mas cada descrição ocupa espaço no contexto do modelo. A prática mostra que 5 a 15 ferramentas bem descritas funcionam melhor do que 50 ferramentas pequenas. Agrupe funções próximas por parâmetros.

Como atualizar o servidor sem reiniciar o cliente?

No transporte stdio, o cliente inicia o processo na abertura, então as mudanças no código só serão captadas após reiniciar o cliente. Em modo de desenvolvimento, é mais prático testar as alterações pelo Inspector e reiniciar o cliente ao final.

O que fazer se o site só entrega dados após a execução de JavaScript?

Nosso servidor trabalha com o HTML original e não verá esses dados. As opções são: encontrar a API interna do site na aba Network do navegador ou conectar um motor de navegador. O segundo caminho está descrito em materiais separados do blog; aqui o evitamos de propósito.

Como limitar o agente para que ele não acesse sites indesejados?

Adicione no _get_html uma verificação de domínio por lista de permissões ou bloqueios a partir de uma variável de ambiente, e retorne um erro compreensível para endereços proibidos. Isso é mais confiável do que confiar nas instruções do chat.

É possível usar um único servidor MCP em vários clientes ao mesmo tempo?

No transporte stdio, cada cliente inicia sua própria cópia do processo, e isso é normal: elas não interferem entre si, mas o cache também é separado. Para ter cache e proxy compartilhados, migre para o transporte HTTP do bloco avançado.

Conclusão: o que você fez e para onde ir a seguir

Vamos resumir. Você preparou o ambiente Python e instalou o SDK oficial do protocolo. Escreveu um servidor MCP do zero e entendeu como o modelo compreende as ferramentas pelas suas descrições. Conectou o servidor ao cliente de IA e viu como o agente baixa páginas sozinho. Adicionou ferramentas de extração de texto, links e elementos por seletores. Direcionou o tráfego por um proxy móvel com rotação de IP. Por fim, tornou o servidor resistente: retentativas, atrasos, cache e limites. Isso já não é um exemplo didático, mas uma ferramenta funcional para tarefas do dia a dia.

O que fazer depois? Comece a usar o servidor em cenários reais: monitoramento de preços de concorrentes, coleta de avaliações, verificação de landing pages, análise de conteúdo do seu nicho. Ao longo do caminho, você entenderá quais ferramentas faltam especificamente para você e as adicionará seguindo o modelo das existentes. Cada nova ferramenta é uma função com uma descrição clara, nada mais complicado.

O próximo nível é o bloco avançado: servidor remoto via HTTP, coleta paralela, trabalho com vários proxies por região e salvamento de resultados em tabelas. E quando você esbarrar em sites com conteúdo dinâmico, dê uma olhada nos artigos relacionados do blog sobre automação de navegador. O principal você já fez: seu agente de IA saiu para a web pelo seu próprio servidor MCP, e você controla totalmente como ele faz isso.