Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,13 @@ The server provides the following tools for interacting with Bugzilla:
- **Returns**: A dictionary containing all available information about the bug (status, assignee, summary, description, attachments, etc.)
- **Example**: `bug_info(12345)` returns complete bug details

- **`bug_comments(id: int, include_private_comments: bool = False)`**: Fetches all comments associated with a given bug ID.
- **`bug_comments(id: int, include_private_comments: bool = False, new_since: Optional[str] = None)`**: Fetches all comments associated with a given bug ID.
- **Parameters**:
- `id`: The bug ID to fetch comments for
- `include_private_comments`: Whether to include private comments (default: `False`)
- `new_since`: Optional date string to only return comments newer than this time
- **Returns**: A list of comment dictionaries, each containing author, timestamp, text, and privacy status
- **Example**: `bug_comments(12345, include_private_comments=True)` returns all comments including private ones
- **Example**: `bug_comments(12345, include_private_comments=True, new_since="2024-01-01")` returns all comments newer than Jan 1, 2024 including private ones

- **`add_comment(bug_id: int, comment: str, is_private: bool = False)`**: Adds a new comment to a specified bug.
- **Parameters**:
Expand Down
10 changes: 7 additions & 3 deletions src/mcp_bugzilla/mcp_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,17 @@ async def bug_info(self, bug_id: int) -> dict[str, Any]:
mcp_log.debug(f"[BZ-RES] {data}")
return data

async def bug_comments(self, bug_id: int) -> list[dict[str, Any]]:
async def bug_comments(self, bug_id: int, new_since: Optional[str] = None) -> list[dict[str, Any]]:
"""Get comments of a bug"""
url = f"/bug/{bug_id}/comment"
mcp_log.info(f"[BZ-REQ] GET {self.api_url}{url}")
params = {}
if new_since:
params["new_since"] = new_since

mcp_log.info(f"[BZ-REQ] GET {self.api_url}{url} params={params}")

try:
r = await self.client.get(url)
r = await self.client.get(url, params=params)
r.raise_for_status()
except httpx.HTTPStatusError as e:
mcp_log.error(
Expand Down
9 changes: 5 additions & 4 deletions src/mcp_bugzilla/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,19 +70,20 @@ async def bug_info(id: int, bz: Bugzilla = Depends(get_bz)) -> dict[str, Any]:

@mcp.tool()
async def bug_comments(
id: int, include_private_comments: bool = False, bz: Bugzilla = Depends(get_bz)
id: int, include_private_comments: bool = False, new_since: Optional[str] = None, bz: Bugzilla = Depends(get_bz)
) -> List[dict[str, Any]]:
"""Returns the comments of given bug id
Private comments are not included by default
but can be explicitly requested
but can be explicitly requested.
new_since allows filtering comments newer than the given date.
"""

mcp_log.info(
f"[LLM-REQ] bug_comments(id={id}, include_private_comments={include_private_comments})"
f"[LLM-REQ] bug_comments(id={id}, include_private_comments={include_private_comments}, new_since={new_since})"
)

try:
all_comments = await bz.bug_comments(id)
all_comments = await bz.bug_comments(id, new_since=new_since)

if include_private_comments:
mcp_log.info(
Expand Down
8 changes: 7 additions & 1 deletion tests/test_mcp_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ async def test_bug_info(bz_client):
@pytest.mark.asyncio
async def test_bug_comments(bz_client):
async with respx.mock(base_url=MOCK_URL) as respx_mock:
respx_mock.get("/rest/bug/123/comment").mock(
route = respx_mock.get("/rest/bug/123/comment").mock(
return_value=Response(
200,
json={
Expand All @@ -61,6 +61,12 @@ async def test_bug_comments(bz_client):
comments = await bz_client.bug_comments(123)
assert len(comments) == 2
assert comments[0]["text"] == "Comment 1"
assert route.called
assert "new_since" not in route.calls.last.request.url.params

comments_with_since = await bz_client.bug_comments(123, new_since="2000-01-01")
assert len(comments_with_since) == 2
assert route.calls.last.request.url.params["new_since"] == "2000-01-01"


@pytest.mark.asyncio
Expand Down