AgentKit / app.py
PD03's picture
Update app.py
877dbfb verified
import os
import requests
from fastapi import FastAPI, HTTPException, Depends
from fastapi.responses import JSONResponse
from fastapi.security.api_key import APIKeyHeader
from fastapi.middleware.cors import CORSMiddleware
# -------------------------------------------------
# CONFIGURATION
# -------------------------------------------------
HUGGINGFACE_BACKEND = os.getenv(
"SAP_BACKEND_URL",
"https://sandbox.api.sap.com/s4hanacloud/sap/opu/odata4/"
"sap/api_purchaseorder_2/srvd_a2x/sap/purchaseorder/0001/PurchaseOrder?$top=10"
)
AGENTKIT_API_KEY = os.getenv("AGENTKIT_API_KEY", None)
BASE_URL = os.getenv("PUBLIC_URL", "https://pd03-agentkit.hf.space") # your Space URL
app = FastAPI(
title="SAP MCP Server",
description="MCP-compatible FastAPI server exposing live SAP Purchase Orders for demo and AgentKit integration.",
version="2.0.0",
)
# -------------------------------------------------
# CORS MIDDLEWARE (needed for Google AI Studio / front-end calls)
# -------------------------------------------------
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # for demo; restrict later if desired
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# -------------------------------------------------
# AUTHENTICATION
# -------------------------------------------------
api_key_header = APIKeyHeader(name="x-agentkit-api-key", auto_error=False)
def verify_api_key(api_key: str = Depends(api_key_header)):
"""Verifies the x-agentkit-api-key header, if configured."""
if AGENTKIT_API_KEY is None:
# open mode
return True
if api_key != AGENTKIT_API_KEY:
raise HTTPException(status_code=401, detail="Invalid or missing API key")
return True
# -------------------------------------------------
# MCP MANIFEST (for AgentKit autodiscovery)
# -------------------------------------------------
@app.get("/.well-known/mcp/manifest.json", include_in_schema=False)
async def get_manifest():
"""Manifest describing this MCP server and its tools."""
manifest = {
"name": "sap_mcp_server",
"description": "MCP server exposing a tool for retrieving SAP purchase orders from the SAP Sandbox API.",
"version": "2.0.0",
"auth": {
"type": "api_key",
"location": "header",
"header_name": "x-agentkit-api-key",
"description": "Custom header used to authenticate MCP requests."
},
"tools": [
{
"name": "get_purchase_orders",
"description": "Fetches the top 10 purchase orders from the SAP Sandbox API.",
"input_schema": {"type": "object", "properties": {}},
"output_schema": {"type": "object"},
"http": {"method": "GET", "url": f"{BASE_URL}/tools/get_purchase_orders"}
}
]
}
return JSONResponse(content=manifest)
# -------------------------------------------------
# TOOL: Fetch Purchase Orders
# -------------------------------------------------
@app.get("/tools/get_purchase_orders", tags=["MCP Tools"])
async def get_purchase_orders(auth=Depends(verify_api_key)):
"""
Fetch the top purchase orders from SAP Sandbox API.
Requires SAP_API_KEY secret and a valid SAP_BACKEND_URL.
"""
sap_api_key = os.getenv("SAP_API_KEY")
if not sap_api_key:
raise HTTPException(status_code=500, detail="SAP_API_KEY not set in environment")
headers = {"APIKey": sap_api_key}
try:
print(f"πŸ“‘ Calling SAP Sandbox: {HUGGINGFACE_BACKEND}")
resp = requests.get(HUGGINGFACE_BACKEND, headers=headers, timeout=60)
resp.raise_for_status()
data = resp.json()
records = data.get("value", [])
print(f"βœ… SAP API returned {len(records)} records")
return {
"source": "SAP Sandbox",
"count": len(records),
"data": records
}
except requests.exceptions.HTTPError as e:
print(f"❌ SAP API HTTP error: {e}")
raise HTTPException(status_code=resp.status_code, detail=f"SAP API error: {e.response.text}")
except Exception as e:
print(f"❌ SAP API general error: {e}")
raise HTTPException(status_code=500, detail=f"Failed to call SAP API: {e}")
# -------------------------------------------------
# HEALTH CHECK
# -------------------------------------------------
@app.get("/health", tags=["System"])
async def health():
return {"status": "ok", "message": "SAP MCP Server is running"}
# -------------------------------------------------
# ROOT (friendly landing page)
# -------------------------------------------------
@app.get("/", tags=["Root"])
async def root():
return {
"message": "πŸ‘‹ Welcome to the SAP MCP Server",
"available_endpoints": {
"health": "/health",
"manifest": "/.well-known/mcp/manifest.json",
"purchase_orders": "/tools/get_purchase_orders"
},
"instructions": "Use /tools/get_purchase_orders with header x-agentkit-api-key to fetch live SAP sandbox data."
}