# BLUEPRINT: Stack Slip [MCP] # Version: 3.1.3 # URL: https://stackslip.app # Location: https://stackslip.app/.well-known/blueprint.txt # Fallback: https://stackslip.app/blueprint.txt # Updated: 2026-05-28 ## CAPABILITIES ## CAPABILITY: login-email description: Sign in with Firebase email and password. Workspace home is /workspace (not /dashboard or /app). Optional /login?next=/path redirects after sign-in; otherwise VERIFY /workspace. input: - name: user-email type: string required: true description: Account email. - name: user-password type: string required: true description: Account password; never log or store. output: - type: redirect description: Session established. auth-required: false scope: form-submit ### UI steps: 1. NAVIGATE /login 2. INPUT [data-agent-id="signin-email"] <> 3. INPUT [data-agent-id="signin-password"] <> 4. CLICK [data-agent-id="signin-submit"] 5. VERIFY url contains "/workspace" ## CAPABILITY: login-google description: Sign in with Google OAuth. Workspace home is /workspace (not /dashboard or /app). input: [] output: - type: redirect description: Session established after OAuth completes. auth-required: false scope: form-submit ### UI steps: 1. NAVIGATE /login 2. CLICK [data-agent-id="signin-google"] 3. COMPLETE User completes Google OAuth in the browser popup 4. VERIFY url contains "/workspace" ## CAPABILITY: create-slip description: Create a packing slip with line items, receiver/client details, optional dock photos, and review — saved to the signed-in workspace (team workers write under the owner uid when applicable). Slips persist in Firestore; images upload via POST https://stackslip.app/routes/uploads/image (Firebase ID token). Run login first if no session. Wizard steps on /create-slip — Select Items, Shipping Info, Photo, Review — then footer control create-slip-wizard-finish (Generate Slip). Repeat product steps 4-6 per line before step 7. Omit steps 9-10 when selecting an existing client. Omit step 12 when no photos (footer allows Skip). Optional UI not covered — barcode scan, custom line items, invoice import, carrier library fields. input: - name: product-id type: string required: true description: Product document id from Products (repeat add/qty steps for multiple lines). - name: product-search-term type: string required: false description: Filter text for the product search field. - name: quantity type: number required: true description: Quantity for each product line (use 1 when not specified). - name: client-document-id-or-new type: string required: true description: Existing client Firestore id, or literal `new` for a new receiver. - name: receiver-name type: string required: false description: Required when client-document-id-or-new is `new`. - name: receiver-email type: string required: false description: Optional receiver email on the slip. - name: photo-files type: file required: false description: Optional shipment photos for the Photo step. output: - type: redirect description: Navigates to /slip-details?id={slipId} after save. auth-required: true scope: form-submit permissions: - data: write - files: write ### MCP tool: create_slip params: client_name: string — matched to existing client by name, or auto-created if not found items: list of {description: string, quantity: int ≥1, sku: string (optional)} carrier_name: string (optional) — shipping carrier label returns: slip_id: string — Firestore document id share_url: string — public viewer URL for the slip slipNumber: string — auto-incremented slip number (PS-001, PS-002…) ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /create-slip 3. WAIT [data-agent-id="create-slip-product-search"] (max: 30s) 4. INPUT [data-agent-id="create-slip-product-search"] <> 5. CLICK [data-agent-id="create-slip-add-product-<>"] 6. INPUT [data-agent-id="create-slip-product-qty-<>"] <> 7. CLICK [data-agent-id="create-slip-wizard-continue"] 8. SELECT [data-agent-id="create-slip-client-select"] "<>" 9. INPUT [data-agent-id="create-slip-new-client-name"] <> 10. INPUT [data-agent-id="create-slip-customer-email"] <> 11. CLICK [data-agent-id="create-slip-wizard-continue"] 12. UPLOAD [data-agent-id="create-slip-photo-gallery-input"] <> 13. CLICK [data-agent-id="create-slip-wizard-continue"] 14. CLICK [data-agent-id="create-slip-wizard-finish"] 15. WAIT [data-agent-id="slip-details-share"] (max: 45s) 16. VERIFY url contains "/slip-details" ## CAPABILITY: view-history description: Open the packing slip history list for the signed-in workspace (Firestore users/{uid}/packing_slips). Free tier slips have 1-year retention; archived slips approaching purge show a warning linking to /pricing#slip-recovery. input: - name: limit type: number required: false description: For API list only — max slips returned (default 10). output: - type: confirmation description: History list visible, slip details when opened, or JSON list when using API. auth-required: true scope: read-only permissions: - data: read ### MCP tool: list_slips params: limit: int (1–100, default 10) status_filter: "active" (default) | "archived" | "all" | "created" | "delivered" returns: data: [{id, customerName, date, itemsCount, status, archived, slipNumber, createdAt}] ### API method: GET endpoint: https://stackslip.app/routes/slips headers: X-Api-Key: <> query: limit: <> response: data: array ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /history 3. WAIT [data-agent-id="history-page"] (max: 30s) 4. VERIFY selector_exists [data-agent-id="history-page"] ## CAPABILITY: open-slip description: Open a saved slip from History into slip details. input: - name: slip-id type: string required: true description: Packing slip document id. output: - type: redirect description: Slip details page for the given id. auth-required: true scope: read-only permissions: - data: read ### MCP tool: get_slip params: slip_id: string — packing slip document id returns: full slip — {slipNumber, customer, shipping, sender, items [{id, name, description, quantity, sku, price, weight, imageUrl}], photoUrls, status, archived, footerMessage, options} ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /history 3. WAIT [data-agent-id="history-page"] (max: 30s) 4. CLICK [data-agent-id="history-slip-card-<>"] 5. VERIFY url contains "/slip-details" ## CAPABILITY: share-slip description: Publish or update a public share link for a saved slip (POST https://stackslip.app/routes/publish). Canonical viewer URL /shared-slip?id={slipId} (aliases /shared, /sharedslip). Modal shape A — expiration select and create-link. Modal shape B — public URL already shown; skip steps 4-5, run 6-8 only. Detect shape after step 3. input: - name: slip-id type: string required: true description: Packing slip document id. - name: expiration-days type: string required: false description: Shape A only — option value 7, 30, 90, or never; default 30 when omitted. output: - type: confirmation description: Share URL visible in modal; public_slips updated when publish ran. auth-required: true scope: form-submit permissions: - data: write ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /slip-details?id=<> 3. CLICK [data-agent-id="slip-details-share"] 4. SELECT [data-agent-id="share-slip-expiration"] "<>" 5. CLICK [data-agent-id="share-slip-create-link"] 6. WAIT [data-agent-id="share-slip-public-url"] (max: 60s) 7. CLICK [data-agent-id="share-slip-copy-link"] 8. VERIFY selector_exists [data-agent-id="share-slip-public-url"] ## CAPABILITY: download-pdf description: Open the browser print dialog for a slip; user chooses Save as PDF in the native print UI. No DOM assertion confirms a saved file after print. input: - name: slip-id type: string required: true description: Packing slip document id. output: - type: file description: PDF only if the user completes Save as PDF in the system dialog. auth-required: true scope: file-download permissions: - data: read ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /slip-details?id=<> 3. VERIFY url contains "/slip-details" 4. WAIT [data-agent-id="slip-details-print"] (max: 30s) 5. CLICK [data-agent-id="slip-details-print"] ## CAPABILITY: manage-clients description: Add a client via the Clients page modal (Firestore users/{uid}/clients). Edit, delete, and CSV import/export are not covered by these steps. input: - name: client-name type: string required: true description: Client or company name. - name: client-email type: string required: false description: Contact email. output: - type: confirmation description: Client saved; clients-page remains visible. auth-required: true scope: form-submit permissions: - data: write - contacts: write ### MCP tool: list_clients returns: data: [{id, name, email, phone, address, company}] — sorted by name note: create_slip auto-creates a client by name if no match exists; call list_clients first to avoid duplicates ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /clients 3. WAIT [data-agent-id="clients-page"] (max: 30s) 4. CLICK [data-agent-id="clients-add-client"] 5. INPUT [data-agent-id="clients-form-name"] <> 6. INPUT [data-agent-id="clients-form-email"] <> 7. CLICK [data-agent-id="clients-form-save"] 8. VERIFY selector_exists [data-agent-id="clients-page"] ## CAPABILITY: manage-products description: Add a product via ProductAddModal on /products. Edit, delete, and CSV import/export are not covered by these steps. input: - name: product-name type: string required: true description: Product display name. - name: sku type: string required: false description: SKU or barcode. - name: price type: number required: false description: Unit price when applicable. - name: weight type: string required: false description: Weight string when applicable. - name: description type: string required: false description: Product description. output: - type: confirmation description: Product saved in inventory; products-page remains visible. auth-required: true scope: form-submit permissions: - data: write ### MCP tool: list_products returns: data: [{id, name, sku, description, price, weight, imageUrl}] — sorted by name ### API method: POST endpoint: https://stackslip.app/routes/products headers: X-Api-Key: <> body: name: <> sku: <> price: <> weight: <> description: <> response: id: string status: string ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /products 3. WAIT [data-agent-id="products-page"] (max: 30s) 4. CLICK [data-agent-id="products-add-product"] 5. INPUT [data-agent-id="products-form-name"] <> 6. INPUT [data-agent-id="products-form-sku"] <> 7. CLICK [data-agent-id="products-form-save"] 8. VERIFY selector_exists [data-agent-id="products-page"] ## CAPABILITY: manage-webhooks description: Register, list, and delete event webhooks for the workspace. Webhooks fire on slip_created events. input: - name: url type: string required: false description: HTTPS endpoint to receive webhook POST payloads. - name: name type: string required: false description: Human label for the webhook. - name: events type: string required: false description: Comma-separated list — slip_created. - name: integration-id type: string required: false description: Integration document id — required for delete. output: - type: confirmation description: Webhook registered, listed, or deleted. auth-required: true scope: account-modify permissions: - account: write ### MCP tool: register_webhook params: url: string — HTTPS endpoint to receive POST payloads name: string — human label for this webhook events: list — slip_created returns: {integration_id, name, url, events} tool: list_webhooks returns: {data: [{id, name, url, events, isActive, createdAt}]} tool: delete_webhook params: integration_id: string — from list_webhooks returns: {deleted: true} ## CAPABILITY: upload-dock-photo description: Two-step MCP flow to attach a dock photo to an existing slip. Step 1 — call get_photo_upload_url to receive a signed GCS PUT URL (expires 900s). Step 2 — PUT the image bytes to that URL with the matching Content-Type header, then call confirm_photo with the returned storage_path to attach the photo to the slip's chain of custody. Supported types: image/jpeg, image/png, image/webp. input: - name: slip-id type: string required: true description: Packing slip document id to attach the photo to. - name: content-type type: string required: false description: MIME type of the image — default image/jpeg. - name: storage-path type: string required: false description: Returned by get_photo_upload_url — passed to confirm_photo after the PUT succeeds. - name: uploaded-by type: string required: false description: Label identifying who uploaded the photo — default "agent". output: - type: confirmation description: photo_url and slip_id returned after confirm_photo. auth-required: true scope: form-submit permissions: - data: write - files: write ### MCP step 1 — get_photo_upload_url params: slip_id: string content_type: "image/jpeg" (default) | "image/png" | "image/webp" returns: {upload_url, storage_path, expires_in_seconds: 900} step 2 — PUT image bytes directly to upload_url with matching Content-Type header (outside MCP) step 3 — confirm_photo params: slip_id: string storage_path: string — returned by get_photo_upload_url uploaded_by: string (default "agent") returns: {photo_url, slip_id} ## CAPABILITY: subscribe-pro description: Upgrade to Pro via Stripe Checkout from /pricing or Settings → Plan. Agents must not automate payment — human completes Stripe. input: [] output: - type: redirect description: User returns to the app after Stripe Checkout when payment succeeds. auth-required: true scope: financial-transaction permissions: - billing: write ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /pricing 3. COMPLETE User selects Pro and completes Stripe Checkout in the browser — agent cannot proceed past this step ## CAPABILITY: purchase-slip-recovery description: Purchase one-time slip recovery via Stripe Checkout at /pricing#slip-recovery. Free tier slips are retained 1 year; recovery restores archived shipment proof for disputes or audits. Price escalates with recovery_count — recovery_1 $49.99, recovery_2 $99.99, recovery_3 $169.99, recovery_4 $249.99 (includes 1 year Pro). Agents must not automate payment — human completes Stripe. input: [] output: - type: redirect description: User returns to /pricing?recovery=success after payment; 4th recovery grants 1 year Pro. auth-required: true scope: financial-transaction permissions: - billing: write - data: read ### UI steps: 1. ASSERT-AUTH 2. NAVIGATE /pricing#slip-recovery 3. COMPLETE User clicks Purchase Slip Recovery and completes Stripe Checkout in the browser — agent cannot proceed past this step ## IDENTITY name: Stack Slip description: Mobile-first PWA for origin shippers — timestamped dock photos on every packing slip, proof before the truck moves for LTL and B2B disputes; no driver app or receiver action required. category: ecommerce contact: https://stackslip.app/faq ## SUMMARY tagline: Timestamped dock photo proof on packing slips — established at your dock before the truck moves. audience: Small manufacturers, B2B shippers, and warehouse teams handing freight to third-party LTL carriers — not fleet operators or last-mile delivery apps. capabilities: - login-email: Sign in with email and password - login-google: Sign in with Google OAuth - create-slip: Build a slip with items, client, photos, and review at the dock - view-history: List past slips in the workspace - open-slip: Open one slip from History by id - share-slip: Publish a public confirmation link for a slip - download-pdf: Print or save a slip as PDF via the browser - manage-clients: Add a client to the workspace library - manage-products: Add a product via UI or REST API - manage-webhooks: Register and manage event webhooks via MCP - upload-dock-photo: Attach dock photos to slips via signed upload URL - subscribe-pro: Upgrade billing through Stripe (human-only payment step) - purchase-slip-recovery: One-time payment to recover archived slips (human-only payment step) ## AUTH provider: firebase methods: email-password, oauth-google, api-key ## MCP protocol: MCP 2025-03-26 (streamable HTTP, stateless) server: stack-slip preferred-transport: streamable_http tested: 2026-05-27 — all 10 tools verified passing (StackMCP) tools: list_slips, get_slip, create_slip, list_clients, list_products, register_webhook, list_webhooks, delete_webhook, get_photo_upload_url, confirm_photo ### TRANSPORT (streamable_http) url: https://stackslip.app/mcp auth: bearer ${STACK_SLIP_API_KEY} ### REQUIRED-SECRETS - STACK_SLIP_API_KEY: description: Stack Slip API key for MCP and API access obtain-at: https://stackslip.app/settings (API Keys) format: stackslip_live_* install: Add to your MCP client config: { "mcpServers": { "stack-slip": { "type": "streamable-http", "url": "https://stackslip.app/mcp", "headers": { "Authorization": "Bearer ${STACK_SLIP_API_KEY}" } } } } note: Publicly readable before connect — read capability ### MCP blocks here, then call tools/call directly; tools/list is optional. Preferred for all programmatic workspace access without UI navigation or REST calls. ## ACCESS preferred: mcp fallback: api last-resort: ui ## TIMING # Observed ranges — agents use the max value in WAIT steps slip-save-and-redirect: 3–15s — use max: 45s photo-upload-per-file: 2–10s — use max: 30s share-link-publish: 5–30s — use max: 60s firebase-auth-redirect: 2–8s — use max: 15s