MCP server wrapping OfficeCLI for OpenWebUI: handle-based HTTP file layer + streamable-HTTP/stdio
Project description
officecli-mcp
An MCP server that wraps OfficeCLI so it can be used from OpenWebUI (and any streamable-HTTP MCP client). It solves OfficeCLI's core limitation for remote clients: OfficeCLI's built-in MCP mode only accepts local file paths, which doesn't work when the LLM client runs in a different container/pod and never holds the file bytes.
officecli-mcp adds a handle-based file layer: an HTTP upload endpoint accepts office documents and returns a file_id; MCP tools then operate on that file_id. OfficeCLI's built-in rendering returns HTML (as text) and screenshots (as base64 images) directly to the LLM, closing the render → look → fix loop.
How it works
OpenWebUI (pod A) officecli-mcp (pod B)
┌──────────────────────────────┐ ┌─────────────────────────────────┐
│ LLM ──► native MCP client │ HTTP │ FastMCP (streamable-HTTP) │
│ (streamable-HTTP) ────┼──────────► tools: create, view_html, │
│ │ │ view_screenshot, edit… │
│ Native Tool "officecli_upload"│ │ │
│ reads __files__, fetches │ HTTP │ HTTP /files (upload → file_id)│
│ bytes, POSTs ───────────────┼──────────► /files/{id} (download) │
│ returns file_id to LLM │ │ │
└──────────────────────────────┘ │ officecli binary (auto-pulled) │
└─────────────────────────────────┘
- The LLM never sees raw bytes — only a short
file_idhandle. - Bytes move server-to-server (OpenWebUI REST → our
/files), never through the model context. officecliis downloaded on first start (latest release for the host platform); the image stays small and decoupled from OfficeCLI version churn.
Transport
- Primary: streamable-HTTP (OpenWebUI native MCP, v0.6.31+, is streamable-HTTP-only — connect directly, no mcpo needed).
- Fallback: stdio (wrap with mcpo for OpenAPI/OpenWebUI if needed).
Status
✅ Implemented and verified end-to-end against the real officecli binary (v1.0.136). See docs/ for the design spec and implementation plan.
Quick start (Docker)
docker compose up -d # serves http://localhost:8765 (auto-pulls officecli on first start)
OpenWebUI: add an MCP connection at http://officecli-mcp:8765/mcp (native MCP, streamable-HTTP), and install the officecli_upload native tool from examples/openwebui_officecli_upload.py with its Valves set.
Local dev
python3 -m pip install -e ".[dev]"
python3 -m pytest # unit tests (no binary needed)
officecli-mcp --transport http --port 8765
E2E against the real binary:
curl -L https://github.com/iOfficeAI/OfficeCLI/releases/latest/download/officecli-linux-x64 -o /tmp/officecli && chmod +x /tmp/officecli
OFFICECLI_BIN=/tmp/officecli python3 -m pytest tests/test_e2e_real.py -v
Tools
All MCP tools are prefixed officecli_ and take a file_id handle (returned by POST /files or the officecli_upload tool):
| Tool | Purpose |
|---|---|
officecli_create |
create a blank doc/xlsx/pptx -> new file_id |
officecli_view_html |
render to HTML (returned as text) |
officecli_view_screenshot |
render a page to PNG (base64 image) |
officecli_view_text / _annotated / _outline / _stats / _issues |
various text views |
officecli_get / _set / _add / _remove / _move / _swap / _edit |
DOM edits |
officecli_validate |
OpenXML schema validation |
officecli_batch |
multi-command batch |
Configuration (env)
| Var | Default | Meaning |
|---|---|---|
OFFICECLI_MCP_TRANSPORT |
http | http (streamable-HTTP) or stdio |
OFFICECLI_MCP_PORT |
8765 | HTTP port |
OFFICECLI_MCP_DATA_DIR |
/data | where the officecli binary lives |
OFFICECLI_MCP_WORK_DIR |
/work | per-file_id workdirs |
OFFICECLI_MCP_WORK_TTL_SECONDS |
3600 | idle file cleanup |
OFFICECLI_MCP_MAX_UPLOAD_MB |
50 | upload size cap |
OFFICECLI_VERSION |
latest | pin a release tag |
OFFICECLI_SHA256 |
(none) | verify binary integrity |
OFFICECLI_MCP_API_KEY |
(none) | if set, require Bearer on HTTP surface |
OpenWebUI setup
- Keep API keys enabled (
ENABLE_API_KEYS=true, the default). The upload shim does not need a stored key - it forwards the current user's credentials via the injected__request__, so it works as a shared Public tool in multi-user setups (each user fetches only their own files). - Install the native tool
examples/openwebui_officecli_upload.py(Workspace > Tools); set Valves (officecli_mcp_url,openwebui_url); make it Public; attach to the model. - Add MCP connection:
http://officecli-mcp:8765/mcp(Settings > Connections). - Ensure the OpenWebUI pod can reach the officecli-mcp pod.
License
Apache-2.0 (same as OfficeCLI).
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file officecli_mcp-0.2.0.tar.gz.
File metadata
- Download URL: officecli_mcp-0.2.0.tar.gz
- Upload date:
- Size: 19.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b5d63c2dd88b6748b1212ba46f7818f8386522551cfa239e130e9661e95c4755
|
|
| MD5 |
01e0dbcf9c8d0071d0fb1c94f9cdfe67
|
|
| BLAKE2b-256 |
8e23406dbe89bde48799778d7c573ab167a479c1e2063b9ef698aa0bcfa3e6b5
|
Provenance
The following attestation bundles were made for officecli_mcp-0.2.0.tar.gz:
Publisher:
publish.yml on xyonium/officecli-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
officecli_mcp-0.2.0.tar.gz -
Subject digest:
b5d63c2dd88b6748b1212ba46f7818f8386522551cfa239e130e9661e95c4755 - Sigstore transparency entry: 2179229981
- Sigstore integration time:
-
Permalink:
xyonium/officecli-mcp@331cf5d93679f37b6a95140b6106b5ad9c3686e4 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/xyonium
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@331cf5d93679f37b6a95140b6106b5ad9c3686e4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file officecli_mcp-0.2.0-py3-none-any.whl.
File metadata
- Download URL: officecli_mcp-0.2.0-py3-none-any.whl
- Upload date:
- Size: 14.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1c211f8a70898b75161dc3760d56bb232154d673153080e04af4a135c906abb5
|
|
| MD5 |
70e668b2fa457040e49b0c37cd234b9f
|
|
| BLAKE2b-256 |
4edef46dd7672416ee60aae2970587720f17093e6e1ee0246f3e2b0e974d8e7f
|
Provenance
The following attestation bundles were made for officecli_mcp-0.2.0-py3-none-any.whl:
Publisher:
publish.yml on xyonium/officecli-mcp
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
officecli_mcp-0.2.0-py3-none-any.whl -
Subject digest:
1c211f8a70898b75161dc3760d56bb232154d673153080e04af4a135c906abb5 - Sigstore transparency entry: 2179230017
- Sigstore integration time:
-
Permalink:
xyonium/officecli-mcp@331cf5d93679f37b6a95140b6106b5ad9c3686e4 -
Branch / Tag:
refs/tags/v0.2.0 - Owner: https://github.com/xyonium
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@331cf5d93679f37b6a95140b6106b5ad9c3686e4 -
Trigger Event:
push
-
Statement type: