首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Go 语言实现 MCP 鉴权,你用的哪种认证方案?

Go 语言实现 MCP 鉴权,你用的哪种认证方案?

作者头像
技术圈
发布2026-04-17 16:41:43
发布2026-04-17 16:41:43
620
举报

在 AI 应用开发中,Model Context Protocol(MCP)已成为连接大模型与外部工具的桥梁。随着 MCP 服务在生产环境中的部署越来越多,鉴权问题也变得至关重要——如何确保只有合法用户才能访问你的 MCP 工具?如何实现细粒度的权限控制?

结合我的项目经验,这篇文章分享一下在 Go 语言中实现 MCP 鉴权的方案。

为什么 MCP 需要鉴权?

简单来说,MCP 是你 AI 系统的"工具箱"——它让 AI 能够调用各种外部工具和资源。如果这个"工具箱"没有任何保护,那相当于你家门钥匙挂在外面,任何人都能进来翻箱倒柜。

常见的鉴权场景包括:

  • 多租户 SaaS 服务:不同用户访问不同的工具和数据
  • 敏感工具保护:如支付、删除、写入等高危操作需要验证
  • 流量控制和审计:知道谁在什么时间调用了什么工具

MCP 官方认证规范

根据 MCP 官方规范,MCP 认证有以下关键要点:

  • 认证是可选的(OPTIONAL),但推荐在生产环境中启用
  • 唯一官方认证方式是 OAuth 2.1,支持 Authorization Code(授权码模式)和 Client Credentials(客户端凭证模式)两种授权类型
  • 客户端必须通过 Authorization: Bearer <access-token> 请求头发送访问令牌
  • 认证仅在 HTTP 传输层实现,STDIO 传输不应使用此规范,而应从环境变量获取凭证
  • 服务器通过 /.well-known/oauth-authorization-server 端点进行元数据发现

⚠️ 注意:MCP 规范没有将 JWT Token 或 API Key 定义为独立的认证方式。JWT 仅可作为 OAuth 2.1 访问令牌的载体格式出现。

Go SDK 的认证支持现状

目前 github.com/mark3labs/mcp-go(v0.48.0)的认证支持情况如下:

代码语言:javascript
复制
✅ 完整支持(PKCE、元数据发现、动态客户端注册)

也就是说,服务端认证需要开发者自行实现。下面我们来看几种实战方案。

方案一:基于 OAuth 2.1 的完整认证(推荐)

OAuth 2.1 是 MCP 规范唯一推荐的认证方式,特别适合需要第三方登录和用户授权的场景。

工作原理

  1. 用户通过授权服务器登录(如 Google、GitHub、企业 IDP)
  2. 获取访问令牌(Access Token)和刷新令牌
  3. 携带令牌通过 Authorization: Bearer <token> 访问 MCP 服务
  4. 服务端验证令牌,可调用用户信息端点获取详情

Go 语言实现

第一步:创建 MCP Server 并注册工具

代码语言:javascript
复制
s := server.NewMCPServer("auth-server", "1.0.0",
    server.WithToolHandlerMiddleware(toolAuthMiddleware),
)
s.AddTool(mcp.NewTool("hello", mcp.WithDescription("Say hello")), handleHello)
// 创建 HTTP Server 并用认证中间件包装
httpServer := server.NewStreamableHTTPServer(s)
http.Handle("/mcp", authMiddleware(httpServer))
log.Fatal(http.ListenAndServe(":8080", nil))

第二步:HTTP 认证中间件 + Tool 级别中间件

代码语言:javascript
复制
// HTTP 中间件:拦截请求,验证 Bearer Token 并注入 context
func authMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ")
        // ... verify token here
        userInfo, err := verifyToken(r.Context(), token) // OIDC 验证
        // ... handle err here
        ctx := context.WithValue(r.Context(), "user", userInfo)
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

// Tool 级别中间件(可选):类型为 func(ToolHandlerFunc) ToolHandlerFunc
func toolAuthMiddleware(next server.ToolHandlerFunc) server.ToolHandlerFunc {
    returnfunc(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
        // 可在此做额外权限检查(如 Scopes)
        return next(ctx, req)
    }
}

第三步:在 Tool Handler 中获取认证信息

代码语言:javascript
复制
func handleHello(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
    userInfo, ok := ctx.Value("user").(*UserInfo)
    if !ok {
        return &mcp.CallToolResult{
            Content: []mcp.Content{&mcp.TextContent{Text: "Unauthorized"}},
            IsError: true,
        }, nil
    }
    return &mcp.CallToolResult{
        Content: []mcp.Content{&mcp.TextContent{
            Text: fmt.Sprintf("Hello, %s!", userInfo.Name),
        }},
    }, nil
}

第四步:OIDC Token 验证

代码语言:javascript
复制
import "github.com/coreos/go-oidc/v3/oidc"

func verifyToken(ctx context.Context, token string) (*UserInfo, error) {
    provider, _ := oidc.NewProvider(ctx, "https://your-org.okta.com")
    verifier := provider.Verifier(&oidc.Config{ClientID: "your-client-id"})
    idToken, err := verifier.Verify(ctx, token) // 验证签名和有效期
    // ... handle err here
    var claims struct {
        Name  string`json:"name"`
        Email string`json:"email"`
    }
    idToken.Claims(&claims) // 提取用户信息
    return &UserInfo{Name: claims.Name, Email: claims.Email}, nil
}

适用场景

  • 需要支持第三方登录(Google、GitHub 等)
  • 企业级应用,需要与现有 IDP 集成
  • 需要用户授权特定权限范围
  • MCP 规范唯一推荐的认证方式

优缺点

优点

缺点

MCP 规范唯一推荐,标准化程度最高

实现复杂度最高

安全性最高,支持令牌撤销和刷新

依赖外部授权服务器

用户体验好,支持单点登录(SSO)

需要处理 PKCE、元数据发现等流程

方案二:自定义 Bearer Token 认证

如果暂时不想引入完整的 OAuth 2.1 基础设施,可以自行实现一个轻量级的 Bearer Token 认证。这种方式不属于 MCP 规范定义的标准认证,但可以作为快速上手的过渡方案。

工作原理

  1. 服务端为每个用户/应用生成唯一的 Token
  2. 客户端请求时放在 Authorization: Bearer <token> 头中
  3. 服务端验证 Token 的有效性(查数据库或缓存)

Go 语言实现

代码语言:javascript
复制
// 简单的 Token 验证中间件
func simpleAuthMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ")
        user, err := db.FindUserByToken(r.Context(), token) // 查库验证
        // ... handle err here
        ctx := context.WithValue(r.Context(), "user", user)
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

适用场景

  • 内部服务间调用
  • 开发和测试环境
  • 快速原型验证

优缺点

优点

缺点

实现简单,快速上手

不符合 MCP 规范标准

验证高效(直接查表)

Token 难以安全存储和轮换

适合机器对机器通信

权限控制粒度粗,缺乏标准化

方案三:基于环境变量的认证(STDIO 传输)

对于使用 STDIO 传输的本地 MCP 工具,MCP 规范明确指出不应使用 OAuth,而应从环境变量中获取凭证。

工作原理

  1. 客户端启动 MCP 服务时传入环境变量(如 API Key、Token)
  2. MCP 服务从环境变量读取凭证
  3. 在工具处理函数中使用凭证访问受保护资源

Go 语言实现

代码语言:javascript
复制
apiKey := os.Getenv("MCP_API_KEY") // 从环境变量获取凭证
s := server.NewMCPServer("stdio-auth-server", "1.0.0")

// 通过闭包捕获 apiKey,在 Tool 中使用
s.AddTool(mcp.NewTool("query_data",
    mcp.WithDescription("Query protected data"),
    mcp.WithString("query", mcp.Required(), mcp.Description("Search query")),
), func(ctx context.Context, req mcp.CallToolRequest) (*mcp.CallToolResult, error) {
    result, err := queryProtectedAPI(apiKey, req.Params.Arguments)
    if err != nil {
        return &mcp.CallToolResult{
            Content: []mcp.Content{&mcp.TextContent{Text: err.Error()}},
            IsError: true,
        }, nil
    }
    return &mcp.CallToolResult{
        Content: []mcp.Content{&mcp.TextContent{Text: result}},
    }, nil
})

server.ServeStdio(s) // 启动 STDIO 服务

适用场景

  • 本地开发工具(如 IDE 插件)
  • 单用户桌面应用
  • 不需要多用户隔离的场景

优缺点

优点

缺点

实现最简单

仅适用于 STDIO 传输

MCP 规范推荐的 STDIO 认证方式

凭证暴露在进程环境中

无需额外基础设施

不支持多用户权限隔离

三种方案对比

维度

OAuth 2.1(推荐)

自定义 Bearer Token

环境变量

MCP 规范支持

✅ 唯一官方方式

❌ 不符合规范

✅ STDIO 推荐

实现复杂度

中等

简单

安全性

最高

令牌撤销

✅ 支持

需自行实现

❌ 需重启进程

第三方登录

✅ 支持

❌ 不支持

❌ 不支持

适合传输层

HTTP(SSE/Streamable)

HTTP

STDIO

适合场景

SaaS、多租户、企业级

内部工具、快速原型

本地工具、IDE 插件

选型建议

选 OAuth 2.1:生产环境、面向外部用户、需要符合 MCP 规范——这是唯一正确的选择。

选自定义 Bearer Token:内部服务、快速验证阶段,但请注意这不属于 MCP 标准认证,未来可能需要迁移到 OAuth 2.1。

选环境变量:本地 STDIO 工具、IDE 插件等单用户场景。

写在最后

MCP 鉴权没有银弹,关键是匹配你的业务场景和技术团队的能力。需要特别强调的是:MCP 规范唯一推荐的认证方式是 OAuth 2.1,Go SDK(mcp-go)目前提供了完整的客户端 OAuth 支持,但服务端认证中间件需要开发者自行实现。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-04-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 技术圈子 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 为什么 MCP 需要鉴权?
  • MCP 官方认证规范
  • Go SDK 的认证支持现状
  • 方案一:基于 OAuth 2.1 的完整认证(推荐)
    • 工作原理
    • Go 语言实现
    • 适用场景
    • 优缺点
  • 方案二:自定义 Bearer Token 认证
    • 工作原理
    • Go 语言实现
    • 适用场景
    • 优缺点
  • 方案三:基于环境变量的认证(STDIO 传输)
    • 工作原理
    • Go 语言实现
    • 适用场景
    • 优缺点
  • 三种方案对比
    • 选型建议
  • 写在最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档