From 15114230575c9290aa5d9a871917571e2878d772 Mon Sep 17 00:00:00 2001 From: KeshavAnandCode Date: Sun, 12 Apr 2026 23:56:49 -0500 Subject: [PATCH] yes --- mcp_server.py | 48 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 12 deletions(-) diff --git a/mcp_server.py b/mcp_server.py index 79d7982..f1f9dd4 100644 --- a/mcp_server.py +++ b/mcp_server.py @@ -1,10 +1,29 @@ +import os +os.environ["MCP_ALLOW_ALL_ORIGINS"] = "1" + import json -import re from pathlib import Path from sentence_transformers import SentenceTransformer from qdrant_client import QdrantClient from qdrant_client.models import Filter, FieldCondition, MatchValue from mcp.server.fastmcp import FastMCP +# Add this right after the FastMCP import, before anything else +from mcp.server import streamable_http +streamable_http.ALLOWED_ORIGINS = None # try this first + +# If that doesn't work, patch the actual check function: +import mcp.server.streamable_http as _sh +_sh.is_valid_origin = lambda origin, allowed: True +import uvicorn +from starlette.middleware.cors import CORSMiddleware +from starlette.middleware.base import BaseHTTPMiddleware +from starlette.requests import Request +from mcp.server.transport_security import TransportSecuritySettings, TransportSecurityMiddleware + +# Monkey-patch to disable DNS rebinding protection entirely +TransportSecurityMiddleware.__init__ = lambda self, settings=None: setattr( + self, "settings", TransportSecuritySettings(enable_dns_rebinding_protection=False) +) # ── Paths ────────────────────────────────────────────────────────────────── project_root = Path(__file__).resolve().parent @@ -12,13 +31,13 @@ project_root = Path(__file__).resolve().parent # ── Models / Clients ─────────────────────────────────────────────────────── model = SentenceTransformer("nomic-ai/nomic-embed-text-v1.5", trust_remote_code=True) -qdrant = QdrantClient(path=str(project_root / "data" / "qdrant_local")) +qdrant = QdrantClient(path=str(project_root / "data" / "qdrant_local")) COLLECTION = "apush_chunks" with open(project_root / "data" / "processed" / "parent_lookup.json") as f: parent_lookup = json.load(f) -# ── Config (same as notebook) ────────────────────────────────────────────── +# ── Config ───────────────────────────────────────────────────────────────── TOP_K = 10 SYSTEM_PROMPT = """You are an expert AP US History tutor helping a student ace their APUSH exam. @@ -33,7 +52,7 @@ ANSWERING: FORMAT — match the question type: - One word/fact → one word -- SAQ → 1 focused paragraph, dense with evidence +- SAQ → 1 focused paragraph, dense with evidence - LEQ/DBQ → full essay: context, thesis, body paragraphs with evidence, nuance - General question → clear prose, as long as needed @@ -50,7 +69,7 @@ def embed_query(query: str) -> list[float]: normalize_embeddings=True, ).tolist() -# ── Retrieve (same as notebook) ──────────────────────────────────────────── +# ── Retrieve ─────────────────────────────────────────────────────────────── def retrieve(query: str) -> dict: hits = qdrant.query_points( collection_name=COLLECTION, @@ -71,7 +90,6 @@ def retrieve(query: str) -> dict: else: confidence = "LOW" - # Deduplicate by parent_id seen_parents = set() unique_hits = [] for h in hits: @@ -84,10 +102,9 @@ def retrieve(query: str) -> dict: sources = [] for h in unique_hits: - pid = h.payload["parent_id"] - parts = parent_lookup.get(pid, []) + pid = h.payload["parent_id"] + parts = parent_lookup.get(pid, []) full_text = "\n\n".join(p["text"] for p in parts) - sources.append({ "score": h.score, "chapter_num": h.payload["chapter_num"], @@ -104,6 +121,14 @@ def retrieve(query: str) -> dict: "sources": sources, } +# ── Origin bypass middleware ──────────────────────────────────────────────── +class AllowAllOriginsMiddleware(BaseHTTPMiddleware): + async def dispatch(self, request: Request, call_next): + # Spoof origin so FastMCP's internal check passes + request._headers = request.headers.mutablecopy() + request._headers["origin"] = "http://127.0.0.1:11434" + return await call_next(request) + # ── MCP Server ───────────────────────────────────────────────────────────── mcp = FastMCP("APUSH Tutor") @@ -141,10 +166,8 @@ def system_prompt() -> str: # ── Run ──────────────────────────────────────────────────────────────────── if __name__ == "__main__": - import uvicorn - from starlette.middleware.cors import CORSMiddleware - app = mcp.streamable_http_app() + app.add_middleware(AllowAllOriginsMiddleware) app.add_middleware( CORSMiddleware, allow_origins=["*"], @@ -152,4 +175,5 @@ if __name__ == "__main__": allow_headers=["*"], ) + print("Starting APUSH MCP server on http://127.0.0.1:52437/mcp") uvicorn.run(app, host="127.0.0.1", port=52437) \ No newline at end of file