fix(mcp+alembic): désactive DNS rebinding (421) + rechaîne migrations 006
MCP : - FastMCP recevait Host=localhost (sans port) mais le pattern par défaut allowed_hosts=["localhost:*", ...] EXIGE un port → 421 Invalid Host header pour tout accès non-localhost (ex: Hermes via http://10.0.0.50:3001/mcp) - Désactive enable_dns_rebinding_protection : le Bearer MCP_API_KEY est la vraie barrière (protection rebinding = anti-attaque navigateur, inutile ici) - nginx /mcp : retour à Host $host (le rewrite localhost était cassé) Alembic : - Collision : 006_notes_urls et 006_product_tags partageaient revision='006' → "Multiple head revisions" au démarrage - Renumérote notes_urls en 0061, chaîné après product_tags Chaîne finale : 005 -> 006 (product_tags) -> 0061 (notes_urls) -> 007 v0.5.15 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+8
-5
@@ -1,16 +1,19 @@
|
||||
"""006 - ajout colonne urls (JSONB) sur notes.items
|
||||
"""0061 - ajout colonne urls (JSONB) sur notes.items
|
||||
|
||||
Revision ID: 006
|
||||
Revises: 005
|
||||
Revision ID: 0061
|
||||
Revises: 006
|
||||
Create Date: 2026-05-30
|
||||
|
||||
Note : renumérotée 0061 (au lieu de 006) pour résoudre une collision avec
|
||||
006_product_tags. Chaînée après product_tags : 005 -> 006 -> 0061 -> 007.
|
||||
"""
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
|
||||
revision = '006'
|
||||
down_revision = '005'
|
||||
revision = '0061'
|
||||
down_revision = '006'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""007 - list_type sur shopping.lists, url/description/image_url sur list_items
|
||||
|
||||
Revision ID: 007
|
||||
Revises: 006
|
||||
Revises: 0061
|
||||
Create Date: 2026-05-30
|
||||
"""
|
||||
|
||||
@@ -9,7 +9,7 @@ from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
revision = '007'
|
||||
down_revision = '006'
|
||||
down_revision = '0061'
|
||||
branch_labels = None
|
||||
depends_on = None
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ from datetime import datetime, timedelta, timezone, date as date_type
|
||||
from decimal import Decimal
|
||||
|
||||
from mcp.server.fastmcp import FastMCP
|
||||
from mcp.server.transport_security import TransportSecuritySettings
|
||||
from sqlalchemy import select, and_, text, or_
|
||||
from sqlalchemy.orm import selectinload
|
||||
|
||||
@@ -15,7 +16,20 @@ from app.models.shopping import ShoppingList, ListItem, Product
|
||||
_VALID_STATUSES = {"pending", "done", "cancelled"}
|
||||
_VALID_PRIORITIES = {"low", "medium", "high"}
|
||||
|
||||
mcp = FastMCP("HomeHub", stateless_http=True, streamable_http_path="/")
|
||||
# La protection DNS rebinding (défaut FastMCP) valide le header Host contre
|
||||
# ["127.0.0.1:*", "localhost:*", "[::1]:*"]. Elle est conçue contre les attaques
|
||||
# navigateur sur des services localhost. Ici l'accès se fait depuis des agents
|
||||
# externes (Hermes) via l'IP du serveur, et la vraie barrière est le Bearer token
|
||||
# MCP_API_KEY (cf. MCPAuthMiddleware). On désactive donc cette protection devenue
|
||||
# redondante et bloquante (sinon 421 "Invalid Host header" sur toute IP non-localhost).
|
||||
mcp = FastMCP(
|
||||
"HomeHub",
|
||||
stateless_http=True,
|
||||
streamable_http_path="/",
|
||||
transport_security=TransportSecuritySettings(
|
||||
enable_dns_rebinding_protection=False,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _serialize(obj):
|
||||
|
||||
Reference in New Issue
Block a user