gopls version
Build info
golang.org/x/tools/gopls v0.20.0 golang.org/x/tools/gopls@v0.20.0 h1:fxOYZXKl6IsOTKIh6IgjDbIDHlr5btOtOUkrGOgFDB4= github.com/BurntSushi/toml@v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg= github.com/fatih/camelcase@v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/gomodifytags@v1.17.1-0.20250423142747-f3939df9aa3c h1:dDSgAjoOMp8da3egfz0t2S+t8RGOpEmEXZubcGuc0Bg= github.com/fatih/structtag@v1.2.0 h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4= github.com/fsnotify/fsnotify@v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k= github.com/google/go-cmp@v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= golang.org/x/exp/typeparams@v0.0.0-20250620022241-b7579e27df2b h1:KdrhdYPDUvJTvrDK9gdjfFd6JTk8vA1WJoldYSi0kHo= golang.org/x/mod@v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= golang.org/x/sync@v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= golang.org/x/sys@v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= golang.org/x/telemetry@v0.0.0-20250710130107-8d8967aff50b h1:DU+gwOBXU+6bO0sEyO7o/NeMlxZxCZEvI7v+J4a1zRQ= golang.org/x/text@v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= golang.org/x/tools@v0.35.1-0.20250728180453-01a3475a31bc h1:ZRKyKRJl/YEWl9ScZwd6Ua6xSt7DE6tHp1I3ucMroGM= golang.org/x/vuln@v1.1.4 h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I= honnef.co/go/tools@v0.7.0-0.dev.0.20250523013057-bbc2f4dd71ea h1:fj8r9irJSpolAGUdZBxJIRY3lLc4jH2Dt4lwnWyWwpw= mvdan.cc/gofumpt@v0.8.0 h1:nZUCeC2ViFaerTcYKstMmfysj6uhQrA2vJe+2vwGU6k= mvdan.cc/xurls/v2@v2.6.0 h1:3NTZpeTxYVWNSokW3MKeyVkz/j7uYXYiMtXRUfmjbgI= go: go1.24.5
go env
AR='ar'
CC='gcc'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_ENABLED='1'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
CXX='g++'
GCCGO='gccgo'
GO111MODULE=''
GOAMD64='v1'
GOARCH='amd64'
GOAUTH='netrc'
GOBIN=''
GOCACHE='/home/david/.cache/go-build'
GOCACHEPROG=''
GODEBUG=''
GOENV='/home/david/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFIPS140='off'
GOFLAGS=''
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build1873223565=/tmp/go-build -gno-record-gcc-switches'
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMOD='/dev/null'
GOMODCACHE='/home/david/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/david/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTELEMETRY='local'
GOTELEMETRYDIR='/home/david/.config/go/telemetry'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.24.1'
GOWORK=''
PKG_CONFIG='pkg-config'
What did you do?
Performing refactoring in go projects using LLMs is inefficient when using gpls mcp alone. This similar project implements a symbol rename tool: https://github.com/isaacphi/mcp-language-server/blob/e4395849a52e18555361abab60a060802c06bf50/tools.go#L305-L364 which is really helpful for the LLM when editing code across multiple files. Sadly this tool isn't maintained and the diagnostics are not as reliable as the ones provided by gopls
, for whatever reason.
I also prefer to use gpls mcp
directly because it's much easier to integrate with my editor, meaning claude code can see the same diagnostics as I do.
What did you see happen?
Without LSP renaming functionality the LLM requests workspace diagnostics and works down the list file by file to fix errors one by one, often re-requesting diagnostics between each fix.
This workflow uses a spends a huge amount of tokens by repeatedly sending all of the diagnostics to the LLM.
What did you expect to see?
To aid with refactoring go code across multiple files gopls mcp
could provide a symbol renaming tool which would reduce the back-and-forth with the LLM because the workspace diagnostics will be less noisy.
Editor and settings
lsp settings:
[language-server.gopls]
command = "gopls"
args = ["-mcp.listen=localhost:8092"]
claude code mcp settings:
"mcpServers": {
"go-pls": {
"type": "sse",
"url": "http://localhost:8092/sessions/1"
}
},
CLAUDE.md:
< pasted output of `gopls mcp -instructions` >
claude code prompt:
> Find all references in the Go source code inside of the src/ directory which reference "freeze" or "frozen" container images. Rename these references to use "containerize" or "is_container" instead. Use the gopls lsp tools to identify symbols that need to be renamed.
...
Total cost: $35.65
Total duration (API): 30m 10.6s
Total duration (wall): 42m 10.1s
Total code changes: 58 lines added, 58 lines removed
Usage by model:
claude-3-5-haiku: 232 input, 55 output, 0 cache read, 0 cache write
claude-3-5-sonnet: 11.7m input, 29.0k output, 0 cache read, 0 cache write
I let this churn for a while and killed the prompt before it was complete because it's faster for me to do this this manually with git grep and LSP code actions.
Logs
No response