Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Test and Install Package

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.12", "3.13"]

steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"

- name: Install dependencies
run: uv sync --group dev

- name: Build and test
run: make all

- name: Upload coverage reports
uses: codecov/codecov-action@v4
if: matrix.python-version == '3.13'
with:
file: ./htmlcov/index.html
fail_ci_if_error: false

- name: Archive test artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: test-artifacts-${{ matrix.python-version }}
path: |
claude-mcp-test.log
htmlcov/
dist/
retention-days: 7
108 changes: 108 additions & 0 deletions .github/workflows/publish.yml.disabled
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
name: Build and Publish to PyPI

on:
push:
tags:
- 'v*' # Trigger on version tags (v1.0.0, v0.8.1, etc.)
workflow_dispatch: # Allow manual triggering

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.13'

- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"

- name: Install dependencies
run: uv sync --group dev

- name: Run comprehensive tests
run: make all

build-and-publish:
needs: test
runs-on: ubuntu-latest
permissions:
contents: read

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.13'

- name: Install uv
uses: astral-sh/setup-uv@v4
with:
version: "latest"

- name: Install dependencies
run: uv sync --group dev

- name: Build package
run: make build

- name: Check package
run: |
uv tool install twine
uv tool run twine check dist/*

- name: Verify version matches tag
run: |
TAG_VERSION=${GITHUB_REF#refs/tags/v}
PACKAGE_VERSION=$(uv run python -c "from src.bertron_mcp.main import __version__; print(__version__)")
echo "Tag version: $TAG_VERSION"
echo "Package version: $PACKAGE_VERSION"
if [ "$TAG_VERSION" != "$PACKAGE_VERSION" ]; then
echo "Version mismatch! Tag: $TAG_VERSION, Package: $PACKAGE_VERSION"
exit 1
fi

- name: Publish to PyPI (using token-based auth)
if: "!contains(github.ref, 'test') && !contains(github.ref, 'dryrun')"
uses: pypa/gh-action-pypi-publish@release/v1
with:
verify-metadata: true
verbose: true
password: ${{ secrets.PYPI_API_TOKEN }}

- name: Publish to TestPyPI (using token-based auth)
if: "contains(github.ref, 'test') && !contains(github.ref, 'dryrun')"
uses: pypa/gh-action-pypi-publish@release/v1
with:
repository-url: https://test.pypi.org/legacy/
verify-metadata: true
verbose: true
password: ${{ secrets.TEST_PYPI_API_TOKEN }}

- name: Dry run (build only)
if: "contains(github.ref, 'dryrun')"
run: |
echo "Dry run mode - would publish these files:"
ls -la dist/
echo "Package contents:"
uv tool run twine check dist/* --verbose

- name: Upload build artifacts
uses: actions/upload-artifact@v4
if: always()
with:
name: build-artifacts-${{ github.ref_name }}
path: dist/
64 changes: 63 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
.PHONY: test-coverage clean install dev format lint all server build upload-test upload release deptry mypy test-mcp test-mcp-extended test-integration test-version test-mcp-protocol test-claude-mcp
.PHONY: test-coverage clean install dev format lint all server build upload-test upload release deptry mypy test-mcp test-mcp-extended test-mcp-tools test-mcp-constraints test-mcp-errors test-integration test-version test-mcp-protocol test-claude-mcp test-uvx test-uvx-mcp

# Default target
all: clean install dev test-coverage format lint mypy deptry build test-mcp test-mcp-extended test-integration test-version

# CI-safe target (no external dependencies)
ci: clean install dev test-coverage format lint mypy build test-version
@echo "✅ CI pipeline completed successfully!"

# CI with network tests (for environments with reliable network)
ci-network: ci test-mcp test-mcp-extended test-integration
@echo "✅ CI pipeline with network tests completed!"

# Install everything for development
dev:
uv sync --group dev
Expand Down Expand Up @@ -61,6 +69,10 @@ upload:
# Complete release workflow
release: clean install test-coverage build

# Comprehensive MCP testing
test-mcp-comprehensive: test-mcp test-mcp-extended test-mcp-tools test-mcp-constraints test-mcp-errors
@echo "✅ All MCP JSON-RPC tests completed successfully!"

# Integration Testing
test-integration:
@echo "🌤️ Testing BERtron MCP integration..."
Expand Down Expand Up @@ -112,3 +124,53 @@ test-claude-mcp:
2>&1 | tee claude-mcp-test.log


# Test uvx installation from GitHub
test-uvx:
@echo "📦 Testing uvx installation from GitHub..."
uvx --from git+https://github.com/ber-data/bertron-mcp.git bertron-mcp --version

# Test uvx MCP server
test-uvx-mcp:
@echo "🔧 Testing uvx MCP server functionality..."
@(echo '{"jsonrpc": "2.0", "method": "initialize", "params": {"protocolVersion": "2025-03-26", "capabilities": {"tools": {}}, "clientInfo": {"name": "test-client", "version": "1.0.0"}}, "id": 1}'; \
sleep 0.1; \
echo '{"jsonrpc": "2.0", "method": "notifications/initialized", "params": {}}'; \
sleep 0.1; \
echo '{"jsonrpc": "2.0", "method": "tools/list", "id": 2}') | \
timeout 10 uvx --from git+https://github.com/ber-data/bertron-mcp.git bertron-mcp

# Test multiple MCP tools via JSON-RPC
test-mcp-tools:
@echo "🛠️ Testing multiple MCP tools via JSON-RPC..."
@(echo '{"jsonrpc": "2.0", "method": "initialize", "params": {"protocolVersion": "2025-03-26", "capabilities": {"tools": {}}, "clientInfo": {"name": "test-client", "version": "1.0.0"}}, "id": 1}'; \
sleep 0.1; \
echo '{"jsonrpc": "2.0", "method": "notifications/initialized", "params": {}}'; \
sleep 0.1; \
echo '{"jsonrpc": "2.0", "method": "tools/call", "params": {"name": "health_check", "arguments": {}}, "id": 2}'; \
sleep 0.5; \
echo '{"jsonrpc": "2.0", "method": "tools/call", "params": {"name": "search_by_source", "arguments": {"source": "NMDC", "limit": 5}}, "id": 3}'; \
sleep 0.5; \
echo '{"jsonrpc": "2.0", "method": "tools/call", "params": {"name": "search_by_type", "arguments": {"entity_type": "sample", "limit": 3}}, "id": 4}') | \
timeout 15 uv run python src/bertron_mcp/main.py

# Test constraint enforcement via JSON-RPC
test-mcp-constraints:
@echo "🚧 Testing constraint enforcement via JSON-RPC..."
@(echo '{"jsonrpc": "2.0", "method": "initialize", "params": {"protocolVersion": "2025-03-26", "capabilities": {"tools": {}}, "clientInfo": {"name": "test-client", "version": "1.0.0"}}, "id": 1}'; \
sleep 0.1; \
echo '{"jsonrpc": "2.0", "method": "notifications/initialized", "params": {}}'; \
sleep 0.1; \
echo '{"jsonrpc": "2.0", "method": "tools/call", "params": {"name": "search_by_source", "arguments": {"source": "NMDC", "limit": 5000}}, "id": 2}') | \
timeout 10 uv run python src/bertron_mcp/main.py

# Test error handling via JSON-RPC
test-mcp-errors:
@echo "❌ Testing error handling via JSON-RPC..."
@(echo '{"jsonrpc": "2.0", "method": "initialize", "params": {"protocolVersion": "2025-03-26", "capabilities": {"tools": {}}, "clientInfo": {"name": "test-client", "version": "1.0.0"}}, "id": 1}'; \
sleep 0.1; \
echo '{"jsonrpc": "2.0", "method": "notifications/initialized", "params": {}}'; \
sleep 0.1; \
echo '{"jsonrpc": "2.0", "method": "tools/call", "params": {"name": "nonexistent_tool", "arguments": {}}, "id": 2}'; \
sleep 0.5; \
echo '{"jsonrpc": "2.0", "method": "tools/call", "params": {"name": "geosearch", "arguments": {"latitude": 91.0, "longitude": 0.0}}, "id": 3}') | \
timeout 10 uv run python src/bertron_mcp/main.py
Loading