{"id":21999930,"url":"https://github.com/mark3labs/mcp-go","last_synced_at":"2026-04-02T14:01:43.176Z","repository":{"id":265076536,"uuid":"895029087","full_name":"mark3labs/mcp-go","owner":"mark3labs","description":"A Go implementation of the Model Context Protocol (MCP), enabling seamless integration between LLM applications and external data sources and tools.","archived":false,"fork":false,"pushed_at":"2026-03-24T12:50:34.000Z","size":105395,"stargazers_count":8423,"open_issues_count":26,"forks_count":800,"subscribers_count":50,"default_branch":"main","last_synced_at":"2026-03-25T16:34:34.865Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://mcp-go.dev/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mark3labs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2024-11-27T12:38:33.000Z","updated_at":"2026-03-25T14:59:51.000Z","dependencies_parsed_at":"2025-02-16T10:24:20.609Z","dependency_job_id":"3d5c86dd-34f0-4b28-aaa1-3c6adaa0d75c","html_url":"https://github.com/mark3labs/mcp-go","commit_stats":null,"previous_names":["mark3labs/mcp-go"],"tags_count":103,"template":false,"template_full_name":null,"purl":"pkg:github/mark3labs/mcp-go","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mark3labs%2Fmcp-go","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mark3labs%2Fmcp-go/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mark3labs%2Fmcp-go/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mark3labs%2Fmcp-go/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mark3labs","download_url":"https://codeload.github.com/mark3labs/mcp-go/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mark3labs%2Fmcp-go/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31307459,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-29T23:08:59.807Z","updated_at":"2026-04-02T14:01:43.163Z","avatar_url":"https://github.com/mark3labs.png","language":"Go","funding_links":[],"categories":["Developer Tools","Development Tools MCP Servers","Go","Development Tools","Artificial Intelligence","A01_文本生成_文本对话","📚 Projects (1974 total)","[Model Context Protocol](https://modelcontextprotocol.io/introduction)","Frameworks","⚙️ DevOps","Building","语言资源库","SDKs","フレームワーク","Language-Specific SDKs","HarmonyOS","Backend","Table of Contents","カテゴリ","MCP Ecosystem","框架","MCP Servers \u0026 Integrations","MCP Servers \u0026 Protocol","MCP Frameworks and libraries","🤖 AI \u0026 Machine Learning"],"sub_categories":["MCP SDKs","Frameworks 🛠️","大语言对话模型及数据","MCP Servers","Multi-modal","🛠️ \u003ca name=\"other-tools-and-integrations\"\u003e\u003c/a\u003eOther Tools and Integrations","Tools","go","Community","🎧 \u003ca name=\"text-to-speech\"\u003e\u003c/a\u003eテキスト読み上げ","Frameworks","Windows Manager","Go","AI Services","🛠️ \u003ca name=\"developer-tools\"\u003e\u003c/a\u003e開発ツール","Core \u0026 Frameworks","Other IDEs","Codex Resources"],"readme":"\u003c!-- omit in toc --\u003e\n\u003cdiv align=\"center\"\u003e\n\u003cimg src=\"./logo.png\" alt=\"MCP Go Logo\"\u003e\n\n[![Build](https://github.com/mark3labs/mcp-go/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mark3labs/mcp-go/actions/workflows/ci.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/mark3labs/mcp-go?cache)](https://goreportcard.com/report/github.com/mark3labs/mcp-go)\n[![GoDoc](https://pkg.go.dev/badge/github.com/mark3labs/mcp-go.svg)](https://pkg.go.dev/github.com/mark3labs/mcp-go)\n\n[![AgentRank](https://agentrank-ai.com/api/badge/tool/mark3labs--mcp-go)](https://agentrank-ai.com/tool/mark3labs--mcp-go/)\n\u003cstrong\u003eA Go implementation of the Model Context Protocol (MCP), enabling seamless integration between LLM applications and external data sources and tools.\u003c/strong\u003e\n\n\u003cbr\u003e\n\n[![Tutorial](http://img.youtube.com/vi/qoaeYMrXJH0/0.jpg)](http://www.youtube.com/watch?v=qoaeYMrXJH0 \"Tutorial\")\n\n\u003cbr\u003e\n\nDiscuss the SDK on [Discord](https://discord.gg/RqSS2NQVsY)\n\n\u003c/div\u003e\n\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n\n    \"github.com/mark3labs/mcp-go/mcp\"\n    \"github.com/mark3labs/mcp-go/server\"\n)\n\nfunc main() {\n    // Create a new MCP server\n    s := server.NewMCPServer(\n        \"Demo 🚀\",\n        \"1.0.0\",\n        server.WithToolCapabilities(false),\n    )\n\n    // Add tool\n    tool := mcp.NewTool(\"hello_world\",\n        mcp.WithDescription(\"Say hello to someone\"),\n        mcp.WithString(\"name\",\n            mcp.Required(),\n            mcp.Description(\"Name of the person to greet\"),\n        ),\n    )\n\n    // Add tool handler\n    s.AddTool(tool, helloHandler)\n\n    // Start the stdio server\n    if err := server.ServeStdio(s); err != nil {\n        fmt.Printf(\"Server error: %v\\n\", err)\n    }\n}\n\nfunc helloHandler(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {\n    name, err := request.RequireString(\"name\")\n    if err != nil {\n        return mcp.NewToolResultError(err.Error()), nil\n    }\n\n    return mcp.NewToolResultText(fmt.Sprintf(\"Hello, %s!\", name)), nil\n}\n```\n\nThat's it!\n\nMCP 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.\n\n### Key features:\n* **Fast**: High-level interface means less code and faster development\n* **Simple**: Build MCP servers with minimal boilerplate\n* **Complete***: MCP Go aims to provide a full implementation of the core MCP specification\n\n(\\*emphasis on *aims*)\n\n🚨 🚧 🏗️ *MCP Go is under active development, as is the MCP specification itself. Core features are working but some advanced capabilities are still in progress.* \n\n\n\u003c!-- omit in toc --\u003e\n## Table of Contents\n\n- [Installation](#installation)\n- [Quickstart](#quickstart)\n- [What is MCP?](#what-is-mcp)\n- [Core Concepts](#core-concepts)\n  - [Server](#server)\n  - [Resources](#resources)\n  - [Tools](#tools)\n  - [Prompts](#prompts)\n- [Examples](#examples)\n- [Extras](#extras)\n  - [Transports](#transports)\n  - [Session Management](#session-management)\n    - [Basic Session Handling](#basic-session-handling)\n    - [Per-Session Tools](#per-session-tools)\n    - [Tool Filtering](#tool-filtering)\n    - [Working with Context](#working-with-context)\n  - [Request Hooks](#request-hooks)\n  - [Tool Handler Middleware](#tool-handler-middleware)\n  - [Regenerating Server Code](#regenerating-server-code)\n\n## Installation\n\n```bash\ngo get github.com/mark3labs/mcp-go\n```\n\n## Quickstart\n\nLet's create a simple MCP server that exposes a calculator tool and some data:\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n\n    \"github.com/mark3labs/mcp-go/mcp\"\n    \"github.com/mark3labs/mcp-go/server\"\n)\n\nfunc main() {\n    // Create a new MCP server\n    s := server.NewMCPServer(\n        \"Calculator Demo\",\n        \"1.0.0\",\n        server.WithToolCapabilities(false),\n        server.WithRecovery(),\n    )\n\n    // Add a calculator tool\n    calculatorTool := mcp.NewTool(\"calculate\",\n        mcp.WithDescription(\"Perform basic arithmetic operations\"),\n        mcp.WithString(\"operation\",\n            mcp.Required(),\n            mcp.Description(\"The operation to perform (add, subtract, multiply, divide)\"),\n            mcp.Enum(\"add\", \"subtract\", \"multiply\", \"divide\"),\n        ),\n        mcp.WithNumber(\"x\",\n            mcp.Required(),\n            mcp.Description(\"First number\"),\n        ),\n        mcp.WithNumber(\"y\",\n            mcp.Required(),\n            mcp.Description(\"Second number\"),\n        ),\n    )\n\n    // Add the calculator handler\n    s.AddTool(calculatorTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {\n        // Using helper functions for type-safe argument access\n        op, err := request.RequireString(\"operation\")\n        if err != nil {\n            return mcp.NewToolResultError(err.Error()), nil\n        }\n        \n        x, err := request.RequireFloat(\"x\")\n        if err != nil {\n            return mcp.NewToolResultError(err.Error()), nil\n        }\n        \n        y, err := request.RequireFloat(\"y\")\n        if err != nil {\n            return mcp.NewToolResultError(err.Error()), nil\n        }\n\n        var result float64\n        switch op {\n        case \"add\":\n            result = x + y\n        case \"subtract\":\n            result = x - y\n        case \"multiply\":\n            result = x * y\n        case \"divide\":\n            if y == 0 {\n                return mcp.NewToolResultError(\"cannot divide by zero\"), nil\n            }\n            result = x / y\n        }\n\n        return mcp.NewToolResultText(fmt.Sprintf(\"%.2f\", result)), nil\n    })\n\n    // Start the server\n    if err := server.ServeStdio(s); err != nil {\n        fmt.Printf(\"Server error: %v\\n\", err)\n    }\n}\n```\n\n## What is MCP?\n\nThe [Model Context Protocol (MCP)](https://modelcontextprotocol.io) 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.\n\nMCP servers can:\n- Expose data through **Resources** (think of these sort of like GET endpoints; they are used to load information into the LLM's context)\n- Provide functionality through **Tools** (sort of like POST endpoints; they are used to execute code or otherwise produce a side effect)\n- Define interaction patterns through **Prompts** (reusable templates for LLM interactions)\n- And more!\n\nmcp-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.\n\n## Core Concepts\n\n\n### Server\n\n\u003cdetails\u003e\n\u003csummary\u003eShow Server Examples\u003c/summary\u003e\n\nThe server is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:\n\n```go\n// Create a basic server\ns := server.NewMCPServer(\n    \"My Server\",  // Server name\n    \"1.0.0\",     // Version\n)\n\n// Start the server using stdio\nif err := server.ServeStdio(s); err != nil {\n    log.Fatalf(\"Server error: %v\", err)\n}\n```\n\n\u003c/details\u003e\n\n### Resources\n\n\u003cdetails\u003e\n\u003csummary\u003eShow Resource Examples\u003c/summary\u003e\nResources are how you expose data to LLMs. They can be anything - files, API responses, database queries, system information, etc. Resources can be:\n\n- Static (fixed URI)\n- Dynamic (using URI templates)\n\nHere's a simple example of a static resource:\n\n```go\n// Static resource example - exposing a README file\nresource := mcp.NewResource(\n    \"docs://readme\",\n    \"Project README\",\n    mcp.WithResourceDescription(\"The project's README file\"), \n    mcp.WithMIMEType(\"text/markdown\"),\n)\n\n// Add resource with its handler\ns.AddResource(resource, func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {\n    content, err := os.ReadFile(\"README.md\")\n    if err != nil {\n        return nil, err\n    }\n    \n    return []mcp.ResourceContents{\n        mcp.TextResourceContents{\n            URI:      \"docs://readme\",\n            MIMEType: \"text/markdown\",\n            Text:     string(content),\n        },\n    }, nil\n})\n```\n\nAnd here's an example of a dynamic resource using a template:\n\n```go\n// Dynamic resource example - user profiles by ID\ntemplate := mcp.NewResourceTemplate(\n    \"users://{id}/profile\",\n    \"User Profile\",\n    mcp.WithTemplateDescription(\"Returns user profile information\"),\n    mcp.WithTemplateMIMEType(\"application/json\"),\n)\n\n// Add template with its handler\ns.AddResourceTemplate(template, func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {\n    // Extract ID from the URI using regex matching\n    // The server automatically matches URIs to templates\n    userID := extractIDFromURI(request.Params.URI)\n    \n    profile, err := getUserProfile(userID)  // Your DB/API call here\n    if err != nil {\n        return nil, err\n    }\n    \n    return []mcp.ResourceContents{\n        mcp.TextResourceContents{\n            URI:      request.Params.URI,\n            MIMEType: \"application/json\",\n            Text:     profile,\n        },\n    }, nil\n})\n```\n\nThe examples are simple but demonstrate the core concepts. Resources can be much more sophisticated - serving multiple contents, integrating with databases or external APIs, etc.\n\u003c/details\u003e\n\n### Tools\n\n\u003cdetails\u003e\n\u003csummary\u003eShow Tool Examples\u003c/summary\u003e\n\nTools 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.\n\n#### Task-Augmented Tools\n\nTask-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:\n\n- **TaskSupportForbidden** (default): The tool cannot be invoked as a task\n- **TaskSupportOptional**: The tool can be invoked as a task or synchronously\n- **TaskSupportRequired**: The tool must be invoked as a task\n\n```go\n// Example: A tool that requires task execution\nprocessBatchTool := mcp.NewTool(\"process_batch\",\n    mcp.WithDescription(\"Process a batch of items asynchronously\"),\n    mcp.WithTaskSupport(mcp.TaskSupportRequired),\n    mcp.WithArray(\"items\",\n        mcp.Description(\"Array of items to process\"),\n        mcp.WithStringItems(),\n        mcp.Required(),\n    ),\n)\n\n// Task tool handler returns CreateTaskResult instead of CallToolResult\ns.AddTaskTool(processBatchTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CreateTaskResult, error) {\n    items := request.GetStringSlice(\"items\", []string{})\n    \n    // Long-running work here\n    for i, item := range items {\n        select {\n        case \u003c-ctx.Done():\n            // Task was cancelled\n            return nil, ctx.Err()\n        default:\n            // Process item...\n            processItem(item)\n        }\n    }\n    \n    // Return result - task ID and metadata are managed by the server\n    return \u0026mcp.CreateTaskResult{\n        Task: mcp.Task{\n            // Task fields (ID, status, etc.) are populated by the server\n        },\n    }, nil\n})\n\n// Enable task capabilities when creating the server\ns := server.NewMCPServer(\n    \"Task Server\",\n    \"1.0.0\",\n    server.WithTaskCapabilities(\n        true, // listTasks: allows clients to list all tasks\n        true, // cancel: allows clients to cancel running tasks\n        true, // toolCallTasks: enables task augmentation for tools\n    ),\n    server.WithMaxConcurrentTasks(10), // Optional: limit concurrent running tasks\n)\n```\n\nTask execution flow:\n1. Client calls tool with task parameter\n2. Server immediately returns task ID\n3. Tool executes asynchronously in the background\n4. Client polls `tasks/result` to retrieve the result\n5. Server sends task status notifications on completion\n\nFor optional task tools, the same tool can be called synchronously (without task parameter) or asynchronously (with task parameter):\n\n```go\n// Tool with optional task support\nanalyzeTool := mcp.NewTool(\"analyze_data\",\n    mcp.WithDescription(\"Analyze data - can run sync or async\"),\n    mcp.WithTaskSupport(mcp.TaskSupportOptional),\n    mcp.WithString(\"data\", mcp.Required()),\n)\n\n// Use AddTaskTool for hybrid tools that support both modes\ns.AddTaskTool(analyzeTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CreateTaskResult, error) {\n    // This handler runs when called as a task\n    data := request.GetString(\"data\", \"\")\n    result := analyzeData(data)\n    \n    return \u0026mcp.CreateTaskResult{\n        Task: mcp.Task{},\n    }, nil\n})\n\n// The server automatically handles both sync and async invocations\n// When called without task param: executes handler and returns immediately\n// When called with task param: executes handler asynchronously\n```\n\n##### Limiting Concurrent Tasks\n\nTo prevent resource exhaustion, you can limit the number of concurrent running tasks:\n\n```go\ns := server.NewMCPServer(\n    \"Task Server\",\n    \"1.0.0\",\n    server.WithTaskCapabilities(true, true, true),\n    server.WithMaxConcurrentTasks(10), // Allow up to 10 concurrent running tasks\n)\n```\n\nWhen 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.\n\nFor traditional synchronous tools that execute and return results immediately:\n\nSimple calculation example:\n```go\ncalculatorTool := mcp.NewTool(\"calculate\",\n    mcp.WithDescription(\"Perform basic arithmetic calculations\"),\n    mcp.WithString(\"operation\",\n        mcp.Required(),\n        mcp.Description(\"The arithmetic operation to perform\"),\n        mcp.Enum(\"add\", \"subtract\", \"multiply\", \"divide\"),\n    ),\n    mcp.WithNumber(\"x\",\n        mcp.Required(),\n        mcp.Description(\"First number\"),\n    ),\n    mcp.WithNumber(\"y\",\n        mcp.Required(),\n        mcp.Description(\"Second number\"),\n    ),\n)\n\ns.AddTool(calculatorTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {\n    args := request.GetArguments()\n    op := args[\"operation\"].(string)\n    x := args[\"x\"].(float64)\n    y := args[\"y\"].(float64)\n\n    var result float64\n    switch op {\n    case \"add\":\n        result = x + y\n    case \"subtract\":\n        result = x - y\n    case \"multiply\":\n        result = x * y\n    case \"divide\":\n        if y == 0 {\n            return mcp.NewToolResultError(\"cannot divide by zero\"), nil\n        }\n        result = x / y\n    }\n    \n    return mcp.FormatNumberResult(result), nil\n})\n```\n\nHTTP request example:\n```go\nhttpTool := mcp.NewTool(\"http_request\",\n    mcp.WithDescription(\"Make HTTP requests to external APIs\"),\n    mcp.WithString(\"method\",\n        mcp.Required(),\n        mcp.Description(\"HTTP method to use\"),\n        mcp.Enum(\"GET\", \"POST\", \"PUT\", \"DELETE\"),\n    ),\n    mcp.WithString(\"url\",\n        mcp.Required(),\n        mcp.Description(\"URL to send the request to\"),\n        mcp.Pattern(\"^https?://.*\"),\n    ),\n    mcp.WithString(\"body\",\n        mcp.Description(\"Request body (for POST/PUT)\"),\n    ),\n)\n\ns.AddTool(httpTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {\n    args := request.GetArguments()\n    method := args[\"method\"].(string)\n    url := args[\"url\"].(string)\n    body := \"\"\n    if b, ok := args[\"body\"].(string); ok {\n        body = b\n    }\n\n    // Create and send request\n    var req *http.Request\n    var err error\n    if body != \"\" {\n        req, err = http.NewRequest(method, url, strings.NewReader(body))\n    } else {\n        req, err = http.NewRequest(method, url, nil)\n    }\n    if err != nil {\n        return mcp.NewToolResultErrorFromErr(\"unable to create request\", err), nil\n    }\n\n    client := \u0026http.Client{}\n    resp, err := client.Do(req)\n    if err != nil {\n        return mcp.NewToolResultErrorFromErr(\"unable to execute request\", err), nil\n    }\n    defer resp.Body.Close()\n\n    // Return response\n    respBody, err := io.ReadAll(resp.Body)\n    if err != nil {\n        return mcp.NewToolResultErrorFromErr(\"unable to read request response\", err), nil\n    }\n\n    return mcp.NewToolResultText(fmt.Sprintf(\"Status: %d\\nBody: %s\", resp.StatusCode, string(respBody))), nil\n})\n```\n\nTools can be used for any kind of computation or side effect:\n- Database queries\n- File operations  \n- External API calls\n- Calculations\n- System operations\n\nEach tool should:\n- Have a clear description\n- Validate inputs\n- Handle errors gracefully \n- Return structured responses\n- Use appropriate result types\n\n\u003c/details\u003e\n\n### Prompts\n\n\u003cdetails\u003e\n\u003csummary\u003eShow Prompt Examples\u003c/summary\u003e\n\nPrompts are reusable templates that help LLMs interact with your server effectively. They're like \"best practices\" encoded into your server. Here are some examples:\n\n```go\n// Simple greeting prompt\ns.AddPrompt(mcp.NewPrompt(\"greeting\",\n    mcp.WithPromptDescription(\"A friendly greeting prompt\"),\n    mcp.WithArgument(\"name\",\n        mcp.ArgumentDescription(\"Name of the person to greet\"),\n    ),\n), func(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {\n    name := request.Params.Arguments[\"name\"]\n    if name == \"\" {\n        name = \"friend\"\n    }\n    \n    return mcp.NewGetPromptResult(\n        \"A friendly greeting\",\n        []mcp.PromptMessage{\n            mcp.NewPromptMessage(\n                mcp.RoleAssistant,\n                mcp.NewTextContent(fmt.Sprintf(\"Hello, %s! How can I help you today?\", name)),\n            ),\n        },\n    ), nil\n})\n\n// Code review prompt with embedded resource\ns.AddPrompt(mcp.NewPrompt(\"code_review\",\n    mcp.WithPromptDescription(\"Code review assistance\"),\n    mcp.WithArgument(\"pr_number\",\n        mcp.ArgumentDescription(\"Pull request number to review\"),\n        mcp.RequiredArgument(),\n    ),\n), func(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {\n    prNumber := request.Params.Arguments[\"pr_number\"]\n    if prNumber == \"\" {\n        return nil, fmt.Errorf(\"pr_number is required\")\n    }\n    \n    return mcp.NewGetPromptResult(\n        \"Code review assistance\",\n        []mcp.PromptMessage{\n            mcp.NewPromptMessage(\n                mcp.RoleUser,\n                mcp.NewTextContent(\"Review the changes and provide constructive feedback.\"),\n            ),\n            mcp.NewPromptMessage(\n                mcp.RoleAssistant,\n                mcp.NewEmbeddedResource(mcp.ResourceContents{\n                    URI: fmt.Sprintf(\"git://pulls/%s/diff\", prNumber),\n                    MIMEType: \"text/x-diff\",\n                }),\n            ),\n        },\n    ), nil\n})\n\n// Database query builder prompt\ns.AddPrompt(mcp.NewPrompt(\"query_builder\",\n    mcp.WithPromptDescription(\"SQL query builder assistance\"),\n    mcp.WithArgument(\"table\",\n        mcp.ArgumentDescription(\"Name of the table to query\"),\n        mcp.RequiredArgument(),\n    ),\n), func(ctx context.Context, request mcp.GetPromptRequest) (*mcp.GetPromptResult, error) {\n    tableName := request.Params.Arguments[\"table\"]\n    if tableName == \"\" {\n        return nil, fmt.Errorf(\"table name is required\")\n    }\n    \n    return mcp.NewGetPromptResult(\n        \"SQL query builder assistance\",\n        []mcp.PromptMessage{\n            mcp.NewPromptMessage(\n                mcp.RoleUser,\n                mcp.NewTextContent(\"Help construct efficient and safe queries for the provided schema.\"),\n            ),\n            mcp.NewPromptMessage(\n                mcp.RoleUser,\n                mcp.NewEmbeddedResource(mcp.ResourceContents{\n                    URI: fmt.Sprintf(\"db://schema/%s\", tableName),\n                    MIMEType: \"application/json\",\n                }),\n            ),\n        },\n    ), nil\n})\n```\n\nPrompts can include:\n- System instructions\n- Required arguments\n- Embedded resources\n- Multiple messages\n- Different content types (text, images, etc.)\n- Custom URI schemes\n\n\u003c/details\u003e\n\n## Examples\n\nFor examples, see the [`examples/`](examples/) directory.\n\nKey examples include:\n- [`examples/task_tool/`](examples/task_tool/) - Demonstrates task-augmented tools with TaskSupportRequired and TaskSupportOptional modes\n- [`examples/structured_input_and_output/`](examples/structured_input_and_output/) - Shows how to use struct-based input/output schemas with type-safe tool handlers\n- [`examples/typed_tools/`](examples/typed_tools/) - Demonstrates type-safe tool handlers with strongly-typed arguments\n- [`examples/custom_context/`](examples/custom_context/) - Shows how to use custom contexts in tool handlers\n- Additional examples covering resources, prompts, and more in the examples directory\n\n## Extras\n\n### Transports\n\nMCP-Go supports stdio, SSE and streamable-HTTP transport layers. For SSE transport, you can use `SetConnectionLostHandler()` to detect and handle disconnections for implementing reconnection logic.\n\n### Session Management\n\nMCP-Go provides a robust session management system that allows you to:\n- Maintain separate state for each connected client\n- Register and track client sessions\n- Send notifications to specific clients\n- Provide per-session tool customization\n\n\u003cdetails\u003e\n\u003csummary\u003eShow Session Management Examples\u003c/summary\u003e\n\n#### Basic Session Handling\n\n```go\n// Create a server with session capabilities\ns := server.NewMCPServer(\n    \"Session Demo\",\n    \"1.0.0\",\n    server.WithToolCapabilities(true),\n)\n\n// Implement your own ClientSession\ntype MySession struct {\n    id           string\n    notifChannel chan mcp.JSONRPCNotification\n    isInitialized bool\n    // Add custom fields for your application\n}\n\n// Implement the ClientSession interface\nfunc (s *MySession) SessionID() string {\n    return s.id\n}\n\nfunc (s *MySession) NotificationChannel() chan\u003c- mcp.JSONRPCNotification {\n    return s.notifChannel\n}\n\nfunc (s *MySession) Initialize() {\n    s.isInitialized = true\n}\n\nfunc (s *MySession) Initialized() bool {\n    return s.isInitialized\n}\n\n// Register a session\nsession := \u0026MySession{\n    id:           \"user-123\",\n    notifChannel: make(chan mcp.JSONRPCNotification, 10),\n}\nif err := s.RegisterSession(context.Background(), session); err != nil {\n    log.Printf(\"Failed to register session: %v\", err)\n}\n\n// Send notification to a specific client\nerr := s.SendNotificationToSpecificClient(\n    session.SessionID(),\n    \"notification/update\",\n    map[string]any{\"message\": \"New data available!\"},\n)\nif err != nil {\n    log.Printf(\"Failed to send notification: %v\", err)\n}\n\n// Unregister session when done\ns.UnregisterSession(context.Background(), session.SessionID())\n```\n\n#### Per-Session Tools\n\nFor more advanced use cases, you can implement the `SessionWithTools` interface to support per-session tool customization:\n\n```go\n// Implement SessionWithTools interface for per-session tools\ntype MyAdvancedSession struct {\n    MySession  // Embed the basic session\n    sessionTools map[string]server.ServerTool\n}\n\n// Implement additional methods for SessionWithTools\nfunc (s *MyAdvancedSession) GetSessionTools() map[string]server.ServerTool {\n    return s.sessionTools\n}\n\nfunc (s *MyAdvancedSession) SetSessionTools(tools map[string]server.ServerTool) {\n    s.sessionTools = tools\n}\n\n// Create and register a session with tools support\nadvSession := \u0026MyAdvancedSession{\n    MySession: MySession{\n        id:           \"user-456\",\n        notifChannel: make(chan mcp.JSONRPCNotification, 10),\n    },\n    sessionTools: make(map[string]server.ServerTool),\n}\nif err := s.RegisterSession(context.Background(), advSession); err != nil {\n    log.Printf(\"Failed to register session: %v\", err)\n}\n\n// Add session-specific tools\nuserSpecificTool := mcp.NewTool(\n    \"user_data\",\n    mcp.WithDescription(\"Access user-specific data\"),\n)\n// You can use AddSessionTool (similar to AddTool)\nerr := s.AddSessionTool(\n    advSession.SessionID(),\n    userSpecificTool,\n    func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {\n        // This handler is only available to this specific session\n        return mcp.NewToolResultText(\"User-specific data for \" + advSession.SessionID()), nil\n    },\n)\nif err != nil {\n    log.Printf(\"Failed to add session tool: %v\", err)\n}\n\n// Or use AddSessionTools directly with ServerTool\n/*\nerr := s.AddSessionTools(\n    advSession.SessionID(),\n    server.ServerTool{\n        Tool: userSpecificTool,\n        Handler: func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {\n            // This handler is only available to this specific session\n            return mcp.NewToolResultText(\"User-specific data for \" + advSession.SessionID()), nil\n        },\n    },\n)\nif err != nil {\n    log.Printf(\"Failed to add session tool: %v\", err)\n}\n*/\n\n// Delete session-specific tools when no longer needed\nerr = s.DeleteSessionTools(advSession.SessionID(), \"user_data\")\nif err != nil {\n    log.Printf(\"Failed to delete session tool: %v\", err)\n}\n```\n\n#### Tool Filtering\n\nYou can also apply filters to control which tools are available to certain sessions:\n\n```go\n// Add a tool filter that only shows tools with certain prefixes\ns := server.NewMCPServer(\n    \"Tool Filtering Demo\",\n    \"1.0.0\",\n    server.WithToolCapabilities(true),\n    server.WithToolFilter(func(ctx context.Context, tools []mcp.Tool) []mcp.Tool {\n        // Get session from context\n        session := server.ClientSessionFromContext(ctx)\n        if session == nil {\n            return tools // Return all tools if no session\n        }\n        \n        // Example: filter tools based on session ID prefix\n        if strings.HasPrefix(session.SessionID(), \"admin-\") {\n            // Admin users get all tools\n            return tools\n        } else {\n            // Regular users only get tools with \"public-\" prefix\n            var filteredTools []mcp.Tool\n            for _, tool := range tools {\n                if strings.HasPrefix(tool.Name, \"public-\") {\n                    filteredTools = append(filteredTools, tool)\n                }\n            }\n            return filteredTools\n        }\n    }),\n)\n```\n\n#### Working with Context\n\nThe session context is automatically passed to tool and resource handlers:\n\n```go\ns.AddTool(mcp.NewTool(\"session_aware\"), func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {\n    // Get the current session from context\n    session := server.ClientSessionFromContext(ctx)\n    if session == nil {\n        return mcp.NewToolResultError(\"No active session\"), nil\n    }\n    \n    return mcp.NewToolResultText(\"Hello, session \" + session.SessionID()), nil\n})\n\n// When using handlers in HTTP/SSE servers, you need to pass the context with the session\nhttpHandler := func(w http.ResponseWriter, r *http.Request) {\n    // Get session from somewhere (like a cookie or header)\n    session := getSessionFromRequest(r)\n    \n    // Add session to context\n    ctx := s.WithContext(r.Context(), session)\n    \n    // Use this context when handling requests\n    // ...\n}\n```\n\n\u003c/details\u003e\n\n### Request Hooks\n\nHook into the request lifecycle by creating a `Hooks` object with your\nselection among the possible callbacks.  This enables telemetry across all\nfunctionality, and observability of various facts, for example the ability\nto count improperly-formatted requests, or to log the agent identity during\ninitialization.\n\nAdd the `Hooks` to the server at the time of creation using the\n`server.WithHooks` option.\n\n### Tool Handler Middleware\n\nAdd middleware to tool call handlers using the `server.WithToolHandlerMiddleware` option. Middlewares can be registered on server creation and are applied on every tool call.\n\nA recovery middleware option is available to recover from panics in a tool call and can be added to the server with the `server.WithRecovery` option.\n\n### Prompt Handler Middleware\n\nAdd middleware to prompt handlers using the `server.WithPromptHandlerMiddleware` option. Middlewares can be registered on server creation and are applied on every `prompts/get` call.\n\n### Prompt Filtering\n\nFilter prompts based on context using the `server.WithPromptFilter` option. This works the same way as tool filtering but applies to `prompts/list` results.\n\n### Regenerating Server Code\n\nServer hooks and request handlers are generated. Regenerate them by running:\n\n```bash\ngo generate ./...\n```\n\nYou need `go` installed and the `goimports` tool available. The generator runs\n`goimports` automatically to format and fix imports.\n\n### Auto-completions\n\nWhen users are filling in argument values for a specific prompt (identified by name) or resource template (identified by URI), servers can provide contextual suggestions.\nTo enable completion support, use the `server.WithCompletions()` option when creating your server.\n\n#### Completion Providers\n\nYou can provide completion logic for both prompt arguments and resource template arguments by implementing the respective interfaces and passing them to the server as options.\n\n\u003cdetails\u003e\n\u003csummary\u003eShow Completion Provider Examples\u003c/summary\u003e\n\n```go\ntype MyPromptCompletionProvider struct{}\n\nfunc (p *MyPromptCompletionProvider) CompletePromptArgument(\n    ctx context.Context,\n    promptName string,\n    argument mcp.CompleteArgument,\n    context mcp.CompleteContext,\n) (*mcp.Completion, error) {\n    // Example: provide style suggestions for a \"code_review\" prompt\n    if promptName == \"code_review\" \u0026\u0026 argument.Name == \"style\" {\n        styles := []string{\"formal\", \"casual\", \"technical\", \"creative\"}\n        var suggestions []string\n        \n        // Filter based on current input\n        for _, style := range styles {\n            if strings.HasPrefix(style, argument.Value) {\n                suggestions = append(suggestions, style)\n            }\n        }\n        \n        return \u0026mcp.Completion{\n            Values: suggestions,\n        }, nil\n    }\n    \n    // Return empty suggestions for unhandled cases\n    return \u0026mcp.Completion{Values: []string{}}, nil\n}\n\ntype MyResourceCompletionProvider struct{}\n\nfunc (p *MyResourceCompletionProvider) CompleteResourceArgument(\n    ctx context.Context,\n    uri string,\n    argument mcp.CompleteArgument,\n    context mcp.CompleteContext,\n) (*mcp.Completion, error) {\n    // Example: provide file path completions\n    if uri == \"file:///{path}\" \u0026\u0026 argument.Name == \"path\" {\n        // You can access previously completed arguments from context.Arguments\n        // context.Arguments is a map[string]string of already-resolved arguments\n        \n        paths := getMatchingPaths(argument.Value) // Your custom logic\n        \n        return \u0026mcp.Completion{\n            Values:  paths[:min(len(paths), 100)], // Max 100 items\n            Total:   len(paths),                    // Total available matches\n            HasMore: len(paths) \u003e 100,              // More results available\n        }, nil\n    }\n    \n    return \u0026mcp.Completion{Values: []string{}}, nil\n}\n\n// Register the provider\nmcpServer := server.NewMCPServer(\n    \"my-server\",\n    \"1.0.0\",\n    server.WithCompletions(),\n    server.WithPromptCompletionProvider(\u0026MyPromptCompletionProvider{}),\n    server.WithResourceCompletionProvider(\u0026MyResourceCompletionProvider{}),\n)\n```\n\n\u003c/details\u003e\n\n#### Completion Context\n\nFor prompts or resource templates with multiple arguments, the `CompleteContext` parameter provides access to previously completed arguments. This allows you to provide contextual suggestions based on earlier choices.\n\n\u003cdetails\u003e\n\u003csummary\u003eShow Completion Context Example\u003c/summary\u003e\n\n```go\nfunc (p *MyProvider) CompleteResourceArgument(\n    ctx context.Context,\n    uri string,\n    argument mcp.CompleteArgument,\n    context mcp.CompleteContext,\n) (*mcp.Completion, error) {\n    // Access previously completed arguments\n    if previousValue, ok := context.Arguments[\"previous_arg\"]; ok {\n        // Provide suggestions based on previous_arg value\n        return getSuggestionsFor(argument.Value, previousValue), nil\n    }\n    \n    return \u0026mcp.Completion{Values: []string{}}, nil\n}\n```\n\n\u003c/details\u003e\n\n#### Response Constraints\n\nWhen returning completion results:\n- Maximum 100 items per response\n- Use `Total` to indicate the total number of available matches\n- Use `HasMore` to signal if additional results exist beyond the returned values\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmark3labs%2Fmcp-go","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmark3labs%2Fmcp-go","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmark3labs%2Fmcp-go/lists"}