Files
Copilot 27dc02aad1 Add anchor text to MCP comment tool responses (#11886)
* Initial plan

* Add comment anchor text to MCP comment tool responses

Agent-Logs-Url: https://github.com/outline/outline/sessions/294b6510-996f-4a86-a7d6-7ed1c336fc19

Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>

* Address PR review: fix auth gap, cache marks, add anchorText tests

- Always authorize read access in update_comment before exposing anchor text
- Cache comment marks per document in list_comments to avoid O(n * docSize)
- Add 4 MCP tests verifying anchorText presence/absence in responses

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: tommoor <380914+tommoor@users.noreply.github.com>
Co-authored-by: Tom Moor <tom@getoutline.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 15:08:34 -04:00

47 lines
1.3 KiB
TypeScript

import {
ProsemirrorHelper,
type CommentMark,
} from "@shared/utils/ProsemirrorHelper";
import type { Comment } from "@server/models";
import { DocumentHelper } from "@server/models/helpers/DocumentHelper";
import presentUser from "./user";
type Options = {
/** Whether to include anchor text, if it exists */
includeAnchorText?: boolean;
/** Precomputed comment marks to avoid reparsing the document. */
commentMarks?: CommentMark[];
};
export default function present(
comment: Comment,
{ includeAnchorText, commentMarks }: Options = {}
) {
let anchorText: string | undefined;
if (includeAnchorText && comment.document) {
const marks =
commentMarks ??
ProsemirrorHelper.getComments(
DocumentHelper.toProsemirror(comment.document)
);
anchorText = ProsemirrorHelper.getAnchorTextForComment(marks, comment.id);
}
return {
id: comment.id,
data: comment.data,
documentId: comment.documentId,
parentCommentId: comment.parentCommentId,
createdBy: presentUser(comment.createdBy),
createdById: comment.createdById,
resolvedAt: comment.resolvedAt,
resolvedBy: comment.resolvedBy ? presentUser(comment.resolvedBy) : null,
resolvedById: comment.resolvedById,
createdAt: comment.createdAt,
updatedAt: comment.updatedAt,
reactions: comment.reactions ?? [],
anchorText,
};
}