nia-mcp-server 1.0.25__py3-none-any.whl → 1.0.27__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of nia-mcp-server might be problematic. Click here for more details.

@@ -3,4 +3,4 @@ NIA MCP Server - Proxy server for NIA Knowledge Agent
3
3
  """
4
4
 
5
5
 
6
- __version__ = "1.0.25"
6
+ __version__ = "1.0.27"
@@ -28,7 +28,7 @@ class NIAApiClient:
28
28
  self.client = httpx.AsyncClient(
29
29
  headers={
30
30
  "Authorization": f"Bearer {api_key}",
31
- "User-Agent": "nia-mcp-server/1.0.25",
31
+ "User-Agent": "nia-mcp-server/1.0.27",
32
32
  "Content-Type": "application/json"
33
33
  },
34
34
  timeout=720.0 # 12 minute timeout for deep research operations
@@ -432,7 +432,104 @@ class NIAApiClient:
432
432
  except Exception as e:
433
433
  logger.error(f"Failed to rename repository: {e}")
434
434
  raise APIError(f"Failed to rename repository: {str(e)}")
435
-
435
+
436
+ async def get_github_tree(
437
+ self,
438
+ owner_repo: str,
439
+ branch: Optional[str] = None,
440
+ include_paths: Optional[List[str]] = None,
441
+ exclude_paths: Optional[List[str]] = None,
442
+ file_extensions: Optional[List[str]] = None,
443
+ exclude_extensions: Optional[List[str]] = None,
444
+ show_full_paths: bool = False
445
+ ) -> Dict[str, Any]:
446
+ """Get file tree directly from GitHub API (no FalkorDB dependency).
447
+
448
+ Args:
449
+ owner_repo: Repository in owner/repo format or repository ID
450
+ branch: Optional branch name (defaults to repository's default branch)
451
+ include_paths: Only include files in these paths (e.g., ["src/", "lib/"])
452
+ exclude_paths: Exclude files in these paths (e.g., ["node_modules/", "dist/"])
453
+ file_extensions: Only include these file extensions (e.g., [".py", ".js"])
454
+ exclude_extensions: Exclude these file extensions (e.g., [".md", ".lock"])
455
+ show_full_paths: Show full file paths instead of hierarchical tree
456
+
457
+ Returns:
458
+ GitHub tree structure with files, directories, and stats
459
+ """
460
+ try:
461
+ # Check if this looks like owner/repo format (contains /)
462
+ if '/' in owner_repo:
463
+ # First, get the repository ID
464
+ status = await self.get_repository_status(owner_repo)
465
+ if not status:
466
+ raise APIError(f"Repository {owner_repo} not found", 404)
467
+
468
+ # Extract the repository ID from status
469
+ repo_id = status.get("repository_id") or status.get("id")
470
+ if not repo_id:
471
+ # Try to get it from list as fallback
472
+ repos = await self.list_repositories()
473
+ for repo in repos:
474
+ if repo.get("repository") == owner_repo:
475
+ repo_id = repo.get("repository_id") or repo.get("id")
476
+ break
477
+
478
+ if not repo_id:
479
+ raise APIError(f"No repository ID found for {owner_repo}", 404)
480
+
481
+ # Get tree using the ID
482
+ params = {}
483
+ if branch:
484
+ params["branch"] = branch
485
+ if include_paths:
486
+ params["include_paths"] = ",".join(include_paths)
487
+ if exclude_paths:
488
+ params["exclude_paths"] = ",".join(exclude_paths)
489
+ if file_extensions:
490
+ params["file_extensions"] = ",".join(file_extensions)
491
+ if exclude_extensions:
492
+ params["exclude_extensions"] = ",".join(exclude_extensions)
493
+ if show_full_paths:
494
+ params["show_full_paths"] = "true"
495
+
496
+ response = await self.client.get(
497
+ f"{self.base_url}/v2/repositories/{repo_id}/github-tree",
498
+ params=params
499
+ )
500
+ response.raise_for_status()
501
+ return response.json()
502
+ else:
503
+ # Assume it's already a repository ID
504
+ params = {}
505
+ if branch:
506
+ params["branch"] = branch
507
+ if include_paths:
508
+ params["include_paths"] = ",".join(include_paths)
509
+ if exclude_paths:
510
+ params["exclude_paths"] = ",".join(exclude_paths)
511
+ if file_extensions:
512
+ params["file_extensions"] = ",".join(file_extensions)
513
+ if exclude_extensions:
514
+ params["exclude_extensions"] = ",".join(exclude_extensions)
515
+ if show_full_paths:
516
+ params["show_full_paths"] = "true"
517
+
518
+ response = await self.client.get(
519
+ f"{self.base_url}/v2/repositories/{owner_repo}/github-tree",
520
+ params=params
521
+ )
522
+ response.raise_for_status()
523
+ return response.json()
524
+
525
+ except httpx.HTTPStatusError as e:
526
+ raise self._handle_api_error(e)
527
+ except APIError:
528
+ raise
529
+ except Exception as e:
530
+ logger.error(f"Failed to get GitHub tree: {e}")
531
+ raise APIError(f"Failed to get GitHub tree: {str(e)}")
532
+
436
533
  # Data Source methods
437
534
 
438
535
  async def create_data_source(
@@ -656,22 +753,86 @@ class NIAApiClient:
656
753
  payload = {
657
754
  "query": query,
658
755
  }
659
-
756
+
660
757
  if output_format:
661
758
  payload["output_format"] = output_format
662
-
759
+
663
760
  response = await self.client.post(
664
761
  f"{self.base_url}/v2/deep-research",
665
762
  json=payload
666
763
  )
667
764
  response.raise_for_status()
668
765
  return response.json()
669
-
766
+
670
767
  except httpx.HTTPStatusError as e:
671
768
  raise self._handle_api_error(e)
672
769
  except Exception as e:
673
770
  raise APIError(f"Deep research failed: {str(e)}")
674
-
771
+
772
+ async def regex_search(
773
+ self,
774
+ repositories: List[str],
775
+ query: str,
776
+ pattern: Optional[str] = None,
777
+ file_extensions: Optional[List[str]] = None,
778
+ languages: Optional[List[str]] = None,
779
+ max_results: int = 50,
780
+ include_context: bool = True,
781
+ context_lines: int = 3
782
+ ) -> Dict[str, Any]:
783
+ """
784
+ Perform regex pattern search over indexed repository source code.
785
+
786
+ Args:
787
+ repositories: List of repositories to search (owner/repo format)
788
+ query: Natural language query or regex pattern
789
+ pattern: Optional explicit regex pattern (overrides query extraction)
790
+ file_extensions: File extensions to filter (e.g., [".js", ".tsx"])
791
+ languages: Programming languages to filter
792
+ max_results: Maximum number of results to return
793
+ include_context: Include surrounding context lines
794
+ context_lines: Number of context lines before/after match
795
+
796
+ Returns:
797
+ Search results with matched patterns and locations
798
+ """
799
+ try:
800
+ # Build repository list
801
+ repo_list = []
802
+ for repo in repositories:
803
+ if isinstance(repo, dict):
804
+ repo_list.append(repo)
805
+ else:
806
+ repo_list.append({"repository": repo})
807
+
808
+ payload = {
809
+ "repositories": repo_list,
810
+ "query": query,
811
+ "max_results": max_results,
812
+ "include_context": include_context,
813
+ "context_lines": context_lines
814
+ }
815
+
816
+ # Add optional parameters
817
+ if pattern:
818
+ payload["pattern"] = pattern
819
+ if file_extensions:
820
+ payload["file_extensions"] = file_extensions
821
+ if languages:
822
+ payload["languages"] = languages
823
+
824
+ response = await self.client.post(
825
+ f"{self.base_url}/v2/regex-search",
826
+ json=payload
827
+ )
828
+ response.raise_for_status()
829
+ return response.json()
830
+
831
+ except httpx.HTTPStatusError as e:
832
+ raise self._handle_api_error(e)
833
+ except Exception as e:
834
+ raise APIError(f"Regex search failed: {str(e)}")
835
+
675
836
  async def get_source_content(
676
837
  self,
677
838
  source_type: str,