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

Files changed (22) hide show
  1. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/PKG-INFO +1 -1
  2. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/pyproject.toml +1 -1
  3. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/src/nia_mcp_server/__init__.py +1 -1
  4. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/src/nia_mcp_server/api_client.py +45 -9
  5. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/src/nia_mcp_server/assets/rules/nia_rules.md +44 -5
  6. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/src/nia_mcp_server/server.py +68 -31
  7. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/.gitignore +0 -0
  8. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/ARCHITECTURE.md +0 -0
  9. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/LICENSE +0 -0
  10. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/README.md +0 -0
  11. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/nia_analytics.log +0 -0
  12. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/nia_mcp_server.log +0 -0
  13. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/src/nia_mcp_server/__main__.py +0 -0
  14. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/src/nia_mcp_server/assets/rules/claude_rules.md +0 -0
  15. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/src/nia_mcp_server/assets/rules/cursor_rules.md +0 -0
  16. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/src/nia_mcp_server/assets/rules/vscode_rules.md +0 -0
  17. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/src/nia_mcp_server/assets/rules/windsurf_rules.md +0 -0
  18. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/src/nia_mcp_server/cli.py +0 -0
  19. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/src/nia_mcp_server/profiles.py +0 -0
  20. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/src/nia_mcp_server/project_init.py +0 -0
  21. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/src/nia_mcp_server/rule_transformer.py +0 -0
  22. {nia_mcp_server-1.0.13 → nia_mcp_server-1.0.15}/src/nia_mcp_server/setup.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nia-mcp-server
3
- Version: 1.0.13
3
+ Version: 1.0.15
4
4
  Summary: Nia Knowledge Agent
5
5
  Project-URL: Homepage, https://trynia.ai
6
6
  Project-URL: Documentation, https://docs.trynia.ai
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "nia-mcp-server"
7
- version = "1.0.13"
7
+ version = "1.0.15"
8
8
  description = "Nia Knowledge Agent"
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.13"
5
+ __version__ = "1.0.15"
@@ -75,7 +75,7 @@ class NIAApiClient:
75
75
  "lifetime limit",
76
76
  "no chat credits",
77
77
  "free api requests",
78
- "5 free",
78
+ "3 free",
79
79
  "usage limit",
80
80
  ]
81
81
  ):
@@ -99,7 +99,7 @@ class NIAApiClient:
99
99
  for phrase in [
100
100
  "lifetime limit",
101
101
  "free api requests",
102
- "5 free",
102
+ "3 free",
103
103
  "usage limit",
104
104
  ]
105
105
  ):
@@ -159,15 +159,33 @@ class NIAApiClient:
159
159
  async def index_repository(self, repo_url: str, branch: str = None) -> Dict[str, Any]:
160
160
  """Index a GitHub repository."""
161
161
  try:
162
- # Parse repo URL to get owner/repo format
162
+ # Handle different input formats
163
163
  if "github.com" in repo_url:
164
- parts = repo_url.rstrip('/').split('/')
165
- owner_repo = f"{parts[-2]}/{parts[-1]}"
164
+ # Remove query parameters and fragments
165
+ clean_url = repo_url.split('?')[0].split('#')[0]
166
+
167
+ # Check if it's a folder URL (contains /tree/)
168
+ if "/tree/" in clean_url:
169
+ # Extract everything after github.com/
170
+ parts = clean_url.split('github.com/', 1)
171
+ if len(parts) > 1:
172
+ repository_path = parts[1].rstrip('/')
173
+ else:
174
+ repository_path = repo_url
175
+ else:
176
+ # Regular repo URL - extract owner/repo
177
+ parts = clean_url.rstrip('/').split('/')
178
+ if len(parts) >= 2:
179
+ repo_name = parts[-1].rstrip('.git') # Remove .git suffix
180
+ repository_path = f"{parts[-2]}/{repo_name}"
181
+ else:
182
+ repository_path = repo_url
166
183
  else:
167
- owner_repo = repo_url
184
+ # Assume it's already in the right format
185
+ repository_path = repo_url
168
186
 
169
187
  payload = {
170
- "repository": owner_repo,
188
+ "repository": repository_path,
171
189
  "branch": branch
172
190
  }
173
191
 
@@ -191,11 +209,29 @@ class NIAApiClient:
191
209
  # First, list all repositories to find the matching one
192
210
  repos = await self.list_repositories()
193
211
 
212
+ # Extract base repository path for matching
213
+ # Handle both "owner/repo" and "owner/repo/folder" formats
214
+ base_repo = owner_repo
215
+ if owner_repo.count('/') > 1:
216
+ # This might be a folder path like "owner/repo/folder"
217
+ # Extract just the owner/repo part
218
+ parts = owner_repo.split('/')
219
+ base_repo = f"{parts[0]}/{parts[1]}"
220
+
194
221
  # Look for a repository matching this owner/repo
195
222
  matching_repo = None
196
223
  for repo in repos:
197
- # Check if repository field matches
198
- if repo.get("repository") == owner_repo:
224
+ repo_path = repo.get("repository", "")
225
+ # Check exact match first
226
+ if repo_path == owner_repo:
227
+ matching_repo = repo
228
+ break
229
+ # Then check if it's the base repository
230
+ elif repo_path == base_repo:
231
+ matching_repo = repo
232
+ break
233
+ # Also check if the stored repo is a folder path that starts with our base
234
+ elif repo_path.startswith(base_repo + "/"):
199
235
  matching_repo = repo
200
236
  break
201
237
 
@@ -29,25 +29,60 @@ Note: Nia is just "Nia" - not an acronym. It's the name of the knowledge search
29
29
  - Structured output needs (tables, lists)
30
30
  - Questions with "best", "which is better", "compare"
31
31
 
32
- ### 3. Query Optimization
32
+ ### 3. Repository Identifier Formats
33
+
34
+ #### Understanding Repository Paths
35
+ When using `search_codebase`, repositories can be specified in different formats:
36
+
37
+ 1. **Full Repository Format**: `owner/repo`
38
+ - Example: `facebook/react`
39
+ - Use this when the entire repository was indexed
40
+
41
+ 2. **Folder-Specific Format**: `owner/repo/tree/branch/folder`
42
+ - Example: `PostHog/posthog/tree/master/docs`
43
+ - Use this EXACT format when a specific folder was indexed
44
+ - This format appears in `list_repositories` output - copy it exactly!
45
+
46
+ #### Important Rules:
47
+ - **Always check `list_repositories` first** to see the exact format
48
+ - **Copy the repository identifier exactly** as shown in the list
49
+ - **Don't modify folder paths** - if it shows `owner/repo/tree/branch/folder`, use that exact string
50
+ - **Don't assume** - a repository indexed as a folder won't work with just `owner/repo`
51
+
52
+ #### Examples:
53
+ ```python
54
+ # Wrong - trying to use base repo when folder was indexed
55
+ search_codebase("What is Flox?", ["PostHog/posthog"]) # ❌ Won't find folder-indexed content
56
+
57
+ # Right - using exact format from list_repositories
58
+ search_codebase("What is Flox?", ["PostHog/posthog/tree/master/docs"]) # ✅ Searches the indexed folder
59
+
60
+ # Wrong - modifying the path
61
+ search_codebase("LLM guide", ["mcp-use/mcp-use/docs"]) # ❌ Missing /tree/main/ part
62
+
63
+ # Right - exact format
64
+ search_codebase("LLM guide", ["mcp-use/mcp-use/tree/main/docs"]) # ✅ Correct format
65
+ ```
66
+
67
+ ### 4. Query Optimization
33
68
  - **Use natural language queries** - Form complete questions, not just keywords
34
69
  - **Be specific and detailed** - "How does authentication work in NextAuth.js?" not "auth nextauth"
35
70
  - **Include context** - Mention specific technologies, frameworks, or use cases
36
71
  - **Leverage repository context** - Specify repositories when searching indexed codebases
37
72
 
38
- ### 4. API Usage Best Practices
39
- - **Handle rate limits gracefully** - Free tier has 25 API request limit
73
+ ### 5. API Usage Best Practices
74
+ - **Handle rate limits gracefully** - Free tier has 3 indexing operations limit
40
75
  - **Cache results mentally** - Avoid redundant searches in the same conversation
41
76
  - **Batch operations** - Index multiple related repositories together
42
77
  - **Monitor status efficiently** - Check status periodically, not continuously
43
78
 
44
- ### 5. Result Interpretation
79
+ ### 6. Result Interpretation
45
80
  - **Provide actionable next steps** - Always suggest how to use the results
46
81
  - **Extract indexable content** - Identify repositories and docs from search results
47
82
  - **Format for readability** - Use markdown formatting for clear presentation
48
83
  - **Include sources** - Always show where information comes from
49
84
 
50
- ### 6. Error Handling
85
+ ### 7. Error Handling
51
86
  - **Explain API limits clearly** - Help users understand free tier limitations
52
87
  - **Suggest alternatives** - Provide workarounds when hitting limits
53
88
  - **Report issues helpfully** - Include enough context for debugging
@@ -63,8 +98,12 @@ Note: Nia is just "Nia" - not an acronym. It's the name of the knowledge search
63
98
 
64
99
  ### Pattern 2: Codebase Understanding
65
100
  1. Check if repository is already indexed with `list_repositories`
101
+ - Note the EXACT repository format shown (especially for folder paths)
102
+ - Example output: "PostHog/posthog/tree/master/docs" (not just "PostHog/posthog")
66
103
  2. If not indexed, use `index_repository` and wait for completion
67
104
  3. Use `search_codebase` with specific technical questions
105
+ - Use the EXACT repository identifier from step 1
106
+ - Don't modify or simplify folder paths
68
107
  4. Include code snippets and file references in responses
69
108
 
70
109
  ### Pattern 3: Documentation Search
@@ -83,7 +83,7 @@ async def index_repository(
83
83
  Index a GitHub repository for intelligent code search.
84
84
 
85
85
  Args:
86
- repo_url: GitHub repository URL (e.g., https://github.com/owner/repo)
86
+ repo_url: GitHub repository URL (e.g., https://github.com/owner/repo or https://github.com/owner/repo/tree/branch)
87
87
  branch: Branch to index (optional, defaults to main branch)
88
88
 
89
89
  Returns:
@@ -121,11 +121,11 @@ async def index_repository(
121
121
 
122
122
  except APIError as e:
123
123
  logger.error(f"API Error indexing repository: {e} (status_code={e.status_code}, detail={e.detail})")
124
- if e.status_code == 403 or "free tier limit" in str(e).lower() or "free api requests" in str(e).lower():
125
- if e.detail and "5 free API requests" in e.detail:
124
+ if e.status_code == 403 or "free tier limit" in str(e).lower() or "indexing operations" in str(e).lower():
125
+ if e.detail and "3 free indexing operations" in e.detail:
126
126
  return [TextContent(
127
127
  type="text",
128
- text=f"❌ {e.detail}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited API access."
128
+ text=f"❌ {e.detail}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited indexing."
129
129
  )]
130
130
  else:
131
131
  return [TextContent(
@@ -137,10 +137,10 @@ async def index_repository(
137
137
  except Exception as e:
138
138
  logger.error(f"Unexpected error indexing repository: {e}")
139
139
  error_msg = str(e)
140
- if "free api requests" in error_msg.lower() or "lifetime limit" in error_msg.lower():
140
+ if "indexing operations" in error_msg.lower() or "lifetime limit" in error_msg.lower():
141
141
  return [TextContent(
142
142
  type="text",
143
- text=f"❌ {error_msg}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited API access."
143
+ text=f"❌ {error_msg}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited indexing."
144
144
  )]
145
145
  return [TextContent(
146
146
  type="text",
@@ -158,11 +158,26 @@ async def search_codebase(
158
158
 
159
159
  Args:
160
160
  query: Natural language search query. Don't just use keywords or unstrctured query, make a comprehensive question to get the best results possible.
161
- repositories: List of repositories to search (owner/repo format). If not specified, searches all indexed repos.
161
+ repositories: List of repositories to search (owner/repo or owner/repo/tree/branch if indexed differently before).
162
+ - "owner/repo" - Search entire repository (e.g., "facebook/react")
163
+ - "owner/repo/tree/branch/folder" - Search specific folder indexed separately
164
+ (e.g., "PostHog/posthog/tree/master/docs")
165
+ Use the EXACT format shown in list_repositories output for folder-indexed repos.
166
+ If not specified, searches all indexed repos.
162
167
  include_sources: Whether to include source code in results
163
168
 
164
169
  Returns:
165
170
  Search results with relevant code snippets and explanations
171
+
172
+ Examples:
173
+ # Search all indexed repositories
174
+ search_codebase("How does authentication work?")
175
+
176
+ # Search specific repository
177
+ search_codebase("How to create custom hooks?", ["facebook/react"])
178
+
179
+ # Search folder-indexed repository (use exact format from list_repositories)
180
+ search_codebase("What is Flox?", ["PostHog/posthog/tree/master/docs"])
166
181
  """
167
182
  try:
168
183
  client = await ensure_api_client()
@@ -279,11 +294,11 @@ async def search_codebase(
279
294
 
280
295
  except APIError as e:
281
296
  logger.error(f"API Error searching codebase: {e} (status_code={e.status_code}, detail={e.detail})")
282
- if e.status_code == 403 or "free tier limit" in str(e).lower() or "free api requests" in str(e).lower():
283
- if e.detail and "5 free API requests" in e.detail:
297
+ if e.status_code == 403 or "free tier limit" in str(e).lower() or "indexing operations" in str(e).lower():
298
+ if e.detail and "3 free indexing operations" in e.detail:
284
299
  return [TextContent(
285
300
  type="text",
286
- text=f"❌ {e.detail}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited API access."
301
+ text=f"❌ {e.detail}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited indexing."
287
302
  )]
288
303
  else:
289
304
  return [TextContent(
@@ -295,10 +310,10 @@ async def search_codebase(
295
310
  except Exception as e:
296
311
  logger.error(f"Unexpected error searching codebase: {e}")
297
312
  error_msg = str(e)
298
- if "free api requests" in error_msg.lower() or "lifetime limit" in error_msg.lower():
313
+ if "indexing operations" in error_msg.lower() or "lifetime limit" in error_msg.lower():
299
314
  return [TextContent(
300
315
  type="text",
301
- text=f"❌ {error_msg}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited API access."
316
+ text=f"❌ {error_msg}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited indexing."
302
317
  )]
303
318
  return [TextContent(
304
319
  type="text",
@@ -419,7 +434,7 @@ async def search_documentation(
419
434
  logger.error(f"API Error searching documentation: {e}")
420
435
  error_msg = f"❌ {str(e)}"
421
436
  if e.status_code == 403 and "lifetime limit" in str(e).lower():
422
- error_msg += "\n\n💡 Tip: You've reached the free tier limit of 5 API requests. Upgrade to Pro for unlimited access."
437
+ error_msg += "\n\n💡 Tip: You've reached the free tier limit of 3 indexing operations. Upgrade to Pro for unlimited access."
423
438
  return [TextContent(type="text", text=error_msg)]
424
439
  except Exception as e:
425
440
  logger.error(f"Error searching documentation: {e}")
@@ -451,6 +466,9 @@ async def list_repositories() -> List[TextContent]:
451
466
  # Format repository list
452
467
  lines = ["# Indexed Repositories\n"]
453
468
 
469
+ # Check if any repositories have folder paths (contain /tree/)
470
+ has_folder_repos = any('/tree/' in repo.get('repository', '') for repo in repositories)
471
+
454
472
  for repo in repositories:
455
473
  status_icon = "✅" if repo.get("status") == "completed" else "⏳"
456
474
 
@@ -470,18 +488,36 @@ async def list_repositories() -> List[TextContent]:
470
488
  lines.append(f"- **Indexed:** {repo['indexed_at']}")
471
489
  if repo.get("error"):
472
490
  lines.append(f"- **Error:** {repo['error']}")
491
+
492
+ # Add usage hint for completed repositories
493
+ if repo.get("status") == "completed":
494
+ lines.append(f"- **Usage:** `search_codebase(query, [\"{repo_name}\"])`")
495
+
496
+ # Add general usage instructions at the end
497
+ lines.extend([
498
+ "\n---",
499
+ "\n## Usage Tips",
500
+ "- To search all repositories: `search_codebase(\"your query\")`",
501
+ "- To search specific repository: `search_codebase(\"your query\", [\"owner/repo\"])`"
502
+ ])
503
+
504
+ if has_folder_repos:
505
+ lines.extend([
506
+ "- For folder-indexed repositories: Use the EXACT repository path shown above",
507
+ " Example: `search_codebase(\"query\", [\"owner/repo/tree/branch/folder\"])`"
508
+ ])
473
509
 
474
510
  return [TextContent(type="text", text="\n".join(lines))]
475
511
 
476
512
  except APIError as e:
477
513
  logger.error(f"API Error listing repositories: {e} (status_code={e.status_code}, detail={e.detail})")
478
514
  # Check for free tier limit errors
479
- if e.status_code == 403 or "free tier limit" in str(e).lower() or "free api requests" in str(e).lower():
515
+ if e.status_code == 403 or "free tier limit" in str(e).lower() or "indexing operations" in str(e).lower():
480
516
  # Extract the specific limit message
481
- if e.detail and "5 free API requests" in e.detail:
517
+ if e.detail and "3 free indexing operations" in e.detail:
482
518
  return [TextContent(
483
519
  type="text",
484
- text=f"❌ {e.detail}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited API access."
520
+ text=f"❌ {e.detail}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited indexing."
485
521
  )]
486
522
  else:
487
523
  return [TextContent(
@@ -494,10 +530,10 @@ async def list_repositories() -> List[TextContent]:
494
530
  logger.error(f"Unexpected error listing repositories (type={type(e).__name__}): {e}")
495
531
  # Check if this looks like an API limit error that wasn't caught properly
496
532
  error_msg = str(e)
497
- if "free api requests" in error_msg.lower() or "lifetime limit" in error_msg.lower():
533
+ if "indexing operations" in error_msg.lower() or "lifetime limit" in error_msg.lower():
498
534
  return [TextContent(
499
535
  type="text",
500
- text=f"❌ {error_msg}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited API access."
536
+ text=f"❌ {error_msg}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited indexing."
501
537
  )]
502
538
  return [TextContent(
503
539
  type="text",
@@ -558,7 +594,7 @@ async def check_repository_status(repository: str) -> List[TextContent]:
558
594
  logger.error(f"API Error checking repository status: {e}")
559
595
  error_msg = f"❌ {str(e)}"
560
596
  if e.status_code == 403 and "lifetime limit" in str(e).lower():
561
- error_msg += "\n\n💡 Tip: You've reached the free tier limit of 5 API requests. Upgrade to Pro for unlimited access."
597
+ error_msg += "\n\n💡 Tip: You've reached the free tier limit of 3 indexing operations. Upgrade to Pro for unlimited access."
562
598
  return [TextContent(type="text", text=error_msg)]
563
599
  except Exception as e:
564
600
  logger.error(f"Error checking repository status: {e}")
@@ -603,7 +639,8 @@ async def index_documentation(
603
639
  - When started indexing, prompt users to either use check_documentation_status tool or go to app.trynia.ai to check the status.
604
640
  - By default, crawls the entire domain (up to 10,000 pages)
605
641
  - Use exclude_patterns to filter out unwanted sections like blogs, changelogs, etc.
606
- - Screenshots are captured by default to provide visual context
642
+ - If you want to search a specific folder, use the EXACT repository path shown above
643
+ - Example: `search_codebase(\"query\", [\"owner/repo/tree/branch/folder\"])`
607
644
  """
608
645
  try:
609
646
  client = await ensure_api_client()
@@ -645,7 +682,7 @@ async def index_documentation(
645
682
  logger.error(f"API Error indexing documentation: {e}")
646
683
  error_msg = f"❌ {str(e)}"
647
684
  if e.status_code == 403 and "lifetime limit" in str(e).lower():
648
- error_msg += "\n\n💡 Tip: You've reached the free tier limit of 5 API requests. Upgrade to Pro for unlimited access."
685
+ error_msg += "\n\n💡 Tip: You've reached the free tier limit of 3 indexing operations. Upgrade to Pro for unlimited access."
649
686
  return [TextContent(type="text", text=error_msg)]
650
687
  except Exception as e:
651
688
  logger.error(f"Error indexing documentation: {e}")
@@ -704,7 +741,7 @@ async def list_documentation() -> List[TextContent]:
704
741
  logger.error(f"API Error listing documentation: {e}")
705
742
  error_msg = f"❌ {str(e)}"
706
743
  if e.status_code == 403 and "lifetime limit" in str(e).lower():
707
- error_msg += "\n\n💡 Tip: You've reached the free tier limit of 5 API requests. Upgrade to Pro for unlimited access."
744
+ error_msg += "\n\n💡 Tip: You've reached the free tier limit of 3 indexing operations. Upgrade to Pro for unlimited access."
708
745
  return [TextContent(type="text", text=error_msg)]
709
746
  except Exception as e:
710
747
  logger.error(f"Error listing documentation: {e}")
@@ -770,7 +807,7 @@ async def check_documentation_status(source_id: str) -> List[TextContent]:
770
807
  logger.error(f"API Error checking documentation status: {e}")
771
808
  error_msg = f"❌ {str(e)}"
772
809
  if e.status_code == 403 and "lifetime limit" in str(e).lower():
773
- error_msg += "\n\n💡 Tip: You've reached the free tier limit of 5 API requests. Upgrade to Pro for unlimited access."
810
+ error_msg += "\n\n💡 Tip: You've reached the free tier limit of 3 indexing operations. Upgrade to Pro for unlimited access."
774
811
  return [TextContent(type="text", text=error_msg)]
775
812
  except Exception as e:
776
813
  logger.error(f"Error checking documentation status: {e}")
@@ -809,7 +846,7 @@ async def delete_documentation(source_id: str) -> List[TextContent]:
809
846
  logger.error(f"API Error deleting documentation: {e}")
810
847
  error_msg = f"❌ {str(e)}"
811
848
  if e.status_code == 403 and "lifetime limit" in str(e).lower():
812
- error_msg += "\n\n💡 Tip: You've reached the free tier limit of 5 API requests. Upgrade to Pro for unlimited access."
849
+ error_msg += "\n\n💡 Tip: You've reached the free tier limit of 3 indexing operations. Upgrade to Pro for unlimited access."
813
850
  return [TextContent(type="text", text=error_msg)]
814
851
  except Exception as e:
815
852
  logger.error(f"Error deleting documentation: {e}")
@@ -848,7 +885,7 @@ async def delete_repository(repository: str) -> List[TextContent]:
848
885
  logger.error(f"API Error deleting repository: {e}")
849
886
  error_msg = f"❌ {str(e)}"
850
887
  if e.status_code == 403 and "lifetime limit" in str(e).lower():
851
- error_msg += "\n\n💡 Tip: You've reached the free tier limit of 5 API requests. Upgrade to Pro for unlimited access."
888
+ error_msg += "\n\n💡 Tip: You've reached the free tier limit of 3 indexing operations. Upgrade to Pro for unlimited access."
852
889
  return [TextContent(type="text", text=error_msg)]
853
890
  except Exception as e:
854
891
  logger.error(f"Error deleting repository: {e}")
@@ -1099,11 +1136,11 @@ async def nia_web_search(
1099
1136
 
1100
1137
  except APIError as e:
1101
1138
  logger.error(f"API Error in web search: {e}")
1102
- if e.status_code == 403 or "free tier limit" in str(e).lower() or "free api requests" in str(e).lower():
1103
- if e.detail and "5 free API requests" in e.detail:
1139
+ if e.status_code == 403 or "free tier limit" in str(e).lower() or "indexing operations" in str(e).lower():
1140
+ if e.detail and "3 free indexing operations" in e.detail:
1104
1141
  return [TextContent(
1105
1142
  type="text",
1106
- text=f"❌ {e.detail}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited API access."
1143
+ text=f"❌ {e.detail}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited indexing."
1107
1144
  )]
1108
1145
  else:
1109
1146
  return [TextContent(
@@ -1278,11 +1315,11 @@ async def nia_deep_research_agent(
1278
1315
 
1279
1316
  except APIError as e:
1280
1317
  logger.error(f"API Error in deep research: {e}")
1281
- if e.status_code == 403 or "free tier limit" in str(e).lower() or "free api requests" in str(e).lower():
1282
- if e.detail and "5 free API requests" in e.detail:
1318
+ if e.status_code == 403 or "free tier limit" in str(e).lower() or "indexing operations" in str(e).lower():
1319
+ if e.detail and "3 free indexing operations" in e.detail:
1283
1320
  return [TextContent(
1284
1321
  type="text",
1285
- text=f"❌ {e.detail}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited API access."
1322
+ text=f"❌ {e.detail}\n\n💡 Tip: Upgrade to Pro at https://trynia.ai/billing for unlimited indexing."
1286
1323
  )]
1287
1324
  else:
1288
1325
  return [TextContent(
File without changes