MCP Server in Golang Providing Data for Amazon Q in JetBrains IDE

Marek SkopowskiMarek Skopowski
4 min read

Today we’re going to build an MCP server in Golang that will provide a Wikipedia Search-like tool, that can be then used as an MCP server in the Amazon Q plugin that resides in the JetBrains IDE.

The MCP tool will be working in the STDIO mode and can be added to any other LLM tool that is supporting the MCP standard. We’re going to use the Goland as an example.

What is the Model Context Protocol (MCP)

The Model Context Protocol (MCP) is an open standard, open-source framework introduced by Anthropic in November 2024 to standardize the way artificial intelligence (AI) systems like large language models (LLMs) integrate and share data with external tools, systems, and data sources.[1] MCP provides a universal interface for reading files, executing functions, and handling contextual prompts.[2] Following its announcement, the protocol was adopted by major AI providers, including OpenAI and Google DeepMind.[3][4]

Source: https://en.wikipedia.org/wiki/Model_Context_Protocol

In other other words, it’s a “common language” that let’s AI models talk to tools, data and apps.

Building the MCP Server

For this article I’m going to use the community library mark3labs/mcp-go that fully supports the MCP standard.

You have to be aware there’s also an official Go SDK for the MCP which is less stable, but provides more strict approach, however requires more bolierplate to kickstart the project.

Okay, straight to the point.

Let’s install the package:

go get github.com/mark3labs/mcp-go

And head straight to setting up the MCP server:

s := server.NewMCPServer(
        "Wikipedia Search",
        "v1.0.0",
        server.WithToolCapabilities(false),
        server.WithRecovery(),
    )

Then the tool definition. This is the part that is being exposed as an “interface” to the “model” client:

wikiTool := mcp.NewTool(
        "wikipedia_search",
        mcp.WithDescription("Search Wikipedia for a query and return the first paragraph"),
        mcp.WithString("query", mcp.Required(), mcp.Description("Search term")),
    )

Now, let’s connect the server and the tool definition:

s.AddTool(wikiTool, func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
        term, err := req.RequireString("query")
        if err != nil {
            return nil, fmt.Errorf("failed to get query: %w", err)
        }

        u := fmt.Sprintf("https://en.wikipedia.org/api/rest_v1/page/summary/%s", url.PathEscape(term))

        ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
        defer cancel()

        httpReq, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
        if err != nil {
            return nil, fmt.Errorf("failed to create request: %w", err)
        }
        httpReq.Header.Set("User-Agent", "Wikipedia-MCP-Server/1.0")

        r, err := http.DefaultClient.Do(httpReq)
        if err != nil {
            return nil, fmt.Errorf("failed to get wikipedia page: %w", err)
        }
        defer func() {
            if closeErr := r.Body.Close(); closeErr != nil {
                fmt.Printf("Warning: failed to close response body: %v\n", closeErr)
            }
        }()

        if r.StatusCode != http.StatusOK {
            return nil, fmt.Errorf("failed to get wikipedia page: %s", r.Status)
        }

        body, err := io.ReadAll(io.LimitReader(r.Body, 1024*1024))
        if err != nil {
            return nil, fmt.Errorf("failed to read response body: %w", err)
        }

        var summary struct {
            Extract string `json:"extract"`
        }
        if err := json.Unmarshal(body, &summary); err != nil {
            return nil, fmt.Errorf("failed to parse response: %w", err)
        }

        if summary.Extract == "" {
            return nil, fmt.Errorf("no summary found for '%s'", term)
        }

        return mcp.NewToolResultText(summary.Extract), nil
    })

Our tool is calling the Wiki API and parsing the summary for the given query. It’s limited to process only 1MB of data and has a timeout of 10 seconds, to not get locked if the network issues will occur.

The last thing required is to run the MCP server:

if err := server.ServeStdio(s); err != nil {
        fmt.Printf("Server error: %v\n", err)
    }

Compiling the MCP Server

To build a real binary application, that can be run in the background an serve as an MCP server, you need to:

go build -o mcp-wiki-tool

And that’s it. When the model will need it it will run it by itself.

Connecting to Amazon Q

In your JetBrains IDE, open Amazon Q plugin and select the followings:

  1. Configure MCP servers:

  1. Add new MCP server:

  1. Provide the details about our newly created MCP server:

Click “Save” and you’re good to go.

On your MCP servers list you should see “WikipediaSearch”:

Now, anytime you ask anything related to the Wikipedia or Amazon Q decides it needs a data from the Wikipedia it will use your model.

You can configure the Amazon Q how it should behave when using your new tool:

You can approve the usage of the tool each time the Amazon Q needs it or just allow it to be used in the background seamlessly.

Our MCP server in action:

Expanding with More Useful Tools

As you can see, the capabilities of the MCP servers are limitless. You can expand your model’s context in a way you want and access tools that aren’t publicly available on the internet.

The MCP is for the models the same what the HTTP was for the Internet. It standardizes the information exchange format.

Please keep in mind that MCP servers are not only for the read-only mode. You can expose endpoints that will be modyfing state of your application, like “attlasian” MCP server allows to manage Jira on your behalf, manage tickets, stories and everything related.

Sources

As always the full source code used for this article you can find on my GitHub: https://github.com/flashlabs/kiss-samples/tree/main/mcp

0
Subscribe to my newsletter

Read articles from Marek Skopowski directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Marek Skopowski
Marek Skopowski

Software Engineer x Data Engineer - I make the world a better place to live with software that enables data-driven decision-making