python-docs-mcp-server 0.1.2__tar.gz → 0.1.4__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.4}/.github/workflows/ci.yml +4 -2
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/.github/workflows/e2e.yml +5 -3
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/.github/workflows/release.yml +46 -8
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/PKG-INFO +2 -1
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/README.md +1 -0
- python_docs_mcp_server-0.1.4/glama.json +6 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/pyproject.toml +1 -1
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/server.json +2 -2
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/server.py +54 -2
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_stdio_hygiene.py +5 -1
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_stdio_smoke.py +76 -11
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/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.4}/.cursorignore +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/.github/INTEGRATION-TEST.md +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/.github/RELEASE.md +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/.gitignore +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/AGENTS.md +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/CLAUDE.md +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/CONTRIBUTING.md +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/LICENSE +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/__init__.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/__main__.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/app_context.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/data/synonyms.yaml +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/detection.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/diagnostics.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/errors.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/ingestion/__init__.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/ingestion/cpython_versions.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/ingestion/inventory.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/ingestion/publish.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/ingestion/sphinx_json.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/models.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/py.typed +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/retrieval/__init__.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/retrieval/budget.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/retrieval/query.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/retrieval/ranker.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/services/__init__.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/services/cache.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/services/content.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/services/observability.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/services/package_docs.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/services/persistent_cache.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/services/search.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/services/version.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/services/version_resolution.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/storage/__init__.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/storage/db.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/src/mcp_server_python_docs/storage/schema.sql +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/__init__.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/conftest.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/fixtures/retrieval_regression_cases.json +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/fixtures/sample_broken.fjson +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/fixtures/sample_library.fjson +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/fixtures/schema-get_docs-input.json +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/fixtures/schema-get_docs-output.json +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/fixtures/schema-list_versions-output.json +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/fixtures/schema-search_docs-input.json +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/fixtures/schema-search_docs-output.json +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_ci_workflows.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_doctor.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_ingestion.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_mcp_get_docs_cache_smoke.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_multi_version.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_package_docs.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_packaging.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_persistent_docs_cache.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_phase1_integration.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_publish.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_retrieval.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_retrieval_regression.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_schema.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_schema_snapshot.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_services.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/tests/test_stability.py +0 -0
- {python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/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
|
|
@@ -35,6 +35,16 @@ jobs:
|
|
|
35
35
|
echo "::error::Tag ${GITHUB_REF_NAME} does not match pyproject.toml version ${PKG_VERSION}"
|
|
36
36
|
exit 1
|
|
37
37
|
fi
|
|
38
|
+
SERVER_VERSION=$(uv run python -c "import json; print(json.load(open('server.json'))['version'])")
|
|
39
|
+
PACKAGE_VERSION=$(uv run python -c "import json; print(json.load(open('server.json'))['packages'][0]['version'])")
|
|
40
|
+
if [ "$TAG_VERSION" != "$SERVER_VERSION" ]; then
|
|
41
|
+
echo "::error::Tag ${GITHUB_REF_NAME} does not match server.json version ${SERVER_VERSION}"
|
|
42
|
+
exit 1
|
|
43
|
+
fi
|
|
44
|
+
if [ "$TAG_VERSION" != "$PACKAGE_VERSION" ]; then
|
|
45
|
+
echo "::error::Tag ${GITHUB_REF_NAME} does not match server.json package version ${PACKAGE_VERSION}"
|
|
46
|
+
exit 1
|
|
47
|
+
fi
|
|
38
48
|
echo "Version check passed: ${PKG_VERSION}"
|
|
39
49
|
|
|
40
50
|
- name: Run linter
|
|
@@ -66,7 +76,7 @@ jobs:
|
|
|
66
76
|
"
|
|
67
77
|
|
|
68
78
|
- name: Upload dist artifacts
|
|
69
|
-
uses: actions/upload-artifact@
|
|
79
|
+
uses: actions/upload-artifact@v7
|
|
70
80
|
with:
|
|
71
81
|
name: dist
|
|
72
82
|
path: dist/
|
|
@@ -84,22 +94,50 @@ jobs:
|
|
|
84
94
|
|
|
85
95
|
steps:
|
|
86
96
|
- name: Download dist artifacts
|
|
87
|
-
uses: actions/download-artifact@
|
|
97
|
+
uses: actions/download-artifact@v8
|
|
88
98
|
with:
|
|
89
99
|
name: dist
|
|
90
100
|
path: dist/
|
|
91
101
|
|
|
92
102
|
- name: Generate artifact attestation
|
|
93
|
-
uses: actions/attest-build-provenance@
|
|
103
|
+
uses: actions/attest-build-provenance@v4
|
|
94
104
|
with:
|
|
95
105
|
subject-path: 'dist/*'
|
|
96
106
|
|
|
97
107
|
- name: Publish to PyPI
|
|
98
108
|
uses: pypa/gh-action-pypi-publish@release/v1
|
|
99
109
|
|
|
100
|
-
|
|
110
|
+
publish-mcp-registry:
|
|
101
111
|
needs: publish
|
|
102
112
|
runs-on: ubuntu-latest
|
|
113
|
+
name: Publish to MCP Registry
|
|
114
|
+
timeout-minutes: 10
|
|
115
|
+
permissions:
|
|
116
|
+
id-token: write
|
|
117
|
+
contents: read
|
|
118
|
+
|
|
119
|
+
steps:
|
|
120
|
+
- uses: actions/checkout@v6
|
|
121
|
+
|
|
122
|
+
- name: Install mcp-publisher
|
|
123
|
+
run: |
|
|
124
|
+
curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" \
|
|
125
|
+
| tar xz mcp-publisher
|
|
126
|
+
|
|
127
|
+
- name: Validate server.json
|
|
128
|
+
run: ./mcp-publisher validate server.json
|
|
129
|
+
|
|
130
|
+
- name: Authenticate to MCP Registry
|
|
131
|
+
run: ./mcp-publisher login github-oidc
|
|
132
|
+
|
|
133
|
+
- name: Publish to MCP Registry
|
|
134
|
+
run: ./mcp-publisher publish
|
|
135
|
+
|
|
136
|
+
github-release:
|
|
137
|
+
needs:
|
|
138
|
+
- publish
|
|
139
|
+
- publish-mcp-registry
|
|
140
|
+
runs-on: ubuntu-latest
|
|
103
141
|
name: Create GitHub Release
|
|
104
142
|
timeout-minutes: 10
|
|
105
143
|
permissions:
|
|
@@ -107,13 +145,13 @@ jobs:
|
|
|
107
145
|
|
|
108
146
|
steps:
|
|
109
147
|
- name: Download dist artifacts
|
|
110
|
-
uses: actions/download-artifact@
|
|
148
|
+
uses: actions/download-artifact@v8
|
|
111
149
|
with:
|
|
112
150
|
name: dist
|
|
113
151
|
path: dist/
|
|
114
152
|
|
|
115
153
|
- name: Create GitHub Release
|
|
116
|
-
uses: softprops/action-gh-release@
|
|
154
|
+
uses: softprops/action-gh-release@v3
|
|
117
155
|
with:
|
|
118
156
|
files: dist/*
|
|
119
157
|
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.4
|
|
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
|
|
@@ -31,6 +31,7 @@ Description-Content-Type: text/markdown
|
|
|
31
31
|
<!-- mcp-name: io.github.ayhammouda/python-docs-mcp-server -->
|
|
32
32
|
|
|
33
33
|
[](https://github.com/ayhammouda/python-docs-mcp-server/actions/workflows/ci.yml)
|
|
34
|
+
[](https://glama.ai/mcp/servers/ayhammouda/python-docs-mcp-server)
|
|
34
35
|
[](LICENSE)
|
|
35
36
|
[](https://www.python.org/)
|
|
36
37
|
[](#why-teams-like-this)
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
<!-- mcp-name: io.github.ayhammouda/python-docs-mcp-server -->
|
|
4
4
|
|
|
5
5
|
[](https://github.com/ayhammouda/python-docs-mcp-server/actions/workflows/ci.yml)
|
|
6
|
+
[](https://glama.ai/mcp/servers/ayhammouda/python-docs-mcp-server)
|
|
6
7
|
[](LICENSE)
|
|
7
8
|
[](https://www.python.org/)
|
|
8
9
|
[](#why-teams-like-this)
|
|
@@ -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.4"
|
|
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.4",
|
|
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.4",
|
|
18
18
|
"runtimeHint": "uvx",
|
|
19
19
|
"transport": {
|
|
20
20
|
"type": "stdio"
|
{python_docs_mcp_server-0.1.2 → python_docs_mcp_server-0.1.4}/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):
|