| | 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 |
| |
|
| | |
| | |
| | |
| | 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") |
| |
|
| | 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", |
| | ) |
| |
|
| | |
| | |
| | |
| | app.add_middleware( |
| | CORSMiddleware, |
| | allow_origins=["*"], |
| | allow_credentials=True, |
| | allow_methods=["*"], |
| | allow_headers=["*"], |
| | ) |
| |
|
| | |
| | |
| | |
| | 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: |
| | |
| | return True |
| | if api_key != AGENTKIT_API_KEY: |
| | raise HTTPException(status_code=401, detail="Invalid or missing API key") |
| | return True |
| |
|
| |
|
| | |
| | |
| | |
| | @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) |
| |
|
| |
|
| | |
| | |
| | |
| | @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}") |
| |
|
| |
|
| | |
| | |
| | |
| | @app.get("/health", tags=["System"]) |
| | async def health(): |
| | return {"status": "ok", "message": "SAP MCP Server is running"} |
| |
|
| |
|
| | |
| | |
| | |
| | @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." |
| | } |
| |
|