feat(32.1-01): publish one MCP scope list and call context

- pact gains MemberTokenScopeCatalog, MCPAdvertisedScopes and MCPCall
- an empty MCP ScopesSupported resolves to the five fixed names including backend
- pier copies advertised scopes and sets MCPCall beside WithDispatch
This commit is contained in:
2026-10-28 14:32:31 +01:00
parent 2cea3127cc
commit 63d05e8acb
11 changed files with 322 additions and 27 deletions

View File

@@ -10,7 +10,8 @@ import (
)
// PRMScopes is the scopes_supported list of the protected resource
// metadata: the OAuth server's MCP scopes plus backend (D-21).
// metadata when the published verifier does not advertise a non-empty
// list: the fixed MCP scopes, including backend.
var PRMScopes = []string{"read", "write", "ai", "offline_access", "backend"}
// mountPRM serves the RFC 9728 protected resource metadata at
@@ -22,6 +23,7 @@ var PRMScopes = []string{"read", "write", "ai", "offline_access", "backend"}
// resource is logged as a warning at boot (Pitfall 8).
func (p *Pier) mountPRM() error {
issuer := p.cfg.AppURL
scopes := append([]string(nil), PRMScopes...)
if verifier, ok := p.app.Lookup[pact.MCPTokenVerifier](); ok && verifier != nil {
if res := verifier.MCPResource(); res != "" {
if u, err := url.Parse(res); err == nil && u.Scheme != "" && u.Host != "" {
@@ -32,10 +34,15 @@ func (p *Pier) mountPRM() error {
"mcp_resource", p.cfg.Resource, "verifier_resource", res)
}
}
if advertised, ok := verifier.(pact.MCPAdvertisedScopes); ok {
if list := advertised.MCPScopesSupported(); len(list) > 0 {
scopes = append([]string(nil), list...)
}
}
}
meta := &oauthex.ProtectedResourceMetadata{
Resource: p.cfg.Resource,
ScopesSupported: append([]string(nil), PRMScopes...),
ScopesSupported: scopes,
BearerMethodsSupported: []string{"header"},
}
if issuer != "" {