feat: add mark3labs/mcp-go adapter; harden DPoP htu and RFC 9728 PRM#12
Merged
Conversation
Add a new `mark3labs` module adapting mark3labs/mcp-go (bearer + DPoP auth, RFC 9728 PRM, HTTPContextFunc forwarding), and tighten DPoP proof verification and Protected Resource Metadata handling across core and the net/http adapter. - DPoP htu binding: compare EscapedPath (encoded %2F is not /), strip default ports and collapse empty paths on both sides (RFC 9110 §7.2, RFC 9449 §4.3), and pin scheme/authority to the configured resource URI instead of the proxy-controlled Host header and r.TLS. - Reject requests carrying more than one DPoP header via NewDPoPContext / ErrMultipleDpopProofs (RFC 9449 §4.3 #1, §7.1). - VerifiedClaims.RequireScopes plural helper with enriched insufficient-scope errors. - Resource.PRMURL() and typed Resource.PRMConfig() for RFC 9728 metadata. - NewAdapterFromClientAndResource constructors return (*Adapter, error) instead of panicking on a nil client. Includes BREAKING (pre-1.0) changes to DPoPContext and the net/http htu reconstruction; see CHANGELOG for migration steps.
The mark3labs adapter module (own go.mod, own mark3labs/vX.Y.Z publish path) was missing from the per-release-tag automation. Extend it everywhere the other modules appear: - release.yml: derive the mark3labs tag; include mark3labs in the vet/lint, require-bump, test, tag-creation, atomic-push, and summary steps. mark3labs wraps the http adapter, so it also gets a require-http bump (after the core-require loop, so the core hash is already stable). - cut-release.yml: extend the pre-cut "tag already exists" guard to the mark3labs tag.
RobertoIskandarani
approved these changes
Jun 16, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a new
mark3labsadapter module formark3labs/mcp-go, and tightens DPoP proof verification and RFC 9728 Protected Resource Metadata handling acrosscoreand thenet/httpadapter.Added
mark3labsmodule — adapter formark3labs/mcp-go. Wraps*authplanehttp.Adapterso consumers get bearer + DPoP auth, RFC 9728 PRM,and
HTTPContextFuncintegration for the mark3labs HTTP server.HTTPContextFuncacceptsWithForwardedContextKeys(...)andWithContextForwarding(fn)to propagate request IDs / tracing spans onto theper-tool-call MCP context. See
mark3labs/docs/user-guide.md.core/resource/verifier:(*VerifiedClaims).RequireScopes(...)plural helperwith enriched insufficient-scope errors (names every missing scope plus the
scopes the token carries, for verbatim use in the
WWW-Authenticateerror_description).core/resource/verifier:NewDPoPContext(...)factory andErrMultipleDpopProofssentinel — the canonical RFC 9449 §4.3 deps: bump github.com/modelcontextprotocol/go-sdk from 1.4.1 to 1.6.0 in /mcp in the gomod-all group #1 enforcementboundary, mapped to a
DPoP error="invalid_dpop_proof"401 challenge (§7.1).core/resource:Resource.PRMURL()and typedResource.PRMConfig()forRFC 9728 metadata, the latter for feeding third-party PRM-serving handlers
without going through the dynamic
PRMResponsemap.Fixed
htubinding comparesEscapedPath()(encoded%2Fis no longertreated as
/), strips explicit default ports (:80/:443, RFC 9110 §7.2),and collapses an empty path to
/on both sides — so bare-origin anddefault-port resources stop spuriously rejecting valid proofs (RFC 9449 §4.3,
RFC 3986 §6.2.2.2).
Breaking changes (pre-1.0)
http: thenet/httpadapter reconstructs DPoPhtufrom the configuredresource URI instead of the proxy-controlled
Hostheader andr.TLS,dropping query/fragment (RFC 9449 §4.3 ci: bump the actions-all group with 2 updates #5). Migration: mount the middleware
before any
http.StripPrefix; apps that relied onHost-derived htu willsee rejections until the resource URI matches the canonical origin.
core/resource/verifier:DPoPContext.Proof(field) is replaced by the(*DPoPContext).Proof()accessor +NewDPoPContextconstructor, so §4.3 deps: bump github.com/modelcontextprotocol/go-sdk from 1.4.1 to 1.6.0 in /mcp in the gomod-all group #1enforcement stays single-source and multi-proof states are unconstructable.
See
CHANGELOG.mdfor the full list and migration details.Testing
go vet,go build,golangci-lint, and the full test suite (incl. the RFCconformance harness) pass across all modules; per-module coverage floors met.