traia-iatp 0.1.2__py3-none-any.whl → 0.1.67__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.
- traia_iatp/__init__.py +105 -8
- traia_iatp/cli/main.py +85 -1
- traia_iatp/client/__init__.py +28 -3
- traia_iatp/client/crewai_a2a_tools.py +32 -12
- traia_iatp/client/d402_a2a_client.py +348 -0
- traia_iatp/contracts/__init__.py +11 -0
- traia_iatp/contracts/data/abis/contract-abis-localhost.json +4091 -0
- traia_iatp/contracts/data/abis/contract-abis-sepolia.json +4890 -0
- traia_iatp/contracts/data/addresses/contract-addresses.json +17 -0
- traia_iatp/contracts/data/addresses/contract-proxies.json +12 -0
- traia_iatp/contracts/iatp_contracts_config.py +263 -0
- traia_iatp/contracts/wallet_creator.py +369 -0
- traia_iatp/core/models.py +17 -3
- traia_iatp/d402/MIDDLEWARE_ARCHITECTURE.md +205 -0
- traia_iatp/d402/PRICE_BUILDER_USAGE.md +249 -0
- traia_iatp/d402/README.md +489 -0
- traia_iatp/d402/__init__.py +54 -0
- traia_iatp/d402/asgi_wrapper.py +469 -0
- traia_iatp/d402/chains.py +102 -0
- traia_iatp/d402/client.py +150 -0
- traia_iatp/d402/clients/__init__.py +7 -0
- traia_iatp/d402/clients/base.py +218 -0
- traia_iatp/d402/clients/httpx.py +266 -0
- traia_iatp/d402/common.py +114 -0
- traia_iatp/d402/encoding.py +28 -0
- traia_iatp/d402/examples/client_example.py +197 -0
- traia_iatp/d402/examples/server_example.py +171 -0
- traia_iatp/d402/facilitator.py +481 -0
- traia_iatp/d402/mcp_middleware.py +296 -0
- traia_iatp/d402/models.py +116 -0
- traia_iatp/d402/networks.py +98 -0
- traia_iatp/d402/path.py +43 -0
- traia_iatp/d402/payment_introspection.py +126 -0
- traia_iatp/d402/payment_signing.py +183 -0
- traia_iatp/d402/price_builder.py +164 -0
- traia_iatp/d402/servers/__init__.py +61 -0
- traia_iatp/d402/servers/base.py +139 -0
- traia_iatp/d402/servers/example_general_server.py +140 -0
- traia_iatp/d402/servers/fastapi.py +253 -0
- traia_iatp/d402/servers/mcp.py +304 -0
- traia_iatp/d402/servers/starlette.py +878 -0
- traia_iatp/d402/starlette_middleware.py +529 -0
- traia_iatp/d402/types.py +300 -0
- traia_iatp/mcp/D402_MCP_ADAPTER_FLOW.md +357 -0
- traia_iatp/mcp/__init__.py +3 -0
- traia_iatp/mcp/d402_mcp_tool_adapter.py +526 -0
- traia_iatp/mcp/mcp_agent_template.py +78 -13
- traia_iatp/mcp/templates/Dockerfile.j2 +27 -4
- traia_iatp/mcp/templates/README.md.j2 +104 -8
- traia_iatp/mcp/templates/cursor-rules.md.j2 +194 -0
- traia_iatp/mcp/templates/deployment_params.json.j2 +1 -2
- traia_iatp/mcp/templates/docker-compose.yml.j2 +13 -3
- traia_iatp/mcp/templates/env.example.j2 +60 -0
- traia_iatp/mcp/templates/mcp_health_check.py.j2 +2 -2
- traia_iatp/mcp/templates/pyproject.toml.j2 +11 -5
- traia_iatp/mcp/templates/pyrightconfig.json.j2 +22 -0
- traia_iatp/mcp/templates/run_local_docker.sh.j2 +320 -10
- traia_iatp/mcp/templates/server.py.j2 +174 -197
- traia_iatp/mcp/traia_mcp_adapter.py +182 -20
- traia_iatp/registry/__init__.py +47 -12
- traia_iatp/registry/atlas_search_indexes.json +108 -54
- traia_iatp/registry/iatp_search_api.py +169 -39
- traia_iatp/registry/mongodb_registry.py +241 -69
- traia_iatp/registry/readmes/EMBEDDINGS_SETUP.md +1 -1
- traia_iatp/registry/readmes/IATP_SEARCH_API_GUIDE.md +8 -8
- traia_iatp/registry/readmes/MONGODB_X509_AUTH.md +1 -1
- traia_iatp/registry/readmes/README.md +3 -3
- traia_iatp/registry/readmes/REFACTORING_SUMMARY.md +6 -6
- traia_iatp/scripts/__init__.py +2 -0
- traia_iatp/scripts/create_wallet.py +244 -0
- traia_iatp/server/a2a_server.py +22 -7
- traia_iatp/server/iatp_server_template_generator.py +23 -0
- traia_iatp/server/templates/.dockerignore.j2 +48 -0
- traia_iatp/server/templates/Dockerfile.j2 +23 -1
- traia_iatp/server/templates/README.md +2 -2
- traia_iatp/server/templates/README.md.j2 +5 -5
- traia_iatp/server/templates/__main__.py.j2 +374 -66
- traia_iatp/server/templates/agent.py.j2 +12 -11
- traia_iatp/server/templates/agent_config.json.j2 +3 -3
- traia_iatp/server/templates/agent_executor.py.j2 +45 -27
- traia_iatp/server/templates/env.example.j2 +32 -4
- traia_iatp/server/templates/gitignore.j2 +7 -0
- traia_iatp/server/templates/pyproject.toml.j2 +13 -12
- traia_iatp/server/templates/run_local_docker.sh.j2 +143 -11
- traia_iatp/server/templates/server.py.j2 +197 -10
- traia_iatp/special_agencies/registry_search_agency.py +1 -1
- traia_iatp/utils/iatp_utils.py +6 -6
- traia_iatp-0.1.67.dist-info/METADATA +320 -0
- traia_iatp-0.1.67.dist-info/RECORD +117 -0
- traia_iatp-0.1.2.dist-info/METADATA +0 -414
- traia_iatp-0.1.2.dist-info/RECORD +0 -72
- {traia_iatp-0.1.2.dist-info → traia_iatp-0.1.67.dist-info}/WHEEL +0 -0
- {traia_iatp-0.1.2.dist-info → traia_iatp-0.1.67.dist-info}/entry_points.txt +0 -0
- {traia_iatp-0.1.2.dist-info → traia_iatp-0.1.67.dist-info}/licenses/LICENSE +0 -0
- {traia_iatp-0.1.2.dist-info → traia_iatp-0.1.67.dist-info}/top_level.txt +0 -0
|
@@ -15,15 +15,23 @@ import logging
|
|
|
15
15
|
from pymongo import MongoClient
|
|
16
16
|
from pymongo import server_api
|
|
17
17
|
|
|
18
|
-
# Import for embeddings
|
|
19
|
-
from .embeddings import get_embedding_service
|
|
20
|
-
|
|
21
18
|
# Get environment variables
|
|
22
19
|
CLUSTER_URI = "traia-iatp-cluster.yzwjvgd.mongodb.net/?retryWrites=true&w=majority&appName=Traia-IATP-Cluster"
|
|
23
20
|
DATABASE_NAME = "iatp"
|
|
24
21
|
|
|
25
22
|
logger = logging.getLogger(__name__)
|
|
26
23
|
|
|
24
|
+
# Projection to exclude large embedding fields from query responses
|
|
25
|
+
# These fields are used internally for vector search but not needed by clients
|
|
26
|
+
MCP_PROJECTION_EXCLUDE_EMBEDDINGS = {
|
|
27
|
+
"description_embedding": 0,
|
|
28
|
+
"capabilities_embedding": 0
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
UTILITY_AGENT_PROJECTION_EXCLUDE_EMBEDDINGS = {
|
|
32
|
+
"embeddings": 0 # Excludes embeddings.description, embeddings.agent_card, embeddings.search_text
|
|
33
|
+
}
|
|
34
|
+
|
|
27
35
|
|
|
28
36
|
@dataclass
|
|
29
37
|
class MCPServerInfo:
|
|
@@ -36,10 +44,25 @@ class MCPServerInfo:
|
|
|
36
44
|
capabilities: List[str]
|
|
37
45
|
metadata: Dict[str, Any]
|
|
38
46
|
tags: List[str]
|
|
47
|
+
is_active: bool = False
|
|
48
|
+
core_tests_passed: bool = False
|
|
49
|
+
crewai_tests_passed: bool = False
|
|
50
|
+
user_uuid: Optional[str] = None
|
|
51
|
+
# Blockchain fields (from PostgreSQL, synced to MongoDB)
|
|
52
|
+
operator_address: Optional[str] = None
|
|
53
|
+
server_address: Optional[str] = None
|
|
54
|
+
server_network: Optional[str] = None
|
|
55
|
+
server_chain_id: Optional[int] = None
|
|
56
|
+
# Token acceptance information
|
|
57
|
+
accepts: Optional[Dict[str, Any]] = None
|
|
39
58
|
|
|
40
59
|
@classmethod
|
|
41
60
|
def from_registry_doc(cls, doc: Dict[str, Any]) -> 'MCPServerInfo':
|
|
42
|
-
"""Create MCPServerInfo from MongoDB document.
|
|
61
|
+
"""Create MCPServerInfo from MongoDB document.
|
|
62
|
+
|
|
63
|
+
Note: Embedding fields (description_embedding, capabilities_embedding)
|
|
64
|
+
should be excluded from queries via projection - they are not needed by clients.
|
|
65
|
+
"""
|
|
43
66
|
# Extract tags from metadata if present
|
|
44
67
|
metadata = doc.get('metadata', {})
|
|
45
68
|
tags = metadata.get('tags', [])
|
|
@@ -52,7 +75,18 @@ class MCPServerInfo:
|
|
|
52
75
|
server_type=doc.get('server_type', 'streamable-http'),
|
|
53
76
|
capabilities=doc.get('capabilities', []),
|
|
54
77
|
metadata=metadata,
|
|
55
|
-
tags=tags
|
|
78
|
+
tags=tags,
|
|
79
|
+
is_active=doc.get('is_active', False),
|
|
80
|
+
core_tests_passed=doc.get('core_tests_passed', False),
|
|
81
|
+
crewai_tests_passed=doc.get('crewai_tests_passed', False),
|
|
82
|
+
user_uuid=doc.get('user_uuid'),
|
|
83
|
+
# Blockchain fields
|
|
84
|
+
operator_address=doc.get('operator_address'),
|
|
85
|
+
server_address=doc.get('server_address'),
|
|
86
|
+
server_network=doc.get('server_network'),
|
|
87
|
+
server_chain_id=doc.get('server_chain_id'),
|
|
88
|
+
# Token acceptance
|
|
89
|
+
accepts=doc.get('accepts')
|
|
56
90
|
)
|
|
57
91
|
|
|
58
92
|
|
|
@@ -69,10 +103,18 @@ class UtilityAgentInfo:
|
|
|
69
103
|
metadata: Dict[str, Any]
|
|
70
104
|
skills: List[Dict[str, Any]]
|
|
71
105
|
endpoints: Optional[Dict[str, Any]] = None
|
|
106
|
+
# D402 payment fields
|
|
107
|
+
d402_enabled: bool = False
|
|
108
|
+
d402_payment_info: Optional[Dict[str, Any]] = None
|
|
72
109
|
|
|
73
110
|
@classmethod
|
|
74
111
|
def from_registry_doc(cls, doc: Dict[str, Any]) -> 'UtilityAgentInfo':
|
|
75
|
-
"""Create UtilityAgentInfo from MongoDB document.
|
|
112
|
+
"""Create UtilityAgentInfo from MongoDB document.
|
|
113
|
+
|
|
114
|
+
Note: The "embeddings" object (containing embeddings.description,
|
|
115
|
+
embeddings.agent_card, embeddings.search_text) should be excluded from
|
|
116
|
+
queries via projection - they are not needed by clients.
|
|
117
|
+
"""
|
|
76
118
|
return cls(
|
|
77
119
|
agent_id=doc.get('agent_id', ''),
|
|
78
120
|
name=doc.get('name', ''),
|
|
@@ -83,13 +125,21 @@ class UtilityAgentInfo:
|
|
|
83
125
|
is_active=doc.get('is_active', True),
|
|
84
126
|
metadata=doc.get('metadata', {}),
|
|
85
127
|
skills=doc.get('skills', []),
|
|
86
|
-
endpoints=doc.get('endpoints') # Get endpoints from root level
|
|
128
|
+
endpoints=doc.get('endpoints'), # Get endpoints from root level
|
|
129
|
+
d402_enabled=doc.get('d402_enabled', False),
|
|
130
|
+
d402_payment_info=doc.get('d402_payment_info')
|
|
87
131
|
)
|
|
88
132
|
|
|
89
133
|
|
|
90
134
|
def get_readonly_connection_string() -> str:
|
|
91
135
|
"""Get read-only MongoDB connection string."""
|
|
92
|
-
|
|
136
|
+
|
|
137
|
+
# Try IAM access
|
|
138
|
+
cluster_host_name = os.environ.get('CLUSTER_HOST_NAME', None)
|
|
139
|
+
if cluster_host_name:
|
|
140
|
+
return f"mongodb+srv://{cluster_host_name}/?authMechanism=MONGODB-AWS&authSource=%24external&retryWrites=true&w=majority&appName=Traia-IATP-Cluster"
|
|
141
|
+
|
|
142
|
+
# Try X.509 certificate authentication next
|
|
93
143
|
cert_file = os.getenv("MONGODB_X509_CERT_FILE")
|
|
94
144
|
if cert_file and os.path.exists(cert_file):
|
|
95
145
|
# Extract just the cluster hostname without query parameters
|
|
@@ -110,9 +160,10 @@ def get_readonly_connection_string() -> str:
|
|
|
110
160
|
|
|
111
161
|
raise ValueError(
|
|
112
162
|
"MongoDB authentication required. Please provide either:\n"
|
|
113
|
-
"1.
|
|
114
|
-
"2.
|
|
115
|
-
"3.
|
|
163
|
+
"1. MONGODB_IAM_ACCESS - Cluster Host Required\n"
|
|
164
|
+
"2. MONGODB_X509_CERT_FILE - Path to X.509 certificate file\n"
|
|
165
|
+
"3. MONGODB_USER and MONGODB_PASSWORD - Username and password\n"
|
|
166
|
+
"4. MONGODB_CONNECTION_STRING - Full connection string"
|
|
116
167
|
)
|
|
117
168
|
|
|
118
169
|
|
|
@@ -178,14 +229,20 @@ class IATPSearchAPI:
|
|
|
178
229
|
collection = db[collection_names["utility_agent"]]
|
|
179
230
|
|
|
180
231
|
if agent_id:
|
|
181
|
-
# Direct lookup by agent_id
|
|
182
|
-
doc = collection.find_one(
|
|
232
|
+
# Direct lookup by agent_id (exclude embeddings for performance)
|
|
233
|
+
doc = collection.find_one(
|
|
234
|
+
{"agent_id": agent_id, "is_active": True},
|
|
235
|
+
UTILITY_AGENT_PROJECTION_EXCLUDE_EMBEDDINGS
|
|
236
|
+
)
|
|
183
237
|
if doc:
|
|
184
238
|
return UtilityAgentInfo.from_registry_doc(doc)
|
|
185
239
|
|
|
186
240
|
if name:
|
|
187
|
-
# Direct lookup by name
|
|
188
|
-
doc = collection.find_one(
|
|
241
|
+
# Direct lookup by name (exclude embeddings for performance)
|
|
242
|
+
doc = collection.find_one(
|
|
243
|
+
{"name": name, "is_active": True},
|
|
244
|
+
UTILITY_AGENT_PROJECTION_EXCLUDE_EMBEDDINGS
|
|
245
|
+
)
|
|
189
246
|
if doc:
|
|
190
247
|
return UtilityAgentInfo.from_registry_doc(doc)
|
|
191
248
|
|
|
@@ -232,8 +289,8 @@ class IATPSearchAPI:
|
|
|
232
289
|
if tag:
|
|
233
290
|
filters["tags"] = tag
|
|
234
291
|
|
|
235
|
-
# Find first matching document
|
|
236
|
-
doc = collection.find_one(filters)
|
|
292
|
+
# Find first matching document (exclude embeddings for performance)
|
|
293
|
+
doc = collection.find_one(filters, UTILITY_AGENT_PROJECTION_EXCLUDE_EMBEDDINGS)
|
|
237
294
|
if doc:
|
|
238
295
|
return UtilityAgentInfo.from_registry_doc(doc)
|
|
239
296
|
|
|
@@ -272,8 +329,11 @@ class IATPSearchAPI:
|
|
|
272
329
|
if capabilities:
|
|
273
330
|
filters["capabilities"] = {"$in": capabilities}
|
|
274
331
|
|
|
275
|
-
# Query with limit
|
|
276
|
-
cursor = collection.find(
|
|
332
|
+
# Query with limit (exclude embeddings for performance)
|
|
333
|
+
cursor = collection.find(
|
|
334
|
+
filters,
|
|
335
|
+
UTILITY_AGENT_PROJECTION_EXCLUDE_EMBEDDINGS
|
|
336
|
+
).limit(limit).sort("registered_at", -1)
|
|
277
337
|
|
|
278
338
|
return [UtilityAgentInfo.from_registry_doc(doc) for doc in cursor]
|
|
279
339
|
|
|
@@ -298,8 +358,9 @@ class IATPSearchAPI:
|
|
|
298
358
|
Returns:
|
|
299
359
|
List of UtilityAgentInfo objects
|
|
300
360
|
"""
|
|
301
|
-
# Generate query embedding
|
|
361
|
+
# Generate query embedding (lazy import to avoid loading OpenAI/Cohere unless needed)
|
|
302
362
|
try:
|
|
363
|
+
from .embeddings import get_embedding_service
|
|
303
364
|
embedding_service = get_embedding_service()
|
|
304
365
|
query_embedding = await embedding_service.generate_query_embedding(query)
|
|
305
366
|
except Exception as e:
|
|
@@ -469,7 +530,7 @@ class IATPSearchAPI:
|
|
|
469
530
|
|
|
470
531
|
if name:
|
|
471
532
|
# Direct lookup by name
|
|
472
|
-
doc = collection.find_one({"name": name, "is_active": True})
|
|
533
|
+
doc = collection.find_one({"name": name, "is_active": True, "core_tests_passed": True})
|
|
473
534
|
if doc:
|
|
474
535
|
return MCPServerInfo.from_registry_doc(doc)
|
|
475
536
|
|
|
@@ -488,7 +549,7 @@ class IATPSearchAPI:
|
|
|
488
549
|
}
|
|
489
550
|
}
|
|
490
551
|
},
|
|
491
|
-
{"$match": {"is_active": True}},
|
|
552
|
+
{"$match": {"is_active": True, "core_tests_passed": True}},
|
|
492
553
|
]
|
|
493
554
|
|
|
494
555
|
# Add additional filters if provided
|
|
@@ -502,6 +563,8 @@ class IATPSearchAPI:
|
|
|
502
563
|
if match_filters:
|
|
503
564
|
pipeline.append({"$match": match_filters})
|
|
504
565
|
|
|
566
|
+
# Exclude embedding fields from results
|
|
567
|
+
pipeline.append({"$project": MCP_PROJECTION_EXCLUDE_EMBEDDINGS})
|
|
505
568
|
pipeline.append({"$limit": 1})
|
|
506
569
|
|
|
507
570
|
results = list(collection.aggregate(pipeline))
|
|
@@ -509,7 +572,7 @@ class IATPSearchAPI:
|
|
|
509
572
|
return MCPServerInfo.from_registry_doc(results[0])
|
|
510
573
|
else:
|
|
511
574
|
# Build standard query filters
|
|
512
|
-
filters = {"is_active": True}
|
|
575
|
+
filters = {"is_active": True, "core_tests_passed": True}
|
|
513
576
|
|
|
514
577
|
if capability:
|
|
515
578
|
filters["capabilities"] = capability
|
|
@@ -518,8 +581,8 @@ class IATPSearchAPI:
|
|
|
518
581
|
# Tags are stored in metadata
|
|
519
582
|
filters["metadata.tags"] = tag
|
|
520
583
|
|
|
521
|
-
# Find first matching document
|
|
522
|
-
doc = collection.find_one(filters)
|
|
584
|
+
# Find first matching document (exclude embeddings for performance)
|
|
585
|
+
doc = collection.find_one(filters, MCP_PROJECTION_EXCLUDE_EMBEDDINGS)
|
|
523
586
|
if doc:
|
|
524
587
|
return MCPServerInfo.from_registry_doc(doc)
|
|
525
588
|
|
|
@@ -529,31 +592,58 @@ class IATPSearchAPI:
|
|
|
529
592
|
def list_mcp_servers(
|
|
530
593
|
cls,
|
|
531
594
|
limit: int = 10,
|
|
595
|
+
page: int = 1,
|
|
532
596
|
tags: Optional[List[str]] = None,
|
|
533
|
-
capabilities: Optional[List[str]] = None
|
|
597
|
+
capabilities: Optional[List[str]] = None,
|
|
598
|
+
user_uuid: Optional[str] = None
|
|
534
599
|
) -> List[MCPServerInfo]:
|
|
535
600
|
"""
|
|
536
601
|
List available MCP servers from the registry.
|
|
537
602
|
|
|
538
603
|
Args:
|
|
539
|
-
limit: Maximum number of servers to return
|
|
604
|
+
limit: Maximum number of servers to return (default: 10)
|
|
605
|
+
page: Page number for pagination, 1-indexed (default: 1)
|
|
540
606
|
tags: Filter by tags
|
|
541
607
|
capabilities: Filter by capabilities
|
|
608
|
+
user_uuid: Filter by user UUID
|
|
542
609
|
|
|
543
610
|
Returns:
|
|
544
611
|
List of MCPServerInfo objects
|
|
612
|
+
|
|
613
|
+
Examples:
|
|
614
|
+
list_mcp_servers(limit=10, page=1) # First 10 servers
|
|
615
|
+
list_mcp_servers(limit=10, page=2) # Next 10 servers
|
|
545
616
|
"""
|
|
617
|
+
if page < 1:
|
|
618
|
+
page = 1
|
|
619
|
+
|
|
620
|
+
skip = (page - 1) * limit
|
|
621
|
+
logger.info(f"list_mcp_servers: limit={limit}, page={page}, tags={tags}, capabilities={capabilities}, user_uuid={user_uuid}")
|
|
622
|
+
|
|
546
623
|
db = cls._get_connection()
|
|
547
624
|
collection_names = get_collection_names()
|
|
548
625
|
collection = db[collection_names["mcp_server"]]
|
|
549
626
|
|
|
627
|
+
logger.info(f"Using collection: {collection_names['mcp_server']}")
|
|
628
|
+
|
|
550
629
|
# Build query filters
|
|
551
|
-
filters = {"is_active": True}
|
|
630
|
+
filters = {"is_active": True, "core_tests_passed": True}
|
|
552
631
|
if capabilities:
|
|
553
632
|
filters["capabilities"] = {"$in": capabilities}
|
|
633
|
+
if user_uuid:
|
|
634
|
+
filters["user_uuid"] = user_uuid
|
|
554
635
|
|
|
555
|
-
|
|
556
|
-
|
|
636
|
+
logger.info(f"Query filters: {filters}")
|
|
637
|
+
|
|
638
|
+
# Count and log total
|
|
639
|
+
total_count = collection.count_documents(filters)
|
|
640
|
+
logger.info(f"Total documents matching filters: {total_count}")
|
|
641
|
+
|
|
642
|
+
# Query with pagination (exclude embeddings for performance)
|
|
643
|
+
cursor = collection.find(
|
|
644
|
+
filters,
|
|
645
|
+
MCP_PROJECTION_EXCLUDE_EMBEDDINGS
|
|
646
|
+
).skip(skip).limit(limit).sort("registered_at", -1)
|
|
557
647
|
|
|
558
648
|
# Manual filtering for tags if needed
|
|
559
649
|
servers = []
|
|
@@ -562,9 +652,11 @@ class IATPSearchAPI:
|
|
|
562
652
|
doc_tags = doc.get("metadata", {}).get("tags", [])
|
|
563
653
|
if not any(tag in doc_tags for tag in tags):
|
|
564
654
|
continue
|
|
655
|
+
|
|
565
656
|
servers.append(MCPServerInfo.from_registry_doc(doc))
|
|
566
657
|
|
|
567
|
-
|
|
658
|
+
logger.info(f"Returning {len(servers)} servers")
|
|
659
|
+
return servers
|
|
568
660
|
|
|
569
661
|
@classmethod
|
|
570
662
|
def get_mcp_server(cls, name: str) -> Optional[Dict[str, Any]]:
|
|
@@ -581,7 +673,8 @@ class IATPSearchAPI:
|
|
|
581
673
|
collection_names = get_collection_names()
|
|
582
674
|
collection = db[collection_names["mcp_server"]]
|
|
583
675
|
|
|
584
|
-
|
|
676
|
+
# Exclude embeddings from response (not needed by clients)
|
|
677
|
+
doc = collection.find_one({"name": name}, MCP_PROJECTION_EXCLUDE_EMBEDDINGS)
|
|
585
678
|
if doc:
|
|
586
679
|
doc["_id"] = str(doc["_id"])
|
|
587
680
|
return doc
|
|
@@ -615,8 +708,9 @@ class IATPSearchAPI:
|
|
|
615
708
|
Returns:
|
|
616
709
|
List of MCPServerInfo objects
|
|
617
710
|
"""
|
|
618
|
-
# Generate query embedding
|
|
711
|
+
# Generate query embedding (lazy import to avoid loading OpenAI/Cohere unless needed)
|
|
619
712
|
try:
|
|
713
|
+
from .embeddings import get_embedding_service
|
|
620
714
|
embedding_service = get_embedding_service()
|
|
621
715
|
query_embedding = await embedding_service.generate_query_embedding(query)
|
|
622
716
|
except Exception as e:
|
|
@@ -652,7 +746,7 @@ class IATPSearchAPI:
|
|
|
652
746
|
"queryVector": query_embedding,
|
|
653
747
|
"numCandidates": limit * 5,
|
|
654
748
|
"limit": limit,
|
|
655
|
-
"filter": {"is_active": True} if active_only else {}
|
|
749
|
+
"filter": {"is_active": True, "core_tests_passed": True} if active_only else {"core_tests_passed": True}
|
|
656
750
|
}
|
|
657
751
|
},
|
|
658
752
|
{
|
|
@@ -666,6 +760,14 @@ class IATPSearchAPI:
|
|
|
666
760
|
"metadata": 1,
|
|
667
761
|
"registered_at": 1,
|
|
668
762
|
"is_active": 1,
|
|
763
|
+
"core_tests_passed": 1,
|
|
764
|
+
"crewai_tests_passed": 1,
|
|
765
|
+
"user_uuid": 1,
|
|
766
|
+
"operator_address": 1,
|
|
767
|
+
"server_address": 1,
|
|
768
|
+
"server_network": 1,
|
|
769
|
+
"server_chain_id": 1,
|
|
770
|
+
"accepts": 1,
|
|
669
771
|
"score": {"$meta": "vectorSearchScore"}
|
|
670
772
|
}
|
|
671
773
|
}
|
|
@@ -687,7 +789,7 @@ class IATPSearchAPI:
|
|
|
687
789
|
"queryVector": query_embedding,
|
|
688
790
|
"numCandidates": limit * 5,
|
|
689
791
|
"limit": limit,
|
|
690
|
-
"filter": {"is_active": True} if active_only else {}
|
|
792
|
+
"filter": {"is_active": True, "core_tests_passed": True} if active_only else {"core_tests_passed": True}
|
|
691
793
|
}
|
|
692
794
|
},
|
|
693
795
|
{
|
|
@@ -701,6 +803,14 @@ class IATPSearchAPI:
|
|
|
701
803
|
"metadata": 1,
|
|
702
804
|
"registered_at": 1,
|
|
703
805
|
"is_active": 1,
|
|
806
|
+
"core_tests_passed": 1,
|
|
807
|
+
"crewai_tests_passed": 1,
|
|
808
|
+
"user_uuid": 1,
|
|
809
|
+
"operator_address": 1,
|
|
810
|
+
"server_address": 1,
|
|
811
|
+
"server_network": 1,
|
|
812
|
+
"server_chain_id": 1,
|
|
813
|
+
"accepts": 1,
|
|
704
814
|
"score": {"$meta": "vectorSearchScore"}
|
|
705
815
|
}
|
|
706
816
|
}
|
|
@@ -749,7 +859,9 @@ class IATPSearchAPI:
|
|
|
749
859
|
]
|
|
750
860
|
|
|
751
861
|
if active_only:
|
|
752
|
-
pipeline.append({"$match": {"is_active": True}})
|
|
862
|
+
pipeline.append({"$match": {"is_active": True, "core_tests_passed": True}})
|
|
863
|
+
else:
|
|
864
|
+
pipeline.append({"$match": {"core_tests_passed": True}})
|
|
753
865
|
|
|
754
866
|
pipeline.append({"$limit": limit})
|
|
755
867
|
|
|
@@ -807,11 +919,29 @@ def find_mcp_server(
|
|
|
807
919
|
|
|
808
920
|
def list_mcp_servers(
|
|
809
921
|
limit: int = 10,
|
|
922
|
+
page: int = 1,
|
|
810
923
|
tags: Optional[List[str]] = None,
|
|
811
|
-
capabilities: Optional[List[str]] = None
|
|
924
|
+
capabilities: Optional[List[str]] = None,
|
|
925
|
+
user_uuid: Optional[str] = None
|
|
812
926
|
) -> List[MCPServerInfo]:
|
|
813
|
-
"""
|
|
814
|
-
|
|
927
|
+
"""
|
|
928
|
+
List available MCP servers from the registry.
|
|
929
|
+
|
|
930
|
+
Args:
|
|
931
|
+
limit: Maximum number of servers to return (default: 10)
|
|
932
|
+
page: Page number for pagination, 1-indexed (default: 1)
|
|
933
|
+
tags: Filter by tags
|
|
934
|
+
capabilities: Filter by capabilities
|
|
935
|
+
user_uuid: Filter by user UUID
|
|
936
|
+
|
|
937
|
+
Returns:
|
|
938
|
+
List of MCPServerInfo objects
|
|
939
|
+
|
|
940
|
+
Examples:
|
|
941
|
+
servers = list_mcp_servers(limit=10, page=1) # First page
|
|
942
|
+
servers = list_mcp_servers(limit=10, page=2) # Second page
|
|
943
|
+
"""
|
|
944
|
+
return IATPSearchAPI.list_mcp_servers(limit, page, tags, capabilities, user_uuid)
|
|
815
945
|
|
|
816
946
|
|
|
817
947
|
async def search_mcp_servers(
|