Install
$ agentstack add mcp-onecer-aioffice Open-source listing, not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Pipes remote content directly into a shell (remote code execution).
What it can access
- ● Network access Used
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
AIOffice
English | [简体中文](README.zh-CN.md)
[](https://github.com/onecer/AIOffice/actions/workflows/ci.yml) [](LICENSE)
Give your agent an Office engine. AIOffice lets AI agents create, query, edit, render, preview and validate real .docx / .xlsx / .pptx the way they call functions: one command in, exactly one JSON envelope out. 100% self-built on pure C#/.NET — one ~36 MB single-file binary, no Microsoft Office, no runtime dependencies, no wrapped third-party engines.
# install (pick one) — then `aioffice version` to check
npx aioffice version # zero-install, great for CI / MCP hosts
npm install -g aioffice # global `aioffice` on your PATH
brew install onecer/tap/aioffice # macOS / Linux
curl -fsSL https://raw.githubusercontent.com/onecer/AIOffice/main/dist/install.sh | sh
aioffice create report.docx --title "Q3 Report"
aioffice edit report.docx --set '/body/p[1]' text="Revenue grew 12%"
aioffice read report.docx --view outline
aioffice diff report.docx old.docx # semantic compare: a sorted change list
aioffice convert report.docx deck.pptx # cross-format: a slide per heading, bullets below
aioffice mcp # the same document engine, as MCP tools over stdio
Why AIOffice
- Illustrated docs — start with the visual docs hub: [docs/README.md](docs/README.md).
- 100% self-built single binary — pure C#/.NET, direct lossless OOXML via DocumentFormat.OpenXml + ClosedXML. No Office, no cloud, no wrapped engines, no runtime to install.
- Three real formats, one tool — author and edit genuine
.docx,.xlsx,.pptxthat open in real Word, Excel and PowerPoint. - Errors that teach — every failure returns one JSON envelope with an actionable
suggestion(andcandidatesfor bad paths), so an agent self-corrects instead of guessing. - render → look → fix — render any node to PNG via the system browser and see what you made; over MCP the image comes back inline.
- Frozen 1.0 contract — a stable, machine-readable surface (
surfaceVersion1.0) your agent can rely on. See [CONTRACT.md](CONTRACT.md). - CLI = MCP, one mental model — the current source tree exposes 19 CLI verbs and 19 MCP tools. Learn it once, drive it from a shell or over stdio.
Show, don't tell
Three real Office files — a pitch deck, a revenue dashboard, and a capability report — built command by command by aioffice alone. No Office installed to build them, no templates, no manual touch-ups. The screenshots below are those exact files opened in LibreOffice — independent, third-party proof that aioffice writes genuine, valid OOXML that any Office app renders faithfully. The full gallery, with the verbatim command sequence behind each one, is in [SHOWCASE.md](SHOWCASE.md); reproduce all three with one script, [examples/tour.sh](examples/tour.sh).
| | | | |---|---|---| | [](SHOWCASE.md#1--a-product-pitch-deck--deckpptx) | [](SHOWCASE.md#2--a-regional-revenue-dashboard--dashboardxlsx) | [](SHOWCASE.md#3--a-capability-report--reportdocx) | | deck.pptx — 6 dark slides + a native bar chart (17 commands) | dashboard.xlsx — KPI band, live =SUM/=XLOOKUP, 2 charts (11 commands) | report.docx — table formula, LaTeX→Office-Math, citations (18 commands) |
How they were made — and the render → look → fix loop, on a smaller example
The three artifacts above are built by [examples/tour.sh](examples/tour.sh) (every command verbatim) and documented in [SHOWCASE.md](SHOWCASE.md). Here's a self-contained miniature of the same workflow — three small files and the render → look → fix loop — that you can paste into an empty directory:
# in an empty working directory, with aioffice on PATH
# ---- deck.pptx — 3 slides, dark background + accent shapes ----
aioffice create deck.pptx
aioffice edit deck.pptx --ops '[
{"op":"add","path":"/slide[1]","type":"shape","props":{"name":"bg","x":0,"y":0,"w":"33.87cm","h":"19.05cm","fill":"0F172A"}},
{"op":"add","path":"/slide[1]","type":"shape","props":{"name":"deco-1","x":26.2,"y":10.8,"w":12,"h":12,"fill":"1E293B"}},
{"op":"add","path":"/slide[1]","type":"shape","props":{"name":"deco-2","x":30.4,"y":15,"w":8,"h":8,"fill":"38BDF8"}},
{"op":"add","path":"/slide[1]","type":"shape","props":{"name":"accent","x":2.6,"y":6.1,"w":5.2,"h":0.16,"fill":"38BDF8"}},
{"op":"add","path":"/slide[1]","type":"shape","props":{"text":"AIOffice","x":2.5,"y":6.6,"w":24,"h":3.6,"fontSize":60,"bold":true,"color":"FFFFFF"}},
{"op":"add","path":"/slide[1]","type":"shape","props":{"text":"An AI-native CLI + MCP server for real Office files","x":2.5,"y":10.4,"w":26,"h":1.8,"fontSize":20,"color":"94A3B8"}},
{"op":"add","path":"/slide[1]","type":"shape","props":{"text":"This deck was built entirely by aioffice edit — no Office installed","x":2.5,"y":16.9,"w":26,"h":1.2,"fontSize":12,"color":"64748B"}}]'
aioffice edit deck.pptx --ops '[
{"op":"add","path":"/slide[1]","type":"slide","position":"after"},
{"op":"add","path":"/slide[2]","type":"shape","props":{"name":"bg","x":0,"y":0,"w":"33.87cm","h":"19.05cm","fill":"0F172A"}},
{"op":"add","path":"/slide[2]","type":"shape","props":{"name":"accent","x":2.6,"y":2.0,"w":3.6,"h":0.16,"fill":"38BDF8"}},
{"op":"add","path":"/slide[2]","type":"shape","props":{"text":"M1 in numbers","x":2.5,"y":2.5,"w":20,"h":2.2,"fontSize":34,"bold":true,"color":"FFFFFF"}},
{"op":"add","path":"/slide[2]","type":"shape","props":{"name":"card-1","x":2.5,"y":6.4,"w":8.6,"h":8.2,"fill":"1E293B"}},
{"op":"add","path":"/slide[2]","type":"shape","props":{"text":"3","x":3.4,"y":7.4,"w":6.8,"h":2.6,"fontSize":48,"bold":true,"color":"38BDF8"}},
{"op":"add","path":"/slide[2]","type":"shape","props":{"text":"file formats — docx, xlsx, pptx — one 36 MB binary","x":3.4,"y":10.6,"w":6.8,"h":3.4,"fontSize":13,"color":"94A3B8"}},
{"op":"add","path":"/slide[2]","type":"shape","props":{"name":"card-2","x":12.6,"y":6.4,"w":8.6,"h":8.2,"fill":"1E293B"}},
{"op":"add","path":"/slide[2]","type":"shape","props":{"text":"17","x":13.5,"y":7.4,"w":6.8,"h":2.6,"fontSize":48,"bold":true,"color":"38BDF8"}},
{"op":"add","path":"/slide[2]","type":"shape","props":{"text":"MCP tools, 1:1 with the CLI verbs","x":13.5,"y":10.6,"w":6.8,"h":3.4,"fontSize":13,"color":"94A3B8"}},
{"op":"add","path":"/slide[2]","type":"shape","props":{"name":"card-3","x":22.7,"y":6.4,"w":8.6,"h":8.2,"fill":"1E293B"}},
{"op":"add","path":"/slide[2]","type":"shape","props":{"text":"0","x":23.6,"y":7.4,"w":6.8,"h":2.6,"fontSize":48,"bold":true,"color":"38BDF8"}},
{"op":"add","path":"/slide[2]","type":"shape","props":{"text":"Office installs required — render, preview, validate built in","x":23.6,"y":10.6,"w":6.8,"h":3.4,"fontSize":13,"color":"94A3B8"}}]'
aioffice edit deck.pptx --ops '[
{"op":"add","path":"/slide[2]","type":"slide","position":"after"},
{"op":"add","path":"/slide[3]","type":"shape","props":{"name":"bg","x":0,"y":0,"w":"33.87cm","h":"19.05cm","fill":"0F172A"}},
{"op":"add","path":"/slide[3]","type":"shape","props":{"name":"deco","x":-3,"y":13.5,"w":10,"h":10,"fill":"1E293B"}},
{"op":"add","path":"/slide[3]","type":"shape","props":{"name":"accent","x":2.6,"y":7.0,"w":5.2,"h":0.16,"fill":"38BDF8"}},
{"op":"add","path":"/slide[3]","type":"shape","props":{"text":"render → look → fix","x":2.5,"y":7.5,"w":28,"h":3.2,"fontSize":44,"bold":true,"color":"FFFFFF"}},
{"op":"add","path":"/slide[3]","type":"shape","props":{"text":"One JSON envelope at a time. github.com/onecer/AIOffice","x":2.5,"y":11,"w":26,"h":1.6,"fontSize":18,"color":"94A3B8"}}]'
aioffice validate deck.pptx
# ---- report.docx — running header, Heading1/2, intro, table ----
aioffice create report.docx
aioffice edit report.docx --ops '[
{"op":"add","path":"/header[1]","type":"header","props":{"text":"AIOffice Demo"}},
{"op":"add","path":"/body","type":"p","position":"inside","props":{"text":"AIOffice M1 Report","style":"Heading1"}},
{"op":"add","path":"/body","type":"p","position":"inside","props":{"text":"This document was created entirely from the command line by aioffice — headings, header, table and styles included. Every block below is addressable (/body/p[2], /body/table[1]) and was written through the same atomic edit batches an AI agent would use."}},
{"op":"add","path":"/body","type":"p","position":"inside","props":{"text":"Milestone snapshot","style":"Heading2"}},
{"op":"add","path":"/body","type":"table","position":"inside","props":{"rows":4,"cols":3}},
{"op":"set","path":"/body/table[1]/tr[1]/tc[1]","props":{"text":"Milestone"}},
{"op":"set","path":"/body/table[1]/tr[1]/tc[2]","props":{"text":"Highlights"}},
{"op":"set","path":"/body/table[1]/tr[1]/tc[3]","props":{"text":"Status"}},
{"op":"set","path":"/body/table[1]/tr[2]/tc[1]","props":{"text":"M0"}},
{"op":"set","path":"/body/table[1]/tr[2]/tc[2]","props":{"text":"create / query / edit / render / validate"}},
{"op":"set","path":"/body/table[1]/tr[2]/tc[3]","props":{"text":"shipped"}},
{"op":"set","path":"/body/table[1]/tr[3]/tc[1]","props":{"text":"M1"}},
{"op":"set","path":"/body/table[1]/tr[3]/tc[2]","props":{"text":"png render, live preview, headers/footers, xlsx charts"}},
{"op":"set","path":"/body/table[1]/tr[3]/tc[3]","props":{"text":"shipped"}},
{"op":"set","path":"/body/table[1]/tr[4]/tc[1]","props":{"text":"M2"}},
{"op":"set","path":"/body/table[1]/tr[4]/tc[2]","props":{"text":"tracked changes, comments, pivot tables"}},
{"op":"set","path":"/body/table[1]/tr[4]/tc[3]","props":{"text":"next"}},
{"op":"add","path":"/body","type":"p","position":"inside","props":{"text":"How it was made","style":"Heading2"}},
{"op":"add","path":"/body","type":"p","position":"inside","props":{"text":"aioffice edit report.docx --ops … applied all of the above in one atomic batch; aioffice validate confirms the OOXML is clean, and aioffice render --to png produced the image you are looking at."}}]'
aioffice read report.docx --view outline # orient: headings + canonical paths
aioffice edit report.docx --remove '/body/p[1]' # drop the empty paragraph create left behind
aioffice validate report.docx
aioffice get report.docx '/header[1]/p[1]' # → "text": "AIOffice Demo"
# ---- metrics.xlsx — sales table, SUM/AVERAGE, formats, bar chart ----
aioffice create metrics.xlsx
aioffice edit metrics.xlsx --ops '[
{"op":"set","path":"/Sheet1/A1","props":{"value":"Month"}},
{"op":"set","path":"/Sheet1/B1","props":{"value":"Revenue"}},
{"op":"set","path":"/Sheet1/C1","props":{"value":"Units"}},
{"op":"set","path":"/Sheet1/A1:C1","props":{"bold":true,"fill":"DBEAFE"}},
{"op":"set","path":"/Sheet1/A2","props":{"value":"Jan"}},
{"op":"set","path":"/Sheet1/B2","props":{"value":48800}},
{"op":"set","path":"/Sheet1/C2","props":{"value":305}},
{"op":"set","path":"/Sheet1/A3","props":{"value":"Feb"}},
{"op":"set","path":"/Sheet1/B3","props":{"value":52400}},
{"op":"set","path":"/Sheet1/C3","props":{"value":327}},
{"op":"set","path":"/Sheet1/A4","props":{"value":"Mar"}},
{"op":"set","path":"/Sheet1/B4","props":{"value":61200}},
{"op":"set","path":"/Sheet1/C4","props":{"value":382}},
{"op":"set","path":"/Sheet1/A5","props":{"value":"Apr"}},
{"op":"set","path":"/Sheet1/B5","props":{"value":57600}},
{"op":"set","path":"/Sheet1/C5","props":{"value":360}},
{"op":"set","path":"/Sheet1/A6","props":{"value":"May"}},
{"op":"set","path":"/Sheet1/B6","props":{"value":66900}},
{"op":"set","path":"/Sheet1/C6","props":{"value":418}},
{"op":"set","path":"/Sheet1/A7","props":{"value":"Total","bold":true}},
{"op":"set","path":"/Sheet1/B7","props":{"value":"=SUM(B2:B6)","bold":true}},
{"op":"set","path":"/Sheet1/C7","props":{"value":"=SUM(C2:C6)","bold":true}},
{"op":"set","path":"/Sheet1/A8","props":{"value":"Average"}},
{"op":"set","path":"/Sheet1/B8","props":{"value":"=AVERAGE(B2:B6)"}},
{"op":"set","path":"/Sheet1/C8","props":{"value":"=AVERAGE(C2:C6)","numberFormat":"0.0"}},
{"op":"set","path":"/Sheet1/B2:B8","props":{"numberFormat":"$#,##0"}},
{"op":"add","path":"/Sheet1","type":"chart","props":{"kind":"bar","dataRange":"A1:B6","anchor":"E2","title":"Revenue by month"}}]'
aioffice get metrics.xlsx /Sheet1/B7 # → "formula": "=SUM(B2:B6)", "cachedValue": 286900
aioffice get metrics.xlsx /Sheet1/B8 # → "formula": "=AVERAGE(B2:B6)", "cachedValue": 57380
aioffice get metrics.xlsx '/Sheet1/chart[1]' # → bar chart "Revenue by month", A1:B6 @ E2
aioffice validate metrics.xlsx
# ---- render: the "look" step ----
aioffice render deck.pptx --to png --scope '/slide[1]' -o deck-1.png
aioffice render deck.pptx --to png --scope '/slide[2]' -o deck-2.png
aioffice render deck.pptx --to svg --scope '/slide[1]' -o deck-1.svg
aioffice render report.docx --to png -o report.png
aioffice render metrics.xlsx --to png -o metrics.png
# ---- look → fix: the slide-2 card labels overflowed their cards ----
aioffice query deck.pptx 'shape:contains("formats")' # find the label → /slide[2]/shape[6]
aioffice edit deck.pptx --ops '[
{"op":"set","path":"/slide[2]/shape[6]","props":{"text":"file formats — one binary"}},
{"op":"set","path":"/slide[2]/shape[9]","props":{"text":"MCP tools, 1:1 with the CLI"}},
{"op":"set","path":"/slide[2]/shape[12]","props":{"text":"Office installs required"}}]'
aioffice validate deck.pptx
aioffice render deck.pptx --to png --scope '/slide[2]' -o deck-2.png
This miniature uses the same loop as the full showcase: create → batched edit → validate → render --to png → look → edit to fix. The xlsx PNG shows the sheet as the HTML renderer draws it: cells, formats and cached formula results; the bar chart lives in the file (see get '/Sheet1/chart[1]') and shows up when Excel opens it. For the three polished artifacts and their verbatim commands, see [SHOWCASE.md](SHOWCASE.md) and [examples/tour.sh](examples/tour.sh).
Why AI-native?
Most office libraries are built for programmers. Most office CLIs are built for humans. AIOffice is built for agents — every design decision optimizes the loop an LLM actually runs: act → observe → recover → verify.
| Feature | What it means for an agent | |---|---| | One JSON envelope per command | {ok, data, error, meta} on stdout, always. Nothing to scrape, nothing to guess. | | Errors that teach | Every error carries a mandatory suggestion. invalid_path even ships candidates — the nearest valid paths, computed server-side. One failed call, zero wasted recovery turns. | | Stable addressing | /body/p[3], /Sheet1/A1:C10, /slide[2]/shape[3] — 1-based, canonical, returned by query so edits never aim at guessed indices. | | Atomic batch edits | edit --ops '[...]' applies all-or-nothing, supports --dry-run, and guards with optimistic concurrency (--expect-rev) — a stale file fails before any write, with stale_address. | | Automatic undo | Every mutation snapshots the pre-image into a 20-deep ring. snapshot restore is one call — and is itself undoable. | | Write-time formula evaluation | Excel formulas are computed and cached into the file (=SUM(A1:A2) → reopen shows 42 instantly). Functions the engine can't evaluate produce an explicit formula_not_evaluated warning — never a silently stale value. | | render → look → fix | Render docx/xlsx to HTML, pptx slides to SVG — and any of them to PNG via the system browser, no Office installed. The agent sees what it made and fixes it. | | Human-in-the-loop preview | preview open serves a live view on localhost; rendered nodes carry data-aio-path, so a human click comes back to the agent as a canonical path via preview selection. | | Sandboxed by default | All file args resolve inside a workspace allowlist (--workspace, symlink-escape checked). Out-of-bounds access → sandbox_denied, exit
…
Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: onecer
- Source: onecer/AIOffice
- License: MIT
- Homepage: https://www.npmjs.com/package/aioffice
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.