Backup automatico script del 2026-09-29 07:00

This commit is contained in:
daniele committed 2026-09-29 07:00:02 +02:00
1 parent 09dcbbdadb
commit a8ddcdd255
2 files changed
+83 -9

No files matched your search

+79 -8
View File
@@ -11,7 +11,7 @@ from typing import Optional
import anyio import anyio
from fastapi import Depends, FastAPI, Form, HTTPException, Request, Response from fastapi import Depends, FastAPI, Form, HTTPException, Request, Response
from fastapi.middleware.cors import CORSMiddleware from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse from fastapi.responses import HTMLResponse, JSONResponse, RedirectResponse, StreamingResponse
from pydantic import BaseModel from pydantic import BaseModel
from starlette.concurrency import run_in_threadpool from starlette.concurrency import run_in_threadpool
@@ -30,7 +30,7 @@ app.add_middleware(
"https://chatgpt.com", "https://chatgpt.com",
"https://chat.openai.com", "https://chat.openai.com",
], ],
allow_methods=["GET", "POST", "OPTIONS"], allow_methods=["GET", "POST", "HEAD", "OPTIONS"],
allow_headers=["*"], allow_headers=["*"],
) )
STATIC_DIR = os.path.join(os.path.dirname(__file__), "static") STATIC_DIR = os.path.join(os.path.dirname(__file__), "static")
@@ -226,8 +226,10 @@ _UNAUTHENTICATED_METHODS = ("initialize", "notifications/initialized", "ping")
async def mcp_post(request: Request): async def mcp_post(request: Request):
header_version = request.headers.get("mcp-protocol-version") header_version = request.headers.get("mcp-protocol-version")
if header_version and header_version not in mcp_server.SUPPORTED_PROTOCOL_VERSIONS: if header_version and header_version not in mcp_server.SUPPORTED_PROTOCOL_VERSIONS:
return JSONResponse( # Non bloccare: Claude/Anthropic mandano versioni nuove; negoziamo nel body initialize
{"error": f"MCP-Protocol-Version non supportata: {header_version}"}, status_code=400 LOGGER.warning(
"MCP-Protocol-Version header=%s non in lista locale — continuo (negoziazione JSON-RPC)",
header_version,
) )
auth_header = request.headers.get("authorization", "") auth_header = request.headers.get("authorization", "")
claims = await run_in_threadpool(oauth.bearer_claims_from_header, auth_header) claims = await run_in_threadpool(oauth.bearer_claims_from_header, auth_header)
@@ -285,15 +287,84 @@ def _timeout_error(msg: dict) -> dict:
} }
@app.get("/mcp") @app.post("/")
def mcp_get(): async def root_mcp_post(request: Request):
"""Alcuni client (Claude) dopo OAuth POST-ano sulla root invece che su /mcp."""
ctype = (request.headers.get("content-type") or "").lower()
accept = (request.headers.get("accept") or "").lower()
if "json" not in ctype and "json" not in accept and "event-stream" not in accept:
raise HTTPException(404, "Not Found")
return await mcp_post(request)
@app.api_route("/mcp", methods=["GET", "HEAD"])
async def mcp_get(request: Request):
"""Streamable HTTP: GET può aprire SSE; HEAD serve alla discovery di Claude."""
if request.method == "HEAD":
return Response(
status_code=200,
headers={
**_auth_challenge_headers(),
"Allow": "GET, HEAD, POST, OPTIONS",
"Content-Type": "application/json",
},
)
accept = (request.headers.get("accept") or "").lower()
if "text/event-stream" in accept:
# Nessun messaggio server-initiated: stream SSE vuoto che si chiude subito
async def _empty():
yield ": loogle-mcp ready\n\n"
return StreamingResponse(
_empty(),
media_type="text/event-stream",
headers={
**_auth_challenge_headers(),
"Cache-Control": "no-cache",
"Connection": "keep-alive",
},
)
return JSONResponse( return JSONResponse(
{"error": "Use POST for MCP JSON-RPC"}, {
status_code=405, "ok": True,
"service": "loogle-mcp",
"transport": "streamable-http",
"endpoint": "/mcp",
"hint": "Usa POST JSON-RPC (initialize, tools/list, tools/call)",
},
headers=_auth_challenge_headers(), headers=_auth_challenge_headers(),
) )
@app.api_route("/mcp/", methods=["GET", "HEAD", "POST", "OPTIONS"])
async def mcp_slash(request: Request):
"""Evita redirect HTTP su /mcp/ (NPM) che rompe Claude."""
if request.method == "POST":
return await mcp_post(request)
if request.method == "OPTIONS":
return Response(
status_code=204,
headers={
"Allow": "GET, HEAD, POST, OPTIONS",
"Access-Control-Allow-Methods": "GET, HEAD, POST, OPTIONS",
"Access-Control-Allow-Headers": "Authorization, Content-Type, Accept, MCP-Protocol-Version, Mcp-Session-Id",
},
)
return await mcp_get(request)
@app.options("/mcp")
async def mcp_options():
return Response(
status_code=204,
headers={
"Allow": "GET, HEAD, POST, OPTIONS",
"Access-Control-Allow-Methods": "GET, HEAD, POST, OPTIONS",
"Access-Control-Allow-Headers": "Authorization, Content-Type, Accept, MCP-Protocol-Version, Mcp-Session-Id",
},
)
def _auth_challenge_headers() -> dict: def _auth_challenge_headers() -> dict:
base = jwt_utils.base_url() base = jwt_utils.base_url()
resource_metadata = f"{base}/.well-known/oauth-protected-resource/mcp" resource_metadata = f"{base}/.well-known/oauth-protected-resource/mcp"
+4 -1
View File
@@ -10,12 +10,15 @@ from . import tools
LOGGER = logging.getLogger("loogle_mcp.server") LOGGER = logging.getLogger("loogle_mcp.server")
# Versioni supportate, dalla più recente: si risponde con quella chiesta dal client # Versioni supportate, dalla più recente: si risponde con quella chiesta dal client
# se supportata, altrimenti con la più recente (negoziazione MCP lifecycle) # se supportata, altrimenti con la più recente (negoziazione MCP lifecycle)
SUPPORTED_PROTOCOL_VERSIONS = ("2025-06-18", "2025-03-26", "2024-11-05") SUPPORTED_PROTOCOL_VERSIONS = ("2025-11-25", "2025-06-18", "2025-03-26", "2024-11-05")
def negotiate_protocol_version(requested: Optional[str]) -> str: def negotiate_protocol_version(requested: Optional[str]) -> str:
if requested in SUPPORTED_PROTOCOL_VERSIONS: if requested in SUPPORTED_PROTOCOL_VERSIONS:
return requested return requested
# Client più nuovi: accettiamo la richiesta dichiarando la più recente che implementiamo
if requested:
LOGGER.info("protocollo sconosciuto %s — negozio %s", requested, SUPPORTED_PROTOCOL_VERSIONS[0])
return SUPPORTED_PROTOCOL_VERSIONS[0] return SUPPORTED_PROTOCOL_VERSIONS[0]
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.