O Language Server Protocol (LSP) é para a edição de código o que o USB é para periféricos: um standard universal que permite a qualquer editor ter suporte nativo para qualquer linguagem. E no OpenCode, é o que dá ao teu agente de IA uma percepção sobre-humana do código que está a ler.

Imagina que estás a programar e o teu editor mostra-te erros a vermelho antes de sequer compilares. Ou que, ao fazeres hover sobre uma função, vês a sua assinatura, documentação e tipos esperados. Ou que o autocomplete te sugere exatamente o método que precisas, com os parâmetros certos, sem teres de decorar nada.

Essa magia toda chama-se Language Server Protocol (LSP). Foi criado pela Microsoft em 2016 para o VS Code, e rapidamente se tornou o standard da indústria. Hoje, todos os editores modernos o suportam: Emacs, Vim, Neovim, Sublime Text, Zed, Helix, e claro, o OpenCode. O LSP tem atualmente mais de 40.000 estrelas no GitHub no repositório da especificação, e dezenas de servidores de linguagem disponíveis.

Vou mostrar-te:

  • O que é o Language Server Protocol e a sua arquitetura cliente-servidor
  • Como o OpenCode usa LSP para autocomplete, diagnóstico, navegação e formatação
  • Como configurar servidores LSP no opencode.json
  • Um exemplo prático: LSP para TypeScript
  • Diferenças e complementaridade entre LSP e MCP
  • Dicas e boas práticas para tirares o máximo partido do LSP

LSP no OpenCode — Thumbnail

⬆ O OpenCode integra Language Server Protocol para dar inteligência ao agente de IA sobre o código


O que é o language server protocol?

O Language Server Protocol (LSP) é um protocolo de comunicação baseado em JSON-RPC 2.0 que standardiza a forma como os editores de código obtêm funcionalidades de inteligência de código: autocomplete, diagnóstico, navegação, refatoração, formatação: para qualquer linguagem de programação.

Antes do LSP, cada editor precisava de uma extensão específica para cada linguagem. O VS Code precisava de uma extensão para TypeScript, outra para Python, outra para Rust. Cada extensão era código diferente, com APIs diferentes, e um esforço de manutenção gigante.

A ideia do LSP é simples e genial: em vez de N linguagens × M editores (explosão combinatória), separa-se o cliente (editor) do servidor (análise da linguagem). O editor comunica com o servidor via JSON-RPC, e o servidor faz todo o trabalho pesado de análise sintática, semântica e type-checking.

Arquitetura LSP no OpenCode

⬆ Arquitetura LSP: OpenCode como cliente comunica com servidores de linguagem via JSON-RPC 2.0

Como funciona na prática:

  1. O editor (OpenCode, VS Code, Neovim) abre um ficheiro
  2. Deteta a extensão do ficheiro (ex: .ts) e inicia o servidor LSP correspondente (ex: typescript-language-server)
  3. O editor envia o conteúdo do ficheiro ao servidor via textDocument/didOpen
  4. O servidor analisa o código e responde com diagnósticos (erros, warnings), completions, etc.
  5. A comunicação é bidirecional e assíncrona: o servidor pode enviar atualizações sempre que o código muda

Nota: O LSP usa exclusivamente JSON-RPC 2.0 como protocolo de transporte, com mensagens request/response e notifications. Isto é exatamente o mesmo protocolo que o MCP usa: mas para um propósito completamente diferente. Ambas as equipas (Microsoft para LSP, Anthropic para MCP) escolheram JSON-RPC pela sua simplicidade e eficácia.


Como o OpenCode usa LSP

No OpenCode, o LSP não serve para mostrar um autocomplete numa UI (não há editor gráfico). Em vez disso, o LSP é usado para dar ao agente de IA uma compreensão profunda do código que está a analisar. O agente "vê" diagnósticos, tipos, referências e definições através do LSP, e usa essa informação para tomar decisões mais informadas.

O OpenCode atua como cliente LSP (não como servidor). Isto significa que ele inicia e comunica com servidores LSP externos (como o typescript-language-server, rust-analyzer, pyright, etc.), consumindo os dados que eles fornecem.

Capacidades LSP que o OpenCode usa:

Capacidade Request LSP O que o agente vê
Diagnóstico textDocument/publishDiagnostics Erros e warnings em tempo real, linha a linha
Autocomplete textDocument/completion Sugestões contextuais para completar código
Hover Info textDocument/hover Tipo, documentação e assinatura de símbolos
Go-to-Definition textDocument/definition Localização exata da definição de um símbolo
Find References textDocument/references Lista de todas as ocorrências de um símbolo
Code Actions textDocument/codeAction Sugestões de correção automática (ex: import em falta)
Formatação textDocument/formatting Código formatado segundo as regras do projeto
Signature Help textDocument/signatureHelp Parâmetros esperados por uma função

Quando o agente do OpenCode pede diagnósticos de um ficheiro, ele não está apenas a fazer cat ao ficheiro. Ele está a perguntar ao servidor LSP: "Há erros aqui? Que tipos estão a ser usados? O que posso melhorar?". O servidor responde com informação estruturada que o LLM pode processar e agir sobre ela.

Exemplo real: Quando pedes ao OpenCode "explica-me este ficheiro e encontra bugs", o agente primeiramente faz textDocument/publishDiagnostics para obter erros do LSP, depois pede textDocument/hover para inspecionar tipos, e só depois te responde com uma análise completa e contextualizada.


Instalação e configuração de lsps

O OpenCode tem LSP desativado por defeito. Para o ativar, precisas de configurar a secção lsp no teu opencode.json.

Ativar todos os servidores built-in:

{
  "$schema": "https://opencode.ai/config.json",
  "lsp": true
}
Copy

Com esta configuração, o OpenCode ativa todos os servidores LSP built-in para os quais encontra as dependências instaladas. Se tens o typescript no package.json, o servidor TypeScript é iniciado. Se tens o rust-analyzer no PATH, o servidor Rust é iniciado. E assim por diante.

Configuração granular (recomendada):

{
  "$schema": "https://opencode.ai/config.json",
  "lsp": {
    "typescript": {
      "command": ["typescript-language-server", "--stdio"],
      "extensions": [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"]
    },
    "rust": {
      "command": ["rust-analyzer"],
      "extensions": [".rs"]
    },
    "pyright": {
      "command": ["pyright-langserver", "--stdio"],
      "extensions": [".py", ".pyi"]
    },
    "gopls": {
      "command": ["gopls"],
      "extensions": [".go"]
    }
  }
}
Copy

Servidores LSP built-in do OpenCode:

O OpenCode vem com suporte para mais de 30 servidores LSP. Aqui estão os mais relevantes:

LSP Server Extensões Requisitos
typescript.ts, .tsx, .js, .jsx, .mjs, .cjsDependência typescript no projeto
rust (rust-analyzer).rsrust-analyzer no PATH
pyright.py, .pyipyright instalado (pip ou npm)
gopls.gogopls no PATH
bash (bash-language-server).sh, .bash, .zshAuto-instala via npm
lua-ls.luaAuto-instala para projetos Lua
zls (Zig).zig, .zonzig no PATH
clangd.c, .cpp, .h, .hppAuto-instala para projetos C/C++
elixir-ls.ex, .exselixir no PATH
jdtls (Java).javaJava SDK 21+
terraform.tf, .tfvarsAuto-instala do GitHub
svelte.svelteAuto-instala para projetos Svelte
vue.vueAuto-instala para projetos Vue
prisma.prismaprisma no PATH
php (intelephense).phpAuto-instala para projetos PHP
yamlls.yaml, .ymlAuto-instala o Red Hat yaml-language-server
deno.ts, .tsx, .js, .jsx, .mjsdeno no PATH + deno.json/deno.jsonc
oxlint.ts, .tsx, .js, .jsxDependência oxlint no projeto

Configurar variáveis de ambiente para LSP:

{
  "lsp": {
    "rust": {
      "command": ["rust-analyzer"],
      "env": {
        "RUST_LOG": "debug",
        "RUST_BACKTRACE": "1"
      }
    }
  }
}
Copy

Passar initialization options:

{
  "lsp": {
    "custom-lsp": {
      "command": ["custom-lsp-server", "--stdio"],
      "extensions": [".custom"],
      "initialization": {
        "preferences": {
          "importModuleSpecifierPreference": "relative"
        }
      }
    }
  }
}
Copy

Desativar servidores específicos:

{
  "lsp": {
    "typescript": {
      "disabled": true
    },
    "pyright": {
      "disabled": true
    }
  }
}
Copy

Adicionar servidores LSP personalizados:

{
  "lsp": {
    "texlab": {
      "command": ["texlab"],
      "extensions": [".tex", ".bib"]
    },
    "solargraph": {
      "command": ["solargraph", "stdio"],
      "extensions": [".rb"]
    }
  }
}
Copy

Exemplo prático: LSP para TypeScript

Vamos montar um exemplo real. Imagina que tens um projeto TypeScript com o seguinte ficheiro src/app.ts:

interface User {
  name: string;
  email?: string;
}

function greet(user: User) {
  return `Olá, ${user.name}!`;
}

const user: User = { name: "Fuzza" };
console.log(greet(user));

const count;
console.log(count.toUpperCase());
Copy

Com o LSP ativo, quando o agente do OpenCode analisa este ficheiro, ele recebe automaticamente:

Diagnósticos (erros e warnings):

  • linha 12:7: erro: 'count' is declared but its value is never read
  • linha 13:17: erro: Property 'toUpperCase' does not exist on type 'undefined'
  • linha 6:3: warning: Parameter 'user' implicitly has 'any' type (se strict mode)

Hover info sobre greet:

  • Assinatura: function greet(user: User): string
  • Documentação inline (se JSDoc estiver presente)

Autocomplete em user.:

  • name: string
  • email?: string | undefined

Code Actions disponíveis:

  • Adicionar tipo explícito ao count
  • Remover variável não utilizada

Isto significa que, mesmo antes de o agente responder, ele já sabe onde estão os erros, que tipos estão a ser usados, e o que pode ser melhorado. A resposta do agente é contextualizada e precisa: não é uma adivinhação.

Servidores LSP no OpenCode

⬆ OpenCode a mostrar diagnóstico LSP ativo e erros detetados no código

Dica: Usa opencode debug lsp para veres o estado atual dos teus servidores LSP: quais estão ativos, quais estão ociosos, e que extensões cada um cobre.


LSP vs MCP: dois protocolos que se complementam

Se leste o nosso guia sobre MCP, deves estar a pensar: "Mas o LSP não é basicamente a mesma coisa que o MCP?"

A resposta curta: não. Mas são complementares. O LSP e o MCP partilham a mesma base (JSON-RPC 2.0) e a mesma filosofia de protocolo aberto, mas servem propósitos fundamentalmente diferentes.

LSP vs MCP

⬆ LSP vs MCP: dois protocolos, dois mundos, um ecossistema

Dimensão LSP MCP
Criado porMicrosoft (2016)Anthropic (2024)
PropósitoInteligência de códigoContexto e ações para LLMs
ClienteEditor/IDE (VS Code, Neovim, OpenCode)Aplicação de IA (Claude, OpenCode, Cline)
ServidorPor linguagem (typescript-language-server)Por domínio (filesystem, github, sentry)
Transportestdio / TCPstdio / SSE / Streamable HTTP
MensagenstextDocument/completion, hovertools/list, tools/call, resources/read
IniciativaDo editor (abrir ficheiro → pedir dados)Do LLM (decidir usar ferramenta)
OutputErros, tipos, sugestões de códigoDados de APIs, ficheiros, ações
TimingContínuo (sempre ativo enquanto editas)Sob demanda (quando o LLM decide)
MaturidadeMaduro (9+ anos, 40k+ estrelas)Jovem (2 anos, 86k+ estrelas)

Como se complementam no OpenCode:

O LSP dá ao agente de IA uma compreensão profunda do código: "Aqui há um erro de tipo", "Esta função espera 3 parâmetros", "Este símbolo está definido neste ficheiro".

O MCP dá ao agente a capacidade de agir sobre o mundo exterior: "Lê este ficheiro", "Faz um commit", "Pesquisa na base de dados", "Cria um PR no GitHub".

No fundo, o LSP é o cérebro (compreensão) e o MCP é o músculo (ação). Um sem o outro é mais limitado; juntos, são uma combinação imbatível para assistência de código com IA.

Leitura recomendada: Vê o nosso guia completo sobre MCP para perceberes como configurar e criar os teus próprios servidores MCP. O LSP e o MCP são os dois pilares de qualquer setup sério de desenvolvimento assistido por IA.


Dicas e boas práticas

Depois de usar LSP com OpenCode no dia-a-dia, estas são as práticas que mais impacto tiveram na minha produtividade:

1. Ativa LSP por projeto, não globalmente

O LSP consome recursos: cada servidor é um processo separado. Num monorepo com TypeScript, Python e Rust, ter os três servidores ativos ao mesmo tempo pode consumir GB de RAM. Configura apenas os LSPs relevantes para cada projeto no opencode.json local.

// opencode.json (projeto TypeScript)
{
  "lsp": {
    "typescript": true
    // rust desativado, pyright desativado
  }
}
Copy

2. Usa opencode debug lsp para troubleshooting

Quando um servidor LSP não está a funcionar como esperado, o comando opencode debug lsp mostra-te o estado de cada servidor: ativo, ocioso, ou com erros. Também podes ver os logs de cada servidor para diagnosticar problemas de inicialização.

3. LSP vs CLI tools: escolhe a ferramenta certa

O LSP é excelente para feedback contínuo e em tempo real, mas para tarefas de verificação pontuais (como correr o type checker ou o linter), pode ser mais eficiente documentar comandos CLI no AGENTS.md. Por exemplo:

# Para verificar erros de tipo:
npm run typecheck

# Para lint:
npm run lint

# Para formatar:
npm run format
Copy

Isto permite ao agente executar verificações completas sob demanda, sem depender exclusivamente do LSP para tarefas que podem ser mais lentas ou inconsistentes.

4. Cuidado com servidores problemáticos

Alguns servidores LSP podem ter comportamentos inesperados: memory leaks, inicialização lenta, ou conflitos entre versões. Se notares que o OpenCode está lento ou a consumir demasiada RAM, verifica se há servidores LSP a acumular processos com ps aux | grep -i lsp.

O OpenCode pode lançar novos processos LSP sem limpar os anteriores em alguns cenários: se isso acontecer, desativa o servidor problemático com "disabled": true e usa apenas os que precisas.

5. Initialization options para servidores específicos

Alguns servidores LSP aceitam opções de inicialização que melhoram o comportamento no OpenCode. Por exemplo, o servidor TypeScript permite configurar preferências de importação:

{
  "lsp": {
    "typescript": {
      "command": ["typescript-language-server", "--stdio"],
      "initialization": {
        "preferences": {
          "importModuleSpecifierPreference": "relative",
          "includeCompletionsForModuleExports": true,
          "includeCompletionsWithInsertText": true
        }
      }
    }
  }
}
Copy

6. Combina LSP com regras persistentes

Cria um ficheiro .opencode/rules com instruções claras sobre como o agente deve usar o diagnóstico LSP:

# .opencode/rules
## LSP
- Antes de responder a pedidos de revisão de código,
  verifica os diagnósticos LSP do ficheiro
- Se houver erros de tipo, prioriza a correção deles
- Usa code actions do LSP quando disponíveis
- Prefere usar `npm run typecheck` para validação final
Copy

7. Desativa LSP quando não precisas

Para projetos pequenos ou tarefas simples (como um script de bash), o LSP pode ser overkill. Desativa-o globalmente no teu ~/.config/opencode/opencode.json e ativa-o apenas nos projetos que realmente beneficiam dele:

// ~/.config/opencode/opencode.json (global — LSP desativado)
{
  "lsp": false
}

// /projeto-typescript/opencode.json (projeto — LSP ativo)
{
  "lsp": {
    "typescript": true
  }
}
Copy

Conclusão

O Language Server Protocol é uma peça fundamental no ecossistema de desenvolvimento moderno. O que começou como uma iniciativa da Microsoft para simplificar o VS Code tornou-se o standard universal para inteligência de código em todos os editores: e agora em agentes de IA como o OpenCode.

No OpenCode, o LSP não é apenas um extra: é uma vantagem estratégica. Enquanto outros agentes de IA "adivinham" o que o código faz, o OpenCode sabe. Sabe onde estão os erros, que tipos cada variável tem, para onde cada função aponta, e o que precisa de ser corrigido.

O que fazer agora?

  • Se nunca usaste LSP no OpenCode, começa por ativar "lsp": true no teu opencode.json
  • Experimenta opencode debug lsp para veres os servidores disponíveis
  • Configura servidores específicos para os teus projetos (TypeScript, Python, Rust, Go, etc.)
  • Combina LSP com MCP: usa o nosso guia de MCP para configurares ferramentas externas
  • Junta-te à comunidade do OpenCode no Discord e partilha as tuas configurações

O futuro do desenvolvimento assistido por IA não é sobre modelos maiores ou mais rápidos: é sobre modelos melhor informados. E o LSP é a ponte que dá aos agentes de IA a compreensão que precisam para serem verdadeiramente úteis.


Recursos adicionais

Comentários (0)

Nenhum comentário ainda. Seja o primeiro!

Deixar comentário