nia-mcp-server 1.0.0__tar.gz → 1.0.3__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.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nia-mcp-server
3
- Version: 1.0.0
3
+ Version: 1.0.3
4
4
  Summary: NIA Knowledge Agent - MCP server for intelligent codebase search
5
5
  Project-URL: Homepage, https://trynia.ai
6
6
  Project-URL: Documentation, https://docs.trynia.ai
@@ -90,6 +90,39 @@ Find the authentication logic in my repositories
90
90
  What are the best practices for error handling according to the docs?
91
91
  ```
92
92
 
93
+ ### Search and index new content
94
+ ```
95
+ Find the best RAG implementations out there
96
+ ```
97
+ Claude will:
98
+ 1. Use the `nia_web_search` tool to find trending RAG repos
99
+ 2. Show you the results with summaries
100
+ 3. Prompt you to index the ones you want
101
+ 4. You say "Index the first two" and it indexes them!
102
+
103
+ ```
104
+ What are the hottest new Rust web frameworks this week?
105
+ ```
106
+ Claude searches trending repos and guides you through indexing them.
107
+
108
+ Advanced search examples:
109
+ ```
110
+ Find GitHub repos similar to langchain/langchain
111
+
112
+ Search for AI papers published in the last 30 days
113
+
114
+ What are the trending machine learning frameworks this month?
115
+ ```
116
+
117
+ ### Deep research questions
118
+ ```
119
+ Compare the top 3 vector databases for RAG applications
120
+
121
+ What are the pros and cons of different LLM orchestration frameworks?
122
+
123
+ Research the latest developments in AI agent architectures
124
+ ```
125
+
93
126
  ### List your resources
94
127
  ```
95
128
  Show me all my indexed repositories and documentation
@@ -97,6 +130,21 @@ Show me all my indexed repositories and documentation
97
130
 
98
131
  ## Available Tools
99
132
 
133
+ ### Search & Research
134
+ - **`nia_web_search`** - AI-powered search of repositories, documentation, and content
135
+ - Finds trending GitHub repos, relevant documentation, and more
136
+ - Returns structured results that guide you to index the best content
137
+ - Advanced options:
138
+ - `category`: Filter by type (github, company, research paper, news, etc.)
139
+ - `days_back`: Find content from the last N days (great for trending)
140
+ - `find_similar_to`: Search for content similar to a given URL
141
+ - Built into NIA's advanced search capabilities
142
+
143
+ - **`nia_deep_research_agent`** - Multi-step AI research for complex questions
144
+ - Best for comparative analysis, comprehensive overviews
145
+ - Returns structured data with citations
146
+ - Examples: "Compare top RAG frameworks", "Analyze trends in AI safety"
147
+
100
148
  ### Repository Management
101
149
  - **`index_repository`** - Index a GitHub repository
102
150
  - **`list_repositories`** - List all indexed repositories
@@ -62,6 +62,39 @@ Find the authentication logic in my repositories
62
62
  What are the best practices for error handling according to the docs?
63
63
  ```
64
64
 
65
+ ### Search and index new content
66
+ ```
67
+ Find the best RAG implementations out there
68
+ ```
69
+ Claude will:
70
+ 1. Use the `nia_web_search` tool to find trending RAG repos
71
+ 2. Show you the results with summaries
72
+ 3. Prompt you to index the ones you want
73
+ 4. You say "Index the first two" and it indexes them!
74
+
75
+ ```
76
+ What are the hottest new Rust web frameworks this week?
77
+ ```
78
+ Claude searches trending repos and guides you through indexing them.
79
+
80
+ Advanced search examples:
81
+ ```
82
+ Find GitHub repos similar to langchain/langchain
83
+
84
+ Search for AI papers published in the last 30 days
85
+
86
+ What are the trending machine learning frameworks this month?
87
+ ```
88
+
89
+ ### Deep research questions
90
+ ```
91
+ Compare the top 3 vector databases for RAG applications
92
+
93
+ What are the pros and cons of different LLM orchestration frameworks?
94
+
95
+ Research the latest developments in AI agent architectures
96
+ ```
97
+
65
98
  ### List your resources
66
99
  ```
67
100
  Show me all my indexed repositories and documentation
@@ -69,6 +102,21 @@ Show me all my indexed repositories and documentation
69
102
 
70
103
  ## Available Tools
71
104
 
105
+ ### Search & Research
106
+ - **`nia_web_search`** - AI-powered search of repositories, documentation, and content
107
+ - Finds trending GitHub repos, relevant documentation, and more
108
+ - Returns structured results that guide you to index the best content
109
+ - Advanced options:
110
+ - `category`: Filter by type (github, company, research paper, news, etc.)
111
+ - `days_back`: Find content from the last N days (great for trending)
112
+ - `find_similar_to`: Search for content similar to a given URL
113
+ - Built into NIA's advanced search capabilities
114
+
115
+ - **`nia_deep_research_agent`** - Multi-step AI research for complex questions
116
+ - Best for comparative analysis, comprehensive overviews
117
+ - Returns structured data with citations
118
+ - Examples: "Compare top RAG frameworks", "Analyze trends in AI safety"
119
+
72
120
  ### Repository Management
73
121
  - **`index_repository`** - Index a GitHub repository
74
122
  - **`list_repositories`** - List all indexed repositories
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "nia-mcp-server"
7
- version = "1.0.0"
7
+ version = "1.0.3"
8
8
  description = "NIA Knowledge Agent - MCP server for intelligent codebase search"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.8"
@@ -2,4 +2,4 @@
2
2
  NIA MCP Server - Proxy server for NIA Knowledge Agent
3
3
  """
4
4
 
5
- __version__ = "1.0.0"
5
+ __version__ = "1.0.3"
@@ -31,7 +31,7 @@ class NIAApiClient:
31
31
  "User-Agent": "nia-mcp-server/1.0.0",
32
32
  "Content-Type": "application/json"
33
33
  },
34
- timeout=300.0 # 5 minute timeout for long operations
34
+ timeout=720.0 # 12 minute timeout for deep research operations
35
35
  )
36
36
 
37
37
  async def close(self):
@@ -474,4 +474,65 @@ class NIAApiClient:
474
474
  except httpx.HTTPStatusError as e:
475
475
  raise self._handle_api_error(e)
476
476
  except Exception as e:
477
- raise APIError(f"Query failed: {str(e)}")
477
+ raise APIError(f"Query failed: {str(e)}")
478
+
479
+ async def web_search(
480
+ self,
481
+ query: str,
482
+ num_results: int = 5,
483
+ category: Optional[str] = None,
484
+ days_back: Optional[int] = None,
485
+ find_similar_to: Optional[str] = None
486
+ ) -> Dict[str, Any]:
487
+ """Perform AI-powered web search."""
488
+ try:
489
+ payload = {
490
+ "query": query,
491
+ "num_results": min(num_results, 10),
492
+ }
493
+
494
+ # Add optional parameters
495
+ if category:
496
+ payload["category"] = category
497
+ if days_back:
498
+ payload["days_back"] = days_back
499
+ if find_similar_to:
500
+ payload["find_similar_to"] = find_similar_to
501
+
502
+ response = await self.client.post(
503
+ f"{self.base_url}/v2/web-search",
504
+ json=payload
505
+ )
506
+ response.raise_for_status()
507
+ return response.json()
508
+
509
+ except httpx.HTTPStatusError as e:
510
+ raise self._handle_api_error(e)
511
+ except Exception as e:
512
+ raise APIError(f"Web search failed: {str(e)}")
513
+
514
+ async def deep_research(
515
+ self,
516
+ query: str,
517
+ output_format: Optional[str] = None
518
+ ) -> Dict[str, Any]:
519
+ """Perform deep research using AI agent."""
520
+ try:
521
+ payload = {
522
+ "query": query,
523
+ }
524
+
525
+ if output_format:
526
+ payload["output_format"] = output_format
527
+
528
+ response = await self.client.post(
529
+ f"{self.base_url}/v2/deep-research",
530
+ json=payload
531
+ )
532
+ response.raise_for_status()
533
+ return response.json()
534
+
535
+ except httpx.HTTPStatusError as e:
536
+ raise self._handle_api_error(e)
537
+ except Exception as e:
538
+ raise APIError(f"Deep research failed: {str(e)}")
@@ -7,10 +7,17 @@ import json
7
7
  import asyncio
8
8
  from typing import List, Optional, Dict, Any
9
9
  from datetime import datetime
10
+ from urllib.parse import urlparse
10
11
 
11
12
  from mcp.server.fastmcp import FastMCP
12
13
  from mcp.types import TextContent, Resource
13
14
  from .api_client import NIAApiClient, APIError
15
+ from dotenv import load_dotenv
16
+
17
+ # Load .env from parent directory (nia-app/.env)
18
+ from pathlib import Path
19
+ env_path = Path(__file__).parent.parent.parent.parent / ".env"
20
+ load_dotenv(env_path)
14
21
 
15
22
  # Configure logging
16
23
  logging.basicConfig(
@@ -19,6 +26,20 @@ logging.basicConfig(
19
26
  )
20
27
  logger = logging.getLogger(__name__)
21
28
 
29
+ # TOOL SELECTION GUIDE FOR AI ASSISTANTS:
30
+ #
31
+ # Use 'nia_web_search' for:
32
+ # - "Find RAG libraries" → Simple search
33
+ # - "What's trending in Rust?" → Quick discovery
34
+ # - "Show me repos like LangChain" → Similarity search
35
+ #
36
+ # Use 'nia_deep_research_agent' for:
37
+ # - "Compare RAG vs GraphRAG approaches" → Comparative analysis
38
+ # - "What are the best vector databases for production?" → Evaluation needed
39
+ # - "Analyze the pros and cons of different LLM frameworks" → Structured analysis
40
+ #
41
+ # The AI should assess query complexity and choose accordingly.
42
+
22
43
  # Create the MCP server
23
44
  mcp = FastMCP("nia-knowledge-agent")
24
45
 
@@ -164,7 +185,7 @@ async def search_codebase(
164
185
  messages=messages,
165
186
  repositories=repositories,
166
187
  data_sources=[], # No documentation sources
167
- search_mode="unified", # Use unified for full answers
188
+ search_mode="repositories", # Use repositories mode to exclude external sources
168
189
  stream=True,
169
190
  include_sources=include_sources
170
191
  ):
@@ -699,6 +720,354 @@ async def delete_repository(repository: str) -> List[TextContent]:
699
720
  text=f"❌ Error deleting repository: {str(e)}"
700
721
  )]
701
722
 
723
+ @mcp.tool()
724
+ async def nia_web_search(
725
+ query: str,
726
+ num_results: int = 5,
727
+ category: Optional[str] = None,
728
+ days_back: Optional[int] = None,
729
+ find_similar_to: Optional[str] = None
730
+ ) -> List[TextContent]:
731
+ """
732
+ Search repositories, documentation, and other content using AI-powered search.
733
+ Returns results formatted to guide next actions.
734
+
735
+ USE THIS TOOL WHEN:
736
+ - Finding specific repos/docs/content ("find X library", "trending Y frameworks")
737
+ - Looking for examples or implementations
738
+ - Searching for what's available on a topic
739
+ - Simple, direct searches that need quick results
740
+ - Finding similar content to a known URL
741
+
742
+ DON'T USE THIS FOR:
743
+ - Comparative analysis (use nia_deep_research_agent instead)
744
+ - Complex multi-faceted questions (use nia_deep_research_agent instead)
745
+ - Questions requiring synthesis of multiple sources (use nia_deep_research_agent instead)
746
+
747
+ Args:
748
+ query: Natural language search query (e.g., "best RAG implementations", "trending rust web frameworks")
749
+ num_results: Number of results to return (default: 5, max: 10)
750
+ category: Filter by category: "github", "company", "research paper", "news", "tweet", "pdf"
751
+ days_back: Only show results from the last N days (for trending content)
752
+ find_similar_to: URL to find similar content to
753
+
754
+ Returns:
755
+ Search results with actionable next steps
756
+ """
757
+ try:
758
+ client = await ensure_api_client()
759
+
760
+ logger.info(f"Searching content for query: {query}")
761
+
762
+ # Use the API client method instead of direct HTTP call
763
+ result = await client.web_search(
764
+ query=query,
765
+ num_results=num_results,
766
+ category=category,
767
+ days_back=days_back,
768
+ find_similar_to=find_similar_to
769
+ )
770
+
771
+ # Extract results
772
+ github_repos = result.get("github_repos", [])
773
+ documentation = result.get("documentation", [])
774
+ other_content = result.get("other_content", [])
775
+
776
+ # Format response to naturally guide next actions
777
+ response_text = f"## 🔍 NIA Web Search Results for: \"{query}\"\n\n"
778
+
779
+ if days_back:
780
+ response_text += f"*Showing results from the last {days_back} days*\n\n"
781
+
782
+ if find_similar_to:
783
+ response_text += f"*Finding content similar to: {find_similar_to}*\n\n"
784
+
785
+ # GitHub Repositories Section
786
+ if github_repos:
787
+ response_text += f"### 📦 GitHub Repositories ({len(github_repos)} found)\n\n"
788
+
789
+ for i, repo in enumerate(github_repos[:num_results], 1):
790
+ response_text += f"**{i}. {repo['title']}**\n"
791
+ response_text += f" 📍 `{repo['url']}`\n"
792
+ if repo.get('published_date'):
793
+ response_text += f" 📅 Updated: {repo['published_date']}\n"
794
+ if repo['summary']:
795
+ response_text += f" 📝 {repo['summary']}...\n"
796
+ if repo['highlights']:
797
+ response_text += f" ✨ Key features: {', '.join(repo['highlights'])}\n"
798
+ response_text += "\n"
799
+
800
+ # Be more aggressive based on query specificity
801
+ if len(github_repos) == 1 or any(specific_word in query.lower() for specific_word in ["specific", "exact", "particular", "find me", "looking for"]):
802
+ response_text += "**🚀 RECOMMENDED ACTION - Index this repository with NIA:**\n"
803
+ response_text += f"```\nIndex {github_repos[0]['owner_repo']}\n```\n"
804
+ response_text += "✨ This will enable AI-powered code search, understanding, and analysis!\n\n"
805
+ else:
806
+ response_text += "**🚀 Make these repositories searchable with NIA's AI:**\n"
807
+ response_text += f"- **Quick start:** Say \"Index {github_repos[0]['owner_repo']}\"\n"
808
+ response_text += "- **Index multiple:** Say \"Index all repositories\"\n"
809
+ response_text += "- **Benefits:** AI-powered code search, architecture understanding, implementation details\n\n"
810
+
811
+ # Documentation Section
812
+ if documentation:
813
+ response_text += f"### 📚 Documentation ({len(documentation)} found)\n\n"
814
+
815
+ for i, doc in enumerate(documentation[:num_results], 1):
816
+ response_text += f"**{i}. {doc['title']}**\n"
817
+ response_text += f" 📍 `{doc['url']}`\n"
818
+ if doc['summary']:
819
+ response_text += f" 📝 {doc['summary']}...\n"
820
+ if doc.get('highlights'):
821
+ response_text += f" ✨ Key topics: {', '.join(doc['highlights'])}\n"
822
+ response_text += "\n"
823
+
824
+ # Be more aggressive for documentation too
825
+ if len(documentation) == 1 or any(specific_word in query.lower() for specific_word in ["docs", "documentation", "guide", "tutorial", "reference"]):
826
+ response_text += "**📖 RECOMMENDED ACTION - Index this documentation with NIA:**\n"
827
+ response_text += f"```\nIndex documentation {documentation[0]['url']}\n```\n"
828
+ response_text += "✨ NIA will make this fully searchable with AI-powered Q&A!\n\n"
829
+ else:
830
+ response_text += "**📖 Make this documentation AI-searchable with NIA:**\n"
831
+ response_text += f"- **Quick start:** Say \"Index documentation {documentation[0]['url']}\"\n"
832
+ response_text += "- **Index all:** Say \"Index all documentation\"\n"
833
+ response_text += "- **Benefits:** Instant answers, smart search, code examples extraction\n\n"
834
+
835
+ # Other Content Section
836
+ if other_content and not github_repos and not documentation:
837
+ response_text += f"### 🌐 Other Content ({len(other_content)} found)\n\n"
838
+
839
+ for i, content in enumerate(other_content[:num_results], 1):
840
+ response_text += f"**{i}. {content['title']}**\n"
841
+ response_text += f" 📍 `{content['url']}`\n"
842
+ if content['summary']:
843
+ response_text += f" 📝 {content['summary']}...\n"
844
+ response_text += "\n"
845
+
846
+ # No results found
847
+ if not github_repos and not documentation and not other_content:
848
+ response_text = f"No results found for '{query}'. Try:\n"
849
+ response_text += "- Using different keywords\n"
850
+ response_text += "- Being more specific (e.g., 'Python RAG implementation')\n"
851
+ response_text += "- Including technology names (e.g., 'LangChain', 'TypeScript')\n"
852
+
853
+ # Add prominent call-to-action if we found indexable content
854
+ if github_repos or documentation:
855
+ response_text += "\n## 🎯 **Ready to unlock NIA's AI capabilities?**\n"
856
+ response_text += "The repositories and documentation above can be indexed for:\n"
857
+ response_text += "- 🤖 AI-powered code understanding and search\n"
858
+ response_text += "- 💡 Instant answers to technical questions\n"
859
+ response_text += "- 🔍 Deep architectural insights\n"
860
+ response_text += "- 📚 Smart documentation Q&A\n\n"
861
+ response_text += "**Just copy and paste the index commands above!**\n"
862
+
863
+ # Add search metadata
864
+ response_text += f"\n---\n"
865
+ response_text += f"*Searched {result.get('total_results', 0)} sources using NIA Web Search*"
866
+
867
+ return [TextContent(type="text", text=response_text)]
868
+
869
+ except APIError as e:
870
+ logger.error(f"API Error in web search: {e}")
871
+ if e.status_code == 403 or "free tier limit" in str(e).lower() or "free api requests" in str(e).lower():
872
+ if e.detail and "25 free API requests" in e.detail:
873
+ return [TextContent(
874
+ type="text",
875
+ text=f"❌ {e.detail}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited API access."
876
+ )]
877
+ else:
878
+ return [TextContent(
879
+ type="text",
880
+ text=f"❌ {str(e)}\n\n💡 Tip: You've reached the free tier limit. Upgrade to Pro for unlimited access."
881
+ )]
882
+ else:
883
+ return [TextContent(type="text", text=f"❌ {str(e)}")]
884
+ except Exception as e:
885
+ logger.error(f"Error in NIA web search: {str(e)}")
886
+ return [TextContent(
887
+ type="text",
888
+ text=f"❌ NIA Web Search error: {str(e)}\n\n"
889
+ "This might be due to:\n"
890
+ "- Network connectivity issues\n"
891
+ "- Service temporarily unavailable"
892
+ )]
893
+
894
+ @mcp.tool()
895
+ async def nia_deep_research_agent(
896
+ query: str,
897
+ output_format: Optional[str] = None
898
+ ) -> List[TextContent]:
899
+ """
900
+ Perform deep, multi-step research on a topic using advanced AI research capabilities.
901
+ Best for complex questions that need comprehensive analysis.
902
+
903
+ USE THIS TOOL WHEN:
904
+ - Comparing multiple options ("compare X vs Y vs Z")
905
+ - Analyzing pros and cons
906
+ - Questions with "best", "top", "which is better"
907
+ - Needing structured analysis or synthesis
908
+ - Complex questions requiring multiple sources
909
+ - Questions about trends, patterns, or developments
910
+ - Requests for comprehensive overviews
911
+
912
+ DON'T USE THIS FOR:
913
+ - Simple lookups (use nia_web_search instead)
914
+ - Finding a specific known item (use nia_web_search instead)
915
+ - Quick searches for repos/docs (use nia_web_search instead)
916
+
917
+ COMPLEXITY INDICATORS:
918
+ - Words like: compare, analyze, evaluate, pros/cons, trade-offs
919
+ - Multiple criteria mentioned
920
+ - Asking for recommendations based on context
921
+ - Needing structured output (tables, lists, comparisons)
922
+
923
+ Args:
924
+ query: Research question (e.g., "Compare top 3 RAG frameworks with pros/cons")
925
+ output_format: Optional structure hint (e.g., "comparison table", "pros and cons list")
926
+
927
+ Returns:
928
+ Comprehensive research results with citations
929
+ """
930
+ try:
931
+ client = await ensure_api_client()
932
+
933
+ logger.info(f"Starting deep research for: {query}")
934
+
935
+ # Use the API client method with proper timeout handling
936
+ try:
937
+ result = await asyncio.wait_for(
938
+ client.deep_research(query=query, output_format=output_format),
939
+ timeout=720.0 # 12 minutes to allow for longer research tasks
940
+ )
941
+ except asyncio.TimeoutError:
942
+ logger.error(f"Deep research timed out after 12 minutes for query: {query}")
943
+ return [TextContent(
944
+ type="text",
945
+ text="❌ Research timed out. The query may be too complex. Try:\n"
946
+ "- Breaking it into smaller questions\n"
947
+ "- Using more specific keywords\n"
948
+ "- Trying the nia_web_search tool for simpler queries"
949
+ )]
950
+
951
+ # Format the research results
952
+ response_text = f"## 🔬 NIA Deep Research Agent Results\n\n"
953
+ response_text += f"**Query:** {query}\n\n"
954
+
955
+ if result.get("data"):
956
+ response_text += "### 📊 Research Findings:\n\n"
957
+
958
+ # Pretty print the JSON data
959
+ import json
960
+ formatted_data = json.dumps(result["data"], indent=2)
961
+ response_text += f"```json\n{formatted_data}\n```\n\n"
962
+
963
+ # Add citations if available
964
+ if result.get("citations"):
965
+ response_text += "### 📚 Sources & Citations:\n\n"
966
+ citation_num = 1
967
+ for field, citations in result["citations"].items():
968
+ if citations:
969
+ response_text += f"**{field}:**\n"
970
+ for citation in citations[:3]: # Limit to 3 citations per field
971
+ response_text += f"{citation_num}. [{citation.get('title', 'Source')}]({citation.get('url', '#')})\n"
972
+ if citation.get('snippet'):
973
+ response_text += f" > {citation['snippet'][:150]}...\n"
974
+ citation_num += 1
975
+ response_text += "\n"
976
+
977
+ response_text += "### 💡 RECOMMENDED NEXT ACTIONS WITH NIA:\n\n"
978
+
979
+ # Extract potential repos and docs from the research data
980
+ repos_found = []
981
+ docs_found = []
982
+
983
+ # Helper function to extract URLs from nested data structures
984
+ def extract_urls_from_data(data, urls_list=None):
985
+ if urls_list is None:
986
+ urls_list = []
987
+
988
+ if isinstance(data, dict):
989
+ for value in data.values():
990
+ extract_urls_from_data(value, urls_list)
991
+ elif isinstance(data, list):
992
+ for item in data:
993
+ extract_urls_from_data(item, urls_list)
994
+ elif isinstance(data, str):
995
+ # Check if this string is a URL
996
+ if data.startswith(('http://', 'https://')):
997
+ urls_list.append(data)
998
+
999
+ return urls_list
1000
+
1001
+ # Extract all URLs from the data
1002
+ all_urls = extract_urls_from_data(result["data"])
1003
+
1004
+ # Filter for GitHub repos and documentation
1005
+ import re
1006
+ github_pattern = r'github\.com/([a-zA-Z0-9-]+/[a-zA-Z0-9-_.]+)'
1007
+
1008
+ for url in all_urls:
1009
+ # Check for GitHub repos
1010
+ github_match = re.search(github_pattern, url)
1011
+ if github_match and '/tree/' not in url and '/blob/' not in url:
1012
+ repos_found.append(github_match.group(1))
1013
+ # Check for documentation URLs
1014
+ elif any(doc_indicator in url.lower() for doc_indicator in ['docs', 'documentation', '.readthedocs.', '/guide', '/tutorial']):
1015
+ docs_found.append(url)
1016
+
1017
+ # Remove duplicates and limit results
1018
+ repos_found = list(set(repos_found))[:3]
1019
+ docs_found = list(set(docs_found))[:3]
1020
+
1021
+ if repos_found:
1022
+ response_text += "**🚀 DISCOVERED REPOSITORIES - Index with NIA for deep analysis:**\n"
1023
+ for repo in repos_found:
1024
+ response_text += f"```\nIndex {repo}\n```\n"
1025
+ response_text += "✨ Enable AI-powered code search and architecture understanding!\n\n"
1026
+
1027
+ if docs_found:
1028
+ response_text += "**📖 DISCOVERED DOCUMENTATION - Index with NIA for smart search:**\n"
1029
+ for doc in docs_found[:2]: # Limit to 2 for readability
1030
+ response_text += f"```\nIndex documentation {doc}\n```\n"
1031
+ response_text += "✨ Make documentation instantly searchable with AI Q&A!\n\n"
1032
+
1033
+ if not repos_found and not docs_found:
1034
+ response_text += "**🔍 Manual indexing options:**\n"
1035
+ response_text += "- If you see any GitHub repos mentioned: Say \"Index [owner/repo]\"\n"
1036
+ response_text += "- If you see any documentation sites: Say \"Index documentation [url]\"\n"
1037
+ response_text += "- These will unlock NIA's powerful AI search capabilities!\n\n"
1038
+
1039
+ response_text += "**📊 Other actions:**\n"
1040
+ response_text += "- Ask follow-up questions about the research\n"
1041
+ response_text += "- Request a different analysis format\n"
1042
+ response_text += "- Search for more specific information\n"
1043
+ else:
1044
+ response_text += "No structured data returned. The research may need a more specific query."
1045
+
1046
+ return [TextContent(type="text", text=response_text)]
1047
+
1048
+ except APIError as e:
1049
+ logger.error(f"API Error in deep research: {e}")
1050
+ if e.status_code == 403 or "free tier limit" in str(e).lower() or "free api requests" in str(e).lower():
1051
+ if e.detail and "25 free API requests" in e.detail:
1052
+ return [TextContent(
1053
+ type="text",
1054
+ text=f"❌ {e.detail}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited API access."
1055
+ )]
1056
+ else:
1057
+ return [TextContent(
1058
+ type="text",
1059
+ text=f"❌ {str(e)}\n\n💡 Tip: You've reached the free tier limit. Upgrade to Pro for unlimited access."
1060
+ )]
1061
+ else:
1062
+ return [TextContent(type="text", text=f"❌ {str(e)}")]
1063
+ except Exception as e:
1064
+ logger.error(f"Error in deep research: {str(e)}")
1065
+ return [TextContent(
1066
+ type="text",
1067
+ text=f"❌ Research error: {str(e)}\n\n"
1068
+ "Try simplifying your question or using the regular nia_web_search tool."
1069
+ )]
1070
+
702
1071
  # Resources
703
1072
 
704
1073
  # Note: FastMCP doesn't have list_resources or read_resource decorators
@@ -1,23 +0,0 @@
1
- #!/bin/bash
2
-
3
- # Development installation script
4
-
5
- echo "Installing NIA MCP Server for development..."
6
-
7
- # Create virtual environment
8
- python -m venv venv
9
-
10
- # Activate virtual environment
11
- source venv/bin/activate
12
-
13
- # Install in editable mode
14
- pip install -e .
15
-
16
- echo ""
17
- echo "✅ Installation complete!"
18
- echo ""
19
- echo "To use the server:"
20
- echo "1. Set your API key: export NIA_API_KEY=your-api-key-here"
21
- echo "2. Run: ./run_local.sh"
22
- echo ""
23
- echo "To test connection: python test_connection.py"
@@ -1,24 +0,0 @@
1
- #!/bin/bash
2
-
3
- # Local development runner for NIA MCP Server
4
-
5
- # Colors
6
- GREEN='\033[0;32m'
7
- YELLOW='\033[1;33m'
8
- RED='\033[0;31m'
9
- NC='\033[0m'
10
-
11
- echo -e "${GREEN}NIA MCP Server - Local Development${NC}"
12
- echo "===================================="
13
-
14
- # Check for API key
15
- if [ -z "$NIA_API_KEY" ]; then
16
- echo -e "${YELLOW}Warning: NIA_API_KEY not set${NC}"
17
- echo "Set it with: export NIA_API_KEY=your-api-key-here"
18
- echo "Get your API key at: https://trynia.ai/api-keys"
19
- exit 1
20
- fi
21
-
22
- # Run the server
23
- echo -e "${GREEN}Starting MCP server...${NC}"
24
- python -m nia_mcp_server
@@ -1,64 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Test script to verify NIA MCP Server connection
4
- """
5
- import os
6
- import asyncio
7
- from src.nia_mcp_server.api_client import NIAApiClient, APIError
8
-
9
- async def test_connection():
10
- """Test the connection to NIA API."""
11
- api_key = os.getenv("NIA_API_KEY")
12
- if not api_key:
13
- print("❌ NIA_API_KEY environment variable not set")
14
- print(" Set it with: export NIA_API_KEY=your-api-key-here")
15
- return
16
-
17
- api_url = os.getenv("NIA_API_URL", "https://api.trynia.ai")
18
- print(f"🔄 Testing connection to NIA API at {api_url}...")
19
-
20
- try:
21
- client = NIAApiClient(api_key, base_url=api_url)
22
-
23
- # Test API key validation
24
- if await client.validate_api_key():
25
- print("✅ API key is valid!")
26
-
27
- # Try to list repositories
28
- try:
29
- repos = await client.list_repositories()
30
- print(f"\n📚 You have {len(repos)} indexed repositories")
31
-
32
- for repo in repos[:3]: # Show first 3
33
- print(f" - {repo['repository']} ({repo.get('status', 'unknown')})")
34
-
35
- if len(repos) > 3:
36
- print(f" ... and {len(repos) - 3} more")
37
-
38
- except APIError as e:
39
- print(f"\n❌ {str(e)}")
40
- if e.status_code == 403 and "lifetime limit" in str(e).lower():
41
- print("\n💡 You've reached the free tier limit of 25 API requests.")
42
- print(" Upgrade to Pro at https://trynia.ai/billing for unlimited access.")
43
-
44
- else:
45
- print("❌ API key validation failed")
46
- print(" This could be due to:")
47
- print(" - Invalid API key")
48
- print(" - Exceeded usage limits (free tier: 25 lifetime requests)")
49
- print(" Check your API key at: https://trynia.ai/api-keys")
50
-
51
- await client.close()
52
-
53
- except APIError as e:
54
- print(f"❌ {str(e)}")
55
- if e.status_code == 403:
56
- print("\n💡 Access forbidden. This usually means:")
57
- print(" - You've exceeded your usage limits")
58
- print(" - Your subscription has expired")
59
- print(" Visit https://trynia.ai/billing to check your account")
60
- except Exception as e:
61
- print(f"❌ Error: {e}")
62
-
63
- if __name__ == "__main__":
64
- asyncio.run(test_connection())
@@ -1,92 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Test script for unified search functionality
4
- """
5
- import os
6
- import asyncio
7
- from src.nia_mcp_server.api_client import NIAApiClient
8
-
9
- async def test_unified_search():
10
- """Test the unified search functionality."""
11
- api_key = os.getenv("NIA_API_KEY")
12
- if not api_key:
13
- print("❌ NIA_API_KEY environment variable not set")
14
- print(" Set it with: export NIA_API_KEY=your-api-key-here")
15
- return
16
-
17
- api_url = os.getenv("NIA_API_URL", "https://api.trynia.ai")
18
- print(f"🔄 Testing unified search at {api_url}...")
19
-
20
- try:
21
- client = NIAApiClient(api_key, base_url=api_url)
22
-
23
- # First, list repositories and data sources
24
- print("\n📚 Listing repositories...")
25
- repos = await client.list_repositories()
26
- print(f"Found {len(repos)} repositories")
27
- for repo in repos[:3]:
28
- print(f" - {repo['repository']} ({repo.get('status', 'unknown')})")
29
-
30
- print("\n📄 Listing documentation sources...")
31
- sources = await client.list_data_sources()
32
- print(f"Found {len(sources)} documentation sources")
33
- for source in sources[:3]:
34
- print(f" - {source.get('url', 'Unknown')} ({source.get('status', 'unknown')})")
35
-
36
- # Test unified search
37
- if repos or sources:
38
- print("\n🔍 Testing unified search...")
39
- query = "authentication"
40
- messages = [{"role": "user", "content": query}]
41
-
42
- # Get first completed repo and source
43
- repo_list = [r["repository"] for r in repos if r.get("status") == "completed"][:1]
44
- source_list = [s["id"] for s in sources if s.get("status") == "completed"][:1]
45
-
46
- if repo_list or source_list:
47
- print(f"Searching for '{query}' across:")
48
- if repo_list:
49
- print(f" - Repository: {repo_list[0]}")
50
- if source_list:
51
- print(f" - Documentation: {sources[0].get('url', 'Unknown')}")
52
-
53
- # Perform unified search
54
- response_text = ""
55
- source_count = 0
56
-
57
- async for chunk in client.query_unified(
58
- messages=messages,
59
- repositories=repo_list,
60
- data_sources=source_list,
61
- search_mode="unified",
62
- stream=True,
63
- include_sources=True
64
- ):
65
- try:
66
- import json
67
- data = json.loads(chunk)
68
- if "content" in data:
69
- response_text += data["content"]
70
- if "sources" in data:
71
- source_count += len(data["sources"])
72
- except:
73
- continue
74
-
75
- print(f"\n✅ Unified search successful!")
76
- print(f"Response preview: {response_text[:200]}...")
77
- print(f"Found {source_count} source references")
78
- else:
79
- print("⚠️ No completed repositories or documentation sources to search")
80
- else:
81
- print("\n⚠️ No repositories or documentation sources found")
82
- print(" Index some content first using the MCP tools")
83
-
84
- await client.close()
85
-
86
- except Exception as e:
87
- print(f"❌ Error: {e}")
88
- import traceback
89
- traceback.print_exc()
90
-
91
- if __name__ == "__main__":
92
- asyncio.run(test_unified_search())
File without changes