Skip to main content
Glama
bestimmaa

@bestimmaa/posprint-mcp

by bestimmaa
README.md
# @bestimmaa/posprint-mcp

MCP server for POS printer receipts using [`@bestimmaa/posprint`](https://www.npmjs.com/package/@bestimmaa/posprint).

The tool is intentionally named `print` so clients can map natural user phrasing such as "print receipt", "hard copy", or "print this out" to the same operation.

## Requirements

- Node.js 20+
- A printer reachable via a CUPS URI supported by `@bestimmaa/posprint`

## MCP Client Configuration

Add this to your MCP client config. No separate installation step is required — `npx` fetches the package on first run.

```json
{
  "mcpServers": {
    "posprint": {
      "command": "npx",
      "args": ["-y", "@bestimmaa/posprint-mcp"]
    }
  }
}
```

## Global Install (optional)

```bash
npm install -g @bestimmaa/posprint-mcp
```

After global installation, you can use the shorter form in your MCP client config:

```json
{
  "mcpServers": {
    "posprint": {
      "command": "posprint-mcp"
    }
  }
}
```

## Docker (remote MCP server)

For clients that can only talk to a *remote* MCP server (e.g. Notion custom agents), run `posprint-mcp` in a Docker container over HTTP instead of stdio. The image defaults to `MCP_TRANSPORT=http`.

### Configuration via `.env`

Copy [`.env.example`](.env.example) to `.env` and fill in your values — `.env` is gitignored, so real tokens/URIs never get committed.

```bash
cp .env.example .env
# edit .env: set POSPRINT_AUTH_TOKEN (e.g. `openssl rand -hex 32`) and PRINTER_URI
docker compose up -d --build
```

`docker-compose.yml` reads `.env` automatically (both for the container's env vars and the host port mapping). To run without Compose, pass the same file to `docker run` directly:

```bash
docker build -t posprint-mcp .
docker run -d --name posprint-mcp -p 3000:3000 --env-file .env posprint-mcp
```

The server listens on `POST /mcp` (MCP Streamable HTTP transport, stateless) and `GET /healthz` (unauthenticated health check). It refuses to start if `POSPRINT_AUTH_TOKEN` is unset, since an unauthenticated remote endpoint would let anyone on the network print to your printer.

Point your remote MCP client at `http://<host>:3000/mcp` with header-based auth:

```
Authorization: Bearer <POSPRINT_AUTH_TOKEN>
```

Note: the container needs network access to your printer's CUPS/IPP endpoint (typically on your LAN), so run it on a network that can reach it (e.g. `--network host`, or a bridge network with routing to the printer's subnet).

**`.local` (mDNS) hostnames will not resolve inside the container** — most base images (including this one) have no mDNS support, so a `PRINTER_URI` like `ipp://myprinter.local:631/...` will fail to connect. Use one of:

- The printer's static/reserved IP address, or
- A regular DNS name if your router provides one (e.g. many Fritz!Box routers also expose LAN devices as `<name>.fritz.box`, which resolves via normal DNS and works fine in containers).

### Environment variables

| Variable | Applies to | Description |
| --- | --- | --- |
| `MCP_TRANSPORT` | both | `stdio` (default) or `http`. The Docker image sets this to `http`. |
| `PORT` | `http` transport | Port to listen on. Defaults to `3000`. |
| `POSPRINT_AUTH_TOKEN` | `http` transport | Bearer token required on every `/mcp` request. **Required** when `MCP_TRANSPORT=http` — the server refuses to start without it. |
| `PRINTER_URI` | both | Default CUPS printer URI. When set, the `print` tool's `printerUri` argument becomes optional; an explicit `printerUri` in a tool call still takes precedence. |

## Development

```bash
npm install
npm run build
npm test
```

Run the local server from source:

```bash
npm run dev
```

Run the built server:

```bash
npm start
```

## Tool: `print`

Input:

- `printerUri?: string` (optional if the server has a default configured via the `PRINTER_URI` environment variable)
- `markdown: string`
- `mode: "preview" | "confirm"`
- `confirmationToken?: string` (required when `mode="confirm"`)
- `options?: { copies?: number; timeoutMs?: number }`

### Two-step confirmation flow

1. Call `print` with `mode: "preview"`.
2. Show the returned snippet to the user and ask for confirmation.
3. Call `print` again with `mode: "confirm"` and the returned `confirmationToken`.

Preview response includes:

- `requiresConfirmation: true`
- `confirmationToken`
- `preview.lineCount`
- `preview.snippet`
- `preview.excessiveLengthWarning` (present when markdown is more than 80 lines)

Confirm response shape:

```json
{ "ok": true, "meta": { "printerUri": "...", "durationMs": 20, "printedAt": "...", "jobId": "optional" } }
```

Error codes:

- `VALIDATION_ERROR`
- `PRINTER_ERROR`
- `TIMEOUT`

TDQS

A3.6/5.0

Scored across 1 tool

Disambiguation5/5

With only one tool, there is no risk of confusion or overlap between tools.

Naming Consistency5/5

A single tool named 'print' is perfectly consistent with itself.

Tool Count2/5

A single tool for a POS printing server feels too minimal; typically one would expect additional utilities like printer listing or status checks.

Completeness2/5

The print tool covers only the core print action via two modes, missing obvious features like printer discovery, job management, or error handling.

Maintenance

ActivityStale
ResponsivenessUnresponsive