3
3
4
4
from mcp .server .fastmcp import FastMCP
5
5
6
+ from config import MCP_TRANSPORT , SNOWFLAKE_TOKEN
6
7
from database import (
7
8
execute_snowflake_query ,
8
9
format_snowflake_row ,
13
14
14
15
logger = logging .getLogger (__name__ )
15
16
17
+ def get_snowflake_token (mcp : FastMCP ) -> Optional [str ]:
18
+ """Get Snowflake token from either config (stdio) or request headers (non-stdio)"""
19
+ if MCP_TRANSPORT == "stdio" :
20
+ return SNOWFLAKE_TOKEN
21
+ else :
22
+ try :
23
+ # Get token from request headers for non-stdio transports
24
+ context = mcp .get_context ()
25
+ if context and hasattr (context , 'request_context' ) and context .request_context :
26
+ headers = context .request_context .request .headers
27
+ return headers .get ("X-Snowflake-Token" )
28
+ except Exception as e :
29
+ logger .error (f"Error getting token from request context: { e } " )
30
+ return None
31
+
16
32
def register_tools (mcp : FastMCP ) -> None :
17
33
"""Register all MCP tools"""
18
34
19
35
@mcp .tool ()
20
- @track_tool_usage ("list_issues " )
21
- async def list_issues (
36
+ @track_tool_usage ("list_jira_issues " )
37
+ async def list_jira_issues (
22
38
project : Optional [str ] = None ,
23
39
issue_type : Optional [str ] = None ,
24
40
status : Optional [str ] = None ,
@@ -41,6 +57,11 @@ async def list_issues(
41
57
Dictionary containing issues list and metadata
42
58
"""
43
59
try :
60
+ # Get the Snowflake token
61
+ snowflake_token = get_snowflake_token (mcp )
62
+ if not snowflake_token :
63
+ return {"error" : "Snowflake token not available" , "issues" : []}
64
+
44
65
# Build SQL query with filters
45
66
sql_conditions = []
46
67
@@ -77,7 +98,7 @@ async def list_issues(
77
98
LIMIT { limit }
78
99
"""
79
100
80
- rows = await execute_snowflake_query (sql )
101
+ rows = await execute_snowflake_query (sql , snowflake_token )
81
102
82
103
issues = []
83
104
issue_ids = []
@@ -121,7 +142,7 @@ async def list_issues(
121
142
issue_ids .append (str (row_dict .get ("ID" )))
122
143
123
144
# Get labels for enrichment
124
- labels_data = await get_issue_labels (issue_ids )
145
+ labels_data = await get_issue_labels (issue_ids , snowflake_token )
125
146
126
147
# Enrich issues with labels
127
148
for issue in issues :
@@ -145,8 +166,8 @@ async def list_issues(
145
166
return {"error" : f"Error reading issues from Snowflake: { str (e )} " , "issues" : []}
146
167
147
168
@mcp .tool ()
148
- @track_tool_usage ("get_issue_details " )
149
- async def get_issue_details (issue_key : str ) -> Dict [str , Any ]:
169
+ @track_tool_usage ("get_jira_issue_details " )
170
+ async def get_jira_issue_details (issue_key : str ) -> Dict [str , Any ]:
150
171
"""
151
172
Get detailed information for a specific JIRA issue by its key from Snowflake.
152
173
@@ -157,6 +178,11 @@ async def get_issue_details(issue_key: str) -> Dict[str, Any]:
157
178
Dictionary containing detailed issue information
158
179
"""
159
180
try :
181
+ # Get the Snowflake token
182
+ snowflake_token = get_snowflake_token (mcp )
183
+ if not snowflake_token :
184
+ return {"error" : "Snowflake token not available" }
185
+
160
186
sql = f"""
161
187
SELECT
162
188
ID, ISSUE_KEY, PROJECT, ISSUENUM, ISSUETYPE, SUMMARY, DESCRIPTION,
@@ -169,7 +195,7 @@ async def get_issue_details(issue_key: str) -> Dict[str, Any]:
169
195
LIMIT 1
170
196
"""
171
197
172
- rows = await execute_snowflake_query (sql )
198
+ rows = await execute_snowflake_query (sql , snowflake_token )
173
199
174
200
if not rows :
175
201
return {"error" : f"Issue with key '{ issue_key } ' not found" }
@@ -215,24 +241,29 @@ async def get_issue_details(issue_key: str) -> Dict[str, Any]:
215
241
}
216
242
217
243
# Get labels for this issue
218
- labels_data = await get_issue_labels ([str (issue ['id' ])])
244
+ labels_data = await get_issue_labels ([str (issue ['id' ])], snowflake_token )
219
245
issue ['labels' ] = labels_data .get (str (issue ['id' ]), [])
220
246
221
- return { " issue" : issue }
247
+ return issue
222
248
223
249
except Exception as e :
224
- return {"error" : f"Error retrieving issue details from Snowflake: { str (e )} " }
250
+ return {"error" : f"Error reading issue details from Snowflake: { str (e )} " }
225
251
226
252
@mcp .tool ()
227
- @track_tool_usage ("get_project_summary " )
228
- async def get_project_summary () -> Dict [str , Any ]:
253
+ @track_tool_usage ("get_jira_project_summary " )
254
+ async def get_jira_project_summary () -> Dict [str , Any ]:
229
255
"""
230
256
Get a summary of all projects in the JIRA data from Snowflake.
231
257
232
258
Returns:
233
259
Dictionary containing project statistics
234
260
"""
235
261
try :
262
+ # Get the Snowflake token
263
+ snowflake_token = get_snowflake_token (mcp )
264
+ if not snowflake_token :
265
+ return {"error" : "Snowflake token not available" }
266
+
236
267
sql = """
237
268
SELECT
238
269
PROJECT,
@@ -244,7 +275,7 @@ async def get_project_summary() -> Dict[str, Any]:
244
275
ORDER BY PROJECT, ISSUESTATUS, PRIORITY
245
276
"""
246
277
247
- rows = await execute_snowflake_query (sql )
278
+ rows = await execute_snowflake_query (sql , snowflake_token )
248
279
columns = ["PROJECT" , "ISSUESTATUS" , "PRIORITY" , "COUNT" ]
249
280
250
281
project_stats = {}
@@ -256,7 +287,7 @@ async def get_project_summary() -> Dict[str, Any]:
256
287
project = row_dict .get ("PROJECT" , "Unknown" )
257
288
status = row_dict .get ("ISSUESTATUS" , "Unknown" )
258
289
priority = row_dict .get ("PRIORITY" , "Unknown" )
259
- count = row_dict .get ("COUNT" , 0 )
290
+ count = int ( row_dict .get ("COUNT" , 0 )) if row_dict . get ( "COUNT" ) is not None else 0
260
291
261
292
if project not in project_stats :
262
293
project_stats [project ] = {
0 commit comments