Initial curated ITWorx_MCP_Hub source from 368fba691ea8d23403b4d56b53b5ec670d7c5020
This commit is contained in:
commit
cb5be898ea
663 files changed
+82674
No files matched your search
@@ -0,0 +1,72 @@
|
||||
"""Single authoritative OAuth contract for the public ChatGPT MCP surface."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from urllib.parse import urlparse
|
||||
|
||||
DEFAULT_PUBLIC_MCP_ORIGIN = "https://mcp.example.com"
|
||||
DEFAULT_CHATGPT_OIDC_ISSUER = "https://auth.example-host.com/application/o/chatgpt-itworx-gitea/"
|
||||
CHATGPT_OAUTH_SCOPES = ("openid", "profile", "email", "offline_access")
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class OAuthMetadataSettings:
|
||||
"""Validated public values shared by metadata and Bearer challenges."""
|
||||
|
||||
public_origin: str
|
||||
issuer: str
|
||||
|
||||
@classmethod
|
||||
def from_environment(cls) -> OAuthMetadataSettings:
|
||||
public_origin = (
|
||||
os.environ.get("HUB_PUBLIC_MCP_URL", "").strip() or DEFAULT_PUBLIC_MCP_ORIGIN
|
||||
).rstrip("/")
|
||||
issuer = (
|
||||
os.environ.get("HUB_MCP_ADDITIONAL_OIDC_ISSUER", "").strip()
|
||||
or DEFAULT_CHATGPT_OIDC_ISSUER
|
||||
)
|
||||
public = urlparse(public_origin)
|
||||
authorization_server = urlparse(issuer)
|
||||
if not (
|
||||
public.scheme == "https"
|
||||
and public.hostname
|
||||
and not public.username
|
||||
and not public.password
|
||||
and public.path in {"", "/"}
|
||||
and not public.query
|
||||
and not public.fragment
|
||||
):
|
||||
raise ValueError("HUB_PUBLIC_MCP_URL must be a safe HTTPS origin")
|
||||
if not (
|
||||
authorization_server.scheme == "https"
|
||||
and authorization_server.hostname
|
||||
and not authorization_server.username
|
||||
and not authorization_server.password
|
||||
and authorization_server.path.endswith("/")
|
||||
and not authorization_server.query
|
||||
and not authorization_server.fragment
|
||||
):
|
||||
raise ValueError("HUB_MCP_ADDITIONAL_OIDC_ISSUER must be a safe HTTPS issuer")
|
||||
return cls(public_origin=public_origin, issuer=issuer)
|
||||
|
||||
|
||||
def protected_resource_metadata(
|
||||
resource_path: str, settings: OAuthMetadataSettings
|
||||
) -> dict[str, object]:
|
||||
"""Return RFC 9728 metadata for one public MCP resource."""
|
||||
|
||||
return {
|
||||
"resource": f"{settings.public_origin}/mcp/{resource_path}",
|
||||
"authorization_servers": [settings.issuer],
|
||||
"scopes_supported": list(CHATGPT_OAUTH_SCOPES),
|
||||
}
|
||||
|
||||
|
||||
def bearer_challenge(resource_path: str, settings: OAuthMetadataSettings) -> str:
|
||||
"""Advertise the same refresh-capable scope contract on a 401 response."""
|
||||
|
||||
scopes = " ".join(CHATGPT_OAUTH_SCOPES)
|
||||
metadata = f"{settings.public_origin}/.well-known/oauth-protected-resource/mcp/{resource_path}"
|
||||
return f'Bearer resource_metadata="{metadata}", scope="{scopes}"'
|
||||
Reference in new issue
Block a user