Upgrade to Pro — share decks privately, control downloads, hide ads and more …

What’s MCP && Authorization?

Avatar for Bo-Yi Wu Bo-Yi Wu
October 14, 2025

What’s MCP && Authorization?

This workshop provides a comprehensive guide to building MCP (Model Context Protocol) servers and clients using the Go programming language. You will learn how to leverage MCP to streamline your workflow and enhance your development environment.

This project demonstrates an OAuth 2.1 protected Model Context Protocol (MCP) server written in Go. It supports multiple OAuth providers (GitHub, GitLab, Gitea) and showcases authenticated MCP tool execution with token context propagation.

The implementation includes both an OAuth authorization server (oauth-server/) and an example OAuth client (oauth-client/), demonstrating the complete OAuth 2.1 flow with PKCE support and flexible storage options.

The server provides:

* Multi-Provider OAuth Integration: Supports GitHub, GitLab, and Gitea as OAuth 2.0 providers for user authentication
* Flexible Storage Backends: Choose between in-memory or Redis-backed storage for OAuth data persistence
* MCP Server with Authentication: Requires valid OAuth tokens for all MCP endpoint access
* Context-based Token Propagation: Injects and propagates authentication tokens through Go's context.Context

Two Authenticated MCP Tools:

* make_authenticated_request: Makes authenticated HTTP requests to external APIs using the user's token
* show_auth_token: Displays a masked version of the current authorization token
* OAuth 2.0 Endpoints: Implements required OAuth endpoints with provider integration
* Dynamic Client Registration: Supports automatic client registration for MCP clients

Conference URL: https://hwdc.ithome.com.tw/2025/lab-page/3994

Avatar for Bo-Yi Wu

Bo-Yi Wu

October 14, 2025
Tweet

More Decks by Bo-Yi Wu

Other Decks in Technology

Transcript

  1. Preparation before workshop • GitHub Account • GitHub Copilot •

    VSCode Editor • Claude Code • Install Golang
  2. What is MCP? (Model Context Protocol) MCP is an open-source

    standard for connecting AI applications to external systems.
  3. { "mcpServers": { "default-stdio-server": { "type": "stdio", "command": "mcp-server", "args":

    ["-t", "stdio"] }, "default-http-server": { "type": "http", "url": "http://localhost:8080/mcp", "headers": { "Authorization": "xxxxxx" } } } } .$1$PO fi HVSBUJPO
  4. Standards Compliance in OAuth • OAuth 2.1 IETF DRAFT (draft-ietf-oauth-v2-1-12)

    • OAuth 2.0 Authorization Server Metadata (RFC8414) • OAuth 2.0 Dynamic Client Registration Protocol (RFC7591) • OAuth 2.0 Protected Resource Metadata (RFC9728)
  5. Standards Compliance in OAuth • OAuth 2.1 IETF DRAFT (draft-ietf-oauth-v2-1-12)

    • OAuth 2.0 Authorization Server Metadata (RFC8414) • OAuth 2.0 Dynamic Client Registration Protocol (RFC7591) • OAuth 2.0 Protected Resource Metadata (RFC9728)
  6. Authorization Flow (Roles) • MCP Server (OAuth 2.1 Resource Server)

    • MCP Client (OAuth 2.1 Client) • Authorization Server • Resource Owner # " $ %
  7. Standards Compliance in OAuth • OAuth 2.1 IETF DRAFT (draft-ietf-oauth-v2-1-12)

    • OAuth 2.0 Authorization Server Metadata (RFC8414) • OAuth 2.0 Dynamic Client Registration Protocol (RFC7591) • OAuth 2.0 Protected Resource Metadata (RFC9728)
  8. Standards Compliance in OAuth • OAuth 2.1 IETF DRAFT (draft-ietf-oauth-v2-1-12)

    • OAuth 2.0 Authorization Server Metadata (RFC8414) • OAuth 2.0 Dynamic Client Registration Protocol (RFC7591) • OAuth 2.0 Protected Resource Metadata (RFC9728)
  9. Standards Compliance in OAuth • OAuth 2.1 IETF DRAFT (draft-ietf-oauth-v2-1-12)

    • OAuth 2.0 Authorization Server Metadata (RFC8414) • OAuth 2.0 Dynamic Client Registration Protocol (RFC7591) • OAuth 2.0 Protected Resource Metadata (RFC9728)
  10. MCP Server • Serve protected resource metadata (RFC9728) • Must

    include the authorization_servers fi eld • Must return a 401 Unauthorized and include a WWW-Authenticate header
  11. MCP Client • Parse WWW-Authenticate headers on HTTP 401 Unauthorized

    response. • Process the protected resource metadata, including available authorization_servers. • Initiate the correct OAuth 2.0 fl ow to obtain tokens form authorization server.
  12. Authorization Server • Support OAuth 2.0 token endpoint(s) as indicated

    in the resource metadata • Issue tokens as de fi ned in the OAuth 2.0 speci fi cation • SHOULD be discoverable via the MCP server’s metadata document.
  13. Dynamic Client Registration • MCP Clients and authorization servers SHOULD

    support the OAuth 2.0 Dynamic Client Registration Protocol (RFC7591) • MCP Clients to automatically obtain OAuth Client IDs (an Secrets) from authorization.
  14. 

  15. // Middleware to check Authorization header authMiddleware := func(c *gin.Context)

    { if c.GetHeader("Authorization") == "" { c.AbortWithStatus(http.StatusUnauthorized) return } c.Next() } router.POST("/mcp", authMiddleware, gin.WrapH(mcpServer.ServeHTTP())) router.GET("/mcp", authMiddleware, gin.WrapH(mcpServer.ServeHTTP())) router.DELETE("/mcp", authMiddleware, gin.WrapH(mcpServer.ServeHTTP())) "VUINJEEMFXBSFGPS6OBVUIPSJ[FEXJUIUPLFO $IFDLBVUIPSJ[FEJO1045 (&5BOE%FMFUFSPVUF
  16. 

  17. // Create OAuth configuration oauthConfig := client.OAuthConfig{ RedirectURI: redirectURI, Scopes:

    []string{"mcp.read", "mcp.write"}, TokenStore: tokenStore, PKCEEnabled: true, // Enable PKCE for public clients } // Try to initialize the client result, err := c.Initialize(context.Background(), mcp.InitializeRequest{ Params: mcp.InitializeParams{ ProtocolVersion: mcp.LATEST_PROTOCOL_VERSION, ClientInfo: mcp.Implementation{ Name: "mcp-oauth-client-example", Version: "1.0.0", }, }, }) $SFBUF0"VUI$PO fi HGPS.$1$MJFOU *OJUJBM.$1$POOFDUJPOGPS0"VUI$MJFOU
  18. router.GET("/.well-known/oauth-protected-resource", corsMiddleware(), func(c *gin.Context) { metadata := &transport.OAuthProtectedResource{ AuthorizationServers: []string{"http://localhost"

    + addr}, Resource: "Example OAuth Protected Resource", ResourceName: "Example OAuth Protected Resource", } c.JSON(http.StatusOK, metadata) }) IUUQTEBUBUSBDLFSJFUGPSHEPDIUNMSGD
  19. 

  20. router.GET("/.well-known/oauth-authorization-server", corsMiddleware(), func(c *gin.Context) { metadata := transport.AuthServerMetadata{ Issuer: "http://localhost"

    + addr, AuthorizationEndpoint: "http://localhost" + addr + "/authorize", TokenEndpoint: "http://localhost" + addr + "/token", RegistrationEndpoint: "http://localhost" + addr + "/register", ScopesSupported: []string{"openid", "profile", "email"}, ResponseTypesSupported: []string{"code"}, GrantTypesSupported: []string{"authorization_code", "refresh_token"}, TokenEndpointAuthMethodsSupported: []string{"none", "client_secret_basic", "client_secret_post"}, CodeChallengeMethodsSupported: []string{"S256"}, // for inspector } c.JSON(http.StatusOK, metadata) }) IUUQTEBUBUSBDLFSJFUGPSHEPDIUNMSGD "VUIPSJ[BUJPO4FSWFS.FUBEBUB
  21. IUUQTMPHJONJDSPTPGUPOMJOFDPNDPNNPOWXFMMLOPXOPQFOJEDPO fi HVSBUJPO { "token_endpoint": "https://login.microsoftonline.com/common/oauth2/v2.0/token", "token_endpoint_auth_methods_supported": [ "client_secret_post", "private_key_jwt",

    "client_secret_basic" ], "jwks_uri": "https://login.microsoftonline.com/common/discovery/v2.0/keys", "subject_types_supported": [ "pairwise" ], "id_token_signing_alg_values_supported": [ "RS256" ], "response_types_supported": [ "code", "id_token token" ], "scopes_supported": [ "openid", "profile", "email" ], "issuer": "https://login.microsoftonline.com/{tenantid}/v2.0", "userinfo_endpoint": "https://graph.microsoft.com/oidc/userinfo", "authorization_endpoint": "https://login.microsoftonline.com/common/oauth2/v2.0/authorize", "claims_supported": [ "sub", "iss", "at_hash", "c_hash", "email" ] }
  22. router.POST("/register", corsMiddleware("Authorization", "Content-Type"), func(c *gin.Context) { var req ClientRegistrationMetadata if

    err := c.ShouldBindJSON(&req); err != nil { c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) return } // Generate client credentials clientID := uuid.New().String() clientSecret := generateClientSecret() // Create client client := &core.Client{ ID: clientID, Secret: clientSecret, RedirectURIs: req.RedirectURIs, GrantTypes: req.GrantTypes, ResponseTypes: req.ResponseTypes, Scope: req.Scope, IssuedAt: time.Now().Unix(), ClientSecretExpiresAt: time.Now().Add(1 * time.Minute).Unix(), } err := oauthStore.CreateClient(context.Background(), client) if err != nil { c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create client", "details": err.Error()}) return } slog.Debug("Client registered", "response", response) c.JSON(http.StatusCreated, response) }) IUUQTEBUBUSBDLFSJFUGPSHEPDIUNMSGD %ZOBNJD$MJFOU3FHJTUSBUJPO1SPUPDPM 1MFBTFJNQMFNFOUUIFSFHJTUSBUJPO fl PX
  23. 

  24. OAuth PKCE Flow • Generate a code veri fi er

    for PKCE (Proof Key for Code Exchange) • Generates a code challenge from a code veri fi er (SHA256 + Base64URL encoding) • Generate anti-CSRF state (32 chars)
  25. 

  26. // Try to initialize again with the token result, err

    = c.Initialize(context.Background(), mcp.InitializeRequest{ Params: mcp.InitializeParams{ ProtocolVersion: mcp.LATEST_PROTOCOL_VERSION, ClientInfo: mcp.Implementation{ Name: "mcp-go-oauth-example", Version: "0.1.0", }, }, }) if result.Capabilities.Tools != nil { tools, err := c.ListTools(context.Background(), mcp.ListToolsRequest{ PaginatedRequest: mcp.PaginatedRequest{ Params: mcp.PaginatedParams{ Cursor: "", }, }, }) for _, tool := range tools.Tools { slog.Info("Available Tool", "name", tool.Name) } } *OJUJBMJ[F.$1$MJFOU"HBJO -JTUBWBJMBCMF.$1UPPMMJTU
  27. { "servers": { "default-stdio-server": { "type": "stdio", "command": "mcp-server", "args":

    ["-t", "stdio"] }, "default-http-server": { "type": "http", "url": "http://localhost:8080/mcp", "headers": { "Authorization": "Bearer 1234567890" } }, "default-oauth-server": { "type": "http", "url": "http://localhost:9093/mcp" } } }