traia-iatp 0.1.1__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 (72) hide show
  1. traia_iatp/README.md +368 -0
  2. traia_iatp/__init__.py +30 -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/grpc_a2a_tools.py +349 -0
  9. traia_iatp/client/root_path_a2a_client.py +1 -0
  10. traia_iatp/core/__init__.py +43 -0
  11. traia_iatp/core/models.py +161 -0
  12. traia_iatp/mcp/__init__.py +15 -0
  13. traia_iatp/mcp/client.py +201 -0
  14. traia_iatp/mcp/mcp_agent_template.py +422 -0
  15. traia_iatp/mcp/templates/Dockerfile.j2 +56 -0
  16. traia_iatp/mcp/templates/README.md.j2 +212 -0
  17. traia_iatp/mcp/templates/cursor-rules.md.j2 +326 -0
  18. traia_iatp/mcp/templates/deployment_params.json.j2 +20 -0
  19. traia_iatp/mcp/templates/docker-compose.yml.j2 +23 -0
  20. traia_iatp/mcp/templates/dockerignore.j2 +47 -0
  21. traia_iatp/mcp/templates/gitignore.j2 +77 -0
  22. traia_iatp/mcp/templates/mcp_health_check.py.j2 +150 -0
  23. traia_iatp/mcp/templates/pyproject.toml.j2 +26 -0
  24. traia_iatp/mcp/templates/run_local_docker.sh.j2 +94 -0
  25. traia_iatp/mcp/templates/server.py.j2 +240 -0
  26. traia_iatp/mcp/traia_mcp_adapter.py +381 -0
  27. traia_iatp/preview_diagrams.html +181 -0
  28. traia_iatp/registry/__init__.py +26 -0
  29. traia_iatp/registry/atlas_search_indexes.json +280 -0
  30. traia_iatp/registry/embeddings.py +298 -0
  31. traia_iatp/registry/iatp_search_api.py +839 -0
  32. traia_iatp/registry/mongodb_registry.py +771 -0
  33. traia_iatp/registry/readmes/ATLAS_SEARCH_INDEXES.md +252 -0
  34. traia_iatp/registry/readmes/ATLAS_SEARCH_SETUP.md +134 -0
  35. traia_iatp/registry/readmes/AUTHENTICATION_UPDATE.md +124 -0
  36. traia_iatp/registry/readmes/EMBEDDINGS_SETUP.md +172 -0
  37. traia_iatp/registry/readmes/IATP_SEARCH_API_GUIDE.md +257 -0
  38. traia_iatp/registry/readmes/MONGODB_X509_AUTH.md +208 -0
  39. traia_iatp/registry/readmes/README.md +251 -0
  40. traia_iatp/registry/readmes/REFACTORING_SUMMARY.md +191 -0
  41. traia_iatp/server/__init__.py +15 -0
  42. traia_iatp/server/a2a_server.py +215 -0
  43. traia_iatp/server/example_template_usage.py +72 -0
  44. traia_iatp/server/iatp_server_agent_generator.py +237 -0
  45. traia_iatp/server/iatp_server_template_generator.py +235 -0
  46. traia_iatp/server/templates/Dockerfile.j2 +49 -0
  47. traia_iatp/server/templates/README.md +137 -0
  48. traia_iatp/server/templates/README.md.j2 +425 -0
  49. traia_iatp/server/templates/__init__.py +1 -0
  50. traia_iatp/server/templates/__main__.py.j2 +450 -0
  51. traia_iatp/server/templates/agent.py.j2 +80 -0
  52. traia_iatp/server/templates/agent_config.json.j2 +22 -0
  53. traia_iatp/server/templates/agent_executor.py.j2 +264 -0
  54. traia_iatp/server/templates/docker-compose.yml.j2 +23 -0
  55. traia_iatp/server/templates/env.example.j2 +67 -0
  56. traia_iatp/server/templates/gitignore.j2 +78 -0
  57. traia_iatp/server/templates/grpc_server.py.j2 +218 -0
  58. traia_iatp/server/templates/pyproject.toml.j2 +76 -0
  59. traia_iatp/server/templates/run_local_docker.sh.j2 +103 -0
  60. traia_iatp/server/templates/server.py.j2 +190 -0
  61. traia_iatp/special_agencies/__init__.py +4 -0
  62. traia_iatp/special_agencies/registry_search_agency.py +392 -0
  63. traia_iatp/utils/__init__.py +10 -0
  64. traia_iatp/utils/docker_utils.py +251 -0
  65. traia_iatp/utils/general.py +64 -0
  66. traia_iatp/utils/iatp_utils.py +126 -0
  67. traia_iatp-0.1.1.dist-info/METADATA +414 -0
  68. traia_iatp-0.1.1.dist-info/RECORD +72 -0
  69. traia_iatp-0.1.1.dist-info/WHEEL +5 -0
  70. traia_iatp-0.1.1.dist-info/entry_points.txt +2 -0
  71. traia_iatp-0.1.1.dist-info/licenses/LICENSE +21 -0
  72. traia_iatp-0.1.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env python
2
+ """
3
+ {{ api_name }} MCP Server Health Check Script
4
+
5
+ This script properly connects to the {{ api_name }} MCP server and checks its health by:
6
+ 1. Establishing a session
7
+ 2. Requesting server info
8
+ 3. Listing available tools
9
+ """
10
+
11
+ import sys
12
+ import json
13
+ import requests
14
+ import argparse
15
+ from typing import Dict, Any
16
+ import uuid
17
+
18
+ def create_mcp_session(base_url: str) -> Dict[str, Any]:
19
+ """Create an MCP session and return session info"""
20
+ # Generate a session ID
21
+ session_id = str(uuid.uuid4())
22
+
23
+ # MCP requires specific headers for streamable-http
24
+ headers = {
25
+ "Content-Type": "application/json",
26
+ "Accept": "application/json, text/event-stream",
27
+ "X-Session-ID": session_id
28
+ }
29
+
30
+ return {"session_id": session_id, "headers": headers, "base_url": base_url}
31
+
32
+ def send_mcp_request(session: Dict[str, Any], method: str, params: Dict = None) -> Dict[str, Any]:
33
+ """Send an MCP JSON-RPC request"""
34
+ request_data = {
35
+ "jsonrpc": "2.0",
36
+ "method": method,
37
+ "params": params or {},
38
+ "id": str(uuid.uuid4())
39
+ }
40
+
41
+ try:
42
+ response = requests.post(
43
+ f"{session['base_url']}/mcp/",
44
+ json=request_data,
45
+ headers=session['headers'],
46
+ timeout=5
47
+ )
48
+
49
+ # Handle both JSON and SSE responses
50
+ if response.headers.get('content-type', '').startswith('text/event-stream'):
51
+ # For SSE, we'd need to parse the event stream
52
+ return {"status": "ok", "message": "Server returned SSE stream"}
53
+ else:
54
+ return response.json()
55
+
56
+ except requests.exceptions.RequestException as e:
57
+ return {"error": str(e)}
58
+
59
+ def check_mcp_server_health(url: str) -> bool:
60
+ """Check if {{ api_name }} MCP server is healthy"""
61
+ print(f"🔍 Checking {{ api_name }} MCP server health at {url}")
62
+
63
+ # Create session
64
+ session = create_mcp_session(url)
65
+ print(f"📝 Created session: {session['session_id']}")
66
+
67
+ # Try to get server info
68
+ print("\n1️⃣ Testing server.info method...")
69
+ result = send_mcp_request(session, "server.info")
70
+
71
+ if "error" in result and "session" not in str(result.get("error", "")):
72
+ print(f"❌ Server info failed: {result}")
73
+ return False
74
+ else:
75
+ print(f"✅ Server responded: {json.dumps(result, indent=2)[:200]}...")
76
+
77
+ # Try to list tools
78
+ print("\n2️⃣ Testing tools/list method...")
79
+ result = send_mcp_request(session, "tools/list")
80
+
81
+ if "error" in result and "session" not in str(result.get("error", "")):
82
+ print(f"❌ List tools failed: {result}")
83
+ return False
84
+ else:
85
+ print(f"✅ Tools list responded: {json.dumps(result, indent=2)[:200]}...")
86
+
87
+ # Check if we have the expected tools
88
+ if "result" in result and "tools" in result["result"]:
89
+ tools = result["result"]["tools"]
90
+ tool_names = [tool.get("name", "") for tool in tools]
91
+ print(f"📋 Available tools: {', '.join(tool_names)}")
92
+
93
+ # Check for expected tools
94
+ expected_tools = ["example_tool", "get_api_info"]
95
+ missing_tools = [tool for tool in expected_tools if tool not in tool_names]
96
+
97
+ if missing_tools:
98
+ print(f"⚠️ Missing expected tools: {', '.join(missing_tools)}")
99
+ else:
100
+ print("✅ All expected {{ api_name }} tools are available!")
101
+
102
+ # Alternative: Try connecting with CrewAI adapter
103
+ print("\n3️⃣ Testing CrewAI adapter connection...")
104
+ try:
105
+ from crewai_tools import MCPServerAdapter
106
+
107
+ server_params = {
108
+ "url": f"{url}/mcp/",
109
+ "transport": "streamable-http"
110
+ }
111
+
112
+ with MCPServerAdapter(server_params) as mcp_tools:
113
+ tools = list(mcp_tools)
114
+ print(f"✅ CrewAI connected successfully! Found {len(tools)} tools")
115
+
116
+ # Print first few tools
117
+ for i, tool in enumerate(tools[:3]):
118
+ print(f" - {tool.name}")
119
+
120
+ if len(tools) > 3:
121
+ print(f" ... and {len(tools) - 3} more")
122
+
123
+ return True
124
+
125
+ except Exception as e:
126
+ print(f"⚠️ CrewAI adapter test failed: {e}")
127
+ # This might fail but server could still be healthy
128
+
129
+ return True
130
+
131
+ def main():
132
+ parser = argparse.ArgumentParser(description="Check {{ api_name }} MCP Server Health")
133
+ parser.add_argument("--url", default="http://localhost:8000",
134
+ help="{{ api_name }} MCP server URL (default: http://localhost:8000)")
135
+ args = parser.parse_args()
136
+
137
+ print(f"🚀 {{ api_name }} MCP Server Health Check")
138
+ print(f"📍 Server URL: {args.url}")
139
+ print(f"📰 Expected tools: example_tool, get_api_info")
140
+ print("="*50)
141
+
142
+ if check_mcp_server_health(args.url):
143
+ print("\n✅ {{ api_name }} MCP Server is healthy and responding!")
144
+ return 0
145
+ else:
146
+ print("\n❌ {{ api_name }} MCP Server health check failed!")
147
+ return 1
148
+
149
+ if __name__ == "__main__":
150
+ sys.exit(main())
@@ -0,0 +1,26 @@
1
+ [project]
2
+ name = "{{ api_slug }}-mcp-server"
3
+ version = "0.1.0"
4
+ description = "MCP server for {{ api_name }} API{% if auth_description %} with authentication support{% endif %}"
5
+ requires-python = ">=3.12"
6
+ dependencies = [
7
+ "crewai-tools[mcp]>=0.48.0",
8
+ "fastmcp>=2.10.1",
9
+ "python-dotenv>=1.1.1",
10
+ "requests>=2.32.4",
11
+ "starlette>=0.46.2",
12
+ "retry>=0.9.2",
13
+ {% if sdk_package %}
14
+ "{{ sdk_package }}",
15
+ {% endif %}
16
+ ]
17
+
18
+ [build-system]
19
+ requires = ["hatchling"]
20
+ build-backend = "hatchling.build"
21
+
22
+ [tool.hatch.build.targets.wheel]
23
+ include = [
24
+ "server.py",
25
+ "mcp_health_check.py",
26
+ ]
@@ -0,0 +1,94 @@
1
+ #!/bin/bash
2
+
3
+ # Script to build and run the {{ api_name }} MCP Server locally in Docker
4
+
5
+ set -e # Exit on error
6
+
7
+ # Color codes for output
8
+ GREEN='\033[0;32m'
9
+ BLUE='\033[0;34m'
10
+ YELLOW='\033[1;33m'
11
+ RED='\033[0;31m'
12
+ NC='\033[0m' # No Color
13
+
14
+ # Configuration
15
+ IMAGE_NAME="{{ api_slug }}-mcp-server"
16
+ CONTAINER_NAME="{{ api_slug }}-mcp-local"
17
+ HOST_PORT=8000
18
+ CONTAINER_PORT=8000
19
+
20
+ echo -e "${BLUE}🚀 Building and running {{ api_name }} MCP Server...${NC}"
21
+ echo
22
+
23
+ # Check if Docker is installed
24
+ if ! command -v docker &> /dev/null; then
25
+ echo -e "${RED}❌ Docker is not installed. Please install Docker first.${NC}"
26
+ exit 1
27
+ fi
28
+
29
+ # Stop and remove existing container if it exists
30
+ if docker ps -a | grep -q $CONTAINER_NAME; then
31
+ echo -e "${YELLOW}🛑 Stopping existing container...${NC}"
32
+ docker stop $CONTAINER_NAME >/dev/null 2>&1 || true
33
+ docker rm $CONTAINER_NAME >/dev/null 2>&1 || true
34
+ fi
35
+
36
+ # Build the Docker image
37
+ echo -e "${BLUE}🔨 Building Docker image...${NC}"
38
+ docker build --no-cache -t $IMAGE_NAME .
39
+
40
+ # Run the container
41
+ echo -e "${BLUE}🏃 Starting container...${NC}"
42
+ docker run -d \
43
+ --name $CONTAINER_NAME \
44
+ -p $HOST_PORT:$CONTAINER_PORT \
45
+ -e STAGE="${STAGE:-MAINNET}" \
46
+ -e LOG_LEVEL="${LOG_LEVEL:-INFO}" \
47
+ {% if api_key_env_var %}
48
+ -e {{ api_key_env_var }}="{% raw %}${{% endraw %}{{ api_key_env_var }}{% raw %}}{% endraw %}" \
49
+ {% endif %}
50
+ -e PORT="$CONTAINER_PORT" \
51
+ $IMAGE_NAME
52
+
53
+ # Wait for the server to start
54
+ echo -e "${YELLOW}⏳ Waiting for server to start...${NC}"
55
+ sleep 3
56
+
57
+ # Check if container is running
58
+ if ! docker ps | grep -q $CONTAINER_NAME; then
59
+ echo -e "${RED}❌ Container failed to start. Checking logs:${NC}"
60
+ docker logs $CONTAINER_NAME
61
+ exit 1
62
+ fi
63
+
64
+ # Get container info
65
+ CONTAINER_ID=$(docker ps -q -f name=$CONTAINER_NAME)
66
+ CONTAINER_IP=$(docker inspect -f '{% raw %}{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}{% endraw %}' $CONTAINER_ID)
67
+
68
+ # Output connection information
69
+ echo
70
+ echo -e "${GREEN}✅ {{ api_name }} MCP Server is running!${NC}"
71
+ echo
72
+ echo -e "${BLUE}📍 Connection Information:${NC}"
73
+ echo -e " Local URL: ${GREEN}http://localhost:${HOST_PORT}/mcp${NC}"
74
+ echo -e " Container IP: ${GREEN}${CONTAINER_IP}:${CONTAINER_PORT}${NC}"
75
+ echo -e " Container Name: ${GREEN}${CONTAINER_NAME}${NC}"
76
+ echo -e " Container ID: ${GREEN}${CONTAINER_ID:0:12}${NC}"
77
+ echo
78
+ echo -e "${BLUE}📝 Useful commands:${NC}"
79
+ echo -e " View logs: ${YELLOW}docker logs -f ${CONTAINER_NAME}${NC}"
80
+ echo -e " Stop server: ${YELLOW}docker stop ${CONTAINER_NAME}${NC}"
81
+ echo -e " Remove container: ${YELLOW}docker rm ${CONTAINER_NAME}${NC}"
82
+ echo -e " Shell access: ${YELLOW}docker exec -it ${CONTAINER_NAME} /bin/bash${NC}"
83
+ echo
84
+ echo -e "${BLUE}🔌 MCP Server Endpoint:${NC}"
85
+ echo -e " ${GREEN}http://localhost:${HOST_PORT}/mcp${NC}"
86
+ echo
87
+
88
+ # Check if the server is responding
89
+ echo -e "${YELLOW}🔍 Checking server health...${NC}"
90
+ if curl -s -o /dev/null -w "%{http_code}" "http://localhost:${HOST_PORT}/mcp" | grep -q "200\|404\|405"; then
91
+ echo -e "${GREEN}✅ Server is responding!${NC}"
92
+ else
93
+ echo -e "${YELLOW}⚠️ Server may still be starting up. Check logs with: docker logs -f ${CONTAINER_NAME}${NC}"
94
+ fi
@@ -0,0 +1,240 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ {{ api_name }} MCP Server{{ auth_description }}
4
+
5
+ A Model Context Protocol server providing {{ api_description }}
6
+ using the {{ api_name }} API{{ auth_details }}.
7
+ """
8
+
9
+ import asyncio
10
+ import logging
11
+ import os
12
+ import sys
13
+ from typing import Dict, Any, Optional
14
+ from datetime import datetime
15
+
16
+ # Third-party imports
17
+ import requests
18
+ from fastmcp import FastMCP, Context
19
+ from fastmcp.server.middleware import Middleware, MiddlewareContext
20
+ from fastmcp.server.dependencies import get_http_request, get_context
21
+ from starlette.requests import Request
22
+ from starlette.responses import JSONResponse
23
+ from retry import retry
24
+ {% if sdk_package %}
25
+ # {{ api_name }} SDK
26
+ # TODO: Adjust the import based on the SDK documentation
27
+ # Common patterns:
28
+ # - from {{ sdk_module }} import Client
29
+ # - from {{ sdk_module }} import {{ api_name }}Client
30
+ # - import {{ sdk_module }}
31
+ # Check the SDK docs for the correct import statement
32
+ import {{ sdk_module }}
33
+ {% endif %}
34
+
35
+ # Configure logging
36
+ logging.basicConfig(
37
+ level=logging.INFO,
38
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
39
+ )
40
+ logger = logging.getLogger('{{ logger_name }}')
41
+
42
+ # Get stage from environment (useful for different API endpoints)
43
+ STAGE = os.getenv("STAGE", "MAINNET").upper()
44
+
45
+
46
+ {% if requires_auth %}
47
+ class AuthMiddleware(Middleware):
48
+ """Middleware to extract and store API keys from Authorization headers."""
49
+
50
+ async def on_request(self, context: MiddlewareContext, call_next):
51
+ """Extract bearer token on each request and bind to context state."""
52
+ try:
53
+ # Access the raw HTTP request
54
+ request: Request = get_http_request()
55
+
56
+ # Debug: log all headers
57
+ logger.info(f"AuthMiddleware: Received request with headers: {dict(request.headers)}")
58
+ logger.info(f"AuthMiddleware: Method: {request.method}, URL: {request.url}")
59
+
60
+ # Extract bearer token from Authorization header
61
+ auth = request.headers.get("Authorization", "")
62
+ token = auth[7:].strip() if auth.lower().startswith("bearer ") else None
63
+
64
+ if not token:
65
+ # Check X-API-KEY header as alternative
66
+ token = request.headers.get("X-API-KEY", "")
67
+
68
+ if token:
69
+ # Store the API key in the context state
70
+ # This will be accessible in tools via get_context()
71
+ if hasattr(context, 'state'):
72
+ context.state.api_key = token
73
+ logger.info(f"API key bound to context state: {token[:10]}...")
74
+ else:
75
+ # Try to store it in the request state as fallback
76
+ request.state.api_key = token
77
+ logger.info(f"API key bound to request state: {token[:10]}...")
78
+ else:
79
+ logger.warning(f"No API key provided in request headers")
80
+
81
+ except Exception as e:
82
+ # This might happen in non-HTTP transports or if get_http_request fails
83
+ logger.debug(f"Could not extract API key from request: {e}")
84
+
85
+ # Proceed with the request (authentication check happens in the tools)
86
+ return await call_next(context)
87
+
88
+
89
+ # Initialize FastMCP server with middleware
90
+ mcp = FastMCP("{{ api_name }} MCP Server", middleware=[AuthMiddleware()])
91
+ {% else %}
92
+ # Initialize FastMCP server
93
+ mcp = FastMCP("{{ api_name }} MCP Server")
94
+ {% endif %}
95
+
96
+
97
+ # Add health check endpoint using FastMCP's custom_route
98
+ @mcp.custom_route("/health", methods=["GET"])
99
+ async def health_check(request: Request) -> JSONResponse:
100
+ """Health check endpoint for container orchestration."""
101
+ return JSONResponse(
102
+ content={
103
+ "status": "healthy",
104
+ "service": "{{ api_slug }}-mcp-server",
105
+ "timestamp": datetime.now().isoformat()
106
+ }
107
+ )
108
+
109
+
110
+ {% if requires_auth %}
111
+ def get_session_api_key(context: Context) -> Optional[str]:
112
+ """Get the API key for the current session."""
113
+ try:
114
+ # Try to get the API key from the context state
115
+ # The middleware should have stored it there
116
+ if hasattr(context, 'state') and hasattr(context.state, 'api_key'):
117
+ return context.state.api_key
118
+
119
+ # Fallback: try to get it from the current HTTP request
120
+ try:
121
+ request: Request = get_http_request()
122
+ if hasattr(request.state, 'api_key'):
123
+ return request.state.api_key
124
+ except Exception:
125
+ pass
126
+
127
+ # If we're in a tool context, try to get the context using the dependency
128
+ try:
129
+ ctx = get_context()
130
+ if hasattr(ctx, 'state') and hasattr(ctx.state, 'api_key'):
131
+ return ctx.state.api_key
132
+ except Exception:
133
+ pass
134
+
135
+ except Exception as e:
136
+ logger.debug(f"Could not retrieve API key from context: {e}")
137
+
138
+ return None
139
+ {% endif %}
140
+
141
+
142
+ # TODO: Add your API-specific functions here
143
+ # Use @retry decorator ONLY for external API calls (not internal functions):
144
+ # @retry(tries=2, delay=1, backoff=2, jitter=(1, 3))
145
+ # def call_{{ api_slug }}_api(query: str, api_key: str) -> Dict[str, Any]:
146
+ # """Call the {{ api_name }} API with the given query."""
147
+ # # You can use STAGE to determine which API endpoint to use:
148
+ # # base_url = "https://api-testnet.example.com" if STAGE == "TESTNET" else "https://api.example.com"
149
+ # # Implement your API logic here (HTTP requests, SDK calls, etc.)
150
+ # pass
151
+
152
+
153
+ @mcp.tool()
154
+ async def example_tool(
155
+ context: Context,
156
+ query: str
157
+ ) -> Dict[str, Any]:
158
+ """
159
+ Example tool for {{ api_name }} API.
160
+
161
+ TODO: Replace this with your actual tool implementation.
162
+
163
+ Args:
164
+ context: MCP context (injected automatically)
165
+ query: Query parameter
166
+
167
+ Returns:
168
+ Dictionary with results
169
+ """
170
+ {% if requires_auth %}
171
+ # Check for API key
172
+ api_key = get_session_api_key(context)
173
+ if not api_key:
174
+ return {"error": "No API key found. Please authenticate with Authorization: Bearer YOUR_API_KEY"}
175
+ {% endif %}
176
+
177
+ # TODO: Implement your tool logic here
178
+ return {
179
+ "status": "success",
180
+ "message": "This is a placeholder. Implement your {{ api_name }} logic here.",
181
+ "query": query,
182
+ "timestamp": datetime.now().isoformat()
183
+ }
184
+
185
+
186
+ @mcp.tool()
187
+ async def get_api_info(context: Context) -> Dict[str, Any]:
188
+ """
189
+ Get information about the {{ api_name }} API service.
190
+
191
+ Args:
192
+ context: MCP context (injected automatically)
193
+
194
+ Returns:
195
+ Dictionary containing API information and status
196
+ """
197
+ {% if requires_auth %}
198
+ # Check authentication status
199
+ api_key = get_session_api_key(context)
200
+ auth_status = "authenticated" if api_key else "not authenticated"
201
+ {% endif %}
202
+
203
+ return {
204
+ "status": "ready",
205
+ {% if requires_auth %}"auth_status": auth_status,{% endif %}
206
+ "api_name": "{{ api_name }}",
207
+ "api_url": "{{ api_url }}",
208
+ "documentation": "{{ docs_url }}",
209
+ "description": "{{ api_description|capitalize }}",
210
+ {% if requires_auth %}"authentication": "Bearer token required in Authorization header"{% else %}"authentication": "No authentication required"{% endif %}
211
+ }
212
+
213
+
214
+ def run_server():
215
+ """Entry point for the executable script"""
216
+ logger.info("Starting {{ api_name }} MCP server{{ auth_description }}...")
217
+ {% if requires_auth %}
218
+ logger.info("Authentication: Clients must provide Authorization: Bearer YOUR_API_KEY")
219
+ {% endif %}
220
+
221
+ # Get configuration from environment
222
+ port = int(os.getenv("PORT", "8000"))
223
+ log_level = os.getenv("LOG_LEVEL", "INFO")
224
+ logger.info(f"Server will listen on port {port}")
225
+
226
+ try:
227
+ mcp.run(
228
+ transport="streamable-http",
229
+ port=port,
230
+ host="0.0.0.0",
231
+ path="/mcp",
232
+ log_level=log_level.lower()
233
+ )
234
+ except Exception as e:
235
+ logger.error(f"Error starting MCP server: {e}")
236
+ raise
237
+
238
+
239
+ if __name__ == "__main__":
240
+ run_server()