2222from mcp .types import ToolAnnotations
2323
2424from mcp_server_python_docs .app_context import AppContext
25+ from mcp_server_python_docs .detection import detect_python_version , match_to_indexed
2526from mcp_server_python_docs .errors import DocsServerError
26- from mcp_server_python_docs .models import GetDocsResult , ListVersionsResult , SearchDocsResult
27+ from mcp_server_python_docs .models import (
28+ DetectPythonVersionResult ,
29+ GetDocsResult ,
30+ ListVersionsResult ,
31+ SearchDocsResult ,
32+ )
2733from mcp_server_python_docs .services .content import ContentService
2834from mcp_server_python_docs .services .search import SearchService
2935from mcp_server_python_docs .services .version import VersionService
@@ -83,6 +89,21 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
8389 content_svc = ContentService (db )
8490 version_svc = VersionService (db )
8591
92+ # Detect user's Python version and match to indexed versions
93+ detected_ver , detected_src = detect_python_version ()
94+ indexed_versions = [
95+ r [0 ] for r in db .execute ("SELECT version FROM doc_sets ORDER BY version" ).fetchall ()
96+ ]
97+ matched = match_to_indexed (detected_ver , indexed_versions )
98+ if matched :
99+ logger .info ("User Python %s matches indexed version — using as default" , matched )
100+ else :
101+ logger .info (
102+ "User Python %s not in index %s — using normal default" ,
103+ detected_ver ,
104+ indexed_versions ,
105+ )
106+
86107 try :
87108 yield AppContext (
88109 db = db ,
@@ -91,6 +112,8 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
91112 search_service = search_svc ,
92113 content_service = content_svc ,
93114 version_service = version_svc ,
115+ detected_python_version = matched ,
116+ detected_python_source = detected_src ,
94117 )
95118 except Exception :
96119 # HYGN-05: log lifespan errors, write last-error.log, re-raise original
@@ -155,6 +178,9 @@ def get_docs(
155178 """Retrieve a documentation page or specific section. Provide anchor for
156179 section-only retrieval (much cheaper). Pagination via start_index."""
157180 app_ctx : AppContext = ctx .request_context .lifespan_context
181+ # Auto-default to detected Python version when no version specified
182+ if version is None and app_ctx .detected_python_version :
183+ version = app_ctx .detected_python_version
158184 try :
159185 return app_ctx .content_service .get_docs (
160186 slug , version , anchor , max_chars , start_index
@@ -179,6 +205,29 @@ def list_versions(
179205 logger .exception ("Unexpected error in list_versions" )
180206 raise ToolError (f"Internal error: { type (e ).__name__ } " )
181207
208+ @mcp .tool (annotations = _TOOL_ANNOTATIONS )
209+ def detect_python_version (
210+ ctx : Context = None , # type: ignore[assignment]
211+ ) -> DetectPythonVersionResult :
212+ """Detect the Python version in the user's environment.
213+ Returns the detected version, how it was found, and whether it
214+ matches an indexed documentation set."""
215+ app_ctx : AppContext = ctx .request_context .lifespan_context
216+ detected_ver = app_ctx .detected_python_version
217+ detected_src = app_ctx .detected_python_source or "unknown"
218+
219+ # Re-run detection to get the raw version even if it didn't match
220+ from mcp_server_python_docs .detection import detect_python_version as _detect
221+
222+ raw_ver , raw_src = _detect ()
223+
224+ return DetectPythonVersionResult (
225+ detected_version = raw_ver ,
226+ source = raw_src ,
227+ matched_index_version = detected_ver ,
228+ is_default = detected_ver is not None ,
229+ )
230+
182231 # SRVR-07: _meta hint for get_docs tool.
183232 # FastMCP 1.27 does not expose a public API for setting _meta on tool
184233 # definitions. Deferred until the mcp SDK adds _meta support to the
0 commit comments