Veeru-c commited on
Commit
4b59886
·
1 Parent(s): 00f4e28

initial commit

Browse files
Files changed (1) hide show
  1. mcp/mcp_server.py +80 -3
mcp/mcp_server.py CHANGED
@@ -415,6 +415,9 @@ def create_jira_user_story(epic_key: str, summary: str, description: str,
415
  """
416
  print(f"[JIRA] Creating user story under {epic_key}: {summary}")
417
 
 
 
 
418
  if use_real_jira():
419
  try:
420
  jira = get_jira_client()
@@ -423,13 +426,13 @@ def create_jira_user_story(epic_key: str, summary: str, description: str,
423
  description_adf = create_adf_description(description)
424
 
425
  story_dict = {
426
- 'project': {'key': epic_key.split('-')[0]},
427
  'summary': summary,
428
  'description': description_adf,
429
  'issuetype': {'name': 'Story'},
430
  # Link to Epic - field name varies by JIRA instance, usually 'parent' for Next-Gen or 'customfield_XXXXX'
431
  # Trying standard 'parent' first for modern JIRA Cloud
432
- 'parent': {'key': epic_key}
433
  }
434
 
435
  new_issue = jira.create_issue(fields=story_dict)
@@ -471,6 +474,69 @@ def create_jira_user_story(epic_key: str, summary: str, description: str,
471
  "timestamp": datetime.now().isoformat()
472
  }
473
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
474
  # ===== Gradio Interface =====
475
  def create_gradio_interface():
476
  """Create Gradio interface for MCP server"""
@@ -556,7 +622,16 @@ def create_gradio_interface():
556
  )
557
 
558
  with gr.Tab("JIRA - Create User Story"):
559
- story_epic = gr.Textbox(label="Epic Key", placeholder="PROJ-100")
 
 
 
 
 
 
 
 
 
560
  story_summary = gr.Textbox(label="Story Summary", placeholder="Story title...")
561
  story_desc = gr.Textbox(
562
  label="Story Description",
@@ -567,6 +642,8 @@ def create_gradio_interface():
567
  create_story_btn = gr.Button("Create User Story", variant="primary")
568
  story_output = gr.JSON(label="Created Story")
569
 
 
 
570
  create_story_btn.click(
571
  create_jira_user_story,
572
  inputs=[story_epic, story_summary, story_desc, story_points],
 
415
  """
416
  print(f"[JIRA] Creating user story under {epic_key}: {summary}")
417
 
418
+ # Extract actual key if format is "KEY: Summary"
419
+ actual_epic_key = epic_key.split(':')[0].strip()
420
+
421
  if use_real_jira():
422
  try:
423
  jira = get_jira_client()
 
426
  description_adf = create_adf_description(description)
427
 
428
  story_dict = {
429
+ 'project': {'key': actual_epic_key.split('-')[0]},
430
  'summary': summary,
431
  'description': description_adf,
432
  'issuetype': {'name': 'Story'},
433
  # Link to Epic - field name varies by JIRA instance, usually 'parent' for Next-Gen or 'customfield_XXXXX'
434
  # Trying standard 'parent' first for modern JIRA Cloud
435
+ 'parent': {'key': actual_epic_key}
436
  }
437
 
438
  new_issue = jira.create_issue(fields=story_dict)
 
474
  "timestamp": datetime.now().isoformat()
475
  }
476
 
477
+ # ===== Helper Functions =====
478
+ def get_available_epics() -> List[str]:
479
+ """Get list of available epics for dropdown"""
480
+ epics_list = []
481
+
482
+ if use_real_jira():
483
+ try:
484
+ # Use direct REST API call to avoid deprecated GET endpoint
485
+ import requests
486
+ from requests.auth import HTTPBasicAuth
487
+
488
+ # Ensure no trailing slash in base URL
489
+ base_url = config.JIRA_URL.rstrip('/')
490
+ api_url = f"{base_url}/rest/api/3/search"
491
+
492
+ auth = HTTPBasicAuth(config.JIRA_EMAIL, config.JIRA_API_TOKEN)
493
+ headers = {
494
+ "Accept": "application/json",
495
+ "Content-Type": "application/json"
496
+ }
497
+
498
+ # Search for all epics in project
499
+ jql = f'project = "{config.JIRA_PROJECT_KEY}" AND issuetype = Epic ORDER BY created DESC'
500
+
501
+ payload = {
502
+ "jql": jql,
503
+ "maxResults": 20,
504
+ "fields": ["summary"]
505
+ }
506
+
507
+ response = requests.post(api_url, json=payload, headers=headers, auth=auth)
508
+
509
+ # Handle 410 fallback
510
+ if response.status_code == 410:
511
+ api_url = f"{base_url}/rest/api/3/search/jql"
512
+ response = requests.post(api_url, json=payload, headers=headers, auth=auth)
513
+
514
+ if response.ok:
515
+ data = response.json()
516
+ issues = data.get("issues", [])
517
+ if "issues" not in data and isinstance(data, list):
518
+ issues = data
519
+
520
+ for issue in issues:
521
+ key = issue.get("key")
522
+ summary = issue.get("fields", {}).get("summary", "")
523
+ epics_list.append(f"{key}: {summary}")
524
+ except Exception as e:
525
+ print(f"[JIRA] Error fetching epics: {e}")
526
+ else:
527
+ # Mock mode
528
+ for epic in mock_epics:
529
+ epics_list.append(f"{epic['key']}: {epic['summary']}")
530
+
531
+ return epics_list
532
+
533
+ def refresh_epics_dropdown():
534
+ """Refresh the choices for the epic dropdown"""
535
+ choices = get_available_epics()
536
+ if not choices:
537
+ return gr.Dropdown.update(choices=[], value=None, label="No Epics Found - Please Create an Epic First")
538
+ return gr.Dropdown.update(choices=choices, value=choices[0] if choices else None, label="Select Epic")
539
+
540
  # ===== Gradio Interface =====
541
  def create_gradio_interface():
542
  """Create Gradio interface for MCP server"""
 
622
  )
623
 
624
  with gr.Tab("JIRA - Create User Story"):
625
+ with gr.Row():
626
+ initial_epics = get_available_epics()
627
+ story_epic = gr.Dropdown(
628
+ choices=initial_epics,
629
+ value=initial_epics[0] if initial_epics else None,
630
+ label="Select Epic" if initial_epics else "No Epics Found - Please Create an Epic First",
631
+ allow_custom_value=True # Allow typing if needed, or strictly selection
632
+ )
633
+ refresh_btn = gr.Button("🔄 Refresh Epics")
634
+
635
  story_summary = gr.Textbox(label="Story Summary", placeholder="Story title...")
636
  story_desc = gr.Textbox(
637
  label="Story Description",
 
642
  create_story_btn = gr.Button("Create User Story", variant="primary")
643
  story_output = gr.JSON(label="Created Story")
644
 
645
+ refresh_btn.click(refresh_epics_dropdown, outputs=[story_epic])
646
+
647
  create_story_btn.click(
648
  create_jira_user_story,
649
  inputs=[story_epic, story_summary, story_desc, story_points],