@@ -64,6 +64,7 @@ def create_mcp_app(settings: Settings):
6464 enableEFS = True if any (re .match (pattern , 'fs_*' ) for pattern in config .get ('tool' , [])) else False
6565 enableTDVS = True if any (re .match (pattern , 'tdvs_*' ) for pattern in config .get ('tool' , [])) else False
6666 enableBAR = True if any (re .match (pattern , 'bar_*' ) for pattern in config .get ('tool' , [])) else False
67+ enableChatCmplt = True if any (re .match (pattern , 'chat_cmplt_*' ) for pattern in config .get ('tool' , [])) else False
6768
6869 # Initialize TD connection and optional teradataml/EFS context
6970 # Pass settings object to TDConn instead of just connection_url
@@ -128,6 +129,116 @@ def create_mcp_app(settings: Settings):
128129 logger .warning (f"BAR system dependencies not available - disabling BAR functionality: { e } " )
129130 enableBAR = False
130131
132+ # Chat Completion module validation (optional)
133+ if enableChatCmplt :
134+ try :
135+ from teradata_mcp_server .tools .chat_cmplt .chat_cmplt_tools import load_chat_cmplt_config
136+
137+ # Test 1: Check if base_url and model are set in chat_cmplt_config.yml
138+ chat_cmplt_config = load_chat_cmplt_config ()
139+ base_url = chat_cmplt_config .get ("base_url" , "" ).strip ()
140+ model = chat_cmplt_config .get ("model" , "" ).strip ()
141+ function_db = chat_cmplt_config .get ("databases" , {}).get ("function_db" , "" ).strip ()
142+
143+ if not base_url or not model :
144+ logger .warning (
145+ f"Chat completion config missing required parameters "
146+ f"(base_url: { 'set' if base_url else 'not set' } , "
147+ f"model: { 'set' if model else 'not set' } ) - "
148+ f"disabling chat completion functionality"
149+ )
150+ enableChatCmplt = False
151+ elif not function_db :
152+ logger .warning (
153+ "Chat completion config missing function database "
154+ "(databases.function_db not set) - disabling chat completion functionality"
155+ )
156+ enableChatCmplt = False
157+ else :
158+ # Tests 2 & 3: Check database function existence and permissions
159+ # Only perform these if we can establish a connection
160+ try :
161+ # Check if connection is available
162+ if not getattr (tdconn , "engine" , None ):
163+ logger .info (
164+ f"Chat completion module config validated (base_url, model, function_db set). "
165+ f"Database checks (function existence and permissions) will be skipped in stdio mode - "
166+ f"they will be validated on first tool use."
167+ )
168+ else :
169+ with tdconn .engine .connect () as conn :
170+ from sqlalchemy import text
171+
172+ # Test 2: Check if CompleteChat function exists in configured database
173+ check_function_sql = text (f"""
174+ SELECT 1
175+ FROM DBC.FunctionsV
176+ WHERE DatabaseName = '{ function_db } '
177+ AND FunctionName = 'CompleteChat'
178+ """ )
179+ result = conn .execute (check_function_sql )
180+ function_exists = result .fetchone () is not None
181+
182+ if not function_exists :
183+ logger .warning (
184+ f"CompleteChat function not found in database '{ function_db } ' - "
185+ f"disabling chat completion functionality"
186+ )
187+ enableChatCmplt = False
188+ else :
189+ # Test 3: Check if current user has execute permission on CompleteChat
190+ # This includes: direct function grants, database-level grants, and role-based grants
191+
192+ # First, get current username
193+ username_result = conn .execute (text ("SELECT USER" ))
194+ current_user = username_result .fetchone ()[0 ]
195+
196+ check_permission_sql = text (f"""
197+ SELECT 1
198+ FROM DBC.AllRightsV
199+ WHERE UPPER(UserName) = UPPER('{ current_user } ')
200+ AND UPPER(DatabaseName) = UPPER('{ function_db } ')
201+ AND (
202+ -- Case 1: Direct grant on the function itself
203+ (UPPER(TableName) = UPPER('CompleteChat') AND AccessRight = 'EF')
204+ OR
205+ -- Case 2: Database-level execute function grant
206+ (TableName = 'All' AND AccessRight = 'EF')
207+ )
208+ """ )
209+ result = conn .execute (check_permission_sql )
210+ has_permission = result .fetchone () is not None
211+
212+ if not has_permission :
213+ logger .warning (
214+ f"User '{ current_user } ' does not have EXECUTE FUNCTION permission "
215+ f"on { function_db } .CompleteChat (checked direct grants, database-level grants, and role-based grants) - "
216+ f"disabling chat completion functionality"
217+ )
218+ enableChatCmplt = False
219+ else :
220+ logger .info (
221+ f"Chat completion module validated successfully "
222+ f"(user: { current_user } , base_url: { base_url [:30 ]} ..., model: { model } , "
223+ f"function: { function_db } .CompleteChat)"
224+ )
225+ except (AttributeError , Exception ) as db_error :
226+ # In stdio mode, connection might not be available at startup
227+ # Log info instead of warning and allow tools to load
228+ # They will fail at runtime if there are actual permission issues
229+ logger .info (
230+ f"Chat completion config validated (base_url, model, function_db set). "
231+ f"Database validation skipped (connection not available at startup): { db_error } . "
232+ f"Function existence and permissions will be validated on first tool use."
233+ )
234+
235+ except (AttributeError , ImportError , ModuleNotFoundError ) as e :
236+ logger .warning (f"Chat completion module not available - disabling chat completion functionality: { e } " )
237+ enableChatCmplt = False
238+ except Exception as e :
239+ logger .warning (f"Error loading chat completion config - disabling chat completion functionality: { e } " )
240+ enableChatCmplt = False
241+
131242 # Middleware (auth + request context)
132243 from teradata_mcp_server .tools .auth_cache import SecureAuthCache
133244 auth_cache = SecureAuthCache (ttl_seconds = settings .auth_cache_ttl )
@@ -358,6 +469,10 @@ def executor(**kwargs):
358469 if tool_name .startswith ("bar_" ) and not enableBAR :
359470 logger .info (f"Skipping BAR tool: { tool_name } (BAR functionality disabled)" )
360471 continue
472+ # Skip chat completion tools if chat completion functionality is disabled
473+ if tool_name .startswith ("chat_cmplt_" ) and not enableChatCmplt :
474+ logger .info (f"Skipping chat completion tool: { tool_name } (chat completion functionality disabled)" )
475+ continue
361476 wrapped = make_tool_wrapper (func )
362477 mcp .tool (name = tool_name , description = wrapped .__doc__ )(wrapped )
363478 logger .info (f"Created tool: { tool_name } " )
0 commit comments