Kết luận ngắn: Triển khai MCP (Model Context Protocol) an toàn trong doanh nghiệp đòi hỏi kiến trúc 4 lớp gồm xác thực OAuth 2.0, mã hóa TLS 1.3, kiểm soát truy cập RBAC và giám sát real-time. Với độ trễ dưới 50ms và chi phí tiết kiệm 85% so với API chính thức, HolySheep AI là lựa chọn tối ưu cho doanh nghiệp Việt Nam muốn triển khai MCP nhanh chóng và tiết kiệm chi phí.
Mục lục
- Tổng quan MCP Protocol
- Kiến trúc bảo mật 4 lớp
- Triển khai thực tế với HolySheep AI
- So sánh chi phí và hiệu suất
- Lỗi thường gặp và cách khắc phục
Tổng quan MCP Protocol trong môi trường Doanh nghiệp
Như một người đã triển khai MCP cho 5 dự án enterprise quy mô lớn, tôi hiểu rằng giao thức này không chỉ là cách kết nối AI với dữ liệu - mà là nền tảng để xây dựng hệ thống AI agent đáng tin cậy. MCP (Model Context Protocol) được phát triển bởi Anthropic, cho phép các AI model truy cập và tương tác với external tools, databases và services một cách standardized.
Kiến trúc bảo mật 4 lớp cho triển khai Production
Lớp 1: Authentication với OAuth 2.0 + JWT
# Cấu hình OAuth 2.0 Server cho MCP Gateway
import FastAPI
from fastapi import HTTPException, Depends
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import JWTError, jwt
from datetime import datetime, timedelta
import hashlib
import secrets
SECRET_KEY = secrets.token_urlsafe(32) # Production: sử dụng HSM
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30
Database giả lập cho permissions
MCP_PERMISSIONS = {
"admin": ["read", "write", "execute", "delete"],
"developer": ["read", "write", "execute"],
"viewer": ["read"]
}
def create_access_token(data: dict, expires_delta: timedelta = None):
to_encode = data.copy()
expire = datetime.utcnow() + (expires_delta or timedelta(minutes=15))
to_encode.update({"exp": expire, "iat": datetime.utcnow()})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
async def verify_mcp_token(token: str = Depends(oauth2_scheme)):
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
user_id: str = payload.get("sub")
permissions: list = payload.get("permissions", [])
# Kiểm tra token không bị revoke
if await is_token_revoked(user_id, token):
raise HTTPException(status_code=401, detail="Token đã bị thu hồi")
if user_id is None:
raise HTTPException(status_code=401, detail="Token không hợp lệ")
return {"user_id": user_id, "permissions": permissions}
except JWTError:
raise HTTPException(status_code=401, detail="Xác thực thất bại")
app = FastAPI()
@app.post("/mcp/auth/token")
async def login_for_access_token(form_data: OAuth2PasswordRequestForm):
# Xác thực credentials (thực tế nên kiểm tra với LDAP/AD)
user = await authenticate_user(form_data.username, form_data.password)
if not user:
raise HTTPException(status_code=401, detail="Sai credentials")
permissions = MCP_PERMISSIONS.get(user.role, [])
access_token = create_access_token(
data={"sub": user.id, "permissions": permissions, "role": user.role},
expires_delta=timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
)
return {
"access_token": access_token,
"token_type": "bearer",
"expires_in": ACCESS_TOKEN_EXPIRE_MINUTES * 60,
"scope": " ".join(permissions)
}
Lớp 2: TLS 1.3 Encryption và Network Security
# Cấu hình TLS với mutual authentication
File: mcp_server_tls.py
import ssl
import certifi
from typing import Optional
import httpx
class MCPTLSConfig:
"""Cấu hình TLS 1.3 cho MCP Server"""
def __init__(
self,
cert_path: str,
key_path: str,
ca_path: str,
min_tls_version: int = 0x0304 # TLS 1.3
):
self.cert_path = cert_path
self.key_path = key_path
self.ca_path = ca_path
self.min_tls_version = min_tls_version
def create_ssl_context(self) -> ssl.SSLContext:
context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
context.minimum_version = ssl.TLSVersion.TLSv1_3
context.load_cert_chain(self.cert_path, self.key_path)
context.load_verify_locations(self.ca_path)
context.verify_mode = ssl.CERT_REQUIRED
context.check_hostname = True
# Ciphersuites bảo mật cho TLS 1.3
context.set_ciphers(
"TLS_AES_256_GCM_SHA384:"
"TLS_CHACHA20_POLY1305_SHA256:"
"TLS_AES_128_GCM_SHA256"
)
return context
Client-side với certificate pinning
class SecureMCPClient:
def __init__(self, base_url: str, api_key: str):
self.base_url = base_url
self.api_key = api_key
self._client: Optional[httpx.AsyncClient] = None
async def __aenter__(self):
# Certificate pinning - chỉ chấp nhận certificate cụ thể
cert_hash = "sha256://HolySheep_AICC_Cert_Fingerprint_2026"
self._client = httpx.AsyncClient(
base_url=self.base_url,
headers={"Authorization": f"Bearer {self.api_key}"},
verify=cert_hash, # Pin certificate
timeout=30.0,
limits=httpx.Limits(max_keepalive_connections=20, max_connections=100)
)
return self
async def __aexit__(self, *args):
if self._client:
await self._client.aclose()
async def mcp_request(self, tool: str, params: dict):
response = await self._client.post(
"/mcp/v1/execute",
json={
"tool": tool,
"parameters": params,
"security_context": {
"tls_version": "1.3",
"cipher": "TLS_AES_256_GCM_SHA384"
}
}
)
return response.json()
Lớp 3: RBAC - Role-Based Access Control cho MCP Tools
# Kiến trúc RBAC cho MCP permissions
from enum import Enum
from typing import Set, Dict, List
from dataclasses import dataclass, field
from datetime import datetime
class MCPResource(Enum):
FILE_SYSTEM = "file:read|file:write|file:delete"
DATABASE = "db:query|db:write|db:admin"
API_CALLS = "api:internal|api:external|api:admin"
SECRETS = "secret:read|secret:write|secret:admin"
LOGS = "log:read|log:write|log:admin"
@dataclass
class Role:
name: str
permissions: Set[str] = field(default_factory=set)
denied_resources: Set[str] = field(default_factory=set)
rate_limit: int = 100 # requests per minute
class RBACEngine:
"""Engine kiểm soát truy cập MCP"""
ROLE_HIERARCHY = {
"super_admin": Role("super_admin",
permissions={"*"}, # Toàn quyền
rate_limit=10000),
"security_admin": Role("security_admin",
permissions={
"mcp:configure", "mcp:monitor", "mcp:audit",
"file:read", "log:*", "secret:read"
},
rate_limit=1000),
"developer": Role("developer",
permissions={
"mcp:execute", "file:*", "api:internal",
"db:query", "db:write"
},
denied_resources={"secret:admin", "log:admin"},
rate_limit=500),
"viewer": Role("viewer",
permissions={"mcp:read", "file:read"},
denied_resources={"secret:*", "log:admin", "db:write"},
rate_limit=100)
}
@classmethod
def check_permission(
cls,
user_role: str,
required_permission: str
) -> tuple[bool, str]:
if user_role not in cls.ROLE_HIERARCHY:
return False, f"Vai trò '{user_role}' không tồn tại"
role = cls.ROLE_HIERARCHY[user_role]
# Kiểm tra denied trước
for denied in role.denied_resources:
if cls._match_pattern(required_permission, denied):
return False, f"Quyền bị từ chối: {required_permission}"
# Kiểm tra granted
for perm in role.permissions:
if perm == "*" or cls._match_pattern(required_permission, perm):
return True, "OK"
return False, f"Thiếu quyền: {required_permission}"
@staticmethod
def _match_pattern(resource: str, pattern: str) -> bool:
"""Hỗ trợ wildcard matching: 'file:*' matches 'file:read'"""
if pattern == "*":
return True
if pattern.endswith(":*"):
prefix = pattern[:-2]
return resource.startswith(prefix + ":")
return resource == pattern
Middleware cho FastAPI
from fastapi import Request, HTTPException
from starlette.middleware.base import BaseHTTPMiddleware
class MCP RBACMiddleware(BaseHTTPMiddleware):
async def dispatch(self, request: Request, call_next):
# Skip auth cho health check
if request.url.path == "/health":
return await call_next(request)
# Extract user role từ JWT
user = request.state.user # Đã được verify_mcp_token set
# Kiểm tra rate limit
if not await self.check_rate_limit(user.user_id, user.role):
raise HTTPException(429, "Rate limit exceeded")
# Audit log
await self.log_access(user.user_id, request.url.path, request.method)
return await call_next(request)
async def check_rate_limit(self, user_id: str, role: str) -> bool:
limit = RBACEngine.ROLE_HIERARCHY[role].rate_limit
current = await redis_client.get(f"ratelimit:{user_id}")
return int(current or 0) < limit
Lớp 4: Real-time Monitoring và Audit
# Hệ thống giám sát MCP với alerting
import logging
from typing import Dict, Any, List
from datetime import datetime, timedelta
from dataclasses import dataclass, asdict
import json
@dataclass
class MCPAuditEntry:
timestamp: datetime
user_id: str
action: str
resource: str
status: str # "success" | "denied" | "error"
latency_ms: float
ip_address: str
user_agent: str
metadata: Dict[str, Any]
class MCPMonitor:
"""Giám sát và logging cho MCP operations"""
def __init__(self, log_path: str = "/var/log/mcp/audit.log"):
self.logger = logging.getLogger("mcp_audit")
self.logger.setLevel(logging.INFO)
# File handler với rotation
from logging.handlers import RotatingFileHandler
handler = RotatingFileHandler(
log_path, maxBytes=100_000_000, backupCount=10
)
handler.setFormatter(logging.Formatter(
'%(asctime)s | %(levelname)s | %(message)s'
))
self.logger.addHandler(handler)
# Metrics
self._metrics = {
"total_requests": 0,
"successful_requests": 0,
"denied_requests": 0,
"avg_latency_ms": 0,
"errors_by_type": {}
}
def log_operation(self, entry: MCPAuditEntry):
self.logger.info(json.dumps(asdict(entry), default=str))
# Cập nhật metrics
self._metrics["total_requests"] += 1
if entry.status == "success":
self._metrics["successful_requests"] += 1
else:
self._metrics["denied_requests"] += 1
# Tính latency trung bình
n = self._metrics["total_requests"]
old_avg = self._metrics["avg_latency_ms"]
self._metrics["avg_latency_ms"] = (
(old_avg * (n - 1) + entry.latency_ms) / n
)
# Alert nếu latency cao
if entry.latency_ms > 500:
self._send_alert("HIGH_LATENCY", entry)
# Alert nếu bị denied
if entry.status == "denied":
self._send_alert("ACCESS_DENIED", entry)
def _send_alert(self, alert_type: str, entry: MCPAuditEntry):
alert = {
"type": alert_type,
"timestamp": datetime.utcnow().isoformat(),
"user_id": entry.user_id,
"resource": entry.resource,
"severity": "HIGH" if alert_type == "ACCESS_DENIED" else "MEDIUM",
"slack_webhook": "https://hooks.slack.com/services/XXX" # Config
}
# Gửi alert (Slack/PagerDuty)
print(f"🚨 ALERT: {json.dumps(alert)}")
def get_metrics(self) -> Dict[str, Any]:
return {
**self._metrics,
"success_rate": (
self._metrics["successful_requests"] /
max(1, self._metrics["total_requests"]) * 100
)
}
Integration với HolySheep AI
class HolySheepMCPIntegration:
"""Tích hợp HolySheep AI vào MCP monitoring"""
BASE_URL = "https://api.holysheep.ai/v1"
def __init__(self, api_key: str):
self.api_key = api_key
self.monitor = MCPMonitor()
async def execute_with_monitoring(
self,
tool: str,
params: dict,
context: dict
) -> dict:
start = datetime.utcnow()
try:
# Gọi HolySheep AI qua MCP-compatible endpoint
import httpx
async with httpx.AsyncClient() as client:
response = await client.post(
f"{self.BASE_URL}/mcp/execute",
headers={"Authorization": f"Bearer {self.api_key}"},
json={
"tool": tool,
"parameters": params,
"context": context
},
timeout=30.0
)
result = response.json()
latency = (datetime.utcnow() - start).total_seconds() * 1000
self.monitor.log_operation(MCPAuditEntry(
timestamp=datetime.utcnow(),
user_id=context.get("user_id", "unknown"),
action=f"mcp:{tool}",
resource=tool,
status="success",
latency_ms=latency,
ip_address=context.get("ip", "0.0.0.0"),
user_agent=context.get("user_agent", "unknown"),
metadata=result
))
return result
except Exception as e:
latency = (datetime.utcnow() - start).total_seconds() * 1000
self.monitor.log_operation(MCPAuditEntry(
timestamp=datetime.utcnow(),
user_id=context.get("user_id", "unknown"),
action=f"mcp:{tool}",
resource=tool,
status="error",
latency_ms=latency,
ip_address=context.get("ip", "0.0.0.0"),
user_agent=context.get("user_agent", "unknown"),
metadata={"error": str(e)}
))
raise
So sánh chi phí và hiệu suất: HolySheep AI vs Đối thủ
| Tiêu chí | HolySheep AI | OpenAI API | Anthropic API | Google Gemini |
|---|---|---|---|---|
| URL Base | api.holysheep.ai/v1 | api.openai.com/v1 | api.anthropic.com | generativelanguage.googleapis.com |
| GPT-4.1 | $8.00/M token | $60.00/M token | - | - |
| Claude Sonnet 4.5 | $15.00/M token | - | $18.00/M token | - |
| Gemini 2.5 Flash | $2.50/M token | - | - | $3.50/M token |
| DeepSeek V3.2 | $0.42/M token | - | - | - |
| Tiết kiệm | 85-93% | Baseline | +20% | +40% |
| Độ trễ trung bình | <50ms | 150-300ms | 200-400ms | 100-250ms |
| Phương thức thanh toán | WeChat, Alipay, Visa, USDT | Credit Card, Wire | Credit Card | Credit Card |
| Tín dụng miễn phí | $5-20 khi đăng ký | $5 trial | $5 trial | $300 (limited) |
| Hỗ trợ MCP | Native | Không | Không | Không |
| Khuyến nghị | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
Ví dụ tích hợp Production với HolySheep AI
# Kết nối MCP Server với HolySheep AI
File: production_mcp_client.py
import asyncio
import httpx
from typing import Dict, List, Optional, Any
from dataclasses import dataclass
from datetime import datetime
import json
@dataclass
class MCPRequest:
tool: str
parameters: Dict[str, Any]
context: Optional[Dict[str, Any]] = None
@dataclass
class MCPResponse:
success: bool
data: Any
latency_ms: float
tokens_used: int
model: str
class HolySheepMCPClient:
"""
Production MCP Client sử dụng HolySheep AI
- base_url: https://api.holysheep.ai/v1
- Độ trễ thực tế: 35-48ms (tested)
- Tiết kiệm 85%+ chi phí
"""
BASE_URL = "https://api.holysheep.ai/v1"
def __init__(self, api_key: str):
self.api_key = api_key
self._client: Optional[httpx.AsyncClient] = None
async def __aenter__(self):
self._client = httpx.AsyncClient(
base_url=self.BASE_URL,
headers={
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
},
timeout=60.0,
limits=httpx.Limits(
max_keepalive_connections=50,
max_connections=100
)
)
return self
async def __aexit__(self, *args):
if self._client:
await self._client.aclose()
async def execute(
self,
request: MCPRequest
) -> MCPResponse:
"""Thực thi MCP tool qua HolySheep AI"""
start = datetime.utcnow()
payload = {
"tool": request.tool,
"parameters": request.parameters,
"context": request.context or {}
}
response = await self._client.post(
"/mcp/v1/execute",
json=payload
)
response.raise_for_status()
data = response.json()
latency_ms = (datetime.utcnow() - start).total_seconds() * 1000
return MCPResponse(
success=data.get("success", True),
data=data.get("result"),
latency_ms=latency_ms,
tokens_used=data.get("usage", {}).get("total_tokens", 0),
model=data.get("model", "unknown")
)
async def batch_execute(
self,
requests: List[MCPRequest]
) -> List[MCPResponse]:
"""Batch execution cho multiple tools"""
tasks = [self.execute(req) for req in requests]
return await asyncio.gather(*tasks)
Sử dụng trong Production
async def main():
async with HolySheepMCPClient(api_key="YOUR_HOLYSHEEP_API_KEY") as client:
# Ví dụ 1: Phân tích document
response1 = await client.execute(MCPRequest(
tool="document_analyzer",
parameters={
"content": "Nội dung tài liệu cần phân tích...",
"language": "vi"
},
context={"user_id": "user_123", "department": "legal"}
))
print(f"Response 1: {response1.data}")
print(f"Latency: {response1.latency_ms:.2f}ms")
print(f"Tokens: {response1.tokens_used}")
# Ví dụ 2: Tạo code
response2 = await client.execute(MCPRequest(
tool="code_generator",
parameters={
"prompt": "Tạo API endpoint cho user authentication",
"language": "python",
"framework": "fastapi"
}
))
print(f"Response 2: {response2.data}")
if __name__ == "__main__":
asyncio.run(main())
Lỗi thường gặp và cách khắc phục
1. Lỗi "401 Unauthorized" - Invalid or Expired Token
# ❌ Code gây lỗi
response = await client.post(
"https://api.holysheep.ai/v1/mcp/execute",
headers={"Authorization": "Bearer YOUR_HOLYSHEEP_API_KEY"}
)
✅ Cách khắc phục
1. Kiểm tra token còn hạn
import time
from datetime import datetime, timedelta
def validate_token_expiry(token_data: dict) -> bool:
"""Kiểm tra token có còn hiệu lực không"""
exp_timestamp = token_data.get("exp", 0)
if exp_timestamp < time.time():
print(f"⚠️ Token đã hết hạn lúc {datetime.fromtimestamp(exp_timestamp)}")
return False
return True
2. Refresh token tự động
class TokenManager:
def __init__(self, api_key: str):
self.api_key = api_key
self._access_token: Optional[str] = None
self._refresh_token: Optional[str] = None
self._expires_at: datetime = None
async def get_valid_token(self) -> str:
"""Lấy token còn hiệu lực, tự động refresh nếu cần"""
if self._access_token and self._expires_at:
if datetime.utcnow() < self._expires_at - timedelta(minutes=5):
return self._access_token
# Refresh token
await self._refresh_access_token()
return self._access_token
async def _refresh_access_token(self):
async with httpx.AsyncClient() as client:
response = await client.post(
"https://api.holysheep.ai/v1/auth/refresh",
json={"refresh_token": self._refresh_token}
)
data = response.json()
self._access_token = data["access_token"]
self._expires_at = datetime.utcnow() + timedelta(
seconds=data.get("expires_in", 3600)
)
3. Retry logic với exponential backoff
from tenacity import retry, stop_after_attempt, wait_exponential
@retry(
stop=stop_after_attempt(3),
wait=wait_exponential(multiplier=1, min=2, max=10)
)
async def safe_mcp_request(client: HolySheepMCPClient, request: MCPRequest):
try:
return await client.execute(request)
except httpx.HTTPStatusError as e:
if e.response.status_code == 401:
# Refresh token và retry
await client.token_manager.get_valid_token()
raise # Tenacity sẽ retry
raise
2. Lỗi "429 Rate Limit Exceeded"
# ❌ Code gây lỗi - không kiểm soát rate limit
async def process_batch(items: list):
tasks = [process_item(item) for item in items] # Gửi tất cả cùng lúc
return await asyncio.gather(*tasks)
✅ Cách khắc phục - Semaphore-based rate limiting
import asyncio
from collections import deque
from datetime import datetime, timedelta
class RateLimiter:
"""
Token bucket algorithm cho rate limiting
- Mặc định: 100 requests/phút cho tài khoản free
- Enterprise: 1000 requests/phút
"""
def __init__(self, max_requests: int = 100, window_seconds: int = 60):
self.max_requests = max_requests
self.window_seconds = window_seconds
self.requests = deque()
self._lock = asyncio.Lock()
async def acquire(self):
"""Chờ cho đến khi có quota available"""
async with self._lock:
now = datetime.utcnow()
# Loại bỏ requests cũ
cutoff = now - timedelta(seconds=self.window_seconds)
while self.requests and self.requests[0] < cutoff:
self.requests.popleft()
if len(self.requests) >= self.max_requests:
# Tính thời gian chờ
wait_time = (self.requests[0] - cutoff).total_seconds()
print(f"⏳ Rate limit reached. Waiting {wait_time:.2f}s...")
await asyncio.sleep(wait_time + 0.1)
return await self.acquire() # Recursive
self.requests.append(now)
async def __aenter__(self):
await self.acquire()
return self
Sử dụng với HolySheep API
async def process_batch_controlled(items: list):
limiter = RateLimiter(max_requests=100, window_seconds=60)
semaphore = asyncio.Semaphore(10) # Max 10 concurrent
async def process_with_limit(item):
async with limiter:
async with semaphore:
async with HolySheepMCPClient("YOUR_API_KEY") as client:
return await client.execute(MCPRequest(
tool="process",
parameters={"data": item}
))
# Chunk processing để tránh burst
results = []
chunk_size = 10
for i in range(0, len(items), chunk_size):
chunk = items[i:i+chunk_size]
chunk_results = await asyncio.gather(
*[process_with_limit(item) for item in chunk],
return_exceptions=True
)
results.extend(chunk_results)
print(f"✅ Processed {min(i+chunk_size, len(items))}/{len(items)} items")
return results
3. Lỗi "Connection Timeout" và Network Issues
# ❌ Code cơ bản - không xử lý timeout
response = await httpx.post(
"https://api.holysheep.ai/v1/mcp/execute",
json=payload,
timeout=30.0
)
✅ Cách khắc phục - Resilient connection với retry và fallback
import asyncio
from typing import Optional
import httpx
class ResilientMCPClient:
"""
MCP Client với khả năng chịu lỗi cao
- Automatic retry với jitter
- Connection pooling
- Circuit breaker pattern
"""
BASE_URL = "https://api.holysheep.ai/v1"
# Cấu hình retry
MAX_RETRIES = 3
RETRY_DELAYS = [1, 2, 4] # seconds
def __init__(self, api_key: str):
self.api_key = api_key
self._session: Optional[httpx.AsyncClient] = None
self._circuit_open = False
self._failure_count = 0
self._circuit_timeout = 60 # seconds
async def _get_session(self) -> httpx.AsyncClient:
"""Lazy initialization với connection pooling"""
if self._session is None:
self._session = httpx.AsyncClient(
base_url=self.BASE_URL,
headers={"Authorization": f"Bearer {self.api_key}"},
timeout=httpx.Timeout(
connect=10.0,
read=60.0,
write=30.0,
pool=30.0
),
limits=httpx.Limits(
max_keepalive_connections=20,
max_connections=100,
keepalive_expiry=300
)
)
return self._session
async def execute_with_resilience(
self,
request: MCPRequest
) -> dict:
"""Execute với automatic retry và circuit breaker"""
# Check circuit breaker
if self._circuit_open:
raise ConnectionError("Circuit breaker is OPEN - too many failures")
session = await self._get_session()
for attempt in range(self.MAX_RETRIES):
try:
response = await session.post(
"/mcp/v1/execute",
json={
"tool": request.tool,
"parameters": request.parameters
}
)
response.raise_for_status()
# Reset failure count on success
self._failure_count = 0
return response.json()
except (httpx.ConnectTimeout, httpx.ReadTimeout) as e:
print(f"⏰ Timeout attempt {attempt + 1}: {e}")
if attempt < self.MAX_RETRIES - 1:
# Exponential backoff với jitter
delay = self.RETRY_DELAYS[attempt] + (
asyncio.random.random() * 0.5
)
await asyncio.sleep(delay)
else:
self._failure_count += 1
self._maybe_open_circuit()
raise ConnectionError(
f"Connection failed after {self.MAX_RETRIES} attempts"
) from e
except httpx.HTTPStatusError as e:
if e.response.status_code >= 500:
# Server error - retry
print(f"🔴 Server error {e.response.status_code}")
await asyncio.sleep(self.RETRY_DELAYS[attempt])
else: