88from mcp .server .streamable_http_manager import StreamableHTTPSessionManager
99
1010# to start (after .venv setup):
11- # python spendee/spendee_mcp.py
11+ # python spendee/spendee_mcp.py
1212
1313# to test:
14- # DANGEROUSLY_OMIT_AUTH=true mcp dev spendee/spendee_mcp.py
14+ # mcp dev spendee/spendee_mcp.py
1515# Then on the url: http://localhost:6274/
1616# setup "Transport Type" to "Streamable HTTP"
1717# and "Server URL" to "http://localhost:8000/mcp"
1818
1919ACCEPTED_TOKEN = os .environ .get ("MCP_TOKEN" , "spendee-token" )
20+ PORT = int (os .environ .get ("MCP_PORT" , 8000 ))
21+ DEBUG_MODE = os .environ .get ("DEBUG_MODE" , "" ) != ""
22+ DISABLE_AUTH = os .environ .get ("DISABLE_AUTH" , "" ) != ""
2023
2124logging .basicConfig (level = logging .DEBUG )
2225logger = logging .getLogger (__name__ )
2326
24- mcp = FastMCP ("spendee" )
27+ mcp = FastMCP ("spendee" , host = "0.0.0.0" , port = PORT )
2528
2629@mcp .tool ()
2730def get_wallets ():
@@ -31,41 +34,65 @@ def get_wallets():
3134 {"id" : 2 , "name" : "Savings" , "currency" : "EUR" , "balance" : 7890.12 },
3235 ]
3336
34- # --- Extra authentication layer ---
35- session_manager = StreamableHTTPSessionManager (
36- app = mcp ._mcp_server , # Use the underlying MCPServer instance
37- )
3837
39- async def auth_middleware (scope , receive , send ):
40- request = Request (scope , receive )
41- auth_header = request .headers .get ("authorization" )
38+ # def server_with_authentication():
39+ # session_manager = StreamableHTTPSessionManager(
40+ # app=mcp._mcp_server, # Use the underlying MCPServer instance
41+ # )
4242
43- if not auth_header or not auth_header .lower ().startswith ("bearer " ):
44- logger .warning ("Missing or invalid Authorization header." )
45- raise HTTPException (401 , "Missing or invalid Authorization header." )
43+ # async def auth_middleware(scope, receive, send):
44+ # request = Request(scope, receive)
45+ # # Log request method, url, and headers for troubleshooting
46+ # if DEBUG_MODE:
47+ # logger.debug(f"Incoming request: method={request.method}, url={request.url}")
48+ # logger.debug(f"Request headers: {dict(request.headers)}")
4649
47- token = auth_header .split (" " , 1 )[1 ]
48- if token != ACCEPTED_TOKEN :
49- logger .warning ("Invalid or expired token." )
50- raise HTTPException (401 , "Invalid or expired token." )
50+ # auth_header = request.headers.get("authorization")
5151
52- await session_manager .handle_request (scope , receive , send )
52+ # if not auth_header or not auth_header.lower().startswith("bearer "):
53+ # logger.warning("Missing or invalid Authorization header.")
54+ # raise HTTPException(401, "Missing or invalid Authorization header.")
5355
54- @contextlib .asynccontextmanager
55- async def lifespan (app : FastAPI ):
56- async with session_manager .run ():
57- logger .info ("StreamableHTTPSessionManager started." )
58- yield
59- logger .info ("StreamableHTTPSessionManager stopped." )
56+ # token = auth_header.split(" ", 1)[1]
57+ # if token != ACCEPTED_TOKEN:
58+ # logger.warning("Invalid or expired token.")
59+ # raise HTTPException(401, "Invalid or expired token.")
6060
61- app = FastAPI (lifespan = lifespan )
62- app .mount ("/mcp" , auth_middleware )
61+ # await session_manager.handle_request(scope, receive, send)
62+
63+ # @contextlib.asynccontextmanager
64+ # async def lifespan(app: FastAPI):
65+ # async with session_manager.run():
66+ # logger.info("StreamableHTTPSessionManager started.")
67+ # yield
68+ # logger.info("StreamableHTTPSessionManager stopped.")
69+
70+ # app = FastAPI(lifespan=lifespan)
71+ # app.mount("/mcp", auth_middleware)
72+
73+ # logger.info(f"Starting Spendee MCP Server with Bearer Token Authentication on port {PORT}")
74+ # logger.info(f"Access the MCP endpoint at http://0.0.0.0:{PORT}/mcp")
75+ # uvicorn.run(app, host="0.0.0.0", port=PORT)
76+
77+ def server_with_sse ():
78+ app = FastAPI ()
79+ @app .get ("/" )
80+ def read_root ():
81+ return {"Hello" : "World" }
82+ #from app.sse import create_sse_server
83+ app .mount ("/" , app .sse .create_sse_server (mcp ))
6384
64- # --- Server Execution ---
6585if __name__ == "__main__" :
66- logger .info ("Starting Spendee MCP Server with Bearer Token Authentication" )
67- logger .info ("Access the MCP endpoint at http://0.0.0.0:8000/mcp" )
68- uvicorn .run (app , host = "0.0.0.0" , port = 8000 )
86+ logger .info ("Starting Spendee MCP Server as SSE without authentication" )
87+ mcp .run (transport = "sse" ) # for n8n compatibility, authentication implemented on cloudflare level
88+ #server_with_sse()
89+
90+ # if DISABLE_AUTH:
91+ # logger.warning("Running without authentication! This is insecure and should only be used for local testing.")
92+ # #mcp.run(transport="streamable-http")
93+ # mcp.run(transport="sse")
94+ # else:
95+ # server_with_authentication()
6996
7097
7198# relevant URLs for learning:
@@ -76,3 +103,4 @@ async def lifespan(app: FastAPI):
76103# - https://modelcontextprotocol.io/docs/tools/debugging
77104# - https://modelcontextprotocol.io/specification/2025-03-26/basic/transports#session-management
78105# - https://github.com/modelcontextprotocol/python-sdk?tab=readme-ov-file#authentication
106+ # - auth inspiration: https://github.com/zahere-dev/mcp-labs/tree/main
0 commit comments