A lightweight Python MCP server that provides high-level tools to read and modify Microsoft Word (.docx) documents using a structured JSON representation. It supports converting DOCX → JSON, deleting/adding/editing elements, and applying multiple operations atomically with automatic versioning.
- Convert DOCX to JSON with semantic text formatting references
- Edit element content/properties by ID
- Add or delete elements (single or multiple)
- Combined operations (add + edit + delete in one call)
- Automatic versioning (
document.v1.docx,document.v2.docx, ...) - Flexible responses: minimal, ID mapping, or full updated JSON
Repository: vcentea/docx_mcp_server (main)
GitHub: https://github.com/vcentea/docx_mcp_server
- Python 3.10+
- System dependencies: none (pure Python)
Install Python dependencies:
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txtrequirements.txt contains:
mcp(FastMCP server runtime)lxml(WordprocessingML parsing)python-docx(DOCX reconstruction)uvicorn,sse-starlette(optional HTTP/SSE transports)pydantic(imported by server)
Run the server over stdio (default):
.venv\Scripts\activate
python mcp_server.pyPoint your MCP client (e.g., IDE/agent) to spawn the above command. The server name is contract-docx-mcp.
The server can run with different transports using environment variables:
MCP_TRANSPORT=stdio(default) |sse|http|wsMCP_HOST(default127.0.0.1)MCP_PORT(default8765)MCP_PATH(e.g.,/mcpfor HTTP)MCP_SSE_PATH(default/sse) andMCP_MESSAGE_PATH(SSE messaging base)
Examples:
set MCP_TRANSPORT=sse
set MCP_PORT=8765
python mcp_server.pyset MCP_TRANSPORT=http
set MCP_PATH=/mcp
python mcp_server.pyIf a network transport fails, the server falls back to stdio.
All tools are exposed via MCP. The JSON schema shown is conceptual and may be invoked according to your MCP client format.
Convert a .docx file into structured JSON with a textProperties registry and element IDs.
Args:
docx_path: string(required)output_json_path?: stringreturn_json?: boolean(default: true)
Returns (if return_json=true):
{ source_file, textProperties, body }
Example:
{
"docx_path": "contract.docx",
"return_json": true
}Extract only the text formatting registry.
Args:
docx_path: stringreturn_json?: boolean(default: true)
Returns: { source_file, textProperties, properties_count }
Delete one or more elements by ID.
Args:
docx_path: stringelement_ids: string | string[]response_format?: "minimal" | "id_mapping" | "full_document"(default:minimal)output_docx_path?: string
Returns: { output_docx_path, version, success, deleted_element_ids, deleted_count, id_mapping?, updated_document? }
Example:
{
"docx_path": "contract.docx",
"element_ids": ["p-3", "t-1"],
"response_format": "id_mapping"
}Insert one or more new elements with optional formatting. Positions: after, before, end.
Args:
docx_path: stringnew_elements: string | object | (string|object)[]position: "after" | "before" | "end"text_properties_ref?: stringreference_element_id?: string(required forafter/before)response_format?: "minimal" | "id_mapping" | "full_document"(default:minimal)output_docx_path?: string
Returns: { output_docx_path, version, success, added_position, reference_element_id?, added_count, id_mapping?, updated_document? }
Examples:
- Append simple text using a known format name:
{
"docx_path": "contract.docx",
"new_elements": "New paragraph text",
"position": "end",
"text_properties_ref": "default_text_format",
"response_format": "id_mapping"
}- Insert multiple paragraphs after an element:
{
"docx_path": "contract.docx",
"new_elements": ["First", "Second"],
"position": "after",
"reference_element_id": "p-2"
}Edit content or properties of a single element by ID. For text content, you can optionally apply a text_properties_ref.
Args:
docx_path: stringelement_id: stringproperty_path: string(e.g.,content,pPr.jc)new_value: anytext_properties_ref?: stringresponse_format?: "minimal" | "id_mapping" | "full_document"output_docx_path?: string
Returns: { output_docx_path, version, success, edited_element_id, property_path, applied_text_properties_ref?, id_mapping?, updated_document? }
Example (replace text content and apply formatting):
{
"docx_path": "contract.docx",
"element_id": "p-1",
"property_path": "content",
"new_value": "Updated Title",
"text_properties_ref": "heading_1_bold_arial_12pt_format"
}Apply deletions → edits → additions atomically in one call.
Args:
docx_path: stringedits?: EditOperation[]additions?: AdditionOperation[]deletions?: string[]response_format?: "minimal" | "id_mapping" | "full_document"output_docx_path?: string
Returns: { output_docx_path, version, success, operations_applied: { deletions, edits, additions, total }, id_mapping?, updated_document? }
Example:
{
"docx_path": "contract.docx",
"deletions": ["p-3"],
"edits": [{
"element_id": "p-1",
"property_path": "content",
"new_value": "Updated",
"text_properties_ref": "heading_1_bold_arial_12pt_format"
}],
"additions": [{
"elements": "Conclusion",
"position": "end",
"text_properties_ref": "default_text_format"
}],
"response_format": "id_mapping"
}- Every write creates a new versioned file near the source:
contract.v1.docx,contract.v2.docx, ... - Choose
response_format: "id_mapping"or"full_document"to receive a mapping of deleted/new IDs and (optionally) the updated JSON.
Only these files are required to run the server:
mcp_server.pypatch_json.pydocx2json_runs_only.pydocx2json_orchestrate.pyjson2docx_structured.pyrequirements.txtREADME.md
Everything else can be excluded (old versions, environment files, legacy folders, tests, samples).
For use with MCP clients that spawn the server as a subprocess:
.venv\Scripts\activate
python mcp_server.pyFor accessing the server from HTTP clients:
.venv\Scripts\activate
python mcp_server.py --transport http --host 0.0.0.0 --port 8778 --path /mcpThis starts an HTTP server on http://0.0.0.0:8778/mcp that can be accessed by HTTP clients supporting the MCP protocol.
--transport: Transport type (stdio,http,sse,ws)--host: Host to bind to (default:127.0.0.1)--port: Port to listen on (default:8765)--path: URL path for HTTP transport (default:/mcp)
This project is published under the MIT License. See the repository for details.