dynamic scope awareness
This commit is contained in:
@@ -15,7 +15,7 @@ from google.oauth2.credentials import Credentials
|
|||||||
|
|
||||||
from auth.oauth21_session_store import store_token_session
|
from auth.oauth21_session_store import store_token_session
|
||||||
from auth.google_auth import save_credentials_to_file
|
from auth.google_auth import save_credentials_to_file
|
||||||
from auth.scopes import SCOPES
|
from auth.scopes import get_current_scopes
|
||||||
from core.config import WORKSPACE_MCP_BASE_URI, WORKSPACE_MCP_PORT
|
from core.config import WORKSPACE_MCP_BASE_URI, WORKSPACE_MCP_PORT
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
@@ -44,10 +44,11 @@ async def handle_oauth_authorize(request: Request):
|
|||||||
# Ensure response_type is code
|
# Ensure response_type is code
|
||||||
params["response_type"] = "code"
|
params["response_type"] = "code"
|
||||||
|
|
||||||
# Merge client scopes with our full SCOPES list
|
# Merge client scopes with scopes for enabled tools only
|
||||||
client_scopes = params.get("scope", "").split() if params.get("scope") else []
|
client_scopes = params.get("scope", "").split() if params.get("scope") else []
|
||||||
# Always include all Google Workspace scopes for full functionality
|
# Include scopes for enabled tools only (not all tools)
|
||||||
all_scopes = set(client_scopes) | set(SCOPES)
|
enabled_tool_scopes = get_current_scopes()
|
||||||
|
all_scopes = set(client_scopes) | set(enabled_tool_scopes)
|
||||||
params["scope"] = " ".join(sorted(all_scopes))
|
params["scope"] = " ".join(sorted(all_scopes))
|
||||||
logger.info(f"OAuth 2.1 authorization: Requesting scopes: {params['scope']}")
|
logger.info(f"OAuth 2.1 authorization: Requesting scopes: {params['scope']}")
|
||||||
|
|
||||||
@@ -222,7 +223,7 @@ async def handle_oauth_protected_resource(request: Request):
|
|||||||
f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}"
|
f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}"
|
||||||
],
|
],
|
||||||
"bearer_methods_supported": ["header"],
|
"bearer_methods_supported": ["header"],
|
||||||
"scopes_supported": SCOPES,
|
"scopes_supported": get_current_scopes(),
|
||||||
"resource_documentation": "https://developers.google.com/workspace",
|
"resource_documentation": "https://developers.google.com/workspace",
|
||||||
"client_registration_required": True,
|
"client_registration_required": True,
|
||||||
"client_configuration_endpoint": f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}/.well-known/oauth-client",
|
"client_configuration_endpoint": f"{WORKSPACE_MCP_BASE_URI}:{WORKSPACE_MCP_PORT}/.well-known/oauth-client",
|
||||||
@@ -287,7 +288,7 @@ async def handle_oauth_authorization_server(request: Request):
|
|||||||
"code_challenge_methods_supported": ["S256"],
|
"code_challenge_methods_supported": ["S256"],
|
||||||
"pkce_required": True,
|
"pkce_required": True,
|
||||||
"grant_types_supported": ["authorization_code", "refresh_token"],
|
"grant_types_supported": ["authorization_code", "refresh_token"],
|
||||||
"scopes_supported": SCOPES,
|
"scopes_supported": get_current_scopes(),
|
||||||
"token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post"]
|
"token_endpoint_auth_methods_supported": ["client_secret_basic", "client_secret_post"]
|
||||||
},
|
},
|
||||||
headers={
|
headers={
|
||||||
@@ -336,7 +337,7 @@ async def handle_oauth_client_config(request: Request):
|
|||||||
],
|
],
|
||||||
"grant_types": ["authorization_code", "refresh_token"],
|
"grant_types": ["authorization_code", "refresh_token"],
|
||||||
"response_types": ["code"],
|
"response_types": ["code"],
|
||||||
"scope": " ".join(SCOPES),
|
"scope": " ".join(get_current_scopes()),
|
||||||
"token_endpoint_auth_method": "client_secret_basic",
|
"token_endpoint_auth_method": "client_secret_basic",
|
||||||
"code_challenge_methods": ["S256"]
|
"code_challenge_methods": ["S256"]
|
||||||
},
|
},
|
||||||
@@ -391,7 +392,7 @@ async def handle_oauth_register(request: Request):
|
|||||||
"redirect_uris": redirect_uris,
|
"redirect_uris": redirect_uris,
|
||||||
"grant_types": body.get("grant_types", ["authorization_code", "refresh_token"]),
|
"grant_types": body.get("grant_types", ["authorization_code", "refresh_token"]),
|
||||||
"response_types": body.get("response_types", ["code"]),
|
"response_types": body.get("response_types", ["code"]),
|
||||||
"scope": body.get("scope", " ".join(SCOPES)),
|
"scope": body.get("scope", " ".join(get_current_scopes())),
|
||||||
"token_endpoint_auth_method": body.get("token_endpoint_auth_method", "client_secret_basic"),
|
"token_endpoint_auth_method": body.get("token_endpoint_auth_method", "client_secret_basic"),
|
||||||
"code_challenge_methods": ["S256"],
|
"code_challenge_methods": ["S256"],
|
||||||
# Additional OAuth 2.1 fields
|
# Additional OAuth 2.1 fields
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ import logging
|
|||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Global variable to store enabled tools (set by main.py)
|
||||||
|
_ENABLED_TOOLS = None
|
||||||
|
|
||||||
# Individual OAuth Scope Constants
|
# Individual OAuth Scope Constants
|
||||||
USERINFO_EMAIL_SCOPE = 'https://www.googleapis.com/auth/userinfo.email'
|
USERINFO_EMAIL_SCOPE = 'https://www.googleapis.com/auth/userinfo.email'
|
||||||
USERINFO_PROFILE_SCOPE = 'https://www.googleapis.com/auth/userinfo.profile'
|
USERINFO_PROFILE_SCOPE = 'https://www.googleapis.com/auth/userinfo.profile'
|
||||||
@@ -121,5 +124,80 @@ CUSTOM_SEARCH_SCOPES = [
|
|||||||
CUSTOM_SEARCH_SCOPE
|
CUSTOM_SEARCH_SCOPE
|
||||||
]
|
]
|
||||||
|
|
||||||
# Combined scopes for all supported Google Workspace operations
|
# Tool-to-scopes mapping
|
||||||
SCOPES = list(set(BASE_SCOPES + CALENDAR_SCOPES + DRIVE_SCOPES + GMAIL_SCOPES + DOCS_SCOPES + CHAT_SCOPES + SHEETS_SCOPES + FORMS_SCOPES + SLIDES_SCOPES + TASKS_SCOPES + CUSTOM_SEARCH_SCOPES))
|
TOOL_SCOPES_MAP = {
|
||||||
|
'gmail': GMAIL_SCOPES,
|
||||||
|
'drive': DRIVE_SCOPES,
|
||||||
|
'calendar': CALENDAR_SCOPES,
|
||||||
|
'docs': DOCS_SCOPES,
|
||||||
|
'sheets': SHEETS_SCOPES,
|
||||||
|
'chat': CHAT_SCOPES,
|
||||||
|
'forms': FORMS_SCOPES,
|
||||||
|
'slides': SLIDES_SCOPES,
|
||||||
|
'tasks': TASKS_SCOPES,
|
||||||
|
'search': CUSTOM_SEARCH_SCOPES
|
||||||
|
}
|
||||||
|
|
||||||
|
def set_enabled_tools(enabled_tools):
|
||||||
|
"""
|
||||||
|
Set the globally enabled tools list.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
enabled_tools: List of enabled tool names.
|
||||||
|
"""
|
||||||
|
global _ENABLED_TOOLS
|
||||||
|
_ENABLED_TOOLS = enabled_tools
|
||||||
|
logger.info(f"Enabled tools set for scope management: {enabled_tools}")
|
||||||
|
|
||||||
|
def get_current_scopes():
|
||||||
|
"""
|
||||||
|
Returns scopes for currently enabled tools.
|
||||||
|
Uses globally set enabled tools or all tools if not set.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of unique scopes for the enabled tools plus base scopes.
|
||||||
|
"""
|
||||||
|
enabled_tools = _ENABLED_TOOLS
|
||||||
|
if enabled_tools is None:
|
||||||
|
# Default behavior - return all scopes
|
||||||
|
enabled_tools = TOOL_SCOPES_MAP.keys()
|
||||||
|
|
||||||
|
# Start with base scopes (always required)
|
||||||
|
scopes = BASE_SCOPES.copy()
|
||||||
|
|
||||||
|
# Add scopes for each enabled tool
|
||||||
|
for tool in enabled_tools:
|
||||||
|
if tool in TOOL_SCOPES_MAP:
|
||||||
|
scopes.extend(TOOL_SCOPES_MAP[tool])
|
||||||
|
|
||||||
|
logger.debug(f"Generated scopes for tools {list(enabled_tools)}: {len(set(scopes))} unique scopes")
|
||||||
|
# Return unique scopes
|
||||||
|
return list(set(scopes))
|
||||||
|
|
||||||
|
def get_scopes_for_tools(enabled_tools=None):
|
||||||
|
"""
|
||||||
|
Returns scopes for enabled tools only.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
enabled_tools: List of enabled tool names. If None, returns all scopes.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
List of unique scopes for the enabled tools plus base scopes.
|
||||||
|
"""
|
||||||
|
if enabled_tools is None:
|
||||||
|
# Default behavior - return all scopes
|
||||||
|
enabled_tools = TOOL_SCOPES_MAP.keys()
|
||||||
|
|
||||||
|
# Start with base scopes (always required)
|
||||||
|
scopes = BASE_SCOPES.copy()
|
||||||
|
|
||||||
|
# Add scopes for each enabled tool
|
||||||
|
for tool in enabled_tools:
|
||||||
|
if tool in TOOL_SCOPES_MAP:
|
||||||
|
scopes.extend(TOOL_SCOPES_MAP[tool])
|
||||||
|
|
||||||
|
# Return unique scopes
|
||||||
|
return list(set(scopes))
|
||||||
|
|
||||||
|
# Combined scopes for all supported Google Workspace operations (backwards compatibility)
|
||||||
|
SCOPES = get_scopes_for_tools()
|
||||||
5
main.py
5
main.py
@@ -140,6 +140,11 @@ def main():
|
|||||||
|
|
||||||
# Import specified tools or all tools if none specified
|
# Import specified tools or all tools if none specified
|
||||||
tools_to_import = args.tools if args.tools is not None else tool_imports.keys()
|
tools_to_import = args.tools if args.tools is not None else tool_imports.keys()
|
||||||
|
|
||||||
|
# Set enabled tools for scope management
|
||||||
|
from auth.scopes import set_enabled_tools
|
||||||
|
set_enabled_tools(list(tools_to_import))
|
||||||
|
|
||||||
safe_print(f"🛠️ Loading {len(tools_to_import)} tool module{'s' if len(tools_to_import) != 1 else ''}:")
|
safe_print(f"🛠️ Loading {len(tools_to_import)} tool module{'s' if len(tools_to_import) != 1 else ''}:")
|
||||||
for tool in tools_to_import:
|
for tool in tools_to_import:
|
||||||
tool_imports[tool]()
|
tool_imports[tool]()
|
||||||
|
|||||||
Reference in New Issue
Block a user