Skip to content

x/tools/gopls: add symbol rename tool for mcp #74887

@dbkegley

Description

@dbkegley

gopls version

Build info

golang.org/x/tools/gopls v0.20.0
golang.org/x/tools/[email protected] h1:fxOYZXKl6IsOTKIh6IgjDbIDHlr5btOtOUkrGOgFDB4=
github.com/BurntSushi/[email protected] h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
github.com/fatih/[email protected] h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
github.com/fatih/[email protected] h1:dDSgAjoOMp8da3egfz0t2S+t8RGOpEmEXZubcGuc0Bg=
github.com/fatih/[email protected] h1:/OdNE99OxoI/PqaW/SuSK9uxxT3f/tcSZgon/ssNSx4=
github.com/fsnotify/[email protected] h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/google/[email protected] h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
golang.org/x/exp/[email protected] h1:KdrhdYPDUvJTvrDK9gdjfFd6JTk8vA1WJoldYSi0kHo=
golang.org/x/[email protected] h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
golang.org/x/[email protected] h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
golang.org/x/[email protected] h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
golang.org/x/[email protected] h1:DU+gwOBXU+6bO0sEyO7o/NeMlxZxCZEvI7v+J4a1zRQ=
golang.org/x/[email protected] h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4=
golang.org/x/[email protected] h1:ZRKyKRJl/YEWl9ScZwd6Ua6xSt7DE6tHp1I3ucMroGM=
golang.org/x/[email protected] h1:Ju8QsuyhX3Hk8ma3CesTbO8vfJD9EvUBgHvkxHBzj0I=
honnef.co/go/[email protected] h1:fj8r9irJSpolAGUdZBxJIRY3lLc4jH2Dt4lwnWyWwpw=
mvdan.cc/[email protected] h1:nZUCeC2ViFaerTcYKstMmfysj6uhQrA2vJe+2vwGU6k=
mvdan.cc/xurls/[email protected] 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    ToolsThis label describes issues relating to any tools in the x/tools repository.goplsIssues related to the Go language server, gopls.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions