Jalankan sesi dokumen agen melalui MCP
Sekilas pandang
Bagian berjudul “Sekilas pandang”Ini adalah satu sesi agen lengkap dengan server Model Context
Protocol (MCP) NextPDF Connect, pesan demi pesan: initialize,
tools/list, enam pemanggilan tools/call yang membangun sebuah brief
proyek satu halaman, dan perjalanan bolak-balik human-in-the-loop (HITL)
yang menerapkan gerbang pada penulisan berkas akhir. Setiap pesan
JSON-RPC di bawah direkam apa adanya dari proses bin/nextpdf-mcp yang
aktif (hanya tool tingkatan core), lalu disanitasi dengan tepat dua cara:
token konfirmasi sekali-pakai ditampilkan sebagai
confirm_<single-use-hex>, dan direktori sementara sistem pada mesin
dipersingkat menjadi C:\Temp. Identifier, skema, posisi, dan jumlah
byte persis seperti yang dikirim server.
Pemasangan
Bagian berjudul “Pemasangan”composer require nextpdf/serverKaitkan transport stdio di host MCP Anda — untuk Claude Desktop (host meluncurkan perintah dari direktorinya sendiri, jadi gunakan path absolut; transport stdio tidak memerlukan API key, tidak seperti transport REST):
{ "mcpServers": { "nextpdf": { "command": "php", "args": ["/absolute/path/to/your/project/vendor/bin/nextpdf-mcp"] } }}Server berbicara JSON-RPC 2.0 yang dipisahkan baris-baru pada stdin/stdout dan menjaga output protokol tetap terpisah secara tegas dari diagnostik: baris startup dan audit diarahkan ke stderr, tidak pernah stdout.
Tinjauan konseptual
Bagian berjudul “Tinjauan konseptual”Sesi dokumen MCP bersifat stateful. create_pdf membuka sebuah dokumen
di penyimpanan dalam-memori server dan mengembalikan sebuah
document_id; setiap panggilan berikutnya menargetkan identifier
tersebut. Tool konten (set_font, add_text, add_table) dieksekusi
seketika pada tingkat risiko Caution dengan pencatatan audit;
preview_layout adalah pembacaan Safe; dan output_pdf dengan sebuah
file_path bersifat Approval Required — ia tidak berjalan pada
panggilan pertama. Sebaliknya, server mengembalikan sebuah tantangan
dengan token sekali-pakai, agen meneruskan tantangan tersebut ke
manusia, dan hanya panggilan-ulang yang membawa _confirmation_token
yang mengeksekusi penulisan. Dokumen yang tertinggal di penyimpanan
kedaluwarsa setelah masa-hidup yang dikonfigurasi (30 menit secara
bawaan).
Pemanggilan tool yang sama menggerakkan mesin tool melalui REST dan gRPC — semua transport ini berbagi satu executor — sehingga semua yang ada di sini kecuali framing stdio ikut berlaku. Lihat Render faktur secara menyeluruh melalui REST untuk mesin yang sama pada permukaan HTTP.
Permukaan API
Bagian berjudul “Permukaan API”| Tool | Peran dalam sesi ini | Tingkat risiko |
|---|---|---|
create_pdf | Membuka dokumen, dapatkan document_id | Caution |
set_font | Pilih heading, lalu muka huruf isi | Caution |
add_text | Baris judul, lalu paragraf pengantar | Caution |
add_table | Tabel checklist pemilik/tanggal-jatuh-tempo | Caution |
preview_layout | Baca keadaan tata letak sebelum output | Safe |
output_pdf (mode berkas) | Tulis PDF — digerbangi | Approval Required |
Deployment yang direkam di sini mendaftarkan 20 tool (13 core, 6 Pro, 1
Enterprise — jumlahnya muncul di respons initialize di bawah); sesi ini
hanya menggunakan tool core, sehingga berjalan tanpa perubahan pada
instalasi yang hanya open-source. Katalog rujukan adalah balasan
tools/list dari server Anda sendiri, dan tangga risiko didefinisikan
dalam rujukan tingkatan risiko HITL.
Sesi, pesan demi pesan
Bagian berjudul “Sesi, pesan demi pesan”1. Inisialisasi koneksi
Bagian berjudul “1. Inisialisasi koneksi”Klien membuka sesi dan menyatakan versi protokolnya:
{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": { "name": "planning-agent", "version": "1.0.0" } }}Server mengonfirmasi versi protokol dan mendeklarasikan kapabilitasnya, termasuk jumlah tool per tingkatan dan bahwa penggerbangan HITL diaktifkan:
{ "jsonrpc": "2.0", "id": 1, "result": { "protocolVersion": "2025-06-18", "capabilities": { "tools": { "listChanged": false }, "nextpdf": { "tiers": { "core": 13, "pro": 6, "enterprise": 1 }, "tool_count": 20, "risk_model_version": 1, "hitl_enabled": true } }, "serverInfo": { "name": "NextPDF Connect", "version": "1.0.0" } }}Klien memberikan pengakuan dengan sebuah notifikasi (notifikasi tidak
membawa id dan tidak menerima respons):
{ "jsonrpc": "2.0", "method": "notifications/initialized"}2. Temukan tool
Bagian berjudul “2. Temukan tool”{ "jsonrpc": "2.0", "id": 2, "method": "tools/list"}Balasan lengkap mencantumkan seluruh 20 tool yang terdaftar beserta skema input lengkapnya. Yang ditampilkan di sini dipersingkat menjadi dua tool yang membuka dan menutup sesi ini — 18 entri yang dihilangkan memiliki bentuk yang sama:
{ "jsonrpc": "2.0", "id": 2, "result": { "tools": [ { "name": "create_pdf", "description": "Create a new PDF document and return a document_id for subsequent operations", "inputSchema": { "type": "object", "properties": { "page_size": { "type": "string", "description": "Page size name (e.g. \"A4\", \"Letter\", \"Legal\", \"A3\")", "default": "A4" }, "orientation": { "type": "string", "enum": [ "portrait", "landscape" ], "description": "Page orientation", "default": "portrait" }, "title": { "type": "string", "description": "Document title metadata" }, "author": { "type": "string", "description": "Document author metadata" } }, "required": [] }, "annotations": { "destructiveHint": false, "idempotentHint": false } }, { "name": "output_pdf", "description": "Finalize the PDF and output to file or return as base64", "inputSchema": { "type": "object", "properties": { "document_id": { "type": "string", "description": "The document_id returned by create_pdf" }, "file_path": { "type": "string", "description": "Absolute file path to save the PDF. If omitted, returns base64-encoded PDF data." }, "destroy": { "type": "boolean", "description": "Whether to remove the document from the store after output", "default": true } }, "required": [ "document_id" ] }, "annotations": { "destructiveHint": false, "openWorldHint": true } } ] }}Perhatikan skema output_pdf: file_path bersifat opsional, dan
anotasinya membawa openWorldHint: true — tool ini dapat menyentuh dunia
di luar sesi, justru itulah sebabnya mode berkas digerbangi.
3. Buka dokumen
Bagian berjudul “3. Buka dokumen”{ "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "create_pdf", "arguments": { "page_size": "A4", "orientation": "portrait", "title": "Project kickoff brief", "author": "Planning agent" } }}{ "jsonrpc": "2.0", "id": 3, "result": { "content": [ { "type": "text", "text": "{\"document_id\":\"doc_3b9f435efa0f32d1da7a131d\",\"page_count\":1,\"page_size\":\"A4\",\"orientation\":\"portrait\"}" } ], "structuredContent": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "page_count": 1, "page_size": "A4", "orientation": "portrait" } }}Setiap hasil tool tiba dua kali dalam satu pesan: sebuah blok teks
content yang dapat dibaca manusia, dan structuredContent yang dapat
dibaca mesin. Baca structuredContent.document_id dan teruskan melalui
setiap panggilan berikutnya.
4. Tambahkan heading
Bagian berjudul “4. Tambahkan heading”Atur muka huruf tebal 16-poin, lalu tempatkan judul:
{ "jsonrpc": "2.0", "id": 4, "method": "tools/call", "params": { "name": "set_font", "arguments": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "family": "helvetica", "style": "B", "size": 16 } }}{ "jsonrpc": "2.0", "id": 4, "result": { "content": [ { "type": "text", "text": "Font set to helvetica B 16pt on document doc_3b9f435efa0f32d1da7a131d." } ] }}{ "jsonrpc": "2.0", "id": 5, "method": "tools/call", "params": { "name": "add_text", "arguments": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "text": "Project kickoff brief" } }}{ "jsonrpc": "2.0", "id": 5, "result": { "content": [ { "type": "text", "text": "{\"document_id\":\"doc_3b9f435efa0f32d1da7a131d\",\"position\":{\"x\":10,\"y\":16,\"page\":0}}" } ], "structuredContent": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "position": { "x": 10, "y": 16, "page": 0 } } }}5. Tambahkan paragraf isi
Bagian berjudul “5. Tambahkan paragraf isi”Kembali ke muka huruf reguler 11-poin untuk teks pengantar; width: 0
memilih tata letak multi-sel lebar-penuh:
{ "jsonrpc": "2.0", "id": 6, "method": "tools/call", "params": { "name": "set_font", "arguments": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "family": "helvetica", "style": "", "size": 11 } }}{ "jsonrpc": "2.0", "id": 6, "result": { "content": [ { "type": "text", "text": "Font set to helvetica 11pt on document doc_3b9f435efa0f32d1da7a131d." } ] }}{ "jsonrpc": "2.0", "id": 7, "method": "tools/call", "params": { "name": "add_text", "arguments": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "text": "Prepared by the planning agent for the 14 July kickoff. Scope, owners, and the first-week checklist are tabled below.", "width": 0, "line_height": 6 } }}{ "jsonrpc": "2.0", "id": 7, "result": { "content": [ { "type": "text", "text": "{\"document_id\":\"doc_3b9f435efa0f32d1da7a131d\",\"position\":{\"x\":10,\"y\":29.75,\"page\":0}}" } ], "structuredContent": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "position": { "x": 10, "y": 29.75, "page": 0 } } }}6. Tambahkan tabel checklist
Bagian berjudul “6. Tambahkan tabel checklist”{ "jsonrpc": "2.0", "id": 8, "method": "tools/call", "params": { "name": "add_table", "arguments": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "html": "<table><tr><th>Work item</th><th>Owner</th><th>Due</th></tr><tr><td>Repository bootstrap</td><td>Devon</td><td>2026-07-15</td></tr><tr><td>CI pipeline</td><td>Ana</td><td>2026-07-17</td></tr><tr><td>Staging deploy</td><td>Priya</td><td>2026-07-21</td></tr></table>" } }}{ "jsonrpc": "2.0", "id": 8, "result": { "content": [ { "type": "text", "text": "{\"document_id\":\"doc_3b9f435efa0f32d1da7a131d\",\"position\":{\"x\":10,\"y\":84.75,\"page\":0}}" } ], "structuredContent": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "position": { "x": 10, "y": 84.75, "page": 0 } } }}Setiap panggilan konten mengembalikan position kursor yang diperbarui,
sehingga agen selalu tahu di mana elemen berikutnya akan mendarat.
7. Pratinjau sebelum meminta persetujuan
Bagian berjudul “7. Pratinjau sebelum meminta persetujuan”preview_layout adalah panggilan Safe yang hanya-baca — agen yang
berperilaku baik memeriksa apa yang telah dibangunnya sebelum meminta
manusia menyetujui sebuah penulisan:
{ "jsonrpc": "2.0", "id": 9, "method": "tools/call", "params": { "name": "preview_layout", "arguments": { "document_id": "doc_3b9f435efa0f32d1da7a131d" } }}{ "jsonrpc": "2.0", "id": 9, "result": { "content": [ { "type": "text", "text": "{\"document_id\":\"doc_3b9f435efa0f32d1da7a131d\",\"total_pages\":1,\"current_page\":0,\"page_dimensions\":{\"width\":595.276,\"height\":841.89},\"margins\":{\"top\":10,\"right\":10,\"bottom\":10,\"left\":10},\"cursor_position\":{\"x\":10,\"y\":84.75}}" } ], "structuredContent": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "total_pages": 1, "current_page": 0, "page_dimensions": { "width": 595.276, "height": 841.89 }, "margins": { "top": 10, "right": 10, "bottom": 10, "left": 10 }, "cursor_position": { "x": 10, "y": 84.75 } } }}8. Minta penulisan berkas — gerbang menjawab lebih dulu
Bagian berjudul “8. Minta penulisan berkas — gerbang menjawab lebih dulu”Agen meminta output_pdf untuk menulis brief yang telah selesai ke disk,
menjaga dokumen tetap hidup (destroy: false) untuk berjaga-jaga jika
manusia menolak dan ia perlu beralih ke output base64:
{ "jsonrpc": "2.0", "id": 10, "method": "tools/call", "params": { "name": "output_pdf", "arguments": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "file_path": "C:\\Temp\\nextpdf-mcp\\kickoff-brief.pdf", "destroy": false } }}Berkas tidak ditulis. Karena mode berkas bersifat Approval Required, server justru menjawab dengan sebuah tantangan konfirmasi:
{ "jsonrpc": "2.0", "id": 10, "result": { "content": [ { "type": "text", "text": "⚠️ CONFIRMATION REQUIRED\n\nOperation: output_pdf\nDescription: Finalize the PDF and output to file or return as base64\n\nTo proceed, call output_pdf again with parameter _confirmation_token: \"confirm_<single-use-hex>\"\nExpires in 300 seconds." } ], "isError": false }}9. Manusia menyetujui — panggil ulang dengan token
Bagian berjudul “9. Manusia menyetujui — panggil ulang dengan token”Agen meneruskan teks tantangan ke manusia. Setelah disetujui, ia
memanggil output_pdf lagi dengan argumen yang sama ditambah
_confirmation_token:
{ "jsonrpc": "2.0", "id": 11, "method": "tools/call", "params": { "name": "output_pdf", "arguments": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "file_path": "C:\\Temp\\nextpdf-mcp\\kickoff-brief.pdf", "destroy": false, "_confirmation_token": "confirm_<single-use-hex>" } }}Token dikonsumsi, penulisan dieksekusi, dan hasilnya melaporkan berkas yang ditulis:
{ "jsonrpc": "2.0", "id": 11, "result": { "content": [ { "type": "text", "text": "{\"document_id\":\"doc_3b9f435efa0f32d1da7a131d\",\"file_path\":\"C:\\\\Temp\\\\nextpdf-mcp\\\\kickoff-brief.pdf\",\"file_size\":3612,\"page_count\":1,\"destroyed\":false}" } ], "structuredContent": { "document_id": "doc_3b9f435efa0f32d1da7a131d", "file_path": "C:\\Temp\\nextpdf-mcp\\kickoff-brief.pdf", "file_size": 3612, "page_count": 1, "destroyed": false } }}Verifikasi berkas yang ditulis
Bagian berjudul “Verifikasi berkas yang ditulis”Sesi ini menulis kickoff-brief.pdf (3.612 byte, satu halaman, cocok
dengan structuredContent.file_size dan page_count). Output
qpdf --check yang direkam untuk berkas persis itu:
checking kickoff-brief.pdfPDF Version: 2.0File is not encryptedFile is not linearizedNo syntax or stream encoding errors found; the file may still containerrors that qpdf cannot detectItu adalah pemeriksaan struktural, dalam kata-kata qpdf sendiri — bukan penetapan konformansi.
Kasus tepi & jebakan
Bagian berjudul “Kasus tepi & jebakan”- Panggilan-ulang harus mengulang argumen yang sama. Token
konfirmasi terikat pada nama tool ditambah digest kanonis dari argumen
yang untuknya token itu diterbitkan. Memanggil ulang dengan sesuatu
yang berubah — bahkan sekadar membalik
destroy— tidak mengonsumsi token; server justru menjawab dengan tantangan baru. Ulangi argumen yang persis sama dan hanya tambahkan_confirmation_token. - Token bersifat sekali-pakai dan kedaluwarsa. Tantangan menyatakan kedaluwarsanya (300 detik). Setelah kedaluwarsa atau dikonsumsi, panggilan tergerbang berikutnya mendapat tantangan baru; teruskan yang baru itu.
- Output berkas mendarat di dalam direktori yang masuk daftar-izin.
Server menolak sebuah
file_pathdi luar direktori sementaranya yang dikonfigurasi denganOutput path rejected by security policy. Akar daftar-izin bawaan adalahnextpdf-mcpdi bawah direktori sementara sistem; operator mengubahnya dengan pengaturantemp_dirdinextpdf-mcp.yaml. - Mode base64 tidak digerbangi.
output_pdftanpafile_pathmengembalikan PDF sebagai base64 pada tingkat Review, tanpa efek samping sistem berkas — lihat Wajibkan persetujuan manusia untuk output berkas untuk pembahasan mendalam tentang batas itu. - Sebuah tantangan adalah hasil, bukan kesalahan. Pesan tantangan
tiba dengan
isError: false; persetujuan yang tertunda adalah jeda alur kerja. Jangan mencoba ulang dalam sebuah loop, dan jangan pernah memalsukan token. - Notifikasi tidak mendapat balasan. Setelah
notifications/initialized, jangan memblokir untuk menunggu baris respons.
Kinerja
Bagian berjudul “Kinerja”Sesi ini bersifat dalam-memori dari ujung ke ujung: panggilan konten kembali dalam milidetik pada jalannya yang direkam, dan waktu yang berlalu didominasi oleh perjalanan bolak-balik persetujuan manusia, yang justru merupakan inti dari gerbang. Penyimpanan dokumen menahan sebuah sesi selama 30 menit waktu diam secara bawaan (maksimum 50 dokumen), sehingga persetujuan yang lambat tidak kehilangan dokumen yang telah dibangun — tetapi dokumen yang ditinggalkan akan dibersihkan.
Catatan keamanan
Bagian berjudul “Catatan keamanan”- Perlakukan token konfirmasi sebagai rahasia sekali-pakai. Teruskan teks tantangan ke manusia; jangan mencatat token atau menyimpannya secara persisten. Halaman ini menyunting token yang direkam justru karena alasan itu.
- Jejak audit berada di stderr. Setiap eksekusi pada tingkat Caution atau lebih tinggi dicatat sebagai audit (tool, risiko, argumen, hasil) melalui PSR-3, dengan parameter sensitif disunting. Diagnostik tidak pernah bercampur ke dalam aliran protokol.
- Daftar-izin path adalah batas sistem berkas. Arahkan
temp_dirke sebuah direktori yang didedikasikan untuk output Connect; jangan memperlebarnya ke lokasi serba-guna. - Tingkat risiko hanya bergerak naik. Sebuah override operator di
nextpdf-mcp.yamldapat menaikkan tingkat risiko sebuah tool tetapi tidak pernah dapat menurunkanoutput_pdfdi bawah Approval Required.
Konformansi
Bagian berjudul “Konformansi”Resep ini tidak membuat klaim standar normatif apa pun. Ia
mendokumentasikan transport stdio MCP (JSON-RPC 2.0, versi protokol
2025-06-18 sebagaimana dinegosiasikan dalam pertukaran initialize
yang direkam) dan kontrak risiko serta konfirmasi milik server. Langkah
qpdf --check di atas hanya mengonfirmasi integritas struktural
berkas yang ditulis; konformansi terhadap sebuah standar ditetapkan oleh
validator independen, bukan ditegaskan oleh perangkat lunak yang
memproduksinya.
Lihat juga
Bagian berjudul “Lihat juga”- Wajibkan persetujuan manusia untuk output berkas — gerbang konfirmasi secara mendalam, termasuk jalur penolakan.
- Render faktur secara menyeluruh melalui REST — mesin tool yang sama melalui HTTP, dengan transkrip wire yang direkam.
- Buat PDF pertama Anda — sesi Connect terkecil.
- Konvensi resep Connect — kontrak yang diikuti setiap resep Connect.
- Tingkatan risiko HITL — tangga risiko kanonis dan resolusi kebijakan.
- Katalog tool — katalog tool rujukan.