feat: Add embedMarkdown to upload response and document attachment format
Build and Push Outline MCP Docker Image / build (push) Successful in 7s

The upload response now includes an embedMarkdown field with the correct
Outline attachment syntax ([name size](/api/attachments.redirect?id=...))
so callers can insert it directly into documents for native card rendering.

IMPLEMENTATION.md updated with storage backend details, auth header,
and embedding format documentation.
This commit is contained in:
2026-05-25 02:52:49 +00:00
parent c68bb66de1
commit 176e1f1040
2 changed files with 68 additions and 4 deletions
+55
View File
@@ -314,6 +314,61 @@ Delete attachment. Params: id (required)
### attachments.redirect
Get attachment URL. Params: id (required)
### Custom HTTP Gateway Upload
Instead of manually calling `attachments.create` and executing the subsequent storage upload, you can use the MCP server's integrated HTTP upload proxy.
This endpoint receives binary content over HTTP, registers the attachment with Outline, and uploads it to the configured storage backend (S3 or local file storage).
- **Endpoint**: `POST /upload`
- **Query Parameters**:
- `documentId` (required): The UUID of the destination Outline document.
- `name` (required): The filename of the attachment (e.g., `image.png`, `document.pdf`).
- **Headers**:
- `Authorization` (required): `Bearer <OUTLINE_API_TOKEN>`
- `Content-Length` (required): The exact size of the file in bytes.
- `Content-Type` (optional): The MIME type of the file (e.g., `application/pdf`, `image/png`). If omitted, it will be auto-detected by filename extension.
- **Request Body**: The raw file binary content.
- **Storage backends**: Auto-detected from the Outline API response.
- **S3**: PUT to pre-signed URL.
- **Local file storage**: Multipart POST to `/api/files.create` with form fields.
- **Response**:
```json
{
"ok": true,
"data": {
"id": "attachment-uuid",
"name": "filename.ext",
"size": 12345,
"contentType": "mime/type",
"url": "/api/attachments.redirect?id=attachment-uuid",
"embedMarkdown": "[filename.ext 12345](/api/attachments.redirect?id=attachment-uuid)"
}
}
```
### Embedding Attachments in Documents
Outline uses a special markdown syntax to render attachment cards (with file icon, name, and download size). The format is:
```
[filename.ext filesize](/api/attachments.redirect?id=attachment-uuid)
```
Where:
- `filename.ext` is the attachment filename
- `filesize` is the file size in bytes (space-separated, not a label)
- The URL is the **relative** `/api/attachments.redirect?id=...` path
The `embedMarkdown` field in the upload response provides this string ready to insert into a document body via `documents.update`.
**Example**: Upload a file and embed it in a document:
```
1. POST /upload?documentId=doc-uuid&name=report.pdf → get embedMarkdown
2. outline_api_call("documents.update", {"id": "doc-uuid", "text": "...\n\n" + embedMarkdown, "append": true})
```
**Important**: Do NOT use absolute URLs (e.g., `https://docs.example.com/api/attachments.redirect?id=...`) — Outline will not render the attachment card for absolute URLs. Always use the relative path.
---
## Auth
+13 -4
View File
@@ -684,16 +684,25 @@ async def upload_endpoint(request: Request) -> JSONResponse:
logger.info("Upload to storage completed successfully")
# 4. Return success and attachment metadata
# 4. Return success with attachment metadata and embedding markdown
att_name = attachment_data.get("name", filename)
att_size = attachment_data.get("size", size)
att_url = attachment_data.get("url", "")
# Outline renders attachment cards when the link text is "filename size"
# and the href is the relative /api/attachments.redirect path.
embed_markdown = f"[{att_name} {att_size}]({att_url})"
return JSONResponse(
{
"ok": True,
"data": {
"id": attachment_data.get("id"),
"name": attachment_data.get("name"),
"size": attachment_data.get("size"),
"name": att_name,
"size": att_size,
"contentType": attachment_data.get("contentType"),
"url": attachment_data.get("url"),
"url": att_url,
"embedMarkdown": embed_markdown,
},
}
)