AI ์์ด์ ํธ๊ฐ HWPX ๋ฌธ์๋ฅผ ๋ฐ๋ก ์ฝ๊ณ , ์ฐพ๊ณ , ์ฑ์ฐ๊ณ , ๋ง๋ค๊ฒ ํ๋ MCP ์๋ฒ
ํ๊ธ ์๋ํ๋ก์ธ์ ์์ด ยท ์์ ํ์ด์ฌ ยท ํฌ๋ก์ค ํ๋ซํผ
| ๊ณ์ธต | ๋ ํฌ | ์ญํ |
|---|---|---|
| ๐ฆ ๋ผ์ด๋ธ๋ฌ๋ฆฌ | python-hwpx |
์์ ํ์ด์ฌ HWPX ํ์ฑยทํธ์งยท์์ฑ ์ฝ์ด |
| ๐ MCP ์๋ฒ | hwpx-mcp-server |
MCP ํด๋ผ์ด์ธํธ(Claude Desktop, VS Code ๋ฑ)์์ HWPX ์กฐ์ |
| ๐ฏ ์์ด์ ํธ ์คํฌ | hwpx-plugins |
์์ด์ ํธ๊ฐ HWPX๋ฅผ ๋ฐ๋ก ์ฐ๊ฒ ํด์ฃผ๋ ๊ณต์ ์คํฌ/ํ๋ฌ๊ทธ์ธ ๋ฒ๋ค |
hwpx-mcp-server๋ ๋ชจ๋ธ ์ปจํ ์คํธ ํ๋กํ ์ฝ(MCP) ํ์ค ์๋ฒ๋ก, python-hwpx ์์์ HWPX ๋ฌธ์์ ์ด๋ยท๊ฒ์ยทํธ์งยท์์์ฑ์ยท์์ฑยท์ถ์ถ์ AI ํด๋ผ์ด์ธํธ์์ ์ง์ ์ํํ๊ฒ ํฉ๋๋ค.
- ์ด์์ฒด์ ๋ฌด๊ด โ Windows, macOS, Linux์์ ๋์
- ํ๊ธ ์๋ํ๋ก์ธ์ ๋ถํ์ โ ์์ ํ์ด์ฌ ์ฒ๋ฆฌ, ์๋ฒยทCIยท๋ก์ปฌ ์ด๋์๋ ๊ฐ์ ํ๋ฆ
- AI ์ฐ๋ ์ค์ฌ โ Claude Desktop, VS Code, Gemini CLI ๋ฑ MCP ํด๋ผ์ด์ธํธ์ ์ง์ ์ฐ๊ฒฐ
- ๋ฌธ์ ์กฐ์์ ๋๊ตฌ ํธ์ถ๋ก ํ์คํ โ ์ฝ๊ธฐยทํธ์งยท๋ณต์ ยท์์์ฑ์ยท๊ฒ์ฆ์ ํ๋์ ๋๊ตฌ ์งํฉ์ผ๋ก ๋ ธ์ถ
- stateless ํธ์ถ โ ๋๊ตฌ๋ง๋ค
filename์ ๋ช ์ํ๋ ์ผ๊ด๋ ๋ฐฉ์
์ฐธ๊ณ ์ด ์๋ฒ๋ Open XML ๊ธฐ๋ฐ
.hwpxํฌ๋งท์ ์ง์ํฉ๋๋ค. ๋ฐ์ด๋๋ฆฌ.hwp๋ ์ง์ ํธ์ง ๋์์ด ์๋๋๋ค.
uv ๊ธฐ์ค:
uvx hwpx-mcp-server๋๋ pip ์ค์น ํ ์คํ:
pip install hwpx-mcp-server
hwpx-mcp-server๋น-HWPX ๋ฌธ์(PDF/DOCX/XLSX/HTML/TXT)๋ฅผ document_to_markdown ๊ฒฝ๋ก๋ก ์ฝ์ผ๋ ค๋ฉด MarkItDown adapter extra๋ฅผ ํจ๊ป ์ค์นํฉ๋๋ค.
pip install "hwpx-mcp-server[ingest]"์๊ตฌ ์ฌํญ: Python >= 3.10 ยท python-hwpx >= 2.29.1
์ค์ ํ์ผ์ ์๋ ๋ธ๋ก ํ๋๋ง ๋ฃ์ผ๋ฉด hwpx ์๋ฒ๋ฅผ ๋ฐ๋ก ์ก์ต๋๋ค.
- Claude Desktop โ
claude_desktop_config.json - Gemini CLI โ
~/.gemini/settings.json - VS Code โ
.vscode/mcp.json(ํค๊ฐmcpServers๋์servers) - Cursor / Windsurf โ ๊ฐ ์๋ํฐ์ MCP ์ค์ ํ์ผ
{
"mcpServers": {
"hwpx": {
"command": "uvx",
"args": ["hwpx-mcp-server"]
}
}
}ํ๊ฒฝ ๋ณ์๋ฅผ ๋๊ธธ ๋๋ env ๋ธ๋ก์ ์ถ๊ฐํฉ๋๋ค.
{
"mcpServers": {
"hwpx": {
"command": "uvx",
"args": ["hwpx-mcp-server"],
"env": {
"HWPX_MCP_MAX_CHARS": "12000",
"HWPX_MCP_ADVANCED": "0",
"LOG_LEVEL": "INFO"
}
}
}
}
hwpx-plugins๋ฒ๋ค์ ๋ฐ์ฒ(plugins/<host>/hwpx-plugin/scripts/hwpx-mcp-server)๋ก๋ ์คํํ ์ ์์ต๋๋ค. ๋ก์ปฌ ๊ฐ๋ฐ ์ ๋ ํฌ๊ฐ ๊ณตํต ๋ถ๋ชจ ์๋์ ์์ผ๋ฉดHWPX_MCP_SERVER_REPO,PYTHON_HWPX_REPO๋ฅผ ์ ๋๊ฒฝ๋ก๋ก ์ง์ ํ์ธ์.
์ฒ์๋ถํฐ ๋ชจ๋ ๋๊ตฌ๋ฅผ ์ธ์ธ ํ์๋ ์์ต๋๋ค. ๋ณดํต ์๋ ํ๋๋ก ์์ํฉ๋๋ค.
- ์ฝ๊ธฐ โ
get_document_infoโget_document_outline/get_document_textโfind_text,get_table_map๋ฑ์ผ๋ก ํ์ํ ๋ถ๋ถ๋ง. (์ ์ฅํ์ง ์์) - ์์ ์์ โ
copy_document๋ก ์ฌ๋ณธ ์์ฑ โ ์ฝ๊ธฐ ๋๊ตฌ๋ก ๋์ ํ์ธ โsearch_and_replace,set_table_cell_text,apply_edits๋ฑ ๊ฐ์ฅ ์์ ๋ณ๊ฒฝ โ ๋ค์ ์ฝ์ด ํ์ธ โ ๊ฒํ ๊ฐ ๋๋ ๋ณต์ฌ๋ณธ์ handoff.
ํต์ฌ์ copy first ยท smallest edit ยท re-read after edits์ ๋๋ค.
๊ธฐ๋ณธ ๋ชจ๋์์ ๋ค์์ HWPX ๋๊ตฌ๋ฅผ ์ ๊ณตํ๋ฉฐ, ๊ณ ๊ธ ๋ชจ๋(HWPX_MCP_ADVANCED=1)์์ ์ ๊ฒยท๊ฒ์ฆ์ฉ ๋๊ตฌ๊ฐ ์ถ๊ฐ๋ฉ๋๋ค. ์๋๋ ํ
๋ง๋ณ ๋ํ ํ์ด๋ผ์ดํธ์
๋๋ค. ์ ์ฒด ๋๊ตฌ ๋ชฉ๋กยท์๊ทธ๋์ฒ๋ docs/use-cases.md์ docs/skill-first-workflows.md๋ฅผ ์ฐธ๊ณ ํ์ธ์.
- ๐ ์ฝ๊ธฐยทํ์ โ
get_document_info,get_document_text,get_document_outline,find_text,get_table_text,get_table_map,find_cell_by_label,list_styles.get_document_map์ ์์๋ผ์ธยทํ ์ง๋ยท๋๋ฆํยท์ต์ปค๋ฅผ ํ ํธ์ถ๋ก ๋ฐํ(์๋ณต ์ต์ํ). (์ ์ฅํ์ง ์์) - ๐ฅ ๋ก์ปฌ ๋ฌธ์ ingest โ
document_to_markdown,document_extract_json,markdown_to_document_plan์ด ๋ก์ปฌ ๋ฌธ์๋ฅผ Markdown/JSON/document plan์ผ๋ก ๋ณํํฉ๋๋ค. HWPX๋python-hwpx์์ง์ ์ฐ์ ์ฌ์ฉํ๊ณ , ๋น-HWPX๋[ingest]extra ์ค์น ์ MarkItDown adapter๋ก ์ฒ๋ฆฌํฉ๋๋ค. - ๐ ๊ฒ์ยท์นํ โ
search_and_replace,batch_replace,replace_in_paragraph,replace_by_anchor. (find_text์ธ ์ฆ์ ์ ์ฅ) - โ๏ธ ํธ์งยทํธ๋์ญ์
โ
add_heading,add_paragraph/insert_paragraph/delete_paragraph,add_page_break,add_memo๊ณ์ด.apply_edits๋ ์ฐ์ฐ ๋ชฉ๋ก ์์ ์ ์ฉ(์ค๊ฐ ์คํจ ์ ์ ์ฒด ๋กค๋ฐฑยทdry_runยทexpected_revision๋์์ฑ ๊ฐ๋ยทidempotency_key),undo_last_edit๋.bak๋ณต์,byte_preserving_patch๋ ๋ฏธ์์ ์์ญ ๋ฐ์ดํธ ๋ณด์กด,add_tracked_edit๋ ๋ณ๊ฒฝ ์ถ์ (redline). - ๐ ํยท์์์ฑ์ โ
add_table,set_table_cell_text,merge_table_cells/split_table_cell,format_table,table_compute(ํฉ๊ณยทํ๊ท ยท์๊ณ),fill_by_path(์ฑ๋ช > right๊ฒฝ๋ก ๊ตฌ๋ฌธ). ๋ฐ์ดํธ ๋ณด์กด ๊ตฌ์กฐ์ ์์์ฑ์: ์ ๋ฐ์ดํธ ์ฑ์(๋น/๋ค์ค ๋ฌธ๋จ)ยทํ/์ด/ํ ์ญ์ ยท๋ณต์ ์ฝ์ ยท์ด ๋๋น ์๋๋ง์ถคยทํฐํธ ์ถ์๋ง์ถค์ ์์ ์์์ ์ฌ๊ตฌ์ฑํ์ง ์๊ณ ๊ทธ๋๋ก ๋ณด์กดํ๋ฉฐ ์ํํ๊ณ ์ค์ ํ์ปด์ผ๋ก ๊ฒ์ฆ(verify_fill).analyze_template_formfit/apply_template_formfit์ ์น์ธ๋ ์์์ ์๋ณธ๊ณผ ๋ค๋ฅธ destination์๋ง ๋ฐ์. - ๐๏ธ ๋๋ฆํ ์์ โ
list_form_fields,fill_form_field(์์ ๋ณด์กด),analyze_form_fill(๋ผ๋ฒจ ๋งค์นญ ์ ๋ขฐ๋ ๋ฑ๊ธ). - ๐งพ ์ ์ธํ ๋ฌธ์ ์์ฑ โ
hwpx.document_plan.v1๋ก OWPML์ ์ง์ ๋ง์ง์ง ์๊ณ ์ ์ธ:validate_document_plan/analyze_document_plan(ํ์ผ ๋ฏธ์์ฑ) โcreate_document_from_plan(์์ฑ+๊ฒ์ฆ),inspect_document_authoring_quality,inspect_operating_plan_quality,create_proposal_document.compose_exam์ ์์ HWPX+๋งํฌ๋ค์ด โ ์ํ์ง ์ฌ์กฐํ(verify_question_splits). - ๐๏ธ ๊ณต๋ฌธ์ยท๋น๊ตยท๋๋ ์์ฐ โ
inspect_official_document_style(ํ์ ์ ๋ฌด ๊ท์ lint: ํญ๋ชฉ๊ธฐํธ ์๊ณยท"๋."ยท๋ถ์ยท๋ ์ง),inspect_reference_consistency,doc_diff/create_comparison_table_document(์ ๊ตฌ๋์กฐํ),mail_merge(ํ ํ๋ฆฟ+CSV/JSON โ N๋ถยทํ์ผ๋ช ํจํดยทzip),inspect_mail_merge_placeholders. - ๐จ ์์ยท๊ทธ๋ฆผยท์์ฑ๊ธฐ โ
set_paragraph_format,set_page_setup,set_header_footer,set_page_number,set_list_format,format_text,create_custom_style(์ ๋ ฅ์ pt/mm/% ์ธ๊ฐ ๋จ์);insert_picture(manifest ์๋ ๋ฑ๋ก)/replace_picture;build_image_grid(์ฌ์ง๋์ง)ยทbuild_meeting_nameplatesยทbuild_organization_chart. - ๐ฅ๏ธ ํ๋ฆฌ๋ทฐยท์ถ์ถยท๋ณต๊ตฌยท์ง๋จ โ
render_preview(HTML/PNG ์๊ฐ ์๊ธฐ๊ฒ์ฆ),hwpx_to_markdown/hwpx_to_html/hwpx_extract_json(payloadยทURL ์ ๋ ฅ, ํ์ผ ๋ฏธ์์ ),repair_hwpx(์๋ณธ ๋ณด์กดยทmimetype-first ์ฌํจํน,recover=true๋ก ์์ ZIP LFH scan ๋ณต๊ตฌ; ์๋ตcrcOk/validatePackage.ok/recoveredํ์ธ),mcp_server_health(๋ฐฐํฌ ์คํ ์๊ธฐ์ง๋จยทcapability handshake). - ๐ฌ ๊ณ ๊ธ(
HWPX_MCP_ADVANCED=1) โpackage_parts,package_get_xml/package_get_text,object_find_by_tag/object_find_by_attr,plan_edit/preview_edit/apply_edit,validate_structure,lint_text_conventions.
์์น ๊ณ์ฝ โ
paragraph_index๋ ๋ณธ๋ฌธ ์ง์ ๋ฌธ๋จ์ 0-based ์ธ๋ฑ์ค์ ๋๋ค. ํ ์ ๋ฌธ๋จ์ ์ด ์ธ๋ฑ์ค์ ์์ง ์๊ณ{"kind":"table_cell_paragraph","table_index":0,"row":0,"col":1,"cell_paragraph_index":0}๊ฐ์location๊ฐ์ฒด๋ก ์ง์ ํ๋ฉฐ,get_table_map/find_text๊ฐ ๋ฐํํ ๊ฐ์ ๊ทธ๋๋ก ๋๊ธธ ์ ์์ต๋๋ค.
์ด ์๋ฒ์ ๊ณต๊ฐ ํ๋ฉด์ ์ MCP ๋๊ตฌ ์งํฉ์ ๋๋ค. ์ํฌํ๋ก ๋ฌธ์๋ ์คํฌ ์์๋ ์ด ๋๊ตฌ๋ค์ ์กฐํฉ ํจํด์ด์ง ๋ณ๋ ๊ณ์ฝ์ด ์๋๋๋ค.
- read first โ ๋จผ์ ์ฝ๊ธฐ ๋๊ตฌ๋ก ๋ฌธ์๋ฅผ ํ์ ํ๋ค.
- copy before risky edits โ ๊ฒฐ๊ณผ๋ฌผ์ ๋ณด์กดํด์ผ ํ๋ฉด
copy_document๋ฅผ ๋จผ์ ํธ์ถํ๋ค. - mutating tools persist immediately โ ์์ ๋๊ตฌ๋ ํธ์ถ ์ฆ์ ์ ์ฅ๋๋ฏ๋ก ๊ฒํ ์ฉ์ ๋ณต์ฌ๋ณธ์์ ์์ ํ๋ค.
- explicit handoff uses the reviewed copy โ ๋ฉํยทhandoff๋ ๊ฒํ ๊ฐ ๋๋ ๋ณต์ฌ๋ณธ ํ์ผ ๊ธฐ์ค.
- advanced mode๋ ์ ๊ฒ/๊ฒ์ฆ์ฉ์ผ๋ก ๋ถ๋ฆฌ โ package inspectionยทedit planningยทvalidation์
HWPX_MCP_ADVANCED=1์ผ ๋๋ง ์ฐ๊ณ ๊ธฐ๋ณธ ํ๋ฆ๊ณผ ์์ง ์๋๋ค.
๋ชจ๋ธ์ operation/plan๋ง ๋ณด๋ด๊ณ raw XML์ ์ง์ ํธ์งํ์ง ์์ต๋๋ค. raw_xml_replace, arbitrary_xpath_mutation ๊ฐ์ ์์ XML ํ๋ฉด์ public ๋๊ตฌ๋ก ๋
ธ์ถ๋์ง ์์ต๋๋ค. ๋ชจ๋ ์ฐ๊ธฐ๋ python-hwpx์ ๋จ์ผ SavePipeline ๊ฒ์ดํธ(VisualComplete)๋ฅผ ํต๊ณผํ๋ฉฐ ์ฐํ ๊ฒฝ๋ก๊ฐ ์์ต๋๋ค(๋ฌด๊ฒฐ์ฑยทXMLยทOPC/IDยท์ด๋ฆผ์์ ยทFormFitยท๋ ์ด์์ยท์๊ฐ ์ค๋ผํด โ ํ๋์ ๋ฆฌํฌํธ).
- ๋ชจ๋ ์ฐ๊ธฐ ์๋ต์
visualComplete๋ธ๋ก์ด ์ค๋ฆฝ๋๋ค:ok,status(verified/unverified/failed),errorCodes,warnings,suggestedRetry. quality๋ธ๋ก์ผ๋ก ๊ฒ์ดํธ๋ฅผ ์ฌ๋ฆฝ๋๋ค(์๋ต ์ transparent = ์ด๋ฆผ์์ ๋ง). ์:apply_edits(..., quality="strict")๋๋quality={"mode":"strict","overflowPolicy":"fail","layoutLint":"strict"}.- ๊ฒ์ดํธ๊ฐ ์คํจํ๋ฉด ์ ์ฅ์ด ๋ณด๋ฅ๋๊ณ (
ok=false), ๊ตฌ์กฐํ๋ ์ค๋ฅ ์ฝ๋(FIELD_OVERFLOW,STALE_LINESEG_DETECTED,VISUAL_COMPLETE_FAILED, โฆ)์suggestedRetry๋ก ์ฌ์๋ํฉ๋๋ค. - capability handshake๊ฐ core/mcp/plugin ๋ฒ์ +ํด์๋ฅผ ์ ๊ฒํ๊ณ , skew ์ ์ฐ๊ธฐ๋ฅผ fail-closed๋ก ์ฐจ๋จํฉ๋๋ค(
mcp_server_health.capability). ์ง๋จ/์ฐํ๋HWPX_MCP_REQUIRE_CAPABILITY=0.
visual_review_required=true๋ ๊ตฌ์กฐ/ํ์ผ ๊ธฐ๋ฐ ๊ฒ์ฆ์ ํต๊ณผํ์ง๋ง ๋ ๋๋ง๋ ์๊ฐ ๋ ์ด์์์ ์์ง ์ฆ๋ช ๋์ง ์์๋ค๋ ๋ป์ ๋๋ค. ์ด์ ๊ณํ์ยทtemplate-formfit ๊ฒฐ๊ณผ๋ฅผ ์ต์ข ์ ์ถ ๊ฐ๋ฅ(submission-ready)์ผ๋ก ์ฃผ์ฅํ๋ ค๋ฉด ์ด๋ฆฐ ๋ฌธ์๋ฅผ ๊ฒํ ํดhwpx.visual-review.v1์ฆ๊ฑฐ๋ฅผ ๋จ๊ธฐ๊ณcurrent.status="observed_pass"์ฌ์ผ ํฉ๋๋ค.
| ๋ณ์ | ์ค๋ช | ๊ธฐ๋ณธ๊ฐ |
|---|---|---|
HWPX_MCP_MAX_CHARS |
ํ ์คํธ ๋ฐํ ๋๊ตฌ ๊ธฐ๋ณธ ์ต๋ ๊ธธ์ด | 10000 |
HWPX_MCP_AUTOBACKUP |
1์ด๋ฉด ์ ์ฅ ์ .bak ๋ฐฑ์
์์ฑ |
1 |
HWPX_MCP_ADVANCED |
1์ด๋ฉด ๊ณ ๊ธ ๋๊ตฌ ํ์ฑํ |
0 |
HWPX_MCP_SANDBOX_ROOT |
์ค์ ์ ์ด root ๋ด๋ถ ์๋/์ ๋๊ฒฝ๋ก๋ง ํ์ฉ | unset |
HWPX_MCP_FETCH_TIMEOUT_SECONDS |
URL ๊ธฐ๋ฐ HWPX fetch timeout | 20.0 |
HWPX_MCP_QUALITY |
์ ์ญ ๊ธฐ๋ณธ ์ ์ฅ ๊ฒ์ดํธ ์ ์ฑ
(transparent/strict). ๋๊ตฌ๋ณ quality๊ฐ ์ฐ์ |
transparent |
HWPX_MCP_REQUIRE_CAPABILITY |
0์ด๋ฉด capability skew fail-closed๋ฅผ ๋(์ง๋จ/์ ๋ฌธ๊ฐ์ฉ) |
1 |
LOG_LEVEL |
๋ก๊ทธ ๋ ๋ฒจ | INFO |
- ์ค์ ์ฌ์ฉ ์ฌ๋ก:
docs/use-cases.md - ์คํฌ ๊ธฐ๋ฐ ์ํฌํ๋ก:
docs/skill-first-workflows.md - ๋ณด์ยทํ๋๋ ๊ฐ์ด๋:
docs/hardening_guide_ko.md - ์ข
ํฉ ํ
์คํธ ๋ฆฌํฌํธ:
tests/hwpx_mcp_report_updated.md - ๋ณ๊ฒฝ ์ด๋ ฅ:
CHANGELOG.md
python -m pip install -e ".[test]" # ํ
์คํธ ์์กด์ฑ ์ค์น
python -m pytest -q # ์ ์ฒด ํ
์คํธ์ฝ์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ python-hwpx ์์์ ๋์ํ๋ฉฐ, ์๋ ๊ณต๊ฐ ํ์คยทํ๋ก์ ํธ์ ๋น์ง๊ณ ์์ต๋๋ค.
- OWPML โ ๊ฐ๋ฐฉํ ์๋ํ๋ก์ธ์ ๋งํฌ์ ์ธ์ด (KS X 6101) โ HWPX๊ฐ ๊ธฐ๋ฐํ๋ ํ๊ตญ ์ฐ์ ํ์ค
- hancom-io/hwpx-owpml-model โ OWPML ์์ ๊ตฌ์กฐ ์ฐธ์กฐ ๋ชจ๋ธ ยท neolord0/hwpxlib โ ์ค๋ผํด ์ํ ์ฝํผ์ค
- edwardkim/rhwp โ ๋ฉฑ๋ฑ์ฑยท๊ฒ์ฆ ๊ฒ์ดํธ ์ค๊ณ ์๊ฐ
Apache License 2.0. See LICENSE and NOTICE.
๊ณ ๊ทํ โ ๊ด๊ต๊ณ ๋ฑํ๊ต ์ ๋ณดยท์ปดํจํฐ ๊ต์ฌ
- ์ด๋ฉ์ผ: kokyuhyun@hotmail.com
- GitHub: @airmang