11from typing import List
22import requests
33import json
4+ import logging
45
56from starlette .exceptions import HTTPException
67from fastmcp .server .dependencies import get_http_request
78
89from src .api .types import MCPConcept
910from src .config .config import get_settings
1011
12+ # Set up logger for this module
13+ logger = logging .getLogger (__name__ )
14+
1115
1216def filter_mcp_concepts (mcp_concepts : List [MCPConcept ]) -> List [MCPConcept ]:
1317 """
@@ -16,67 +20,102 @@ def filter_mcp_concepts(mcp_concepts: List[MCPConcept]) -> List[MCPConcept]:
1620 return [mcp_concept for mcp_concept in mcp_concepts if not mcp_concept .deprecated ]
1721
1822
19- def __query_graphql_organizations ():
23+ def query_graphql_organizations ():
2024 """
2125 Query the GraphQL endpoint to get a list of organizations the user has access to.
2226
2327 Returns:
2428 List of organizations with their IDs and names
2529 """
2630 settings = get_settings ()
27-
2831 graphql_endpoint = settings .graphql_public_endpoint
2932
33+ logger .debug (f"GraphQL endpoint: { graphql_endpoint } " )
34+ logger .debug (f"Settings auth method: { settings .auth_method } " )
35+ logger .debug (f"Settings is_remote: { settings .is_remote } " )
36+
3037 # GraphQL query for organizations
3138 query = """
32- query GetOrganizations {
39+ query {
3340 organizations {
3441 orgID
3542 name
3643 }
3744 }
3845 """
3946
47+ # Get access token with logging
48+ try :
49+ access_token = __get_access_token ()
50+ # Only log first/last 8 chars for security
51+ token_preview = (
52+ f"{ access_token [:8 ]} ...{ access_token [- 8 :]} "
53+ if len (access_token ) > 16
54+ else "***"
55+ )
56+ logger .debug (f"Access token (preview): { token_preview } " )
57+ except Exception as e :
58+ logger .error (f"Failed to get access token: { str (e )} " )
59+ raise
60+
4061 # Headers with authentication
4162 headers = {
42- "Authorization" : f"Bearer { __get_access_token () } " ,
63+ "Authorization" : f"Bearer { access_token } " ,
4364 "Content-Type" : "application/json" ,
65+ "Accept" : "application/json" ,
66+ "User-Agent" : "SingleStore-MCP-Server" ,
4467 }
4568
4669 # Payload for the GraphQL request
47- payload = {
48- "operationName" : "GetOrganizations" ,
49- "query" : query ,
50- "variables" : {},
51- }
70+ payload = {"query" : query .strip ()}
71+
72+ logger .debug (f"Request headers: { dict (headers )} " )
73+ logger .debug (f"Request payload: { payload } " )
5274
5375 try :
76+ logger .debug (f"Making POST request to: { graphql_endpoint } " )
77+
78+ # Use the base GraphQL endpoint without query parameters
5479 response = requests .post (
55- f"{ graphql_endpoint } ?q=GetOrganizations" ,
56- headers = headers ,
57- json = payload ,
80+ graphql_endpoint , headers = headers , json = payload , timeout = 30
5881 )
5982
83+ logger .debug (f"Response status code: { response .status_code } " )
84+ logger .debug (f"Response headers: { dict (response .headers )} " )
85+ logger .debug (f"Raw response text: { response .text } " )
86+
6087 if response .status_code != 200 :
61- raise ValueError (
62- f"GraphQL request failed with status code { response . status_code } : { response . text } "
63- )
88+ error_msg = f"GraphQL request failed with status code { response . status_code } : { response . text } "
89+ logger . error ( error_msg )
90+ raise ValueError ( error_msg )
6491
6592 data = response .json ()
93+ logger .debug (f"Parsed response data: { data } " )
94+
6695 if "errors" in data :
6796 errors = data ["errors" ]
6897 error_message = "; " .join (
6998 [error .get ("message" , "Unknown error" ) for error in errors ]
7099 )
100+ logger .error (f"GraphQL errors: { errors } " )
71101 raise ValueError (f"GraphQL query error: { error_message } " )
72102
73103 if "data" in data and "organizations" in data ["data" ]:
74- return data ["data" ]["organizations" ]
104+ organizations = data ["data" ]["organizations" ]
105+ logger .info (f"Found { len (organizations )} organizations" )
106+ return organizations
75107 else :
108+ logger .warning ("No organizations found in response" )
76109 return []
77110
111+ except requests .exceptions .RequestException as e :
112+ error_msg = f"Network error when querying organizations: { str (e )} "
113+ logger .error (error_msg )
114+ raise ValueError (error_msg )
78115 except Exception as e :
79- raise ValueError (f"Failed to query organizations: { str (e )} " )
116+ error_msg = f"Failed to query organizations: { str (e )} "
117+ logger .error (error_msg )
118+ raise ValueError (error_msg )
80119
81120
82121def build_request (
@@ -110,6 +149,13 @@ def build_request_endpoint(endpoint: str, params: dict = None):
110149 # Add organization ID as a query parameter
111150 if settings .is_remote :
112151 params ["organizationID" ] = settings .org_id
152+ elif (
153+ hasattr (settings , "org_id" )
154+ and settings .org_id
155+ and settings .auth_method == "oauth_token"
156+ ):
157+ # For local OAuth token authentication, also add organization ID
158+ params ["organizationID" ] = settings .org_id
113159
114160 if params and type == "GET" : # Only add query params for GET requests
115161 url += "?"
@@ -244,6 +290,14 @@ def __get_org_id() -> str:
244290 if settings .is_remote :
245291 return settings .org_id
246292 else :
293+ # For local settings with OAuth token authentication, check if org_id is already set
294+ if (
295+ hasattr (settings , "org_id" )
296+ and settings .org_id
297+ and settings .auth_method == "oauth_token"
298+ ):
299+ return settings .org_id
300+
247301 organization = build_request ("GET" , "organizations/current" )
248302 if "orgID" in organization :
249303 return organization ["orgID" ]
@@ -260,14 +314,41 @@ def __get_access_token() -> str:
260314 """
261315 settings = get_settings ()
262316
317+ logger .debug (f"Getting access token, is_remote: { settings .is_remote } " )
318+
263319 access_token : str
264320 if settings .is_remote :
265321 request = get_http_request ()
266322 access_token = request .headers .get ("Authorization" , "" ).replace ("Bearer " , "" )
323+ logger .debug (
324+ f"Remote access token retrieved (length: { len (access_token ) if access_token else 0 } )"
325+ )
267326 else :
268327 access_token = settings .api_key
328+ logger .debug (
329+ f"Local access token retrieved (length: { len (access_token ) if access_token else 0 } )"
330+ )
269331
270332 if not access_token :
333+ logger .warning ("No access token available!" )
271334 raise HTTPException (401 , "Unauthorized: No access token provided" )
272335
273336 return access_token
337+
338+
339+ def get_current_organization ():
340+ """
341+ Get the current organization details from the management API.
342+
343+ Returns:
344+ dict: Organization details including orgID and name
345+ """
346+ try :
347+ organization = build_request ("GET" , "organizations/current" )
348+ logger .debug (f"Current organization response: { organization } " )
349+ return organization
350+ except Exception as e :
351+ logger .error (f"Failed to get current organization: { str (e )} " )
352+ raise ValueError (
353+ f"Could not retrieve current organization from the API: { str (e )} "
354+ )
0 commit comments