This guide is for users who want to connect a local-network printer to Poke. The goal is to:
- connect a Huawei PixLab printer on the local network to a Raspberry Pi;
- manage the print queue through CUPS;
- expose printing capabilities to Poke through MCP;
- let Poke upload files to the Raspberry Pi and print them;
- protect the public endpoint with a Bearer API key; and
- automatically delete uploaded files after seven days.
This guide uses a Huawei PixLab V1 as an example. Other printers that support AirPrint, IPP, or driverless printing can follow the same approach.
1. Final Architecture#
Poke
│ HTTPS + Authorization: Bearer <MCP_API_KEY>
↓
Cloudflare Tunnel
↓
Raspberry Pi 127.0.0.1:3000
↓
mcp-compat-proxy.mjs
├─ Authentication
├─ Poke-compatible MCP sessions
├─ File upload tools
├─ print_url download tool
└─ Printer alias and option normalization
↓
Raspberry Pi 127.0.0.1:3001
↓
lan-mcp-cups
↓
CUPS
↓
Huawei PixLab driverless queueDo not expose CUPS port 631 directly to the public internet. Expose only the authenticated MCP endpoint.
2. Included Files#
The accompanying files are included with this site. Download them from the following paths, or create files with the same names manually on the deployment machine:
/downloads/huawei-printer-mcp/mcp-compat-proxy.mjs
/downloads/huawei-printer-mcp/huawei-printer-mcp-upstream.service
/downloads/huawei-printer-mcp/huawei-printer-mcp-proxy.service
/downloads/huawei-printer-mcp/cleanup-uploads.sh
/downloads/huawei-printer-mcp/huawei-printer-upload-cleanup.service
/downloads/huawei-printer-mcp/huawei-printer-upload-cleanup.timerWhen copying these files to the Raspberry Pi, the default installation directory is:
/home/pi/huawei-printer-mcp/If your username is not pi, replace every /home/pi in the examples and the User=pi and Group=pi values in the systemd units with your actual username.
3. Prerequisites#
The Raspberry Pi needs:
- Debian or Raspberry Pi OS;
- to be on the same local network as the printer;
- SSH installed and enabled;
- internet access for Cloudflare Tunnel and npm installation; and
- a domain that can be used with Cloudflare Tunnel.
Install the base packages:
sudo apt update
sudo apt install -y \
cups cups-client cups-bsd \
cups-browsed cups-filters avahi-daemon \
curl opensslNotes:
cupsandcups-client: the CUPS printing system;cups-bsd: provideslpr, whichlan-mcp-cupsuses forprint_file;cups-browsedandcups-filters: provide driverless and auto-discovered queues; andavahi-daemon: discovers.local, Bonjour, and AirPrint devices.
Enable CUPS:
sudo systemctl enable --now cups
sudo systemctl enable --now cups-browsed
sudo systemctl enable --now avahi-daemonTo manage CUPS in a browser:
sudo cupsctl --remote-any --remote-admin --share-printers
sudo usermod -aG lpadmin "$USER"
sudo systemctl restart cupsOpen:
https://<Raspberry-Pi-IP>:6314. Install Node.js and lan-mcp-cups#
Verify Node.js:
node -v
npm -vNode.js 20 or later is recommended.
Install lan-mcp-cups:
sudo npm install -g lan-mcp-cups
command -v lan-mcp-cupsThe output should resemble:
/usr/local/bin/lan-mcp-cups5. Configure the CUPS Print Queue#
First, inspect auto-discovered printers:
lpstat -p -d
lpstat -v
lpoptions -p <printer-name> -lA typical auto-discovered Huawei PixLab queue looks like this:
HUAWEI_PixLab_V1_0374Prefer this driverless auto-discovered queue over a manually created generic Printer - IPP Everywhere queue. The latter can produce blank pages or printer-side job cancellation for some PDF or image jobs.
Check the queue driver:
grep -Ei 'NickName|ModelName' /etc/cups/ppd/HUAWEI_PixLab_V1_0374.ppdThe ideal output includes:
HUAWEI PixLab V1, driverless, cups-filtersSet the default printer:
sudo lpadmin -d HUAWEI_PixLab_V1_0374
lpoptions -d HUAWEI_PixLab_V1_0374Set common default options:
sudo lpadmin \
-p HUAWEI_PixLab_V1_0374 \
-o ColorModel=Gray \
-o PageSize=A4 \
-o MediaType=Stationery \
-o cupsPrintQuality=Normal \
-o sides=one-sided \
-o print-scaling=auto-fitVerify the queue:
lpstat -p -d
lpoptions -p HUAWEI_PixLab_V1_03746. Deploy the MCP Files#
Create the directory:
mkdir -p /home/pi/huawei-printer-mcp/uploads
chmod 700 /home/pi/huawei-printer-mcp/uploadsCopy the accompanying files to the Raspberry Pi:
scp huawei-printer-mcp-poke-files/mcp-compat-proxy.mjs \
pi@<Raspberry-Pi-IP>:/home/pi/huawei-printer-mcp/
scp huawei-printer-mcp-poke-files/huawei-printer-mcp-upstream.service \
pi@<Raspberry-Pi-IP>:/home/pi/huawei-printer-mcp/
scp huawei-printer-mcp-poke-files/huawei-printer-mcp-proxy.service \
pi@<Raspberry-Pi-IP>:/home/pi/huawei-printer-mcp/
scp huawei-printer-mcp-poke-files/cleanup-uploads.sh \
pi@<Raspberry-Pi-IP>:/home/pi/huawei-printer-mcp/
scp huawei-printer-mcp-poke-files/huawei-printer-upload-cleanup.service \
pi@<Raspberry-Pi-IP>:/home/pi/huawei-printer-mcp/
scp huawei-printer-mcp-poke-files/huawei-printer-upload-cleanup.timer \
pi@<Raspberry-Pi-IP>:/home/pi/huawei-printer-mcp/Make the script executable:
chmod 755 /home/pi/huawei-printer-mcp/cleanup-uploads.sh7. Generate an MCP API Key#
This key is only for Poke to access your printing MCP. It is neither a Poke API key nor a Cloudflare token.
openssl rand -hex 32 > /home/pi/huawei-printer-mcp/mcp-api-key
chmod 600 /home/pi/huawei-printer-mcp/mcp-api-keyView the key:
cat /home/pi/huawei-printer-mcp/mcp-api-keyLater, enter only the character string itself in Poke’s API Key field. Do not prepend Bearer .
8. Install the systemd Services#
Install the two MCP services:
sudo install -o root -g root -m 0644 \
/home/pi/huawei-printer-mcp/huawei-printer-mcp-upstream.service \
/etc/systemd/system/huawei-printer-mcp-upstream.service
sudo install -o root -g root -m 0644 \
/home/pi/huawei-printer-mcp/huawei-printer-mcp-proxy.service \
/etc/systemd/system/huawei-printer-mcp-proxy.service
sudo systemctl daemon-reload
sudo systemctl enable --now huawei-printer-mcp-upstream.service
sudo systemctl enable --now huawei-printer-mcp-proxy.serviceThe services are:
huawei-printer-mcp-upstream.service
lan-mcp-cups, listening on 127.0.0.1:3001
huawei-printer-mcp-proxy.service
Authenticated session bridge, listening on 127.0.0.1:3000Check them:
systemctl is-enabled huawei-printer-mcp-upstream.service
systemctl is-active huawei-printer-mcp-upstream.service
systemctl is-enabled huawei-printer-mcp-proxy.service
systemctl is-active huawei-printer-mcp-proxy.service
ss -lntp | grep 3000
ss -lntp | grep 3001View logs:
journalctl -u huawei-printer-mcp-upstream.service -n 50 --no-pager
journalctl -u huawei-printer-mcp-proxy.service -n 50 --no-pagerImportant environment variables in huawei-printer-mcp-proxy.service:
MCP_PROXY_API_KEY_FILE=/home/pi/huawei-printer-mcp/mcp-api-key
MCP_UPLOAD_DIR=/home/pi/huawei-printer-mcp/uploads
MCP_MAX_UPLOAD_BYTES=78643200
MCP_PRINTER_ALIAS=Huawei_PixLab
MCP_TARGET_PRINTER=HUAWEI_PixLab_V1_037478643200 bytes equals 75 MiB.
9. Automatically Clean Uploaded Files After Seven Days#
Install the cleanup service and timer:
sudo install -o root -g root -m 0644 \
/home/pi/huawei-printer-mcp/huawei-printer-upload-cleanup.service \
/etc/systemd/system/huawei-printer-upload-cleanup.service
sudo install -o root -g root -m 0644 \
/home/pi/huawei-printer-mcp/huawei-printer-upload-cleanup.timer \
/etc/systemd/system/huawei-printer-upload-cleanup.timer
sudo systemctl daemon-reload
sudo systemctl enable --now huawei-printer-upload-cleanup.timerThe cleanup policy is:
Directory: /home/pi/huawei-printer-mcp/uploads
Retention: 7 days
Frequency: once per dayRun a dry run first:
sudo -u pi -H env \
DRY_RUN=1 \
MCP_UPLOAD_DIR=/home/pi/huawei-printer-mcp/uploads \
MCP_UPLOAD_RETENTION_DAYS=7 \
/home/pi/huawei-printer-mcp/cleanup-uploads.shView the timer:
systemctl list-timers --all huawei-printer-upload-cleanup.timer --no-pagerRun cleanup manually now:
sudo systemctl start huawei-printer-upload-cleanup.service10. Configure Cloudflare Tunnel#
Create a tunnel in Cloudflare Zero Trust:
Zero Trust
→ Networks
→ Tunnels
→ Create a tunnelAfter installing cloudflared on the Raspberry Pi, install the service using the command provided by the Cloudflare page.
Example public hostname:
Hostname: printer-mcp.example.com
Service Type: HTTP
Service URL: http://127.0.0.1:3000Notes:
- Cloudflare points to
127.0.0.1:3000; - do not point it to
3001; - do not point it to CUPS port
631; and - add
/mcpwhen entering the URL in Poke.
Check:
systemctl status cloudflared --no-pager
curl -i https://printer-mcp.example.com/mcpWithout an API key, it should return:
HTTP 401 Unauthorized11. Add the MCP Server in Poke#
Fill in Poke’s custom integration as follows:
Name:
Huawei Printer
MCP Server URL:
https://printer-mcp.example.com/mcp
API Key:
<the complete contents of /home/pi/huawei-printer-mcp/mcp-api-key>Do not enter:
Bearer xxxxxEnter only:
xxxxx12. Tools Available in Poke#
After deployment, Poke should show these tools:
list_printers
print_file
add_printer
upload_file
upload_and_print_file
print_urlRecommended:
print_urlWhen Poke can obtain an attachment download URL, let the Raspberry Pi download and print it.
You can also use:
upload_and_print_fileWhen Poke can send file contents to MCP as base64 or plain text, this uploads and prints the file immediately.
To upload without printing:
upload_file13. Tool Call Examples#
1. Upload Text Only#
{
"name": "upload_file",
"arguments": {
"file_name": "note.txt",
"content_text": "hello printer\n"
}
}2. Upload a Base64 File and Print It#
{
"name": "upload_and_print_file",
"arguments": {
"file_name": "document.pdf",
"content_base64": "<base64>",
"printer": "Huawei_PixLab",
"copies": 1,
"options": "ColorModel=Gray PageSize=A4 MediaType=Stationery cupsPrintQuality=Normal sides=one-sided print-scaling=auto-fit"
}
}The proxy automatically maps Huawei_PixLab to:
HUAWEI_PixLab_V1_03743. Download a URL and Print It#
{
"name": "print_url",
"arguments": {
"url": "https://example.com/file.pdf",
"file_name": "file.pdf",
"printer": "Huawei_PixLab",
"copies": 1,
"options": "ColorModel=Gray PageSize=A4 sides=one-sided"
}
}Security limits:
- only
httpandhttpsare supported; - localhost and private-network addresses are rejected by default;
- the maximum file size is 75 MiB; and
- uploaded files are deleted automatically after seven days.
14. Verification Commands#
Requests Without an API Key Must Be Rejected#
curl -i https://printer-mcp.example.com/mcpExpected:
HTTP/2 401
www-authenticate: BearerInitialize With an API Key#
MCP_KEY="$(cat /home/pi/huawei-printer-mcp/mcp-api-key)"
curl -i \
-X POST https://printer-mcp.example.com/mcp \
-H "Authorization: Bearer $MCP_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
--data-raw '{
"jsonrpc":"2.0",
"id":1,
"method":"initialize",
"params":{
"protocolVersion":"2025-03-26",
"capabilities":{},
"clientInfo":{"name":"manual-test","version":"1.0.0"}
}
}'The response headers should include:
mcp-session-id: ...15. Common Issues#
1. spawn lpr ENOENT#
Cause: cups-bsd is not installed, so the system does not have lpr.
Fix:
sudo apt install -y cups-bsd
command -v lpr2. lpr: unable to access "127.0.0.1"#
Cause: MCP_CUPS_SERVER=127.0.0.1 was set for lan-mcp-cups. It adds -h 127.0.0.1 to lpr, causing 127.0.0.1 to be treated as a file name.
Fix: do not set these for a local CUPS installation:
MCP_CUPS_SERVER
MCP_CUPS_PORTKeep only:
MCP_CUPS_DEFAULT_PRINTER
MCP_CUPS_HTTP_HOST
MCP_CUPS_HTTP_PORT3. Invalid Request: Server already initialized#
Cause: the HTTP transport in lan-mcp-cups does not handle repeated initialization well. This can be triggered when Poke or the proxy retries.
Fix: use the mcp-compat-proxy.mjs session bridge from this guide. It exposes multiple client sessions to Poke while reusing a single upstream session.
4. Blank Pages or Printer-Side Job Cancellation#
First check the queue driver:
grep -Ei 'NickName|ModelName' /etc/cups/ppd/<queue-name>.ppdUse a driver that resembles:
HUAWEI PixLab V1, driverless, cups-filtersAvoid the generic queue:
Printer - IPP EverywhereAlso ensure the print options use names supported by the queue:
ColorModel=Gray
PageSize=A4
MediaType=Stationery
cupsPrintQuality=Normal
sides=one-sided
print-scaling=auto-fit5. Poke Shows No Tools#
Check:
journalctl -u huawei-printer-mcp-proxy.service -n 100 --no-pager
journalctl -u huawei-printer-mcp-upstream.service -n 100 --no-pagerConfirm the public endpoint can show tools with an API key:
MCP_KEY="$(cat /home/pi/huawei-printer-mcp/mcp-api-key)"
curl -i https://printer-mcp.example.com/mcp \
-H "Authorization: Bearer $MCP_KEY"If Poke has cached an old tool list, remove and add the integration again, or refresh the connection in Poke.
16. Maintenance Commands#
Restart MCP:
sudo systemctl restart huawei-printer-mcp-upstream.service huawei-printer-mcp-proxy.serviceView status:
systemctl status huawei-printer-mcp-upstream.service --no-pager
systemctl status huawei-printer-mcp-proxy.service --no-pagerView uploaded files:
ls -lh /home/pi/huawei-printer-mcp/uploadsAdjust the upload size, for example to 100 MiB:
sudo systemctl edit huawei-printer-mcp-proxy.serviceEnter:
[Service]
Environment=MCP_MAX_UPLOAD_BYTES=104857600Then:
sudo systemctl daemon-reload
sudo systemctl restart huawei-printer-mcp-proxy.serviceAdjust the retention period, for example to 14 days:
sudo systemctl edit huawei-printer-upload-cleanup.serviceEnter:
[Service]
Environment=MCP_UPLOAD_RETENTION_DAYS=14Then:
sudo systemctl daemon-reload
sudo systemctl restart huawei-printer-upload-cleanup.timer17. Security Recommendations#
- Give the API key only to Poke.
- Do not share
/home/pi/huawei-printer-mcp/mcp-api-keywith anyone. - Have Cloudflare Tunnel forward only to
127.0.0.1:3000. - Do not expose CUPS port
631to the public internet. - Regularly check the upload directory size:
du -sh /home/pi/huawei-printer-mcp/uploads- For a Poke integration shared by multiple people, limit the default copy count. In Poke rules, require confirmation for jobs longer than 10 pages or with more than one copy.