Convert documents (txt, markdown, pdf, etc.) to HTML
Project description
Toa is a library for converting documents to HTML.
[!tip] By default, it returns a string-type HTML fragment. You can decide how to render it yourself, such as beautifying the page display.
The built-in HTML templates can return fully structured HTML content, supporting Mermaid stylesheets, formulas, and syntax highlighting, which can be enabled selectively.
Toa supports the following conversions:
- Ebooks: EPUB
- Emails: EML, MSG(outlook)
- Documents: DOCX, PDF, TXT, MD(Markdown)
- Spreadsheets: XLSX, XLS, CSV
- Presentations: PPTX
- Data Exchange: JSON, JSONL
- Markup Languages: XML, HTML
- Multimedia: audio files, video files, supports audio-to-text conversion and video subtitles extraction.
- Resources from the Internet
- ...
Toa provides convenience for online previewing of documents, emails, data reports, e-books, etc.
Of course, Toa can also convert HTML to Markdown.
Install
pip install toa
Can be used after installation
toa -h
toa-mcp -help
It may only support following content can be converted to HTML.
- such as
json,jsonl,txt,md, etc. - file streams
- external links (such as web crawlers, FTP, and WebSockets)
Extras: [mcp], [csv], [docx], [epub], [excel], [outlook], [pdf], [pptx], [rss], [audio], [video]
uv add 'toa[mcp, csv, excel]'
[lite]supports capabilities other than[video].[all]will install all dependencies. If you don't want to make a choice, this might be the best option, and an additional OCR engine needs to be installed.
with OCR If OCR image recognition is required, you can choose an OCR engine. Such as paddleocr, easyocr, pytesseract, for example:
uv add paddlepaddle paddleocr
Usage
Use in command line
toa md.md
toa md.md -o md.html --wrapper default --mermaid --highlight --formula
[!note] If the file does not exist, it may be treated as a string and ultimately returned as an HTML fragment.
--wrapper: HTML fragment wrapper-o: output filename--mermaid: mermaid rendering is required.--highlight: highlight rendering is required.--formula: Requires support for rendering mathematical formulas.
standard input
cat pdf.pdf | toa
cat pdf.pdf | toa --wrapper default -o pdf.html --source-url https://example.com/pdf.pdf --engine default
--source-url: An accessible file address ensures the page displays correctly.--engine: rendering engine name
[!important] Some content can only be displayed correctly with server support.
fetch from websocket endpoint
toa ws://examples.com/ws
toa wss://examples.com/wss
fetch from ftp server
toa ftp://ftp.example.com/readme.txt
Use it in Python coding
from toa import Toa
toa = Toa()
result = toa.convert('md.md')
print(result.content) # <p>md.md</p>
toa-mcp
Toa has built-in MCP capabilities. The corresponding separate command is toa-mcp. toa-mcp is a server based on the MCP (Model Context Protocol) protocol, providing a standardized API interface for the toa command-line tool.
Multi-mode Operation:
- HTTP: Provides a RESTful API interface, suitable for web integration.
- SSE: Server sends events, supports real-time push notifications.
- WebSocket: Bidirectional persistent connection for real-time interaction.
- Stdio: Standard input/output communication, suitable for integration with AI assistants.
| endpoint | method | description |
|---|---|---|
/sse |
Get/POST | Message data is transmitted in a streaming manner (Server-to-Client). |
/messages |
GET | Standard message retrieval endpoint (Polling/REST). |
/mcp |
GET | Streamable HTTP (Model Context Protocol / Long-polling transport). |
/ws |
GET (Upgrade) | Full-duplex bidirectional streaming (WebSocket connection for real-time interaction). |
/ping |
GET | Check service availability (Heartbeat). |
MCP protocol supports
{
"jsonrpc": "2.0",
"method": "tools/list",
"params": {},
"id": 1
}
Integrations
There are multiple ways to integrate.
Microservice architecture
prepare docker-compose.yml
# docker-compose.yml
services:
toa-cli:
image: sunshmo/toa:latest
entrypoint: ["toa"]
command: ["--help"]
stdin_open: true
tty: true
toa-mcp:
image: sunshmo/toa:latest
entrypoint: ["toa-mcp", "--transport", "http"]
ports:
- "56156:56156"
# other services
Build and start service
docker-compose up toa-cli
docker-compose up -d toa-mcp
AI assistant integration Such as, Cursor, openclaw, claude, etc.
{
"mcpServers": {
"toa": {
"command": "toa-mcp",
"args": ["--transport", "stdio"]
}
}
}
You can also use the docker command.
{
"mcpServers": {
"toa": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"-v",
"./path/data:/data", // resource directory mapping
"sunshmo/toa:latest",
"toa-mcp",
"--transport",
"stdio"
]
}
}
}
Integration with coding If toa-mcp is already running, then you can call it in the program. No programming language restrictions. For example, below uses HTTP transport.
async def with_http():
import httpx
async with httpx.AsyncClient(follow_redirects=True) as client:
response = await client.post(
"http://localhost:56156/mcp",
headers={"Content-Type": "application/json", "Accept": "application/json"},
json={"jsonrpc": "2.0", "method": "tools/list", "id": 1},
)
print("tools:", response.json())
Below is the capability of Java to call toa-mcp
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
public class McpHttpClient {
private static final ObjectMapper mapper = new ObjectMapper();
public static void withHttp() throws Exception {
HttpClient client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NORMAL)
.connectTimeout(Duration.ofSeconds(10))
.build();
// build JSON-RPC request
ObjectNode request = mapper.createObjectNode();
request.put("jsonrpc", "2.0");
request.put("method", "tools/list");
request.put("id", 1);
HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(URI.create("http://localhost:56156/mcp"))
.header("Content-Type", "application/json")
.header("Accept", "application/json")
.timeout(Duration.ofSeconds(30))
.POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(request)))
.build();
HttpResponse<String> response = client.send(httpRequest, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() == 200) {
JsonNode result = mapper.readTree(response.body());
System.out.println("tools: " + result.toPrettyString());
} else {
System.err.println("HTTP Error: " + response.statusCode());
}
}
public static void main(String[] args) throws Exception {
withHttp();
}
}
with web MCP Inspector debug
npx @modelcontextprotocol/inspector
The accessible UI address after startup is http://localhost:6274. You can switch the Transport Type to STDIO, SSE, or Streamable HTTP.
STDIO: Enter toa-mcp in the command field and click Connect.
SSE:
- Start service:
toa-mcp --transport http, ortoa-mcp --transport sse, ortoa-mcp --transport wscan all start the web service. - Enter
URL:http://localhost:56156/sse - click
Connect
Streamable HTTP:
- Enter
URL:http://localhost:56156/mcp - click
Connect
Docker
Running MCP Web Server Using Docker to build eliminates the hassle of OCR installation. Running toa-mcp service in Docker.
docker run -d \
-p 56156:56156 \
--name toa \
-v /the/host/dir:/data \
sunshmo/toa:latest \
toa-mcp --transport http
Verify if the service is usable, visit http://localhost:56156/ping, Seeing "pong" indicates a normal startup.
[!tip]
-voption maps a host directory to a container directory, allowing you to use a directory path within the container as the target file path when calling the function.
STDIO
docker run --rm -i sunshmo/toa:latest toa < your.eml
Plugin
In reality, there may be files that Toa currently does not support for conversion, or you may want to override Toa's default capabilities. In such cases, you can achieve this by using an extension plugin.
You can do like this:
- Implement a class that inherits from BaseConverter
- then register the converter with Toa
Below is one full example scenario.
plugin example
from typing import BinaryIO
from toa import Toa, BaseConverter, InputInfo, OutputInfo, ConversionResult
class MyToaConverter(BaseConverter):
def __init__(self) -> None:
super().__init__()
@property
def check_dependencies(self) -> bool:
"""
Returns a boolean value. Returns True if there are no external dependencies;
otherwise, the conversion will throw an error.
"""
return True
@property
def suffixes(self) -> list[str]:
"""Define extension (Format: ['.toa'])"""
return [".toa"]
@property
def mime_types(self) -> list[str]:
return []
def convert(
self,
input_stream: BinaryIO,
input_info: InputInfo,
output_info: OutputInfo | None = None,
**kwargs,
) -> ConversionResult:
return ConversionResult(content="Result from plugin conversion")
toa = Toa()
# register
toa.add_converter(MyToaConverter())
result = toa.convert("abc.toa")
print(result.content)
[!note] Either
suffixesormime_typesmust be a value that is not of typeNoneType.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file toa-0.1.1.tar.gz.
File metadata
- Download URL: toa-0.1.1.tar.gz
- Upload date:
- Size: 61.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
487d8effeeb0d279be61bfa03a1aa2508bfca26a6f5c84307b06fd44d14f7b25
|
|
| MD5 |
9c62a69aec747e50ca58d766c1084f43
|
|
| BLAKE2b-256 |
cf314e8faa57fccf0a775cf57318428ac665e0daf1e6dfe2a8b5d2e188b7d083
|
File details
Details for the file toa-0.1.1-py3-none-any.whl.
File metadata
- Download URL: toa-0.1.1-py3-none-any.whl
- Upload date:
- Size: 77.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.8
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
69f34b05eb76cc62f822f2a7f7dab88049321bf98952573ef3fc7e212bd23f90
|
|
| MD5 |
d1b4352637c799e71f52afea5674cc16
|
|
| BLAKE2b-256 |
a881a8442aae4456198b1ac078f84d26399ea03d5672c7333adcc1c18deae7d6
|