python-docs-mcp-server 0.1.2__tar.gz → 0.1.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/.github/workflows/ci.yml +4 -2
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/.github/workflows/e2e.yml +5 -3
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/.github/workflows/release.yml +7 -7
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/PKG-INFO +1 -1
- python_docs_mcp_server-0.1.3/glama.json +6 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/pyproject.toml +1 -1
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/server.json +2 -2
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/server.py +54 -2
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_stdio_hygiene.py +5 -1
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_stdio_smoke.py +76 -11
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/uv.lock +1 -1
- python_docs_mcp_server-0.1.2/.planning/FULL-CODEBASE-REVIEW.md +0 -318
- python_docs_mcp_server-0.1.2/.planning/PROJECT.md +0 -121
- python_docs_mcp_server-0.1.2/.planning/REQUIREMENTS.md +0 -342
- python_docs_mcp_server-0.1.2/.planning/ROADMAP.md +0 -144
- python_docs_mcp_server-0.1.2/.planning/STATE.md +0 -105
- python_docs_mcp_server-0.1.2/.planning/config.json +0 -51
- python_docs_mcp_server-0.1.2/.planning/phases/01-foundation-stdio-hygiene-symbol-slice/01-01-PLAN.md +0 -217
- python_docs_mcp_server-0.1.2/.planning/phases/01-foundation-stdio-hygiene-symbol-slice/01-01-SUMMARY.md +0 -18
- python_docs_mcp_server-0.1.2/.planning/phases/01-foundation-stdio-hygiene-symbol-slice/01-02-PLAN.md +0 -255
- python_docs_mcp_server-0.1.2/.planning/phases/01-foundation-stdio-hygiene-symbol-slice/01-02-SUMMARY.md +0 -14
- python_docs_mcp_server-0.1.2/.planning/phases/01-foundation-stdio-hygiene-symbol-slice/01-03-PLAN.md +0 -435
- python_docs_mcp_server-0.1.2/.planning/phases/01-foundation-stdio-hygiene-symbol-slice/01-03-SUMMARY.md +0 -17
- python_docs_mcp_server-0.1.2/.planning/phases/01-foundation-stdio-hygiene-symbol-slice/01-04-PLAN.md +0 -434
- python_docs_mcp_server-0.1.2/.planning/phases/01-foundation-stdio-hygiene-symbol-slice/01-04-SUMMARY.md +0 -20
- python_docs_mcp_server-0.1.2/.planning/phases/01-foundation-stdio-hygiene-symbol-slice/01-05-PLAN.md +0 -419
- python_docs_mcp_server-0.1.2/.planning/phases/01-foundation-stdio-hygiene-symbol-slice/01-05-SUMMARY.md +0 -15
- python_docs_mcp_server-0.1.2/.planning/phases/01-foundation-stdio-hygiene-symbol-slice/01-CONTEXT.md +0 -87
- python_docs_mcp_server-0.1.2/.planning/phases/01-foundation-stdio-hygiene-symbol-slice/01-DISCUSSION-LOG.md +0 -108
- python_docs_mcp_server-0.1.2/.planning/phases/01-foundation-stdio-hygiene-symbol-slice/01-RESEARCH.md +0 -217
- python_docs_mcp_server-0.1.2/.planning/phases/01-foundation-stdio-hygiene-symbol-slice/01-REVIEW-FIX.md +0 -85
- python_docs_mcp_server-0.1.2/.planning/phases/01-foundation-stdio-hygiene-symbol-slice/01-REVIEW.md +0 -176
- python_docs_mcp_server-0.1.2/.planning/phases/02-schema-storage/02-A-PLAN.md +0 -216
- python_docs_mcp_server-0.1.2/.planning/phases/02-schema-storage/02-A-SUMMARY.md +0 -32
- python_docs_mcp_server-0.1.2/.planning/phases/02-schema-storage/02-B-PLAN.md +0 -99
- python_docs_mcp_server-0.1.2/.planning/phases/02-schema-storage/02-B-SUMMARY.md +0 -32
- python_docs_mcp_server-0.1.2/.planning/phases/02-schema-storage/02-C-PLAN.md +0 -410
- python_docs_mcp_server-0.1.2/.planning/phases/02-schema-storage/02-C-SUMMARY.md +0 -31
- python_docs_mcp_server-0.1.2/.planning/phases/02-schema-storage/02-CONTEXT.md +0 -60
- python_docs_mcp_server-0.1.2/.planning/phases/02-schema-storage/02-RESEARCH.md +0 -212
- python_docs_mcp_server-0.1.2/.planning/phases/02-schema-storage/02-REVIEW-FIX.md +0 -50
- python_docs_mcp_server-0.1.2/.planning/phases/02-schema-storage/02-REVIEW.md +0 -101
- python_docs_mcp_server-0.1.2/.planning/phases/02-schema-storage/02-VERIFICATION.md +0 -67
- python_docs_mcp_server-0.1.2/.planning/phases/03-retrieval-layer/03-A-PLAN.md +0 -181
- python_docs_mcp_server-0.1.2/.planning/phases/03-retrieval-layer/03-A-SUMMARY.md +0 -29
- python_docs_mcp_server-0.1.2/.planning/phases/03-retrieval-layer/03-B-PLAN.md +0 -205
- python_docs_mcp_server-0.1.2/.planning/phases/03-retrieval-layer/03-B-SUMMARY.md +0 -26
- python_docs_mcp_server-0.1.2/.planning/phases/03-retrieval-layer/03-C-PLAN.md +0 -175
- python_docs_mcp_server-0.1.2/.planning/phases/03-retrieval-layer/03-C-SUMMARY.md +0 -24
- python_docs_mcp_server-0.1.2/.planning/phases/03-retrieval-layer/03-CONTEXT.md +0 -76
- python_docs_mcp_server-0.1.2/.planning/phases/03-retrieval-layer/03-D-PLAN.md +0 -201
- python_docs_mcp_server-0.1.2/.planning/phases/03-retrieval-layer/03-D-SUMMARY.md +0 -27
- python_docs_mcp_server-0.1.2/.planning/phases/03-retrieval-layer/03-RESEARCH.md +0 -299
- python_docs_mcp_server-0.1.2/.planning/phases/03-retrieval-layer/03-REVIEW-FIX.md +0 -56
- python_docs_mcp_server-0.1.2/.planning/phases/03-retrieval-layer/03-REVIEW.md +0 -148
- python_docs_mcp_server-0.1.2/.planning/phases/03-retrieval-layer/03-VALIDATION.md +0 -83
- python_docs_mcp_server-0.1.2/.planning/phases/03-retrieval-layer/03-VERIFICATION.md +0 -64
- python_docs_mcp_server-0.1.2/.planning/phases/04-sphinx-json-ingestion-atomic-swap-publishing/04-A-PLAN.md +0 -182
- python_docs_mcp_server-0.1.2/.planning/phases/04-sphinx-json-ingestion-atomic-swap-publishing/04-B-PLAN.md +0 -153
- python_docs_mcp_server-0.1.2/.planning/phases/04-sphinx-json-ingestion-atomic-swap-publishing/04-C-PLAN.md +0 -225
- python_docs_mcp_server-0.1.2/.planning/phases/04-sphinx-json-ingestion-atomic-swap-publishing/04-CONTEXT.md +0 -78
- python_docs_mcp_server-0.1.2/.planning/phases/04-sphinx-json-ingestion-atomic-swap-publishing/04-D-PLAN.md +0 -555
- python_docs_mcp_server-0.1.2/.planning/phases/04-sphinx-json-ingestion-atomic-swap-publishing/04-DISCUSSION-LOG.md +0 -46
- python_docs_mcp_server-0.1.2/.planning/phases/04-sphinx-json-ingestion-atomic-swap-publishing/04-PATTERNS.md +0 -66
- python_docs_mcp_server-0.1.2/.planning/phases/04-sphinx-json-ingestion-atomic-swap-publishing/04-RESEARCH.md +0 -189
- python_docs_mcp_server-0.1.2/.planning/phases/04-sphinx-json-ingestion-atomic-swap-publishing/04-REVIEW-FIX.md +0 -62
- python_docs_mcp_server-0.1.2/.planning/phases/04-sphinx-json-ingestion-atomic-swap-publishing/04-REVIEW.md +0 -139
- python_docs_mcp_server-0.1.2/.planning/phases/04-sphinx-json-ingestion-atomic-swap-publishing/04-VALIDATION.md +0 -83
- python_docs_mcp_server-0.1.2/.planning/phases/05-services-tool-polish-caching/05-A-PLAN.md +0 -389
- python_docs_mcp_server-0.1.2/.planning/phases/05-services-tool-polish-caching/05-B-PLAN.md +0 -248
- python_docs_mcp_server-0.1.2/.planning/phases/05-services-tool-polish-caching/05-C-PLAN.md +0 -279
- python_docs_mcp_server-0.1.2/.planning/phases/05-services-tool-polish-caching/05-CONTEXT.md +0 -64
- python_docs_mcp_server-0.1.2/.planning/phases/05-services-tool-polish-caching/05-D-PLAN.md +0 -262
- python_docs_mcp_server-0.1.2/.planning/phases/05-services-tool-polish-caching/05-E-PLAN.md +0 -114
- python_docs_mcp_server-0.1.2/.planning/phases/05-services-tool-polish-caching/05-F-PLAN.md +0 -403
- python_docs_mcp_server-0.1.2/.planning/phases/05-services-tool-polish-caching/05-PATTERNS.md +0 -103
- python_docs_mcp_server-0.1.2/.planning/phases/05-services-tool-polish-caching/05-RESEARCH.md +0 -140
- python_docs_mcp_server-0.1.2/.planning/phases/05-services-tool-polish-caching/05-REVIEW-FIX.md +0 -80
- python_docs_mcp_server-0.1.2/.planning/phases/05-services-tool-polish-caching/05-REVIEW.md +0 -175
- python_docs_mcp_server-0.1.2/.planning/phases/05-services-tool-polish-caching/05-VALIDATION.md +0 -79
- python_docs_mcp_server-0.1.2/.planning/phases/06-multi-version-packaging-correctness/06-CONTEXT.md +0 -60
- python_docs_mcp_server-0.1.2/.planning/phases/06-multi-version-packaging-correctness/06-REVIEW-FIX.md +0 -59
- python_docs_mcp_server-0.1.2/.planning/phases/06-multi-version-packaging-correctness/06-REVIEW.md +0 -104
- python_docs_mcp_server-0.1.2/.planning/phases/06-multi-version-packaging-correctness/06-SUMMARY.md +0 -58
- python_docs_mcp_server-0.1.2/.planning/phases/06-multi-version-packaging-correctness/06a-PLAN.md +0 -411
- python_docs_mcp_server-0.1.2/.planning/phases/06-multi-version-packaging-correctness/06b-PLAN.md +0 -212
- python_docs_mcp_server-0.1.2/.planning/phases/06-multi-version-packaging-correctness/06c-PLAN.md +0 -246
- python_docs_mcp_server-0.1.2/.planning/phases/07-stability-tests-release-polish/07-CONTEXT.md +0 -63
- python_docs_mcp_server-0.1.2/.planning/phases/07-stability-tests-release-polish/07-REVIEW-FIX.md +0 -49
- python_docs_mcp_server-0.1.2/.planning/phases/07-stability-tests-release-polish/07-REVIEW.md +0 -116
- python_docs_mcp_server-0.1.2/.planning/phases/07-stability-tests-release-polish/07-VERIFICATION.md +0 -65
- python_docs_mcp_server-0.1.2/.planning/phases/07-stability-tests-release-polish/07a-PLAN.md +0 -170
- python_docs_mcp_server-0.1.2/.planning/phases/07-stability-tests-release-polish/07a-SUMMARY.md +0 -33
- python_docs_mcp_server-0.1.2/.planning/phases/07-stability-tests-release-polish/07b-PLAN.md +0 -179
- python_docs_mcp_server-0.1.2/.planning/phases/07-stability-tests-release-polish/07b-SUMMARY.md +0 -39
- python_docs_mcp_server-0.1.2/.planning/phases/07-stability-tests-release-polish/07c-PLAN.md +0 -217
- python_docs_mcp_server-0.1.2/.planning/phases/07-stability-tests-release-polish/07c-SUMMARY.md +0 -29
- python_docs_mcp_server-0.1.2/.planning/phases/07-stability-tests-release-polish/07d-PLAN.md +0 -337
- python_docs_mcp_server-0.1.2/.planning/phases/07-stability-tests-release-polish/07d-SUMMARY.md +0 -38
- python_docs_mcp_server-0.1.2/.planning/phases/08-ship/08-CONTEXT.md +0 -68
- python_docs_mcp_server-0.1.2/.planning/phases/08-ship/08-REVIEW-FIX.md +0 -66
- python_docs_mcp_server-0.1.2/.planning/phases/08-ship/08-REVIEW.md +0 -134
- python_docs_mcp_server-0.1.2/.planning/phases/08-ship/08-VERIFICATION.md +0 -49
- python_docs_mcp_server-0.1.2/.planning/phases/08-ship/08a-PLAN.md +0 -180
- python_docs_mcp_server-0.1.2/.planning/phases/08-ship/08a-SUMMARY.md +0 -33
- python_docs_mcp_server-0.1.2/.planning/phases/08-ship/08b-PLAN.md +0 -205
- python_docs_mcp_server-0.1.2/.planning/phases/08-ship/08b-SUMMARY.md +0 -31
- python_docs_mcp_server-0.1.2/.planning/phases/08-ship/08c-PLAN.md +0 -161
- python_docs_mcp_server-0.1.2/.planning/phases/08-ship/08c-SUMMARY.md +0 -32
- python_docs_mcp_server-0.1.2/.planning/research/ARCHITECTURE.md +0 -946
- python_docs_mcp_server-0.1.2/.planning/research/FEATURES.md +0 -435
- python_docs_mcp_server-0.1.2/.planning/research/PITFALLS.md +0 -843
- python_docs_mcp_server-0.1.2/.planning/research/STACK.md +0 -344
- python_docs_mcp_server-0.1.2/.planning/research/SUMMARY.md +0 -277
- python_docs_mcp_server-0.1.2/.planning/v0.1.0-MILESTONE-AUDIT.md +0 -120
- python_docs_mcp_server-0.1.2/PR9_MCP_TEST_PLAN.md +0 -393
- python_docs_mcp_server-0.1.2/PR9_SMOKE_FAILURE_FIX_PLAN.md +0 -445
- python_docs_mcp_server-0.1.2/docs/launch/reddit-posts.md +0 -110
- python_docs_mcp_server-0.1.2/docs/launch/show-hn.md +0 -89
- python_docs_mcp_server-0.1.2/docs/superpowers/plans/2026-05-11-pr22-coherence-fixes.md +0 -864
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/.cursorignore +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/.github/INTEGRATION-TEST.md +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/.github/RELEASE.md +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/.gitignore +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/AGENTS.md +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/CLAUDE.md +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/CONTRIBUTING.md +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/LICENSE +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/README.md +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/__init__.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/__main__.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/app_context.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/data/synonyms.yaml +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/detection.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/diagnostics.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/errors.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/ingestion/__init__.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/ingestion/cpython_versions.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/ingestion/inventory.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/ingestion/publish.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/ingestion/sphinx_json.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/models.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/py.typed +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/retrieval/__init__.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/retrieval/budget.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/retrieval/query.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/retrieval/ranker.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/services/__init__.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/services/cache.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/services/content.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/services/observability.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/services/package_docs.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/services/persistent_cache.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/services/search.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/services/version.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/services/version_resolution.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/storage/__init__.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/storage/db.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/storage/schema.sql +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/__init__.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/conftest.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/fixtures/retrieval_regression_cases.json +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/fixtures/sample_broken.fjson +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/fixtures/sample_library.fjson +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/fixtures/schema-get_docs-input.json +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/fixtures/schema-get_docs-output.json +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/fixtures/schema-list_versions-output.json +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/fixtures/schema-search_docs-input.json +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/fixtures/schema-search_docs-output.json +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_ci_workflows.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_doctor.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_ingestion.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_mcp_get_docs_cache_smoke.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_multi_version.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_package_docs.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_packaging.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_persistent_docs_cache.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_phase1_integration.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_publish.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_retrieval.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_retrieval_regression.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_schema.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_schema_snapshot.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_services.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_stability.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/tests/test_synonyms.py +0 -0
|
@@ -18,10 +18,12 @@ jobs:
|
|
|
18
18
|
name: Test (Python ${{ matrix.python-version }}, ${{ matrix.os }})
|
|
19
19
|
|
|
20
20
|
steps:
|
|
21
|
-
- uses: actions/checkout@
|
|
21
|
+
- uses: actions/checkout@v6
|
|
22
22
|
|
|
23
23
|
- name: Install uv
|
|
24
|
-
uses: astral-sh/setup-uv@
|
|
24
|
+
uses: astral-sh/setup-uv@v8.1.0
|
|
25
|
+
with:
|
|
26
|
+
cache-suffix: py${{ matrix.python-version }}
|
|
25
27
|
|
|
26
28
|
- name: Set up Python ${{ matrix.python-version }}
|
|
27
29
|
run: uv python install ${{ matrix.python-version }}
|
|
@@ -17,10 +17,12 @@ jobs:
|
|
|
17
17
|
python-version: ["3.13", "3.14"]
|
|
18
18
|
|
|
19
19
|
steps:
|
|
20
|
-
- uses: actions/checkout@
|
|
20
|
+
- uses: actions/checkout@v6
|
|
21
21
|
|
|
22
22
|
- name: Install uv
|
|
23
|
-
uses: astral-sh/setup-uv@
|
|
23
|
+
uses: astral-sh/setup-uv@v8.1.0
|
|
24
|
+
with:
|
|
25
|
+
cache-suffix: py${{ matrix.python-version }}
|
|
24
26
|
|
|
25
27
|
- name: Set up Python ${{ matrix.python-version }}
|
|
26
28
|
run: uv python install ${{ matrix.python-version }}
|
|
@@ -48,7 +50,7 @@ jobs:
|
|
|
48
50
|
|
|
49
51
|
- name: Upload E2E logs and cache artifacts
|
|
50
52
|
if: always()
|
|
51
|
-
uses: actions/upload-artifact@
|
|
53
|
+
uses: actions/upload-artifact@v7
|
|
52
54
|
with:
|
|
53
55
|
name: e2e-python-${{ matrix.python-version }}
|
|
54
56
|
path: |
|
|
@@ -16,10 +16,10 @@ jobs:
|
|
|
16
16
|
timeout-minutes: 15
|
|
17
17
|
|
|
18
18
|
steps:
|
|
19
|
-
- uses: actions/checkout@
|
|
19
|
+
- uses: actions/checkout@v6
|
|
20
20
|
|
|
21
21
|
- name: Install uv
|
|
22
|
-
uses: astral-sh/setup-uv@
|
|
22
|
+
uses: astral-sh/setup-uv@v8.1.0
|
|
23
23
|
|
|
24
24
|
- name: Set up Python 3.13
|
|
25
25
|
run: uv python install 3.13
|
|
@@ -66,7 +66,7 @@ jobs:
|
|
|
66
66
|
"
|
|
67
67
|
|
|
68
68
|
- name: Upload dist artifacts
|
|
69
|
-
uses: actions/upload-artifact@
|
|
69
|
+
uses: actions/upload-artifact@v7
|
|
70
70
|
with:
|
|
71
71
|
name: dist
|
|
72
72
|
path: dist/
|
|
@@ -84,13 +84,13 @@ jobs:
|
|
|
84
84
|
|
|
85
85
|
steps:
|
|
86
86
|
- name: Download dist artifacts
|
|
87
|
-
uses: actions/download-artifact@
|
|
87
|
+
uses: actions/download-artifact@v8
|
|
88
88
|
with:
|
|
89
89
|
name: dist
|
|
90
90
|
path: dist/
|
|
91
91
|
|
|
92
92
|
- name: Generate artifact attestation
|
|
93
|
-
uses: actions/attest-build-provenance@
|
|
93
|
+
uses: actions/attest-build-provenance@v4
|
|
94
94
|
with:
|
|
95
95
|
subject-path: 'dist/*'
|
|
96
96
|
|
|
@@ -107,13 +107,13 @@ jobs:
|
|
|
107
107
|
|
|
108
108
|
steps:
|
|
109
109
|
- name: Download dist artifacts
|
|
110
|
-
uses: actions/download-artifact@
|
|
110
|
+
uses: actions/download-artifact@v8
|
|
111
111
|
with:
|
|
112
112
|
name: dist
|
|
113
113
|
path: dist/
|
|
114
114
|
|
|
115
115
|
- name: Create GitHub Release
|
|
116
|
-
uses: softprops/action-gh-release@
|
|
116
|
+
uses: softprops/action-gh-release@v3
|
|
117
117
|
with:
|
|
118
118
|
files: dist/*
|
|
119
119
|
generate_release_notes: true
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-docs-mcp-server
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: A read-only, version-aware MCP retrieval server over Python standard library documentation
|
|
5
5
|
Author-email: Aymen Hammouda <hammouda.aymen@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-docs-mcp-server"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.3"
|
|
8
8
|
description = "A read-only, version-aware MCP retrieval server over Python standard library documentation"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -8,13 +8,13 @@
|
|
|
8
8
|
"url": "https://github.com/ayhammouda/python-docs-mcp-server",
|
|
9
9
|
"source": "github"
|
|
10
10
|
},
|
|
11
|
-
"version": "0.1.
|
|
11
|
+
"version": "0.1.3",
|
|
12
12
|
"packages": [
|
|
13
13
|
{
|
|
14
14
|
"registryType": "pypi",
|
|
15
15
|
"registryBaseUrl": "https://pypi.org",
|
|
16
16
|
"identifier": "python-docs-mcp-server",
|
|
17
|
-
"version": "0.1.
|
|
17
|
+
"version": "0.1.3",
|
|
18
18
|
"runtimeHint": "uvx",
|
|
19
19
|
"transport": {
|
|
20
20
|
"type": "stdio"
|
{python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.3}/src/mcp_server_python_docs/server.py
RENAMED
|
@@ -9,7 +9,9 @@ from __future__ import annotations
|
|
|
9
9
|
import asyncio
|
|
10
10
|
import importlib.resources
|
|
11
11
|
import logging
|
|
12
|
+
import os
|
|
12
13
|
import sqlite3
|
|
14
|
+
import subprocess
|
|
13
15
|
import sys
|
|
14
16
|
import traceback
|
|
15
17
|
from collections.abc import AsyncIterator
|
|
@@ -61,6 +63,55 @@ def _assert_fts5(conn: sqlite3.Connection) -> None:
|
|
|
61
63
|
assert_fts5_available(conn)
|
|
62
64
|
|
|
63
65
|
|
|
66
|
+
def _auto_build_symbol_index(index_path) -> bool:
|
|
67
|
+
"""Build a small symbol-only index when the server starts without one.
|
|
68
|
+
|
|
69
|
+
This keeps hosted scanners/directories such as Glama from failing MCP
|
|
70
|
+
introspection on a fresh container while preserving the documented full
|
|
71
|
+
corpus command for normal users. Set PYTHON_DOCS_MCP_DISABLE_AUTO_INDEX=1
|
|
72
|
+
to require an explicitly prebuilt index.
|
|
73
|
+
"""
|
|
74
|
+
if os.environ.get("PYTHON_DOCS_MCP_DISABLE_AUTO_INDEX") == "1":
|
|
75
|
+
return False
|
|
76
|
+
|
|
77
|
+
versions = os.environ.get("PYTHON_DOCS_MCP_AUTO_INDEX_VERSIONS", "3.13")
|
|
78
|
+
logger.warning(
|
|
79
|
+
"No index found at %s; auto-building symbol-only Python docs index for %s",
|
|
80
|
+
index_path,
|
|
81
|
+
versions,
|
|
82
|
+
)
|
|
83
|
+
try:
|
|
84
|
+
result = subprocess.run(
|
|
85
|
+
[
|
|
86
|
+
sys.executable,
|
|
87
|
+
"-m",
|
|
88
|
+
"mcp_server_python_docs",
|
|
89
|
+
"build-index",
|
|
90
|
+
"--versions",
|
|
91
|
+
versions,
|
|
92
|
+
"--skip-content",
|
|
93
|
+
],
|
|
94
|
+
check=False,
|
|
95
|
+
capture_output=True,
|
|
96
|
+
text=True,
|
|
97
|
+
timeout=180,
|
|
98
|
+
)
|
|
99
|
+
except (OSError, subprocess.TimeoutExpired) as e:
|
|
100
|
+
logger.error("Auto index build failed to start or timed out: %s", e)
|
|
101
|
+
return False
|
|
102
|
+
|
|
103
|
+
if result.returncode != 0:
|
|
104
|
+
logger.error(
|
|
105
|
+
"Auto index build failed with exit code %s:\n%s",
|
|
106
|
+
result.returncode,
|
|
107
|
+
(result.stderr or result.stdout)[-4000:],
|
|
108
|
+
)
|
|
109
|
+
return False
|
|
110
|
+
|
|
111
|
+
logger.info("Auto index build complete at %s", index_path)
|
|
112
|
+
return index_path.exists()
|
|
113
|
+
|
|
114
|
+
|
|
64
115
|
@asynccontextmanager
|
|
65
116
|
async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
|
|
66
117
|
"""Manage application lifecycle with typed context (SRVR-01).
|
|
@@ -72,8 +123,9 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[AppContext]:
|
|
|
72
123
|
cache_dir = get_cache_dir()
|
|
73
124
|
index_path = get_index_path()
|
|
74
125
|
|
|
75
|
-
# Fail fast on missing index
|
|
76
|
-
|
|
126
|
+
# Fail fast on missing index unless a small symbol-only auto-index succeeds
|
|
127
|
+
# (SRVR-10 plus hosted-directory scanner compatibility).
|
|
128
|
+
if not index_path.exists() and not _auto_build_symbol_index(index_path):
|
|
77
129
|
from mcp_server_python_docs.ingestion.cpython_versions import (
|
|
78
130
|
SUPPORTED_DOC_VERSIONS_CSV,
|
|
79
131
|
)
|
|
@@ -67,12 +67,16 @@ class TestStdioHygiene:
|
|
|
67
67
|
import tempfile
|
|
68
68
|
|
|
69
69
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
70
|
+
env = {
|
|
71
|
+
**_isolated_cache_env(tmpdir),
|
|
72
|
+
"PYTHON_DOCS_MCP_DISABLE_AUTO_INDEX": "1",
|
|
73
|
+
}
|
|
70
74
|
result = subprocess.run(
|
|
71
75
|
[sys.executable, "-m", "mcp_server_python_docs", "serve"],
|
|
72
76
|
capture_output=True,
|
|
73
77
|
text=True,
|
|
74
78
|
timeout=10,
|
|
75
|
-
env=
|
|
79
|
+
env=env,
|
|
76
80
|
)
|
|
77
81
|
# Server should exit with error (missing index)
|
|
78
82
|
assert result.returncode != 0
|
|
@@ -16,6 +16,7 @@ import json
|
|
|
16
16
|
import os
|
|
17
17
|
import subprocess
|
|
18
18
|
import sys
|
|
19
|
+
import threading
|
|
19
20
|
import time
|
|
20
21
|
from pathlib import Path
|
|
21
22
|
|
|
@@ -100,17 +101,17 @@ def _create_test_index(cache_dir: Path) -> Path:
|
|
|
100
101
|
return db_path
|
|
101
102
|
|
|
102
103
|
|
|
103
|
-
def _make_request(method: str, params: dict | None = None, req_id: int = 1) -> bytes:
|
|
104
|
+
def _make_request(method: str, params: dict[str, object] | None = None, req_id: int = 1) -> bytes:
|
|
104
105
|
"""Build a JSON-RPC 2.0 request as newline-terminated bytes."""
|
|
105
|
-
msg = {"jsonrpc": "2.0", "id": req_id, "method": method}
|
|
106
|
+
msg: dict[str, object] = {"jsonrpc": "2.0", "id": req_id, "method": method}
|
|
106
107
|
if params is not None:
|
|
107
108
|
msg["params"] = params
|
|
108
109
|
return json.dumps(msg).encode() + b"\n"
|
|
109
110
|
|
|
110
111
|
|
|
111
|
-
def _make_notification(method: str, params: dict | None = None) -> bytes:
|
|
112
|
+
def _make_notification(method: str, params: dict[str, object] | None = None) -> bytes:
|
|
112
113
|
"""Build a JSON-RPC 2.0 notification (no id) as newline-terminated bytes."""
|
|
113
|
-
msg = {"jsonrpc": "2.0", "method": method}
|
|
114
|
+
msg: dict[str, object] = {"jsonrpc": "2.0", "method": method}
|
|
114
115
|
if params is not None:
|
|
115
116
|
msg["params"] = params
|
|
116
117
|
return json.dumps(msg).encode() + b"\n"
|
|
@@ -170,6 +171,19 @@ def _find_response(responses: list[dict], req_id: int) -> dict | None:
|
|
|
170
171
|
return None
|
|
171
172
|
|
|
172
173
|
|
|
174
|
+
def _request_ids(stdin_data: bytes) -> list[int]:
|
|
175
|
+
"""Return request ids present in newline-delimited JSON-RPC input."""
|
|
176
|
+
request_ids: list[int] = []
|
|
177
|
+
for line in stdin_data.splitlines():
|
|
178
|
+
try:
|
|
179
|
+
parsed = json.loads(line)
|
|
180
|
+
except json.JSONDecodeError:
|
|
181
|
+
continue
|
|
182
|
+
if isinstance(parsed, dict) and "id" in parsed:
|
|
183
|
+
request_ids.append(parsed["id"])
|
|
184
|
+
return request_ids
|
|
185
|
+
|
|
186
|
+
|
|
173
187
|
class TestStdioSmoke:
|
|
174
188
|
"""Spawn the MCP server as a subprocess and verify protocol compliance."""
|
|
175
189
|
|
|
@@ -192,13 +206,64 @@ class TestStdioSmoke:
|
|
|
192
206
|
env=self.env,
|
|
193
207
|
)
|
|
194
208
|
assert proc.stdin is not None
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
209
|
+
assert proc.stdout is not None
|
|
210
|
+
assert proc.stderr is not None
|
|
211
|
+
|
|
212
|
+
stdout_lines: list[bytes] = []
|
|
213
|
+
stderr_lines: list[bytes] = []
|
|
214
|
+
output_lock = threading.Lock()
|
|
215
|
+
|
|
216
|
+
def read_stream(stream, sink: list[bytes]) -> None:
|
|
217
|
+
for line in iter(stream.readline, b""):
|
|
218
|
+
with output_lock:
|
|
219
|
+
sink.append(line)
|
|
220
|
+
|
|
221
|
+
stdout_thread = threading.Thread(
|
|
222
|
+
target=read_stream,
|
|
223
|
+
args=(proc.stdout, stdout_lines),
|
|
224
|
+
daemon=True,
|
|
225
|
+
)
|
|
226
|
+
stderr_thread = threading.Thread(
|
|
227
|
+
target=read_stream,
|
|
228
|
+
args=(proc.stderr, stderr_lines),
|
|
229
|
+
daemon=True,
|
|
230
|
+
)
|
|
231
|
+
stdout_thread.start()
|
|
232
|
+
stderr_thread.start()
|
|
233
|
+
|
|
234
|
+
expected_ids = _request_ids(stdin_data)
|
|
235
|
+
deadline = time.monotonic() + timeout
|
|
236
|
+
try:
|
|
237
|
+
for line in stdin_data.splitlines(keepends=True):
|
|
238
|
+
proc.stdin.write(line)
|
|
239
|
+
proc.stdin.flush()
|
|
240
|
+
|
|
241
|
+
while time.monotonic() < deadline:
|
|
242
|
+
with output_lock:
|
|
243
|
+
responses = _read_responses(b"".join(stdout_lines))
|
|
244
|
+
if all(_find_response(responses, req_id) is not None for req_id in expected_ids):
|
|
245
|
+
break
|
|
246
|
+
if proc.poll() is not None:
|
|
247
|
+
break
|
|
248
|
+
time.sleep(0.02)
|
|
249
|
+
finally:
|
|
250
|
+
try:
|
|
251
|
+
proc.stdin.close()
|
|
252
|
+
except BrokenPipeError:
|
|
253
|
+
pass
|
|
254
|
+
proc.stdin = None
|
|
255
|
+
|
|
256
|
+
remaining = max(0.1, deadline - time.monotonic())
|
|
257
|
+
try:
|
|
258
|
+
proc.wait(timeout=remaining)
|
|
259
|
+
except subprocess.TimeoutExpired:
|
|
260
|
+
proc.kill()
|
|
261
|
+
proc.wait(timeout=5)
|
|
262
|
+
|
|
263
|
+
stdout_thread.join(timeout=1)
|
|
264
|
+
stderr_thread.join(timeout=1)
|
|
265
|
+
stdout = b"".join(stdout_lines)
|
|
266
|
+
stderr = b"".join(stderr_lines)
|
|
202
267
|
return subprocess.CompletedProcess(proc.args, proc.returncode, stdout, stderr)
|
|
203
268
|
|
|
204
269
|
def test_server_lists_tools_no_stdout_pollution(self):
|