“분명 지난주에 올린 건데… 회의록 폴더에도 없고, 검색해도 안 나와요.”
Confluence를 쓰는 팀이라면 한 번쯤 들어 본 말일 겁니다. 문서가 없어서가 아니라, 있어야 할 자리에 없어서 생기는 일입니다. 이 글은 그 문제를 풀려고 만든 Forge 앱이 Rovo 에이전트를 거쳐 MCP 도구가 되기까지의 기록입니다.
문서가 쌓이면 자연스럽게 폴더 구조가 생깁니다. 회의록, 요구사항 정의서, 인사팀, 개발 관련 문서처럼 성격별로 나누고, 그 뒤로는 새 페이지를 어디에 둘지가 매번 문제가 됩니다. 지금 폴더의 성격에 맞는지, 더 알맞은 자리가 따로 있는지는 스페이스 전체 구조를 알아야 판단할 수 있는데, 문서가 수십 개를 넘어가면 사람이 매번 그 판단을 하기는 어렵습니다. 그래서 페이지는 만든 사람이 그때 보고 있던 폴더에 남고, 찾는 사람은 엉뚱한 곳을 뒤지게 됩니다.

그래서 이 판단을 LLM에게 맡기는 작은 Forge 앱을 만들었습니다. 페이지를 열면 스페이스의 폴더·페이지 구조를 읽고, 본문과 비교해 “이 페이지는 어느 폴더 아래가 맞다”를 사유와 함께 추천하고, 원하면 그 자리로 옮겨 줍니다.
처음에는 페이지 화면의 버튼과 메뉴로 만들었고, 다음에는 같은 기능을 Rovo 채팅에서 쓸 수 있도록 Forge에서 에이전트를 정의했습니다. 그리고 올해 Forge에 rovo:mcp 모듈이 미리보기(preview) 기능으로 추가되면서, 이 앱의 액션들을 MCP 규격의 도구로 내보내 Rovo Studio에서 만든 에이전트가 쓰게 하는 데까지 왔습니다.
이 글은 그 흐름을 순서대로 따라갑니다. 필요에서 시작한 Forge 앱 개발, 그 기능을 Rovo 에이전트로 확장한 과정, 그리고 같은 기능을 도구로 내보내(MCP) 에이전트 정의에 사용하는 방식까지입니다.
이 글에 나오는 용어는 여섯 가지입니다. 뜻만 먼저 짚고 갑니다.

그리고 이어서 설명드릴 Rovo, 에이전트, 도구(MCP), Forge 앱이 서로 어떻게 이어지는지 아래 관계도로 정리했습니다.

페이지를 열고 앱을 실행하면, 앱이 스페이스의 페이지·폴더·화이트보드·데이터베이스를 CQL로 읽어 계층 구조를 만들고, 현재 페이지의 제목과 본문을 함께 LLM에 넘겨 가장 어울리는 부모(폴더 또는 상위 페이지)를 고르게 합니다. 결과는 추천 위치와 사유로 돌아오고, “추천 경로로 이동”을 누르면 실제로 페이지를 이동합니다.

이 앱의 진입점은 두 개입니다. 하나는 페이지 제목 아래 바이라인에 붙는 버튼(confluence:contentBylineItem)이고, 다른 하나는 페이지 오른쪽 위 “···” 메뉴의 Apps 항목(confluence:contentAction)입니다. 둘 다 같은 프론트엔드 화면을 띄우고 같은 함수를 호출합니다.



modules:
confluence:contentBylineItem: # 제목 아래 바이라인 버튼
- key: confluence-ai-organizer-byline
resource: main
render: native
resolver:
function: resolver
title: AI Page Organizer
viewportSize: medium
confluence:contentAction: # "···" 메뉴 > Apps 항목
- key: confluence-ai-organizer-action
resource: main
render: native
resolver:
function: resolver
title: Recommend Page Location
viewportSize: medium
llm: # Forge LLMs API (추천 판단에 사용)
- key: confluence-ai-organizer-llm
model:
- claude이 앱의 핵심 동작은 “구조를 읽는다”와 “옮긴다” 두 가지라서, 이 둘을 Forge의 액션(action) 모듈로 따로 떼어 두었습니다. 뒤에서 에이전트와 도구가 부르는 단위가 됩니다.
앱을 개발한 다음에는, 화면에서 버튼을 누르는 대신 Rovo 채팅에서 “이 페이지 정리해줘”라고 말하면 동작하게 만들고 싶었습니다. Forge에는 앱이 에이전트를 정의하는 rovo:agent 모듈이 있습니다. 지시문(프롬프트)과 사용할 액션 목록을 manifest에 적으면, 앱을 설치한 사이트의 Rovo 채팅에 그 에이전트가 나타납니다.
rovo:agent:
- key: confluence-ai-organizer-rovo-agent
name: Confluence AI Page Organizer
description: "Confluence 스페이스 내의 디렉토리 구조를 분석하고 최적의 위치로 페이지를 자동 이동시켜 주는 정리 비서입니다."
prompt: |
Confluence 문서 정리 비서. 답변은 최대 2문장으로 짧게 작성한다.
정리 요청 시 get-space-tree-action을 먼저 호출한다. ...
다르면 사유를 짧게 말한 뒤에만 move-page-action 확인 카드를 제시하고 Confirm 전에는 호출하지 않는다.
취소/거부 시 "이동 요청이 취소되었습니다."라고 종료하고 재호출·재추천하지 않는다.
actions:
- get-space-tree-action
- move-page-action여기서 역할이 나뉩니다. 2장의 화면에서는 판단을 Forge LLMs API가 했지만, 에이전트에서는 판단을 Rovo가 합니다. 액션 두 개는 그저 트리를 읽고 옮기는 도구일 뿐이고, 어떤 순서로 부를지, 옮기기 전에 확인을 받을지는 지시문이 정합니다.
페이지를 열어 둔 채 에이전트에게 “이 페이지가 지금 위치에 맞는지 판단해서, 더 알맞은 폴더가 있으면 그리로 정리해줘”라고 했습니다. 에이전트가 스페이스 트리를 읽고 “회의록 성격의 문서이므로 ‘회의록’ 폴더가 더 적절하다”고 판단한 뒤, 지시문대로 확인 카드를 먼저 띄우고, Confirm 시 tool을 호출한 다음 결과를 짧게 알려줍니다.


잘 동작했지만 한계도 분명했습니다. 지시문이 앱 안에 고정돼 있어서, 말투를 바꾸거나 확인 절차를 더 두거나 Jira 이슈 만들기 같은 다른 기능과 묶어 쓰려면 앱을 고쳐 다시 배포해야 합니다. 팀마다 원하는 동작이 다른데 그때마다 개발이 끼어드는 구조입니다.
3장의 방식(앱이 에이전트까지 정의)과 도구만 내놓는 방식의 차이는 이렇습니다.

rovo:agent는 앱에서 완성된 에이전트를 만드는 것, 그리고 rovo:mcp는 에이전트가 쓸 Tool을 만드는 것입니다.
| 항목 | 앱에 내장된 에이전트 (rovo:agent) | 도구만 내놓기 (rovo:mcp, 이번 방식) |
|---|---|---|
| 비유 | 완성된 로봇을 받는 것 | 레고 블록을 받는 것 |
| 말투·일하는 순서 | 개발자가 정해 둔 대로 | 사용하는 팀이 Rovo Studio에서 직접 정함 |
| 바꾸고 싶을 때 | 앱 수정 → 재배포 | 지시문 고치고 저장 |
| 다른 도구와 조합 | 불가 | Jira 이슈 만들기, Slack 알림 등과 한 에이전트에 섞어 쓸 수 있음 |
| 실행 권한 | 앱 권한(asApp) 또는 사용자 권한(asUser) 선택 | 항상 “그 도구를 쓰는 사람”의 권한(asUser) |
| 상태 | 정식(GA) | 미리보기(Preview), 앱당 1개, 액션 최대 50개 |
결국 rovo:mcp까지 가려는 이유는 하나입니다. 앱은 ‘무엇을 할 수 있는가’만 책임지고, ‘어떤 순서로, 어떤 확인을 거쳐, 다른 도구와 어떻게 묶어 쓸 것인가’는 사용하는 팀이 정하게 하고 싶었습니다. 앱을 고치지 않고도 팀마다 다른 에이전트를 만들 수 있다면, 개발자는 도구만 잘 만들면 됩니다.
앱 설정 파일 manifest.yml에 “이 두 액션을 도구로 내놓겠다”고 적습니다. 이미 있는 액션의 이름(key)을 나열하기만 하면 됩니다.
modules:
rovo:mcp:
- key: confluence-ai-organizer-mcp # 이 도구 묶음의 이름표
name: "AI Page Organizer MCP" # Studio 화면에 보일 이름 (30자 이내)
tools:
- get-space-tree-action # 도구 1: 스페이스 트리 조회
- move-page-action # 도구 2: 페이지 이동액션 자체는 이렇게 생겼습니다. description은 에이전트가 읽는 “사용 설명서”이고, inputs는 도구를 부를 때 채워야 하는 “빈칸”입니다. 여기에 적은 문장이 그대로 Studio 화면과 에이전트의 판단에 쓰입니다.
action:
- key: get-space-tree-action
name: "스페이스 트리 조회 (Get Space Tree)"
function: run-get-tree-func # 실제로 실행될 함수
actionVerb: GET # 읽기만 하는 도구라는 표시
description: "Confluence 스페이스 내의 모든 페이지, 폴더, 화이트보드, 데이터베이스 노드 및 계층 구조 목록을 수집합니다. 페이지 화면 밖(MCP 클라이언트)에서 호출할 때는 pageId 또는 spaceKey 중 하나를 반드시 전달합니다."
inputs:
pageId:
title: "수집 대상 페이지 ID"
type: string
required: false
description: "기준이 되는 Confluence Page ID"
spaceKey:
title: "스페이스 키 (Space Key)"
type: string
required: false
description: "조회할 Confluence 스페이스 키(예: DEV). pageId가 없을 때 사용합니다."여기서부터는 화면에서 클릭으로 진행합니다. 순서대로 따라가면 됩니다.
앱이 설치되면 Rovo Studio의 Tools 화면 왼쪽 “Connected apps” 목록에 앱 이름이 자동으로 생깁니다. 별도 등록 절차는 없습니다.

앱 이름을 누르면 도구 두 개가 카드로 보입니다. 카드의 제목과 설명은 4-2의 name과 description이 그대로 온 것입니다. 이름 뒤 “(development)”는 개발용 환경에 배포된 버전이라는 표시로, 정식 환경에 배포하면 꼬리표 없는 도구가 따로 생깁니다.

Studio > Agents > “Create an agent”를 누르고, 에이전트에게 시킬 일을 씁니다. 이번에 쓴 지시문의 핵심은 세 가지였습니다.
✅ 정리 요청이 오면 먼저 스페이스 구조를 읽어라.
✅ 페이지를 옮기기 전에는 반드시 어디로 옮길지 사용자에게 확인받아라.
✅ 실패하면 이유를 설명하고 다른 방법을 제안하라.

Tools 옆 “Add tools”를 누르면 도구 고르는 창이 뜹니다. Atlassian 기본 도구, 연결된 앱(Forge 앱 포함), 외부 MCP 서버 세 묶음으로 나뉘어 있습니다.

왼쪽에서 앱 이름을 고르고, 도구 두 개에 체크한 뒤 Add를 누릅니다.

Publish를 누르면 끝입니다. 에이전트 상세 화면에 지시문과 도구 2개가 붙어 있는 것이 보입니다.


Confluence 아무 화면에서 오른쪽 위 “Ask Rovo”를 누르고, 위쪽 에이전트 이름을 눌러 방금 만든 에이전트를 선택합니다.

먼저 “너는 어떤 일을 도와줄 수 있어? 쓸 수 있는 도구도 같이 알려줘”라고 물어봤습니다. 앱에서 온 도구 두 개(get-space-tree-action, move-page-action)가 Atlassian 기본 도구들과 나란히 나옵니다. 도구가 제대로 붙었다는 뜻입니다.

이번엔 특정 페이지를 열지 않은 홈 화면에서 “Software Development 스페이스에 어떤 페이지들이 어떤 구조로 들어 있는지 보여줘”라고 했습니다. 에이전트가 스페이스 트리 조회 도구를 부르는 과정(“Invoking tool”)이 그대로 보입니다.

도구가 값을 돌려주면 에이전트가 그걸 보기 좋게 정리해 답합니다.

페이지를 옮겨 달라고도 해 봤습니다. “‘Template – Decision documentation’ 페이지를 ‘Template – Meeting notes’ 아래로 옮겨줘”라고 하니 바로 옮겼습니다.

왼쪽 페이지 트리를 새로고침하면 실제로 옮겨져 있습니다. 테스트가 끝난 뒤 같은 방법으로 원래 자리에 되돌려 놓았습니다.

actionVerb: UPDATE로 표시해도 Studio가 자동으로 “정말 실행할까요?”를 묻지는 않습니다. 지시문에 “실행 전에 확인받을 것”이라고 적어도 항상 지켜지지는 않았습니다. 되돌리기 어려운 작업이라면 도구 쪽에서 확인용 입력값을 따로 요구하는 식으로 한 번 더 막는 것이 안전합니다.https://mcp.atlassian.com/v1/forge/<installationId> 주소로 Forge 도구를 부르게 한다는 계획(RFC-134)이 있지만, 검증 시점(2026-09-29)에 이 주소는 404였습니다.token이 들어간 키는 가리고 찍어야 합니다.처음 목표는 단순했습니다. 문서가 쌓일수록 어려워지는 “이 페이지, 어디에 있어야 하지?”라는 판단을 LLM에게 맡기는 것이었습니다. 그 판단을 페이지 화면의 버튼으로 시작해, Rovo 채팅에서 말로 시킬 수 있는 에이전트로 넓혔고, 마지막에는 에이전트를 정의하는 일 자체를 사용하는 팀에게 넘겼습니다. 앱은 세 단계 내내 같은 액션 두 개만 갖고 있었습니다. 달라진 것은 그 액션을 누가, 어떤 방식으로 부르느냐였습니다.
앱 쪽에서 한 일은 설정 파일에 rovo:mcp 모듈을 추가하고, 액션이 페이지 화면 밖에서도 동작하도록 입력값을 받게 하고, 권한 호출을 사용자 기준으로 바꾼 것입니다. 사용하는 쪽에서 한 일은 Rovo Studio에서 클릭 몇 번으로 도구를 붙이고 지시문을 쓴 것입니다. 그 결과 같은 앱 기능을 팀마다 다른 성격의 에이전트로 조합해 쓸 수 있게 됐습니다. 개발자는 “무엇을 할 수 있는가”만 책임지고, “어떻게 쓸 것인가”는 팀이 정하는 구조입니다.
물론 아직 미리보기 단계라 문서와 다르게 움직이는 부분이 있었고, Atlassian 바깥의 AI에서 이 도구를 부르는 길은 열리지 않았습니다. 그래도 방향은 분명해 보입니다. Forge 앱의 기능이 화면에 갇히지 않고 Rovo 에이전트의 부품이 되는 것, 그리고 그 부품을 조립하는 권한이 개발자에서 사용하는 팀으로 옮겨 가는 것입니다. 이 앱의 액션 두 개는 기본 도구로도 되는 일이었지만, 회사 고유의 규칙이나 외부 시스템 연동처럼 기본 도구가 못 하는 일을 도구로 내놓을 때도 같은 길을 쓰면 됩니다. 다음 글에서는 외부 MCP 주소가 열리면 Claude Code 같은 바깥 도구에서 같은 액션을 부르는 것까지 이어서 확인해 볼 생각입니다.