Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4e7bf67
refactor: Use GitPython instead of git in command line
iburel Aug 8, 2025
67c1ec3
fix: properly use GitPython subcommands
NicolasIRAGNE Aug 8, 2025
e143f24
fix: properly use GitPython subcommands
NicolasIRAGNE Aug 8, 2025
b5a1af3
feat: add MCP (Model Context Protocol) server support
iburel Aug 8, 2025
3fa790e
test: add comprehensive MCP server testing and documentation
iburel Aug 8, 2025
cac4faf
test: add comprehensive MCP server testing and documentation
NicolasIRAGNE Aug 9, 2025
4a64fb4
fix: use mcp==1.12.4 instead of mcp>=1.0.0
Aug 12, 2025
81fdf80
drop support for Python 3.8/3.9, require 3.10+
Aug 12, 2025
2baa72b
fix: update test assertions to match GitPython implementation
Aug 12, 2025
61c4bb0
style: apply pre-commit fixes
Aug 12, 2025
b672b8f
style: apply additional pre-commit fixes
Aug 12, 2025
0d419d4
fix: prevent exception information exposure in MCP server
Aug 12, 2025
cee4735
fix: remove problematic docs and fix markdown formatting
Aug 12, 2025
3072551
fix: remove problematic files to fix CI
Aug 12, 2025
642f930
fix: resolve CodeQL security issues and pre-commit hook violations
Aug 12, 2025
289a642
fix: update mcp_server tests to match changed logging calls
Aug 12, 2025
577f6de
fix: disable pylint import-error for optional MCP dependency
Aug 12, 2025
83f0ecd
fix: correct token value in test to match expected value
Aug 12, 2025
f599bfa
fix: suppress remaining dynamic import violations
Aug 12, 2025
46e9749
fix: resolve all pre-commit hook violations
Aug 12, 2025
9869051
refactor to run with --mcp and add metrics
NicolasIRAGNE Aug 12, 2025
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix: resolve CodeQL security issues and pre-commit hook violations
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
  • Loading branch information
2 people authored and NicolasIRAGNE committed Aug 24, 2025
commit 642f930e8e06ff6e2f2222e9c33441b3aceded7b
15 changes: 12 additions & 3 deletions src/gitingest/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,18 +165,27 @@ async def _async_main(
output : str | None
The path where the output file will be written (default: ``digest.txt`` in current directory).
Use ``"-"`` to write to ``stdout``.
mcp_server : bool
If ``True``, starts the MCP (Model Context Protocol) server instead of normal operation (default: ``False``).

Raises
------
click.Abort
Raised if an error occurs during execution and the command must be aborted.
click.ClickException
Raised if MCP server dependencies are not installed when MCP mode is requested.

"""
# Check if MCP server mode is requested
if mcp_server:
from gitingest.mcp_server import start_mcp_server

await start_mcp_server()
# Dynamic import to avoid circular imports and optional dependency
try:
from gitingest.mcp_server import start_mcp_server

await start_mcp_server()
except ImportError as e:
msg = f"MCP server dependencies not installed: {e}"
raise click.ClickException(msg) from e
return

try:
Expand Down
2 changes: 1 addition & 1 deletion src/gitingest/entrypoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import shutil
import stat
import sys
from collections.abc import AsyncGenerator, Callable
from contextlib import asynccontextmanager
from pathlib import Path
from typing import TYPE_CHECKING
Expand All @@ -25,6 +24,7 @@
from gitingest.utils.query_parser_utils import KNOWN_GIT_HOSTS

if TYPE_CHECKING:
from collections.abc import AsyncGenerator, Callable
from types import TracebackType

from gitingest.schemas import IngestionQuery
Expand Down
14 changes: 8 additions & 6 deletions src/gitingest/mcp_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@

from __future__ import annotations

from collections.abc import Sequence
from typing import Any
from typing import TYPE_CHECKING, Any

from mcp.server import Server
from mcp.server.stdio import stdio_server
Expand All @@ -12,6 +11,9 @@
from gitingest.entrypoint import ingest_async
from gitingest.utils.logging_config import get_logger

if TYPE_CHECKING:
from collections.abc import Sequence

# Initialize logger for this module
logger = get_logger(__name__)

Expand Down Expand Up @@ -86,7 +88,7 @@ async def call_tool(name: str, arguments: dict[str, Any]) -> Sequence[TextConten
return await _handle_ingest_repository(arguments)
return [TextContent(type="text", text=f"Unknown tool: {name}")]
except Exception as e:
logger.error(f"Error in tool call {name}: {e}", exc_info=True)
logger.exception("Error in tool call %s", name)
return [TextContent(type="text", text=f"Error executing {name}: {e!s}")]


Expand Down Expand Up @@ -144,17 +146,17 @@ async def _handle_ingest_repository(arguments: dict[str, Any]) -> Sequence[TextC
return [TextContent(type="text", text=response_content)]

except Exception as e:
logger.error(f"Error during ingestion: {e}", exc_info=True)
logger.exception("Error during ingestion")
return [TextContent(type="text", text=f"Error ingesting repository: {e!s}")]


async def start_mcp_server():
async def start_mcp_server() -> None:
"""Start the MCP server with stdio transport."""
logger.info("Starting Gitingest MCP server with stdio transport")
await _run_stdio()


async def _run_stdio():
async def _run_stdio() -> None:
"""Run the MCP server with stdio transport."""
async with stdio_server() as (read_stream, write_stream):
await app.run(
Expand Down
3 changes: 1 addition & 2 deletions src/gitingest/utils/compat_func.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Compatibility functions for Python 3.8."""

import os
from pathlib import Path


Expand All @@ -20,7 +19,7 @@ def readlink(path: Path) -> Path:
The target of the symlink.

"""
return Path(os.readlink(path))
return Path(path).readlink()


def removesuffix(s: str, suffix: str) -> str:
Expand Down
11 changes: 7 additions & 4 deletions src/gitingest/utils/git_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import base64
import re
import sys
from collections.abc import Generator, Iterable
from contextlib import contextmanager
from pathlib import Path
from typing import TYPE_CHECKING, Final
Expand All @@ -19,6 +18,8 @@
from gitingest.utils.logging_config import get_logger

if TYPE_CHECKING:
from collections.abc import Generator, Iterable

from gitingest.schemas import CloneConfig

# Initialize logger for this module
Expand Down Expand Up @@ -221,7 +222,6 @@ async def fetch_remote_branches_or_tags(url: str, *, ref_type: str, token: str |
git_cmd = git.Git()

# Prepare environment with authentication if needed
env = None
if token and is_github_host(url):
auth_url = _add_token_to_url(url, token)
url = auth_url
Expand Down Expand Up @@ -266,6 +266,11 @@ def create_git_repo(local_path: str, url: str, token: str | None = None) -> git.
git.Repo
A GitPython Repo object configured with authentication.

Raises
------
ValueError
If the provided local_path is not a valid git repository.

"""
try:
repo = git.Repo(local_path)
Expand Down Expand Up @@ -552,8 +557,6 @@ def _add_token_to_url(url: str, token: str) -> str:
The URL with embedded authentication.

"""
from urllib.parse import urlparse, urlunparse

parsed = urlparse(url)
# Add token as username in URL (GitHub supports this)
netloc = f"x-oauth-basic:{token}@{parsed.hostname}"
Expand Down