-
Notifications
You must be signed in to change notification settings - Fork 18.6k
Description
What did you do?
I configured the GitHub Copilot CLI to use gopls MCP:
e.g. in ~/.copilot/mcp-config.json
{
"mcpServers": {
"gopls": {
"type": "local",
"command": "/Users/mmcdonnell/go/bin/gopls",
"args": [
"mcp",
"-rpc.trace",
"-logfile=/tmp/gopls-mcp.log"
],
"tools": [
"*"
]
}
}
}What did you expect to see?
When using GitHub's Copilot CLI, and asking it a question related to my Go project, that it would be able to consult the gopls MCP.
What did you see instead?
Errors that prevented GitHub's Copilot CLI from working at all (to the point where I have to stop the Copilot CLI, remove the gopls MCP configuration, and then restart the Copilot CLI to help debug the issue):
Model call failed: {"message":"Invalid schema for function 'gopls-go_workspace': In context=(), object schema missing properties.","code":"invalid_request_body"} (Request ID: F98F:E764:5993DC6:686577B:693943F2)
Build info
I was initially using the latest stable release of gopls (e.g. go install golang.org/x/tools/gopls@latest), but then decided to install the most recent pre-release (e.g. go install golang.org/x/tools/gopls@v0.21.0-pre.2) to see if there were any improvements/fixes that maybe I wasn't aware of.
I'm currently still using the pre-release version:
$ gopls version
golang.org/x/tools/gopls v0.21.0-pre.2
Debugging Information
Here is the trace log file:
2025/12/10 10:09:08 Listening for MCP messages on stdin...
read: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"github-copilot-developer","version":"1.0.0"}}}
write: {"jsonrpc":"2.0","id":0,"result":{"capabilities":{"logging":{},"tools":{"listChanged":true}},"instructions":"# The gopls MCP server\n\nThese instructions describe how to efficiently work in the Go programming language using the gopls MCP server. You can load this file directly into a session where the gopls MCP server is connected.\n\n## Detecting a Go workspace\n\nAt the start of every session, you MUST use the `go_workspace` tool to learn about the Go workspace. ONLY if you are in a Go workspace, you MUST run `go_vulncheck` immediately afterwards to identify any existing security risks. The rest of these instructions apply whenever that tool indicates that the user is in a Go workspace.\n\n## Go programming workflows\n\nThese guidelines MUST be followed whenever working in a Go workspace. There are two workflows described below: the 'Read Workflow' must be followed when the user asks a question about a Go workspace. The 'Edit Workflow' must be followed when the user edits a Go workspace.\n\nYou may re-do parts of each workflow as necessary to recover from errors. However, you must not skip any steps.\n\n### Read workflow\n\nThe goal of the read workflow is to understand the codebase.\n\n1. **Understand the workspace layout**: Start by using `go_workspace` to understand the overall structure of the workspace, such as whether it's a module, a workspace, or a GOPATH project.\n\n2. **Find relevant symbols**: If you're looking for a specific type, function, or variable, use `go_search`. This is a fuzzy search that will help you locate symbols even if you don't know the exact name or location.\n EXAMPLE: search for the 'Server' type: `go_search({\"query\":\"server\"})`\n\n3. **Understand a file and its intra-package dependencies**: When you have a file path and want to understand its contents and how it connects to other files *in the same package*, use `go_file_context`. This tool will show you a summary of the declarations from other files in the same package that are used by the current file. `go_file_context` MUST be used immediately after reading any Go file for the first time, and MAY be re-used if dependencies have changed.\n EXAMPLE: to understand `server.go`'s dependencies on other files in its package: `go_file_context({\"file\":\"/path/to/server.go\"})`\n\n4. **Understand a package's public API**: When you need to understand what a package provides to external code (i.e., its public API), use `go_package_api`. This is especially useful for understanding third-party dependencies or other packages in the same monorepo.\n EXAMPLE: to see the API of the `storage` package: `go_package_api({\"packagePaths\":[\"example.com/internal/storage\"]})`\n\n### Editing workflow\n\nThe editing workflow is iterative. You should cycle through these steps until the task is complete.\n\n1. **Read first**: Before making any edits, follow the Read Workflow to understand the user's request and the relevant code.\n\n2. **Find references**: Before modifying the definition of any symbol, use the `go_symbol_references` tool to find all references to that identifier. This is critical for understanding the impact of your change. Read the files containing references to evaluate if any further edits are required.\n EXAMPLE: `go_symbol_references({\"file\":\"/path/to/server.go\",\"symbol\":\"Server.Run\"})`\n\n3. **Make edits**: Make the required edits, including edits to references you identified in the previous step. Don't proceed to the next step until all planned edits are complete.\n\n4. **Check for errors**: After every code modification, you MUST call the `go_diagnostics` tool. Pass the paths of the files you have edited. This tool will report any build or analysis errors.\n EXAMPLE: `go_diagnostics({\"files\":[\"/path/to/server.go\"]})`\n\n5. **Fix errors**: If `go_diagnostics` reports any errors, fix them. The tool may provide suggested quick fixes in the form of diffs. You should review these diffs and apply them if they are correct. Once you've applied a fix, re-run `go_diagnostics` to confirm that the issue is resolved. It is OK to ignore 'hint' or 'info' diagnostics if they are not relevant to the current task. Note that Go diagnostic messages may contain a summary of the source code, which may not match its exact text.\n\n6. **Check for vulnerabilities**: If your edits involved adding or updating dependencies in the go.mod file, you MUST run a vulnerability check on the entire workspace. This ensures that the new dependencies do not introduce any security risks. This step should be performed after all build errors are resolved. EXAMPLE: `go_vulncheck({\"pattern\":\"./...\"})`\n\n7. **Run tests**: Once `go_diagnostics` reports no errors (and ONLY once there are no errors), run the tests for the packages you have changed. You can do this with `go test [packagePath...]`. Don't run `go test ./...` unless the user explicitly requests it, as doing so may slow down the iteration loop.\n\n","protocolVersion":"2025-06-18","serverInfo":{"name":"gopls","version":"v1.0.0"}}}
read: {"jsonrpc":"2.0","method":"notifications/initialized"}
read error: EOF":"2.0","id":1,"method":"tools/list"}
write: {"jsonrpc":"2.0","id":1,"result":{"tools":[{"description":"Provides Go workspace diagnostics.\n\nChecks for parse and build errors across the entire Go workspace. If provided,\n\"files\" holds absolute paths for active files, on which additional linting is\nperformed.\n","inputSchema":{"type":"object","properties":{"files":{"type":"array","description":"absolute paths to active files, if any","items":{"type":"string"}}},"additionalProperties":false},"name":"go_diagnostics"},{"description":"Summarizes a file's cross-file dependencies","inputSchema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","description":"the absolute path to the file"}},"additionalProperties":false},"name":"go_file_context"},{"description":"Provides a summary of a Go package API","inputSchema":{"type":"object","required":["packagePaths"],"properties":{"packagePaths":{"type":"array","description":"the go package paths to describe","items":{"type":"string"}}},"additionalProperties":false},"name":"go_package_api"},{"description":"Renames a symbol in the Go workspace\n\nFor example, given arguments {\"file\": \"/path/to/foo.go\", \"symbol\": \"Foo\", \"new_name\": \"Bar\"},\ngo_rename_symbol returns the edits necessary to rename the symbol \"Foo\" (located in the file foo.go) to\n\"Bar\" across the Go workspace.","inputSchema":{"type":"object","required":["file","symbol","new_name"],"properties":{"file":{"type":"string","description":"the absolute path to the file containing the symbol"},"new_name":{"type":"string","description":"the new name for the symbol"},"symbol":{"type":"string","description":"the symbol or qualified symbol"}},"additionalProperties":false},"name":"go_rename_symbol"},{"description":"Search for symbols in the Go workspace.\n\nSearch for symbols using case-insensitive fuzzy search, which may match all or\npart of the fully qualified symbol name. For example, the query 'foo' matches\nGo symbols 'Foo', 'fooBar', 'futils.Oboe', 'github.com/foo/bar.Baz'.\n\nResults are limited to 100 symbols.\n","inputSchema":{"type":"object","required":["query"],"properties":{"query":{"type":"string","description":"the fuzzy search query to use for matching symbols"}},"additionalProperties":false},"name":"go_search"},{"description":"Provides the locations of references to a (possibly qualified)\npackage-level Go symbol referenced from the current file.\n\nFor example, given arguments {\"file\": \"/path/to/foo.go\", \"name\": \"Foo\"},\ngo_symbol_references returns references to the symbol \"Foo\" declared\nin the current package.\n\nSimilarly, given arguments {\"file\": \"/path/to/foo.go\", \"name\": \"lib.Bar\"},\ngo_symbol_references returns references to the symbol \"Bar\" in the imported lib\npackage.\n\nFinally, symbol references supporting querying fields and methods: symbol\n\"T.M\" selects the \"M\" field or method of the \"T\" type (or value), and \"lib.T.M\"\ndoes the same for a symbol in the imported package \"lib\".\n","inputSchema":{"type":"object","required":["file","symbol"],"properties":{"file":{"type":"string","description":"the absolute path to the file containing the symbol"},"symbol":{"type":"string","description":"the symbol or qualified symbol"}},"additionalProperties":false},"name":"go_symbol_references"},{"description":"Runs a vulnerability check on the Go workspace.\n\n\tThe check is performed on a given package pattern within a specified directory.\n\tIf no directory is provided, it defaults to the workspace root.\n\tIf no pattern is provided, it defaults to \"./...\".","inputSchema":{"type":"object","properties":{"dir":{"type":"string","description":"directory to run the vulnerability check within"},"pattern":{"type":"string","description":"package pattern to check"}},"additionalProperties":false},"name":"go_vulncheck","outputSchema":{"type":"object","properties":{"findings":{"type":"array","items":{"type":"object","required":["id","details","affectedPackages"],"properties":{"affectedPackages":{"type":"array","items":{"type":"string"}},"details":{"type":"string"},"id":{"type":"string"}},"additionalProperties":false}},"logs":{"type":"string"}},"additionalProperties":false}},{"description":"Summarize the Go programming language workspace","inputSchema":{"type":"object"},"name":"go_workspace"}]}}
read error: EOF
According to GitHub Copilot CLI:
That error is because gopls advertises go_workspace with an inputSchema of {"type":"object"} but no properties field, and the Copilot MCP client strictly requires object schemas to include "properties": {} (even if empty), so it rejects the tool as invalid.
Your config is fine; you’ll need either (a) a newer gopls build where go_workspace’s schema is fixed to include "properties": {}, or (b) to avoid using gopls as an MCP server until upstream updates—if you’ve already installed @latest, the next step is to build gopls from a commit that fixes this or open/track an issue with the gopls team citing this schema error.