TianshangScribe
FreeNot checkedMCP server for Office documents — create, edit, fill templates, convert, and extract Word/Excel/PowerPoint. LaTeX-style markup, math formulas, PDF export, templ
About
MCP server for Office documents — create, edit, fill templates, convert, and extract Word/Excel/PowerPoint. LaTeX-style markup, math formulas, PDF export, template loops, and document diff. stdio / SSE / Streamable HTTP with auth and rate limiting.
README
PyPI CI License TianshangScribe MCP server
Cross-platform Office document processing for developers, CLI automation, and AI agents. Create, edit, template-fill, and convert Word (.docx), Excel (.xlsx), and PowerPoint (.pptx) documents, with LaTeX-style markup, native OMML math formulas, and a template engine ({{placeholders}}, {{#each}} loops, {{#if}} conditions). Ships an MCP Server with 14 tools (7 unified + 7 dedicated Excel/PPT tools) over stdio, SSE, and Streamable HTTP transports, with bearer-token auth and rate limiting.
Warning: Unstable API \u2014 breaking changes expected
This project is pre-1.0 (0.x). The CLI options, MCP tool signatures, template syntax, and output formats are not frozen and may change without notice. Compatibility commitment: any breaking change will be announced in the CHANGELOG at least one release in advance and accompanied by a migration guide. For production use, pin to a specific version and review the CHANGELOG before upgrading.
Install
pip install tianshang-scribe
# Or from source:
git clone https://github.com/Tianshang301/TianshangScribe.git
cd TianshangScribe
pip install -e ".[dev]"
Linux Deployment
Docker (recommended for MCP Server over Streamable HTTP):
git clone https://github.com/Tianshang301/TianshangScribe.git
cd TianshangScribe
docker compose up -d
# Streamable HTTP MCP Server at http://localhost:8080/mcp
# (override transport / auth / rate limits via TIANSHANG_SCRIBE_* env vars)
.deb package (Debian / Ubuntu):
# Download from GitHub Releases
sudo dpkg -i tianshang-scribe_0.8.0_all.deb
tianshang-scribe --help
pipx (isolated CLI):
pipx install tianshang-scribe
tianshang-scribe --help
Requires Python 3.10+ · python-docx · openpyxl · python-pptx · typer · rich · lxml
Quick Start
# Create a Word document
tianshang-scribe -w --create -a "Hello World" -o hello.docx
# Replace text (--regex for regex mode)
tianshang-scribe input.docx -r "old" --replace-new "new" -o output.docx
# LaTeX markup with nesting
tianshang-scribe -w --create --latex-style \
-s "font=Times New Roman,size=14" \
-a "\bfseries{\itshape{bold italic}} \fontsize{24}{Heading} \color{FF0000}{red}" \
-o styled.docx
# Math formulas —auto-converted to native Word OMML
tianshang-scribe -w --create \
--math "x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}" \
--math "\sum_{i=0}^{n} i^2" \
-o formulas.docx
# Template filling (JSON / CSV / YAML →{{placeholder}})
tianshang-scribe template.docx -t data.json -o filled.docx
# Convert to PDF (office2pdf ~2MB, or LibreOffice fallback)
tianshang-scribe input.docx --topdf -o output.pdf
# MCP Server —stdio mode (Claude Code / Cursor)
python -m tianshang_scribe.mcp.server
# MCP Server —SSE mode (Dify / Coze / FastGPT)
python -m tianshang_scribe.mcp.server --transport sse --port 8080
# Excel: import CSV, sort, export JSON
tianshang-scribe -e --create --from-csv data.csv --sort "A1:A10 asc" --to-json -o out.json
# Excel: add formula, protect workbook
tianshang-scribe budget.xlsx --formula "B10 =SUM(B2:B9)" --protect "p@ss" -o protected.xlsx
Global Options
| Parameter | Description |
|---|---|
input_file |
Input document path (omit with --create) |
-w --word |
Process Word document |
-e --excel |
Process Excel workbook |
-p --ppt |
Process PowerPoint presentation |
-o --output |
Output file path |
--force |
Allow overwriting existing files |
--topdf |
Output as PDF |
--stdin |
Read from standard input |
--stdout |
Write to standard output |
When -w/-e/-p is omitted, the document type is inferred from the input file extension.
Operations
| Option | Description | Example |
|---|---|---|
-cr --create |
Create blank document | --create -w |
-a --add |
Add text | -a "Hello" |
--column |
Target column for --add |
--column 2 |
-r --replace |
Find and replace | -r "foo" --replace-new "bar" |
-d --delete |
Delete content | -d "keyword" |
-cl --clear |
Clear content / formats / links | --clear formats |
-m --modify |
Modify content | -m "old" --modify-new "new" |
-s --style |
Set style | -s "font=Times,size=14,bold" |
-t --template |
Template filling | -t data.json |
-x --extract |
Extract data (math/latex etc.) |
-x latex |
--meta |
Set properties | --meta "title=Report,author=John" |
--latex-style |
Enable LaTeX parsing | |
--math |
Add math formula (Word) | --math "\frac{a}{b}" |
--math-style |
Math parsing dialect (office/mathtype) | --math-style mathtype |
--math-font |
OMML math font (default Cambria Math) | --math-font "Times New Roman" |
--math-mtef |
Embed as MathType OLE object (MTEF) | --math "\frac{a}{b}" --math-mtef |
--heading |
Add heading (Word) | --heading "level:1 text:Intro" |
--regex |
Regex mode | Use with --replace --delete |
--merge |
Merge files | --merge "a.docx,b.docx" |
--split |
Split document (Excel only: --split by-sheet) |
--split by-sheet |
--comment |
Add comment (Word) / speaker notes (PPT) | --comment "2 Note text" |
--add-table |
Add table (Word) | --add-table "H1,H2|a1,a2" |
--chart-add |
Add chart (Excel) | --chart-add "type=bar data=B1:C10" |
--batch |
Batch mode | --batch |
--files |
Glob pattern for batch | --files "reports/*.docx" |
--schedule-db |
Schedule SQLite DB path | --schedule-db ~/.tianshang-scribe/schedules.db |
--schedule-add |
Register schedule | --schedule-add "daily|0 9 * * *|echo hi" |
--schedule-rm |
Remove schedule | --schedule-rm daily |
--schedule-list |
List schedules | --schedule-list |
--schedule-run |
Run schedule now | --schedule-run daily |
--schedule-run-all |
Run due schedules | --schedule-run-all |
--run-script |
Run script in sandbox | --run-script build.py |
--stdin |
Read from stdin | |
--stdout |
Write to stdout |
Word-Specific Options
| Option | Description | Example |
|---|---|---|
--heading |
Add heading | --heading "level:1 text:Intro" |
--math |
Add math formula | --math "\frac{a}{b}" |
--latex-style |
Enable LaTeX markup | |
--toc |
Generate table of contents | --toc |
--section-break |
Insert section break | --section-break |
--header |
Set page header | --header "Chapter 1" |
--footer |
Set page footer | --footer "Page X" |
--watermark |
Text watermark | --watermark "DRAFT" |
--tomd |
Convert to Markdown | --tomd |
--tohtml |
Convert to HTML | --tohtml |
Excel-Specific Options
| Option | Description | Example |
|---|---|---|
--sheet-add |
Add worksheet | --sheet-add "Q1" |
--sheet-delete |
Delete worksheet | --sheet-delete "Sheet2" |
--sheet-rename |
Rename worksheet | --sheet-rename "Old New" |
--column-width |
Set column width | --column-width "2=20" |
--row-height |
Set row height | --row-height "3=30" |
--formula |
Set cell formula | --formula "A1 =SUM(B1:B10)" |
--from-csv |
Import CSV data | --from-csv data.csv |
--sort |
Sort range | --sort "A1:A10 asc" |
--chart-add |
Add chart | --chart-add "type=bar data=B1:C10" |
--freeze |
Freeze panes | --freeze "A2" |
--number-format |
Set number format | --number-format "A1:A10=0.00%" |
--conditional-format |
Conditional format | --conditional-format "B2:B100=color_scale" |
--data-validation |
Data validation | --data-validation "C2:C50=list:yes,no" |
--protect |
Set password | --protect "p@ss" |
--unprotect |
Remove password | --unprotect |
--to-csv |
Export as CSV | |
--to-json |
Export as JSON | |
--to-html |
Export as HTML |
LaTeX Style Markup
Embed the following markup in --add content. Enable with --latex-style. Supports nesting.
| Syntax | Effect |
|---|---|
\bfseries{text} |
Bold |
\itshape{text} |
Italic |
\scshape{text} |
Small caps |
\underline{text} |
Underline |
\rmfamily{text} |
Roman (serif) |
\sffamily{text} |
Sans-serif |
\ttfamily{text} |
Monospace |
\fontfamily{Arial}{text} |
Specific font |
\fontsize{18}{text} |
Font size (pt) |
\color{FF0000}{text} |
Color (hex) |
\centering{...} |
Center align **—* |
\raggedright{...} |
Left align **—* |
\raggedleft{...} |
Right align **—* |
\linespread{1.5}{...} |
Line spacing **—* |
\indent{...} / \noindent{...} |
Indent **—* |
\heading{2}{Title} |
Insert heading |
\newpage |
Page break |
\includegraphics{path} |
Insert image |
**—* Paragraph-level formatting (creates a new paragraph).
Font Configuration
| Command | Effect |
|---|---|
\setmainfont{Name} |
Default Western font |
\setCJKmainfont{Name} |
Default CJK font |
\setsansfont{Name} |
Sans-serif font |
\setCJKsansfont{Name} |
CJK sans-serif font |
\setmonofont{Name} |
Monospace font |
\setCJKmonofont{Name} |
CJK monospace font |
Word OOXML natively separates w:ascii (Western) and w:eastAsia (CJK) fonts, enabling automatic font switching in mixed-script text.
Math Formulas
LaTeX math formulas via --math are converted to native Word OMML (Office Math Markup Language). The converter is a hand-written recursive-descent parser (expression → term → factor → atom) over a nested, immutable token tree (fraction, root, N-ary, sub/sup, accent, styled, delimiter tokens), dispatched through an O(1) command table with precompiled regexes and zero-copy argument slicing. Use --math-font "Times New Roman" to render equations with a MathType-style serif font instead of Word's default Cambria Math (<m:mathPr><m:mathFont>). --math-style mathtype switches the LaTeX parsing dialect for MathType compatibility. Use --math-mtef to embed the formula as a real MathType OLE object (MTEF binary) instead — editable by legacy MathType (6.x and earlier), the same format --extract math reads back. Output is byte-for-byte stable across releases (guarded by a golden-snapshot regression suite).
Supported Syntax
| Category | Commands |
|---|---|
| Fractions | \frac{num}{den} |
| Roots | \sqrt{content} \sqrt[n]{content} |
| Sup/Subscripts | x^{2} x_{i} x_{i}^{n} |
| Sums/Integrals | \sum \int \oint \prod \coprod \bigcup \bigcap \bigvee \bigwedge |
| Limits | \lim_{x \to 0} \max \min \sup \inf |
| Named Functions | \sin \cos \tan \cot \sec \csc \log \ln \det \Pr \gcd \deg \dim \hom \ker \arg |
| Greek Letters | \alpha \beta \gamma —\Gamma \Delta \Theta — |
| Symbols | \pm \times \div \cdot \infty \partial \nabla \forall \exists — |
| Relations | \leq \geq \neq \approx \equiv \propto \subset \supset \in — |
| Arrows | \to \rightarrow \leftarrow \mapsto \uparrow — |
| Accents | \hat{x} \bar{x} \tilde{x} \dot{x} \ddot{x} \vec{x} \widehat{x} \widetilde{x} — |
| Brackets | \left( \right) \left[ \right] \left\{ \right\} |
| Math Fonts | \mathrm{abc} \mathbf{abc} \mathit{abc} \mathcal{ABC} \mathbb{ABC} \mathsf{abc} \mathtt{abc} |
Math Typography
Conforms to mainstream math journal standards (AMS, Elsevier, Springer):
| Content | Style | Example |
|---|---|---|
| Single-letter variables | Italic | a b x y |
| Digits | Upright | 0 1 2 — |
| Named functions | Upright | \sin \cos \log |
| Lowercase Greek | Italic | \alpha \beta \gamma |
| Uppercase Greek | Upright | \Gamma \Delta \Theta |
Auto-Detection
Commands in --add text are automatically recognized as math even without $...$ wrapping:
- With arguments:
\frac\sqrt\sum\int\prod\lim - Accents:
\hat{x}\bar{x}\vec{x}etc. - Unary operators:
\sin\cos\tan\log\lnetc. H_{2}Oandm^{2}in plain text become Unicode sub/superscripts (H₂O / m²)
Style Syntax
--style uses comma-separated key-value pairs:
--style "font=Times New Roman,size=14,bold,italic,color=FF0000,align=center"
| Key | Aliases | Value | Description |
|---|---|---|---|
font |
font_name, font-family |
Font name | Western font |
cjk-font |
cjk_font_name, cjk-font-family |
Font name | CJK font |
size |
font_size, font-size |
pt | Font size |
bold |
flag | Bold | |
italic |
flag | Italic | |
underline |
flag | Underline | |
color |
font_color, font-color |
FF0000 |
Hex color |
align |
alignment |
left/center/right/justify |
Alignment |
Boolean keys (bold italic underline) are True when present.
Template Filling
Supports JSON, CSV, and YAML data sources. Replaces {{placeholder}} in documents. Nested objects expand with dot notation. Loops iterate over list values. Conditionals show/hide blocks.
{
"name": "John Doe",
"date": "2026-07-28",
"user": { "city": "Beijing" },
"show": true,
"paid": false,
"items": [
{ "product": "Widget", "price": "10" },
{ "product": "Gadget", "price": "20" }
]
}
{{name}} → John Doe
{{user.city}} → Beijing
{{#each items}} → repeats the block for each item
{{product}}: {{price}}
{{/each}}
{{#if show}} → shown only when show is truthy
Confidential content
{{/if}}
{{#if role=admin}} → shown only when role equals "admin"
Admin dashboard
{{/if}}
{{#unless paid}} → shown only when paid is falsy
Payment required
{{/unless}}
Excel Features
| Feature | CLI Option |
|---|---|
| Sheet management | --sheet-add --sheet-delete --sheet-rename |
| Column/row sizing | --column-width --row-height |
| Formulas | --formula "A1 =SUM(B1:B10)" |
| Data import | --from-csv |
| Data export | --to-csv --to-json --to-html |
| Sorting | --sort "A1:A10 asc" |
| Charts | --chart-add "type=bar data=B1:C10" |
| Protection | --protect --unprotect |
PPT Features
| Feature | Description |
|---|---|
| Slide management | Add, delete, reorder slides (--slide-add, --slide-delete, --slide-move) |
| Layouts | Apply slide layouts by name or index (--layout) |
| Speaker notes | Add presenter notes (--notes) |
| Math formulas | $...$ / $$...$$ rendered as native OMML |
| Transitions | Set slide transitions —fade, push, wipe, etc. (--transition) |
| Export | Save slides as images (--toimg), convert to PDF (--topdf) |
| Media compression | Compress images (--compress-media "1920,80") |
| Tables & charts | Insert table/chart on the last slide (--ppt-table "H1,H2|a1,a2", --ppt-chart "bar|S1,S2|Cat1,1,2") |
| Protection | Set/remove password (--protect, --unprotect) |
Interactive Session (open)
tianshang-scribe open <file> [--latex-style] [--env-file <file>] [-w|-e|-p] opens a document in an interactive REPL that holds it in memory; save persists, quit prompts on unsaved changes.
doc.docx> add "Hello"
doc.docx> table @data.csv # relative paths resolve against the document's directory
doc.docx> env alias h1 "heading 1" # define a command alias
doc.docx> h1 "Summary" # use it immediately
doc.docx> save
doc.docx> quit
Commands: add heading table math replace delete style extract info path save env help quit.
The session automatically enters the document's directory on start (restored on exit), so @data.csv, path out.docx, and save rel.docx all resolve relative to the document.
REPL environment files configure defaults per project or user. Load order: --env-file wins, then <project>/.scribe/repl.rc over ~/.tianshang-scribe/repl.rc.
[repl]
latex_style = true
[aliases]
h1 = heading 1
[startup]
commands = style font=Times New Roman,size=12,cjk-font=SimSun
latex on
envshows the current environment;env alias <name> <command...>/env unalias <name>manage aliases at runtime.- Default fonts go through
[startup]stylecommands (set_stylemerges persistently);[repl]only holdslatex_style.
Exit Codes
| Code | Meaning |
|---|---|
0 |
Success |
1 |
General error |
2 |
Argument error |
3 |
Not implemented |
MCP Server
TianshangScribe includes an MCP (Model Context Protocol) server —AI Agents can create, edit, fill templates, convert, and extract data from Office documents.
Quick Connect
stdio (Claude Code, Cursor):
{"mcpServers": {"tianshang-scribe": {
"command": "python", "args": ["-m", "tianshang_scribe.mcp.server"]
}}}
SSE (Dify, Coze, FastGPT):
python -m tianshang_scribe.mcp.server --transport sse --host 0.0.0.0 --port 8080
{"mcpServers": {"tianshang-scribe": {
"url": "http://localhost:8080/sse", "transport": "sse"
}}}
Tools (14)
| Tool | Description |
|---|---|
create_office_document |
Create .docx / .xlsx / .pptx with structured content blocks |
edit_office_document |
Replace, delete, modify, style, add operations on existing docs |
fill_template |
Fill {{placeholders}} with data; supports {{#each}} / {{#if}} |
convert_document |
Convert between formats (docx↔pdf/md/html, xlsx↔csv/json) |
extract_document_data |
Extract metadata, full text, or document structure |
validate_template |
Pre-check template placeholders against data before filling |
compare_documents |
Paragraph-level diff between two .docx files |
create_excel_workbook |
Create .xlsx from typed sheet specs (headers/rows/formulas/formats) |
edit_excel_workbook |
Typed Excel ops: write_cell, set_formula, sort, add_sheet, … |
create_presentation |
Create .pptx from typed slide specs (title/bullets/table/chart) |
edit_presentation |
Typed PPT ops: add_slide, add_text, add_table, add_chart, … |
analyze_excel_data |
Read-only workbook profiling: types, nulls, duplicates, samples |
Capabilities
| Feature | Detail |
|---|---|
| Protocol | MCP 2024-11-05 · stdio + SSE · JSON-RPC 2.0 |
| Resources | resources/list + resources/read —documents exposed as readable URIs |
| Prompts | 5 built-in workflow templates (prompts/list + prompts/get) |
| Progress | notifications/progress during PDF conversion and long operations |
| Response | Multi-type content[]: text message + resource (file URI, MIME type, size) |
| Schema | enum, default, examples, minimum/maximum constraints on all params |
Production (SSE only)
# With authentication
TIANSHANG_SCRIBE_AUTH_TOKEN="secret" \
python -m tianshang_scribe.mcp.server --transport sse --host 0.0.0.0 --port 8080
# Health check
curl http://localhost:8080/health
# {"status":"ok","version":"0.9.0","uptime_seconds":3600,"active_sessions":3,"tools_available":14}
# CORS whitelist
python -m tianshang_scribe.mcp.server --transport sse --cors-origins "https://coze.com,https://dify.ai"
Endpoints: GET /health · GET /sse · POST /message?session_id=X
Full documentation: docs/mcp/README.md.
python tests/integration/mcp/mcp_stdio_smoke.py # 9/9 quick tests (stdio)
python tests/integration/mcp/test_sse.py # 3/3 SSE transport tests
python tests/integration/mcp/mcp_agent_sim.py # 11-scenario Agent simulation
Architecture
src/
└── tianshang_scribe/ # importable package (tianshang_scribe.*)
├── cli/ # Typer CLI entry
│ ├── main.py # Command parsing & dispatch
│ └── global_opts.py # File path / type inference
├── core/ # Document engine abstraction
│ ├── document.py # DocumentABC unified interface
│ ├── word_engine.py # Word engine (python-docx)
│ ├── excel_engine.py# Excel engine (openpyxl)
│ └── ppt_engine.py # PPT engine (python-pptx)
├── rendering/ # Style & formula rendering
│ ├── styles.py # TextStyle dataclass
│ ├── latex_parser.py # LaTeX markup parser
│ ├── math_omml.py # LaTeX →OMML math converter
│ └── template.py # Template filling engine
├── transform/ # Format conversion
│ └── pdf.py # PDF export (office2pdf + LibreOffice)
├── mcp/ # MCP Server (official mcp SDK 2.x)
│ ├── server.py # build_server + entry (stdio / SSE / Streamable HTTP)
│ ├── transport.py # transport wiring + ASGI middleware
│ ├── schemas.py # pydantic models + as_dict
│ ├── auth.py # Bearer token auth
│ ├── rate_limit.py # token bucket rate limiting
│ ├── metrics.py # Prometheus-style metrics
│ ├── security.py # read-only / destructive classification
│ ├── prompts.py # 5 prompt workflows
│ ├── tools/ # 14 Agent tools (7 unified + 7 dedicated)
│ │ ├── _registry.py # tool registry (schemas auto-derived)
│ │ ├── _dedicated_schemas.py # typed param models for dedicated tools
│ │ ├── create.py / edit.py / template.py / convert.py
│ │ ├── validate.py / compare.py
│ │ ├── excel_create.py / excel_edit.py / analyze_excel.py
│ │ └── ppt_create.py / ppt_edit.py
│ └── errors.py # structured error codes + fixes
└── utils/ # Utility functions
└── file_utils.py
Tech Stack
| Component | Technology |
|---|---|
| CLI | Typer + Rich |
| Word | python-docx |
| Excel | openpyxl |
| PPT | python-pptx |
| Math | Hand-written recursive-descent parser → OMML XML (immutable token tree, command dispatch table) |
| Templates | Custom engine ({{placeholder}}, {{#each}}, {{#if}}) |
| office2pdf (~2MB Rust binary, zero deps) + LibreOffice fallback | |
| Quality | pytest (936 tests) · ruff · mypy |
Build EXE
pip install pyinstaller
pyinstaller --onefile --name tianshang-scribe --hidden-import openpyxl.cell._writer --hidden-import openpyxl.cell.read_only --hidden-import openpyxl.styles --hidden-import openpyxl.chart --hidden-import openpyxl.comments src/tianshang_scribe/cli/main.py
# dist/tianshang-scribe.exe (~35 MB)
Demo
python -m demo.generate_demos
# demo/demo_word.docx —LaTeX + math + TOC + watermark
# demo/demo_excel.xlsx —CSV import + formulas + chart + protection
# demo/demo_ppt.pptx —slides + notes + transitions + math formulas
CLI compliance test:
python demo/test_cli.py
Development
git clone https://github.com/Tianshang301/TianshangScribe.git
cd TianshangScribe
pip install -e ".[dev]"
pytest tests/ -v # Run tests
ruff check src/tianshang_scribe/ tests/ # Lint
mypy src/tianshang_scribe/ # Type check
License
Apache-2.0
Installing TianshangScribe
This server has no published package — it is built from source. Open the repository and follow its README.
▸ github.com/Tianshang301/TianshangScribeFAQ
Is TianshangScribe MCP free?
Yes, TianshangScribe MCP is free — one-click install via Unyly at no cost.
Does TianshangScribe need an API key?
No, TianshangScribe runs without API keys or environment variables.
Is TianshangScribe hosted or self-hosted?
Self-hosted: the server runs locally on your machine via the install command above.
How do I install TianshangScribe in Claude Desktop, Claude Code or Cursor?
Open TianshangScribe on unyly.org, pick your client tab (Claude Desktop, Claude Code, Cursor) and press Install — the config is generated automatically, no JSON editing.
Related MCPs
GitHub
PRs, issues, code search, CI status
by GitHubFilesystem
Secure file operations with configurable access controls.
Memory
Knowledge graph-based persistent memory system.
Template MCP Server
A CLI tool to create a new Model Context Protocol server project with TypeScript support, dual transport options, and an extensible structure
by mcpdotdirectAmap Maps Mcp Server
MCP server for using the AMap Maps API
by duxiaohuiSupabase
Database, auth and storage
by SupabaseEverything
Reference / test server with prompts, resources, and tools.
Git
Tools to read, search, and manipulate Git repositories.
Sequential Thinking
Dynamic and reflective problem-solving through thought sequences.
Time
Time and timezone conversion capabilities.
Compare TianshangScribe with
Not sure what to pick?
Find your stack in 60 seconds
Author?
Embed badge for your README
Browse similar
All development MCPs
