MCPcopy Index your code
hub / github.com/mark3labs/mcp-go

github.com/mark3labs/mcp-go @v0.55.1 sqlite

repository ↗ · DeepWiki ↗ · release v0.55.1 ↗
2,683 symbols 12,844 edges 189 files 1,393 documented · 52% 26 cross-repo links
README

MCP Go Logo

Build Go Report Card GoDoc

AgentRank A Go implementation of the Model Context Protocol (MCP), enabling seamless integration between LLM applications and external data sources and tools.

Tutorial

Discuss the SDK on Discord

package main

import (
    "context"
    "fmt"

    "github.com/mark3labs/mcp-go/mcp"
    "github.com/mark3labs/mcp-go/server"
)

func main() {
    // Create a new MCP server
    s := server.NewMCPServer(
        "Demo 🚀",
        "1.0.0",
        server.WithToolCapabilities(false),
    )

    // Add tool
    tool := mcp.NewTool("hello_world",
        mcp.WithDescription("Say hello to someone"),
        mcp.WithString("name",
            mcp.Required(),
            mcp.Description("Name of the person to greet"),
        ),
    )

    // Add tool handler
    s.AddTool(tool, helloHandler)

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

func helloHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
    name, err := request.RequireString("name")
    if err != nil {
        return mcp.NewToolResultError(err.Error()), nil
    }

    return mcp.NewToolResultText(fmt.Sprintf("Hello, %s!", name)), nil
}

That's it!

MCP Go handles all the complex protocol details and server management, so you can focus on building great tools. It aims to be high-level and easy to use.

Key features:

  • Fast: High-level interface means less code and faster development
  • Simple: Build MCP servers with minimal boilerplate
  • Complete*: MCP Go aims to provide a full implementation of the core MCP specification

(*emphasis on aims)

🚨 🚧 🏗️ MCP Go is under active development, as is the MCP specification itself. Core features are working but some advanced capabilities are still in progress.

Table of Contents

Installation

go get github.com/mark3labs/mcp-go

Quickstart

Let's create a simple MCP server that exposes a calculator tool and some data:

package main

import (
    "context"
    "fmt"

    "github.com/mark3labs/mcp-go/mcp"
    "github.com/mark3labs/mcp-go/server"
)

func main() {
    // Create a new MCP server
    s := server.NewMCPServer(
        "Calculator Demo",
        "1.0.0",
        server.WithToolCapabilities(false),
        server.WithRecovery(),
    )

    // Add a calculator tool
    calculatorTool := mcp.NewTool("calculate",
        mcp.WithDescription("Perform basic arithmetic operations"),
        mcp.WithString("operation",
            mcp.Required(),
            mcp.Description("The operation to perform (add, subtract, multiply, divide)"),
            mcp.Enum("add", "subtract", "multiply", "divide"),
        ),
        mcp.WithNumber("x",
            mcp.Required(),
            mcp.Description("First number"),
        ),
        mcp.WithNumber("y",
            mcp.Required(),
            mcp.Description("Second number"),
        ),
    )

    // Add the calculator handler
    s.AddTool(calculatorTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {
        // Using helper functions for type-safe argument access
        op, err := request.RequireString("operation")
        if err != nil {
            return mcp.NewToolResultError(err.Error()), nil
        }

        x, err := request.RequireFloat("x")
        if err != nil {
            return mcp.NewToolResultError(err.Error()), nil
        }

        y, err := request.RequireFloat("y")
        if err != nil {
            return mcp.NewToolResultError(err.Error()), nil
        }

        var result float64
        switch op {
        case "add":
            result = x + y
        case "subtract":
            result = x - y
        case "multiply":
            result = x * y
        case "divide":
            if y == 0 {
                return mcp.NewToolResultError("cannot divide by zero"), nil
            }
            result = x / y
        }

        return mcp.NewToolResultText(fmt.Sprintf("%.2f", result)), nil
    })

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

What is MCP?

The Model Context Protocol (MCP) lets you build servers that expose data and functionality to LLM applications in a secure, standardized way. Think of it like a web API, but specifically designed for LLM interactions.

MCP servers can: - Expose data through Resources (think of these sort of like GET endpoints; they are used to load information into the LLM's context) - Provide functionality through Tools (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect) - Define interaction patterns through Prompts (reusable templates for LLM interactions) - And more!

mcp-go implements the Model Context Protocol specification version 2025-11-25, with backward compatibility for versions 2025-06-18, 2025-03-26, and 2024-11-05.

Core Concepts

Server

Show Server Examples

The server is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:

// Create a basic server
s := server.NewMCPServer(
    "My Server",  // Server name
    "1.0.0",     // Version
)

// Start the server using stdio
if err := server.ServeStdio(s); err != nil {
    log.Fatalf("Server error: %v", err)
}

Resources

Show Resource Examples

Resources are how you expose data to LLMs. They can be anything - files, API responses, database queries, system information, etc. Resources can be:

  • Static (fixed URI)
  • Dynamic (using URI templates)

Here's a simple example of a static resource:

// Static resource example - exposing a README file
resource := mcp.NewResource(
    "docs://readme",
    "Project README",
    mcp.WithResourceDescription("The project's README file"), 
    mcp.WithMIMEType("text/markdown"),
)

// Add resource with its handler
s.AddResource(resource, func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
    content, err := os.ReadFile("README.md")
    if err != nil {
        return nil, err
    }

    return []mcp.ResourceContents{
        mcp.TextResourceContents{
            URI:      "docs://readme",
            MIMEType: "text/markdown",
            Text:     string(content),
        },
    }, nil
})

And here's an example of a dynamic resource using a template:

// Dynamic resource example - user profiles by ID
template := mcp.NewResourceTemplate(
    "users://{id}/profile",
    "User Profile",
    mcp.WithTemplateDescription("Returns user profile information"),
    mcp.WithTemplateMIMEType("application/json"),
)

// Add template with its handler
s.AddResourceTemplate(template, func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {
    // Extract ID from the URI using regex matching
    // The server automatically matches URIs to templates
    userID := extractIDFromURI(request.Params.URI)

    profile, err := getUserProfile(userID)  // Your DB/API call here
    if err != nil {
        return nil, err
    }

    return []mcp.ResourceContents{
        mcp.TextResourceContents{
            URI:      request.Params.URI,
            MIMEType: "application/json",
            Text:     profile,
        },
    }, nil
})

The examples are simple but demonstrate the core concepts. Resources can be much more sophisticated - serving multiple contents, integrating with databases or external APIs, etc.

Tools

Show Tool Examples

Tools let LLMs take actions through your server. Unlike resources, tools are expected to perform computation and have side effects. They're similar to POST endpoints in a REST API.

Task-Augmented Tools

Task-augmented tools execute asynchronously and return results via polling. This is useful for long-running operations that would otherwise block or time out. Task tools support three modes:

  • TaskSupportForbidden (default): The tool cannot be invoked as a task
  • TaskSupportOptional: The tool can be invoked as a task or synchronously
  • TaskSupportRequired: The tool must be invoked as a task
// Example: A tool that requires task execution
processBatchTool := mcp.NewTool("process_batch",
    mcp.WithDescription("Process a batch of items asynchronously"),
    mcp.WithTaskSupport(mcp.TaskSupportRequired),
    mcp.WithArray("items",
        mcp.Description("Array of items to process"),
        mcp.WithStringItems(),
        mcp.Required(),
    ),
)

// Task tool handler returns CreateTaskResult instead of CallToolResult
s.AddTaskTool(processBatchTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CreateTaskResult, error) {
    items := request.GetStringSlice("items", []string{})

    // Long-running work here
    for i, item := range items {
        select {
        case <-ctx.Done():
            // Task was cancelled
            return nil, ctx.Err()
        default:
            // Process item...
            processItem(item)
        }
    }

    // Return result - task ID and metadata are managed by the server
    return &mcp.CreateTaskResult{
        Task: mcp.Task{
            // Task fields (ID, status, etc.) are populated by the server
        },
    }, nil
})

// Enable task capabilities when creating the server
s := server.NewMCPServer(
    "Task Server",
    "1.0.0",
    server.WithTaskCapabilities(
        true, // listTasks: allows clients to list all tasks
        true, // cancel: allows clients to cancel running tasks
        true, // toolCallTasks: enables task augmentation for tools
    ),
    server.WithMaxConcurrentTasks(10), // Optional: limit concurrent running tasks
)

Task execution flow: 1. Client calls tool with task parameter 2. Server immediately returns task ID 3. Tool executes asynchronously in the background 4. Client polls tasks/result to retrieve the result 5. Server sends task status notifications on completion

For optional task tools, the same tool can be called synchronously (without task parameter) or asynchronously (with task parameter):

// Tool with optional task support
analyzeTool := mcp.NewTool("analyze_data",
    mcp.WithDescription("Analyze data - can run sync or async"),
    mcp.WithTaskSupport(mcp.TaskSupportOptional),
    mcp.WithString("data", mcp.Required()),
)

// Use AddTaskTool for hybrid tools that support both modes
s.AddTaskTool(analyzeTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CreateTaskResult, error) {
    // This handler runs when called as a task
    data := request.GetString("data", "")
    result := analyzeData(data)

    return &mcp.CreateTaskResult{
        Task: mcp.Task{},
    }, nil
})

// The server automatically handles both sync and async invocations
// When called without task param: executes handler and returns immediately
// When called with task param: executes handler asynchronously
Limiting Concurrent Tasks

To prevent resource exhaustion, you can limit the number of concurrent running tasks:

s := server.NewMCPServer(
    "Task Server",
    "1.0.0",
    server.WithTaskCapabilities(true, true, true),
    server.WithMaxConcurrentTasks(10), // Allow up to 10 concurrent running tasks
)

When the limit is reached, new task creation requests will fail with an error. Completed, failed, or cancelled tasks don't count toward the limit - only tasks in "working" status. If WithMaxConcurrentTasks is not specified or set to 0, there is no limit on concurrent tasks.

For traditional synchronous tools that execute and return results immediately:

Simple calculation example: ```go calculatorTool := mcp.NewTool("calculate", mcp.WithDescription("Perform basic arithmetic calculations"), mcp.WithString("operation", mcp.Required(), mcp.Description("The arithmetic operation to perform"), mcp.Enum("add", "subtract", "multiply", "divide"), ), mcp.WithNumber("x", mcp.Required(), mcp.Description("First number"), ), mcp.WithNumber("y", mcp.Required(), mcp.Description("Second number"), ), )

s.AddTool(calculatorTool, func(ctx context.Context,

Extension points exported contracts — how you extend this code

RootsHandler (Interface)
RootsHandler defines the interface for handling roots requests from servers. Clients can implement this interface to pro [6 …
client/roots.go
SamplingHandler (Interface)
SamplingHandler defines the interface for handling sampling requests from servers. Clients can implement this interface [8 …
client/sampling.go
Interface (Interface)
Interface for the transport layer. [9 implementers]
client/transport/interface.go
ClientSession (Interface)
ClientSession represents an active session that can be used by MCPServer to interact with client. [20 implementers]
server/session.go
SamplingHandler (Interface)
SamplingHandler defines the interface for handling sampling requests from servers. [8 implementers]
server/inprocess_session.go
Tracer (Interface)
Tracer starts spans. Start returns a context carrying the new span and the span itself. [17 implementers]
tracing/tracing.go
SessionWithSampling (Interface)
SessionWithSampling extends ClientSession to support sampling requests. [5 implementers]
server/sampling.go
ElicitationHandler (Interface)
ElicitationHandler defines the interface for handling elicitation requests from servers. Clients can implement this inte [4 …
client/elicitation.go

Core symbols most depended-on inside this repo

NewMCPServer
called by 443
server/server.go
Set
called by 260
otel/meta_carrier.go
NewTool
called by 236
mcp/tools.go
Close
called by 232
client/interface.go
Error
called by 218
server/server.go
AddTool
called by 168
server/server.go
Error
called by 145
client/transport/error.go
NewRequestId
called by 136
mcp/types.go

Shape

Function 1,303
Method 894
Struct 331
FuncType 86
Interface 38
TypeAlias 31

Languages

Go100%

Modules by API surface

mcp/types.go163 symbols
server/server.go140 symbols
server/hooks.go121 symbols
mcp/tools.go100 symbols
server/streamable_http.go98 symbols
mcp/utils.go73 symbols
server/session_test.go61 symbols
server/server_test.go57 symbols
server/session.go56 symbols
server/sse.go54 symbols
mcp/tools_test.go54 symbols
client/client.go49 symbols

Dependencies from manifests, versioned

github.com/cespare/xxhash/v2v2.3.0 · 1×
github.com/go-logr/logrv1.4.3 · 1×
github.com/go-logr/stdrv1.2.2 · 1×
github.com/google/jsonschema-gov0.4.2 · 1×
github.com/pmezard/go-difflibv1.0.0 · 1×
github.com/rogpeppe/go-internalv1.14.1 · 1×
github.com/santhosh-tekuri/jsonschema/v6v6.0.2 · 1×

For agents

$ claude mcp add mcp-go \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact