← Voltar para o blog

Go e MCP: Como Criar Servidores de IA com o SDK Oficial

Aprenda a criar servidores MCP em Go com o SDK oficial. Tutorial pratico com tools, resources e prompts para integrar IA com suas aplicacoes Go.

O Model Context Protocol (MCP) esta transformando a forma como aplicacoes se conectam a modelos de IA. Criado pela Anthropic e agora sob governanca da Linux Foundation, o MCP define um padrao aberto para que LLMs acessem ferramentas, dados e recursos externos de forma estruturada. Com o lancamento do SDK oficial em Go – mantido em colaboracao com o Google – a linguagem ganha um papel central nesse ecossistema.

Se voce ja construiu APIs REST em Go ou microsservicos com gRPC, criar servidores MCP vai parecer natural. A arquitetura segue o mesmo padrao idiomatico que torna Go tao produtivo para backend.

O que e o Model Context Protocol

MCP e um protocolo que padroniza como assistentes de IA (Claude, ChatGPT, Gemini) se comunicam com servicos externos. Em vez de cada integracao ser um caso especial, o MCP define tres primitivas:

  • Tools – funcoes que o modelo pode chamar (consultar banco de dados, enviar email, executar codigo)
  • Resources – dados que o modelo pode ler (arquivos, documentos, configuracoes)
  • Prompts – templates de instrucoes reutilizaveis

O protocolo usa JSON-RPC 2.0 sobre diferentes transportes: stdio (para CLIs), SSE (Server-Sent Events) e HTTP streamable.

Instalando o SDK Oficial

O SDK oficial vive em github.com/modelcontextprotocol/go-sdk. Para adicionar ao seu projeto:

go get github.com/modelcontextprotocol/go-sdk@latest

O pacote principal e mcp, que define as APIs para servidores e clientes. A arquitetura segue o padrao da standard library – similar a net/http – com tipos Server e Client como cidadaos de primeira classe.

Se voce usa Go modules, o SDK se integra sem atrito ao seu workflow existente.

Criando seu Primeiro Servidor MCP

Vamos construir um servidor MCP que expoe ferramentas uteis para um assistente de IA. O exemplo implementa uma tool que consulta informacoes sobre repositorios Go:

package main

import (
	"context"
	"fmt"
	"log"
	"os"

	"github.com/modelcontextprotocol/go-sdk/mcp"
)

func main() {
	// Cria o servidor MCP
	server := mcp.NewServer(
		"go-tools",
		"1.0.0",
		mcp.WithDescription("Ferramentas Go para assistentes de IA"),
	)

	// Registra uma tool
	server.AddTool(
		mcp.NewTool(
			"analisar_modulo",
			"Analisa um modulo Go e retorna informacoes sobre dependencias",
			mcp.Input(
				mcp.Property("modulo", mcp.String(), "Nome do modulo Go (ex: github.com/gin-gonic/gin)"),
				mcp.Required("modulo"),
			),
		),
		analisarModuloHandler,
	)

	// Executa sobre stdio
	transport := mcp.NewStdioTransport()
	if err := server.Run(context.Background(), transport); err != nil {
		log.Fatal(err)
	}
}

func analisarModuloHandler(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
	modulo := req.Params.Arguments["modulo"].(string)

	info := fmt.Sprintf(
		"Modulo: %s\nStatus: disponivel no pkg.go.dev\nUse: go get %s",
		modulo, modulo,
	)

	return &mcp.CallToolResult{
		Content: []mcp.Content{
			mcp.TextContent(info),
		},
	}, nil
}

O servidor recebe requisicoes JSON-RPC via stdin e responde via stdout. Qualquer cliente MCP compativel (Claude Desktop, Cursor, etc.) pode se conectar e usar a tool analisar_modulo.

Adicionando Resources

Resources permitem que o modelo leia dados estruturados. Vamos adicionar um resource que expoe a lista de dependencias do projeto atual:

server.AddResource(
	mcp.NewResource(
		"go://dependencias",
		"Lista de dependencias do go.mod atual",
		mcp.WithMIMEType("application/json"),
	),
	func(ctx context.Context, req mcp.ReadResourceRequest) (*mcp.ReadResourceResult, error) {
		data, err := os.ReadFile("go.mod")
		if err != nil {
			return nil, fmt.Errorf("erro ao ler go.mod: %w", err)
		}

		return &mcp.ReadResourceResult{
			Contents: []mcp.ResourceContents{
				mcp.TextResourceContents(
					"go://dependencias",
					string(data),
					"text/plain",
				),
			},
		}, nil
	},
)

Com isso, quando o assistente de IA precisa entender as dependencias do projeto, ele consulta o resource go://dependencias em vez de adivinhar. Esse padrao de tratamento de erros com wrapping usando fmt.Errorf com %w permite que erros sejam rastreados corretamente pela cadeia de chamadas.

Registrando Prompts Reutilizaveis

Prompts sao templates que guiam o comportamento do modelo. Por exemplo, um prompt para revisao de codigo Go:

server.AddPrompt(
	mcp.NewPrompt(
		"revisar_codigo_go",
		"Revisa codigo Go seguindo boas praticas",
		mcp.WithArgument("arquivo", "Caminho do arquivo Go a revisar"),
	),
	func(ctx context.Context, req mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {
		arquivo := req.Params.Arguments["arquivo"]

		return &mcp.GetPromptResult{
			Description: "Revisao de codigo Go",
			Messages: []mcp.PromptMessage{
				{
					Role: mcp.User,
					Content: mcp.TextContent(fmt.Sprintf(
						`Revise o arquivo %s seguindo estas diretrizes:
1. Tratamento de erros idiomatico (sem panic em codigo de producao)
2. Nomenclatura seguindo convencoes Go (camelCase exportado, lowercase interno)
3. Uso correto de goroutines e channels
4. Interfaces pequenas e composiveis
5. Testes unitarios adequados`,
						arquivo,
					)),
				},
			},
		}, nil
	},
)

Servidor Completo com Multiplas Tools

Na pratica, um servidor MCP expoe varias ferramentas complementares. Aqui esta um exemplo mais robusto que combina analise de codigo com execucao de testes:

func registrarTools(server *mcp.Server) {
	// Tool: executar testes
	server.AddTool(
		mcp.NewTool(
			"executar_testes",
			"Executa testes Go no diretorio especificado",
			mcp.Input(
				mcp.Property("diretorio", mcp.String(), "Diretorio dos testes (ex: ./...)"),
				mcp.Property("verbose", mcp.Boolean(), "Saida detalhada"),
			),
		),
		executarTestesHandler,
	)

	// Tool: verificar cobertura
	server.AddTool(
		mcp.NewTool(
			"cobertura_testes",
			"Retorna a cobertura de testes do projeto",
		),
		coberturaHandler,
	)

	// Tool: analisar performance
	server.AddTool(
		mcp.NewTool(
			"benchmark",
			"Executa benchmarks Go e retorna resultados",
			mcp.Input(
				mcp.Property("pacote", mcp.String(), "Pacote para benchmark"),
				mcp.Property("tempo", mcp.String(), "Duracao do benchmark (ex: 5s)"),
			),
		),
		benchmarkHandler,
	)
}

func executarTestesHandler(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
	dir := "./..."
	if d, ok := req.Params.Arguments["diretorio"].(string); ok {
		dir = d
	}

	args := []string{"test", dir}
	if v, ok := req.Params.Arguments["verbose"].(bool); ok && v {
		args = append(args, "-v")
	}

	cmd := exec.CommandContext(ctx, "go", args...)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return &mcp.CallToolResult{
			Content: []mcp.Content{
				mcp.TextContent(fmt.Sprintf("Testes falharam:\n%s", output)),
			},
			IsError: true,
		}, nil
	}

	return &mcp.CallToolResult{
		Content: []mcp.Content{
			mcp.TextContent(string(output)),
		},
	}, nil
}

Observe como o handler retorna IsError: true em vez de retornar um erro Go – isso sinaliza ao modelo que a tool executou mas o resultado indica falha, permitindo que o assistente trate o problema. Esse padrao e diferente de retornar error, que indicaria falha no proprio servidor MCP.

Usando Concorrencia no Servidor MCP

Go brilha quando o servidor MCP precisa processar multiplas requisicoes simultaneamente. Cada chamada de tool ja roda em sua propria goroutine pelo SDK, mas voce pode usar padroes de concorrencia dentro dos handlers:

func analisarProjetoHandler(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
	type resultado struct {
		nome  string
		dados string
		err   error
	}

	analises := []string{"lint", "vet", "test"}
	ch := make(chan resultado, len(analises))

	for _, a := range analises {
		go func(nome string) {
			cmd := exec.CommandContext(ctx, "go", nome, "./...")
			out, err := cmd.CombinedOutput()
			ch <- resultado{nome: nome, dados: string(out), err: err}
		}(a)
	}

	var relatorio strings.Builder
	for range analises {
		r := <-ch
		if r.err != nil {
			relatorio.WriteString(fmt.Sprintf("[%s] FALHOU:\n%s\n", r.nome, r.dados))
		} else {
			relatorio.WriteString(fmt.Sprintf("[%s] OK\n", r.nome))
		}
	}

	return &mcp.CallToolResult{
		Content: []mcp.Content{
			mcp.TextContent(relatorio.String()),
		},
	}, nil
}

O uso de context garante que, se o cliente cancelar a requisicao, todas as goroutines filhas sao encerradas corretamente.

Configurando no Claude Desktop

Para usar seu servidor MCP com o Claude Desktop, adicione ao arquivo de configuracao:

{
  "mcpServers": {
    "go-tools": {
      "command": "go",
      "args": ["run", "./cmd/mcp-server"],
      "env": {
        "GOPATH": "/home/dev/go"
      }
    }
  }
}

Para distribuir o servidor como binario, use goreleaser ou go build com cross-compilation para gerar executaveis para todas as plataformas.

Testando Servidores MCP

Testar servidores MCP em Go segue os mesmos principios de testes em Go. O SDK fornece helpers para simular o transporte:

func TestAnalisarModulo(t *testing.T) {
	server := mcp.NewServer("test", "1.0.0")
	server.AddTool(
		mcp.NewTool("analisar_modulo", "Analisa modulo"),
		analisarModuloHandler,
	)

	// Cria cliente de teste conectado ao servidor
	client, cleanup := mcp.NewTestClient(t, server)
	defer cleanup()

	// Chama a tool
	result, err := client.CallTool(context.Background(), "analisar_modulo", map[string]any{
		"modulo": "github.com/gin-gonic/gin",
	})
	if err != nil {
		t.Fatal(err)
	}

	if len(result.Content) == 0 {
		t.Fatal("resultado vazio")
	}
}

Usar fuzzing nativo do Go tambem e recomendado para testar a robustez dos handlers contra inputs inesperados.

MCP vs API REST: Quando Usar Cada Um

AspectoAPI RESTMCP
ProtocoloHTTP/JSONJSON-RPC 2.0
Consumidor principalAplicacoesModelos de IA
DescobertaOpenAPI/SwaggerAutomatica pelo protocolo
AutenticacaoOAuth, JWT, API keysOAuth (em desenvolvimento)
TransporteHTTPstdio, SSE, HTTP
EstadoStateless por padraoSessao persistente

Para APIs consumidas por humanos e aplicacoes tradicionais, REST continua sendo o padrao. MCP e especifico para a comunicacao entre assistentes de IA e ferramentas – e os dois podem coexistir no mesmo projeto.

Proximos Passos

O ecossistema MCP em Go esta crescendo rapidamente. Alem do SDK oficial, existem alternativas da comunidade como mcp-go para quem precisa de transportes HTTP e SSE avancados. Considere tambem explorar observabilidade para monitorar seus servidores MCP em producao e Docker para containerizar o deploy.

Com Go e MCP, voce pode transformar qualquer sistema existente em uma ferramenta acessivel por assistentes de IA – sem reescrever codigo, sem mudar de linguagem, e com a performance e confiabilidade que Go oferece. Para tratamento de erros robusto nos seus handlers MCP, veja como usar errors.AsType do Go 1.26 para inspecao type-safe. Para projetos que tambem envolvem frontend, veja como Go e HTMX podem complementar sua arquitetura.

FAQ

O que e o Model Context Protocol (MCP)? MCP e um protocolo aberto criado pela Anthropic, agora sob a Linux Foundation, que padroniza como modelos de IA se conectam a ferramentas e dados externos. Ele define tres primitivas: tools (funcoes), resources (dados) e prompts (templates).

Preciso saber sobre IA para usar o MCP SDK em Go? Nao. Criar um servidor MCP e essencialmente criar um backend que expoe funcionalidades via JSON-RPC. Se voce sabe construir APIs em Go, ja tem todo o conhecimento necessario.

Qual a diferenca entre o SDK oficial e o mcp-go da comunidade? O SDK oficial (modelcontextprotocol/go-sdk) e mantido em colaboracao com o Google e foca em conformidade total com a spec. O mcp-go (mark3labs/mcp-go) oferece transportes HTTP e SSE adicionais e uma API mais simplificada para casos de uso comuns.

Posso usar MCP em producao? Sim, mas o SDK ainda esta em desenvolvimento ativo. Para producao, fixe a versao no go.mod e acompanhe o changelog do repositorio oficial para breaking changes.

Como depurar um servidor MCP? Use slog para logging estruturado dentro dos handlers. O SDK tambem suporta o MCP Inspector, uma ferramenta de depuracao que permite testar tools e resources interativamente.