traia-iatp 0.1.29__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.

Potentially problematic release.


This version of traia-iatp might be problematic. Click here for more details.

Files changed (107) hide show
  1. traia_iatp/README.md +368 -0
  2. traia_iatp/__init__.py +54 -0
  3. traia_iatp/cli/__init__.py +5 -0
  4. traia_iatp/cli/main.py +483 -0
  5. traia_iatp/client/__init__.py +10 -0
  6. traia_iatp/client/a2a_client.py +274 -0
  7. traia_iatp/client/crewai_a2a_tools.py +335 -0
  8. traia_iatp/client/d402_a2a_client.py +293 -0
  9. traia_iatp/client/grpc_a2a_tools.py +349 -0
  10. traia_iatp/client/root_path_a2a_client.py +1 -0
  11. traia_iatp/contracts/__init__.py +12 -0
  12. traia_iatp/contracts/iatp_contracts_config.py +263 -0
  13. traia_iatp/contracts/wallet_creator.py +255 -0
  14. traia_iatp/core/__init__.py +43 -0
  15. traia_iatp/core/models.py +172 -0
  16. traia_iatp/d402/__init__.py +55 -0
  17. traia_iatp/d402/chains.py +102 -0
  18. traia_iatp/d402/client.py +150 -0
  19. traia_iatp/d402/clients/__init__.py +7 -0
  20. traia_iatp/d402/clients/base.py +218 -0
  21. traia_iatp/d402/clients/httpx.py +219 -0
  22. traia_iatp/d402/common.py +114 -0
  23. traia_iatp/d402/encoding.py +28 -0
  24. traia_iatp/d402/examples/client_example.py +197 -0
  25. traia_iatp/d402/examples/server_example.py +171 -0
  26. traia_iatp/d402/facilitator.py +453 -0
  27. traia_iatp/d402/fastapi_middleware/__init__.py +6 -0
  28. traia_iatp/d402/fastapi_middleware/middleware.py +225 -0
  29. traia_iatp/d402/fastmcp_middleware.py +147 -0
  30. traia_iatp/d402/mcp_middleware.py +434 -0
  31. traia_iatp/d402/middleware.py +193 -0
  32. traia_iatp/d402/models.py +116 -0
  33. traia_iatp/d402/networks.py +98 -0
  34. traia_iatp/d402/path.py +43 -0
  35. traia_iatp/d402/payment_introspection.py +104 -0
  36. traia_iatp/d402/payment_signing.py +178 -0
  37. traia_iatp/d402/paywall.py +119 -0
  38. traia_iatp/d402/starlette_middleware.py +326 -0
  39. traia_iatp/d402/template.py +1 -0
  40. traia_iatp/d402/types.py +300 -0
  41. traia_iatp/mcp/__init__.py +18 -0
  42. traia_iatp/mcp/client.py +201 -0
  43. traia_iatp/mcp/d402_mcp_tool_adapter.py +361 -0
  44. traia_iatp/mcp/mcp_agent_template.py +481 -0
  45. traia_iatp/mcp/templates/Dockerfile.j2 +80 -0
  46. traia_iatp/mcp/templates/README.md.j2 +310 -0
  47. traia_iatp/mcp/templates/cursor-rules.md.j2 +520 -0
  48. traia_iatp/mcp/templates/deployment_params.json.j2 +20 -0
  49. traia_iatp/mcp/templates/docker-compose.yml.j2 +32 -0
  50. traia_iatp/mcp/templates/dockerignore.j2 +47 -0
  51. traia_iatp/mcp/templates/env.example.j2 +57 -0
  52. traia_iatp/mcp/templates/gitignore.j2 +77 -0
  53. traia_iatp/mcp/templates/mcp_health_check.py.j2 +150 -0
  54. traia_iatp/mcp/templates/pyproject.toml.j2 +32 -0
  55. traia_iatp/mcp/templates/pyrightconfig.json.j2 +22 -0
  56. traia_iatp/mcp/templates/run_local_docker.sh.j2 +390 -0
  57. traia_iatp/mcp/templates/server.py.j2 +175 -0
  58. traia_iatp/mcp/traia_mcp_adapter.py +543 -0
  59. traia_iatp/preview_diagrams.html +181 -0
  60. traia_iatp/registry/__init__.py +26 -0
  61. traia_iatp/registry/atlas_search_indexes.json +280 -0
  62. traia_iatp/registry/embeddings.py +298 -0
  63. traia_iatp/registry/iatp_search_api.py +846 -0
  64. traia_iatp/registry/mongodb_registry.py +771 -0
  65. traia_iatp/registry/readmes/ATLAS_SEARCH_INDEXES.md +252 -0
  66. traia_iatp/registry/readmes/ATLAS_SEARCH_SETUP.md +134 -0
  67. traia_iatp/registry/readmes/AUTHENTICATION_UPDATE.md +124 -0
  68. traia_iatp/registry/readmes/EMBEDDINGS_SETUP.md +172 -0
  69. traia_iatp/registry/readmes/IATP_SEARCH_API_GUIDE.md +257 -0
  70. traia_iatp/registry/readmes/MONGODB_X509_AUTH.md +208 -0
  71. traia_iatp/registry/readmes/README.md +251 -0
  72. traia_iatp/registry/readmes/REFACTORING_SUMMARY.md +191 -0
  73. traia_iatp/scripts/__init__.py +2 -0
  74. traia_iatp/scripts/create_wallet.py +244 -0
  75. traia_iatp/server/__init__.py +15 -0
  76. traia_iatp/server/a2a_server.py +219 -0
  77. traia_iatp/server/example_template_usage.py +72 -0
  78. traia_iatp/server/iatp_server_agent_generator.py +237 -0
  79. traia_iatp/server/iatp_server_template_generator.py +235 -0
  80. traia_iatp/server/templates/.dockerignore.j2 +48 -0
  81. traia_iatp/server/templates/Dockerfile.j2 +49 -0
  82. traia_iatp/server/templates/README.md +137 -0
  83. traia_iatp/server/templates/README.md.j2 +425 -0
  84. traia_iatp/server/templates/__init__.py +1 -0
  85. traia_iatp/server/templates/__main__.py.j2 +565 -0
  86. traia_iatp/server/templates/agent.py.j2 +94 -0
  87. traia_iatp/server/templates/agent_config.json.j2 +22 -0
  88. traia_iatp/server/templates/agent_executor.py.j2 +279 -0
  89. traia_iatp/server/templates/docker-compose.yml.j2 +23 -0
  90. traia_iatp/server/templates/env.example.j2 +84 -0
  91. traia_iatp/server/templates/gitignore.j2 +78 -0
  92. traia_iatp/server/templates/grpc_server.py.j2 +218 -0
  93. traia_iatp/server/templates/pyproject.toml.j2 +78 -0
  94. traia_iatp/server/templates/run_local_docker.sh.j2 +103 -0
  95. traia_iatp/server/templates/server.py.j2 +243 -0
  96. traia_iatp/special_agencies/__init__.py +4 -0
  97. traia_iatp/special_agencies/registry_search_agency.py +392 -0
  98. traia_iatp/utils/__init__.py +10 -0
  99. traia_iatp/utils/docker_utils.py +251 -0
  100. traia_iatp/utils/general.py +64 -0
  101. traia_iatp/utils/iatp_utils.py +126 -0
  102. traia_iatp-0.1.29.dist-info/METADATA +423 -0
  103. traia_iatp-0.1.29.dist-info/RECORD +107 -0
  104. traia_iatp-0.1.29.dist-info/WHEEL +5 -0
  105. traia_iatp-0.1.29.dist-info/entry_points.txt +2 -0
  106. traia_iatp-0.1.29.dist-info/licenses/LICENSE +21 -0
  107. traia_iatp-0.1.29.dist-info/top_level.txt +1 -0
@@ -0,0 +1,520 @@
1
+ # {{ api_name }} MCP Server Implementation Guide
2
+
3
+ You are working on implementing the {{ api_name }} MCP (Model Context Protocol) server. The basic structure has been set up, and your task is to implement the actual API integration.
4
+
5
+ ## API Information
6
+
7
+ - **API Name**: {{ api_name }}
8
+ - **Documentation**: [{{ docs_url }}]({{ docs_url }})
9
+ - **Website**: [{{ api_url }}]({{ api_url }})
10
+ {% if sdk_package %}
11
+ - **SDK**: `{{ sdk_package }}` (already included in pyproject.toml)
12
+ {% endif %}
13
+ - **Authentication**: {% if requires_auth %}Required - API key via `{{ api_key_env_var }}` environment variable{% else %}Not required{% endif %}
14
+
15
+ {% if requires_auth %}
16
+ ## 🔒 HTTP 402 Payment Protocol - Dual-Mode Operation
17
+
18
+ This MCP server implements the **HTTP 402 Payment Required** protocol using the **traia_iatp.d402** module with dual-mode support:
19
+
20
+ ### Mode 1: Authenticated (Free Access)
21
+
22
+ When a client provides their own {{ api_name }} API key:
23
+
24
+ ```
25
+ Request Headers:
26
+ Authorization: Bearer CLIENT_API_KEY
27
+
28
+ Flow:
29
+ 1. Client connects with their {{ api_name }} API key
30
+ 2. MCP server uses client's API key to call {{ api_name }} API
31
+ 3. No payment required
32
+ 4. Client pays {{ api_name }} directly (not the MCP server)
33
+ ```
34
+
35
+ **Use Case**: Clients who already have a {{ api_name }} subscription/API key
36
+
37
+ ### Mode 2: Payment Required (Paid Access)
38
+
39
+ When a client doesn't have their own API key but pays via x402/d402 protocol:
40
+
41
+ ```
42
+ Request Headers:
43
+ X-PAYMENT: <base64_encoded_x402_payment>
44
+
45
+ X402 Payment Header Format (created by x402.clients.base.create_payment_header()):
46
+ {
47
+ "x402Version": 1,
48
+ "scheme": "exact",
49
+ "network": "base-sepolia",
50
+ "payload": {
51
+ "signature": "0x...",
52
+ "authorization": {
53
+ "from": "0xCLIENT_ADDRESS",
54
+ "to": "0xSERVER_ADDRESS",
55
+ "value": "1000", // atomic units (wei)
56
+ "validAfter": "1700000000",
57
+ "validBefore": "1700000300",
58
+ "nonce": "hex..."
59
+ }
60
+ }
61
+ }
62
+
63
+ Flow:
64
+ 1. Client creates EIP-3009 transferWithAuthorization signature
65
+ 2. Client sends Payment header with encoded payment payload
66
+ 3. MCP server verifies payment using traia_iatp.d402.facilitator
67
+ 4. MCP server uses its INTERNAL {{ api_name }} API key to call the API
68
+ 5. Client pays the MCP server (not {{ api_name }})
69
+ ```
70
+
71
+ **Use Case**: Pay-per-use clients without their own {{ api_name }} subscription
72
+
73
+ ### D402 Protocol Integration
74
+
75
+ This server uses the **traia_iatp.d402** module which implements:
76
+ - EIP-3009 transferWithAuthorization for gasless payments
77
+ - Payment verification via IATP Settlement Facilitator
78
+ - On-chain transaction verification
79
+ - Multiple token support (USDC, TRAIA, etc.)
80
+
81
+ **Dependencies** (already in pyproject.toml):
82
+ - `traia-iatp>=0.1.27` - Provides d402 module
83
+ - `web3>=6.15.0` - For blockchain verification
84
+
85
+ ### Implementation Pattern for Tools
86
+
87
+ **For auto-generated tools** (from OpenAPI), the endpoint implementer will generate code like this:
88
+
89
+ ```python
90
+ from traia_iatp.d402.mcp_middleware import EndpointPaymentInfo, verify_endpoint_payment
91
+
92
+ @mcp.tool()
93
+ async def your_tool_name(context: Context, param1: str) -> Dict[str, Any]:
94
+ """Your tool description."""
95
+
96
+ # Get client's API key (if provided)
97
+ api_key = get_session_api_key(context)
98
+
99
+ # If no API key, verify payment for this specific endpoint
100
+ if not api_key:
101
+ # Each endpoint has specific payment requirements
102
+ endpoint_payment = EndpointPaymentInfo(
103
+ settlement_token_address="0xUSDC...", # From endpoint config
104
+ settlement_token_network="base-sepolia", # From endpoint config
105
+ payment_price_float=0.001, # From endpoint config
106
+ payment_price_wei="1000", # From endpoint config
107
+ server_address="0xSERVER..." # Server's payment address
108
+ )
109
+
110
+ # Verify payment matches this endpoint's requirements
111
+ if not verify_endpoint_payment(context, endpoint_payment):
112
+ return {
113
+ "error": "Payment required or insufficient",
114
+ "code": 402,
115
+ "required_payment": {
116
+ "token": "0xUSDC...",
117
+ "network": "base-sepolia",
118
+ "amount": 0.001
119
+ }
120
+ }
121
+
122
+ # Dual-mode: determine which API key to use
123
+ if api_key:
124
+ # MODE 1: Use client's API key (free for client)
125
+ api_key_to_use = api_key
126
+ else:
127
+ # MODE 2: Use server's internal API key (client paid)
128
+ api_key_to_use = os.getenv("{{ api_key_env_var }}")
129
+
130
+ # Call API
131
+ headers = {"Authorization": f"Bearer {api_key_to_use}"}
132
+ response = requests.get("{{ api_url }}/endpoint", headers=headers)
133
+ return response.json()
134
+ ```
135
+
136
+ **Key points**:
137
+ 1. Each tool verifies payment against **its specific endpoint requirements**
138
+ 2. Different endpoints can have different tokens, networks, and prices
139
+ 3. Payment amount/token/network are verified per-endpoint
140
+ 4. The middleware just extracts payment payload globally
141
+
142
+ ### Middleware Chain
143
+
144
+ The server has TWO middleware in sequence:
145
+
146
+ 1. **AuthMiddleware**: Extracts client's API key from Authorization header
147
+ 2. **D402MCPMiddleware**: Extracts and validates payment payload from Payment header
148
+
149
+ ### How Per-Endpoint Payment Works
150
+
151
+ Unlike FastAPI where middleware can be applied per-route, FastMCP has global middleware.
152
+ Therefore:
153
+
154
+ 1. **D402MCPMiddleware**: Extracts payment payload globally, stores in `context.state.payment_payload`
155
+ 2. **Each Tool**: Calls `verify_endpoint_payment()` with its specific requirements
156
+ - Verifies payment token matches endpoint's settlement token
157
+ - Verifies payment amount meets endpoint's price
158
+ - Verifies payment network matches endpoint's network
159
+
160
+ **Result**: Different endpoints can accept different tokens, on different networks, at different prices!
161
+
162
+ ### Environment Variables
163
+
164
+ **Required**:
165
+ - `{{ api_key_env_var }}`: Server's internal {{ api_name }} API key (used when clients pay via 402)
166
+ - `SERVER_ADDRESS`: MCP server's payment address (where 402 payments are sent)
167
+
168
+ **Required for Settlement (Production)**:
169
+ - `MCP_OPERATOR_PRIVATE_KEY`: Private key for signing settlement attestations (proof of service completion)
170
+ - `MCP_OPERATOR_ADDRESS`: Public address corresponding to operator private key (for verification)
171
+
172
+ **Optional**:
173
+ - `D402_FACILITATOR_URL`: Custom d402 facilitator URL (default: "https://facilitator.d402.net")
174
+ - `D402_FACILITATOR_API_KEY`: API key for private facilitator
175
+ - `D402_TESTING_MODE`: Set to "true" for local testing without settlement (default: "false")
176
+
177
+ **Example .env file**:
178
+ ```bash
179
+ # API Authentication (server's internal key for payment mode)
180
+ {{ api_key_env_var }}=your_{{ api_slug }}_api_key_here
181
+
182
+ # Server Payment Address (where 402 payments are received)
183
+ SERVER_ADDRESS=0x1234567890123456789012345678901234567890
184
+
185
+ # Operator Keys (for signing settlement attestations)
186
+ MCP_OPERATOR_PRIVATE_KEY=0x1234567890abcdef... # Keep secure!
187
+ MCP_OPERATOR_ADDRESS=0x9876543210fedcba... # Derived from private key
188
+
189
+ # Optional: Custom facilitator
190
+ D402_FACILITATOR_URL=https://facilitator.d402.net
191
+ D402_FACILITATOR_API_KEY=facilitator_api_key
192
+
193
+ # Optional: Testing mode (skip settlement for local dev)
194
+ D402_TESTING_MODE=false # Set to 'true' for testing without facilitator
195
+ ```
196
+
197
+ **About Operator Keys**:
198
+ - The operator signs settlement attestations after completing each paid request
199
+ - Attestation proves: service was completed + output hash is valid
200
+ - Can use the same key as SERVER_ADDRESS or a separate signing key
201
+ - Required for on-chain settlement via IATP Settlement Layer
202
+
203
+ **Note on Endpoint-Specific Configuration**:
204
+ Each endpoint's payment requirements (token, network, price) are embedded in the tool code.
205
+ These come from the endpoint configuration in the database/OpenAPI schema.
206
+
207
+ {% endif %}
208
+
209
+ ## Implementation Checklist
210
+
211
+ ### 1. Update Deployment Configuration
212
+
213
+ **IMPORTANT**: Update the `deployment_params.json` file with all implemented capabilities:
214
+
215
+ ```json
216
+ {
217
+ "mcp_server": {
218
+ "capabilities": [
219
+ // Replace these with your actual implemented tool names
220
+ "search_{{ api_slug.replace('-', '_') }}",
221
+ "get_{{ api_slug.replace('-', '_') }}_info",
222
+ // Add all other tools you implement
223
+ ]
224
+ },
225
+ "tags": ["{{ api_name_lower }}", "api", /* add relevant tags like "search", "data", etc. */]
226
+ }
227
+ ```
228
+
229
+ ### 2. Study the API Documentation
230
+
231
+ First, thoroughly review the API documentation at {{ docs_url }} to understand:
232
+ - Available endpoints
233
+ - Request/response formats
234
+ - Rate limits
235
+ - Error handling
236
+ {% if requires_auth %}- Authentication method (API key placement in headers, query params, etc.){% endif %}
237
+ - Specific features and capabilities to expose as tools
238
+
239
+ ### 3. Implement API Client Functions
240
+
241
+ Add functions to call the {{ api_name }} API with retry support. Example pattern:
242
+
243
+ ```python
244
+ from retry import retry
245
+
246
+ {% if sdk_package %}# Using the SDK with retry decorator
247
+ @retry(tries=2, delay=1, backoff=2, jitter=(1, 3))
248
+ def call_{{ api_slug.replace('-', '_') }}_api(endpoint: str, params: Dict[str, Any], api_key: str) -> Dict[str, Any]:
249
+ """Call {{ api_name }} API using the SDK with automatic retry."""
250
+ # Initialize the SDK client
251
+ client = {{ sdk_module }}.Client(api_key=api_key)
252
+
253
+ # Make the API call - will retry once on any exception
254
+ try:
255
+ response = client.call_endpoint(params)
256
+ return response.to_dict()
257
+ except Exception as e:
258
+ raise Exception(f"{{ api_name }} API error: {str(e)}")
259
+ {% else %}# Using requests library with retry decorator
260
+ @retry(tries=2, delay=1, backoff=2, jitter=(1, 3))
261
+ def call_{{ api_slug.replace('-', '_') }}_api(endpoint: str, params: Dict[str, Any], api_key: str) -> Dict[str, Any]:
262
+ """Call {{ api_name }} API endpoint with automatic retry."""
263
+ base_url = "https://api.example.com/v1" # TODO: Get actual base URL from docs
264
+
265
+ headers = {
266
+ {% if requires_auth %}"Authorization": f"Bearer {api_key}", # Or "X-API-Key": api_key
267
+ {% endif %}"Content-Type": "application/json"
268
+ }
269
+
270
+ # Will retry once on any requests.RequestException
271
+ try:
272
+ response = requests.get(f"{base_url}/{endpoint}",
273
+ params=params,
274
+ headers=headers,
275
+ timeout=30)
276
+ response.raise_for_status()
277
+ return response.json()
278
+ except requests.RequestException as e:
279
+ raise Exception(f"{{ api_name }} API error: {str(e)}")
280
+ {% endif %}```
281
+
282
+ #### Retry Configuration Explained
283
+
284
+ - `tries=2`: Total attempts (1 original + 1 retry)
285
+ - `delay=1`: Wait 1 second before retry
286
+ - `backoff=2`: Multiply delay by 2 for subsequent retries (if more than 2 tries)
287
+ - `jitter=(1, 3)`: Add random delay between 1-3 seconds to avoid thundering herd
288
+
289
+ ### 4. Create MCP Tools
290
+
291
+ Replace the `example_tool` placeholder with actual tools. **Each tool you implement MUST be added to the `capabilities` array in `deployment_params.json`**.
292
+
293
+ #### Search/Query Tool
294
+ ```python
295
+ @mcp.tool()
296
+ async def search_{{ api_slug.replace('-', '_') }}(
297
+ context: Context,
298
+ query: str,
299
+ limit: int = 10
300
+ ) -> Dict[str, Any]:
301
+ """
302
+ Search {{ api_name }} for [specific data type].
303
+
304
+ Args:
305
+ context: MCP context (injected automatically)
306
+ query: Search query
307
+ limit: Maximum number of results
308
+
309
+ Returns:
310
+ Dictionary with search results
311
+ """
312
+ {% if requires_auth %}
313
+ api_key = get_session_api_key(context)
314
+ if not api_key:
315
+ return {"error": "No API key found. Please authenticate with Authorization: Bearer YOUR_API_KEY"}
316
+ {% endif %}
317
+
318
+ try:
319
+ # The call_{{ api_slug.replace('-', '_') }}_api function already has retry logic
320
+ results = call_{{ api_slug.replace('-', '_') }}_api(
321
+ "search", # TODO: Use actual endpoint
322
+ {"q": query, "limit": limit},
323
+ {% if requires_auth %}api_key{% else %}None{% endif %})
324
+ return {
325
+ "status": "success",
326
+ "results": results
327
+ }
328
+ except Exception as e:
329
+ return {"error": str(e)}
330
+ ```
331
+
332
+ #### Get/Fetch Tool
333
+ ```python
334
+ @mcp.tool()
335
+ async def get_{{ api_slug.replace('-', '_') }}_info(
336
+ context: Context,
337
+ item_id: str
338
+ ) -> Dict[str, Any]:
339
+ """
340
+ Get detailed information about a specific item.
341
+
342
+ Args:
343
+ context: MCP context (injected automatically)
344
+ item_id: ID of the item to fetch
345
+
346
+ Returns:
347
+ Dictionary with item details
348
+ """
349
+ # Similar implementation pattern
350
+ ```
351
+
352
+ #### Create/Update Tool (if applicable)
353
+ ```python
354
+ @mcp.tool()
355
+ async def create_{{ api_slug.replace('-', '_') }}_item(
356
+ context: Context,
357
+ name: str,
358
+ data: Dict[str, Any]
359
+ ) -> Dict[str, Any]:
360
+ """
361
+ Create a new item in {{ api_name }}.
362
+
363
+ Args:
364
+ context: MCP context (injected automatically)
365
+ name: Name of the item
366
+ data: Additional data for the item
367
+
368
+ Returns:
369
+ Dictionary with creation result
370
+ """
371
+ # Implementation here
372
+ ```
373
+
374
+ ### 5. Best Practices
375
+
376
+ 1. **Error Handling**: Always wrap API calls in try-except blocks and return user-friendly error messages
377
+ 2. **Input Validation**: Validate parameters before making API calls
378
+ 3. **Rate Limiting**: Respect API rate limits, implement delays if needed
379
+ 4. **Response Formatting**: Return consistent response structures across all tools
380
+ 5. **Logging**: Use the logger for debugging but don't log sensitive data like API keys
381
+ 6. **Documentation**: Write clear docstrings for each tool explaining parameters and return values
382
+ 7. **Retry Strategy**: Use the `@retry` decorator on API client functions for resilience
383
+
384
+ #### Retry Best Practices
385
+
386
+ - **Only use retry for external API calls** - Don't add retry to internal functions, database operations, or file operations
387
+ - **Apply retry to API client functions**, not MCP tool functions directly
388
+ - **Use `tries=2`** (1 original attempt + 1 retry) to balance reliability and responsiveness
389
+ - **Add jitter** to prevent thundering herd when multiple clients retry simultaneously
390
+ - **Don't retry on authentication errors** - use conditional retry if needed:
391
+ ```python
392
+ from retry import retry
393
+ import requests
394
+
395
+ def retry_on_server_error(exception):
396
+ """Only retry on server errors (5xx), not client errors (4xx)"""
397
+ if isinstance(exception, requests.HTTPError):
398
+ return 500 <= exception.response.status_code < 600
399
+ return True # Retry on other exceptions like network errors
400
+
401
+ @retry(tries=2, delay=1, backoff=2, jitter=(1, 3), exceptions=retry_on_server_error)
402
+ def call_api_with_smart_retry(endpoint, params, api_key):
403
+ # API implementation
404
+ pass
405
+ ```
406
+ - **Log retry attempts** for debugging:
407
+ ```python
408
+ @retry(tries=2, delay=1, logger=logger)
409
+ def call_{{ api_slug.replace('-', '_') }}_api(...):
410
+ # Implementation
411
+ ```
412
+
413
+ #### When to Use Retry
414
+
415
+ **✅ DO use retry for:**
416
+ - HTTP requests to external APIs
417
+ - Network operations that can fail temporarily
418
+ - Remote service calls that may experience transient errors
419
+
420
+ **❌ DON'T use retry for:**
421
+ - MCP tool functions (they should handle errors gracefully instead)
422
+ - Local file operations
423
+ - Database queries (unless specifically needed for connection issues)
424
+ - Authentication/validation logic
425
+ - Data processing or computation functions
426
+
427
+ ### 6. Testing
428
+
429
+ After implementing tools, test them:
430
+
431
+ 1. Run the server locally:
432
+ ```bash
433
+ ./run_local_docker.sh
434
+ ```
435
+
436
+ 2. Use the health check script:
437
+ ```bash
438
+ python mcp_health_check.py
439
+ ```
440
+
441
+ 3. Test with CrewAI:
442
+ ```python
443
+ {% if requires_auth %}from traia_iatp.mcp.traia_mcp_adapter import create_mcp_adapter_with_auth
444
+
445
+ # Authenticated connection
446
+ with create_mcp_adapter_with_auth(
447
+ url="http://localhost:8000/mcp/",
448
+ api_key="your-api-key"
449
+ ) as tools:
450
+ # Test your tools
451
+ for tool in tools:
452
+ print(f"Tool: {tool.name}")
453
+ {% else %}from traia_iatp.mcp.traia_mcp_adapter import create_mcp_adapter
454
+
455
+ # Standard connection (no authentication)
456
+ with create_mcp_adapter(
457
+ url="http://localhost:8000/mcp/"
458
+ ) as tools:
459
+ # Test your tools
460
+ for tool in tools:
461
+ print(f"Tool: {tool.name}")
462
+ {% endif %}
463
+ ```
464
+
465
+ ### 7. Update Documentation
466
+
467
+ After implementing the tools:
468
+
469
+ 1. **Update README.md**:
470
+ - List all implemented tools with descriptions
471
+ - Add usage examples for each tool
472
+ - Include any specific setup instructions
473
+
474
+ 2. **Update deployment_params.json**:
475
+ - Ensure ALL tool names are in the `capabilities` array
476
+ - Add relevant tags based on functionality
477
+ - Verify authentication settings match implementation
478
+
479
+ 3. **Add Tool Examples** in README.md:
480
+ ```python
481
+ # Example usage of each tool
482
+ result = await tool.search_{{ api_slug.replace('-', '_') }}(query="example", limit=5)
483
+ ```
484
+
485
+ ### 8. Pre-Deployment Checklist
486
+
487
+ Before marking the implementation as complete:
488
+
489
+ - [ ] All placeholder code has been replaced with actual implementation
490
+ - [ ] All tools are properly documented with docstrings
491
+ - [ ] Error handling is implemented for all API calls
492
+ - [ ] `deployment_params.json` contains all tool names in capabilities
493
+ - [ ] README.md has been updated with usage examples
494
+ - [ ] Server runs successfully with `./run_local_docker.sh`
495
+ - [ ] Health check passes
496
+ - [ ] At least one tool works end-to-end
497
+
498
+ ### 9. Common {{ api_name }} Use Cases
499
+
500
+ Based on the API documentation, consider implementing tools for these common use cases:
501
+
502
+ 1. **TODO**: List specific use cases based on {{ api_name }} capabilities
503
+ 2. **TODO**: Add more relevant use cases
504
+ 3. **TODO**: Include any special features of this API
505
+
506
+ ### 10. Example API Calls
507
+
508
+ Here are some example API calls from the {{ api_name }} documentation that you should implement:
509
+
510
+ ```
511
+ TODO: Add specific examples from the API docs
512
+ ```
513
+
514
+ ## Need Help?
515
+
516
+ - Check the {{ api_name }} API documentation: {{ docs_url }}
517
+ - Review the MCP specification: https://modelcontextprotocol.io
518
+ - Look at other MCP server examples in the Traia-IO organization
519
+
520
+ Remember: The goal is to make {{ api_name }}'s capabilities easily accessible to AI agents through standardized MCP tools.
@@ -0,0 +1,20 @@
1
+ {
2
+ "github_url": "https://github.com/Traia-IO/{{ api_slug }}-mcp-server",
3
+ "mcp_server": {
4
+ "name": "{{ api_slug }}-mcp",
5
+ "description": "{{ api_description|capitalize }}",
6
+ "server_type": "streamable-http",
7
+ "requires_api_key": {{ requires_auth|lower }},
8
+ {% if requires_auth %}"api_key_header": "Authorization",
9
+ "api_keys": ["{{ api_key_env_var }}"],
10
+ {% endif %}"capabilities": [
11
+ "example_tool",
12
+ "get_api_info"
13
+ ]
14
+ },
15
+ "deployment_method": "cloud_run",
16
+ "gcp_project_id": "traia-mcp-servers",
17
+ "gcp_region": "us-central1",
18
+ "tags": ["{{ api_name_lower }}", "api", "mcp"],
19
+ "ref": "main"
20
+ }
@@ -0,0 +1,32 @@
1
+ version: '3.8'
2
+
3
+ services:
4
+ {{ api_slug }}-mcp:
5
+ build: .
6
+ container_name: {{ api_slug }}-mcp-server
7
+ ports:
8
+ - "8000:8000"
9
+ environment:
10
+ - PORT=8000
11
+ - STAGE=${STAGE:-MAINNET}
12
+ - LOG_LEVEL=${LOG_LEVEL:-INFO}
13
+ {% if requires_auth %}
14
+ # API Authentication (server's internal key for payment mode)
15
+ # Set this in .env file when deploying (creator provides their master API key)
16
+ - {{ api_key_env_var }}={% raw %}${{% endraw %}{{ api_key_env_var }}{% raw %}}{% endraw %}
17
+ {% endif %}
18
+ # D402 Payment Protocol Configuration
19
+ - SERVER_ADDRESS=${SERVER_ADDRESS:-}
20
+ - MCP_OPERATOR_PRIVATE_KEY=${MCP_OPERATOR_PRIVATE_KEY:-} # For signing settlement attestations
21
+ - MCP_OPERATOR_ADDRESS=${MCP_OPERATOR_ADDRESS:-} # Operator's public address (for verification)
22
+ - D402_FACILITATOR_URL=${D402_FACILITATOR_URL:-https://facilitator.d402.net}
23
+ - D402_FACILITATOR_API_KEY=${D402_FACILITATOR_API_KEY:-}
24
+ - D402_TESTING_MODE=${D402_TESTING_MODE:-false} # Set to 'true' for local testing without facilitator
25
+ volumes:
26
+ - ./logs:/app/logs
27
+ restart: unless-stopped
28
+ healthcheck:
29
+ test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
30
+ interval: 30s
31
+ timeout: 10s
32
+ retries: 3
@@ -0,0 +1,47 @@
1
+ # Python cache
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+
7
+ # Virtual environments
8
+ .venv/
9
+ venv/
10
+ ENV/
11
+ env/
12
+
13
+ # IDE
14
+ .vscode/
15
+ .idea/
16
+ *.swp
17
+ *.swo
18
+
19
+ # Git
20
+ .git/
21
+ .gitignore
22
+
23
+ # Documentation
24
+ README.md
25
+ docs/
26
+
27
+ # Tests
28
+ tests/
29
+ pytest_cache/
30
+ .coverage
31
+
32
+ # OS
33
+ .DS_Store
34
+ Thumbs.db
35
+
36
+ # Temporary files
37
+ *.log
38
+ *.tmp
39
+ .cache/
40
+
41
+ # uv
42
+ uv.lock
43
+
44
+ # Docker
45
+ Dockerfile
46
+ docker-compose.yml
47
+ .dockerignore
@@ -0,0 +1,57 @@
1
+ # {{ api_name }} MCP Server Environment Configuration
2
+ #
3
+ # IMPORTANT: These values will be set during deployment (Phase 2)
4
+ # This file is a template - actual .env will be created with real values
5
+
6
+ # ============================================
7
+ # Server Configuration
8
+ # ============================================
9
+ PORT=8000
10
+ STAGE=MAINNET
11
+ LOG_LEVEL=INFO
12
+
13
+ {% if requires_auth %}
14
+ # ============================================
15
+ # API Authentication (Set during deployment)
16
+ # ============================================
17
+ # Server's internal {{ api_name }} API key
18
+ # This is used when clients pay via HTTP 402 (payment mode)
19
+ # Will be provided by MCP server creator during deployment
20
+ {{ api_key_env_var }}=
21
+
22
+ {% endif %}
23
+ # ============================================
24
+ # D402 Payment Protocol (Set during deployment)
25
+ # ============================================
26
+ # MCP server's payment address (IATP wallet contract address)
27
+ # Generated during deployment when IATP wallet contract is created
28
+ SERVER_ADDRESS=
29
+
30
+ # Operator keys for signing settlement attestations
31
+ # Generated during deployment from IATP wallet contract
32
+ MCP_OPERATOR_PRIVATE_KEY=
33
+ MCP_OPERATOR_ADDRESS=
34
+
35
+ # Facilitator configuration
36
+ D402_FACILITATOR_URL=https://facilitator.d402.net
37
+ D402_FACILITATOR_API_KEY=
38
+
39
+ # Default settlement token configuration
40
+ # Used as defaults for example tools and fallback for endpoints
41
+ DEFAULT_SETTLEMENT_TOKEN=0x036CbD53842c5426634e7929541eC2318f3dCF7e
42
+ DEFAULT_SETTLEMENT_NETWORK=sepolia
43
+
44
+ # Testing mode
45
+ D402_TESTING_MODE=true
46
+
47
+ # ============================================
48
+ # Deployment Process
49
+ # ============================================
50
+ # Phase 1 (Completed): Code generation
51
+ # Phase 2 (Next): Deployment via deploy_mcp_lambda_handler
52
+ # 1. Create IATP wallet contract → Get SERVER_ADDRESS
53
+ # 2. Generate operator keys → Get MCP_OPERATOR_PRIVATE_KEY & MCP_OPERATOR_ADDRESS
54
+ # 3. Get API key from creator{% if requires_auth %} → Set {{ api_key_env_var }}{% endif %}
55
+ # 4. Deploy to GCP with actual environment variables
56
+ # 5. Register in MongoDB
57
+