generated from personal-projects/leo-claude-mktplace
Compare commits
2 Commits
c9961293d9
...
5075139841
| Author | SHA1 | Date | |
|---|---|---|---|
| 5075139841 | |||
| 16436c847a |
@@ -143,7 +143,7 @@ cp .env.example .env
|
|||||||
nano .env
|
nano .env
|
||||||
|
|
||||||
# Run the server
|
# Run the server
|
||||||
gitea-http-wrapper
|
gitea-mcp-remote
|
||||||
```
|
```
|
||||||
|
|
||||||
The server will start on the configured host/port (default: `http://127.0.0.1:8000`).
|
The server will start on the configured host/port (default: `http://127.0.0.1:8000`).
|
||||||
@@ -237,10 +237,10 @@ pip install -e ".[dev]"
|
|||||||
pytest
|
pytest
|
||||||
|
|
||||||
# Run with coverage
|
# Run with coverage
|
||||||
pytest --cov=gitea_http_wrapper
|
pytest --cov=gitea_mcp_remote
|
||||||
|
|
||||||
# Run specific test file
|
# Run specific test file
|
||||||
pytest src/gitea_http_wrapper/tests/test_config.py
|
pytest src/gitea_mcp_remote/tests/test_config.py
|
||||||
```
|
```
|
||||||
|
|
||||||
### Project Structure
|
### Project Structure
|
||||||
@@ -248,7 +248,7 @@ pytest src/gitea_http_wrapper/tests/test_config.py
|
|||||||
```
|
```
|
||||||
gitea-mcp-remote/
|
gitea-mcp-remote/
|
||||||
├── src/
|
├── src/
|
||||||
│ └── gitea_http_wrapper/
|
│ └── gitea_mcp_remote/
|
||||||
│ ├── __init__.py
|
│ ├── __init__.py
|
||||||
│ ├── server.py # Main HTTP server
|
│ ├── server.py # Main HTTP server
|
||||||
│ ├── config/
|
│ ├── config/
|
||||||
|
|||||||
244
docs/sprint-proposals/SPRINT-01-SUMMARY.md
Normal file
244
docs/sprint-proposals/SPRINT-01-SUMMARY.md
Normal file
@@ -0,0 +1,244 @@
|
|||||||
|
# Sprint 01: Core Architecture Correction - SUMMARY
|
||||||
|
|
||||||
|
**Status:** 🟡 AWAITING APPROVAL
|
||||||
|
**Milestone:** [Sprint 01: Core Architecture Correction](https://gitea.hotserv.cloud/personal-projects/gitea-mcp-remote/milestone/29)
|
||||||
|
**Sprint Duration:** 1 week (Feb 3-10, 2026)
|
||||||
|
**Total Estimated Effort:** 19-28 hours
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Sprint Overview
|
||||||
|
|
||||||
|
This sprint addresses **three fatal architectural problems** introduced in the v1.0.0 release. This is **surgical correction work**, not a rewrite - supporting modules (config, middleware, filtering, tests) are solid and only need import path updates.
|
||||||
|
|
||||||
|
### The Three Fatal Problems
|
||||||
|
|
||||||
|
1. **Subprocess Architecture → Direct Python Import**
|
||||||
|
- Current: Spawns gitea-mcp-server as subprocess
|
||||||
|
- Required: Direct Python import from marketplace package
|
||||||
|
|
||||||
|
2. **Custom REST API → MCP Streamable HTTP Protocol**
|
||||||
|
- Current: Custom endpoints `/tools/list` and `/tools/call`
|
||||||
|
- Required: MCP protocol `POST /mcp` with JSON-RPC 2.0
|
||||||
|
|
||||||
|
3. **Missing Marketplace Dependency**
|
||||||
|
- Current: Comment about installing separately
|
||||||
|
- Required: Actual pip dependency from marketplace Git repo
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Issues Created
|
||||||
|
|
||||||
|
All issues are in Gitea milestone: **Sprint 01: Core Architecture Correction**
|
||||||
|
|
||||||
|
| Issue | Title | Type | Size | Est. Time | Dependencies |
|
||||||
|
|-------|-------|------|------|-----------|--------------|
|
||||||
|
| [#19](https://gitea.hotserv.cloud/personal-projects/gitea-mcp-remote/issues/19) | Rename package to gitea_mcp_remote and update configuration | Refactor | M | 2-3h | None |
|
||||||
|
| [#20](https://gitea.hotserv.cloud/personal-projects/gitea-mcp-remote/issues/20) | Update middleware and filtering with new import paths | Refactor | S | 1h | #19 |
|
||||||
|
| [#21](https://gitea.hotserv.cloud/personal-projects/gitea-mcp-remote/issues/21) | Move tests to repository root and update imports | Refactor | M | 1-2h | #19, #20 |
|
||||||
|
| [#22](https://gitea.hotserv.cloud/personal-projects/gitea-mcp-remote/issues/22) | Add marketplace dependency and update project config | Build | S | 1h | #19 |
|
||||||
|
| [#23](https://gitea.hotserv.cloud/personal-projects/gitea-mcp-remote/issues/23) | Remove old server and create MCP base server structure | Feature | M | 2-3h | #19, #20, #22 |
|
||||||
|
| [#24](https://gitea.hotserv.cloud/personal-projects/gitea-mcp-remote/issues/24) | Implement MCP Streamable HTTP protocol endpoints | Feature | M | 2-3h | #23 |
|
||||||
|
| [#25](https://gitea.hotserv.cloud/personal-projects/gitea-mcp-remote/issues/25) | Create Docker multi-service infrastructure with Caddy | Build | M | 3-4h | #22, #24 |
|
||||||
|
| [#26](https://gitea.hotserv.cloud/personal-projects/gitea-mcp-remote/issues/26) | Create startup scripts and MCP server tests | Test | M | 2-3h | #24 |
|
||||||
|
| [#27](https://gitea.hotserv.cloud/personal-projects/gitea-mcp-remote/issues/27) | Create CLAUDE.md and update deployment documentation | Docs | M | 2-3h | All |
|
||||||
|
| [#28](https://gitea.hotserv.cloud/personal-projects/gitea-mcp-remote/issues/28) | Final validation and integration testing | Test | M | 2-3h | All |
|
||||||
|
|
||||||
|
**Total Issues:** 10 (was 9, split large task into 2 medium tasks)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Execution Order
|
||||||
|
|
||||||
|
The dependency graph ensures proper execution order:
|
||||||
|
|
||||||
|
```
|
||||||
|
#19 (Rename + Config) ← FOUNDATION
|
||||||
|
├─→ #20 (Middleware + Filtering)
|
||||||
|
│ └─→ #21 (Tests)
|
||||||
|
│
|
||||||
|
├─→ #22 (pyproject.toml)
|
||||||
|
│ ├─→ #23 (MCP Base Server)
|
||||||
|
│ │ ├─→ #24 (MCP Protocol)
|
||||||
|
│ │ │ ├─→ #25 (Docker)
|
||||||
|
│ │ │ └─→ #26 (Scripts + Tests)
|
||||||
|
│ │ │
|
||||||
|
│ └─→ #21 (Tests - can run parallel)
|
||||||
|
│
|
||||||
|
└─→ All above
|
||||||
|
└─→ #27 (Documentation)
|
||||||
|
└─→ #28 (Final Validation)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Recommended sequence:**
|
||||||
|
1. #19 → #20 → #22 → #21 (Foundation - Day 1-2)
|
||||||
|
2. #23 → #24 (Core server - Day 2-3)
|
||||||
|
3. #25 → #26 (Infrastructure - Day 3-4)
|
||||||
|
4. #27 → #28 (Documentation and validation - Day 4-5)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What to KEEP (Rename Imports Only)
|
||||||
|
|
||||||
|
These modules are **well-tested and solid**:
|
||||||
|
|
||||||
|
- ✅ `config/settings.py` - Minor field changes only
|
||||||
|
- ✅ `middleware/auth.py` - Import paths only
|
||||||
|
- ✅ `filtering/filter.py` - Change ValueError to warning
|
||||||
|
- ✅ All tests - Move to root, update imports
|
||||||
|
- ✅ `DEPLOYMENT.md` - Update references
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What to REPLACE
|
||||||
|
|
||||||
|
- ❌ `server.py` → ✅ `server_http.py` (new MCP implementation)
|
||||||
|
- ❌ `pyproject.toml` → ✅ Updated with marketplace dependency
|
||||||
|
- ❌ `docker-compose.yml` → ✅ `docker/docker-compose.yml` (two services)
|
||||||
|
- ❌ `Dockerfile` → ✅ `docker/Dockerfile` (git + port 8080)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## New Files to CREATE
|
||||||
|
|
||||||
|
- 📄 `docker/Caddyfile` - Reverse proxy config
|
||||||
|
- 📄 `CLAUDE.md` - Project guidance for Claude Code
|
||||||
|
- 📄 `tests/test_server_http.py` - MCP server tests
|
||||||
|
- 📄 `scripts/start.sh` - Production startup
|
||||||
|
- 📄 `scripts/healthcheck.sh` - Docker healthcheck
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Success Criteria (16 Validations)
|
||||||
|
|
||||||
|
### Package Structure (3)
|
||||||
|
- [ ] `src/gitea_mcp_remote/` exists (not `gitea_http_wrapper`)
|
||||||
|
- [ ] No imports reference `gitea_http_wrapper`
|
||||||
|
- [ ] `tests/` is at repository root (not in `src/`)
|
||||||
|
|
||||||
|
### Configuration (3)
|
||||||
|
- [ ] `config/settings.py` has `mcp_auth_mode` field
|
||||||
|
- [ ] `config/settings.py` has `gitea_repo: str | None`
|
||||||
|
- [ ] HTTP defaults are `0.0.0.0:8080`
|
||||||
|
|
||||||
|
### Server Implementation (4)
|
||||||
|
- [ ] `server_http.py` imports from `mcp_server` package
|
||||||
|
- [ ] MCP endpoints exist: `POST /mcp`, `HEAD /mcp`
|
||||||
|
- [ ] Health endpoints exist: `/health`, `/healthz`, `/ping`
|
||||||
|
- [ ] No subprocess spawning code
|
||||||
|
|
||||||
|
### Dependencies (3)
|
||||||
|
- [ ] `pyproject.toml` has marketplace Git dependency
|
||||||
|
- [ ] Entry point is `gitea-mcp-remote` (not `gitea-http-wrapper`)
|
||||||
|
- [ ] Can run: `pip install -e .` successfully
|
||||||
|
|
||||||
|
### Docker (3)
|
||||||
|
- [ ] `docker/docker-compose.yml` has two services (app + caddy)
|
||||||
|
- [ ] `docker/Dockerfile` installs git and uses port 8080
|
||||||
|
- [ ] `docker/Caddyfile` exists and proxies to app:8080
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Timeline
|
||||||
|
|
||||||
|
### Effort Distribution
|
||||||
|
- **Small (1-2h):** 2 issues (#20, #22) = 2-4 hours
|
||||||
|
- **Medium (2-4h):** 8 issues (#19, #21, #23-28) = 17-24 hours
|
||||||
|
- **Total:** 19-28 hours ≈ 23.5 hours average
|
||||||
|
|
||||||
|
### Sprint Schedule (1 week)
|
||||||
|
- **Day 1-2:** Foundation (Issues #19-22) - 5-7 hours
|
||||||
|
- **Day 2-3:** Core Server (Issues #23-24) - 4-6 hours
|
||||||
|
- **Day 3-4:** Infrastructure (Issues #25-26) - 5-7 hours
|
||||||
|
- **Day 4-5:** Docs & Validation (Issues #27-28) - 4-6 hours
|
||||||
|
- **Buffer:** 1-2 hours for unexpected issues
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Risk Assessment
|
||||||
|
|
||||||
|
### Low Risk ✅
|
||||||
|
- Config, middleware, filtering: Well-tested, only import changes
|
||||||
|
- Test relocation: No logic changes
|
||||||
|
|
||||||
|
### Medium Risk ⚠️
|
||||||
|
- `server_http.py`: New file, but following MCP HTTP spec
|
||||||
|
- MCP protocol integration: Well-documented standard
|
||||||
|
|
||||||
|
### High Risk 🔴
|
||||||
|
- Docker multi-service: Requires Caddy configuration
|
||||||
|
- Marketplace Git dependency: Must be accessible during build
|
||||||
|
|
||||||
|
### Mitigation
|
||||||
|
1. Execute in exact dependency order
|
||||||
|
2. Test at each major milestone
|
||||||
|
3. Validate Docker build before deployment
|
||||||
|
4. Keep development branch for rollback
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Documentation Created
|
||||||
|
|
||||||
|
1. **[sprint-01-core-architecture-correction.md](./sprint-01-core-architecture-correction.md)**
|
||||||
|
- Executive summary
|
||||||
|
- Three fatal problems explained
|
||||||
|
- What to keep vs replace
|
||||||
|
- Architecture diagram
|
||||||
|
- Risk assessment
|
||||||
|
|
||||||
|
2. **[sprint-01-implementation-guide.md](./sprint-01-implementation-guide.md)**
|
||||||
|
- Step-by-step technical implementation
|
||||||
|
- Code snippets for each change
|
||||||
|
- Validation commands
|
||||||
|
- Complete file replacements
|
||||||
|
|
||||||
|
3. **[sprint-01-issue-breakdown.md](./sprint-01-issue-breakdown.md)**
|
||||||
|
- Detailed issue descriptions
|
||||||
|
- Dependency graph
|
||||||
|
- Execution order
|
||||||
|
- Size distribution
|
||||||
|
|
||||||
|
4. **[SPRINT-01-SUMMARY.md](./SPRINT-01-SUMMARY.md)** (this file)
|
||||||
|
- Sprint overview
|
||||||
|
- Issue table with links
|
||||||
|
- Success criteria
|
||||||
|
- Approval checklist
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Links
|
||||||
|
|
||||||
|
- **Milestone:** https://gitea.hotserv.cloud/personal-projects/gitea-mcp-remote/milestone/29
|
||||||
|
- **Repository:** https://gitea.hotserv.cloud/personal-projects/gitea-mcp-remote
|
||||||
|
- **Branch:** development
|
||||||
|
- **Marketplace:** https://gitea.hotserv.cloud/personal-projects/leo-claude-mktplace
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Approval Checklist
|
||||||
|
|
||||||
|
Before execution begins, verify:
|
||||||
|
|
||||||
|
- [ ] All 10 issues created and assigned to milestone
|
||||||
|
- [ ] Dependencies correctly set between issues
|
||||||
|
- [ ] Labels applied correctly (Type, Priority, Component, Size)
|
||||||
|
- [ ] Implementation guide reviewed and accurate
|
||||||
|
- [ ] Timeline is realistic (1 week)
|
||||||
|
- [ ] Success criteria are clear and testable
|
||||||
|
- [ ] Rollback plan understood (development branch)
|
||||||
|
- [ ] User has reviewed and approved the plan
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
**AWAITING USER APPROVAL** to begin execution.
|
||||||
|
|
||||||
|
Once approved:
|
||||||
|
1. Start with Issue #19 (Foundation)
|
||||||
|
2. Follow dependency order strictly
|
||||||
|
3. Update issue status as work progresses
|
||||||
|
4. Run validation after each major milestone
|
||||||
|
5. Complete sprint with Issue #28 (Final Validation)
|
||||||
|
|
||||||
|
**Note:** This is attempt #3. User emphasized paying close attention to details. All requirements from the architectural correction prompt have been captured in the issue breakdown.
|
||||||
329
docs/sprint-proposals/sprint-01-core-architecture-correction.md
Normal file
329
docs/sprint-proposals/sprint-01-core-architecture-correction.md
Normal file
@@ -0,0 +1,329 @@
|
|||||||
|
# Sprint 01: Core Architecture Correction
|
||||||
|
|
||||||
|
**Status:** Planning
|
||||||
|
**Sprint Duration:** 1 week (estimated 20-24 hours of work)
|
||||||
|
**Priority:** CRITICAL - Architectural Foundation
|
||||||
|
**Attempt:** #3 (Pay close attention to details)
|
||||||
|
|
||||||
|
## Executive Summary
|
||||||
|
|
||||||
|
This sprint addresses three fatal architectural problems introduced in the v1.0.0 release that prevent the HTTP wrapper from functioning correctly with the MCP protocol. This is **surgical correction work**, not a rewrite. Supporting modules (config, middleware, filtering, tests) are solid and only need import path updates.
|
||||||
|
|
||||||
|
## The Three Fatal Problems
|
||||||
|
|
||||||
|
### 1. Subprocess Architecture → Direct Python Import
|
||||||
|
**Current (Wrong):** `server.py` spawns `gitea-mcp-server` as a subprocess
|
||||||
|
**Required (Correct):** Direct Python import from marketplace package
|
||||||
|
|
||||||
|
```python
|
||||||
|
# WRONG (current)
|
||||||
|
self.process = await asyncio.create_subprocess_exec("gitea-mcp-server", ...)
|
||||||
|
|
||||||
|
# CORRECT (target)
|
||||||
|
from mcp_server import get_tool_definitions, create_tool_dispatcher, GiteaClient, GiteaConfig
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why this is fatal:** Cannot access marketplace code as subprocess, breaks MCP protocol contract.
|
||||||
|
|
||||||
|
### 2. Custom REST API → MCP Streamable HTTP Protocol
|
||||||
|
**Current (Wrong):** Custom endpoints `/tools/list` and `/tools/call`
|
||||||
|
**Required (Correct):** MCP Streamable HTTP protocol
|
||||||
|
|
||||||
|
```python
|
||||||
|
# WRONG (current)
|
||||||
|
POST /tools/list
|
||||||
|
POST /tools/call
|
||||||
|
|
||||||
|
# CORRECT (target)
|
||||||
|
POST /mcp # JSON-RPC 2.0 messages
|
||||||
|
HEAD /mcp # Protocol version header
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why this is fatal:** Not compatible with Claude Desktop's MCP client implementation.
|
||||||
|
|
||||||
|
### 3. Missing Marketplace Dependency
|
||||||
|
**Current (Wrong):** Comment in pyproject.toml about installing separately
|
||||||
|
**Required (Correct):** Actual pip dependency from marketplace Git repository
|
||||||
|
|
||||||
|
```toml
|
||||||
|
# WRONG (current)
|
||||||
|
# gitea-mcp-server - installed separately (not on PyPI yet)
|
||||||
|
|
||||||
|
# CORRECT (target)
|
||||||
|
dependencies = [
|
||||||
|
"gitea-mcp-server @ git+https://gitea.hotserv.cloud/personal-projects/leo-claude-mktplace.git#subdirectory=mcp-servers/gitea",
|
||||||
|
...
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why this is fatal:** Dependency not installable, breaks Docker builds and deployment.
|
||||||
|
|
||||||
|
## What to KEEP (Rename Imports Only)
|
||||||
|
|
||||||
|
These modules are **solid and well-tested**. Only update import paths from `gitea_http_wrapper` to `gitea_mcp_remote`:
|
||||||
|
|
||||||
|
### config/settings.py
|
||||||
|
- **Keep:** Overall structure, Pydantic settings, validation logic
|
||||||
|
- **Minor changes:**
|
||||||
|
- Make `gitea_repo` optional (allow None)
|
||||||
|
- Add `mcp_auth_mode: str = "optional"` field
|
||||||
|
- Change HTTP defaults: `http_host="0.0.0.0"`, `http_port=8080`
|
||||||
|
- Remove `get_gitea_mcp_env()` method (no longer needed for subprocess)
|
||||||
|
|
||||||
|
### middleware/auth.py
|
||||||
|
- **Keep:** Entire file logic unchanged
|
||||||
|
- **Change:** Import paths only (`gitea_http_wrapper` → `gitea_mcp_remote`)
|
||||||
|
|
||||||
|
### filtering/filter.py
|
||||||
|
- **Keep:** Entire filtering logic
|
||||||
|
- **Changes:**
|
||||||
|
- Line 30: Change `raise ValueError(...)` to `logger.warning(...)` (non-fatal)
|
||||||
|
- Import paths: `gitea_http_wrapper` → `gitea_mcp_remote`
|
||||||
|
|
||||||
|
### Tests (all files)
|
||||||
|
- **Keep:** All test logic and fixtures
|
||||||
|
- **Move:** `src/gitea_http_wrapper/tests/` → `tests/` (top-level)
|
||||||
|
- **Change:** Import paths to reflect new structure
|
||||||
|
|
||||||
|
### DEPLOYMENT.md
|
||||||
|
- **Keep:** Overall deployment guide structure
|
||||||
|
- **Update:** References to new MCP endpoints, Docker structure, marketplace dependency
|
||||||
|
|
||||||
|
## What to REPLACE
|
||||||
|
|
||||||
|
### server.py → server_http.py
|
||||||
|
**Complete replacement** with:
|
||||||
|
- Direct Python imports from marketplace `mcp_server`
|
||||||
|
- MCP Streamable HTTP transport (`POST /mcp`, `HEAD /mcp`)
|
||||||
|
- JSON-RPC 2.0 message handling
|
||||||
|
- GiteaClient instantiation with GiteaConfig
|
||||||
|
- Tool dispatcher integration
|
||||||
|
- Keep health endpoints: `/health`, `/healthz`, `/ping`
|
||||||
|
|
||||||
|
### pyproject.toml
|
||||||
|
**Full replacement** with:
|
||||||
|
- Marketplace Git dependency
|
||||||
|
- Updated package name: `gitea-mcp-remote`
|
||||||
|
- New entry point: `gitea-mcp-remote = "gitea_mcp_remote.server_http:main"`
|
||||||
|
- Updated test paths: `testpaths = ["tests"]`
|
||||||
|
|
||||||
|
### docker-compose.yml → docker/docker-compose.yml
|
||||||
|
**Move and restructure** with:
|
||||||
|
- Two services: `app` (Python server) and `caddy` (reverse proxy)
|
||||||
|
- App listens on port 8080 (internal)
|
||||||
|
- Caddy exposes port 443 (external HTTPS)
|
||||||
|
- Volume for Caddy certs persistence
|
||||||
|
|
||||||
|
### Dockerfile → docker/Dockerfile
|
||||||
|
**Replace** with:
|
||||||
|
- Install `git` package (for Git dependency install)
|
||||||
|
- Expose port 8080 (not 8000)
|
||||||
|
- Use `curl` for healthcheck (not wget)
|
||||||
|
- Install from `requirements.txt` first, then marketplace dependency
|
||||||
|
|
||||||
|
## New Files to CREATE
|
||||||
|
|
||||||
|
### docker/Caddyfile
|
||||||
|
Reverse proxy configuration:
|
||||||
|
- HTTPS termination
|
||||||
|
- Proxy to app:8080
|
||||||
|
- MCP endpoint routing
|
||||||
|
|
||||||
|
### CLAUDE.md
|
||||||
|
Project guidance for Claude Code:
|
||||||
|
- Architecture explanation
|
||||||
|
- Development workflows
|
||||||
|
- Deployment procedures
|
||||||
|
- MCP protocol notes
|
||||||
|
|
||||||
|
### scripts/start.sh
|
||||||
|
Production startup script:
|
||||||
|
- Environment validation
|
||||||
|
- Graceful startup
|
||||||
|
- Logging configuration
|
||||||
|
|
||||||
|
### scripts/healthcheck.sh
|
||||||
|
Docker healthcheck script:
|
||||||
|
- Check `/health` endpoint
|
||||||
|
- Validate MCP endpoint
|
||||||
|
- Exit codes for Docker
|
||||||
|
|
||||||
|
### tests/test_server_http.py
|
||||||
|
New test file for HTTP server:
|
||||||
|
- MCP endpoint tests
|
||||||
|
- JSON-RPC 2.0 validation
|
||||||
|
- Protocol version tests
|
||||||
|
|
||||||
|
## Package Rename
|
||||||
|
|
||||||
|
**From:** `src/gitea_http_wrapper/`
|
||||||
|
**To:** `src/gitea_mcp_remote/`
|
||||||
|
|
||||||
|
All imports throughout codebase must be updated:
|
||||||
|
```python
|
||||||
|
# OLD
|
||||||
|
from gitea_http_wrapper.config import GiteaSettings
|
||||||
|
|
||||||
|
# NEW
|
||||||
|
from gitea_mcp_remote.config import GiteaSettings
|
||||||
|
```
|
||||||
|
|
||||||
|
## Execution Order (18 Steps)
|
||||||
|
|
||||||
|
This is the **exact sequence** that must be followed:
|
||||||
|
|
||||||
|
1. Rename package directory: `gitea_http_wrapper` → `gitea_mcp_remote`
|
||||||
|
2. Update `config/settings.py` (fields + imports)
|
||||||
|
3. Update `middleware/auth.py` (imports only)
|
||||||
|
4. Update `filtering/filter.py` (warning + imports)
|
||||||
|
5. Move tests: `src/gitea_mcp_remote/tests/` → `tests/`
|
||||||
|
6. Update all test imports
|
||||||
|
7. Delete old `server.py`
|
||||||
|
8. Create new `server_http.py` with MCP protocol
|
||||||
|
9. Replace `pyproject.toml` with marketplace dependency
|
||||||
|
10. Update `pytest.ini` test paths
|
||||||
|
11. Create `docker/` directory
|
||||||
|
12. Move and update `docker-compose.yml` → `docker/docker-compose.yml`
|
||||||
|
13. Replace `Dockerfile` → `docker/Dockerfile`
|
||||||
|
14. Create `docker/Caddyfile`
|
||||||
|
15. Create `scripts/start.sh` and `scripts/healthcheck.sh`
|
||||||
|
16. Create `tests/test_server_http.py`
|
||||||
|
17. Create `CLAUDE.md`
|
||||||
|
18. Update `DEPLOYMENT.md` references
|
||||||
|
|
||||||
|
## Validation Checklist (16 Items)
|
||||||
|
|
||||||
|
After implementation, ALL must pass:
|
||||||
|
|
||||||
|
### Package Structure
|
||||||
|
- [ ] `src/gitea_mcp_remote/` exists (not `gitea_http_wrapper`)
|
||||||
|
- [ ] No imports reference `gitea_http_wrapper`
|
||||||
|
- [ ] `tests/` is at repository root (not in `src/`)
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
- [ ] `config/settings.py` has `mcp_auth_mode` field
|
||||||
|
- [ ] `config/settings.py` has `gitea_repo: str | None`
|
||||||
|
- [ ] HTTP defaults are `0.0.0.0:8080`
|
||||||
|
|
||||||
|
### Server Implementation
|
||||||
|
- [ ] `server_http.py` imports from `mcp_server` package
|
||||||
|
- [ ] MCP endpoints exist: `POST /mcp`, `HEAD /mcp`
|
||||||
|
- [ ] Health endpoints exist: `/health`, `/healthz`, `/ping`
|
||||||
|
- [ ] No subprocess spawning code
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
- [ ] `pyproject.toml` has marketplace Git dependency
|
||||||
|
- [ ] Entry point is `gitea-mcp-remote` (not `gitea-http-wrapper`)
|
||||||
|
- [ ] Can run: `pip install -e .` successfully
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
- [ ] `docker/docker-compose.yml` has two services (app + caddy)
|
||||||
|
- [ ] `docker/Dockerfile` installs git and uses port 8080
|
||||||
|
- [ ] `docker/Caddyfile` exists and proxies to app:8080
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
- [ ] All tests pass: `pytest tests/`
|
||||||
|
|
||||||
|
## Architecture Diagram
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ Claude Desktop (MCP Client) │
|
||||||
|
└───────────────────────┬─────────────────────────────────────┘
|
||||||
|
│ JSON-RPC 2.0 over HTTP
|
||||||
|
│ POST /mcp
|
||||||
|
↓
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ Caddy (HTTPS Termination) │
|
||||||
|
│ - TLS/SSL │
|
||||||
|
│ - Reverse proxy to :8080 │
|
||||||
|
└───────────────────────┬─────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
↓
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ server_http.py (MCP HTTP Transport) │
|
||||||
|
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ Starlette App │ │
|
||||||
|
│ │ - POST /mcp (JSON-RPC handler) │ │
|
||||||
|
│ │ - HEAD /mcp (protocol version) │ │
|
||||||
|
│ │ - /health endpoints │ │
|
||||||
|
│ └────────────────────┬────────────────────────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ↓ │
|
||||||
|
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ Middleware Stack │ │
|
||||||
|
│ │ - BearerAuthMiddleware (auth.py) ✓ Keep │ │
|
||||||
|
│ │ - HealthCheckBypassMiddleware ✓ Keep │ │
|
||||||
|
│ └────────────────────┬────────────────────────────────────┘ │
|
||||||
|
│ │ │
|
||||||
|
│ ↓ │
|
||||||
|
│ ┌─────────────────────────────────────────────────────────┐ │
|
||||||
|
│ │ Tool Dispatcher │ │
|
||||||
|
│ │ - create_tool_dispatcher() from mcp_server │ │
|
||||||
|
│ │ - Tool filtering (filter.py) ✓ Keep │ │
|
||||||
|
│ └────────────────────┬────────────────────────────────────┘ │
|
||||||
|
└──────────────────────┼──────────────────────────────────────┘
|
||||||
|
│ Direct Python calls
|
||||||
|
↓
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ Marketplace: mcp_server (gitea-mcp-server) │
|
||||||
|
│ - GiteaClient │
|
||||||
|
│ - GiteaConfig │
|
||||||
|
│ - get_tool_definitions() │
|
||||||
|
│ - create_tool_dispatcher() │
|
||||||
|
└───────────────────────┬─────────────────────────────────────┘
|
||||||
|
│ HTTPS API calls
|
||||||
|
↓
|
||||||
|
┌─────────────────────────────────────────────────────────────┐
|
||||||
|
│ Gitea Instance (gitea.hotserv.cloud) │
|
||||||
|
└─────────────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## Risk Assessment
|
||||||
|
|
||||||
|
### Low Risk (Supporting Modules)
|
||||||
|
- Config, middleware, filtering: Well-tested, only import changes
|
||||||
|
- Tests: Moving location, no logic changes
|
||||||
|
|
||||||
|
### Medium Risk (New Server Implementation)
|
||||||
|
- `server_http.py`: New file, but following MCP HTTP spec closely
|
||||||
|
- MCP protocol integration: Well-documented standard
|
||||||
|
|
||||||
|
### High Risk (Deployment Changes)
|
||||||
|
- Docker multi-service setup: Requires Caddy configuration
|
||||||
|
- Marketplace Git dependency: Must be accessible during build
|
||||||
|
|
||||||
|
### Mitigation Strategy
|
||||||
|
1. Execute in exact order (dependencies first, server last)
|
||||||
|
2. Test at each major milestone (config → middleware → server)
|
||||||
|
3. Validate Docker build before final deployment
|
||||||
|
4. Keep development branch for rollback if needed
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
1. ✅ All 16 validation items pass
|
||||||
|
2. ✅ Can install via `pip install -e .`
|
||||||
|
3. ✅ Can build Docker image successfully
|
||||||
|
4. ✅ Can start via `docker-compose up`
|
||||||
|
5. ✅ MCP endpoint responds to `POST /mcp` with protocol version
|
||||||
|
6. ✅ Claude Desktop can connect and list tools
|
||||||
|
7. ✅ Can create Gitea issue via MCP protocol
|
||||||
|
8. ✅ All tests pass
|
||||||
|
|
||||||
|
## Timeline Estimate
|
||||||
|
|
||||||
|
- **Setup & Config Changes:** 2-3 hours
|
||||||
|
- **Server Rewrite:** 4-6 hours
|
||||||
|
- **Docker Restructure:** 3-4 hours
|
||||||
|
- **Testing & Validation:** 4-5 hours
|
||||||
|
- **Documentation:** 2-3 hours
|
||||||
|
- **Buffer for Issues:** 4-5 hours
|
||||||
|
|
||||||
|
**Total:** 19-26 hours → 1 week sprint
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- MCP Streamable HTTP Spec: https://spec.modelcontextprotocol.io/specification/basic/transports/
|
||||||
|
- JSON-RPC 2.0 Spec: https://www.jsonrpc.org/specification
|
||||||
|
- Marketplace Repository: https://gitea.hotserv.cloud/personal-projects/leo-claude-mktplace
|
||||||
|
- Original Issue: (To be created in this sprint)
|
||||||
1454
docs/sprint-proposals/sprint-01-implementation-guide.md
Normal file
1454
docs/sprint-proposals/sprint-01-implementation-guide.md
Normal file
File diff suppressed because it is too large
Load Diff
489
docs/sprint-proposals/sprint-01-issue-breakdown.md
Normal file
489
docs/sprint-proposals/sprint-01-issue-breakdown.md
Normal file
@@ -0,0 +1,489 @@
|
|||||||
|
# Sprint 01: Issue Breakdown
|
||||||
|
|
||||||
|
## Issue Structure
|
||||||
|
|
||||||
|
Each issue is sized for 1-4 hours of work and includes:
|
||||||
|
- Clear acceptance criteria
|
||||||
|
- Dependencies on other issues
|
||||||
|
- Reference to implementation guide
|
||||||
|
- Appropriate labels
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Issue #1: Rename Package Directory and Update Config
|
||||||
|
|
||||||
|
**Title:** `[Sprint 01] refactor: Rename package to gitea_mcp_remote and update configuration`
|
||||||
|
|
||||||
|
**Estimated Time:** 2-3 hours
|
||||||
|
|
||||||
|
**Labels:**
|
||||||
|
- `Type/Refactor`
|
||||||
|
- `Priority/High`
|
||||||
|
- `Component/Core`
|
||||||
|
- `Size/M`
|
||||||
|
|
||||||
|
**Dependencies:** None
|
||||||
|
|
||||||
|
**Description:**
|
||||||
|
|
||||||
|
Rename the package directory from `gitea_http_wrapper` to `gitea_mcp_remote` and update the configuration module with new fields required for MCP protocol.
|
||||||
|
|
||||||
|
**Tasks:**
|
||||||
|
- [ ] Rename `src/gitea_http_wrapper/` to `src/gitea_mcp_remote/`
|
||||||
|
- [ ] Update `config/settings.py`:
|
||||||
|
- Make `gitea_repo` optional (allow None)
|
||||||
|
- Add `mcp_auth_mode: str = "optional"` field
|
||||||
|
- Change HTTP defaults: `http_host="0.0.0.0"`, `http_port=8080`
|
||||||
|
- Remove `get_gitea_mcp_env()` method
|
||||||
|
- [ ] Update `config/__init__.py` imports
|
||||||
|
- [ ] Verify imports work: `from gitea_mcp_remote.config import GiteaSettings`
|
||||||
|
|
||||||
|
**Acceptance Criteria:**
|
||||||
|
- Package directory is `src/gitea_mcp_remote/`
|
||||||
|
- Config has `mcp_auth_mode` field
|
||||||
|
- Config has optional `gitea_repo` field
|
||||||
|
- HTTP defaults are `0.0.0.0:8080`
|
||||||
|
- Can import: `from gitea_mcp_remote.config import GiteaSettings`
|
||||||
|
|
||||||
|
**Implementation Reference:**
|
||||||
|
See `docs/sprint-proposals/sprint-01-implementation-guide.md` - Phase 1, Issues #1-2
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Issue #2: Update Middleware and Filtering Modules
|
||||||
|
|
||||||
|
**Title:** `[Sprint 01] refactor: Update middleware and filtering with new import paths`
|
||||||
|
|
||||||
|
**Estimated Time:** 1 hour
|
||||||
|
|
||||||
|
**Labels:**
|
||||||
|
- `Type/Refactor`
|
||||||
|
- `Priority/High`
|
||||||
|
- `Component/Core`
|
||||||
|
- `Size/S`
|
||||||
|
|
||||||
|
**Dependencies:** Issue #1
|
||||||
|
|
||||||
|
**Description:**
|
||||||
|
|
||||||
|
Update middleware and filtering modules to use new package name. Middleware requires only import changes, filtering changes ValueError to warning.
|
||||||
|
|
||||||
|
**Tasks:**
|
||||||
|
- [ ] Update `middleware/__init__.py` imports
|
||||||
|
- [ ] Update `middleware/auth.py` - imports only
|
||||||
|
- [ ] Update `filtering/__init__.py` imports
|
||||||
|
- [ ] Update `filtering/filter.py`:
|
||||||
|
- Add logging import
|
||||||
|
- Change line 29-32 ValueError to logger.warning
|
||||||
|
- [ ] Verify imports work
|
||||||
|
|
||||||
|
**Acceptance Criteria:**
|
||||||
|
- Middleware imports from `gitea_mcp_remote.middleware`
|
||||||
|
- Filtering imports from `gitea_mcp_remote.filtering`
|
||||||
|
- ToolFilter logs warning instead of raising ValueError when both filter types specified
|
||||||
|
- Can import both modules successfully
|
||||||
|
|
||||||
|
**Implementation Reference:**
|
||||||
|
See `docs/sprint-proposals/sprint-01-implementation-guide.md` - Phase 2, Issues #3-4
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Issue #3: Relocate Tests and Update Imports
|
||||||
|
|
||||||
|
**Title:** `[Sprint 01] refactor: Move tests to repository root and update imports`
|
||||||
|
|
||||||
|
**Estimated Time:** 1-2 hours
|
||||||
|
|
||||||
|
**Labels:**
|
||||||
|
- `Type/Refactor`
|
||||||
|
- `Priority/High`
|
||||||
|
- `Component/Tests`
|
||||||
|
- `Size/M`
|
||||||
|
|
||||||
|
**Dependencies:** Issue #1, Issue #2
|
||||||
|
|
||||||
|
**Description:**
|
||||||
|
|
||||||
|
Move test suite from `src/gitea_mcp_remote/tests/` to repository root `tests/` directory and update all test imports to use new package name.
|
||||||
|
|
||||||
|
**Tasks:**
|
||||||
|
- [ ] Move `src/gitea_mcp_remote/tests/` to `tests/`
|
||||||
|
- [ ] Update imports in `tests/conftest.py`
|
||||||
|
- [ ] Update imports in `tests/test_config.py`
|
||||||
|
- [ ] Update imports in `tests/test_middleware.py`
|
||||||
|
- [ ] Update imports in `tests/test_filtering.py`
|
||||||
|
- [ ] Update `pytest.ini` to use `testpaths = tests`
|
||||||
|
- [ ] Run pytest and verify all tests pass
|
||||||
|
|
||||||
|
**Acceptance Criteria:**
|
||||||
|
- Tests located at repository root: `tests/`
|
||||||
|
- No tests in `src/gitea_mcp_remote/tests/`
|
||||||
|
- All test imports use `gitea_mcp_remote` package name
|
||||||
|
- All existing tests pass: `pytest tests/ -v`
|
||||||
|
- pytest.ini references `testpaths = tests`
|
||||||
|
|
||||||
|
**Implementation Reference:**
|
||||||
|
See `docs/sprint-proposals/sprint-01-implementation-guide.md` - Phase 3, Issues #5-6
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Issue #4: Replace pyproject.toml with Marketplace Dependency
|
||||||
|
|
||||||
|
**Title:** `[Sprint 01] build: Add marketplace dependency and update project configuration`
|
||||||
|
|
||||||
|
**Estimated Time:** 1 hour
|
||||||
|
|
||||||
|
**Labels:**
|
||||||
|
- `Type/Build`
|
||||||
|
- `Priority/Critical`
|
||||||
|
- `Component/Dependencies`
|
||||||
|
- `Size/S`
|
||||||
|
|
||||||
|
**Dependencies:** Issue #1
|
||||||
|
|
||||||
|
**Description:**
|
||||||
|
|
||||||
|
Replace pyproject.toml with new configuration including the marketplace Git dependency for gitea-mcp-server.
|
||||||
|
|
||||||
|
**Tasks:**
|
||||||
|
- [ ] Update `pyproject.toml`:
|
||||||
|
- Add marketplace Git dependency
|
||||||
|
- Update package name to `gitea-mcp-remote`
|
||||||
|
- Change entry point to `gitea-mcp-remote`
|
||||||
|
- Update version to 1.1.0
|
||||||
|
- Update test paths to `testpaths = ["tests"]`
|
||||||
|
- [ ] Test installation: `pip install -e .`
|
||||||
|
- [ ] Verify marketplace dependency installs
|
||||||
|
- [ ] Verify entry point exists: `which gitea-mcp-remote`
|
||||||
|
|
||||||
|
**Acceptance Criteria:**
|
||||||
|
- pyproject.toml includes marketplace Git dependency
|
||||||
|
- Entry point is `gitea-mcp-remote` (not `gitea-http-wrapper`)
|
||||||
|
- Can run: `pip install -e .` successfully
|
||||||
|
- Marketplace dependency installs from Git repository
|
||||||
|
- Command `gitea-mcp-remote` is available
|
||||||
|
|
||||||
|
**Implementation Reference:**
|
||||||
|
See `docs/sprint-proposals/sprint-01-implementation-guide.md` - Phase 5, Issue #9
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Issue #5: Implement MCP HTTP Server
|
||||||
|
|
||||||
|
**Title:** `[Sprint 01] feat: Implement MCP Streamable HTTP protocol server`
|
||||||
|
|
||||||
|
**Estimated Time:** 4-6 hours
|
||||||
|
|
||||||
|
**Labels:**
|
||||||
|
- `Type/Feature`
|
||||||
|
- `Priority/Critical`
|
||||||
|
- `Component/Core`
|
||||||
|
- `Size/L` → **BREAKDOWN REQUIRED**
|
||||||
|
|
||||||
|
**Dependencies:** Issue #1, Issue #2, Issue #4
|
||||||
|
|
||||||
|
**Description:**
|
||||||
|
|
||||||
|
**NOTE:** This is a Large (L) task that should be broken down into Medium (M) subtasks:
|
||||||
|
|
||||||
|
### Subtask 5.1: Remove Old Server and Create MCP Base Server (2-3 hours)
|
||||||
|
- Delete `src/gitea_mcp_remote/server.py`
|
||||||
|
- Create `src/gitea_mcp_remote/server_http.py` with:
|
||||||
|
- Imports from marketplace `mcp_server`
|
||||||
|
- GiteaMCPServer class with GiteaClient initialization
|
||||||
|
- Startup/shutdown handlers
|
||||||
|
- Basic route structure
|
||||||
|
|
||||||
|
### Subtask 5.2: Implement MCP Protocol Endpoints (2-3 hours)
|
||||||
|
- Add HEAD /mcp endpoint (protocol version)
|
||||||
|
- Add POST /mcp endpoint (JSON-RPC 2.0 handler)
|
||||||
|
- Implement MCP methods:
|
||||||
|
- `initialize`
|
||||||
|
- `tools/list`
|
||||||
|
- `tools/call`
|
||||||
|
- Add error handling for JSON-RPC
|
||||||
|
|
||||||
|
**Combined Tasks:**
|
||||||
|
- [ ] Delete old `server.py`
|
||||||
|
- [ ] Create new `server_http.py`
|
||||||
|
- [ ] Import from marketplace: `from mcp_server import ...`
|
||||||
|
- [ ] Implement GiteaMCPServer class
|
||||||
|
- [ ] Implement HEAD /mcp (protocol version)
|
||||||
|
- [ ] Implement POST /mcp (JSON-RPC handler)
|
||||||
|
- [ ] Implement initialize method
|
||||||
|
- [ ] Implement tools/list method with filtering
|
||||||
|
- [ ] Implement tools/call method with dispatcher
|
||||||
|
- [ ] Keep health endpoints: /health, /healthz, /ping
|
||||||
|
- [ ] Add JSON-RPC error handling
|
||||||
|
- [ ] Verify imports: `from gitea_mcp_remote.server_http import GiteaMCPServer`
|
||||||
|
|
||||||
|
**Acceptance Criteria:**
|
||||||
|
- Old `server.py` deleted
|
||||||
|
- New `server_http.py` exists
|
||||||
|
- Imports from marketplace `mcp_server` package
|
||||||
|
- MCP endpoints exist: `POST /mcp`, `HEAD /mcp`
|
||||||
|
- Health endpoints exist: `/health`, `/healthz`, `/ping`
|
||||||
|
- No subprocess spawning code
|
||||||
|
- Can import server module successfully
|
||||||
|
- JSON-RPC 2.0 request/response handling works
|
||||||
|
|
||||||
|
**Implementation Reference:**
|
||||||
|
See `docs/sprint-proposals/sprint-01-implementation-guide.md` - Phase 4, Issues #7-8
|
||||||
|
|
||||||
|
**Recommendation:** Create two separate issues (5.1 and 5.2) to keep within M size.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Issue #6: Create Docker Infrastructure
|
||||||
|
|
||||||
|
**Title:** `[Sprint 01] build: Create Docker multi-service infrastructure with Caddy`
|
||||||
|
|
||||||
|
**Estimated Time:** 3-4 hours
|
||||||
|
|
||||||
|
**Labels:**
|
||||||
|
- `Type/Build`
|
||||||
|
- `Priority/High`
|
||||||
|
- `Component/Docker`
|
||||||
|
- `Size/M`
|
||||||
|
|
||||||
|
**Dependencies:** Issue #4, Issue #5
|
||||||
|
|
||||||
|
**Description:**
|
||||||
|
|
||||||
|
Create Docker infrastructure with two-service architecture: Python app and Caddy reverse proxy.
|
||||||
|
|
||||||
|
**Tasks:**
|
||||||
|
- [ ] Create `docker/` directory
|
||||||
|
- [ ] Create `docker/docker-compose.yml` with two services (app + caddy)
|
||||||
|
- [ ] Create `docker/Dockerfile`:
|
||||||
|
- Install git package
|
||||||
|
- Expose port 8080
|
||||||
|
- Use curl for healthcheck
|
||||||
|
- Install marketplace dependency
|
||||||
|
- [ ] Create `docker/Caddyfile`:
|
||||||
|
- HTTPS termination
|
||||||
|
- Proxy to app:8080
|
||||||
|
- MCP endpoint routing
|
||||||
|
- [ ] Validate Dockerfile builds
|
||||||
|
- [ ] Validate docker-compose configuration
|
||||||
|
- [ ] Validate Caddyfile syntax
|
||||||
|
|
||||||
|
**Acceptance Criteria:**
|
||||||
|
- `docker/docker-compose.yml` has two services (app + caddy)
|
||||||
|
- `docker/Dockerfile` installs git and uses port 8080
|
||||||
|
- `docker/Caddyfile` exists and proxies to app:8080
|
||||||
|
- Can build: `docker build -f docker/Dockerfile -t test .`
|
||||||
|
- Can validate: `docker-compose -f docker/docker-compose.yml config`
|
||||||
|
- Caddy config validates successfully
|
||||||
|
|
||||||
|
**Implementation Reference:**
|
||||||
|
See `docs/sprint-proposals/sprint-01-implementation-guide.md` - Phase 6, Issues #11-14
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Issue #7: Create Utility Scripts and Server Tests
|
||||||
|
|
||||||
|
**Title:** `[Sprint 01] test: Create startup scripts and MCP server tests`
|
||||||
|
|
||||||
|
**Estimated Time:** 2-3 hours
|
||||||
|
|
||||||
|
**Labels:**
|
||||||
|
- `Type/Test`
|
||||||
|
- `Priority/Medium`
|
||||||
|
- `Component/Tests`
|
||||||
|
- `Size/M`
|
||||||
|
|
||||||
|
**Dependencies:** Issue #5
|
||||||
|
|
||||||
|
**Description:**
|
||||||
|
|
||||||
|
Create production utility scripts and comprehensive tests for the new MCP HTTP server.
|
||||||
|
|
||||||
|
**Tasks:**
|
||||||
|
- [ ] Create `scripts/start.sh` (production startup)
|
||||||
|
- [ ] Create `scripts/healthcheck.sh` (Docker healthcheck)
|
||||||
|
- [ ] Make scripts executable
|
||||||
|
- [ ] Create `tests/test_server_http.py`:
|
||||||
|
- Health endpoint tests
|
||||||
|
- MCP HEAD endpoint test (protocol version)
|
||||||
|
- MCP POST endpoint tests (initialize, tools/list, tools/call)
|
||||||
|
- JSON-RPC error handling tests
|
||||||
|
- Tool filtering integration test
|
||||||
|
- [ ] Run new tests and verify they pass
|
||||||
|
|
||||||
|
**Acceptance Criteria:**
|
||||||
|
- `scripts/start.sh` validates environment and starts server
|
||||||
|
- `scripts/healthcheck.sh` checks health endpoint
|
||||||
|
- Both scripts are executable
|
||||||
|
- `tests/test_server_http.py` exists with comprehensive coverage
|
||||||
|
- All new tests pass: `pytest tests/test_server_http.py -v`
|
||||||
|
- All existing tests still pass: `pytest tests/ -v`
|
||||||
|
|
||||||
|
**Implementation Reference:**
|
||||||
|
See `docs/sprint-proposals/sprint-01-implementation-guide.md` - Phase 7-8, Issues #15-16
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Issue #8: Create Documentation
|
||||||
|
|
||||||
|
**Title:** `[Sprint 01] docs: Create CLAUDE.md and update deployment documentation`
|
||||||
|
|
||||||
|
**Estimated Time:** 2-3 hours
|
||||||
|
|
||||||
|
**Labels:**
|
||||||
|
- `Type/Documentation`
|
||||||
|
- `Priority/Medium`
|
||||||
|
- `Component/Documentation`
|
||||||
|
- `Size/M`
|
||||||
|
|
||||||
|
**Dependencies:** All previous issues
|
||||||
|
|
||||||
|
**Description:**
|
||||||
|
|
||||||
|
Create comprehensive project documentation for Claude Code and update deployment guide with new MCP protocol and Docker structure.
|
||||||
|
|
||||||
|
**Tasks:**
|
||||||
|
- [ ] Create `CLAUDE.md`:
|
||||||
|
- Project overview
|
||||||
|
- Architecture diagram
|
||||||
|
- Development workflows
|
||||||
|
- MCP protocol notes
|
||||||
|
- Configuration reference
|
||||||
|
- Deployment instructions
|
||||||
|
- Troubleshooting guide
|
||||||
|
- [ ] Update `DEPLOYMENT.md`:
|
||||||
|
- Replace custom REST API refs with MCP protocol
|
||||||
|
- Update Docker structure (docker/ directory, two services)
|
||||||
|
- Update marketplace dependency installation
|
||||||
|
- Update Claude Desktop config example
|
||||||
|
- Add MCP protocol debugging section
|
||||||
|
- [ ] Verify documentation accuracy
|
||||||
|
|
||||||
|
**Acceptance Criteria:**
|
||||||
|
- `CLAUDE.md` exists with complete project guidance
|
||||||
|
- `DEPLOYMENT.md` updated with MCP protocol references
|
||||||
|
- No references to old `/tools/list` or `/tools/call` endpoints
|
||||||
|
- Docker paths reference `docker/docker-compose.yml`
|
||||||
|
- Claude Desktop config shows `/mcp` endpoint
|
||||||
|
- All code examples are accurate
|
||||||
|
|
||||||
|
**Implementation Reference:**
|
||||||
|
See `docs/sprint-proposals/sprint-01-implementation-guide.md` - Phase 9, Issues #17-18
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Issue #9: Final Validation and Integration Testing
|
||||||
|
|
||||||
|
**Title:** `[Sprint 01] test: Final validation and integration testing`
|
||||||
|
|
||||||
|
**Estimated Time:** 2-3 hours
|
||||||
|
|
||||||
|
**Labels:**
|
||||||
|
- `Type/Test`
|
||||||
|
- `Priority/Critical`
|
||||||
|
- `Component/Integration`
|
||||||
|
- `Size/M`
|
||||||
|
|
||||||
|
**Dependencies:** All previous issues
|
||||||
|
|
||||||
|
**Description:**
|
||||||
|
|
||||||
|
Run complete validation checklist to ensure all architectural corrections are in place and working correctly.
|
||||||
|
|
||||||
|
**Tasks:**
|
||||||
|
- [ ] Verify package structure (no gitea_http_wrapper)
|
||||||
|
- [ ] Verify no old imports remain
|
||||||
|
- [ ] Verify config has all new fields
|
||||||
|
- [ ] Verify server has MCP endpoints
|
||||||
|
- [ ] Run: `pip install -e .` successfully
|
||||||
|
- [ ] Run: `pytest tests/ -v` - all tests pass
|
||||||
|
- [ ] Build Docker image successfully
|
||||||
|
- [ ] Validate docker-compose configuration
|
||||||
|
- [ ] Validate Caddyfile syntax
|
||||||
|
- [ ] Test MCP endpoint responds to protocol version request
|
||||||
|
- [ ] Test MCP endpoint handles JSON-RPC messages
|
||||||
|
- [ ] Document any issues found
|
||||||
|
- [ ] Create follow-up issues if needed
|
||||||
|
|
||||||
|
**Acceptance Criteria:**
|
||||||
|
All 16 validation items pass:
|
||||||
|
|
||||||
|
**Package Structure:**
|
||||||
|
- [ ] `src/gitea_mcp_remote/` exists (not `gitea_http_wrapper`)
|
||||||
|
- [ ] No imports reference `gitea_http_wrapper`
|
||||||
|
- [ ] `tests/` is at repository root (not in `src/`)
|
||||||
|
|
||||||
|
**Configuration:**
|
||||||
|
- [ ] `config/settings.py` has `mcp_auth_mode` field
|
||||||
|
- [ ] `config/settings.py` has `gitea_repo: str | None`
|
||||||
|
- [ ] HTTP defaults are `0.0.0.0:8080`
|
||||||
|
|
||||||
|
**Server Implementation:**
|
||||||
|
- [ ] `server_http.py` imports from `mcp_server` package
|
||||||
|
- [ ] MCP endpoints exist: `POST /mcp`, `HEAD /mcp`
|
||||||
|
- [ ] Health endpoints exist: `/health`, `/healthz`, `/ping`
|
||||||
|
- [ ] No subprocess spawning code
|
||||||
|
|
||||||
|
**Dependencies:**
|
||||||
|
- [ ] `pyproject.toml` has marketplace Git dependency
|
||||||
|
- [ ] Entry point is `gitea-mcp-remote` (not `gitea-http-wrapper`)
|
||||||
|
- [ ] Can run: `pip install -e .` successfully
|
||||||
|
|
||||||
|
**Docker:**
|
||||||
|
- [ ] `docker/docker-compose.yml` has two services (app + caddy)
|
||||||
|
- [ ] `docker/Dockerfile` installs git and uses port 8080
|
||||||
|
- [ ] `docker/Caddyfile` exists and proxies to app:8080
|
||||||
|
|
||||||
|
**Tests:**
|
||||||
|
- [ ] All tests pass: `pytest tests/`
|
||||||
|
|
||||||
|
**Implementation Reference:**
|
||||||
|
See `docs/sprint-proposals/sprint-01-implementation-guide.md` - Final Validation section
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Issue Dependencies Graph
|
||||||
|
|
||||||
|
```
|
||||||
|
Issue #1 (Rename + Config)
|
||||||
|
├─→ Issue #2 (Middleware + Filtering)
|
||||||
|
│ └─→ Issue #3 (Tests)
|
||||||
|
│
|
||||||
|
├─→ Issue #4 (pyproject.toml)
|
||||||
|
│ ├─→ Issue #5 (MCP Server)
|
||||||
|
│ │ ├─→ Issue #6 (Docker)
|
||||||
|
│ │ └─→ Issue #7 (Scripts + Tests)
|
||||||
|
│ │
|
||||||
|
│ └─→ Issue #3 (Tests)
|
||||||
|
│
|
||||||
|
└─→ All above
|
||||||
|
└─→ Issue #8 (Documentation)
|
||||||
|
└─→ Issue #9 (Final Validation)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Execution Order
|
||||||
|
|
||||||
|
1. Issue #1 - Rename + Config (Foundation)
|
||||||
|
2. Issue #2 - Middleware + Filtering (Supporting modules)
|
||||||
|
3. Issue #4 - pyproject.toml (Dependencies before server)
|
||||||
|
4. Issue #3 - Tests (Can run in parallel with #4)
|
||||||
|
5. Issue #5 - MCP Server (Core implementation) **Consider splitting into 5.1 and 5.2**
|
||||||
|
6. Issue #6 - Docker (Deployment infrastructure)
|
||||||
|
7. Issue #7 - Scripts + Tests (Validation tools)
|
||||||
|
8. Issue #8 - Documentation (After implementation complete)
|
||||||
|
9. Issue #9 - Final Validation (Sprint completion)
|
||||||
|
|
||||||
|
## Size Distribution
|
||||||
|
|
||||||
|
- **Small (1-2h):** Issues #2, #4 (2 issues)
|
||||||
|
- **Medium (2-4h):** Issues #1, #3, #6, #7, #8, #9 (6 issues)
|
||||||
|
- **Large (4-6h):** Issue #5 (1 issue - SHOULD BE SPLIT)
|
||||||
|
|
||||||
|
**Recommendation:** Split Issue #5 into two Medium issues for better tracking and clearer completion criteria.
|
||||||
|
|
||||||
|
## Total Estimated Time
|
||||||
|
|
||||||
|
- Minimum: 19 hours
|
||||||
|
- Maximum: 28 hours
|
||||||
|
- Average: 23.5 hours
|
||||||
|
- **Sprint Duration:** 1 week (5 working days)
|
||||||
@@ -44,7 +44,7 @@ dev = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[project.scripts]
|
[project.scripts]
|
||||||
gitea-http-wrapper = "gitea_http_wrapper.server:main"
|
gitea-mcp-remote = "gitea_mcp_remote.server:main"
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
Homepage = "https://github.com/lmiranda/gitea-mcp-remote"
|
Homepage = "https://github.com/lmiranda/gitea-mcp-remote"
|
||||||
@@ -55,7 +55,7 @@ where = ["src"]
|
|||||||
|
|
||||||
[tool.pytest.ini_options]
|
[tool.pytest.ini_options]
|
||||||
asyncio_mode = "auto"
|
asyncio_mode = "auto"
|
||||||
testpaths = ["src/gitea_http_wrapper/tests"]
|
testpaths = ["src/gitea_mcp_remote/tests"]
|
||||||
python_files = ["test_*.py"]
|
python_files = ["test_*.py"]
|
||||||
python_classes = ["Test*"]
|
python_classes = ["Test*"]
|
||||||
python_functions = ["test_*"]
|
python_functions = ["test_*"]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
[pytest]
|
[pytest]
|
||||||
testpaths = src/gitea_http_wrapper/tests
|
testpaths = src/gitea_mcp_remote/tests
|
||||||
python_files = test_*.py
|
python_files = test_*.py
|
||||||
python_classes = Test*
|
python_classes = Test*
|
||||||
python_functions = test_*
|
python_functions = test_*
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
"""Configuration loader module."""
|
|
||||||
|
|
||||||
from .settings import GiteaSettings, load_settings
|
|
||||||
|
|
||||||
__all__ = ["GiteaSettings", "load_settings"]
|
|
||||||
5
src/gitea_mcp_remote/config/__init__.py
Normal file
5
src/gitea_mcp_remote/config/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
"""Configuration module for Gitea MCP HTTP transport."""
|
||||||
|
|
||||||
|
from gitea_mcp_remote.config.settings import GiteaSettings, load_settings
|
||||||
|
|
||||||
|
__all__ = ["GiteaSettings", "load_settings"]
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
"""Configuration settings for Gitea HTTP MCP wrapper."""
|
"""Configuration settings for Gitea MCP HTTP transport."""
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
@@ -30,18 +30,18 @@ class GiteaSettings(BaseSettings):
|
|||||||
...,
|
...,
|
||||||
description="Default repository owner/organization",
|
description="Default repository owner/organization",
|
||||||
)
|
)
|
||||||
gitea_repo: str = Field(
|
gitea_repo: str | None = Field(
|
||||||
...,
|
default=None,
|
||||||
description="Default repository name",
|
description="Default repository name (optional)",
|
||||||
)
|
)
|
||||||
|
|
||||||
# HTTP Server Configuration
|
# HTTP Server Configuration
|
||||||
http_host: str = Field(
|
http_host: str = Field(
|
||||||
default="127.0.0.1",
|
default="0.0.0.0",
|
||||||
description="HTTP server bind address",
|
description="HTTP server bind address",
|
||||||
)
|
)
|
||||||
http_port: int = Field(
|
http_port: int = Field(
|
||||||
default=8000,
|
default=8080,
|
||||||
ge=1,
|
ge=1,
|
||||||
le=65535,
|
le=65535,
|
||||||
description="HTTP server port",
|
description="HTTP server port",
|
||||||
@@ -52,6 +52,10 @@ class GiteaSettings(BaseSettings):
|
|||||||
default=None,
|
default=None,
|
||||||
description="Bearer token for HTTP authentication (optional)",
|
description="Bearer token for HTTP authentication (optional)",
|
||||||
)
|
)
|
||||||
|
mcp_auth_mode: str = Field(
|
||||||
|
default="optional",
|
||||||
|
description="MCP authentication mode: 'required', 'optional', or 'none'",
|
||||||
|
)
|
||||||
|
|
||||||
# Tool Filtering Configuration
|
# Tool Filtering Configuration
|
||||||
enabled_tools: Optional[str] = Field(
|
enabled_tools: Optional[str] = Field(
|
||||||
@@ -85,15 +89,6 @@ class GiteaSettings(BaseSettings):
|
|||||||
return None
|
return None
|
||||||
return [tool.strip() for tool in self.disabled_tools.split(",") if tool.strip()]
|
return [tool.strip() for tool in self.disabled_tools.split(",") if tool.strip()]
|
||||||
|
|
||||||
def get_gitea_mcp_env(self) -> dict[str, str]:
|
|
||||||
"""Get environment variables for the wrapped Gitea MCP server."""
|
|
||||||
return {
|
|
||||||
"GITEA_BASE_URL": self.gitea_url,
|
|
||||||
"GITEA_API_TOKEN": self.gitea_token,
|
|
||||||
"GITEA_DEFAULT_OWNER": self.gitea_owner,
|
|
||||||
"GITEA_DEFAULT_REPO": self.gitea_repo,
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def load_settings(env_file: Optional[Path] = None) -> GiteaSettings:
|
def load_settings(env_file: Optional[Path] = None) -> GiteaSettings:
|
||||||
"""
|
"""
|
||||||
@@ -1,7 +1,10 @@
|
|||||||
"""Tool filtering for Claude Desktop compatibility."""
|
"""Tool filtering for Claude Desktop compatibility."""
|
||||||
|
|
||||||
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class ToolFilter:
|
class ToolFilter:
|
||||||
"""
|
"""
|
||||||
@@ -22,13 +25,11 @@ class ToolFilter:
|
|||||||
Args:
|
Args:
|
||||||
enabled_tools: List of tool names to enable. If None, all tools are enabled.
|
enabled_tools: List of tool names to enable. If None, all tools are enabled.
|
||||||
disabled_tools: List of tool names to disable. Takes precedence over enabled_tools.
|
disabled_tools: List of tool names to disable. Takes precedence over enabled_tools.
|
||||||
|
|
||||||
Raises:
|
|
||||||
ValueError: If both enabled_tools and disabled_tools are specified.
|
|
||||||
"""
|
"""
|
||||||
if enabled_tools is not None and disabled_tools is not None:
|
if enabled_tools is not None and disabled_tools is not None:
|
||||||
raise ValueError(
|
logger.warning(
|
||||||
"Cannot specify both enabled_tools and disabled_tools. Choose one filtering mode."
|
"Both enabled_tools and disabled_tools specified. "
|
||||||
|
"Disabled list takes precedence over enabled list."
|
||||||
)
|
)
|
||||||
|
|
||||||
self.enabled_tools = set(enabled_tools) if enabled_tools else None
|
self.enabled_tools = set(enabled_tools) if enabled_tools else None
|
||||||
@@ -16,9 +16,9 @@ from starlette.requests import Request
|
|||||||
from starlette.responses import JSONResponse
|
from starlette.responses import JSONResponse
|
||||||
from starlette.routing import Route
|
from starlette.routing import Route
|
||||||
|
|
||||||
from gitea_http_wrapper.config import GiteaSettings, load_settings
|
from gitea_mcp_remote.config import GiteaSettings, load_settings
|
||||||
from gitea_http_wrapper.filtering import ToolFilter
|
from gitea_mcp_remote.filtering import ToolFilter
|
||||||
from gitea_http_wrapper.middleware import (
|
from gitea_mcp_remote.middleware import (
|
||||||
BearerAuthMiddleware,
|
BearerAuthMiddleware,
|
||||||
HealthCheckBypassMiddleware,
|
HealthCheckBypassMiddleware,
|
||||||
)
|
)
|
||||||
@@ -298,7 +298,7 @@ def main() -> None:
|
|||||||
|
|
||||||
# Run server
|
# Run server
|
||||||
uvicorn.run(
|
uvicorn.run(
|
||||||
"gitea_http_wrapper.server:app",
|
"gitea_mcp_remote.server:app",
|
||||||
host=settings.http_host,
|
host=settings.http_host,
|
||||||
port=settings.http_port,
|
port=settings.http_port,
|
||||||
log_level="info",
|
log_level="info",
|
||||||
@@ -6,7 +6,7 @@ from pathlib import Path
|
|||||||
import pytest
|
import pytest
|
||||||
from pydantic import ValidationError
|
from pydantic import ValidationError
|
||||||
|
|
||||||
from gitea_http_wrapper.config import GiteaSettings, load_settings
|
from gitea_mcp_remote.config import GiteaSettings, load_settings
|
||||||
|
|
||||||
|
|
||||||
class TestGiteaSettings:
|
class TestGiteaSettings:
|
||||||
@@ -2,18 +2,24 @@
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from gitea_http_wrapper.filtering import ToolFilter
|
from gitea_mcp_remote.filtering import ToolFilter
|
||||||
|
|
||||||
|
|
||||||
class TestToolFilter:
|
class TestToolFilter:
|
||||||
"""Test ToolFilter class."""
|
"""Test ToolFilter class."""
|
||||||
|
|
||||||
def test_init_with_both_lists_raises(self):
|
def test_init_with_both_lists_logs_warning(self, caplog):
|
||||||
"""Test that specifying both enabled and disabled lists raises error."""
|
"""Test that specifying both enabled and disabled lists logs warning."""
|
||||||
with pytest.raises(ValueError) as exc_info:
|
import logging
|
||||||
ToolFilter(enabled_tools=["tool1"], disabled_tools=["tool2"])
|
|
||||||
|
|
||||||
assert "Cannot specify both" in str(exc_info.value)
|
with caplog.at_level(logging.WARNING):
|
||||||
|
filter = ToolFilter(enabled_tools=["tool1"], disabled_tools=["tool2"])
|
||||||
|
|
||||||
|
assert "Both enabled_tools and disabled_tools specified" in caplog.text
|
||||||
|
assert "Disabled list takes precedence" in caplog.text
|
||||||
|
|
||||||
|
# Verify disabled list takes precedence
|
||||||
|
assert not filter.should_include_tool("tool2")
|
||||||
|
|
||||||
def test_passthrough_mode(self):
|
def test_passthrough_mode(self):
|
||||||
"""Test passthrough mode (no filtering)."""
|
"""Test passthrough mode (no filtering)."""
|
||||||
@@ -6,7 +6,7 @@ from starlette.responses import JSONResponse
|
|||||||
from starlette.routing import Route
|
from starlette.routing import Route
|
||||||
from starlette.testclient import TestClient
|
from starlette.testclient import TestClient
|
||||||
|
|
||||||
from gitea_http_wrapper.middleware import (
|
from gitea_mcp_remote.middleware import (
|
||||||
BearerAuthMiddleware,
|
BearerAuthMiddleware,
|
||||||
HealthCheckBypassMiddleware,
|
HealthCheckBypassMiddleware,
|
||||||
)
|
)
|
||||||
Reference in New Issue
Block a user