Add comprehensive release infrastructure and tooling

- Add automated GitHub Actions workflow for multi-platform releases
- Add release script with version management and validation
- Add Docker container support with multi-stage builds
- Add comprehensive release documentation and templates
- Update Cargo.toml with complete package metadata
- Add command-line argument parsing with security options
- Update README with detailed configuration examples

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Andy
2025-08-11 14:40:53 +08:00
parent 39e94c1b13
commit 705e8bfa91
11 changed files with 1819 additions and 30 deletions
+2 -1
View File
@@ -1,7 +1,8 @@
{
"permissions": {
"allow": [
"Bash(chmod:*)"
"Bash(chmod:*)",
"Bash(cargo build:*)"
],
"deny": []
}
+58
View File
@@ -0,0 +1,58 @@
---
name: Release Checklist
about: Checklist for preparing a new release
title: 'Release v[VERSION]'
labels: 'release'
assignees: ''
---
## Pre-release Checklist
- [ ] All planned features and fixes are merged
- [ ] All tests are passing on main branch
- [ ] Documentation is updated
- [ ] CHANGELOG.md is updated (if maintained separately)
- [ ] Version is updated in Cargo.toml
- [ ] No critical security vulnerabilities in dependencies
## Release Process
- [ ] Run `./scripts/release.sh [patch|minor|major|version X.Y.Z]`
- [ ] Verify all CI checks pass
- [ ] Tag is created and pushed
- [ ] GitHub release is created automatically
- [ ] Binaries are built for all platforms
- [ ] Crate is published to crates.io (for stable releases)
- [ ] Docker images are pushed
## Post-release Tasks
- [ ] Verify release artifacts are available
- [ ] Test installation from released binaries
- [ ] Update any dependent projects
- [ ] Announce release (if applicable)
## Release Notes
<!--
Add release notes here:
- New features
- Bug fixes
- Breaking changes
- Performance improvements
- Security fixes
-->
## Verification Commands
```bash
# Test the release script (dry run)
./scripts/release.sh patch --dry-run
# Run pre-release checks
./scripts/release.sh check
# Create the actual release
./scripts/release.sh patch # or minor/major/version X.Y.Z
```
+490
View File
@@ -0,0 +1,490 @@
name: Release
on:
push:
tags:
- 'v*.*.*'
workflow_dispatch:
inputs:
version:
description: 'Version to release (e.g., v1.0.0)'
required: true
type: string
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
validate-release:
name: Validate Release
runs-on: ubuntu-latest
outputs:
version: ${{ steps.get-version.outputs.version }}
tag: ${{ steps.get-version.outputs.tag }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Get version from tag or input
id: get-version
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
VERSION="${{ github.event.inputs.version }}"
echo "version=${VERSION#v}" >> $GITHUB_OUTPUT
echo "tag=${VERSION}" >> $GITHUB_OUTPUT
else
VERSION="${GITHUB_REF#refs/tags/}"
echo "version=${VERSION#v}" >> $GITHUB_OUTPUT
echo "tag=${VERSION}" >> $GITHUB_OUTPUT
fi
- name: Validate version format
run: |
VERSION="${{ steps.get-version.outputs.version }}"
if ! [[ $VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then
echo "❌ Invalid version format: $VERSION"
echo "Expected format: X.Y.Z or X.Y.Z-suffix"
exit 1
fi
echo "✅ Valid version format: $VERSION"
- name: Check if version matches Cargo.toml
run: |
CARGO_VERSION=$(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
INPUT_VERSION="${{ steps.get-version.outputs.version }}"
if [ "$CARGO_VERSION" != "$INPUT_VERSION" ]; then
echo "❌ Version mismatch:"
echo " Cargo.toml: $CARGO_VERSION"
echo " Tag/Input: $INPUT_VERSION"
exit 1
fi
echo "✅ Version matches Cargo.toml: $INPUT_VERSION"
test:
name: Run Tests
runs-on: ${{ matrix.os }}
needs: validate-release
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
rust: [stable]
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
- name: Cache Cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-release-${{ hashFiles('**/Cargo.lock') }}
- name: Install system dependencies (Ubuntu)
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
pkg-config \
libssl-dev \
libfontconfig1-dev \
libfreetype6-dev \
libjpeg-dev \
libpng-dev
- name: Install system dependencies (macOS)
if: matrix.os == 'macos-latest'
run: |
brew update
brew install pkg-config freetype jpeg libpng
- name: Run tests
run: cargo test --all-features --verbose
build:
name: Build Release Artifacts
runs-on: ${{ matrix.job.os }}
needs: [validate-release, test]
strategy:
matrix:
job:
- { os: ubuntu-latest, target: x86_64-unknown-linux-gnu, use-cross: false }
- { os: ubuntu-latest, target: x86_64-unknown-linux-musl, use-cross: true }
- { os: ubuntu-latest, target: aarch64-unknown-linux-gnu, use-cross: true }
- { os: ubuntu-latest, target: aarch64-unknown-linux-musl, use-cross: true }
- { os: windows-latest, target: x86_64-pc-windows-msvc, use-cross: false }
- { os: macos-latest, target: x86_64-apple-darwin, use-cross: false }
- { os: macos-latest, target: aarch64-apple-darwin, use-cross: false }
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.job.target }}
- name: Install cross compilation tools
if: matrix.job.use-cross
run: |
cargo install cross --git https://github.com/cross-rs/cross
- name: Cache Cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-${{ matrix.job.target }}-cargo-release-${{ hashFiles('**/Cargo.lock') }}
- name: Install system dependencies (Ubuntu)
if: matrix.job.os == 'ubuntu-latest' && !matrix.job.use-cross
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
pkg-config \
libssl-dev \
libfontconfig1-dev \
libfreetype6-dev \
libjpeg-dev \
libpng-dev
- name: Install system dependencies (macOS)
if: matrix.job.os == 'macos-latest'
run: |
brew update
brew install pkg-config freetype jpeg libpng
- name: Build release binary
run: |
if [ "${{ matrix.job.use-cross }}" = "true" ]; then
cross build --release --target ${{ matrix.job.target }} --all-features
else
cargo build --release --target ${{ matrix.job.target }} --all-features
fi
- name: Prepare release archive
shell: bash
run: |
VERSION="${{ needs.validate-release.outputs.version }}"
TARGET="${{ matrix.job.target }}"
# Create staging directory
mkdir -p staging
# Copy binary
if [[ "${{ matrix.job.os }}" == "windows-latest" ]]; then
cp "target/${TARGET}/release/docx-mcp.exe" staging/
BINARY="docx-mcp.exe"
else
cp "target/${TARGET}/release/docx-mcp" staging/
BINARY="docx-mcp"
fi
# Copy additional files
cp README.md staging/
cp LICENSE staging/
# Create archive name
ARCHIVE="docx-mcp-${VERSION}-${TARGET}"
# Create archive
cd staging
if [[ "${{ matrix.job.os }}" == "windows-latest" ]]; then
7z a "../${ARCHIVE}.zip" *
echo "ARCHIVE=${ARCHIVE}.zip" >> $GITHUB_ENV
else
tar czf "../${ARCHIVE}.tar.gz" *
echo "ARCHIVE=${ARCHIVE}.tar.gz" >> $GITHUB_ENV
fi
cd ..
# Generate checksums
if [[ "${{ matrix.job.os }}" == "windows-latest" ]]; then
certutil -hashfile "${ARCHIVE}.zip" SHA256 > "${ARCHIVE}.zip.sha256"
else
shasum -a 256 "${ARCHIVE}.tar.gz" > "${ARCHIVE}.tar.gz.sha256"
fi
echo "BINARY=${BINARY}" >> $GITHUB_ENV
- name: Upload release artifacts
uses: actions/upload-artifact@v4
with:
name: release-${{ matrix.job.target }}
path: |
${{ env.ARCHIVE }}
${{ env.ARCHIVE }}.sha256
create-release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: [validate-release, build]
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Prepare release assets
run: |
mkdir -p release-assets
find artifacts -type f -name "*.tar.gz" -o -name "*.zip" -o -name "*.sha256" | \
xargs -I {} cp {} release-assets/
ls -la release-assets/
- name: Generate changelog
id: changelog
run: |
VERSION="${{ needs.validate-release.outputs.version }}"
TAG="${{ needs.validate-release.outputs.tag }}"
# Get previous tag
PREV_TAG=$(git tag --sort=-version:refname | grep -v "^${TAG}$" | head -1)
echo "Generating changelog from ${PREV_TAG} to ${TAG}"
# Generate changelog
if [ -n "$PREV_TAG" ]; then
CHANGELOG=$(git log --pretty=format:"- %s (%h)" --no-merges ${PREV_TAG}..HEAD)
else
CHANGELOG=$(git log --pretty=format:"- %s (%h)" --no-merges)
fi
# Create release notes
cat > release-notes.md << EOF
## What's Changed
${CHANGELOG}
## Installation
### Pre-built Binaries
Download the appropriate binary for your system:
- **Linux x86_64**: \`docx-mcp-${VERSION}-x86_64-unknown-linux-gnu.tar.gz\`
- **Linux x86_64 (musl)**: \`docx-mcp-${VERSION}-x86_64-unknown-linux-musl.tar.gz\`
- **Linux ARM64**: \`docx-mcp-${VERSION}-aarch64-unknown-linux-gnu.tar.gz\`
- **macOS Intel**: \`docx-mcp-${VERSION}-x86_64-apple-darwin.tar.gz\`
- **macOS Apple Silicon**: \`docx-mcp-${VERSION}-aarch64-apple-darwin.tar.gz\`
- **Windows x86_64**: \`docx-mcp-${VERSION}-x86_64-pc-windows-msvc.zip\`
### From Source
\`\`\`bash
cargo install --git https://github.com/hongkongkiwi/docx-mcp --tag ${TAG}
\`\`\`
### Verification
All binaries are provided with SHA256 checksums for verification:
\`\`\`bash
# Linux/macOS
shasum -a 256 -c docx-mcp-${VERSION}-your-target.tar.gz.sha256
# Windows
certutil -hashfile docx-mcp-${VERSION}-x86_64-pc-windows-msvc.zip SHA256
\`\`\`
## Full Changelog
**Full Changelog**: https://github.com/hongkongkiwi/docx-mcp/compare/${PREV_TAG}...${TAG}
EOF
echo "CHANGELOG_FILE=release-notes.md" >> $GITHUB_OUTPUT
- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.validate-release.outputs.tag }}
name: Release ${{ needs.validate-release.outputs.tag }}
body_path: ${{ steps.changelog.outputs.CHANGELOG_FILE }}
files: release-assets/*
draft: false
prerelease: ${{ contains(needs.validate-release.outputs.version, '-') }}
generate_release_notes: false
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish-crate:
name: Publish to crates.io
runs-on: ubuntu-latest
needs: [validate-release, create-release]
if: ${{ !contains(needs.validate-release.outputs.version, '-') }} # Only publish stable releases
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
pkg-config \
libssl-dev \
libfontconfig1-dev \
libfreetype6-dev \
libjpeg-dev \
libpng-dev
- name: Cache Cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ubuntu-cargo-publish-${{ hashFiles('**/Cargo.lock') }}
- name: Verify package
run: cargo package --dry-run
- name: Publish to crates.io
run: cargo publish
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
docker-release:
name: Build and Push Docker Images
runs-on: ubuntu-latest
needs: [validate-release, create-release]
permissions:
contents: read
packages: write
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Docker Hub
if: ${{ secrets.DOCKERHUB_USERNAME && secrets.DOCKERHUB_TOKEN }}
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/${{ github.repository }}
${{ secrets.DOCKERHUB_USERNAME && format('{0}/docx-mcp', secrets.DOCKERHUB_USERNAME) || '' }}
tags: |
type=ref,event=tag
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest,enable={{is_default_branch}}
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
update-docs:
name: Update Documentation
runs-on: ubuntu-latest
needs: [validate-release, create-release]
permissions:
contents: write
pages: write
id-token: write
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y \
build-essential \
pkg-config \
libssl-dev \
libfontconfig1-dev \
libfreetype6-dev \
libjpeg-dev \
libpng-dev
- name: Generate documentation
run: |
cargo doc --all-features --no-deps
echo '<meta http-equiv="refresh" content="0; url=docx_mcp">' > target/doc/index.html
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./target/doc
cname: docs.example.com # Replace with your custom domain if you have one
notify-success:
name: Notify Release Success
runs-on: ubuntu-latest
needs: [create-release, publish-crate, docker-release, update-docs]
if: success()
steps:
- name: Success notification
run: |
echo "🎉 Release ${{ needs.validate-release.outputs.tag }} completed successfully!"
echo "- ✅ GitHub release created"
echo "- ✅ Binaries built for all platforms"
echo "- ✅ Published to crates.io"
echo "- ✅ Docker images pushed"
echo "- ✅ Documentation updated"
notify-failure:
name: Notify Release Failure
runs-on: ubuntu-latest
needs: [validate-release, test, build, create-release, publish-crate, docker-release, update-docs]
if: failure()
steps:
- name: Failure notification
run: |
echo "❌ Release ${{ needs.validate-release.outputs.tag }} failed!"
echo "Please check the workflow logs for details."
exit 1
+23 -3
View File
@@ -2,11 +2,28 @@
name = "docx-mcp"
version = "0.1.0"
edition = "2021"
authors = ["Your Name <your.email@example.com>"]
description = "A comprehensive Model Context Protocol (MCP) server for Microsoft Word DOCX file manipulation"
documentation = "https://docs.rs/docx-mcp"
homepage = "https://github.com/hongkongkiwi/docx-mcp"
repository = "https://github.com/hongkongkiwi/docx-mcp"
readme = "README.md"
license = "MIT"
keywords = ["mcp", "docx", "word", "document", "pdf"]
categories = ["text-processing", "api-bindings", "command-line-utilities"]
exclude = [
"/.github/*",
"/tests/fixtures/*",
"/example/*",
"/benches/*",
"/.gitignore",
"/deny.toml"
]
[dependencies]
# Official MCP SDK
mcp-server = "0.3"
mcp-core = "0.3"
mcp-server = "0.1"
mcp-core = "0.1"
# Async runtime
tokio = { version = "1.40", features = ["full"] }
@@ -26,7 +43,7 @@ lopdf = "0.34"
rusttype = "0.9" # Font rendering in pure Rust
# Embedded fonts for PDF
include_bytes_plus = "1.0"
include-bytes-plus = "1.0"
# Image processing (pure Rust)
image = { version = "0.25", features = ["png", "jpeg", "webp", "bmp", "gif"] }
@@ -66,6 +83,9 @@ chrono = { version = "0.4", features = ["serde"] }
regex = "1.10"
once_cell = "1.20"
# Command line argument parsing
clap = { version = "4.5", features = ["derive"] }
# Optional external tool support
headless_chrome = { version = "1.0", optional = true }
wkhtmltopdf = { version = "0.4", optional = true }
+77
View File
@@ -0,0 +1,77 @@
# Multi-stage Docker build for docx-mcp
FROM rust:1.75-slim as builder
# Install system dependencies for building
RUN apt-get update && apt-get install -y \
pkg-config \
libssl-dev \
libfontconfig1-dev \
libfreetype6-dev \
libjpeg-dev \
libpng-dev \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# Set working directory
WORKDIR /app
# Copy manifests
COPY Cargo.toml Cargo.lock ./
COPY build.rs ./
# Copy source code
COPY src/ ./src/
COPY benches/ ./benches/
COPY tests/ ./tests/
# Build the application
RUN cargo build --release --all-features
# Runtime stage
FROM debian:bookworm-slim
# Install runtime dependencies
RUN apt-get update && apt-get install -y \
libssl3 \
libfontconfig1 \
libfreetype6 \
libjpeg62-turbo \
libpng16-16 \
ca-certificates \
libreoffice \
poppler-utils \
&& rm -rf /var/lib/apt/lists/*
# Create non-root user
RUN groupadd -r docxmcp && useradd -r -g docxmcp -s /bin/bash -d /app docxmcp
# Create app directory and set ownership
WORKDIR /app
RUN chown -R docxmcp:docxmcp /app
# Copy the built binary from builder stage
COPY --from=builder /app/target/release/docx-mcp /usr/local/bin/docx-mcp
RUN chmod +x /usr/local/bin/docx-mcp
# Copy additional files if needed
COPY README.md LICENSE ./
# Switch to non-root user
USER docxmcp
# Create temp directory for document processing
RUN mkdir -p /tmp/docx-mcp && chmod 755 /tmp/docx-mcp
# Expose default MCP port (though MCP typically uses stdin/stdout)
EXPOSE 8080
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD /usr/local/bin/docx-mcp --version || exit 1
# Set environment variables
ENV RUST_LOG=info
ENV DOCX_MCP_TEMP_DIR=/tmp/docx-mcp
# Default command
CMD ["/usr/local/bin/docx-mcp"]
+202 -9
View File
@@ -60,8 +60,13 @@ The server includes comprehensive security features for enterprise and restricte
### Readonly Mode
```bash
# Enable readonly mode - only allows document viewing and analysis
# Using environment variables
export DOCX_MCP_READONLY=true
./target/release/docx-mcp
# Using command line arguments
./target/release/docx-mcp --readonly
```
In readonly mode, only these operations are allowed:
@@ -74,32 +79,51 @@ In readonly mode, only these operations are allowed:
### Command Filtering
```bash
# Whitelist specific commands only
# Using environment variables
export DOCX_MCP_WHITELIST="open_document,extract_text,get_metadata,export_to_markdown"
# Using command line arguments
./target/release/docx-mcp --whitelist open_document,extract_text,get_metadata,export_to_markdown
# Or blacklist dangerous commands
# Using environment variables
export DOCX_MCP_BLACKLIST="save_document,convert_to_pdf,merge_documents"
# Using command line arguments
./target/release/docx-mcp --blacklist save_document,convert_to_pdf,merge_documents
```
### Sandbox Mode
```bash
# Restrict all file operations to temp directory only
# Using environment variables
export DOCX_MCP_SANDBOX=true
./target/release/docx-mcp
# Using command line arguments
./target/release/docx-mcp --sandbox
```
### Resource Limits
```bash
# Set maximum document size (100MB default)
# Using environment variables
export DOCX_MCP_MAX_SIZE=52428800 # 50MB
# Set maximum number of open documents
export DOCX_MCP_MAX_DOCS=20
# Disable external tools
export DOCX_MCP_NO_EXTERNAL_TOOLS=true
# Disable network operations
export DOCX_MCP_NO_NETWORK=true
./target/release/docx-mcp
# Using command line arguments
./target/release/docx-mcp \
--max-size 52428800 \
--max-docs 20 \
--no-external-tools \
--no-network
```
## 🤖 AI Tool Integration
@@ -125,6 +149,39 @@ Add to your Claude Desktop configuration file:
}
```
**With Security Options (using command-line arguments):**
```json
{
"mcpServers": {
"docx": {
"command": "/absolute/path/to/docx-mcp/target/release/docx-mcp",
"args": ["--readonly", "--max-size", "52428800", "--no-network"],
"env": {
"RUST_LOG": "info"
}
}
}
}
```
**With Security Options (using environment variables):**
```json
{
"mcpServers": {
"docx": {
"command": "/absolute/path/to/docx-mcp/target/release/docx-mcp",
"args": [],
"env": {
"RUST_LOG": "info",
"DOCX_MCP_READONLY": "true",
"DOCX_MCP_MAX_SIZE": "52428800",
"DOCX_MCP_NO_NETWORK": "true"
}
}
}
}
```
After adding, restart Claude Desktop. You can then ask Claude to:
- "Create a new Word document with our Q4 report"
- "Convert this DOCX file to PDF"
@@ -135,6 +192,7 @@ After adding, restart Claude Desktop. You can then ask Claude to:
Add to your Cursor settings (`~/.cursor/config.json` or through Settings UI):
**Basic Configuration:**
```json
{
"mcp": {
@@ -151,10 +209,24 @@ Add to your Cursor settings (`~/.cursor/config.json` or through Settings UI):
}
```
### Windsurf (Codeium)
Add to your Windsurf configuration (`~/.windsurf/config.json`):
**With Security Options (using command-line arguments):**
```json
{
"mcp": {
"servers": {
"docx": {
"command": "/absolute/path/to/docx-mcp/target/release/docx-mcp",
"args": ["--sandbox", "--whitelist", "open_document,extract_text,export_to_markdown"],
"env": {
"RUST_LOG": "info"
}
}
}
}
}
```
**With Security Options (using environment variables):**
```json
{
"mcp": {
@@ -162,6 +234,46 @@ Add to your Windsurf configuration (`~/.windsurf/config.json`):
"docx": {
"command": "/absolute/path/to/docx-mcp/target/release/docx-mcp",
"args": [],
"env": {
"RUST_LOG": "info",
"DOCX_MCP_SANDBOX": "true",
"DOCX_MCP_WHITELIST": "open_document,extract_text,export_to_markdown"
}
}
}
}
}
```
### Windsurf (Codeium)
Add to your Windsurf configuration (`~/.windsurf/config.json`):
**Basic Configuration:**
```json
{
"mcp": {
"servers": {
"docx": {
"command": "/absolute/path/to/docx-mcp/target/release/docx-mcp",
"args": [],
"env": {
"RUST_LOG": "info"
}
}
}
}
}
```
**With Security Options (using arguments):**
```json
{
"mcp": {
"servers": {
"docx": {
"command": "/absolute/path/to/docx-mcp/target/release/docx-mcp",
"args": ["--readonly", "--no-external-tools"],
"env": {
"RUST_LOG": "info"
}
@@ -175,6 +287,7 @@ Add to your Windsurf configuration (`~/.windsurf/config.json`):
Add to your Continue configuration (`~/.continue/config.json`):
**Basic Configuration:**
```json
{
"models": [
@@ -192,10 +305,29 @@ Add to your Continue configuration (`~/.continue/config.json`):
}
```
**With Security Options:**
```json
{
"models": [
{
"title": "Your Model",
"provider": "your-provider",
"mcp_servers": {
"docx": {
"command": "/absolute/path/to/docx-mcp/target/release/docx-mcp",
"args": ["--sandbox", "--max-size", "10485760"]
}
}
}
]
}
```
### VS Code with MCP Extension
If using the MCP extension for VS Code, add to your workspace settings (`.vscode/settings.json`):
**Basic Configuration:**
```json
{
"mcp.servers": {
@@ -210,6 +342,67 @@ If using the MCP extension for VS Code, add to your workspace settings (`.vscode
}
```
**With Security Options:**
```json
{
"mcp.servers": {
"docx": {
"command": "/absolute/path/to/docx-mcp/target/release/docx-mcp",
"args": ["--readonly", "--blacklist", "save_document,merge_documents"],
"env": {
"RUST_LOG": "info"
}
}
}
}
```
## 🔧 Command Line Arguments
The DOCX MCP server supports the following command-line arguments for configuration:
```bash
docx-mcp --help
```
### Available Arguments
| Argument | Environment Variable | Description | Example |
|----------|---------------------|-------------|---------|
| `--readonly` | `DOCX_MCP_READONLY=true` | Enable readonly mode - only viewing operations | `--readonly` |
| `--whitelist <COMMANDS>` | `DOCX_MCP_WHITELIST` | Comma-separated list of allowed commands | `--whitelist open_document,extract_text` |
| `--blacklist <COMMANDS>` | `DOCX_MCP_BLACKLIST` | Comma-separated list of forbidden commands | `--blacklist save_document,convert_to_pdf` |
| `--sandbox` | `DOCX_MCP_SANDBOX=true` | Restrict file operations to temp directory only | `--sandbox` |
| `--no-external-tools` | `DOCX_MCP_NO_EXTERNAL_TOOLS=true` | Disable external tools (LibreOffice, etc.) | `--no-external-tools` |
| `--no-network` | `DOCX_MCP_NO_NETWORK=true` | Disable network operations | `--no-network` |
| `--max-size <BYTES>` | `DOCX_MCP_MAX_SIZE` | Maximum document size in bytes | `--max-size 52428800` |
| `--max-docs <COUNT>` | `DOCX_MCP_MAX_DOCS` | Maximum number of open documents | `--max-docs 20` |
| `--help` | - | Show help information | `--help` |
| `--version` | - | Show version information | `--version` |
### Example Usage
```bash
# Basic usage
./target/release/docx-mcp
# Readonly mode with size limit
./target/release/docx-mcp --readonly --max-size 10485760
# Sandbox mode with command whitelist
./target/release/docx-mcp --sandbox --whitelist open_document,extract_text,export_to_markdown
# Multiple security options
./target/release/docx-mcp \
--readonly \
--no-external-tools \
--no-network \
--max-size 52428800 \
--max-docs 10
```
**Note:** Command-line arguments take precedence over environment variables when both are specified.
## 📚 Features
### Document Operations
+249
View File
@@ -0,0 +1,249 @@
# Release Guide
This document describes the release process for docx-mcp.
## Overview
The release process is automated using GitHub Actions and includes:
- Automated testing on multiple platforms
- Building release binaries for all supported targets
- Publishing to crates.io
- Creating GitHub releases with binaries
- Building and pushing Docker images
- Updating documentation
## Release Types
### Semantic Versioning
We follow [Semantic Versioning](https://semver.org/):
- **MAJOR**: Incompatible API changes
- **MINOR**: New features (backwards compatible)
- **PATCH**: Bug fixes (backwards compatible)
### Pre-release Versions
Pre-release versions can include suffixes like:
- `1.0.0-alpha.1` - Alpha releases
- `1.0.0-beta.1` - Beta releases
- `1.0.0-rc.1` - Release candidates
## Quick Release Process
For most releases, use the automated release script:
```bash
# Patch release (1.0.0 -> 1.0.1)
./scripts/release.sh patch
# Minor release (1.0.0 -> 1.1.0)
./scripts/release.sh minor
# Major release (1.0.0 -> 2.0.0)
./scripts/release.sh major
# Specific version
./scripts/release.sh version 1.5.0
# Pre-release
./scripts/release.sh version 1.0.0-beta.1
```
## Manual Release Process
If you need to create a release manually:
### 1. Pre-release Checks
```bash
# Run all checks
./scripts/release.sh check
# Or manually:
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-features
cargo build --release --all-features
cargo package --dry-run
```
### 2. Update Version
Update the version in `Cargo.toml`:
```toml
[package]
version = "1.2.3"
```
Update `Cargo.lock`:
```bash
cargo update -p docx-mcp
```
### 3. Commit and Tag
```bash
git add Cargo.toml Cargo.lock
git commit -m "Release v1.2.3"
git tag -a "v1.2.3" -m "Release v1.2.3"
git push origin main
git push origin v1.2.3
```
### 4. GitHub Actions
The release workflow will automatically:
1. Validate the release
2. Run tests on all platforms
3. Build binaries for all targets
4. Create GitHub release
5. Publish to crates.io (stable releases only)
6. Build and push Docker images
7. Update documentation
## Supported Platforms
Release binaries are built for:
- **Linux**: x86_64-unknown-linux-gnu, x86_64-unknown-linux-musl
- **Linux ARM**: aarch64-unknown-linux-gnu, aarch64-unknown-linux-musl
- **macOS**: x86_64-apple-darwin, aarch64-apple-darwin
- **Windows**: x86_64-pc-windows-msvc
## Docker Images
Docker images are published to:
- GitHub Container Registry: `ghcr.io/hongkongkiwi/docx-mcp`
- Docker Hub: `dockerhub-username/docx-mcp` (if configured)
Tags include:
- `latest` - Latest stable release
- `v1.2.3` - Specific version
- `1.2.3` - Semantic version
- `1.2` - Major.minor version
- `1` - Major version
## Publishing to crates.io
Stable releases (without pre-release suffixes) are automatically published to crates.io.
### Prerequisites
1. Set `CARGO_REGISTRY_TOKEN` secret in GitHub repository settings
2. Ensure you have publishing permissions for the crate
### Manual Publishing
```bash
# Dry run
cargo publish --dry-run
# Publish
cargo publish
```
## Troubleshooting
### Release Workflow Fails
1. Check the Actions tab in GitHub for detailed logs
2. Common issues:
- Version mismatch between tag and Cargo.toml
- Tests failing on specific platforms
- Missing secrets (CARGO_REGISTRY_TOKEN, DOCKERHUB credentials)
### Version Already Exists
If you need to recreate a release:
1. Delete the tag: `git tag -d v1.2.3 && git push origin :v1.2.3`
2. Delete the GitHub release (if created)
3. Create the tag again
### Docker Build Fails
1. Check if all dependencies are available in the Docker environment
2. Verify Dockerfile syntax and build context
3. Test locally: `docker build -t docx-mcp:test .`
### crates.io Publishing Fails
1. Verify `CARGO_REGISTRY_TOKEN` is set and valid
2. Check if version already exists
3. Ensure all required metadata is in Cargo.toml
4. Run `cargo package --dry-run` to check for issues
## Security Considerations
### Signing Releases
Currently, releases are not cryptographically signed. Consider adding:
1. GPG signing of Git tags
2. Binary signing with platform-specific tools
3. SBOM (Software Bill of Materials) generation
### Supply Chain Security
- Dependencies are audited in CI with `cargo audit`
- Docker images use specific base image versions
- Build reproducibility is enhanced with Rust's deterministic builds
## Release Checklist
Use this checklist for important releases:
- [ ] All planned features are implemented
- [ ] All tests pass locally and in CI
- [ ] Documentation is updated
- [ ] Breaking changes are documented
- [ ] Migration guide is provided (for major releases)
- [ ] Security implications are reviewed
- [ ] Performance regression tests pass
- [ ] Cross-platform compatibility verified
- [ ] Release notes are prepared
## Post-Release Tasks
After a release:
1. **Verify Installation**: Test installation from released binaries
2. **Update Examples**: Update example configurations if needed
3. **Notify Users**: Announce significant releases
4. **Monitor Issues**: Watch for issues related to the new release
5. **Update Dependencies**: Consider updating dependent projects
## Emergency Releases
For critical security fixes:
1. Create a hotfix branch from the affected release tag
2. Apply minimal fix
3. Follow expedited release process
4. Consider yanking affected versions from crates.io if necessary
```bash
# Yank a version from crates.io (if needed)
cargo yank --version 1.2.3
# Un-yank if needed later
cargo yank --version 1.2.3 --undo
```
## Release Schedule
- **Patch releases**: As needed for bug fixes
- **Minor releases**: Monthly or when significant features accumulate
- **Major releases**: Annually or when breaking changes are necessary
## Getting Help
- Open an issue for release-related problems
- Check GitHub Actions logs for CI failures
- Review this guide and workflow files for automation details
+265 -13
View File
@@ -169,20 +169,62 @@ flamegraph:
changelog:
git cliff --output CHANGELOG.md
# Prepare a release
# Release commands using the release script
# Create a patch release (0.1.0 -> 0.1.1)
release-patch:
./scripts/release.sh patch
# Create a minor release (0.1.0 -> 0.2.0)
release-minor:
./scripts/release.sh minor
# Create a major release (0.1.0 -> 1.0.0)
release-major:
./scripts/release.sh major
# Create a specific version release
release-version version:
./scripts/release.sh version {{version}}
# Dry run of patch release (see what would happen)
release-patch-dry:
./scripts/release.sh patch --dry-run
# Dry run of minor release
release-minor-dry:
./scripts/release.sh minor --dry-run
# Dry run of major release
release-major-dry:
./scripts/release.sh major --dry-run
# Dry run of specific version release
release-version-dry version:
./scripts/release.sh version {{version}} --dry-run
# Run all pre-release checks
release-check:
./scripts/release.sh check
# Generate changelog since last tag
release-changelog:
./scripts/release.sh changelog
# Create git tag for current version
release-tag:
./scripts/release.sh tag
# Prepare a release (legacy command - use release-* commands above)
prepare-release version:
# Update version in Cargo.toml
sed -i 's/^version = ".*"/version = "{{version}}"/' Cargo.toml
# Update dependencies to use new version
cargo update
# Run full test suite
just ci
# Generate changelog
just changelog
# Commit changes
git add .
git commit -m "chore: prepare release {{version}}"
git tag -a "v{{version}}" -m "Release {{version}}"
@echo "⚠️ This command is deprecated. Use 'just release-version {{version}}' instead."
@echo "The new release commands provide better automation and safety checks."
@echo ""
@echo "Available release commands:"
@echo " just release-patch - Bump patch version"
@echo " just release-minor - Bump minor version"
@echo " just release-major - Bump major version"
@echo " just release-version X.Y.Z - Set specific version"
# Show project statistics
stats:
@@ -222,3 +264,213 @@ init-hooks:
remove-hooks:
rm -f .git/hooks/pre-commit
echo "Pre-commit hook removed"
# Docker commands
# Build multi-platform Docker image
docker-build-multiarch:
docker buildx create --use --name multiarch || true
docker buildx build --platform linux/amd64,linux/arm64 -t docx-mcp:latest .
# Build and tag Docker image for release
docker-build-release version:
docker buildx build --platform linux/amd64,linux/arm64 \
-t docx-mcp:{{version}} \
-t docx-mcp:latest \
-t ghcr.io/hongkongkiwi/docx-mcp:{{version}} \
-t ghcr.io/hongkongkiwi/docx-mcp:latest \
.
# Push Docker images to registry
docker-push version:
docker push docx-mcp:{{version}}
docker push docx-mcp:latest
docker push ghcr.io/hongkongkiwi/docx-mcp:{{version}}
docker push ghcr.io/hongkongkiwi/docx-mcp:latest
# Run Docker container with volume mount for testing
docker-test:
docker run --rm -it -v $(pwd)/test-docs:/test-docs docx-mcp:latest
# Development environment commands
# Full development setup from scratch
dev-setup:
# Install Rust if not present
@if ! command -v rustup >/dev/null 2>&1; then \
echo "Installing Rust..."; \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y; \
source ~/.cargo/env; \
fi
# Setup toolchain and tools
just setup
# Initialize git hooks
just init-hooks
# Build project
just build
echo "✅ Development environment ready!"
# Check system dependencies
check-deps:
@echo "=== System Dependencies Check ==="
@echo "Checking required tools..."
@command -v rustc >/dev/null && echo "✅ Rust compiler found" || echo "❌ Rust compiler not found"
@command -v cargo >/dev/null && echo "✅ Cargo found" || echo "❌ Cargo not found"
@command -v git >/dev/null && echo "✅ Git found" || echo "❌ Git not found"
@command -v docker >/dev/null && echo "✅ Docker found" || echo "❌ Docker not found"
@command -v just >/dev/null && echo "✅ Just found" || echo "❌ Just not found"
@echo ""
@echo "Optional tools:"
@command -v libreoffice >/dev/null && echo "✅ LibreOffice found" || echo "⚠️ LibreOffice not found (optional)"
@command -v pdftoppm >/dev/null && echo "✅ pdftoppm found" || echo "⚠️ pdftoppm not found (optional)"
@command -v convert >/dev/null && echo "✅ ImageMagick convert found" || echo "⚠️ ImageMagick not found (optional)"
# Cross-compilation commands
# Build for all supported targets
build-all-targets:
# Install targets if not present
rustup target add x86_64-unknown-linux-gnu
rustup target add x86_64-unknown-linux-musl
rustup target add aarch64-unknown-linux-gnu
rustup target add x86_64-apple-darwin
rustup target add aarch64-apple-darwin
rustup target add x86_64-pc-windows-msvc
# Build for each target
cargo build --release --target x86_64-unknown-linux-gnu --all-features
cargo build --release --target x86_64-unknown-linux-musl --all-features
cargo build --release --target x86_64-apple-darwin --all-features
@echo "✅ Built for all available targets"
# Build using cross for Linux targets
build-cross-linux:
cargo install cross --git https://github.com/cross-rs/cross
cross build --release --target x86_64-unknown-linux-gnu --all-features
cross build --release --target x86_64-unknown-linux-musl --all-features
cross build --release --target aarch64-unknown-linux-gnu --all-features
cross build --release --target aarch64-unknown-linux-musl --all-features
# Maintenance commands
# Update all dependencies to latest versions
update-deps:
cargo update
cargo outdated --depth 1
# Check for security vulnerabilities and update
security-update:
cargo audit fix
cargo update
# Clean everything (including registry cache)
clean-all:
cargo clean
rm -rf ~/.cargo/registry/cache
rm -rf ~/.cargo/git/db
docker system prune -f
# Backup project (excluding target and build artifacts)
backup:
#!/usr/bin/env bash
BACKUP_NAME="docx-mcp-backup-$(date +%Y%m%d-%H%M%S)"
tar czf "${BACKUP_NAME}.tar.gz" \
--exclude='target' \
--exclude='.git' \
--exclude='*.log' \
--exclude='*.tmp' \
.
echo "✅ Backup created: ${BACKUP_NAME}.tar.gz"
# Development workflows
# Quick development loop (format, build, test unit, lint)
dev-loop:
just fmt
just build
just test-unit
just clippy
# Full quality check (everything CI runs)
quality-check:
just fmt-check
just clippy
just test
just docs-check
just audit
just deny
# Continuous development with file watching
dev-watch:
cargo install cargo-watch
cargo watch -w src -w tests -x "build" -x "test --lib"
# Performance analysis
perf-analysis:
# Build optimized release
cargo build --release --all-features
# Run criterion benchmarks
cargo bench --all-features
# Generate flamegraph if available
@if command -v flamegraph >/dev/null 2>&1; then \
echo "Generating flamegraph..."; \
cargo flamegraph --bin docx-mcp -- --help; \
fi
# MCP-specific commands
# Test MCP server functionality
test-mcp:
@echo "Testing MCP server..."
# Build the server
cargo build --release --all-features
# Run basic functionality test
python3 example/test_client.py || echo "❌ MCP test failed"
# Generate MCP documentation
mcp-docs:
@echo "Generating MCP server documentation..."
cargo run --bin docx-mcp -- --help > docs/CLI_REFERENCE.md
@echo "✅ CLI reference updated"
# Example commands
# Run all examples
run-examples:
@echo "Running all examples..."
@if [ -f example/test_client.py ]; then python3 example/test_client.py; fi
@if [ -f example/automation_example.py ]; then python3 example/automation_example.py; fi
# Generate test documents
gen-test-docs:
@echo "Generating test documents..."
mkdir -p test-docs
# You could add commands here to generate various test DOCX files
# Utility commands
# Show detailed project info
info:
@echo "=== Project Information ==="
@echo "Name: docx-mcp"
@echo "Version: $(grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')"
@echo "Rust version: $(rustc --version)"
@echo "Cargo version: $(cargo --version)"
@echo ""
just stats
# List all available commands with descriptions
help:
@echo "=== Available Commands ==="
@just --list
@echo ""
@echo "=== Release Commands ==="
@echo " release-patch - Create patch release (0.1.0 -> 0.1.1)"
@echo " release-minor - Create minor release (0.1.0 -> 0.2.0)"
@echo " release-major - Create major release (0.1.0 -> 1.0.0)"
@echo " release-version X - Create specific version release"
@echo " release-*-dry - Dry run versions of above commands"
@echo ""
@echo "=== Development Workflows ==="
@echo " dev-loop - Quick development cycle"
@echo " quality-check - Full quality assessment"
@echo " dev-setup - Complete development environment setup"
+355
View File
@@ -0,0 +1,355 @@
#!/bin/bash
# Release script for docx-mcp
# This script helps with version management and release preparation
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Helper functions
info() {
echo -e "${BLUE}$1${NC}"
}
success() {
echo -e "${GREEN}$1${NC}"
}
warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
error() {
echo -e "${RED}$1${NC}"
}
# Check if we're in a git repository
check_git_repo() {
if ! git rev-parse --git-dir > /dev/null 2>&1; then
error "Not in a git repository"
exit 1
fi
}
# Check if working directory is clean
check_clean_working_dir() {
if ! git diff-index --quiet HEAD --; then
error "Working directory is not clean. Please commit or stash your changes."
exit 1
fi
}
# Get current version from Cargo.toml
get_current_version() {
grep '^version = ' Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/'
}
# Update version in Cargo.toml
update_version() {
local new_version=$1
info "Updating version to $new_version"
# Update Cargo.toml
sed -i.bak "s/^version = \".*\"/version = \"$new_version\"/" Cargo.toml
rm Cargo.toml.bak
# Update Cargo.lock
cargo update -p docx-mcp
success "Version updated to $new_version"
}
# Generate changelog since last tag
generate_changelog() {
local last_tag=$(git tag --sort=-version:refname | head -1)
local new_version=$1
info "Generating changelog since $last_tag"
if [ -n "$last_tag" ]; then
git log --pretty=format:"- %s (%h)" --no-merges ${last_tag}..HEAD > CHANGELOG.tmp
else
git log --pretty=format:"- %s (%h)" --no-merges > CHANGELOG.tmp
fi
echo "## Release $new_version ($(date +%Y-%m-%d))"
echo ""
cat CHANGELOG.tmp
echo ""
rm CHANGELOG.tmp
}
# Run pre-release checks
run_checks() {
info "Running pre-release checks..."
# Format check
info "Checking code formatting..."
cargo fmt --all -- --check
success "Code formatting is correct"
# Clippy check
info "Running Clippy..."
cargo clippy --all-targets --all-features -- -D warnings
success "Clippy checks passed"
# Tests
info "Running tests..."
cargo test --all-features
success "All tests passed"
# Build check
info "Testing release build..."
cargo build --release --all-features
success "Release build successful"
# Package check
info "Testing package..."
cargo package --dry-run
success "Package validation passed"
}
# Create and push git tag
create_tag() {
local version=$1
local tag="v$version"
info "Creating git tag $tag"
# Create annotated tag
git tag -a "$tag" -m "Release $tag"
success "Created tag $tag"
# Ask if user wants to push
echo -n "Push tag to origin? [y/N]: "
read -r response
if [[ "$response" =~ ^[Yy]$ ]]; then
git push origin "$tag"
success "Tag pushed to origin"
else
warning "Tag not pushed. Remember to push it manually: git push origin $tag"
fi
}
# Show usage information
usage() {
cat << EOF
Usage: $0 [COMMAND] [OPTIONS]
Commands:
patch Bump patch version (0.1.0 -> 0.1.1)
minor Bump minor version (0.1.0 -> 0.2.0)
major Bump major version (0.1.0 -> 1.0.0)
version X.Y.Z Set specific version
check Run pre-release checks only
changelog Generate changelog since last tag
tag Create git tag for current version
Options:
--dry-run Show what would be done without making changes
--no-checks Skip pre-release checks (not recommended)
--no-tag Don't create git tag
--help Show this help message
Examples:
$0 patch # Bump to next patch version
$0 version 1.0.0 # Set version to 1.0.0
$0 check # Run all pre-release checks
$0 patch --dry-run # Show what patch release would do
EOF
}
# Parse version bump type
bump_version() {
local current_version=$1
local bump_type=$2
# Split version into components
IFS='.' read -ra VERSION_PARTS <<< "$current_version"
local major=${VERSION_PARTS[0]}
local minor=${VERSION_PARTS[1]}
local patch=${VERSION_PARTS[2]}
case $bump_type in
"patch")
patch=$((patch + 1))
;;
"minor")
minor=$((minor + 1))
patch=0
;;
"major")
major=$((major + 1))
minor=0
patch=0
;;
*)
error "Invalid bump type: $bump_type"
exit 1
;;
esac
echo "${major}.${minor}.${patch}"
}
# Validate version format
validate_version() {
local version=$1
if ! [[ $version =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.-]+)?$ ]]; then
error "Invalid version format: $version"
error "Expected format: X.Y.Z or X.Y.Z-suffix"
exit 1
fi
}
# Main script logic
main() {
local command=$1
local dry_run=false
local no_checks=false
local no_tag=false
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
--dry-run)
dry_run=true
shift
;;
--no-checks)
no_checks=true
shift
;;
--no-tag)
no_tag=true
shift
;;
--help)
usage
exit 0
;;
*)
if [ -z "$command" ]; then
command=$1
elif [ -z "$version_arg" ] && [ "$command" = "version" ]; then
version_arg=$1
fi
shift
;;
esac
done
# Check if command provided
if [ -z "$command" ]; then
usage
exit 1
fi
# Basic checks
check_git_repo
if [ "$dry_run" = false ]; then
check_clean_working_dir
fi
current_version=$(get_current_version)
info "Current version: $current_version"
case $command in
"patch"|"minor"|"major")
new_version=$(bump_version "$current_version" "$command")
;;
"version")
if [ -z "$version_arg" ]; then
error "Version argument required for 'version' command"
exit 1
fi
new_version=$version_arg
validate_version "$new_version"
;;
"check")
run_checks
success "All pre-release checks passed!"
exit 0
;;
"changelog")
generate_changelog "$current_version"
exit 0
;;
"tag")
if [ "$dry_run" = true ]; then
info "Would create tag v$current_version"
else
create_tag "$current_version"
fi
exit 0
;;
*)
error "Unknown command: $command"
usage
exit 1
;;
esac
info "New version will be: $new_version"
if [ "$dry_run" = true ]; then
warning "DRY RUN MODE - No changes will be made"
info "Would update version from $current_version to $new_version"
if [ "$no_checks" = false ]; then
info "Would run pre-release checks"
fi
if [ "$no_tag" = false ]; then
info "Would create git tag v$new_version"
fi
exit 0
fi
# Confirm with user
echo -n "Proceed with release $new_version? [y/N]: "
read -r response
if [[ ! "$response" =~ ^[Yy]$ ]]; then
warning "Release cancelled"
exit 0
fi
# Run pre-release checks
if [ "$no_checks" = false ]; then
run_checks
fi
# Update version
update_version "$new_version"
# Commit version bump
git add Cargo.toml Cargo.lock
git commit -m "Release $new_version"
success "Version bump committed"
# Create tag
if [ "$no_tag" = false ]; then
create_tag "$new_version"
fi
# Generate changelog for reference
info "Changelog for release:"
generate_changelog "$new_version"
success "Release $new_version completed!"
info "Next steps:"
info "1. Push commits: git push origin main"
if [ "$no_tag" = false ]; then
info "2. Push tag: git push origin v$new_version (if not done already)"
fi
info "3. GitHub Actions will automatically create the release"
}
# Run main function with all arguments
main "$@"
+4 -2
View File
@@ -3,6 +3,7 @@ use mcp_server::{Server, ServerBuilder, ServerOptions};
use mcp_core::ToolManager;
use tracing::info;
use tracing_subscriber::{EnvFilter, fmt, prelude::*};
use clap::Parser;
mod docx_tools;
mod docx_handler;
@@ -23,8 +24,9 @@ async fn main() -> Result<()> {
.with(EnvFilter::from_default_env())
.init();
// Load security configuration from environment
let security_config = security::SecurityConfig::from_env();
// Parse command line arguments (which also includes environment variables)
let args = security::Args::parse();
let security_config = security::SecurityConfig::from_args(args);
info!("Starting DOCX MCP Server - Security: {}", security_config.get_summary());
let docx_provider = DocxToolsProvider::new_with_security(security_config);
+93 -1
View File
@@ -2,6 +2,46 @@ use serde::{Deserialize, Serialize};
use std::collections::HashSet;
use std::env;
use tracing::{debug, info, warn};
use clap::Parser;
/// Command line arguments for the DOCX MCP server
#[derive(Parser, Debug)]
#[command(name = "docx-mcp")]
#[command(about = "A comprehensive Model Context Protocol (MCP) server for Microsoft Word DOCX file manipulation")]
#[command(version)]
pub struct Args {
/// Enable readonly mode - only allow viewing operations
#[arg(long, env = "DOCX_MCP_READONLY")]
pub readonly: bool,
/// Comma-separated whitelist of allowed commands
#[arg(long, env = "DOCX_MCP_WHITELIST", value_delimiter = ',')]
pub whitelist: Option<Vec<String>>,
/// Comma-separated blacklist of forbidden commands
#[arg(long, env = "DOCX_MCP_BLACKLIST", value_delimiter = ',')]
pub blacklist: Option<Vec<String>>,
/// Enable sandbox mode - restrict file operations to temp directory only
#[arg(long, env = "DOCX_MCP_SANDBOX")]
pub sandbox: bool,
/// Disable external tools (LibreOffice, etc.)
#[arg(long, env = "DOCX_MCP_NO_EXTERNAL_TOOLS")]
pub no_external_tools: bool,
/// Disable network operations
#[arg(long, env = "DOCX_MCP_NO_NETWORK")]
pub no_network: bool,
/// Maximum document size in bytes
#[arg(long, env = "DOCX_MCP_MAX_SIZE")]
pub max_size: Option<usize>,
/// Maximum number of open documents
#[arg(long, env = "DOCX_MCP_MAX_DOCS")]
pub max_docs: Option<usize>,
}
/// Security configuration for the MCP server
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -47,7 +87,59 @@ impl Default for SecurityConfig {
}
impl SecurityConfig {
/// Load configuration from environment variables
/// Create configuration from command line arguments
pub fn from_args(args: Args) -> Self {
let mut config = Self::default();
// Apply command line arguments
if args.readonly {
config.readonly_mode = true;
info!("Running in READONLY mode - only viewing operations allowed");
}
if let Some(whitelist) = args.whitelist {
let commands: HashSet<String> = whitelist.into_iter().collect();
info!("Command whitelist enabled with {} commands", commands.len());
config.command_whitelist = Some(commands);
}
if let Some(blacklist) = args.blacklist {
let commands: HashSet<String> = blacklist.into_iter().collect();
info!("Command blacklist enabled with {} blocked commands", commands.len());
config.command_blacklist = Some(commands);
}
if args.sandbox {
config.sandbox_mode = true;
config.allow_external_tools = false;
config.allow_network = false;
info!("Running in SANDBOX mode - restricted file operations");
}
if args.no_external_tools {
config.allow_external_tools = false;
info!("External tools disabled");
}
if args.no_network {
config.allow_network = false;
info!("Network operations disabled");
}
if let Some(size) = args.max_size {
config.max_document_size = size;
info!("Max document size set to {} bytes", size);
}
if let Some(max) = args.max_docs {
config.max_open_documents = max;
info!("Max open documents set to {}", max);
}
config
}
/// Load configuration from environment variables (deprecated, use from_args instead)
pub fn from_env() -> Self {
let mut config = Self::default();