Construindo um Gerador de Posts para Blog com MCP, Nextra e LLMs
Updated on

Neste tutorial, criaremos uma solução técnica que permite conversar com um grande modelo de linguagem (LLM) e solicitar que ele gere conteúdo para seu blog baseado em Nextra. O conteúdo será escrito em MDX e automaticamente compromissoado ao repositório GitHub do seu blog como novos posts. Exploraremos duas implementações dessa integração Protocolo de Contexto de Modelo (MCP):
- Serverless via GitHub Actions: Usar um fluxo de trabalho do GitHub Actions para gerenciar todo o processo – invocando o LLM e comprometendo o artigo gerado.
- Hospedado via API Next.js: Implementar um servidor MCP simples como um endpoint de API do Next.js (usando o
jojocys/nextra-agent-blog
como exemplo de plataforma de blog) que atua como cliente MCP. Esse endpoint chamará o LLM e enviará novos posts ao GitHub em tempo real.
O MCP é um padrão aberto para conectar assistentes de IA a ferramentas e dados externos. Ele fornece uma interface universal para que modelos de IA interajam com sistemas como serviços em nuvem, bancos de dados – até plataformas como GitHub e Slack – sem necessidade de integração personalizada para cada ferramenta (Explicação do Protocolo de Contexto de Modelo (MCP) (opens in a new tab)). Em outras palavras, o MCP permite que agentes de IA usem “ferramentas” para realizar ações além de seu conhecimento base. Por exemplo, um assistente de IA poderia usar MCP para realizar tarefas como enviar e-mails, implantar mudanças no código ou publicar posts de blog (Construir e implantar servidores do Protocolo de Contexto de Modelo (MCP) na Cloudflare (opens in a new tab)). Aqui, nossa “ferramenta” será a capacidade de criar um novo arquivo MDX e comprometê-lo em um repositório Git (o blog).
Ao final deste guia, você terá uma configuração funcional onde você (como único usuário) poderá solicitar um artigo de blog a um agente de IA e tê-lo exibido automaticamente no seu site. Focaremos em como as peças se conectam (cliente MCP ↔︎ LLM e LLM ↔︎ GitHub) e consideraremos um cenário de usuário único, sem autenticação adicional.
Visão Geral da Solução
Antes de mergulhar no código, vamos delinear a arquitetura e o fluxo de trabalho:
-
Plataforma do Blog: Usamos um site em Next.js com o tema de blog Nextra (como o repositório
jojocys/nextra-agent-blog
) para hospedar nosso conteúdo. Posts são armazenados como arquivos MDX (Markdown com JSX) no repositório (por exemplo, na pastapages/posts
). O Nextra exibirá qualquer arquivo MDX nesta pasta como um post de blog, usando seus metadados (frontmatter: título, data, etc.) e conteúdo. -
LLM (Assistente de IA): Usaremos um modelo de IA (por exemplo, GPT da OpenAI ou Claude da Anthropic) para gerar o conteúdo do post do blog. O modelo receberá um prompt (possivelmente via interface de chat ou API) descrevendo o artigo a ser escrito, produzindo uma resposta em formato MDX.
-
Cliente & Servidor MCP: Em termos de MCP, o LLM atua como um host que pode chamar ferramentas externas via uma interface cliente-servidor. Implementaremos uma configuração MCP mínima:
- Na abordagem Serverless (GitHub Actions), o fluxo do GitHub Actions funciona como cliente MCP. Ele inicia a conversa com o LLM (host) e depois executa a “ferramenta de escrever post” comprometendo no repositório.
- Na abordagem API Next.js, criaremos uma rota de API personalizada que atua como tanto cliente quanto servidor MCP para nosso repositório de blog (fornecendo a ferramenta de criar commits). Essencialmente, esse endpoint será uma ponte entre o LLM e o GitHub.
-
Integração com GitHub: Ambas as abordagens usarão a API do GitHub para adicionar o novo post ao repositório. Isso pode ser feito via operações Git diretas ou API HTTP do GitHub. Veremos exemplos de ambos. (Vale notar que o ecossistema MCP da Anthropic já inclui um conector pré-construído ao GitHub que suporta operações de repositório (GitHub - modelcontextprotocol/servers (opens in a new tab)), mas aqui aprenderemos construindo por conta própria.)
Com este contexto, começaremos pelo método serverless do GitHub Actions.
Abordagem 1: Gerador de Posts com GitHub Actions sem servidor
Nessa abordagem, usamos um fluxo de trabalho do GitHub Actions para gerar e publicar posts de blog sob demanda. Isso significa que você não precisa rodar servidor dedicado – o GitHub criará um runner para executar os passos sempre que acionado. O fluxo de trabalho fará:
- Disparo: Você (o usuário) aciona o fluxo (manual ou por evento de disparo no repositório) e fornece um prompt ou tópico para o post.
- Invocação do LLM: O fluxo chama a API do LLM (OpenAI ou Claude) com um prompt solicitando um post em MDX sobre o tópico.
- Criação do arquivo: Captura a resposta do LLM (o conteúdo MDX) e salva como um arquivo
.mdx
novo na pasta de posts do repositório, incluindo um frontmatter YAML (título, data, etc.). - Commit no GitHub: O arquivo é comprometido e enviado ao branch principal, tornando o post ao vivo.
Vamos criar o arquivo de fluxo de trabalho. No seu repositório de blog (que usa Nextra), adicione em .github/workflows/llm-agent.yml
:
name: Gerador de Posts do Blog com LLM
# Disparador manual
on:
workflow_dispatch:
inputs:
prompt:
description: "Tópico ou prompt para o post do blog"
required: true
type: string
permissions:
contents: write # permite push no repositório
jobs:
gerar_post:
runs-on: ubuntu-latest
steps:
- name: Checar repositório
uses: actions/checkout@v3
- name: Instalar jq
run: sudo apt-get -y install jq
- name: Gerar conteúdo do blog com OpenAI
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
echo "Prompt: ${{ github.event.inputs.prompt }}"
REQUEST_DATA=$(jq -n --arg prompt "${{ github.event.inputs.prompt }}" '{
"model": "gpt-3.5-turbo",
"messages": [
{"role": "system", "content": "Você é um assistente de blogs técnico. Escreva um post MDX com frontmatter YAML (título, data, descrição, tipo: posts) sobre o tópico fornecido."},
{"role": "user", "content": $prompt}
]
}')
RESPONSE=$(curl -sS -H "Content-Type: application/json" \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-d "$REQUEST_DATA" \
https://api.openai.com/v1/chat/completions)
POST_CONTENT=$(echo "$RESPONSE" | jq -r '.choices[0].message.content')
TIMESTAMP=$(date +"%Y-%m-%d-%H%M")
FILENAME="posts/llm-post-$TIMESTAMP.mdx"
echo "Criando novo arquivo de post: $FILENAME"
echo "$POST_CONTENT" > $FILENAME
- name: Commitar e enviar
run: |
git config user.name "github-actions"
git config user.email "github-actions@users.noreply.github.com"
git add posts/*.mdx
git commit -m "Post gerado pelo LLM"
git push
Explicação rápida:
- Disparo manual que recebe o tópico do usuário
- Instala
jq
para processamento JSON - Chama a API do OpenAI com prompt customizado
- Extrai o conteúdo MDX gerado
- Cria um arquivo novo na pasta
posts/
com timestamp - Faz commit e push
Assim, ao rodar este workflow e fornecer um prompt, o sistema gerará e publicará um novo post automaticamente.
Como usar na prática
Na aba Actions do seu repositório, escolha o fluxo "Gerador de Posts do Blog" e clique em "Run workflow". Insira o tópico desejado (exemplo: "Explicação de como usar MCP em Next.js") e execute. Após alguns instantes, o novo arquivo aparecerá na pasta posts/
. Se seu blog estiver configurado para gerar páginas automaticamente (como com Vercel + Next.js), a nova postagem estará visível no site pouco tempo depois.
Segurança e limitações
- O API Key do OpenAI deve estar armazenado em Segredos do repositório (
OPENAI_API_KEY
) - O pipeline push direto ao branch principal é simples, mas para segurança você pode modificar para criar pull requests, revisões, etc.
- O conteúdo é gerado automaticamente e não passa por revisão humana – ajuste o prompt ou adicione moderação conforme necessário.
- Para Claude ou outros modelos, basta trocar a API e o payload do passo correspondente.
Abordagem 2: Servidor MCP hospedado via API Next.js
Outra alternativa é criar uma rota de API no seu Next.js que funcione como um servidor MCP. Essa rota receberia uma solicitação de um prompt, acionaria o LLM para gerar o MDX, e comprometeria o arquivo no repositório GitHub — tudo sob demanda, com uma interface web ou chat.
Como fazer:
- Configure suas chaves de API (
OPENAI_API_KEY
,GITHUB_PAT
) como variáveis de ambiente (.env.local
) - Crie uma API em
pages/api/generate-post.js
(ou no novo roteadorapp/api/...
) - No código, as funções que fazem a chamada ao LLM e ao GitHub serão similares às do exemplo acima, mas tudo em uma requisição HTTP.
Exemplo de implementação simples (Next.js):
import { Octokit } from "@octokit/rest";
import { Configuration, OpenAIApi } from "openai";
export default async function handler(req, res) {
const { prompt } = req.body;
if (!prompt) {
return res.status(400).json({ error: "Prompt não fornecido" });
}
try {
const openaiConfig = new Configuration({ apiKey: process.env.OPENAI_API_KEY });
const openai = new OpenAIApi(openaiConfig);
const chatRes = await openai.createChatCompletion({
model: "gpt-3.5-turbo",
messages: [
{ role: "system", content: "Você é um assistente técnico que escreve posts MDX com frontmatter YAML para blogs." },
{ role: "user", content: prompt }
]
});
const mdx = chatRes.data.choices[0].message.content;
// Opcional: extrair título do frontmatter para criar o nome do arquivo
const titleMatch = mdx.match(/^title:\s*\"?(.+)\"?/m);
const title = titleMatch ? titleMatch[1] : "sem-titulo";
const slug = title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/(^-|-$)/g, "");
const filename = `posts/${slug || "post"}-${Date.now()}.mdx`;
// Se desejar, inserir data e tipo no frontmatter se não tiver
let finalContent = mdx;
if (!/^date:/.test(mdx)) {
finalContent = finalContent.replace(/^title:.*$/m, `$&\ndate: ${new Date().toISOString()}`);
}
if (!/^type:/.test(mdx)) {
finalContent = finalContent.replace(/^title:.*$/m, `$&\ntype: posts`);
}
const octokit = new Octokit({ auth: process.env.GITHUB_PAT });
await octokit.rest.repos.createOrUpdateFileContents({
owner: process.env.GITHUB_REPO_OWNER,
repo: process.env.GITHUB_REPO_NAME,
path: filename,
message: `Post automatizado: "${title}"`,
content: Buffer.from(finalContent).toString("base64"),
committer: { name: "MCP", email: "mcp@example.com" },
author: { name: "MCP", email: "mcp@example.com" }
});
res.status(200).json({ mensagem: "Post criado", arquivo: filename });
} catch (err) {
console.error(err);
res.status(500).json({ erro: err.message });
}
}
Como usar:
- Faça uma requisição POST para
/api/generate-post
com JSON{"prompt": "Seu tema aqui"}
- A API chamará o LLM, criará o arquivo MDX e o comprometerá no GitHub
- O seu site se atualizará automaticamente ao reconhecer novo conteúdo
Vantagens:
- Pode integrar com uma interface web onde você conversa ou insere prompts
- Controla quando gerar/publicar o post
- Flexível e facilmente ajustável
Conclusão
Criamos um sistema que conecta um modelo de IA a um repositório de conteúdo, permitindo que a IA gere posts automaticamente e publique-os no seu blog. Apresentamos:
- Uma solução serverless usando GitHub Actions, ideal para automação simples e direta
- Uma solução hospedada via API Next.js, útil para interações mais dinâmicas
Ambas exemplificam a ideia do MCP — uma interface padronizada para que IA possa interagir com sistemas externos, como seu blog.
Você pode adaptar e expandir esses exemplos: ajustar os prompts, acrescentar revisão humana, usar outros provedores de LLMs ou criar novos ferramentas MCP. Assim, seu assistente de IA pode fazer muito mais, além de publicar posts!
Fontes:
- Anthropic, Introducing the Model Context Protocol (MCP) – Padrão aberto para conexões de IA com sistemas externos (Lacoste, 2024 (opens in a new tab))
- Cloudflare, Levar MCP às massas – MCP permite ações como publicação de posts via ferramentas externas (Cloudflare Blog (opens in a new tab))
- Repositório de Servidores MCP — inclui um servidor GitHub para operações de repositório (file management, API do GitHub) (GitHub - modelcontextprotocol/servers (opens in a new tab))