Improve AI Context: Use Your Local Go Module Cache

When I used an AI assistant to write Go code that used a third-party library, it sometimes generated code with wrong function signatures, missing types, or outdated APIs - especially for packages that were new or not very popular. After a while, I started instructing the assistants to look at specific files in my Go module cache. While this helped, it was hard to synchronize prompts and rules across all the AI assistants I used, whether that’s Cursor IDE, Claude, or others.

To address this issue, I built a simple MCP server that keeps everything in one place. In this blog post, I’ll explain how to use it and compare the results with and without the MCP.

TL;DR

Install my mcp-local-context MCP server to provide AI tools with instructions on how to search your local Go module cache for accurate context. All installation and usage instructions are in the tool’s README . Alternatively, you can use the manual prompts directly in your AI tool of choice.

The problem

As I mentioned above, AI coding assistants often generate incorrect Go code when working with third-party packages. They rely on outdated documentation, incomplete examples, or assumptions based on their training data - which may be months or years old.

While existing third-party services provide context for packages, they add external dependencies and potential privacy concerns. The Go module cache is already on your machine - why not use it directly?

Solution: mcp-local-context

I built an MCP server that runs locally on your machine and provides AI tools with instructions on how to access your Go module cache. MCP (Model Context Protocol) is an open protocol that allows AI assistants to access external data sources.

The server doesn’t parse Go files or search for documentation itself, at least in the current implementation as of the date of writing this post. Instead, it provides hints and instructions to the LLM on how to search for context in your local $GOMODCACHE directory. This guides the AI to look at the actual source code in your module cache rather than relying on outdated training data.

Installation: Follow the guide in the repository README . If you prefer not to install the server, you can use the manual prompts directly in your AI tool of choice.

Real-world test: NATS.IO

To demonstrate the difference, I tested the MCP server with NATS.IO , a popular messaging system with a comprehensive SDK. I chose NATS.IO as a representative example because its SDK is feature-rich, and AI models may not have complete knowledge of all its methods.

I used the following prompt with Cursor’s Composer-1 model (I used this model for consistency, as Claude Sonnet 4.5 appeared to have memorized context from previous attempts):

Create a NATS.IO subscriber and publisher. The subscriber should send a basic event, such as the coordinates of a point, and the publisher should calculate the distance between the previous point and the current point. Use Cobra for commands.

Additionally, add a debug HTTP endpoint to see the number of currently pending messages.

Use local-context mcp.

Compare the branches : with and without using the MCP.

Without MCP: Manual Implementation

Without access to the module cache, the AI generated code that manually tracked pending messages using atomic counters:

var (
    pendingCount int64
)

_, err = nc.Subscribe(subscriberSubject, func(msg *natsio.Msg) {
    atomic.AddInt64(&pendingCount, 1)

    ...

    atomic.AddInt64(&pendingCount, -1)
})

This works, but not correctly, ignoring the possible tail of pending messages for the exact subscription and so on. Moreover, it’s reinventing functionality that already exists in the SDK.

With MCP: Using SDK Methods

With MCP providing instructions on how to search the module cache, the AI correctly identified and used the SDK’s Pending() method:

var (
	pendingLock sync.RWMutex
	pendingMsgs int
)
...
sub, err = nc.Subscribe(subject, func(msg *nats.Msg) {
    ...
    pendingLock.Lock()
    msgs, _, err := sub.Pending()
    if err == nil {
        pendingMsgs = msgs
    }
    pendingLock.Unlock()
})
...
http.HandleFunc("/debug/pending", func(w http.ResponseWriter, r *http.Request) {
    pendingLock.RLock()
    count := pendingMsgs
    pendingLock.RUnlock()

    msgs, bytes, err := sub.Pending()
    ...

    response := map[string]interface{}{
        "pending_messages": msgs,
        "pending_bytes":    bytes,
        "cached_count":     count,
    }
    ...
})

Why this matters: The Pending() method handles edge cases, thread safety, and provides accurate counts that manual tracking might miss. It’s also the idiomatic way to use the SDK.

🤖 Note: The generated code structures differ due to LLM non-determinism, but the key difference is clear: with MCP, the AI discovered and used the proper SDK method instead of implementing a manual workaround.

⚠️ One more note: the generated code in both cases is far from perfect. For example, the LLM confused the publisher and the subscriber in the last example. However, the point of this blog post is simply to show a way to provide more context to the LLM. Of course, you still need to review the generated code. At the end of the day, you, not the LLM, are responsible for the software.

Conclusion

Improving the context you provide to AI coding assistants isn’t just about getting correct code - it’s about leveraging the tools you already have. Your Go module cache contains the exact source code, examples, documentation, and API definitions for the dependencies you’re actually using. By giving AI tools access to this local context, you eliminate the guesswork that leads to wrong function signatures, outdated APIs, and manual workarounds.

The MCP server approach demonstrates that you don’t need to rely on third-party services or hope that AI models have the right information in their training data. You can take control of the context directly, ensuring accuracy while maintaining privacy and reducing costs.

Try it yourself: Install the MCP server or use the manual prompts , and see how it improves your AI-generated Go code.

The solution works well for me, and I hope it helps you too. Over time, it can be extended with features like dependency indexing to improve context retrieval, especially for large dependencies. If you have ideas for improvements, feel free to send a pull request 👍.