generated from personal-projects/leo-claude-mktplace
Merge feat/19: Rename package to gitea_mcp_remote and update configuration
This commit is contained in:
@@ -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/
|
||||||
|
|||||||
@@ -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