[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-5139":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":17,"stars7d":18,"stars30d":19,"stars90d":16,"forks30d":16,"starsTrendScore":20,"compositeScore":21,"rankGlobal":10,"rankLanguage":10,"license":22,"archived":23,"fork":23,"defaultBranch":24,"hasWiki":25,"hasPages":25,"topics":26,"createdAt":10,"pushedAt":10,"updatedAt":27,"readmeContent":28,"aiSummary":29,"trendingCount":16,"starSnapshotCount":16,"syncStatus":30,"lastSyncTime":31,"discoverSource":32},5139,"mcp-go","mark3labs\u002Fmcp-go","mark3labs","A Go implementation of the Model Context Protocol (MCP), enabling seamless integration between LLM applications and external data sources and tools.","http:\u002F\u002Fmcp-go.dev\u002F",null,"Go",8796,842,52,10,0,1,26,114,14,89.78,"MIT License",false,"main",true,[],"2026-06-12 04:00:24","\u003C!-- omit in toc -->\n\u003Cdiv align=\"center\">\n\u003Cimg src=\".\u002Flogo.png\" alt=\"MCP Go Logo\">\n\n[![Build](https:\u002F\u002Fgithub.com\u002Fmark3labs\u002Fmcp-go\u002Factions\u002Fworkflows\u002Fci.yml\u002Fbadge.svg?branch=main)](https:\u002F\u002Fgithub.com\u002Fmark3labs\u002Fmcp-go\u002Factions\u002Fworkflows\u002Fci.yml)\n[![Go Report Card](https:\u002F\u002Fgoreportcard.com\u002Fbadge\u002Fgithub.com\u002Fmark3labs\u002Fmcp-go?cache)](https:\u002F\u002Fgoreportcard.com\u002Freport\u002Fgithub.com\u002Fmark3labs\u002Fmcp-go)\n[![GoDoc](https:\u002F\u002Fpkg.go.dev\u002Fbadge\u002Fgithub.com\u002Fmark3labs\u002Fmcp-go.svg)](https:\u002F\u002Fpkg.go.dev\u002Fgithub.com\u002Fmark3labs\u002Fmcp-go)\n\n[![AgentRank](https:\u002F\u002Fagentrank-ai.com\u002Fapi\u002Fbadge\u002Ftool\u002Fmark3labs--mcp-go)](https:\u002F\u002Fagentrank-ai.com\u002Ftool\u002Fmark3labs--mcp-go\u002F)\n\u003Cstrong>A Go implementation of the Model Context Protocol (MCP), enabling seamless integration between LLM applications and external data sources and tools.\u003C\u002Fstrong>\n\n\u003Cbr>\n\n[![Tutorial](http:\u002F\u002Fimg.youtube.com\u002Fvi\u002FqoaeYMrXJH0\u002F0.jpg)](http:\u002F\u002Fwww.youtube.com\u002Fwatch?v=qoaeYMrXJH0 \"Tutorial\")\n\n\u003Cbr>\n\nDiscuss the SDK on [Discord](https:\u002F\u002Fdiscord.gg\u002FRqSS2NQVsY)\n\n\u003C\u002Fdiv>\n\n\n```go\npackage main\n\nimport (\n    \"context\"\n    \"fmt\"\n\n    \"github.com\u002Fmark3labs\u002Fmcp-go\u002Fmcp\"\n    \"github.com\u002Fmark3labs\u002Fmcp-go\u002Fserver\"\n)\n\nfunc main() {\n    \u002F\u002F Create a new MCP server\n    s := server.NewMCPServer(\n        \"Demo 🚀\",\n        \"1.0.0\",\n        server.WithToolCapabilities(false),\n    )\n\n    \u002F\u002F 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    \u002F\u002F Add tool handler\n    s.AddTool(tool, helloHandler)\n\n    \u002F\u002F 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 -->\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  - [OAuth Protected Resource Metadata](#oauth-protected-resource-metadata)\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\u002Fmark3labs\u002Fmcp-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\u002Fmark3labs\u002Fmcp-go\u002Fmcp\"\n    \"github.com\u002Fmark3labs\u002Fmcp-go\u002Fserver\"\n)\n\nfunc main() {\n    \u002F\u002F 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    \u002F\u002F 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    \u002F\u002F Add the calculator handler\n    s.AddTool(calculatorTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error) {\n        \u002F\u002F 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 \u002F y\n        }\n\n        return mcp.NewToolResultText(fmt.Sprintf(\"%.2f\", result)), nil\n    })\n\n    \u002F\u002F 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:\u002F\u002Fmodelcontextprotocol.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>\n\u003Csummary>Show Server Examples\u003C\u002Fsummary>\n\nThe server is your core interface to the MCP protocol. It handles connection management, protocol compliance, and message routing:\n\n```go\n\u002F\u002F Create a basic server\ns := server.NewMCPServer(\n    \"My Server\",  \u002F\u002F Server name\n    \"1.0.0\",     \u002F\u002F Version\n)\n\n\u002F\u002F Start the server using stdio\nif err := server.ServeStdio(s); err != nil {\n    log.Fatalf(\"Server error: %v\", err)\n}\n```\n\n\u003C\u002Fdetails>\n\n### Resources\n\n\u003Cdetails>\n\u003Csummary>Show Resource Examples\u003C\u002Fsummary>\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\u002F\u002F Static resource example - exposing a README file\nresource := mcp.NewResource(\n    \"docs:\u002F\u002Freadme\",\n    \"Project README\",\n    mcp.WithResourceDescription(\"The project's README file\"), \n    mcp.WithMIMEType(\"text\u002Fmarkdown\"),\n)\n\n\u002F\u002F 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:\u002F\u002Freadme\",\n            MIMEType: \"text\u002Fmarkdown\",\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\u002F\u002F Dynamic resource example - user profiles by ID\ntemplate := mcp.NewResourceTemplate(\n    \"users:\u002F\u002F{id}\u002Fprofile\",\n    \"User Profile\",\n    mcp.WithTemplateDescription(\"Returns user profile information\"),\n    mcp.WithTemplateMIMEType(\"application\u002Fjson\"),\n)\n\n\u002F\u002F Add template with its handler\ns.AddResourceTemplate(template, func(ctx context.Context, request mcp.ReadResourceRequest) ([]mcp.ResourceContents, error) {\n    \u002F\u002F Extract ID from the URI using regex matching\n    \u002F\u002F The server automatically matches URIs to templates\n    userID := extractIDFromURI(request.Params.URI)\n    \n    profile, err := getUserProfile(userID)  \u002F\u002F Your DB\u002FAPI 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\u002Fjson\",\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\u002Fdetails>\n\n### Tools\n\n\u003Cdetails>\n\u003Csummary>Show Tool Examples\u003C\u002Fsummary>\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\u002F\u002F 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\u002F\u002F 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    \u002F\u002F Long-running work here\n    for i, item := range items {\n        select {\n        case \u003C-ctx.Done():\n            \u002F\u002F Task was cancelled\n            return nil, ctx.Err()\n        default:\n            \u002F\u002F Process item...\n            processItem(item)\n        }\n    }\n    \n    \u002F\u002F Return result - task ID and metadata are managed by the server\n    return &mcp.CreateTaskResult{\n        Task: mcp.Task{\n            \u002F\u002F Task fields (ID, status, etc.) are populated by the server\n        },\n    }, nil\n})\n\n\u002F\u002F Enable task capabilities when creating the server\ns := server.NewMCPServer(\n    \"Task Server\",\n    \"1.0.0\",\n    server.WithTaskCapabilities(\n        true, \u002F\u002F listTasks: allows clients to list all tasks\n        true, \u002F\u002F cancel: allows clients to cancel running tasks\n        true, \u002F\u002F toolCallTasks: enables task augmentation for tools\n    ),\n    server.WithMaxConcurrentTasks(10), \u002F\u002F 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\u002Fresult` 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\u002F\u002F 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\u002F\u002F Use AddTaskTool for hybrid tools that support both modes\ns.AddTaskTool(analyzeTool, func(ctx context.Context, request mcp.CallToolRequest) (*mcp.CreateTaskResult, error) {\n    \u002F\u002F This handler runs when called as a task\n    data := request.GetString(\"data\", \"\")\n    result := analyzeData(data)\n    \n    return &mcp.CreateTaskResult{\n        Task: mcp.Task{},\n    }, nil\n})\n\n\u002F\u002F The server automatically handles both sync and async invocations\n\u002F\u002F When called without task param: executes handler and returns immediately\n\u002F\u002F 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), \u002F\u002F 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 \u002F 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?:\u002F\u002F.*\"),\n    ),\n    mcp.WithString(\"body\",\n        mcp.Description(\"Request body (for POST\u002FPUT)\"),\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    \u002F\u002F 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 := &http.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    \u002F\u002F 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\u002Fdetails>\n\n### Prompts\n\n\u003Cdetails>\n\u003Csummary>Show Prompt Examples\u003C\u002Fsummary>\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\u002F\u002F 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\u002F\u002F 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:\u002F\u002Fpulls\u002F%s\u002Fdiff\", prNumber),\n                    MIMEType: \"text\u002Fx-diff\",\n                }),\n            ),\n        },\n    ), nil\n})\n\n\u002F\u002F 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:\u002F\u002Fschema\u002F%s\", tableName),\n                    MIMEType: \"application\u002Fjson\",\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\u002Fdetails>\n\n## Examples\n\nFor examples, see the [`examples\u002F`](examples\u002F) directory.\n\nKey examples include:\n- [`examples\u002Ftask_tool\u002F`](examples\u002Ftask_tool\u002F) - Demonstrates task-augmented tools with TaskSupportRequired and TaskSupportOptional modes\n- [`examples\u002Fstructured_input_and_output\u002F`](examples\u002Fstructured_input_and_output\u002F) - Shows how to use struct-based input\u002Foutput schemas with type-safe tool handlers\n- [`examples\u002Ftyped_tools\u002F`](examples\u002Ftyped_tools\u002F) - Demonstrates type-safe tool handlers with strongly-typed arguments\n- [`examples\u002Fcustom_context\u002F`](examples\u002Fcustom_context\u002F) - 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### Embedding StreamableHTTP in non-net\u002Fhttp frameworks\n\n`StreamableHTTPServer` is an `http.Handler`, so it can be mounted in any\nrouter that speaks `net\u002Fhttp`. To embed it in a framework that does **not**\ngo through `net\u002Fhttp` (e.g. [fasthttp](https:\u002F\u002Fgithub.com\u002Fvalyala\u002Ffasthttp)\nor [fiber](https:\u002F\u002Fgofiber.io\u002F)) without buffering the response through an\nadaptor, use the transport-agnostic `Handle` entry point:\n\n```go\nfunc (s *StreamableHTTPServer) Handle(w HTTPResponseWriter, r *HTTPRequest)\n```\n\n`HTTPRequest` is a plain struct (`Method`, `URL`, `Header`, `Body`,\n`Context`) and `HTTPResponseWriter` is a small interface (`Header`,\n`WriteHeader`, `Write`, `Flush`, `CanStream`). Implementations whose\nunderlying transport cannot stream MUST return `false` from `CanStream`;\nthe server will then reject GET (SSE listening) with `405 Method Not\nAllowed` and keep POST responses as buffered `application\u002Fjson` instead of\nupgrading to `text\u002Fevent-stream`.\n\nSee the [HTTP transport docs](https:\u002F\u002Fmcp-go.dev\u002Ftransports\u002Fhttp#embedding-in-non-nethttp-frameworks)\nfor a full fasthttp\u002Ffiber adapter example. `ServeHTTP` is unchanged and\nremains the conventional `net\u002Fhttp` entry point.\n\n### OAuth Protected Resource Metadata\n\nServers that require OAuth can advertise their authorization requirements\nvia the [RFC 9728](https:\u002F\u002Fdatatracker.ietf.org\u002Fdoc\u002Fhtml\u002Frfc9728)\n`\u002F.well-known\u002Foauth-protected-resource` endpoint referenced by the\n[MCP authorization spec](https:\u002F\u002Fmodelcontextprotocol.io\u002Fspecification\u002F2025-06-18\u002Fbasic\u002Fauthorization).\nUse `server.WithProtectedResourceMetadata` (or\n`server.WithSSEProtectedResourceMetadata`) to auto-mount the endpoint, or\n`server.NewProtectedResourceMetadataHandler` to wire it into a custom router.\nSee the [HTTP transport docs](https:\u002F\u002Fmcp-go.dev\u002Ftransports\u002Fhttp#oauth-protected-resource-metadata-rfc-9728) for examples.\n\n```go\nhttpServer := server.NewStreamableHTTPServer(mcpServer,\n    server.WithProtectedResourceMetadata(server.ProtectedResourceMetadataConfig{\n        Resource:             \"https:\u002F\u002Fmy-mcp-server.com\",\n        AuthorizationServers: []string{\"https:\u002F\u002Fauth.example.com\"},\n        ScopesSupported:      []string{\"mcp:read\", \"mcp:write\"},\n    }),\n)\n```\n\n### CORS for browser-based clients\n\nServers exposed to browser-based MCP clients can opt into Cross-Origin\nResource Sharing handling on either HTTP transport. CORS is disabled by\ndefault; configure it explicitly via `server.WithStreamableHTTPCORS` or\n`server.WithSSECORS`:\n\n```go\nhttpServer := server.NewStreamableHTTPServer(mcpServer,\n    server.WithEndpointPath(\"\u002Fmcp\"),\n    server.WithStreamableHTTPCORS(\n        server.WithCORSAllowedOrigins(\"https:\u002F\u002Fmy-ai-app.com\", \"http:\u002F\u002Flocalhost:3000\"),\n        server.WithCORSAllowCredentials(),\n        server.WithCORSMaxAge(300),\n    ),\n)\n```\n\nThe transport answers preflight (`OPTIONS`) requests directly and decorates\nsimple responses with the appropriate `Access-Control-Allow-Origin`,\n`Access-Control-Allow-Credentials`, `Access-Control-Expose-Headers` and\n`Vary` headers. Sensible defaults are used when the corresponding option is\nomitted (`GET, POST, DELETE, OPTIONS` for methods; `Content-Type,\nMcp-Session-Id, Last-Event-ID, Authorization` for request headers;\n`Mcp-Session-Id` for exposed headers). Combining `WithCORSAllowedOrigins(\"*\")`\nwith `WithCORSAllowCredentials()` echoes the request `Origin` to remain\nspec-compliant.\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>\n\u003Csummary>Show Session Management Examples\u003C\u002Fsummary>\n\n#### Basic Session Handling\n\n```go\n\u002F\u002F Create a server with session capabilities\ns := server.NewMCPServer(\n    \"Session Demo\",\n    \"1.0.0\",\n    server.WithToolCapabilities(true),\n)\n\n\u002F\u002F Implement your own ClientSession\ntype MySession struct {\n    id           string\n    notifChannel chan mcp.JSONRPCNotification\n    isInitialized bool\n    \u002F\u002F Add custom fields for your application\n}\n\n\u002F\u002F 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\u002F\u002F Register a session\nsession := &MySession{\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\u002F\u002F Send notification to a specific client\nerr := s.SendNotificationToSpecificClient(\n    session.SessionID(),\n    \"notification\u002Fupdate\",\n    map[string]any{\"message\": \"New data available!\"},\n)\nif err != nil {\n    log.Printf(\"Failed to send notification: %v\", err)\n}\n\n\u002F\u002F 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\u002F\u002F Implement SessionWithTools interface for per-session tools\ntype MyAdvancedSession struct {\n    MySession  \u002F\u002F Embed the basic session\n    sessionTools map[string]server.ServerTool\n}\n\n\u002F\u002F 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\u002F\u002F Create and register a session with tools support\nadvSession := &MyAdvancedSession{\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\u002F\u002F Add session-specific tools\nuserSpecificTool := mcp.NewTool(\n    \"user_data\",\n    mcp.WithDescription(\"Access user-specific data\"),\n)\n\u002F\u002F 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        \u002F\u002F 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\u002F\u002F Or use AddSessionTools directly with ServerTool\n\u002F*\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            \u002F\u002F 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*\u002F\n\n\u002F\u002F 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\u002F\u002F 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        \u002F\u002F Get session from context\n        session := server.ClientSessionFromContext(ctx)\n        if session == nil {\n            return tools \u002F\u002F Return all tools if no session\n        }\n        \n        \u002F\u002F Example: filter tools based on session ID prefix\n        if strings.HasPrefix(session.SessionID(), \"admin-\") {\n            \u002F\u002F Admin users get all tools\n            return tools\n        } else {\n            \u002F\u002F 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    \u002F\u002F 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\u002F\u002F When using handlers in HTTP\u002FSSE servers, you need to pass the context with the session\nhttpHandler := func(w http.ResponseWriter, r *http.Request) {\n    \u002F\u002F Get session from somewhere (like a cookie or header)\n    session := getSessionFromRequest(r)\n    \n    \u002F\u002F Add session to context\n    ctx := s.WithContext(r.Context(), session)\n    \n    \u002F\u002F Use this context when handling requests\n    \u002F\u002F ...\n}\n```\n\n\u003C\u002Fdetails>\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\u002Fget` 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\u002Flist` results.\n\n### Regenerating Server Code\n\nServer hooks and request handlers are generated. Regenerate them by running:\n\n```bash\ngo generate .\u002F...\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>\n\u003Csummary>Show Completion Provider Examples\u003C\u002Fsummary>\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    \u002F\u002F Example: provide style suggestions for a \"code_review\" prompt\n    if promptName == \"code_review\" && argument.Name == \"style\" {\n        styles := []string{\"formal\", \"casual\", \"technical\", \"creative\"}\n        var suggestions []string\n        \n        \u002F\u002F 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 &mcp.Completion{\n            Values: suggestions,\n        }, nil\n    }\n    \n    \u002F\u002F Return empty suggestions for unhandled cases\n    return &mcp.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    \u002F\u002F Example: provide file path completions\n    if uri == \"file:\u002F\u002F\u002F{path}\" && argument.Name == \"path\" {\n        \u002F\u002F You can access previously completed arguments from context.Arguments\n        \u002F\u002F context.Arguments is a map[string]string of already-resolved arguments\n        \n        paths := getMatchingPaths(argument.Value) \u002F\u002F Your custom logic\n        \n        return &mcp.Completion{\n            Values:  paths[:min(len(paths), 100)], \u002F\u002F Max 100 items\n            Total:   len(paths),                    \u002F\u002F Total available matches\n            HasMore: len(paths) > 100,              \u002F\u002F More results available\n        }, nil\n    }\n    \n    return &mcp.Completion{Values: []string{}}, nil\n}\n\n\u002F\u002F Register the provider\nmcpServer := server.NewMCPServer(\n    \"my-server\",\n    \"1.0.0\",\n    server.WithCompletions(),\n    server.WithPromptCompletionProvider(&MyPromptCompletionProvider{}),\n    server.WithResourceCompletionProvider(&MyResourceCompletionProvider{}),\n)\n```\n\n\u003C\u002Fdetails>\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>\n\u003Csummary>Show Completion Context Example\u003C\u002Fsummary>\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    \u002F\u002F Access previously completed arguments\n    if previousValue, ok := context.Arguments[\"previous_arg\"]; ok {\n        \u002F\u002F Provide suggestions based on previous_arg value\n        return getSuggestionsFor(argument.Value, previousValue), nil\n    }\n    \n    return &mcp.Completion{Values: []string{}}, nil\n}\n```\n\n\u003C\u002Fdetails>\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","mcp-go 是一个用 Go 语言实现的 Model Context Protocol (MCP)，旨在实现 LLM 应用与外部数据源和工具之间的无缝集成。其核心功能包括快速开发、简单易用以及对 MCP 核心规范的全面支持，通过提供高层次接口减少代码量并简化服务器管理过程。适用于需要将大语言模型应用与多样化的外部服务或数据库连接起来的场景，如构建智能助手、自动化工作流等。由于项目仍处于积极开发阶段，部分高级特性可能尚未完全成熟。",2,"2026-06-11 03:02:42","top_language"]