Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
9 changes: 7 additions & 2 deletions src/mcp_atlassian/jira/comments.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,16 @@ def get_issue_comments(
logger.error(f"Error getting comments for issue {issue_key}: {str(e)}")
raise Exception(f"Error getting comments: {str(e)}") from e

def add_comment(self, issue_key: str, comment: str) -> dict[str, Any]:
def add_comment(
self, issue_key: str, comment: str, visibility: dict[str, str] = None
) -> dict[str, Any]:
"""
Add a comment to an issue.

Args:
issue_key: The issue key (e.g. 'PROJ-123')
comment: Comment text to add (in Markdown format)
visibility: (optional) Restrict comment visibility (e.g. {"type":"group","value:"jira-users"})

Returns:
The created comment details
Expand All @@ -70,7 +73,9 @@ def add_comment(self, issue_key: str, comment: str) -> dict[str, Any]:
# Convert Markdown to Jira's markup format
jira_formatted_comment = self._markdown_to_jira(comment)

result = self.jira.issue_add_comment(issue_key, jira_formatted_comment)
result = self.jira.issue_add_comment(
issue_key, jira_formatted_comment, visibility
)
if not isinstance(result, dict):
msg = f"Unexpected return value type from `jira.issue_add_comment`: {type(result)}"
logger.error(msg)
Expand Down
9 changes: 8 additions & 1 deletion src/mcp_atlassian/servers/jira.py
Original file line number Diff line number Diff line change
Expand Up @@ -985,13 +985,20 @@ async def add_comment(
ctx: Context,
issue_key: Annotated[str, Field(description="Jira issue key (e.g., 'PROJ-123')")],
comment: Annotated[str, Field(description="Comment text in Markdown format")],
visibility: Annotated[
dict[str, str],
Field(
description="""(Optional) Comment visibility (e.g. {"type":"group","value":"jira-users"})"""
),
] = None,
) -> str:
"""Add a comment to a Jira issue.

Args:
ctx: The FastMCP context.
issue_key: Jira issue key.
comment: Comment text in Markdown.
visibility: (Optional) Comment visibility (e.g. {"type":"group","value":"jira-users"}).

Returns:
JSON string representing the added comment object.
Expand All @@ -1001,7 +1008,7 @@ async def add_comment(
"""
jira = await get_jira_fetcher(ctx)
# add_comment returns dict
result = jira.add_comment(issue_key, comment)
result = jira.add_comment(issue_key, comment, visibility)
return json.dumps(result, indent=2, ensure_ascii=False)


Expand Down
37 changes: 34 additions & 3 deletions tests/unit/jira/test_comments.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ def test_add_comment_basic(self, comments_mixin):
"Test comment"
)
comments_mixin.jira.issue_add_comment.assert_called_once_with(
"TEST-123", "*This* is _Jira_ formatted"
"TEST-123", "*This* is _Jira_ formatted", None
)
assert result["id"] == "10001"
assert result["body"] == "This is a comment"
Expand Down Expand Up @@ -211,7 +211,7 @@ def hello():
markdown_comment
)
comments_mixin.jira.issue_add_comment.assert_called_once_with(
"TEST-123", "*This* is _Jira_ formatted"
"TEST-123", "*This* is _Jira_ formatted", None
)
assert result["body"] == "*This* is _Jira_ formatted"

Expand All @@ -230,9 +230,40 @@ def test_add_comment_with_empty_comment(self, comments_mixin):

# Verify - for empty comments, markdown_to_jira should NOT be called as per implementation
comments_mixin.preprocessor.markdown_to_jira.assert_not_called()
comments_mixin.jira.issue_add_comment.assert_called_once_with("TEST-123", "")
comments_mixin.jira.issue_add_comment.assert_called_once_with(
"TEST-123", "", None
)
assert result["body"] == ""

def test_add_comment_with_restricted_visibility(self, comments_mixin):
"""Test add_comment with visibility set."""
# Setup mock response
comments_mixin.jira.issue_add_comment.return_value = {
"id": "10001",
"body": "This is a comment",
"created": "2024-01-01T10:00:00.000+0000",
"author": {"displayName": "John Doe"},
}

# Call the method
result = comments_mixin.add_comment(
"TEST-123", "Test comment", {"type": "group", "value": "restricted"}
)

# Verify
comments_mixin.preprocessor.markdown_to_jira.assert_called_once_with(
"Test comment"
)
comments_mixin.jira.issue_add_comment.assert_called_once_with(
"TEST-123",
"*This* is _Jira_ formatted",
{"type": "group", "value": "restricted"},
)
assert result["id"] == "10001"
assert result["body"] == "This is a comment"
assert result["created"] == "2024-01-01 10:00:00+00:00" # Parsed date
assert result["author"] == "John Doe"

def test_add_comment_with_error(self, comments_mixin):
"""Test add_comment with an error response."""
# Setup mock to raise exception
Expand Down