Skip to main content
Glama
xuanji86

GunStore-POS Admin MCP

by xuanji86

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
FRAPPE_API_KEYYesFrappe API key generated from user settings
FRAPPE_BASE_URLYesBase URL of the Frappe instance (e.g., https://pos.oldsteelarsenal.com)
FRAPPE_API_SECRETYesFrappe API secret generated from user settings

Instructions

Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.

This server publishes no instructions, or was last inspected before Glama recorded them.

Capabilities

Features and capabilities supported by this server

Protocol revision2025-11-25

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
frappe_list_documentsA

List documents of any doctype.

filters are Frappe-style: a list of [field, operator, value] (e.g. [["is_firearm","=",1],["status","=","Active"]]) or a simple {field: value} dict. limit defaults to 20; pass limit=0 for all rows. Call frappe_describe_doctype first if unsure of field names.

frappe_get_documentA

Fetch one document by name. For a Single/Settings doctype, name == doctype (e.g. doctype='RSR Settings', name='RSR Settings').

frappe_describe_doctypeA

List a doctype's fields (custom fields included): fieldname, label, fieldtype, options, reqd. Fields flagged is_password=true can never be written through this MCP — set those in Desk.

frappe_create_documentB

Create a document. Credential/password fields are stripped automatically. A few fields are refused outright rather than stripped — see frappe_update_document.

frappe_update_documentA

Update fields on a document. Credential/password fields are stripped automatically (set those in Desk). Some fields are refused outright and fail the whole call: on GunBroker Settings the environment switches (sandbox_mode, enabled, base_url_override), the credentials and the money fields — those decide whether a real firearm reaches the real marketplace, so they are a Desk change by a person.

frappe_delete_documentA

Delete a document. Requires confirm=true. For firearms/Items prefer frappe_run_method('ffl_core.api.item_admin.force_delete', ...) which preserves the A&D audit trail.

frappe_submit_documentA

Submit a draft document (docstatus 0 -> 1). Requires confirm=true — submitting can fire side effects (e.g. a FastBound push on FFL Acquisition).

frappe_cancel_documentB

Cancel a submitted document (docstatus 1 -> 2). Requires confirm=true.

frappe_run_methodA

Call any whitelisted server method by dotted path, e.g. 'ffl_integrations.rsr.tasks.sync_catalog_now'. Generic Frappe mutators (frappe.client.set_value/insert/save/delete/bulk_update/...) are refused — use the structured frappe_*_document tools, which enforce the guards. Methods whose name implies a destructive action — or that are on the explicit high-consequence list — require confirm=true.

frappe_run_reportB

Run a Script/Query Report (e.g. 'Firearms In Stock') and return its columns + result rows.

get_settingsA

Read an integration's Settings. which: ffl | fastbound | rsr | payroc | woocommerce | dealer (dealer-portal WooCommerce) | shipstation | gunbroker. Password fields are never returned by Frappe.

update_settingsA

Update an integration's Settings. which: ffl | fastbound | rsr | payroc | woocommerce | dealer (dealer-portal WooCommerce) | shipstation | gunbroker. Credential/password fields are stripped — set those in Desk. On gunbroker the environment, credential and money fields are refused outright (enabled, sandbox_mode, base_url_override, dev_key, sandbox_dev_key, username, password, end_strategy, check_deposit_account, card_checkout_enabled) — the call fails rather than half-applying.

rsr_sync_catalogA

Trigger a full RSR catalog sync. Runs in the background — returns once queued.

rsr_test_connectionA

Probe the RSR FTPS connection + configuration (read-only).

fastbound_test_connectionA

Probe the FastBound API connection (read-only).

woo_test_connectionA

Probe a WooCommerce store's API connection (read-only). site: retail (main store) | dealer (dealer portal).

woo_push_itemA

Push (create or update) the WooCommerce product(s) for an Item. Per-serial firearms push every Active Serial No individually; non-firearm and uniform-price firearms push a single item-level product. For ONE gun use woo_push_serial instead. site: retail | dealer. Consequential — confirm=true.

woo_delist_itemA

Set the WooCommerce product for an Item to Draft + stock 0, hiding it from the shop immediately. site: retail | dealer. confirm=true.

woo_reconcileA

Push the item-level product AND all Active Serial Nos for an Item in one call. Suitable for the initial listing of a per-serial firearm where everything needs to go live at once. site: retail | dealer. confirm=true.

woo_push_serialA

Push (create or update) the WooCommerce product for ONE firearm Serial No — the per-gun listing action (SKU item_code::serial). Prefer this over woo_push_item when only specific guns changed: woo_push_item pushes EVERY Active serial of that item. site: retail | dealer. confirm=true.

woo_delist_serialA

Set ONE Serial No's WooCommerce product to Draft + stock 0, hiding that gun from the shop immediately. site: retail | dealer. confirm=true.

set_serial_titleA

Set the per-gun WooCommerce listing title for one firearm (writes Serial No.item_name). A per-serial firearm's Woo product name is taken from Serial No.item_name, falling back to the shared Item name — so this gives one physical gun its own title instead of the model name shared by every serial. Not yet live: it takes effect on the next push (woo_push_serial / woo_push_item). The field is fetch_if_empty so the value persists once set.

gb_test_connectionA

Probe the GunBroker API connection + credentials (read-only). Reports which environment answered: the "sandbox" key in the reply is true for api.sandbox.gunbroker.com, false for the real marketplace. Read that key before doing anything else — it is how you find out which GunBroker this POS is wired to. It cannot be changed from this server: every write path refuses sandbox_mode, so switching environment is a Desk change made by a person. Needs SYSTEM_ROLES on the POS — the other three gb_ tools need only STOCK_ROLES, so a stock-only API user sees a 403 here alone.

gb_listing_statusA

What this POS and GunBroker each think of ONE gun's listing (read-only). "state" is the POS view — unlisted | push_pending | listed | end_pending | sold | sold_unknown | ended — and "remote" is what GunBroker says right now, or null when there is no listing to ask about. Use this before pushing or ending anything if the two might disagree.

atf_verify_fflA

Live-verify an FFL number via ATF EZ Check and upsert an ATF FFL Record. Creates/updates a record, so requires confirm=true.

firearms_in_stockA

Run the 'Firearms In Stock' report — in-stock firearms by serial, with acquisition source + FastBound link. Optional warehouse / manufacturer filter.

find_itemB

Typeahead search for Items by barcode / item code / name.

item_stockA

Stock on hand per item: {item_code: qty} summed across all warehouses. Accepts a list, a JSON list, or a comma-separated string. Read-only.

available_serialsA

In-stock Serial Nos per firearm item, each with its per-gun sell price: {item_code: [{serial, sell_price, ...}]}. Use for 'which units do we have of this model + at what price'. By default mirrors the POS picker: held / consigned-out / consignment-warehouse guns are EXCLUDED (they're not sellable over the counter). Pass exclude_unavailable=false for the RAW list — inventory audits that must also see consigned/held guns. Read-only.

rsr_catalog_searchA

Search the RSR distributor CATALOG (not local stock) by keyword / RSR stock # / UPC / MFG #. Use find_item for items already in this store. Read-only. Promote a catalog row to a sellable Item with promote_to_item.

boundbook_reconcileA

Reconcile in-stock firearm Serial Nos against the FastBound bound book — find guns FastBound shows as disposed but still Active in our inventory. apply=false (default) is a READ-ONLY dry run that just reports them. apply=true removes them from stock and requires confirm=true. Optional item_ids (FastBound item ids) narrows the scan.

receive_goodsA

Receive stock via the Receive Goods flow: creates + submits a Purchase Receipt; for firearms it also creates one FFL Acquisition per serial and pushes them to FastBound. payload mirrors the Receive Goods page: {supplier, source, warehouse, acquisition_source, items:[{item_code, qty, rate, serials:[...], manufacturer, model_name, caliber, firearm_type, importer, sell_price, service_need}], ...}. Consequential — confirm=true.

add_stockA

Add stock for a NON-serialized item (Material Receipt Stock Entry). Do NOT use for serial-tracked firearms — those go through receive_goods so the FFL flow runs. confirm=true.

set_stockA

Set a NON-serialized item's on-hand qty to an absolute value via Stock Reconciliation (physical count / write-off). reason is recorded in the audit trail. confirm=true.

toggle_service_needB

Set a firearm's 'Service Needed' (gunsmith) flag on its Serial No, opening or closing the gunsmith ToDo accordingly. confirm=true.

push_serial_to_fastboundA

Push a post-acquisition per-unit correction (manufacturer / importer) for one already-booked firearm to FastBound, editing the bound-book item in place (PUT /Items/{id}). No-op if the gun isn't in FastBound yet. confirm=true.

verify_supplier_fflB

Live ATF EZ Check on a Supplier's FFL and update that supplier's verification status/fields. confirm=true (it writes to the Supplier).

reverify_all_fflsC

Re-run ATF EZ Check for EVERY FFL supplier on file (batch re-verification). confirm=true.

promote_to_itemA

Promote an RSR catalog row into a sellable Item (manufacturer / model / caliber / prices / images flow in from the catalog). payload mirrors the promote flow, e.g. {rsr_stock_number, item_code?, item_name?, ...}. confirm=true. Find candidates with rsr_catalog_search.

backfill_from_rsrA

Backfill manufacturer / model / caliber / etc. on existing Items from the RSR catalog (fills only empty fields, never overwrites). item_codes omitted = all RSR-linked items. confirm=true.

pending_ordersA

The Pending Order queue, counter + dealer rows: submitted firearm shipments that still need disposing, payment, or a ShipStation push. Web-shop rows come from pending_web_orders. Consignment fulfillment is NOT here — outbound consignments live in their own queue (see consignment_queue); this list explicitly excludes consignment invoices. Read-only.

pending_web_ordersA

Paid WooCommerce web orders awaiting fulfillment — the source='woo' rows of the Pending Order page. Read-only.

dispose_orderA

Dispose (ship) the firearms on a submitted counter/dealer order: books one FFL transfer disposition per not-yet-disposed serial; each disposition's on_submit issues the stock-out and pushes FastBound. Server blocks it while unpaid or the destination FFL is invalid; idempotent. VERIFY the destination FFL and serials first (the UI makes staff tick exactly that). confirm=true.

dispose_web_orderA

Dispose the firearms on a paid Woo Online Order (web row). No ShipStation push here — the store's own WooCommerce plugin ships web orders. Idempotent per {serial, order}. confirm=true.

record_paymentA

Record a later payment against a submitted, not-fully-paid Sales Invoice — books + submits a Payment Entry and returns the new balance. amount omitted = the full outstanding; mode_of_payment 'Zelle' requires transaction_number. confirm=true.

push_shipmentA

Push a submitted order to ShipStation so staff can buy the label there — the Pending Order 'Ship' action. Synchronous, idempotent, fails closed on an invalid FFL or unpaid order; independent of the Dispose step. confirm=true.

mark_shipped_manuallyA

Clear a DISPOSED order from the Pending Order queue without a ShipStation push (label bought elsewhere / integration off / FFL expired after dispose). Refuses while any firearm is undisposed. confirm=true.

shipstation_test_connectionA

Probe the ShipStation API (GET /v2/carriers; read-only).

start_4473B

Kick off the ATF 4473 for a firearm POS/Sales Invoice: holds the invoice in Draft and opens a FastBound 4473 for the cashier to complete. serial_by_item_row maps invoice ITEM ROW name -> actual serial, e.g. {"a1b2c3d4": "SN123"}. Returns the FastBound URL. confirm=true.

manager_override_4473A

Manager force-complete a stuck firearm POS sale whose 4473 WAS genuinely completed in FastBound but never synced back (edited serial, deleted disposition, FastBound down). Mints the Retail Sale disposition(s) marked manual_override with WHO + WHY — auditable; does NOT push FastBound, so reconcile the bound book separately. reason is required. confirm=true.

start_transfer_4473A

Start a customer-transfer 4473: builds the transfer POS Invoice server-side ($0 line per gun + one Transfer Fee line) and opens the FastBound 4473. Get fee_item and the default fee via frappe_run_method 'ffl_core.firearm.get_transfer_config'. FFL-dealer customers are refused server-side (their 4473 gate doesn't apply). confirm=true.

consignment_queueA

The outbound-consignment "At Dealer" queue — every unfinished Consignment Out (Draft / Shipped) as one card: dealer + shippability, ShipStation state, tracking, line pills, and the action gating the Dispose/Ship buttons read. An INDEPENDENT queue from pending_orders (which excludes consignment invoices). include_closed=true also returns Closed/Cancelled history. Read-only.

consignment_dealersA

Every FFL-dealer Customer with its consignment shippability: FFL number, eZ-Check status, expiry, plus shippable/block_reason (the same gate ship_consignment_out enforces). Use before building a consignment. Read-only.

consignment_serialsA

In-stock (Active) serials pickable for an outbound consignment, annotated with settlement/reference prices (cost = dealer price, msrp = retail) and — for blocked guns — why they can't be picked (blocked rows are returned greyed, not hidden). Filter by item_code and/or a search string. Read-only.

consignment_dealer_ordersA

The post-sale consignment settlement queue: Sold lines whose settlement invoice isn't booked yet OR whose invoice isn't paid off. Failed rows sort first. Retry a failed settlement invoice with retry_consignment_invoice. Read-only.

create_consignment_outA

Build an outbound consignment to an FFL dealer. payload: {dealer, company?, notes?, dispose_now?, lines: [{item_code, serial, cost, msrp}]}. dispose_now=0 (default) saves a Draft (guns held, Woo delisted, dispose later from the queue); dispose_now=1 also disposes + best-effort ShipStation push immediately — if a gate blocks (expired dealer FFL) the build still succeeds as Draft with degraded=1. Find candidates with consignment_dealers / consignment_serials. Consequential — confirm=true.

ship_consignment_outA

Dispose (ship) every Draft line of a Consignment Out: books the FFL transfer disposition per gun, moves stock to the consignment warehouse, pushes FastBound. All lines are validated before any is mutated; re-running ships 0 (idempotent). Server blocks on an invalid dealer FFL. VERIFY the dealer + serials first. confirm=true.

push_consignment_shipmentA

Push a DISPOSED Consignment Out to ShipStation so staff can buy the outbound label — the At Dealer queue's Ship action. Synchronous, idempotent, persists nothing on API failure (safe to retry). Independent of the Dispose step. confirm=true.

mark_consignment_shippedA

Clear a DISPOSED consignment's Ship step without a ShipStation push (label bought elsewhere / integration off / dealer FFL expired after dispose) — the consignment twin of mark_shipped_manually. Optional tracking_number / carrier hand-record the label so the dealer portal shows it. confirm=true.

retry_consignment_invoiceA

Retry the settlement Sales Invoice for a Sold consignment line whose automatic booking failed (error log / total mismatch / dealer FFL expired at submit) — the Dealer Orders queue's Retry Invoice action. line = the Consignment Out Line name (see consignment_dealer_orders). To UNDO a booked settlement, cancel that settlement Sales Invoice instead (frappe_cancel_document) — the cancel hook reopens the parent. confirm=true.

return_consignment_linesA

Take unsold consigned guns BACK from the dealer: books a real FFL re-acquisition per gun (pushed to FastBound by its own hook) and moves stock back to the main (or given) warehouse. lines = Consignment Out Line names. confirm=true.

cancel_consignmentA

Cancel a consignment that should never have happened. With line: cancel ONE shipped line ("the gun never left the store" — undoes the disposition; only reachable pre-invoice). Without line: cancel the whole DRAFT document (never-shipped staging record; books/moves nothing). reason is required and recorded. confirm=true.

update_consignment_pricesA

Edit the per-consignment price snapshot on At Dealer lines — the queue's "Edit prices" dialog (PR #224). prices: {line_name: {"cost": required > 0, "msrp": tri-state}} — omit the "msrp" key to keep the stored MSRP, send "" / null to clear it, anything else must be > 0. Writes ONLY this shipment's line snapshot ("Dealer Price" + MSRP), never Serial No / Item masters; settlement and the dealer portal read the same snapshot, so both follow automatically. Server gates: line must be At Dealer with no booked settlement invoice; the whole batch is validated before anything is written (one bad line rejects all). Line names come from consignment_queue. confirm=true.

cancel_orderA

Cancel a submitted counter/dealer transfer order — the Pending Order page's Cancel Order action. Cascades safely: cancels the invoice (its hooks reverse the dispositions → stock back in → FastBound delete queued), cancels linked Sales Orders, voids the ShipStation order, and books a refund Payment Entry for whatever was actually paid (refund_mode/refund_reference when a refund is due). reason is required and recorded. confirm=true.

upload_attachmentA

Upload a LOCAL file to the POS as a File document, optionally attached to a document (doctype + name) and/or set into its Attach field (fieldname). Returns the File doc incl. file_url. Default is_private=true — product photos that WooCommerce must sideload need is_private=false. For bulk photo+gallery imports prefer the firearm-listing-import script (it resizes images first; oversized originals break the Woo push).

distributor_ordersB

List Distributor Orders (drop-ship / restock purchase orders to RSR). status: Draft | Queued | Placed | Acknowledged | Hold | Partially Shipped | Complete | Cancelled | Error (empty = all). Read-only.

distributor_route_queueA

The human confirmation queue: Draft Distributor Orders awaiting an operator, plus web orders PARKED before routing (unpaid, missing/expired buyer FFL, incomplete address) with the reason and the destination FFL's expiry. This is the list to read before confirming anything. Read-only.

distributor_catalog_searchA

Typeahead the distributor's catalog by keyword / stock # / UPC / MFG #. Reads the locally-synced catalog, not live stock — use distributor_check_availability before acting on a quantity. Read-only.

distributor_quoteA

Per-item economics: cost, MAP, MSRP, suggested sell price (the same pricing chain the storefront listing publishes), last-known catalog qty, restricted states, and the block flags. Pass item_code for a stocked item or sku for a raw catalog row. The quantity is the CACHED catalog figure — its freshness is not asserted here. Read-only, no HTTP to the distributor.

distributor_check_availabilityA

LIVE quantity/price re-confirm straight from the distributor for the given lines ([{sku, qty}, …]). Changes nothing, but unlike distributor_quote it does reach RSR over HTTP — use it to second-check before confirming an order, not to browse.

distributor_precheck_fdsA

Ask the distributor whether the transfer dealer named on this FDS order accepts drop-shipped firearms — the cheapest way to avoid an FDS Hold. Reaches RSR over HTTP; changes nothing.

distributor_fulfillment_optionsA

Everything needed to decide how to fill ONE web order: per line, the distributor candidates (cheapest first), a LOCAL stock comparison row, and a verdict. Read-only — it plans nothing and orders nothing.

THREE-VALUED FIELDS. if not x is WRONG on both of these; null means "not determined yet", never "fine":

  • verdict.fulfillable — true / false / null. Null carries a reason: unknown_destination (the destination state is not captured yet — the NORMAL state while an order sits in Pending Route or before the buyer's FFL is on file) or stale_feed (the only quantity that could cover the line came off a feed past its refresh window).

  • restricted_state — true / false / null, same null meaning.

Treat null as HOLD: report the line as undetermined and quote the reason. Never state that such a line can ship — a restricted item to an unresolved destination is exactly the case this must not wave through.

CANDIDATE FLAGS: not_carried = that distributor has no catalog row for the item (listed rather than dropped, so it is not misread as out-of-stock); blocked = carried but unbuyable (distributor block / vendor approval); stale = quantity from an aged feed. Unbuyable rows sort to the BOTTOM, so the first candidate is the one MOST LIKELY to be actionable — but the row's own verdict and flags decide that, not its position. Ranking is not permission.

MONEY: unit_landed is PER UNIT and goods-only. Freight does not exist until the order is placed, so shipping is null with shipping_known false. Do not present unit_landed as a landed cost, and do not multiply it by quantity and call the result final.

sales_reportA

The POS Sales Report (revenue + profit, all channels), returned UNCHANGED — columns, rows and the report_summary cards. view: "Order" (per-order), "Order Detail" (order → line drill-down) or "Product" (default here — the CPA tax-reporting view: per-line tax from ERPNext's stored item-wise tax details, tax rows classified to Sales Tax / Shipping / Unclassified fail-closed). channel: POS | Web | Manual (empty = all). product_type: "Firearms" | "Non-Firearms" (empty = all) — any OTHER value is REFUSED by the server rather than ignored (F-2: an unrecognised value used to return everything unfiltered, which reads as "no rows of that type"). Profit is net (pre-tax). Read-only.

gl_entriesA

General-ledger rows for a date range, optionally filtered by account / party / voucher_no / voucher_type. Cancelled GL is ALWAYS excluded (is_cancelled=0 — cancel+amend refund reworks drop out automatically). Truncation is explicit: when more rows exist than limit, the result carries truncated:true — never a silent cut, a silently-shortened ledger reconciles to wrong numbers. limit is clamped to 1..5000 (0 or empty falls back to 500 — NOT Frappe's "0 = all" convention); for more rows, paginate by narrowing the date range. Read-only.

financial_statementA

One of the standard financial statements over a date range: statement = "pnl" (Profit and Loss Statement), "balance_sheet" or "trial_balance". P&L/BS run filter_based_on="Date Range" with the given periodicity (Monthly/Quarterly/Half-Yearly/Yearly). Trial Balance needs the range inside ONE fiscal year (ERPNext requires a fiscal_year filter; it is resolved from the dates — a spanning range is refused rather than guessed). company defaults to the default company. Read-only.

tax_liabilityA

Sales-tax liability roll-forward for the period, straight from the GL. TRAP: an invoice's "Total Taxes and Charges" includes shipping and other charges — it is NOT the sales tax; only GL rows on the sales-tax account(s) count, which is all this tool reads.

Accounts are resolved dynamically — the default enabled Sales Taxes and Charges Template's distinct account_heads (the same rule the server's setup/tax.py and Sales Report use; nothing hardcoded) — and echoed back in the result. Rows are is_cancelled=0; cancel+amend restatements land on the amended invoice's posting_date.

Output: opening_balance (before from_date), collected credits split by voucher (Sales Invoice = sales accrual; Journal Entry = adjustments, listed separately, never merged into sales), remitted debits split by voucher (Journal Entry = remittance payments; Sales Invoice = return / amend reversals), any other voucher type fail-closed into its own "other" bucket, and closing_balance. The identity closing == opening + credits − debits is asserted internally to the cent; a classification that drops rows raises instead of returning numbers. Single-state (TX) system — there is deliberately no state parameter. Read-only.

ar_ap_summaryA

Aged Accounts Receivable (kind="ar") or Accounts Payable ("ap") as of a date — the standard ERPNext ageing report (Posting Date basis, 30/60/90/120 buckets). Consignment settlement invoices appear in AR under their dealer. company defaults to the default company. Read-only.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/xuanji86/gunstore-pos-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server