@exactpdf/mcp 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -8
- package/dist/run.js +57 -4
- package/package.json +2 -2
- package/server.json +3 -3
package/README.md
CHANGED
|
@@ -56,11 +56,12 @@ For a local checkout of this monorepo:
|
|
|
56
56
|
| `exactpdf_extract_text` | POST /api/v1/extract-text | 1 |
|
|
57
57
|
| `exactpdf_pdf_structured_markdown` | POST /api/v1/pdf-structured-markdown | 1 |
|
|
58
58
|
| `exactpdf_estimate_speech_cost` | local estimate | 0 |
|
|
59
|
-
| `
|
|
60
|
-
| `
|
|
61
|
-
| `
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
59
|
+
| `exactpdf_voice_preview` | POST /api/v1/voice-preview | 0 |
|
|
60
|
+
| `exactpdf_pdf_to_speech` | POST /api/v1/pdf-to-speech | 1/min |
|
|
61
|
+
| `exactpdf_pdf_to_audiobook` | POST /api/v1/pdf-to-audiobook | 1/min |
|
|
62
|
+
| `exactpdf_generate_audiobook` | POST /api/v1/generate-audiobook | 1/min |
|
|
63
|
+
| `exactpdf_translate_and_speak` | POST /api/v1/translate-and-speak | 3/min |
|
|
64
|
+
| `exactpdf_presentation_narration` | POST /api/v1/presentation-narration | 1/min |
|
|
64
65
|
| `exactpdf_job_status` | GET /api/v1/jobs/:id | 0 |
|
|
65
66
|
| `exactpdf_get_speech_job` | GET /api/v1/speech-jobs/:id | 0 |
|
|
66
67
|
| `exactpdf_download_audio` | GET /api/v1/speech-jobs/:id/download | 0 |
|
|
@@ -69,9 +70,10 @@ Async audiobook flow:
|
|
|
69
70
|
|
|
70
71
|
```text
|
|
71
72
|
1. exactpdf_estimate_speech_cost(path="/abs/book.pdf", mode="audiobook")
|
|
72
|
-
2.
|
|
73
|
-
3.
|
|
74
|
-
4.
|
|
73
|
+
2. exactpdf_voice_preview(text="Read the first paragraph in an audiobook tone", voice_style="audiobook")
|
|
74
|
+
3. exactpdf_generate_audiobook(path="/abs/book.pdf", voice_style="audiobook")
|
|
75
|
+
4. exactpdf_get_speech_job(job_id="...", download=false)
|
|
76
|
+
5. exactpdf_download_audio(job_id="...") after status is succeeded
|
|
75
77
|
```
|
|
76
78
|
|
|
77
79
|
`exactpdf_pdf_to_speech`, `exactpdf_pdf_to_audiobook`, and `exactpdf_generate_audiobook` accept optional `callback_url` and `webhook_secret`. ExactPDF signs webhook bodies with `x-exactpdf-signature: sha256=<hmac>` over `timestamp.body`.
|
package/dist/run.js
CHANGED
|
@@ -24,8 +24,8 @@ function requireKey() {
|
|
|
24
24
|
}
|
|
25
25
|
return k;
|
|
26
26
|
}
|
|
27
|
-
const server = new McpServer({ name: 'exactpdf', version: '0.2.
|
|
28
|
-
instructions: 'ExactPDF API tools: exactpdf_account + exactpdf_pdf_info (free); merge, split, rotate, compress, images→PDF, extract-text, pdf-structured-markdown (1 credit each on success); async pdf-to-speech/pdf-to-audiobook/generate-audiobook (10 credits), translate-and-speak (20 credits), presentation narration (10 credits), plus speech job polling/download. Set EXACTPDF_API_KEY.',
|
|
27
|
+
const server = new McpServer({ name: 'exactpdf', version: '0.2.7' }, {
|
|
28
|
+
instructions: 'ExactPDF API tools: exactpdf_account + exactpdf_pdf_info (free); merge, split, rotate, compress, images→PDF, extract-text, pdf-structured-markdown (1 credit each on success); voice-preview (free), async pdf-to-speech/pdf-to-audiobook/generate-audiobook (10 credits), translate-and-speak (20 credits), presentation narration (10 credits), plus speech job polling/download. Set EXACTPDF_API_KEY.',
|
|
29
29
|
});
|
|
30
30
|
async function saveBinaryFromResponse(res, prefix, fallbackExt) {
|
|
31
31
|
const buf = Buffer.from(await res.arrayBuffer());
|
|
@@ -793,7 +793,8 @@ server.registerTool('exactpdf_estimate_speech_cost', {
|
|
|
793
793
|
}
|
|
794
794
|
const estimatedMinutes = minutes ?? Math.max(1, Math.ceil(estimatedChars / 900));
|
|
795
795
|
const selectedMode = target_language ? 'translate' : (mode ?? 'audiobook');
|
|
796
|
-
const
|
|
796
|
+
const creditsPerMinute = selectedMode === 'translate' ? 3 : 1;
|
|
797
|
+
const credits = Math.max(1, estimatedMinutes * creditsPerMinute);
|
|
797
798
|
return {
|
|
798
799
|
content: [
|
|
799
800
|
{
|
|
@@ -805,14 +806,66 @@ server.registerTool('exactpdf_estimate_speech_cost', {
|
|
|
805
806
|
file_bytes: fileBytes,
|
|
806
807
|
characters: estimatedChars || null,
|
|
807
808
|
generated_minutes: estimatedMinutes,
|
|
809
|
+
credits_per_minute: creditsPerMinute,
|
|
808
810
|
current_credit_cost: credits,
|
|
809
|
-
note: 'ExactPDF
|
|
811
|
+
note: 'ExactPDF charges async speech jobs by estimated generated minutes: 1 credit/minute for standard speech, 3 credits/minute for translate-and-speak. Path-based estimates are rough until the API extracts PDF text.',
|
|
810
812
|
},
|
|
811
813
|
}, null, 2),
|
|
812
814
|
},
|
|
813
815
|
],
|
|
814
816
|
};
|
|
815
817
|
});
|
|
818
|
+
server.registerTool('exactpdf_voice_preview', {
|
|
819
|
+
description: 'Generate a short server-side voice preview before submitting a paid PDF speech job. Saves MP3/WAV locally. Does not consume credits.',
|
|
820
|
+
inputSchema: z.object({
|
|
821
|
+
text: z.string().optional().describe('Preview text, capped server-side at 600 characters.'),
|
|
822
|
+
output_format: z.enum(['mp3', 'wav']).optional().describe('Audio preview format. Default: mp3.'),
|
|
823
|
+
voice_style: z
|
|
824
|
+
.enum(['professional', 'audiobook', 'educational', 'presenter', 'conversational'])
|
|
825
|
+
.optional()
|
|
826
|
+
.describe('Narration style. Default: professional.'),
|
|
827
|
+
voice_id: z.string().optional().describe('Optional Google Cloud voice name, e.g. en-US-Standard-H.'),
|
|
828
|
+
language: z.string().optional().describe('Language hint such as en, hi, es, fr. Default: en.'),
|
|
829
|
+
speed: z.number().min(0.5).max(2).optional().describe('Speech speed multiplier, 0.5-2.0.'),
|
|
830
|
+
}),
|
|
831
|
+
}, async ({ text, output_format, voice_style, voice_id, language, speed }) => {
|
|
832
|
+
const key = requireKey();
|
|
833
|
+
const res = await fetch(`${BASE}/api/v1/voice-preview`, {
|
|
834
|
+
method: 'POST',
|
|
835
|
+
headers: {
|
|
836
|
+
Authorization: `Bearer ${key}`,
|
|
837
|
+
Accept: '*/*',
|
|
838
|
+
'Content-Type': 'application/json',
|
|
839
|
+
},
|
|
840
|
+
body: JSON.stringify({
|
|
841
|
+
...(text ? { text } : {}),
|
|
842
|
+
...(output_format ? { output_format } : {}),
|
|
843
|
+
...(voice_style ? { voice_style } : {}),
|
|
844
|
+
...(voice_id ? { voice_id } : {}),
|
|
845
|
+
...(language ? { language } : {}),
|
|
846
|
+
...(typeof speed === 'number' ? { speed } : {}),
|
|
847
|
+
}),
|
|
848
|
+
});
|
|
849
|
+
if (!res.ok) {
|
|
850
|
+
const raw = await res.text();
|
|
851
|
+
return {
|
|
852
|
+
content: [{ type: 'text', text: `voice-preview failed HTTP ${res.status}\n${raw.slice(0, 8000)}` }],
|
|
853
|
+
isError: true,
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
const ext = extensionFromContentType(res.headers.get('content-type'), output_format ?? 'mp3');
|
|
857
|
+
const outPath = await saveBinaryFromResponse(res, 'exactpdf-voice-preview', ext);
|
|
858
|
+
return {
|
|
859
|
+
content: [
|
|
860
|
+
{
|
|
861
|
+
type: 'text',
|
|
862
|
+
text: `Voice preview saved: ${outPath}\n` +
|
|
863
|
+
`Credits used: ${res.headers.get('x-credits-used') ?? '0'}\n` +
|
|
864
|
+
`Provider: ${res.headers.get('x-exactpdf-provider') ?? 'unknown'}`,
|
|
865
|
+
},
|
|
866
|
+
],
|
|
867
|
+
};
|
|
868
|
+
});
|
|
816
869
|
server.registerTool('exactpdf_pdf_to_speech', {
|
|
817
870
|
description: 'Create an async PDF→speech job via /api/v1/pdf-to-speech (10 credits). Alias of the production audiobook pipeline.',
|
|
818
871
|
inputSchema: speechJobSchema,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@exactpdf/mcp",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "MCP server for ExactPDF — PDF tools, async PDF
|
|
3
|
+
"version": "0.2.7",
|
|
4
|
+
"description": "MCP server for ExactPDF — PDF tools, voice previews, async PDF speech/audiobook jobs, polling, and API credits.",
|
|
5
5
|
"mcpName": "com.exactpdf/mcp",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/run.js",
|
package/server.json
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
|
|
3
3
|
"name": "com.exactpdf/mcp",
|
|
4
4
|
"title": "ExactPDF",
|
|
5
|
-
"description": "Agent-facing PDF API: merge, split, rotate, compress, images, metadata, text, Markdown, async speech/audiobook, multilingual speech, and presentation narration jobs.",
|
|
6
|
-
"version": "0.2.
|
|
5
|
+
"description": "Agent-facing PDF API: merge, split, rotate, compress, images, metadata, text, Markdown, voice previews, async speech/audiobook, multilingual speech, and presentation narration jobs.",
|
|
6
|
+
"version": "0.2.7",
|
|
7
7
|
"websiteUrl": "https://exactpdf.com/docs/api",
|
|
8
8
|
"packages": [
|
|
9
9
|
{
|
|
10
10
|
"registryType": "npm",
|
|
11
11
|
"identifier": "@exactpdf/mcp",
|
|
12
|
-
"version": "0.2.
|
|
12
|
+
"version": "0.2.7",
|
|
13
13
|
"transport": {
|
|
14
14
|
"type": "stdio"
|
|
15
15
|
}
|