A lightweight Model Context Protocol (MCP) server that exposes document conversion as an AI tool. Built on GroupDocs.Conversion for .NET and the official MCP C# SDK.
Drop a file into a folder, call the convert_document tool, get the result — no boilerplate, no upload streams.
- One tool —
convert_documentconverts any supported source document to a target format - File-path based — source and output are relative paths on mounted folders; no binary blobs in the MCP payload
- Dual transport — STDIO for local/desktop MCP hosts, HTTP for remote/Docker deployments
- Path sandboxing — all paths are resolved under configured roots;
.., absolute paths and symlinks are rejected - Bounded concurrency — configurable semaphore limits parallel conversions
- Health endpoints —
/health/liveand/health/readyfor container orchestration - Docker-first — single Linux image, non-root user, data via mounted volumes
| Format | Extension |
|---|---|
pdf |
|
| Word | docx |
| Excel | xlsx |
| PowerPoint | pptx |
| HTML | html |
| Plain text | txt |
| JPEG image | jpg |
| PNG image | png |
GroupDocs.Conversion supports 100+ source formats as input.
- .NET 8 SDK (for local/development use)
- Docker (for containerized deployment)
- GroupDocs.Conversion license (optional — runs in evaluation mode without one)
# 1. Clone the repository
git clone https://github.com/groupdocs-conversion/groupdocs-conversion-mcp.git
cd groupdocs-conversion-mcp
# 2. (Optional) Place your GroupDocs license
mkdir -p docker/secrets
cp /path/to/your.lic docker/secrets/groupdocs-license.lic
# 3. Start the server
docker compose -f docker/docker-compose.yml up -d
# 4. Verify it's running
curl http://localhost:8080/health/readyThe server listens on http://localhost:8080/mcp (Streamable HTTP transport).
git clone https://github.com/groupdocs-conversion/groupdocs-conversion-mcp.git
cd groupdocs-conversion-mcp
# Set paths for your local machine
export INPUT_ROOT=/tmp/gdconv/in
export OUTPUT_ROOT=/tmp/gdconv/out
export WORK_ROOT=/tmp/gdconv/work
mkdir -p $INPUT_ROOT $OUTPUT_ROOT $WORK_ROOT
dotnet run --project src/GroupDocs.Conversion.McpServerThe server runs in STDIO mode by default — suitable for Claude Desktop, VS Code MCP extensions, and other local MCP hosts.
Add to claude_desktop_config.json:
{
"mcpServers": {
"groupdocs-conversion": {
"command": "dotnet",
"args": [
"run",
"--project",
"/absolute/path/to/src/GroupDocs.Conversion.McpServer"
],
"env": {
"INPUT_ROOT": "/your/input/folder",
"OUTPUT_ROOT": "/your/output/folder",
"WORK_ROOT": "/tmp/gdconv/work"
}
}
}
}{
"mcpServers": {
"groupdocs-conversion": {
"url": "http://localhost:8080/mcp"
}
}
}{
"mcp.servers": {
"groupdocs-conversion": {
"url": "http://localhost:8080/mcp"
}
}
}{
"name": "convert_document",
"description": "Convert one document under the configured input root into a target format and save the result under the configured output root.",
"inputSchema": {
"type": "object",
"properties": {
"sourcePath": {
"type": "string",
"description": "Relative path to the source file under INPUT_ROOT."
},
"targetFormat": {
"type": "string",
"description": "Target format: pdf, docx, xlsx, pptx, html, txt, jpg, png."
},
"outputPath": {
"type": "string",
"description": "Relative path to the output file under OUTPUT_ROOT."
},
"overwrite": {
"type": "boolean",
"default": false
},
"password": {
"type": ["string", "null"],
"description": "Password for protected source documents."
}
},
"required": ["sourcePath", "targetFormat", "outputPath"]
}
}{
"sourcePath": "reports/quarterly.docx",
"targetFormat": "pdf",
"outputPath": "converted/quarterly.pdf",
"overwrite": false
}{
"success": true,
"sourcePath": "reports/quarterly.docx",
"outputPath": "converted/quarterly.pdf",
"targetFormat": "pdf",
"durationMs": 842,
"outputExists": true,
"outputSizeBytes": 153284
}{
"success": false,
"errorCode": "source_not_found",
"message": "Source file not found: 'reports/quarterly.docx'",
"sourcePath": "reports/quarterly.docx",
"targetFormat": "pdf"
}| Code | Meaning |
|---|---|
invalid_request |
Missing or malformed input field |
source_not_found |
Source file does not exist under INPUT_ROOT |
source_outside_allowed_root |
Source path escapes INPUT_ROOT |
output_outside_allowed_root |
Output path escapes OUTPUT_ROOT |
output_exists |
Output file exists and overwrite is false |
unsupported_target_format |
Requested format is not in the supported set |
input_too_large |
Source file exceeds MAX_INPUT_FILE_MB |
conversion_timeout |
Conversion exceeded CONVERSION_TIMEOUT_SECONDS |
conversion_failed |
GroupDocs threw an exception during conversion |
license_error |
GroupDocs license could not be loaded |
internal_error |
Unexpected server error |
| Variable | Default | Description |
|---|---|---|
MCP_TRANSPORT |
stdio |
Transport mode: stdio or http |
ASPNETCORE_URLS |
http://0.0.0.0:8080 |
HTTP listen address (HTTP mode only) |
INPUT_ROOT |
/data/in |
Absolute path to the input folder |
OUTPUT_ROOT |
/data/out |
Absolute path to the output folder |
WORK_ROOT |
/data/work |
Writable temp folder used during conversion |
LOG_ROOT |
/data/logs |
Log output directory |
MAX_CONCURRENT_CONVERSIONS |
2 |
Maximum parallel conversions |
MAX_INPUT_FILE_MB |
200 |
Maximum source file size in megabytes |
CONVERSION_TIMEOUT_SECONDS |
300 |
Per-conversion timeout in seconds |
ALLOW_OVERWRITE |
false |
Allow output to overwrite existing files globally |
AUTH_MODE |
none |
Authentication mode (none or apikey) |
API_KEY |
(empty) | Bearer token required when AUTH_MODE=apikey |
GROUPDOCS_LICENSE_PATH |
(empty) | Path to the GroupDocs .lic file |
| Container path | Purpose | Recommended host mount |
|---|---|---|
/data/in |
Source documents (read-only) | /srv/gdconv/in:/data/in:ro |
/data/out |
Converted output files | /srv/gdconv/out:/data/out |
/data/work |
Temporary working files | /srv/gdconv/work:/data/work |
/data/logs |
Application logs | /srv/gdconv/logs:/data/logs |
| Endpoint | Description |
|---|---|
GET /health/live |
Returns 200 when the process is running |
GET /health/ready |
Returns 200 when all storage roots exist and WORK_ROOT is writable |
Without a license the server runs in evaluation mode — conversions are functional but output documents may contain evaluation watermarks.
To apply a license:
# Docker: mount as a secret
mkdir -p docker/secrets
cp your-license.lic docker/secrets/groupdocs-license.lic
# Then set the path in the container
GROUPDOCS_LICENSE_PATH=/run/secrets/groupdocs-licenseThe license file is never committed to the repository. secrets/ is listed in .gitignore.
See GroupDocs licensing documentation for details.
# Restore and build
dotnet build
# Run tests
dotnet test
# Publish a self-contained binary
dotnet publish src/GroupDocs.Conversion.McpServer \
-c Release -r linux-x64 --self-contained true -o ./publish
# Build Docker image
docker build -f docker/Dockerfile -t groupdocs/groupdocs-conversion-mcp:1.0.0 .src/
GroupDocs.Conversion.McpServer/
Program.cs # Entry point, transport selection
Tooling/
ConvertDocumentTool.cs # MCP tool registration
Services/
ConversionService.cs # Conversion orchestration
PathSandboxService.cs # Path validation and sandboxing
FormatMappingService.cs # Format string → ConvertOptions
Models/ # Request / response / error models
Options/ # Typed configuration
Health/
HealthChecks.cs # /health/ready check
tests/
GroupDocs.Conversion.McpServer.Tests/
PathSandboxTests.cs
FormatMappingTests.cs
ConversionServiceTests.cs
docker/
Dockerfile
docker-compose.yml
samples/
input/ # Place source documents here when using Docker Compose
output/ # Converted documents appear here
- Only relative paths are accepted; absolute paths and
..traversal are rejected - Source and output paths are fully resolved and verified to stay within their configured roots
- The input volume should be mounted read-only (
:ro) wherever possible - File size is validated before conversion begins
- Each conversion runs with a cancellation token and a configurable timeout
- The container runs as a non-root user
- Secrets (license file, API key) are mounted at runtime, never baked into the image
The MCP server wrapper code in this repository is licensed under the MIT License.
Dependency notice: This project depends on GroupDocs.Conversion for .NET, which is a separate commercial product with its own license terms. A GroupDocs license must be obtained independently. See groupdocs.com for pricing and trial options.
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-change - Make your changes and add tests
- Run
dotnet test— all tests must pass - Open a pull request
Please keep pull requests focused on a single change. New format support, security improvements, and bug fixes are welcome.