code-puppy 0.0.127__py3-none-any.whl → 0.0.129__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.
Files changed (35) hide show
  1. code_puppy/__init__.py +1 -0
  2. code_puppy/agent.py +65 -69
  3. code_puppy/agents/agent_code_puppy.py +0 -3
  4. code_puppy/agents/runtime_manager.py +231 -0
  5. code_puppy/command_line/command_handler.py +56 -25
  6. code_puppy/command_line/mcp_commands.py +1298 -0
  7. code_puppy/command_line/meta_command_handler.py +3 -2
  8. code_puppy/command_line/model_picker_completion.py +21 -8
  9. code_puppy/http_utils.py +1 -1
  10. code_puppy/main.py +99 -158
  11. code_puppy/mcp/__init__.py +23 -0
  12. code_puppy/mcp/async_lifecycle.py +237 -0
  13. code_puppy/mcp/circuit_breaker.py +218 -0
  14. code_puppy/mcp/config_wizard.py +437 -0
  15. code_puppy/mcp/dashboard.py +291 -0
  16. code_puppy/mcp/error_isolation.py +360 -0
  17. code_puppy/mcp/examples/retry_example.py +208 -0
  18. code_puppy/mcp/health_monitor.py +549 -0
  19. code_puppy/mcp/managed_server.py +346 -0
  20. code_puppy/mcp/manager.py +701 -0
  21. code_puppy/mcp/registry.py +412 -0
  22. code_puppy/mcp/retry_manager.py +321 -0
  23. code_puppy/mcp/server_registry_catalog.py +751 -0
  24. code_puppy/mcp/status_tracker.py +355 -0
  25. code_puppy/messaging/spinner/textual_spinner.py +6 -2
  26. code_puppy/model_factory.py +19 -4
  27. code_puppy/models.json +8 -6
  28. code_puppy/tui/app.py +19 -27
  29. code_puppy/tui/tests/test_agent_command.py +22 -15
  30. {code_puppy-0.0.127.data → code_puppy-0.0.129.data}/data/code_puppy/models.json +8 -6
  31. {code_puppy-0.0.127.dist-info → code_puppy-0.0.129.dist-info}/METADATA +4 -3
  32. {code_puppy-0.0.127.dist-info → code_puppy-0.0.129.dist-info}/RECORD +35 -19
  33. {code_puppy-0.0.127.dist-info → code_puppy-0.0.129.dist-info}/WHEEL +0 -0
  34. {code_puppy-0.0.127.dist-info → code_puppy-0.0.129.dist-info}/entry_points.txt +0 -0
  35. {code_puppy-0.0.127.dist-info → code_puppy-0.0.129.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,751 @@
1
+ """
2
+ MCP Server Registry Catalog - Pre-configured MCP servers.
3
+ A curated collection of MCP servers that can be easily searched and installed.
4
+ """
5
+
6
+ from typing import Dict, List, Optional
7
+ from dataclasses import dataclass, field
8
+
9
+ @dataclass
10
+ class MCPServerTemplate:
11
+ """Template for a pre-configured MCP server."""
12
+ id: str
13
+ name: str
14
+ display_name: str
15
+ description: str
16
+ category: str
17
+ tags: List[str]
18
+ type: str # "stdio", "http", "sse"
19
+ config: Dict
20
+ author: str = "Community"
21
+ verified: bool = False
22
+ popular: bool = False
23
+ requires: List[str] = field(default_factory=list) # Required tools/dependencies
24
+ example_usage: str = ""
25
+
26
+ def to_server_config(self, custom_name: Optional[str] = None) -> Dict:
27
+ """Convert template to server configuration."""
28
+ config = {
29
+ "name": custom_name or self.name,
30
+ "type": self.type,
31
+ **self.config
32
+ }
33
+ return config
34
+
35
+
36
+ # Pre-configured MCP Server Registry
37
+ MCP_SERVER_REGISTRY: List[MCPServerTemplate] = [
38
+
39
+ # ========== File System & Storage ==========
40
+ MCPServerTemplate(
41
+ id="filesystem",
42
+ name="filesystem",
43
+ display_name="Filesystem Access",
44
+ description="Read and write files in specified directories",
45
+ category="Storage",
46
+ tags=["files", "io", "read", "write", "directory"],
47
+ type="stdio",
48
+ config={
49
+ "command": "npx",
50
+ "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
51
+ "timeout": 30
52
+ },
53
+ verified=True,
54
+ popular=True,
55
+ requires=["node", "npm"],
56
+ example_usage="Access and modify files in /tmp directory"
57
+ ),
58
+
59
+ MCPServerTemplate(
60
+ id="filesystem-home",
61
+ name="filesystem-home",
62
+ display_name="Home Directory Access",
63
+ description="Read and write files in user's home directory",
64
+ category="Storage",
65
+ tags=["files", "home", "user", "personal"],
66
+ type="stdio",
67
+ config={
68
+ "command": "npx",
69
+ "args": ["-y", "@modelcontextprotocol/server-filesystem", "~"],
70
+ "timeout": 30
71
+ },
72
+ verified=True,
73
+ requires=["node", "npm"]
74
+ ),
75
+
76
+ MCPServerTemplate(
77
+ id="gdrive",
78
+ name="gdrive",
79
+ display_name="Google Drive",
80
+ description="Access and manage Google Drive files",
81
+ category="Storage",
82
+ tags=["google", "drive", "cloud", "storage", "sync"],
83
+ type="stdio",
84
+ config={
85
+ "command": "npx",
86
+ "args": ["-y", "@modelcontextprotocol/server-gdrive"],
87
+ "timeout": 30
88
+ },
89
+ verified=True,
90
+ popular=True,
91
+ requires=["node", "npm", "google-auth"]
92
+ ),
93
+
94
+ # ========== Databases ==========
95
+ MCPServerTemplate(
96
+ id="postgres",
97
+ name="postgres",
98
+ display_name="PostgreSQL Database",
99
+ description="Connect to and query PostgreSQL databases",
100
+ category="Database",
101
+ tags=["database", "sql", "postgres", "postgresql", "query"],
102
+ type="stdio",
103
+ config={
104
+ "command": "npx",
105
+ "args": ["-y", "@modelcontextprotocol/server-postgres", "postgresql://localhost/mydb"],
106
+ "timeout": 30
107
+ },
108
+ verified=True,
109
+ popular=True,
110
+ requires=["node", "npm", "postgresql"],
111
+ example_usage="postgresql://user:password@localhost:5432/dbname"
112
+ ),
113
+
114
+ MCPServerTemplate(
115
+ id="sqlite",
116
+ name="sqlite",
117
+ display_name="SQLite Database",
118
+ description="Connect to and query SQLite databases",
119
+ category="Database",
120
+ tags=["database", "sql", "sqlite", "local", "embedded"],
121
+ type="stdio",
122
+ config={
123
+ "command": "npx",
124
+ "args": ["-y", "@modelcontextprotocol/server-sqlite", "path/to/database.db"],
125
+ "timeout": 30
126
+ },
127
+ verified=True,
128
+ popular=True,
129
+ requires=["node", "npm"]
130
+ ),
131
+
132
+ MCPServerTemplate(
133
+ id="mysql",
134
+ name="mysql",
135
+ display_name="MySQL Database",
136
+ description="Connect to and query MySQL databases",
137
+ category="Database",
138
+ tags=["database", "sql", "mysql", "mariadb", "query"],
139
+ type="stdio",
140
+ config={
141
+ "command": "npx",
142
+ "args": ["-y", "@modelcontextprotocol/server-mysql", "mysql://localhost/mydb"],
143
+ "timeout": 30
144
+ },
145
+ verified=True,
146
+ requires=["node", "npm", "mysql"]
147
+ ),
148
+
149
+ MCPServerTemplate(
150
+ id="mongodb",
151
+ name="mongodb",
152
+ display_name="MongoDB Database",
153
+ description="Connect to and query MongoDB databases",
154
+ category="Database",
155
+ tags=["database", "nosql", "mongodb", "document", "query"],
156
+ type="stdio",
157
+ config={
158
+ "command": "npx",
159
+ "args": ["-y", "@modelcontextprotocol/server-mongodb", "mongodb://localhost:27017/mydb"],
160
+ "timeout": 30
161
+ },
162
+ verified=True,
163
+ requires=["node", "npm", "mongodb"]
164
+ ),
165
+
166
+ # ========== Development Tools ==========
167
+ MCPServerTemplate(
168
+ id="git",
169
+ name="git",
170
+ display_name="Git Repository",
171
+ description="Manage Git repositories and perform version control operations",
172
+ category="Development",
173
+ tags=["git", "version-control", "repository", "commit", "branch"],
174
+ type="stdio",
175
+ config={
176
+ "command": "npx",
177
+ "args": ["-y", "@modelcontextprotocol/server-git"],
178
+ "timeout": 30
179
+ },
180
+ verified=True,
181
+ popular=True,
182
+ requires=["node", "npm", "git"]
183
+ ),
184
+
185
+ MCPServerTemplate(
186
+ id="github",
187
+ name="github",
188
+ display_name="GitHub API",
189
+ description="Access GitHub repositories, issues, PRs, and more",
190
+ category="Development",
191
+ tags=["github", "api", "repository", "issues", "pull-requests"],
192
+ type="stdio",
193
+ config={
194
+ "command": "npx",
195
+ "args": ["-y", "@modelcontextprotocol/server-github"],
196
+ "env": {"GITHUB_TOKEN": "$GITHUB_TOKEN"},
197
+ "timeout": 30
198
+ },
199
+ verified=True,
200
+ popular=True,
201
+ requires=["node", "npm", "github-token"]
202
+ ),
203
+
204
+ MCPServerTemplate(
205
+ id="gitlab",
206
+ name="gitlab",
207
+ display_name="GitLab API",
208
+ description="Access GitLab repositories, issues, and merge requests",
209
+ category="Development",
210
+ tags=["gitlab", "api", "repository", "issues", "merge-requests"],
211
+ type="stdio",
212
+ config={
213
+ "command": "npx",
214
+ "args": ["-y", "@modelcontextprotocol/server-gitlab"],
215
+ "env": {"GITLAB_TOKEN": "$GITLAB_TOKEN"},
216
+ "timeout": 30
217
+ },
218
+ verified=True,
219
+ requires=["node", "npm", "gitlab-token"]
220
+ ),
221
+
222
+ # ========== Web & Browser ==========
223
+ MCPServerTemplate(
224
+ id="puppeteer",
225
+ name="puppeteer",
226
+ display_name="Puppeteer Browser",
227
+ description="Control headless Chrome for web scraping and automation",
228
+ category="Web",
229
+ tags=["browser", "web", "scraping", "automation", "chrome", "puppeteer"],
230
+ type="stdio",
231
+ config={
232
+ "command": "npx",
233
+ "args": ["-y", "@modelcontextprotocol/server-puppeteer"],
234
+ "timeout": 60
235
+ },
236
+ verified=True,
237
+ popular=True,
238
+ requires=["node", "npm", "chrome"]
239
+ ),
240
+
241
+ MCPServerTemplate(
242
+ id="playwright",
243
+ name="playwright",
244
+ display_name="Playwright Browser",
245
+ description="Cross-browser automation for web testing and scraping",
246
+ category="Web",
247
+ tags=["browser", "web", "testing", "automation", "playwright"],
248
+ type="stdio",
249
+ config={
250
+ "command": "npx",
251
+ "args": ["-y", "@modelcontextprotocol/server-playwright"],
252
+ "timeout": 60
253
+ },
254
+ verified=True,
255
+ requires=["node", "npm"]
256
+ ),
257
+
258
+ MCPServerTemplate(
259
+ id="fetch",
260
+ name="fetch",
261
+ display_name="Web Fetch",
262
+ description="Fetch and process web pages and APIs",
263
+ category="Web",
264
+ tags=["web", "http", "api", "fetch", "request"],
265
+ type="stdio",
266
+ config={
267
+ "command": "npx",
268
+ "args": ["-y", "@modelcontextprotocol/server-fetch"],
269
+ "timeout": 30
270
+ },
271
+ verified=True,
272
+ requires=["node", "npm"]
273
+ ),
274
+
275
+ # ========== Communication ==========
276
+ MCPServerTemplate(
277
+ id="slack",
278
+ name="slack",
279
+ display_name="Slack Integration",
280
+ description="Send messages and interact with Slack workspaces",
281
+ category="Communication",
282
+ tags=["slack", "chat", "messaging", "notification"],
283
+ type="stdio",
284
+ config={
285
+ "command": "npx",
286
+ "args": ["-y", "@modelcontextprotocol/server-slack"],
287
+ "env": {"SLACK_TOKEN": "$SLACK_TOKEN"},
288
+ "timeout": 30
289
+ },
290
+ verified=True,
291
+ popular=True,
292
+ requires=["node", "npm", "slack-token"]
293
+ ),
294
+
295
+ MCPServerTemplate(
296
+ id="discord",
297
+ name="discord",
298
+ display_name="Discord Bot",
299
+ description="Interact with Discord servers and channels",
300
+ category="Communication",
301
+ tags=["discord", "chat", "bot", "messaging"],
302
+ type="stdio",
303
+ config={
304
+ "command": "npx",
305
+ "args": ["-y", "@modelcontextprotocol/server-discord"],
306
+ "env": {"DISCORD_TOKEN": "$DISCORD_TOKEN"},
307
+ "timeout": 30
308
+ },
309
+ verified=True,
310
+ requires=["node", "npm", "discord-token"]
311
+ ),
312
+
313
+ MCPServerTemplate(
314
+ id="email",
315
+ name="email",
316
+ display_name="Email (SMTP/IMAP)",
317
+ description="Send and receive emails",
318
+ category="Communication",
319
+ tags=["email", "smtp", "imap", "mail"],
320
+ type="stdio",
321
+ config={
322
+ "command": "npx",
323
+ "args": ["-y", "@modelcontextprotocol/server-email"],
324
+ "timeout": 30
325
+ },
326
+ verified=True,
327
+ requires=["node", "npm"]
328
+ ),
329
+
330
+ # ========== AI & Machine Learning ==========
331
+ MCPServerTemplate(
332
+ id="openai",
333
+ name="openai",
334
+ display_name="OpenAI API",
335
+ description="Access OpenAI models for text, image, and embedding generation",
336
+ category="AI",
337
+ tags=["ai", "openai", "gpt", "dalle", "embedding"],
338
+ type="stdio",
339
+ config={
340
+ "command": "npx",
341
+ "args": ["-y", "@modelcontextprotocol/server-openai"],
342
+ "env": {"OPENAI_API_KEY": "$OPENAI_API_KEY"},
343
+ "timeout": 60
344
+ },
345
+ verified=True,
346
+ popular=True,
347
+ requires=["node", "npm", "openai-api-key"]
348
+ ),
349
+
350
+ MCPServerTemplate(
351
+ id="anthropic",
352
+ name="anthropic",
353
+ display_name="Anthropic Claude API",
354
+ description="Access Anthropic's Claude models",
355
+ category="AI",
356
+ tags=["ai", "anthropic", "claude", "llm"],
357
+ type="stdio",
358
+ config={
359
+ "command": "npx",
360
+ "args": ["-y", "@modelcontextprotocol/server-anthropic"],
361
+ "env": {"ANTHROPIC_API_KEY": "$ANTHROPIC_API_KEY"},
362
+ "timeout": 60
363
+ },
364
+ verified=True,
365
+ requires=["node", "npm", "anthropic-api-key"]
366
+ ),
367
+
368
+ # ========== Data Processing ==========
369
+ MCPServerTemplate(
370
+ id="pandas",
371
+ name="pandas",
372
+ display_name="Pandas Data Analysis",
373
+ description="Process and analyze data using Python pandas",
374
+ category="Data",
375
+ tags=["data", "pandas", "python", "analysis", "csv", "dataframe"],
376
+ type="stdio",
377
+ config={
378
+ "command": "python",
379
+ "args": ["-m", "mcp_server_pandas"],
380
+ "timeout": 30
381
+ },
382
+ verified=True,
383
+ popular=True,
384
+ requires=["python", "pandas", "mcp-server-pandas"]
385
+ ),
386
+
387
+ MCPServerTemplate(
388
+ id="jupyter",
389
+ name="jupyter",
390
+ display_name="Jupyter Notebook",
391
+ description="Execute code in Jupyter notebooks",
392
+ category="Data",
393
+ tags=["jupyter", "notebook", "python", "data-science"],
394
+ type="stdio",
395
+ config={
396
+ "command": "python",
397
+ "args": ["-m", "mcp_server_jupyter"],
398
+ "timeout": 60
399
+ },
400
+ verified=True,
401
+ requires=["python", "jupyter", "mcp-server-jupyter"]
402
+ ),
403
+
404
+ # ========== Cloud Services ==========
405
+ MCPServerTemplate(
406
+ id="aws-s3",
407
+ name="aws-s3",
408
+ display_name="AWS S3 Storage",
409
+ description="Manage AWS S3 buckets and objects",
410
+ category="Cloud",
411
+ tags=["aws", "s3", "storage", "cloud", "bucket"],
412
+ type="stdio",
413
+ config={
414
+ "command": "npx",
415
+ "args": ["-y", "@modelcontextprotocol/server-aws-s3"],
416
+ "env": {
417
+ "AWS_ACCESS_KEY_ID": "$AWS_ACCESS_KEY_ID",
418
+ "AWS_SECRET_ACCESS_KEY": "$AWS_SECRET_ACCESS_KEY"
419
+ },
420
+ "timeout": 30
421
+ },
422
+ verified=True,
423
+ popular=True,
424
+ requires=["node", "npm", "aws-credentials"]
425
+ ),
426
+
427
+ MCPServerTemplate(
428
+ id="azure-storage",
429
+ name="azure-storage",
430
+ display_name="Azure Storage",
431
+ description="Manage Azure blob storage",
432
+ category="Cloud",
433
+ tags=["azure", "storage", "cloud", "blob"],
434
+ type="stdio",
435
+ config={
436
+ "command": "npx",
437
+ "args": ["-y", "@modelcontextprotocol/server-azure-storage"],
438
+ "env": {"AZURE_STORAGE_CONNECTION_STRING": "$AZURE_STORAGE_CONNECTION_STRING"},
439
+ "timeout": 30
440
+ },
441
+ verified=True,
442
+ requires=["node", "npm", "azure-credentials"]
443
+ ),
444
+
445
+ # ========== Security & Authentication ==========
446
+ MCPServerTemplate(
447
+ id="1password",
448
+ name="1password",
449
+ display_name="1Password Vault",
450
+ description="Access 1Password vaults securely",
451
+ category="Security",
452
+ tags=["security", "password", "vault", "1password", "secrets"],
453
+ type="stdio",
454
+ config={
455
+ "command": "op",
456
+ "args": ["mcp-server"],
457
+ "timeout": 30
458
+ },
459
+ verified=True,
460
+ requires=["1password-cli"]
461
+ ),
462
+
463
+ MCPServerTemplate(
464
+ id="vault",
465
+ name="vault",
466
+ display_name="HashiCorp Vault",
467
+ description="Manage secrets in HashiCorp Vault",
468
+ category="Security",
469
+ tags=["security", "vault", "secrets", "hashicorp"],
470
+ type="stdio",
471
+ config={
472
+ "command": "npx",
473
+ "args": ["-y", "@modelcontextprotocol/server-vault"],
474
+ "env": {"VAULT_TOKEN": "$VAULT_TOKEN"},
475
+ "timeout": 30
476
+ },
477
+ verified=True,
478
+ requires=["node", "npm", "vault-token"]
479
+ ),
480
+
481
+ # ========== Documentation & Knowledge ==========
482
+ MCPServerTemplate(
483
+ id="context7",
484
+ name="context7",
485
+ display_name="Context7 Documentation Search",
486
+ description="Search and retrieve documentation from multiple sources with AI-powered context understanding",
487
+ category="Documentation",
488
+ tags=["documentation", "search", "context", "ai", "knowledge", "docs", "cloud"],
489
+ type="stdio",
490
+ config={
491
+ "timeout": 30,
492
+ "command": "npx",
493
+ "args": ["-y", "@upstash/context7-mcp","--api-key", "ctx7sk-c884daad-4169-47ca-b44a-bd30ba77c4db"]
494
+ },
495
+ verified=True,
496
+ popular=True,
497
+ requires=[],
498
+ example_usage="Cloud-based service - no local setup required"
499
+ ),
500
+
501
+ MCPServerTemplate(
502
+ id="confluence",
503
+ name="confluence",
504
+ display_name="Confluence Wiki",
505
+ description="Access and manage Confluence pages",
506
+ category="Documentation",
507
+ tags=["wiki", "confluence", "documentation", "atlassian"],
508
+ type="stdio",
509
+ config={
510
+ "command": "npx",
511
+ "args": ["-y", "@modelcontextprotocol/server-confluence"],
512
+ "env": {"CONFLUENCE_TOKEN": "$CONFLUENCE_TOKEN"},
513
+ "timeout": 30
514
+ },
515
+ verified=True,
516
+ requires=["node", "npm", "confluence-token"]
517
+ ),
518
+
519
+ MCPServerTemplate(
520
+ id="notion",
521
+ name="notion",
522
+ display_name="Notion Workspace",
523
+ description="Access and manage Notion pages and databases",
524
+ category="Documentation",
525
+ tags=["notion", "wiki", "documentation", "database"],
526
+ type="stdio",
527
+ config={
528
+ "command": "npx",
529
+ "args": ["-y", "@modelcontextprotocol/server-notion"],
530
+ "env": {"NOTION_TOKEN": "$NOTION_TOKEN"},
531
+ "timeout": 30
532
+ },
533
+ verified=True,
534
+ popular=True,
535
+ requires=["node", "npm", "notion-token"]
536
+ ),
537
+
538
+ # ========== DevOps & Infrastructure ==========
539
+ MCPServerTemplate(
540
+ id="docker",
541
+ name="docker",
542
+ display_name="Docker Management",
543
+ description="Manage Docker containers and images",
544
+ category="DevOps",
545
+ tags=["docker", "container", "devops", "infrastructure"],
546
+ type="stdio",
547
+ config={
548
+ "command": "npx",
549
+ "args": ["-y", "@modelcontextprotocol/server-docker"],
550
+ "timeout": 30
551
+ },
552
+ verified=True,
553
+ popular=True,
554
+ requires=["node", "npm", "docker"]
555
+ ),
556
+
557
+ MCPServerTemplate(
558
+ id="kubernetes",
559
+ name="kubernetes",
560
+ display_name="Kubernetes Cluster",
561
+ description="Manage Kubernetes resources",
562
+ category="DevOps",
563
+ tags=["kubernetes", "k8s", "container", "orchestration"],
564
+ type="stdio",
565
+ config={
566
+ "command": "npx",
567
+ "args": ["-y", "@modelcontextprotocol/server-kubernetes"],
568
+ "timeout": 30
569
+ },
570
+ verified=True,
571
+ requires=["node", "npm", "kubectl"]
572
+ ),
573
+
574
+ MCPServerTemplate(
575
+ id="terraform",
576
+ name="terraform",
577
+ display_name="Terraform Infrastructure",
578
+ description="Manage infrastructure as code with Terraform",
579
+ category="DevOps",
580
+ tags=["terraform", "iac", "infrastructure", "devops"],
581
+ type="stdio",
582
+ config={
583
+ "command": "npx",
584
+ "args": ["-y", "@modelcontextprotocol/server-terraform"],
585
+ "timeout": 60
586
+ },
587
+ verified=True,
588
+ requires=["node", "npm", "terraform"]
589
+ ),
590
+
591
+ # ========== Monitoring & Observability ==========
592
+ MCPServerTemplate(
593
+ id="prometheus",
594
+ name="prometheus",
595
+ display_name="Prometheus Metrics",
596
+ description="Query Prometheus metrics",
597
+ category="Monitoring",
598
+ tags=["monitoring", "metrics", "prometheus", "observability"],
599
+ type="stdio",
600
+ config={
601
+ "command": "npx",
602
+ "args": ["-y", "@modelcontextprotocol/server-prometheus", "http://localhost:9090"],
603
+ "timeout": 30
604
+ },
605
+ verified=True,
606
+ requires=["node", "npm"]
607
+ ),
608
+
609
+ MCPServerTemplate(
610
+ id="grafana",
611
+ name="grafana",
612
+ display_name="Grafana Dashboards",
613
+ description="Access Grafana dashboards and alerts",
614
+ category="Monitoring",
615
+ tags=["monitoring", "dashboard", "grafana", "visualization"],
616
+ type="stdio",
617
+ config={
618
+ "command": "npx",
619
+ "args": ["-y", "@modelcontextprotocol/server-grafana"],
620
+ "env": {"GRAFANA_TOKEN": "$GRAFANA_TOKEN"},
621
+ "timeout": 30
622
+ },
623
+ verified=True,
624
+ requires=["node", "npm", "grafana-token"]
625
+ ),
626
+
627
+ # ========== Package Management ==========
628
+ MCPServerTemplate(
629
+ id="npm",
630
+ name="npm",
631
+ display_name="NPM Package Manager",
632
+ description="Search and manage NPM packages",
633
+ category="Package Management",
634
+ tags=["npm", "node", "package", "javascript"],
635
+ type="stdio",
636
+ config={
637
+ "command": "npx",
638
+ "args": ["-y", "@modelcontextprotocol/server-npm"],
639
+ "timeout": 30
640
+ },
641
+ verified=True,
642
+ requires=["node", "npm"]
643
+ ),
644
+
645
+ MCPServerTemplate(
646
+ id="pypi",
647
+ name="pypi",
648
+ display_name="PyPI Package Manager",
649
+ description="Search and manage Python packages",
650
+ category="Package Management",
651
+ tags=["python", "pip", "pypi", "package"],
652
+ type="stdio",
653
+ config={
654
+ "command": "python",
655
+ "args": ["-m", "mcp_server_pypi"],
656
+ "timeout": 30
657
+ },
658
+ verified=True,
659
+ requires=["python", "mcp-server-pypi"]
660
+ ),
661
+ ]
662
+
663
+
664
+ class MCPServerCatalog:
665
+ """Catalog for searching and managing pre-configured MCP servers."""
666
+
667
+ def __init__(self):
668
+ self.servers = MCP_SERVER_REGISTRY
669
+ self._build_index()
670
+
671
+ def _build_index(self):
672
+ """Build search index for fast lookups."""
673
+ self.by_id = {s.id: s for s in self.servers}
674
+ self.by_category = {}
675
+ for server in self.servers:
676
+ if server.category not in self.by_category:
677
+ self.by_category[server.category] = []
678
+ self.by_category[server.category].append(server)
679
+
680
+ def search(self, query: str) -> List[MCPServerTemplate]:
681
+ """
682
+ Search for servers by name, description, or tags.
683
+
684
+ Args:
685
+ query: Search query string
686
+
687
+ Returns:
688
+ List of matching server templates
689
+ """
690
+ query_lower = query.lower()
691
+ results = []
692
+
693
+ for server in self.servers:
694
+ # Check name
695
+ if query_lower in server.name.lower():
696
+ results.append(server)
697
+ continue
698
+
699
+ # Check display name
700
+ if query_lower in server.display_name.lower():
701
+ results.append(server)
702
+ continue
703
+
704
+ # Check description
705
+ if query_lower in server.description.lower():
706
+ results.append(server)
707
+ continue
708
+
709
+ # Check tags
710
+ for tag in server.tags:
711
+ if query_lower in tag.lower():
712
+ results.append(server)
713
+ break
714
+
715
+ # Check category
716
+ if query_lower in server.category.lower() and server not in results:
717
+ results.append(server)
718
+
719
+ # Sort by relevance (name matches first, then popular)
720
+ results.sort(key=lambda s: (
721
+ not s.name.lower().startswith(query_lower),
722
+ not s.popular,
723
+ s.name
724
+ ))
725
+
726
+ return results
727
+
728
+ def get_by_id(self, server_id: str) -> Optional[MCPServerTemplate]:
729
+ """Get server template by ID."""
730
+ return self.by_id.get(server_id)
731
+
732
+ def get_by_category(self, category: str) -> List[MCPServerTemplate]:
733
+ """Get all servers in a category."""
734
+ return self.by_category.get(category, [])
735
+
736
+ def list_categories(self) -> List[str]:
737
+ """List all available categories."""
738
+ return sorted(self.by_category.keys())
739
+
740
+ def get_popular(self, limit: int = 10) -> List[MCPServerTemplate]:
741
+ """Get popular servers."""
742
+ popular = [s for s in self.servers if s.popular]
743
+ return popular[:limit]
744
+
745
+ def get_verified(self) -> List[MCPServerTemplate]:
746
+ """Get all verified servers."""
747
+ return [s for s in self.servers if s.verified]
748
+
749
+
750
+ # Global catalog instance
751
+ catalog = MCPServerCatalog()