GunStore-POS Admin MCP
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| FRAPPE_API_KEY | Yes | Frappe API key generated from user settings | |
| FRAPPE_BASE_URL | Yes | Base URL of the Frappe instance (e.g., https://pos.oldsteelarsenal.com) | |
| FRAPPE_API_SECRET | Yes | Frappe 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
| Capability | Details |
|---|---|
| tools | {
"listChanged": false
} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
| experimental | {} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| 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.
Treat null as HOLD: report the line as undetermined and quote the CANDIDATE FLAGS: MONEY: |
| 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
|
| 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
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
No resources | |
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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