HWP转Markdown服务

将HWP/HWPX文件转换为Markdown格式的API服务,支持多种MCP客户端集成。

  • by beomzh
  • TypeScript
  • 本地部署
  • 更新于
在 GitHub 查看 beomzh/hwpConverMdMCP

使用说明

hwpConvertMdMCP

将HWP/HWPX文件转换为Markdown hwpConverMd API的模型上下文协议(MCP)服务器。

Claude Desktop、Cursor、Claude Code、Flowise等MCP客户端可以使用HWP文档转换功能。


体系结构

MCP 클라이언트 (Claude Desktop / Cursor / Flowise CustomFunction)
        │
        │  stdio 또는 Streamable HTTP (JSON-RPC + SSE)
        ▼
  hwpConverMdMCP (Node.js MCP Server)
        │
        │  HTTP (multipart/form-data)
        ▼
  hwpConverMd (Python FastAPI Server)
        │
        ├── HwpFastConverter (XML 직접 파싱, 고속)
        ├── HwpConverter (hwp5html 폴백)
        │
        ├── POST /api/v1/convert        → JSON (markdown + download_url)
        ├── POST /api/v1/convert/base64  → JSON (Base64 입력, Flowise용)
        ├── POST /api/v1/upload-md       → JSON (임의 MD 저장 → download_url 발급)
        └── GET  /api/v1/download/{file} → 파일 다운로드

前提条件

  • Node.js >= 18.0.0
  • hwpConverMd 必须运行Python服务器

运行hwpConverMd服务器

# Docker로 실행 (권장)
cd ../hwpConverMd
docker compose up --build

# 또는 직접 실행
pip install -r requirements.txt
uvicorn app.main:app --host 0.0.0.0 --port 8000

如果服务器正常运行 http://localhost:8000/ 在 {"status": "ok"} 可以查看响应。


安装

npm install
npm run build

MCP工具

“工具”“说明”“参数”“响应” |------|------|----------|------| | convert_hwp_to_md |转换为本地文件路径| filePath:文件路径| markdown文本| | convert_hwp_content_to_md |转换为Base64内容| content:Base64, filename:文件名| markdown+ [DOWNLOAD_URL] |

convert_hwp_content_to_md响应格式

该工具是MCP content 数组返回两个文本块:

{
  "content": [
    { "type": "text", "text": "# 변환된 마크다운 내용..." },
    { "type": "text", "text": "[DOWNLOAD_URL]/api/v1/download/파일명.md" }
  ]
}
  • 第一块:转换后的标注全文
  • 第二块: [DOWNLOAD_URL] 前缀+HWP API的下载路径(可能没有)

使用方法

1.在Claude桌面上使用(stdio)

claude_desktop_config.json添加到:

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json 视窗: %APPDATA%\Claude\claude_desktop_config.json

{
  "mcpServers": {
    "hwp-converter": {
      "command": "node",
      "args": ["/absolute/path/to/hwpConverMdMCP/dist/transport/stdio.js"],
      "env": {
        "HWP_API_URL": "http://localhost:8000"
      }
    }
  }
}

2.在Cursor中使用(stdio)

在项目根目录中 .cursor/mcp.json 创建:

{
  "mcpServers": {
    "hwp-converter": {
      "command": "node",
      "args": ["/absolute/path/to/hwpConverMdMCP/dist/transport/stdio.js"],
      "env": {
        "HWP_API_URL": "http://localhost:8000"
      }
    }
  }
}

3.在Claude Code中使用(stdio)

claude mcp add hwp-converter \
  -e HWP_API_URL=http://localhost:8000 \
  -- node /absolute/path/to/hwpConverMdMCP/dist/transport/stdio.js

4.Streamable HTTP模式(用于Flowise/Web客户端)

# 빌드 후 실행
npm run start:http

# 또는 개발 모드
npm run dev:http

MCP端点: http://localhost:3000/mcp

Docker Compose

根目录的 docker-compose.yml使用共同启动整个堆栈(API+MCP+Flowise):

# 루트 디렉토리에서
cd ..
docker compose up -d --build

服务端口URL |--------|------|-----| |api | 8000 |http://localhost:8000/docs | |mcp|3001|http://localhost:3001/mcp | |流量|3000|http://localhost:3000 |

MCP容器的 HWP_API_URL=http://api:8000 (Docker内部网络)


环境变量

变量 说明 默认值
HWP_API_URL hwpConverMd API서버 URL http://localhost:8000
MCP_HTTP_PORT Streamable HTTP端口 3000

开发

npm install

npm run dev:stdio     # stdio 모드 개발
npm run dev:http      # HTTP 모드 개발
npm run build         # TypeScript 빌드

npm run start:stdio   # stdio 모드 실행
npm run start:http    # HTTP 모드 실행

Kubenetes部署

清单结构

k8s_manifest/
├── common/
│   ├── namespace.yaml         # 네임스페이스
│   ├── default-deny.yaml      # 기본 NetworkPolicy deny-all
│   └── resource-quota.yaml    # 리소스 제한
└── mcp/
    ├── serviceaccount.yaml    # 전용 ServiceAccount
    ├── rbac.yaml              # 최소 권한 RBAC
    ├── configmap.yaml         # 설정
    ├── mcp-deployment.yaml    # Deployment + Service
    ├── networkpolicy.yaml     # MCP → API 통신 허용
    └── ingress.yaml           # 외부 접근

部署

# 공통 리소스
kubectl apply -f k8s_manifest/common/

# MCP 서버
kubectl apply -f k8s_manifest/mcp/

K8s操作注意事项

MCP服务器作为一台运行(推荐)

MCP服务器 内存会话使用。在多个Pod上运行 initialize 收到请求的Pod和 tools/call 收到请求的Pod不同 "Server not initialized" 发生错误。

# MCP는 1대 고정 (stateful)
kubectl scale deploy hwp-mcp --replicas=1

# HPA가 걸려있으면 제거
kubectl delete hpa hwp-mcp

MCP服务器只进行协议中继(几乎不使用CPU),一台就足够了。实际转换负载由HWP API负责,并通过HPA进行缩放。

如果需要多个Pod,请在Ingress中添加会话属性:

nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "MCP_ROUTE"
nginx.ingress.kubernetes.io/session-cookie-max-age: "600"

Ingress设置(必需)

Base64编码的HWP文件将发送到JSON body,因此需要增加body size限制和超时:

metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "50m"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "360"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "360"

Flowise调用时使用内部URL

Flowise CustomFunction调用MCP时 K8s内部服务URL请使用:

// K8s 내부 (권장) - Ingress 안 거침, body size 제한 없음
const MCP_URL = 'http://hwp-mcp-svc:3000/mcp';

// 외부 Ingress (비권장) - hairpin NAT, SSL, body size 제한
const MCP_URL = 'https://hwp-mcp.your-domain.com/mcp';

安全设置

项目 应用程序
服务帐户 仅限服务SA, automountServiceAccountToken: false
基于角色的访问控制 仅允许ConfigMap读取(最低权限)
安全上下文 runAsNonRoot, drop ALL capabilities, seccompProfile: RuntimeDefault
网络策略 default-deny-all +仅明示允许(mcp->api,ingress->mcp)

确认

# Pod 상태
kubectl get pods -l app=hwp-mcp

# MCP 초기화 테스트
kubectl port-forward svc/hwp-mcp-svc 3000:3000
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}'

调用MCP工具

方法A:MCP客户端应用程序(Claude Desktop/Cursor)

设置后,如果用自然语言请求,LLM将自动调用工具:

“把这个HWP文件转换成标记下载:/path/to/document.hwp”

方法B:MCP Client SDK编程

import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const client = new Client({ name: "my-app", version: "1.0.0" });
await client.connect(
  new StreamableHTTPClientTransport(new URL("http://localhost:3000/mcp"))
);

// 파일 경로로 변환 (로컬 환경)
const result = await client.callTool({
  name: "convert_hwp_to_md",
  arguments: { filePath: "/path/to/document.hwp" },
});

// Base64로 변환 (원격/K8s/Flowise 환경)
const result2 = await client.callTool({
  name: "convert_hwp_content_to_md",
  arguments: { content: base64String, filename: "document.hwp" },
});

方法C:curl直接调用JSON-RPC

# 1. 세션 초기화
SESSION_ID=$(curl -si -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}}}' \
  | grep -i mcp-session-id | awk -F': ' '{print $2}' | tr -d '\r')

echo "Session: $SESSION_ID"

# 2. Initialized 알림
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Mcp-Session-Id: $SESSION_ID" \
  -d '{"jsonrpc":"2.0","method":"notifications/initialized"}'

# 3. 도구 호출
curl -X POST http://localhost:3000/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "Mcp-Session-Id: $SESSION_ID" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"convert_hwp_to_md","arguments":{"filePath":"/path/to/doc.hwp"}}}'

两个工具的使用情况

“工具”“何时使用”“环境” |------|----------|------| | convert_hwp_to_md |MCP服务器等文件系统|本地,Docker volume mount | | convert_hwp_content_to_md |文件系统分离的环境K8s、Flowise、远程服务器|


LLM集成

这个MCP服务器本身就是LLM的连接层。

方式 说明 需要代码
Claude Desktop/Cursor 仅通过config.json设置自动启动 无
克劳德代码 claude mcp add 通过命令注册 无
Flowise 从CustomFunction调用MCP JSON-RPC CustomFunction代码
编程(Anthropic API) MCP Client+Claude API组合 examples/llm-with-mcp.ts

Anthropic Claude API+MCP集成示例

ANTHROPIC_API_KEY=sk-ant-... npx tsx examples/llm-with-mcp.ts /path/to/doc.hwp "이 문서를 요약해줘"

详细代码包括: examples/llm-with-mcp.ts请参阅。