feat: add MCP server core, stdio and streamable HTTP transports and serve command
Low-level SDK server built from the catalog plus gitea_api_request, with TOOLSETS/READ_ONLY/DISABLED_TOOLS filters, schema validation without value echo, one audit event per call, static bearer verifier, identity resolver hook, /health, DNS-rebinding protection, rate limiting and fail-closed startup checks.
This commit is contained in:
1 parent
581ca67bf8
commit
c9e2c481e7
11 files changed
+2846
-14
No files matched your search
@@ -1,16 +1,20 @@
|
||||
"""Command line entry point (``aegis-gitea-mcp``).
|
||||
|
||||
Subcommands: ``serve`` (default), ``setup`` and ``version``. ``serve`` and
|
||||
``setup`` are filled in by later chunks.
|
||||
Subcommands: ``serve`` (default), ``setup`` and ``version``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
from collections.abc import Sequence
|
||||
|
||||
from pydantic import ValidationError
|
||||
|
||||
from aegis_gitea_mcp import __version__, setup_cmd
|
||||
from aegis_gitea_mcp.config import Settings, get_settings, reset_settings
|
||||
from aegis_gitea_mcp.logging_utils import configure_logging
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
@@ -28,6 +32,15 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
default=None,
|
||||
help="transport to serve (default: MCP_TRANSPORT, else stdio)",
|
||||
)
|
||||
serve.add_argument("--host", default=None, help="HTTP bind address (default: MCP_HOST)")
|
||||
serve.add_argument(
|
||||
"--port",
|
||||
type=int,
|
||||
default=None,
|
||||
choices=range(1, 65536),
|
||||
metavar="PORT",
|
||||
help="HTTP port (default: MCP_PORT)",
|
||||
)
|
||||
|
||||
setup = subparsers.add_parser("setup", help="verify a Gitea instance and write the env file")
|
||||
setup_cmd.add_arguments(setup)
|
||||
@@ -35,10 +48,40 @@ def build_parser() -> argparse.ArgumentParser:
|
||||
return parser
|
||||
|
||||
|
||||
def _not_implemented(command: str) -> int:
|
||||
"""Report an unbuilt command and return the usage-error exit code."""
|
||||
print(f"aegis-gitea-mcp {command}: not implemented yet", file=sys.stderr)
|
||||
return 2
|
||||
def _load_settings(args: argparse.Namespace) -> Settings | None:
|
||||
"""Load settings with the ``serve`` flags applied; print problems and return None."""
|
||||
port = getattr(args, "port", None)
|
||||
overrides = {
|
||||
"MCP_TRANSPORT": getattr(args, "transport", None),
|
||||
"MCP_HOST": getattr(args, "host", None),
|
||||
"MCP_PORT": None if port is None else str(port),
|
||||
}
|
||||
for name, value in overrides.items():
|
||||
if value is not None:
|
||||
os.environ[name] = value
|
||||
reset_settings()
|
||||
try:
|
||||
return get_settings()
|
||||
except ValidationError as exc:
|
||||
# Print field names and messages only: str(exc) would echo the offending values.
|
||||
print("aegis-gitea-mcp: invalid configuration:", file=sys.stderr)
|
||||
for error in exc.errors(include_input=False, include_url=False):
|
||||
field = ".".join(str(part) for part in error["loc"]).upper() or "settings"
|
||||
print(f" {field}: {error['msg']}", file=sys.stderr)
|
||||
return None
|
||||
|
||||
|
||||
def run_serve(args: argparse.Namespace) -> int:
|
||||
"""Run the MCP server over the selected transport and return the exit code."""
|
||||
from aegis_gitea_mcp import transports
|
||||
|
||||
settings = _load_settings(args)
|
||||
if settings is None:
|
||||
return 2
|
||||
configure_logging(settings.log_level)
|
||||
if settings.mcp_transport == "http":
|
||||
return transports.run_http(settings)
|
||||
return transports.run_stdio(settings)
|
||||
|
||||
|
||||
def main(argv: Sequence[str] | None = None) -> int:
|
||||
@@ -51,7 +94,7 @@ def main(argv: Sequence[str] | None = None) -> int:
|
||||
return 0
|
||||
if command == "setup":
|
||||
return setup_cmd.run_setup(args)
|
||||
return _not_implemented(command)
|
||||
return run_serve(args)
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
|
||||
Reference in new issue
Block a user