chore(opax-mcp): document public MCP deployment
This commit is contained in:
parent
14d61b131f
commit
592944041f
9
.dockerignore
Normal file
9
.dockerignore
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
spire-1.15.3/data
|
||||||
|
.venv
|
||||||
|
.venv-flake8
|
||||||
|
__pycache__
|
||||||
|
*.pyc
|
||||||
|
*.pyo
|
||||||
|
*.pyd
|
||||||
|
.pytest_cache
|
||||||
|
.coverage
|
||||||
8
.gitignore
vendored
8
.gitignore
vendored
|
|
@ -11,6 +11,14 @@ dist/
|
||||||
|
|
||||||
# Virtual environments
|
# Virtual environments
|
||||||
.venv/
|
.venv/
|
||||||
|
.venv-flake8/
|
||||||
|
opax-mcp/tmp_venv/
|
||||||
|
spire-1.15.3/
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
.env.*
|
||||||
|
erver.py fix
|
||||||
|
h to use --no-cache and correct secret mount
|
||||||
venv/
|
venv/
|
||||||
env/
|
env/
|
||||||
.env
|
.env
|
||||||
|
|
|
||||||
15
Dockerfile
Normal file
15
Dockerfile
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
FROM python:3.11-slim
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY requirements.txt .
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
ENV PORT=8080
|
||||||
|
ENV PYTHONUNBUFFERED=1
|
||||||
|
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8080"]
|
||||||
7
cloudbuild.opax-mcp.yaml
Normal file
7
cloudbuild.opax-mcp.yaml
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
steps:
|
||||||
|
- name: 'gcr.io/cloud-builders/docker'
|
||||||
|
args: ['build', '-t', 'us-central1-docker.pkg.dev/propane-will-491900-m5/osvauco-repo/opax-mcp:latest', './opax-mcp']
|
||||||
|
- name: 'gcr.io/cloud-builders/docker'
|
||||||
|
args: ['push', 'us-central1-docker.pkg.dev/propane-will-491900-m5/osvauco-repo/opax-mcp:latest']
|
||||||
|
images:
|
||||||
|
- 'us-central1-docker.pkg.dev/propane-will-491900-m5/osvauco-repo/opax-mcp:latest'
|
||||||
|
|
@ -18,7 +18,7 @@ echo "=== 3. Push image ==="
|
||||||
docker push "${FULL_IMAGE}"
|
docker push "${FULL_IMAGE}"
|
||||||
|
|
||||||
echo "=== 4. Deploy with pre-built image ==="
|
echo "=== 4. Deploy with pre-built image ==="
|
||||||
gcloud run deploy "${SERVICE}" --image="${FULL_IMAGE}" --region="${REGION}" --service-account="jason-vauger@${PROJECT}.iam.gserviceaccount.com" --set-secrets="MCPSECRET=mcp-server-key:latest" --no-allow-unauthenticated --port=8080 --memory=512Mi --cpu=1 --min-instances=0 --max-instances=2 --quiet
|
gcloud run deploy "${SERVICE}" --image="${FULL_IMAGE}" --region="${REGION}" --service-account="jason-vauger@${PROJECT}.iam.gserviceaccount.com" --set-secrets="MCPSECRET=mcp-server-key:latest" --allow-unauthenticated --port=8080 --memory=512Mi --cpu=1 --min-instances=0 --max-instances=2 --quiet
|
||||||
|
|
||||||
echo "=== 5. Verify ==="
|
echo "=== 5. Verify ==="
|
||||||
SVC_URL=$(gcloud run services describe "${SERVICE}" --region="${REGION}" --format='value(status.url)')
|
SVC_URL=$(gcloud run services describe "${SERVICE}" --region="${REGION}" --format='value(status.url)')
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,11 @@ spec:
|
||||||
secretKeyRef:
|
secretKeyRef:
|
||||||
key: latest
|
key: latest
|
||||||
name: TWILIO_FROM_NUMBER
|
name: TWILIO_FROM_NUMBER
|
||||||
|
- name: MCPSECRET
|
||||||
|
valueFrom:
|
||||||
|
secretKeyRef:
|
||||||
|
key: latest
|
||||||
|
name: mcp-server-key
|
||||||
image: us-central1-docker.pkg.dev/propane-will-491900-m5/osvauco-repo/opax-mcp:latest
|
image: us-central1-docker.pkg.dev/propane-will-491900-m5/osvauco-repo/opax-mcp:latest
|
||||||
name: opax-mcp-1
|
name: opax-mcp-1
|
||||||
ports:
|
ports:
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,12 @@ logger.info(f"OLLAMA_BASE_URL: {OLLAMA_BASE_URL}")
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
async def _verify_auth(request: Request) -> None:
|
async def _verify_auth(request: Request) -> None:
|
||||||
|
logger.info(
|
||||||
|
"MCP auth attempt: has_api_key=%s has_x_mcp_secret=%s has_bearer=%s",
|
||||||
|
bool(request.headers.get("api-key")),
|
||||||
|
bool(request.headers.get("X-MCP-Secret")),
|
||||||
|
request.headers.get("Authorization", "").startswith("Bearer "),
|
||||||
|
)
|
||||||
secret = os.getenv("MCPSECRET") or os.getenv("MCP_SECRET", "")
|
secret = os.getenv("MCPSECRET") or os.getenv("MCP_SECRET", "")
|
||||||
secret = secret.strip()
|
secret = secret.strip()
|
||||||
if not secret:
|
if not secret:
|
||||||
|
|
@ -81,8 +87,6 @@ async def _verify_auth(request: Request) -> None:
|
||||||
if auth_header.startswith("Bearer "):
|
if auth_header.startswith("Bearer "):
|
||||||
token = auth_header[7:]
|
token = auth_header[7:]
|
||||||
|
|
||||||
print(f"DEBUG: token={repr(token)} secret={repr(secret)} match={token==secret if token and secret else False}")
|
|
||||||
|
|
||||||
if not token or token != secret:
|
if not token or token != secret:
|
||||||
raise HTTPException(status_code=401, detail="Invalid or missing API key")
|
raise HTTPException(status_code=401, detail="Invalid or missing API key")
|
||||||
def _agent_headers() -> dict:
|
def _agent_headers() -> dict:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user