nia-mcp-server 1.0.25__tar.gz → 1.0.27__tar.gz
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.
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/PKG-INFO +1 -1
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/pyproject.toml +1 -1
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/src/nia_mcp_server/__init__.py +1 -1
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/src/nia_mcp_server/api_client.py +167 -6
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/src/nia_mcp_server/server.py +1547 -650
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/.gitignore +0 -0
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/ARCHITECTURE.md +0 -0
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/LICENSE +0 -0
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/README.md +0 -0
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/nia_analytics.log +0 -0
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/nia_mcp_server.log +0 -0
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/src/nia_mcp_server/__main__.py +0 -0
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/src/nia_mcp_server/assets/rules/claude_rules.md +0 -0
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/src/nia_mcp_server/assets/rules/cursor_rules.md +0 -0
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/src/nia_mcp_server/assets/rules/nia_rules.md +0 -0
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/src/nia_mcp_server/assets/rules/vscode_rules.md +0 -0
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/src/nia_mcp_server/assets/rules/windsurf_rules.md +0 -0
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/src/nia_mcp_server/cli.py +0 -0
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/src/nia_mcp_server/profiles.py +0 -0
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/src/nia_mcp_server/project_init.py +0 -0
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/src/nia_mcp_server/rule_transformer.py +0 -0
- {nia_mcp_server-1.0.25 → nia_mcp_server-1.0.27}/src/nia_mcp_server/setup.py +0 -0
|
@@ -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.
|
|
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,
|