devrev-Python-SDK 2.6.0__tar.gz → 2.7.0__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.
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/Dockerfile +2 -2
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/PKG-INFO +1 -1
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/changelog.md +15 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/hooks/copy_llms.py +7 -8
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/llms-ctx-full.txt +1 -1
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/llms-ctx.txt +1 -1
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/llms-mcp.txt +1 -1
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/llms.txt +1 -1
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/pyproject.toml +1 -1
- devrev_python_sdk-2.7.0/src/devrev_mcp/resources/server_info.py +42 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/server.py +8 -0
- devrev_python_sdk-2.7.0/src/devrev_mcp/tools/server_info.py +108 -0
- devrev_python_sdk-2.7.0/tests/unit/mcp/test_server_info.py +336 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/agents/bug-fixer.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/agents/builder.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/agents/documentation.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/agents/foreman.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/agents/pr-review-boss.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/agents/release-manager.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/agents/simplifier.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/agents/tester.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/commands/foreman-work.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/commands/release-prepare.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/commands/review-start.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/commands/simplify-code.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/rules/code-quality.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/rules/data-modeling.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/rules/devrev-sdk.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/rules/git-workflow.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/rules/pull-requests.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/rules/python-development.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/rules/security.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.augment/rules/testing.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.dockerignore +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.env.sample +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.github/ISSUE_TEMPLATE/question.yml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.github/dependabot.yml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.github/pull_request_template.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.github/workflows/api-check.yml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.github/workflows/ci.yml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.github/workflows/claude-code-review.yml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.github/workflows/claude.yml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.github/workflows/deploy.yml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.github/workflows/docs.yml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.github/workflows/integration-tests.yml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.github/workflows/release.yml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.github/workflows/sync-openapi.yml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.gitignore +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/.pre-commit-config.yaml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/CODE_OF_CONDUCT.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/CONTRIBUTING.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/DEPRECATIONS.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/KNOWN_ISSUES.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/OPENAPI_SPEC_DISCREPANCIES.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/README.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/SECURITY.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/augment-mcp-config-remote.json +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/augment-mcp-config.json +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/augment-settings.json +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/benchmarks/README.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/benchmarks/bench_http_client.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/benchmarks/bench_models.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/benchmarks/bench_pagination.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/benchmarks/conftest.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/context7.json +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/deploy/README.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/deploy/audit-logging-setup.sh +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/deploy/cloudbuild.yaml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/deploy/monitoring/README.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/deploy/monitoring/alert-policies.yaml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/deploy/monitoring/dashboard.json +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/deploy/monitoring/validate-config.sh +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/deploy/service.yaml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docker-compose.yml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/beta/brands.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/beta/engagements.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/beta/incidents.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/beta/index.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/beta/question-answers.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/beta/recommendations.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/beta/search.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/beta/uoms.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/beta-api-differences.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/client.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/config.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/exceptions.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/index.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/models/accounts.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/models/base.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/models/index.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/models/users.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/models/works.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/services/accounts.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/services/articles.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/services/code-changes.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/services/conversations.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/services/dev-users.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/services/groups.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/services/index.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/services/links.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/services/parts.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/services/rev-users.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/services/slas.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/services/tags.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/services/timeline-entries.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/services/webhooks.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/api/services/works.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/examples/advanced.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/examples/basic.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/examples/beta-features.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/examples/index.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/examples/integrations.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/getting-started/authentication.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/getting-started/index.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/getting-started/installation.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/getting-started/quickstart.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/guides/beta-api.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/guides/compatibility.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/guides/configuration.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/guides/error-handling.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/guides/github-actions-setup.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/guides/index.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/guides/logging.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/guides/pagination.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/guides/sync-vs-async.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/guides/testing.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/guides/version-support.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/guides/write-integration-testing-strategy.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/index.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/mcp/deployment.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/mcp/index.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/mcp/quickstart.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/mcp/tools-reference.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/docs/stylesheets/extra.css +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/README.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/basic/README.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/basic/async_example.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/basic/create_work.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/basic/error_handling.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/basic/list_accounts.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/basic/pagination.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/basic/search_users.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/integrations/cloud_functions/README.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/integrations/cloud_functions/main.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/integrations/cloud_functions/requirements.txt +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/integrations/fastapi/README.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/integrations/fastapi/main.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/integrations/fastapi/requirements.txt +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/integrations/flask/README.md +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/integrations/flask/app.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/examples/integrations/flask/requirements.txt +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/mkdocs.yml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/openapi-beta.yaml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/openapi-public.yaml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/openapi-spec-corrections.yaml +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/scripts/build_ai_docs.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/scripts/setup-github-secrets.sh +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/client.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/config.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/exceptions.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/accounts.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/articles.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/base.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/brands.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/code_changes.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/conversations.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/dev_users.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/engagements.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/groups.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/incidents.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/links.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/notifications.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/parts.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/preferences.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/question_answers.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/recommendations.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/rev_users.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/search.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/slas.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/sync.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/tags.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/tasks.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/timeline_entries.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/timeline_events.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/track_events.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/uoms.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/webhooks.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/widgets.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/models/works.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/py.typed +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/accounts.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/articles.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/base.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/brands.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/code_changes.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/conversations.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/dev_users.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/engagements.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/groups.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/incidents.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/links.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/notifications.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/parts.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/preferences.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/question_answers.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/recommendations.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/rev_users.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/search.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/slas.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/tags.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/timeline_entries.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/track_events.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/uoms.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/webhooks.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/services/works.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/utils/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/utils/deprecation.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/utils/http.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/utils/logging.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev/utils/pagination.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/__main__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/config.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/middleware/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/middleware/audit.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/middleware/auth.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/middleware/health.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/middleware/rate_limit.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/prompts/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/prompts/escalation.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/prompts/investigate.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/prompts/response.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/prompts/summarize.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/prompts/triage.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/resources/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/resources/account.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/resources/article.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/resources/conversation.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/resources/part.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/resources/ticket.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/resources/user.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/tools/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/tools/accounts.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/tools/articles.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/tools/conversations.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/tools/engagements.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/tools/groups.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/tools/incidents.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/tools/links.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/tools/parts.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/tools/recommendations.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/tools/search.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/tools/slas.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/tools/tags.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/tools/timeline.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/tools/users.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/tools/works.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/utils/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/utils/errors.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/utils/formatting.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/src/devrev_mcp/utils/pagination.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/conftest.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/conftest.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/test_accounts_e2e.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/test_all_readonly_endpoints.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/test_backwards_compatibility.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/test_contacts_e2e.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/test_core_services_phase1.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/test_extended_services_phase2.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/test_get_endpoints.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/test_issues_e2e.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/test_kb_articles_e2e.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/test_ping.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/test_question_answers_e2e.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/test_readonly_endpoints.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/test_specialized_services_phase3.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/test_tickets_e2e.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/test_write_operations.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/utils/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/utils/cleanup.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/utils/constants.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/integration/utils/data_manager.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/conftest.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_audit.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_config.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_phase4_transport.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_prompts.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_resources.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_tools_accounts.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_tools_articles.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_tools_conversations.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_tools_engagements.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_tools_groups.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_tools_incidents.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_tools_links.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_tools_parts.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_tools_recommendations.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_tools_search.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_tools_slas.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_tools_tags.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_tools_timeline.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_tools_users.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_tools_works.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/mcp/test_utils.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/models/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/models/test_user_state_regression.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/__init__.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/conftest.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_articles.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_async_services.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_brands.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_code_changes.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_conversations.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_engagements.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_groups.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_incidents.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_links.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_notifications.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_parts.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_preferences.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_question_answers.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_recommendations.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_search.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_slas.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_tags.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_timeline_entries.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_track_events.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_uoms.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_webhooks.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/services/test_works.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/test_base_service.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/test_client.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/test_config.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/test_deprecation.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/test_exceptions.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/test_http.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/test_logging.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/tests/unit/test_pagination.py +0 -0
- {devrev_python_sdk-2.6.0 → devrev_python_sdk-2.7.0}/uv.lock +0 -0
|
@@ -39,11 +39,11 @@ FROM python:3.11-slim AS runtime
|
|
|
39
39
|
# Metadata labels
|
|
40
40
|
LABEL maintainer="Matthew G. Monteleone <matthewm@augmentcode.com>" \
|
|
41
41
|
description="DevRev MCP Server - A Model Context Protocol server for the DevRev platform" \
|
|
42
|
-
version="2.
|
|
42
|
+
version="2.6.0" \
|
|
43
43
|
org.opencontainers.image.source="https://github.com/mgmonteleone/py-dev-rev" \
|
|
44
44
|
org.opencontainers.image.title="DevRev MCP Server" \
|
|
45
45
|
org.opencontainers.image.description="Production-ready MCP server for DevRev API integration" \
|
|
46
|
-
org.opencontainers.image.version="2.
|
|
46
|
+
org.opencontainers.image.version="2.6.0" \
|
|
47
47
|
org.opencontainers.image.licenses="MIT"
|
|
48
48
|
|
|
49
49
|
# Set environment variables for Python
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: devrev-Python-SDK
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.7.0
|
|
4
4
|
Summary: A modern, type-safe Python SDK for the DevRev API
|
|
5
5
|
Project-URL: Homepage, https://github.com/mgmonteleone/py-dev-rev
|
|
6
6
|
Project-URL: Documentation, https://github.com/mgmonteleone/py-dev-rev
|
|
@@ -5,6 +5,20 @@ All notable changes to the DevRev Python SDK will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.7.0] - 2026-02-28
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Server Version Discoverability**: AI agents can now discover the server's version, capabilities, and update status dynamically
|
|
13
|
+
- **Server Instructions**: `FastMCP` constructor includes `instructions` parameter with version info, delivered to agents on connection
|
|
14
|
+
- **`devrev_server_info` Tool**: Returns server version, uptime, Python version, platform, enabled capabilities, and checks PyPI for the latest published version
|
|
15
|
+
- **`devrev://server/info` Resource**: Static server metadata resource for agents preferring resource-based discovery
|
|
16
|
+
- **PyPI Version Check**: Runtime check against PyPI to determine if the server is running the latest version, with graceful degradation on network failure
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- **Version Comparison**: `_compare_versions` now catches `InvalidVersion` from the `packaging` library for graceful degradation with malformed version strings
|
|
21
|
+
|
|
8
22
|
## [2.6.0] - 2026-02-28
|
|
9
23
|
|
|
10
24
|
### Added
|
|
@@ -474,6 +488,7 @@ This release marks the completion of all four development phases, providing a pr
|
|
|
474
488
|
|
|
475
489
|
| Version | Date | Highlights |
|
|
476
490
|
|---------|------|------------|
|
|
491
|
+
| 2.7.0 | 2026-02-28 | 🔍 Server version discoverability for AI agents |
|
|
477
492
|
| 2.6.0 | 2026-02-28 | 🔐 Compliance-grade audit logging, MCP documentation |
|
|
478
493
|
| 2.4.1 | 2026-02-27 | 🐛 CI: mypy strict-mode type errors, test collection |
|
|
479
494
|
| 2.4.0 | 2026-02-25 | 🔑 MCP Server: Per-user DevRev PAT authentication |
|
|
@@ -10,16 +10,16 @@ import shutil
|
|
|
10
10
|
from pathlib import Path
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
def on_post_build(config, **
|
|
13
|
+
def on_post_build(config, **_kwargs):
|
|
14
14
|
"""Copy llms*.txt files from repo root to site output directory.
|
|
15
|
-
|
|
15
|
+
|
|
16
16
|
This hook runs after MkDocs builds the site and copies all llms*.txt files
|
|
17
17
|
from the repository root to the site output directory, making them accessible
|
|
18
18
|
at the root URL of the documentation site.
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
Args:
|
|
21
21
|
config: MkDocs configuration dictionary.
|
|
22
|
-
**
|
|
22
|
+
**_kwargs: Additional keyword arguments (unused).
|
|
23
23
|
"""
|
|
24
24
|
# Get paths from config
|
|
25
25
|
repo_root = Path(config["config_file_path"]).parent
|
|
@@ -27,10 +27,10 @@ def on_post_build(config, **kwargs):
|
|
|
27
27
|
|
|
28
28
|
# List of llms.txt files to copy
|
|
29
29
|
llms_files = [
|
|
30
|
-
"llms.txt",
|
|
31
|
-
"llms-ctx.txt",
|
|
30
|
+
"llms.txt", # Main llms.txt file
|
|
31
|
+
"llms-ctx.txt", # Context-focused version
|
|
32
32
|
"llms-ctx-full.txt", # Full context version
|
|
33
|
-
"llms-mcp.txt",
|
|
33
|
+
"llms-mcp.txt", # MCP-specific version
|
|
34
34
|
]
|
|
35
35
|
|
|
36
36
|
# Copy each file if it exists
|
|
@@ -42,4 +42,3 @@ def on_post_build(config, **kwargs):
|
|
|
42
42
|
print(f"[OK] Copied {filename} to site root")
|
|
43
43
|
else:
|
|
44
44
|
print(f"[WARNING] {filename} not found in repo root")
|
|
45
|
-
|
|
@@ -13,7 +13,7 @@ A modern, type-safe Python SDK and MCP Server for the DevRev API with:
|
|
|
13
13
|
**Install**: `pip install devrev-python-sdk`
|
|
14
14
|
**Install with MCP**: `pip install devrev-python-sdk[mcp]`
|
|
15
15
|
**Docs**: https://mgmonteleone.github.io/py-dev-rev/
|
|
16
|
-
**Version**: 2.
|
|
16
|
+
**Version**: 2.7.0
|
|
17
17
|
|
|
18
18
|
## Authentication
|
|
19
19
|
|
|
@@ -6,7 +6,7 @@ A modern, type-safe Python SDK and MCP Server for the DevRev API. Requires Pytho
|
|
|
6
6
|
**Install SDK**: `pip install devrev-python-sdk`
|
|
7
7
|
**Install with MCP**: `pip install devrev-python-sdk[mcp]`
|
|
8
8
|
**Docs**: https://mgmonteleone.github.io/py-dev-rev/
|
|
9
|
-
**Version**: 2.
|
|
9
|
+
**Version**: 2.7.0
|
|
10
10
|
|
|
11
11
|
## SDK Quick Start
|
|
12
12
|
|
|
@@ -10,7 +10,7 @@ Key information:
|
|
|
10
10
|
- Both sync and async clients available (DevRevClient, AsyncDevRevClient)
|
|
11
11
|
- Uses Pydantic v2 for all request/response models
|
|
12
12
|
- MCP Server command: `devrev-mcp-server`
|
|
13
|
-
- Version 2.
|
|
13
|
+
- Version 2.7.0 (current)
|
|
14
14
|
|
|
15
15
|
## SDK Quick Start
|
|
16
16
|
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""MCP resource for DevRev server information."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
import platform
|
|
8
|
+
import sys
|
|
9
|
+
|
|
10
|
+
from devrev_mcp import __version__
|
|
11
|
+
from devrev_mcp.server import mcp
|
|
12
|
+
|
|
13
|
+
logger = logging.getLogger(__name__)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@mcp.resource("devrev://server/info")
|
|
17
|
+
async def get_server_info_resource() -> str:
|
|
18
|
+
"""Get DevRev MCP Server information as a resource.
|
|
19
|
+
|
|
20
|
+
Returns static server metadata including version, Python version,
|
|
21
|
+
and links. For dynamic information like uptime and latest PyPI version,
|
|
22
|
+
use the devrev_server_info tool instead.
|
|
23
|
+
|
|
24
|
+
Returns:
|
|
25
|
+
JSON string containing server metadata.
|
|
26
|
+
"""
|
|
27
|
+
return json.dumps(
|
|
28
|
+
{
|
|
29
|
+
"uri": "devrev://server/info",
|
|
30
|
+
"type": "server_info",
|
|
31
|
+
"name": "DevRev MCP Server",
|
|
32
|
+
"version": __version__,
|
|
33
|
+
"python_version": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
|
|
34
|
+
"platform": platform.system(),
|
|
35
|
+
"links": {
|
|
36
|
+
"github": "https://github.com/mgmonteleone/py-dev-rev",
|
|
37
|
+
"documentation": "https://mgmonteleone.github.io/py-dev-rev/",
|
|
38
|
+
"pypi": "https://pypi.org/project/devrev-Python-SDK/",
|
|
39
|
+
},
|
|
40
|
+
"note": "Use devrev_server_info tool for dynamic info (uptime, latest version check).",
|
|
41
|
+
}
|
|
42
|
+
)
|
|
@@ -140,6 +140,12 @@ _transport_security = _build_transport_security(_config)
|
|
|
140
140
|
|
|
141
141
|
mcp = FastMCP(
|
|
142
142
|
_config.server_name,
|
|
143
|
+
instructions=(
|
|
144
|
+
f"DevRev MCP Server v{__version__} — provides AI access to the DevRev platform "
|
|
145
|
+
f"for managing support tickets, customer accounts, knowledge bases, and workflows. "
|
|
146
|
+
f"Use the devrev_server_info tool to check version details, capabilities, and whether "
|
|
147
|
+
f"this is the latest version."
|
|
148
|
+
),
|
|
143
149
|
lifespan=app_lifespan,
|
|
144
150
|
host=_config.host,
|
|
145
151
|
port=_config.port,
|
|
@@ -237,6 +243,7 @@ from devrev_mcp.tools import groups as _groups_tools # noqa: E402, F401
|
|
|
237
243
|
from devrev_mcp.tools import incidents as _incidents_tools # noqa: E402, F401
|
|
238
244
|
from devrev_mcp.tools import links as _links_tools # noqa: E402, F401
|
|
239
245
|
from devrev_mcp.tools import parts as _parts_tools # noqa: E402, F401
|
|
246
|
+
from devrev_mcp.tools import server_info as _server_info_tools # noqa: E402, F401
|
|
240
247
|
from devrev_mcp.tools import slas as _slas_tools # noqa: E402, F401
|
|
241
248
|
from devrev_mcp.tools import tags as _tags_tools # noqa: E402, F401
|
|
242
249
|
from devrev_mcp.tools import timeline as _timeline_tools # noqa: E402, F401
|
|
@@ -259,6 +266,7 @@ from devrev_mcp.resources import account as _account_resources # noqa: E402, F4
|
|
|
259
266
|
from devrev_mcp.resources import article as _article_resources # noqa: E402, F401
|
|
260
267
|
from devrev_mcp.resources import conversation as _conversation_resources # noqa: E402, F401
|
|
261
268
|
from devrev_mcp.resources import part as _part_resources # noqa: E402, F401
|
|
269
|
+
from devrev_mcp.resources import server_info as _server_info_resources # noqa: E402, F401
|
|
262
270
|
from devrev_mcp.resources import ticket as _ticket_resources # noqa: E402, F401
|
|
263
271
|
from devrev_mcp.resources import user as _user_resources # noqa: E402, F401
|
|
264
272
|
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
"""MCP tool for DevRev server information and version checking."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import logging
|
|
6
|
+
import platform
|
|
7
|
+
import sys
|
|
8
|
+
import time
|
|
9
|
+
from typing import Any
|
|
10
|
+
|
|
11
|
+
import httpx
|
|
12
|
+
from mcp.server.fastmcp import Context
|
|
13
|
+
|
|
14
|
+
from devrev_mcp import __version__
|
|
15
|
+
from devrev_mcp.server import mcp
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
# PyPI package name for version lookups
|
|
20
|
+
_PYPI_PACKAGE_NAME = "devrev-Python-SDK"
|
|
21
|
+
_PYPI_URL = f"https://pypi.org/pypi/{_PYPI_PACKAGE_NAME}/json"
|
|
22
|
+
_PYPI_TIMEOUT = 5.0
|
|
23
|
+
|
|
24
|
+
# Static metadata
|
|
25
|
+
_GITHUB_URL = "https://github.com/mgmonteleone/py-dev-rev"
|
|
26
|
+
_DOCS_URL = "https://mgmonteleone.github.io/py-dev-rev/"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _compare_versions(current: str, latest: str) -> bool | None:
|
|
30
|
+
"""Compare two version strings. Returns True if current >= latest."""
|
|
31
|
+
try:
|
|
32
|
+
from packaging.version import Version
|
|
33
|
+
|
|
34
|
+
return Version(current) >= Version(latest)
|
|
35
|
+
except Exception:
|
|
36
|
+
# Catches ImportError (packaging not installed) and InvalidVersion (malformed version)
|
|
37
|
+
pass
|
|
38
|
+
# Fallback: simple tuple comparison
|
|
39
|
+
try:
|
|
40
|
+
current_parts = tuple(int(x) for x in current.split("."))
|
|
41
|
+
latest_parts = tuple(int(x) for x in latest.split("."))
|
|
42
|
+
return current_parts >= latest_parts
|
|
43
|
+
except (ValueError, AttributeError):
|
|
44
|
+
return None
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
async def _fetch_latest_pypi_version() -> str | None:
|
|
48
|
+
"""Fetch the latest version from PyPI. Returns None on failure."""
|
|
49
|
+
try:
|
|
50
|
+
async with httpx.AsyncClient() as client:
|
|
51
|
+
response = await client.get(_PYPI_URL, timeout=_PYPI_TIMEOUT)
|
|
52
|
+
response.raise_for_status()
|
|
53
|
+
data = response.json()
|
|
54
|
+
version = data.get("info", {}).get("version")
|
|
55
|
+
return str(version) if version is not None else None
|
|
56
|
+
except Exception:
|
|
57
|
+
logger.debug("Failed to fetch latest version from PyPI", exc_info=True)
|
|
58
|
+
return None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@mcp.tool()
|
|
62
|
+
async def devrev_server_info(ctx: Context[Any, Any, Any]) -> dict[str, Any]:
|
|
63
|
+
"""Get DevRev MCP Server information including version, capabilities, and update status.
|
|
64
|
+
|
|
65
|
+
Returns server version, enabled features, uptime, and checks PyPI for the
|
|
66
|
+
latest published version so you can tell the user whether they are up to date.
|
|
67
|
+
|
|
68
|
+
Use this tool when asked about the MCP server version, capabilities, or status.
|
|
69
|
+
"""
|
|
70
|
+
from devrev_mcp.middleware.health import _start_time
|
|
71
|
+
|
|
72
|
+
app = ctx.request_context.lifespan_context
|
|
73
|
+
|
|
74
|
+
# Calculate uptime
|
|
75
|
+
uptime_seconds = int(time.monotonic() - _start_time) if _start_time is not None else 0
|
|
76
|
+
|
|
77
|
+
# Fetch latest version from PyPI
|
|
78
|
+
latest_version = await _fetch_latest_pypi_version()
|
|
79
|
+
is_latest = _compare_versions(__version__, latest_version) if latest_version else None
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
"server": {
|
|
83
|
+
"name": app.config.server_name,
|
|
84
|
+
"version": __version__,
|
|
85
|
+
"uptime_seconds": uptime_seconds,
|
|
86
|
+
"python_version": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
|
|
87
|
+
"platform": platform.system(),
|
|
88
|
+
},
|
|
89
|
+
"capabilities": {
|
|
90
|
+
"beta_tools_enabled": app.config.enable_beta_tools,
|
|
91
|
+
"destructive_tools_enabled": app.config.enable_destructive_tools,
|
|
92
|
+
"auth_mode": app.config.auth_mode,
|
|
93
|
+
"transport": app.config.transport,
|
|
94
|
+
"audit_logging": app.config.audit_log_enabled,
|
|
95
|
+
"rate_limit_rpm": app.config.rate_limit_rpm,
|
|
96
|
+
},
|
|
97
|
+
"update_status": {
|
|
98
|
+
"current_version": __version__,
|
|
99
|
+
"latest_version": latest_version or "unknown",
|
|
100
|
+
"is_latest": is_latest,
|
|
101
|
+
"pypi_package": _PYPI_PACKAGE_NAME,
|
|
102
|
+
},
|
|
103
|
+
"links": {
|
|
104
|
+
"github": _GITHUB_URL,
|
|
105
|
+
"documentation": _DOCS_URL,
|
|
106
|
+
"pypi": f"https://pypi.org/project/{_PYPI_PACKAGE_NAME}/",
|
|
107
|
+
},
|
|
108
|
+
}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
"""Tests for DevRev MCP server info tool and resource."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from unittest.mock import AsyncMock, MagicMock, patch
|
|
7
|
+
|
|
8
|
+
import pytest
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TestServerInfoResource:
|
|
12
|
+
"""Tests for the devrev://server/info resource."""
|
|
13
|
+
|
|
14
|
+
@pytest.mark.asyncio
|
|
15
|
+
async def test_returns_valid_json(self):
|
|
16
|
+
"""Test that the resource returns valid JSON."""
|
|
17
|
+
from devrev_mcp.resources.server_info import get_server_info_resource
|
|
18
|
+
|
|
19
|
+
result = await get_server_info_resource()
|
|
20
|
+
data = json.loads(result)
|
|
21
|
+
assert isinstance(data, dict)
|
|
22
|
+
|
|
23
|
+
@pytest.mark.asyncio
|
|
24
|
+
async def test_contains_required_fields(self):
|
|
25
|
+
"""Test that the resource contains all required fields."""
|
|
26
|
+
from devrev_mcp.resources.server_info import get_server_info_resource
|
|
27
|
+
|
|
28
|
+
result = await get_server_info_resource()
|
|
29
|
+
data = json.loads(result)
|
|
30
|
+
assert data["uri"] == "devrev://server/info"
|
|
31
|
+
assert data["type"] == "server_info"
|
|
32
|
+
assert "version" in data
|
|
33
|
+
assert "python_version" in data
|
|
34
|
+
assert "platform" in data
|
|
35
|
+
assert "links" in data
|
|
36
|
+
assert "note" in data
|
|
37
|
+
|
|
38
|
+
@pytest.mark.asyncio
|
|
39
|
+
async def test_links_contain_urls(self):
|
|
40
|
+
"""Test that links contain expected URLs."""
|
|
41
|
+
from devrev_mcp.resources.server_info import get_server_info_resource
|
|
42
|
+
|
|
43
|
+
result = await get_server_info_resource()
|
|
44
|
+
data = json.loads(result)
|
|
45
|
+
assert "github" in data["links"]
|
|
46
|
+
assert "documentation" in data["links"]
|
|
47
|
+
assert "pypi" in data["links"]
|
|
48
|
+
assert data["links"]["github"].startswith("https://")
|
|
49
|
+
|
|
50
|
+
@pytest.mark.asyncio
|
|
51
|
+
async def test_version_matches_package(self):
|
|
52
|
+
"""Test that the version matches the package version."""
|
|
53
|
+
from devrev_mcp import __version__
|
|
54
|
+
from devrev_mcp.resources.server_info import get_server_info_resource
|
|
55
|
+
|
|
56
|
+
result = await get_server_info_resource()
|
|
57
|
+
data = json.loads(result)
|
|
58
|
+
assert data["version"] == __version__
|
|
59
|
+
|
|
60
|
+
@pytest.mark.asyncio
|
|
61
|
+
async def test_python_version_format(self):
|
|
62
|
+
"""Test that python_version is in X.Y.Z format."""
|
|
63
|
+
from devrev_mcp.resources.server_info import get_server_info_resource
|
|
64
|
+
|
|
65
|
+
result = await get_server_info_resource()
|
|
66
|
+
data = json.loads(result)
|
|
67
|
+
parts = data["python_version"].split(".")
|
|
68
|
+
assert len(parts) == 3
|
|
69
|
+
assert all(p.isdigit() for p in parts)
|
|
70
|
+
|
|
71
|
+
@pytest.mark.asyncio
|
|
72
|
+
async def test_note_mentions_tool(self):
|
|
73
|
+
"""Test that the note directs users to the tool for dynamic info."""
|
|
74
|
+
from devrev_mcp.resources.server_info import get_server_info_resource
|
|
75
|
+
|
|
76
|
+
result = await get_server_info_resource()
|
|
77
|
+
data = json.loads(result)
|
|
78
|
+
assert "devrev_server_info" in data["note"]
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class TestServerInfoTool:
|
|
82
|
+
"""Tests for the devrev_server_info tool."""
|
|
83
|
+
|
|
84
|
+
@pytest.mark.asyncio
|
|
85
|
+
async def test_returns_server_section(self, mock_ctx):
|
|
86
|
+
"""Test that the tool returns server information."""
|
|
87
|
+
from devrev_mcp.tools.server_info import devrev_server_info
|
|
88
|
+
|
|
89
|
+
with (
|
|
90
|
+
patch(
|
|
91
|
+
"devrev_mcp.tools.server_info._fetch_latest_pypi_version",
|
|
92
|
+
new_callable=AsyncMock,
|
|
93
|
+
return_value="2.6.0",
|
|
94
|
+
),
|
|
95
|
+
patch("devrev_mcp.middleware.health._start_time", 0.0),
|
|
96
|
+
):
|
|
97
|
+
result = await devrev_server_info(mock_ctx)
|
|
98
|
+
|
|
99
|
+
assert "server" in result
|
|
100
|
+
assert "version" in result["server"]
|
|
101
|
+
assert "name" in result["server"]
|
|
102
|
+
assert "uptime_seconds" in result["server"]
|
|
103
|
+
assert "python_version" in result["server"]
|
|
104
|
+
assert "platform" in result["server"]
|
|
105
|
+
|
|
106
|
+
@pytest.mark.asyncio
|
|
107
|
+
async def test_returns_capabilities_section(self, mock_ctx):
|
|
108
|
+
"""Test that the tool returns capabilities information."""
|
|
109
|
+
from devrev_mcp.tools.server_info import devrev_server_info
|
|
110
|
+
|
|
111
|
+
with patch(
|
|
112
|
+
"devrev_mcp.tools.server_info._fetch_latest_pypi_version",
|
|
113
|
+
new_callable=AsyncMock,
|
|
114
|
+
return_value="2.6.0",
|
|
115
|
+
):
|
|
116
|
+
result = await devrev_server_info(mock_ctx)
|
|
117
|
+
|
|
118
|
+
assert "capabilities" in result
|
|
119
|
+
caps = result["capabilities"]
|
|
120
|
+
assert "beta_tools_enabled" in caps
|
|
121
|
+
assert "destructive_tools_enabled" in caps
|
|
122
|
+
assert "auth_mode" in caps
|
|
123
|
+
assert "transport" in caps
|
|
124
|
+
assert "audit_logging" in caps
|
|
125
|
+
assert "rate_limit_rpm" in caps
|
|
126
|
+
|
|
127
|
+
@pytest.mark.asyncio
|
|
128
|
+
async def test_returns_update_status_section(self, mock_ctx):
|
|
129
|
+
"""Test that the tool returns update status information."""
|
|
130
|
+
from devrev_mcp.tools.server_info import devrev_server_info
|
|
131
|
+
|
|
132
|
+
with patch(
|
|
133
|
+
"devrev_mcp.tools.server_info._fetch_latest_pypi_version",
|
|
134
|
+
new_callable=AsyncMock,
|
|
135
|
+
return_value="2.6.0",
|
|
136
|
+
):
|
|
137
|
+
result = await devrev_server_info(mock_ctx)
|
|
138
|
+
|
|
139
|
+
assert "update_status" in result
|
|
140
|
+
status = result["update_status"]
|
|
141
|
+
assert "current_version" in status
|
|
142
|
+
assert "latest_version" in status
|
|
143
|
+
assert "is_latest" in status
|
|
144
|
+
assert "pypi_package" in status
|
|
145
|
+
|
|
146
|
+
@pytest.mark.asyncio
|
|
147
|
+
async def test_returns_links_section(self, mock_ctx):
|
|
148
|
+
"""Test that the tool returns links."""
|
|
149
|
+
from devrev_mcp.tools.server_info import devrev_server_info
|
|
150
|
+
|
|
151
|
+
with patch(
|
|
152
|
+
"devrev_mcp.tools.server_info._fetch_latest_pypi_version",
|
|
153
|
+
new_callable=AsyncMock,
|
|
154
|
+
return_value="2.6.0",
|
|
155
|
+
):
|
|
156
|
+
result = await devrev_server_info(mock_ctx)
|
|
157
|
+
|
|
158
|
+
assert "links" in result
|
|
159
|
+
assert "github" in result["links"]
|
|
160
|
+
assert "documentation" in result["links"]
|
|
161
|
+
assert "pypi" in result["links"]
|
|
162
|
+
|
|
163
|
+
@pytest.mark.asyncio
|
|
164
|
+
async def test_pypi_failure_returns_unknown(self, mock_ctx):
|
|
165
|
+
"""Test graceful handling when PyPI is unreachable."""
|
|
166
|
+
from devrev_mcp.tools.server_info import devrev_server_info
|
|
167
|
+
|
|
168
|
+
with patch(
|
|
169
|
+
"devrev_mcp.tools.server_info._fetch_latest_pypi_version",
|
|
170
|
+
new_callable=AsyncMock,
|
|
171
|
+
return_value=None,
|
|
172
|
+
):
|
|
173
|
+
result = await devrev_server_info(mock_ctx)
|
|
174
|
+
|
|
175
|
+
assert result["update_status"]["latest_version"] == "unknown"
|
|
176
|
+
assert result["update_status"]["is_latest"] is None
|
|
177
|
+
|
|
178
|
+
@pytest.mark.asyncio
|
|
179
|
+
async def test_is_latest_true_when_current_equals_latest(self, mock_ctx):
|
|
180
|
+
"""Test is_latest is True when versions match."""
|
|
181
|
+
from devrev_mcp import __version__
|
|
182
|
+
from devrev_mcp.tools.server_info import devrev_server_info
|
|
183
|
+
|
|
184
|
+
with patch(
|
|
185
|
+
"devrev_mcp.tools.server_info._fetch_latest_pypi_version",
|
|
186
|
+
new_callable=AsyncMock,
|
|
187
|
+
return_value=__version__,
|
|
188
|
+
):
|
|
189
|
+
result = await devrev_server_info(mock_ctx)
|
|
190
|
+
|
|
191
|
+
assert result["update_status"]["is_latest"] is True
|
|
192
|
+
|
|
193
|
+
@pytest.mark.asyncio
|
|
194
|
+
async def test_is_latest_false_when_behind(self, mock_ctx):
|
|
195
|
+
"""Test is_latest is False when a newer version exists."""
|
|
196
|
+
from devrev_mcp.tools.server_info import devrev_server_info
|
|
197
|
+
|
|
198
|
+
with patch(
|
|
199
|
+
"devrev_mcp.tools.server_info._fetch_latest_pypi_version",
|
|
200
|
+
new_callable=AsyncMock,
|
|
201
|
+
return_value="99.99.99",
|
|
202
|
+
):
|
|
203
|
+
result = await devrev_server_info(mock_ctx)
|
|
204
|
+
|
|
205
|
+
assert result["update_status"]["is_latest"] is False
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
class TestVersionComparison:
|
|
209
|
+
"""Tests for the _compare_versions helper."""
|
|
210
|
+
|
|
211
|
+
def test_equal_versions(self):
|
|
212
|
+
from devrev_mcp.tools.server_info import _compare_versions
|
|
213
|
+
|
|
214
|
+
assert _compare_versions("2.6.0", "2.6.0") is True
|
|
215
|
+
|
|
216
|
+
def test_current_newer(self):
|
|
217
|
+
from devrev_mcp.tools.server_info import _compare_versions
|
|
218
|
+
|
|
219
|
+
assert _compare_versions("2.7.0", "2.6.0") is True
|
|
220
|
+
|
|
221
|
+
def test_current_older(self):
|
|
222
|
+
from devrev_mcp.tools.server_info import _compare_versions
|
|
223
|
+
|
|
224
|
+
assert _compare_versions("2.5.0", "2.6.0") is False
|
|
225
|
+
|
|
226
|
+
def test_major_version_difference(self):
|
|
227
|
+
from devrev_mcp.tools.server_info import _compare_versions
|
|
228
|
+
|
|
229
|
+
assert _compare_versions("3.0.0", "2.99.99") is True
|
|
230
|
+
assert _compare_versions("1.99.99", "2.0.0") is False
|
|
231
|
+
|
|
232
|
+
def test_invalid_version_returns_none(self):
|
|
233
|
+
"""Test that invalid versions return None when packaging is not available."""
|
|
234
|
+
import sys
|
|
235
|
+
from unittest.mock import patch
|
|
236
|
+
|
|
237
|
+
from devrev_mcp.tools.server_info import _compare_versions
|
|
238
|
+
|
|
239
|
+
# Mock ImportError to force fallback to simple comparison
|
|
240
|
+
# We need to patch the import at the point where it's used
|
|
241
|
+
with patch.dict(sys.modules, {"packaging.version": None}):
|
|
242
|
+
result = _compare_versions("invalid", "also-invalid")
|
|
243
|
+
assert result is None
|
|
244
|
+
|
|
245
|
+
def test_invalid_version_with_packaging_degrades_gracefully(self):
|
|
246
|
+
"""Test that invalid versions degrade gracefully even when packaging is available."""
|
|
247
|
+
from devrev_mcp.tools.server_info import _compare_versions
|
|
248
|
+
|
|
249
|
+
# When packaging is available but version strings are invalid, should return None
|
|
250
|
+
result = _compare_versions("invalid", "also-invalid")
|
|
251
|
+
assert result is None
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
class TestFetchLatestPyPIVersion:
|
|
255
|
+
"""Tests for the _fetch_latest_pypi_version helper."""
|
|
256
|
+
|
|
257
|
+
@pytest.mark.asyncio
|
|
258
|
+
async def test_successful_fetch(self):
|
|
259
|
+
"""Test successful PyPI version fetch."""
|
|
260
|
+
from devrev_mcp.tools.server_info import _fetch_latest_pypi_version
|
|
261
|
+
|
|
262
|
+
mock_response = MagicMock()
|
|
263
|
+
mock_response.json.return_value = {"info": {"version": "2.6.0"}}
|
|
264
|
+
mock_response.raise_for_status = MagicMock()
|
|
265
|
+
|
|
266
|
+
with patch("devrev_mcp.tools.server_info.httpx.AsyncClient") as mock_client_cls:
|
|
267
|
+
mock_client = AsyncMock()
|
|
268
|
+
mock_client.get = AsyncMock(return_value=mock_response)
|
|
269
|
+
mock_client.__aenter__ = AsyncMock(return_value=mock_client)
|
|
270
|
+
mock_client.__aexit__ = AsyncMock(return_value=None)
|
|
271
|
+
mock_client_cls.return_value = mock_client
|
|
272
|
+
|
|
273
|
+
result = await _fetch_latest_pypi_version()
|
|
274
|
+
assert result == "2.6.0"
|
|
275
|
+
|
|
276
|
+
@pytest.mark.asyncio
|
|
277
|
+
async def test_network_error_returns_none(self):
|
|
278
|
+
"""Test that network errors return None."""
|
|
279
|
+
from devrev_mcp.tools.server_info import _fetch_latest_pypi_version
|
|
280
|
+
|
|
281
|
+
with patch("devrev_mcp.tools.server_info.httpx.AsyncClient") as mock_client_cls:
|
|
282
|
+
mock_client = AsyncMock()
|
|
283
|
+
mock_client.get = AsyncMock(side_effect=Exception("Network error"))
|
|
284
|
+
mock_client.__aenter__ = AsyncMock(return_value=mock_client)
|
|
285
|
+
mock_client.__aexit__ = AsyncMock(return_value=None)
|
|
286
|
+
mock_client_cls.return_value = mock_client
|
|
287
|
+
|
|
288
|
+
result = await _fetch_latest_pypi_version()
|
|
289
|
+
assert result is None
|
|
290
|
+
|
|
291
|
+
@pytest.mark.asyncio
|
|
292
|
+
async def test_malformed_response_returns_none(self):
|
|
293
|
+
"""Test that malformed JSON responses return None gracefully."""
|
|
294
|
+
from devrev_mcp.tools.server_info import _fetch_latest_pypi_version
|
|
295
|
+
|
|
296
|
+
mock_response = MagicMock()
|
|
297
|
+
mock_response.json.return_value = {} # Missing 'info' key
|
|
298
|
+
mock_response.raise_for_status = MagicMock()
|
|
299
|
+
|
|
300
|
+
with patch("devrev_mcp.tools.server_info.httpx.AsyncClient") as mock_client_cls:
|
|
301
|
+
mock_client = AsyncMock()
|
|
302
|
+
mock_client.get = AsyncMock(return_value=mock_response)
|
|
303
|
+
mock_client.__aenter__ = AsyncMock(return_value=mock_client)
|
|
304
|
+
mock_client.__aexit__ = AsyncMock(return_value=None)
|
|
305
|
+
mock_client_cls.return_value = mock_client
|
|
306
|
+
|
|
307
|
+
result = await _fetch_latest_pypi_version()
|
|
308
|
+
assert result is None # .get("info", {}).get("version") returns None
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
class TestServerInstructions:
|
|
312
|
+
"""Tests for the server instructions parameter."""
|
|
313
|
+
|
|
314
|
+
def test_mcp_server_has_instructions(self):
|
|
315
|
+
"""Test that the MCP server instance has instructions set."""
|
|
316
|
+
import os
|
|
317
|
+
from unittest.mock import patch as mock_patch
|
|
318
|
+
|
|
319
|
+
with mock_patch.dict(os.environ, {"DEVREV_API_TOKEN": "test-token"}, clear=False):
|
|
320
|
+
from devrev_mcp.server import mcp
|
|
321
|
+
|
|
322
|
+
# FastMCP stores instructions - check it's set and contains version info
|
|
323
|
+
assert mcp.instructions is not None
|
|
324
|
+
assert "DevRev MCP Server" in mcp.instructions
|
|
325
|
+
assert "devrev_server_info" in mcp.instructions
|
|
326
|
+
|
|
327
|
+
def test_instructions_contain_version(self):
|
|
328
|
+
"""Test that instructions include the version string."""
|
|
329
|
+
import os
|
|
330
|
+
from unittest.mock import patch as mock_patch
|
|
331
|
+
|
|
332
|
+
with mock_patch.dict(os.environ, {"DEVREV_API_TOKEN": "test-token"}, clear=False):
|
|
333
|
+
from devrev_mcp import __version__
|
|
334
|
+
from devrev_mcp.server import mcp
|
|
335
|
+
|
|
336
|
+
assert __version__ in mcp.instructions
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|