Skip to main content
Glama

BSN Inventory MCP

Streamable HTTP MCP server for BSN SKU/material identification and inventory availability.

Setup

npm install
cp .env.example .env

Edit .env before running. Keep secrets in .env or the parent shell, not in source files.

Required to start: set at least one inbound MCP bearer key:

BSN_MCP_API_KEY=
BSN_MCP_API_KEY_1=
BSN_MCP_API_KEY_2=

Clients must send:

Authorization: Bearer <local_mcp_api_key>

When the server is hosted behind Amazon Bedrock AgentCore Runtime with AWS_IAM, SigV4 uses the Authorization header. In that case, configure a custom key header and allowlist that header in the AgentCore runtime:

BSN_MCP_API_KEY_HEADER=X-Api-Key

BSN_MCP_API_KEY is kept as a legacy slot-1 alias. For key rotation, prefer numbered slots. The server accepts any configured value from BSN_MCP_API_KEY, BSN_MCP_API_KEY_1, or BSN_MCP_API_KEY_2.

Inventory lookup defaults to PROD. These values are required only when calling getInventoryAvailability:

BSN_INVENTORY_API_ENV=prod
BSN_API_BASE_URL_QA=https://api-qa.bsnsports.com:443
BSN_API_BASE_URL_PROD=https://api.bsnsports.com:443
BSN_INVENTORY_API_KEY_QA=
BSN_INVENTORY_API_KEY_PROD=
BSN_INVENTORY_API_KEY=
BSN_INVENTORY_RESPONSE_PAYLOAD_FORMAT=pretty

BSN_INVENTORY_RESPONSE_PAYLOAD_FORMAT supports pretty and json. Use pretty by default because the server normalizes that payload into a complete color/size inventory matrix.

SKU/material identification uses local brand SKU catalogs in resources/skus/*.jsonl first. OpenAI file search is the fallback path when the local catalog has weak, ambiguous, or unavailable results. Set at least one OpenAI key before calling getVectorStoreFiles or before relying on vector fallback from identifySkuMaterial:

OPENAI_API_KEY=
OPENAI_API_KEY_1=
OPENAI_API_KEY_2=
OPENAI_SKU_VECTOR_STORE_IDS=
OPENAI_SKU_BRAND_VECTOR_STORE_IDS=
OPENAI_SKU_SEARCH_MODEL=gpt-5.5
OPENAI_SKU_SEARCH_MAX_OUTPUT_TOKENS=900

OPENAI_SKU_SEARCH_MODEL is optional and defaults to gpt-5.5. Set it in .env to use a different model.

OPENAI_API_KEY is kept as a legacy slot-1 alias. For rotation, prefer OPENAI_API_KEY_1 and OPENAI_API_KEY_2. The server tries configured OpenAI keys in order and only falls back to the next configured key when OpenAI rejects the current key for authentication or authorization.

OPENAI_SKU_VECTOR_STORE_IDS is optional. When set, it scopes broad fallback SKU search and getVectorStoreFiles to those comma-separated vector stores. When unset, vector fallback from identifySkuMaterial discovers accessible completed OpenAI vector stores at runtime, and getVectorStoreFiles lists accessible stores from OpenAI. identifySkuMaterial also accepts per-call vectorStoreIds when a client needs to search a specific store such as SanMar.

OPENAI_SKU_BRAND_VECTOR_STORE_IDS is optional. When set, vector fallback from identifySkuMaterial routes a provided brand to that brand's vector store before broad env or discovery search. Use comma-separated brand=vectorStoreId entries, such as nike=vs_...,adidas=vs_...; use | inside one entry if a brand needs multiple stores. Fallback vector-store precedence is explicit vectorStoreIds, then brand route, then OPENAI_SKU_VECTOR_STORE_IDS, then OpenAI discovery.

The local SanMar JSONL catalog is searched as the distributor/multi-brand fallback. Include the SanMar sanmar_skus vector store as the OpenAI fallback for SanMar-sourced and SM* catalog families before using BSN Shop or web search as a last resort; pass its current vector store ID through identifySkuMaterial.vectorStoreIds when it was not already searched.

Related MCP server: Product MCP Server

Key Rotation

Use numbered key slots to rotate without interrupting users:

  1. Put the current key in BSN_MCP_API_KEY_1 or OPENAI_API_KEY_1.

  2. Put the new key in BSN_MCP_API_KEY_2 or OPENAI_API_KEY_2.

  3. Update clients or the OpenAI project/provider side to use the new key.

  4. Remove the old key after traffic has moved.

  5. Optionally move the new key back to slot 1 before the next rotation.

The unnumbered BSN_MCP_API_KEY and OPENAI_API_KEY variables continue to work for existing installs. Avoid keeping different values in both legacy and numbered slot 1 longer than needed; leave only the active numbered slots after rotation.

Run

npm run dev

Or run compiled output:

npm run build
npm run start

Default MCP endpoint:

http://127.0.0.1:3100/mcp

For client-specific connection examples and hosted-client notes, see MCP_CLIENT_CONNECTIONS.md.

Source Layout

  • src/main.ts is the process entrypoint and owns startup validation plus listen().

  • src/http/app.ts owns the Streamable HTTP endpoint, bearer auth boundary, and per-request transport lifecycle.

  • src/mcp/server.ts creates the McpServer and registers resources, prompts, and config metadata.

  • src/tools/registerInventoryTools.ts registers the public MCP tools.

  • src/inventory/, src/openai/, src/resources/, and src/prompts/ contain the domain-specific helpers used by those tools.

  • src/index.ts is import-safe and only re-exports modules for tests or local consumers.

Architecture

flowchart TB
    Client["MCP Client"] -->|"POST /mcp<br/>Authorization: Bearer key"| App

    subgraph Http["HTTP/Auth Boundary"]
        App["Express MCP App<br/>src/http/app.ts"]
        Auth["Bearer Auth<br/>src/auth/mcpAuth.ts"]
        Reject["Unauthorized response<br/>no transport allocated"]
        App --> Auth
        Auth -->|"authorized"| Transport["Stateless Streamable HTTP Transport<br/>per request"]
        Auth -.->|"missing/invalid bearer key"| Reject
    end

    subgraph Runtime["Per-request MCP Runtime"]
        Server["McpServer<br/>src/mcp/server.ts"]
        Tools["Public Tool Registration<br/>src/tools/registerInventoryTools.ts"]
        Resources["Context Resources<br/>resources/ via BSN_RESOURCES_DIR"]
        Prompts["Local Prompts<br/>prompts/"]
        ApiConfig["api-config Resource<br/>runtime metadata"]
        Server --> Tools
        Server --> Resources
        Server --> Prompts
        Server --> ApiConfig
    end

    Transport --> Server

    Config["Environment Config<br/>src/config/env.ts"] --> Auth
    Config --> Resources
    Config --> ApiConfig
    Tools --> ReturnShape["MCP Tool Return<br/>concise text + structuredContent"]

Tool Workflow

flowchart TB
    Need["User needs SKU/material or inventory"] --> Known{"Exact material ID known?"}
    Known -->|"yes"| InventoryTool["getInventoryAvailability"]
    Known -->|"no"| IdentifyTool["identifySkuMaterial"]

    IdentifyTool --> LocalSku["Local resources/skus JSONL lookup<br/>brand file first, SanMar fallback"]
    LocalSku --> LocalCandidate{"Confident local candidate?"}
    LocalCandidate -->|"yes"| Candidate
    LocalCandidate -->|"no"| SearchScope["Resolve fallback vector scope<br/>explicit vectorStoreIds, brand route,<br/>OPENAI_SKU_VECTOR_STORE_IDS, or discovery"]
    SanMar["SanMar sanmar_skus vector store<br/>distributor/multi-brand fallback where available"] -.-> SearchScope
    SearchScope --> Responses["OpenAI Responses API<br/>file_search"]
    Responses --> Candidate{"Usable SKU/material candidate?"}

    Candidate -->|"yes"| InventoryTool
    Candidate -->|"no"| LastResort["searchBsnShopLastResort<br/>returns host-agent instructions only"]
    LastResort -.-> HostSearch["Host agent searches BSN Shop<br/>outside this MCP server"]
    HostSearch --> ExactFound{"Exact material ID found?"}
    ExactFound -->|"yes"| InventoryTool
    ExactFound -->|"no"| AskUser["Ask user for SKU, material ID,<br/>product link, or clearer details"]

    InventoryTool --> BsnApi["BSN Inventory API<br/>/v1/private/inventory-inquiry/{material_id}"]
    BsnApi --> Normalize["Inventory Normalization<br/>src/inventory/normalize.ts"]
    Normalize --> InventoryReturn["Inventory result<br/>structuredContent source of truth"]

    VectorFiles["getVectorStoreFiles"] --> StoreScope["Explicit vectorStoreIds,<br/>OPENAI_SKU_VECTOR_STORE_IDS,<br/>or OpenAI discovery"]
    StoreScope --> StoresApi["OpenAI Vector Stores API<br/>metadata only"]
    StoresApi --> StoreReturn["Vector store/file metadata<br/>no file contents"]

Dashed edges describe guidance or host-agent activity outside this MCP server process.

Tools

  • identifySkuMaterial

  • getVectorStoreFiles

  • searchBsnShopLastResort

  • getInventoryAvailability

Use identifySkuMaterial when a user provides a natural-language product description, partial SKU, or uncertain style/color/size wording. It searches local brand JSONL catalogs in resources/skus first and returns immediately when the local candidate is confident. If local candidates are weak, ambiguous, or unavailable, it searches explicit vectorStoreIds, brand-routed vector stores, configured OpenAI vector stores, or discovered OpenAI vector stores and returns closest SKU/material candidates with evidence. It does not check live inventory.

Use getVectorStoreFiles to inspect accessible OpenAI vector stores and their attached vector store file metadata. It does not fetch file contents. It uses explicit vectorStoreIds input first, then OPENAI_SKU_VECTOR_STORE_IDS, then OpenAI vector store discovery.

Use searchBsnShopLastResort only when local SKU lookup and explicit, configured, or discovered vector-store search, including the SanMar distributor/multi-brand fallback where relevant, return no usable SKU/material candidates. It does not scrape or browse from the MCP server. It returns instructions for the host agent to search https://www.bsnsports.com/shop/, preserve exact product identifiers from matching products, resolve styles/SKUs to a material ID when needed, and then call getInventoryAvailability only after an exact material ID is found.

Use getInventoryAvailability only after the exact material ID is known. Pass optional color and size when the user asks for a specific variant quantity. It calls:

/v1/private/inventory-inquiry/{material_id}

The text response contains a compact inventory summary and, when color, size, or a full material ID can identify a variant, the matched inventory cell. Matched cells include the split stock levels and combined total when available, for example Matched availability: available 1778, IP 1528, DS 250, total 1778. Agents should report IP and DS separately in addition to the combined total for inventory questions. If the upstream pretty payload only exposes segment-coded IP and DS rows, the normalizer maps them to ip and ds; when explicit available and total fields are absent and both values are numeric, it computes available and total as IP + DS. If the requested text does not match the inventory matrix labels, the matcher also tries color and size codes embedded in full material IDs such as NKCJ1611657LRG. structuredContent.data is the source of truth for normalized product, size, color, inventory-cell fields, and matchedAvailability.

Resources

Inventory-only context resources are exposed under:

context://bsn-inventory-mcp/resources/<relative-path>

Use resources/instructions.md as the entry resource and resources/tool-map.md for the tool workflow. BSN_RESOURCES_DIR controls local context resources and the server-side resources/skus/*.jsonl SKU catalogs. Those SKU catalogs are searched before OpenAI vector stores; large JSONL files are intended for server-side lookup, not whole-file model context.

Secret-free runtime metadata is exposed under:

config://bsn-inventory-mcp

The config resource includes registered operations, prompt metadata, environment variable names, selected inventory environment, logging settings, local SKU catalog metadata, brand vector-store routing metadata, and vector-store discovery settings. It does not include credential values.

Prompts

Only inventory/SKU prompt templates belong in prompts/. check-inventory is the default prompt for inventory lookup.

Checks

npm run check

The combined check runs:

npm run typecheck
npm run typecheck:test
npm test
npm run build

GitHub Actions runs npm ci and npm run check on pushes to main and pull requests.

F
license - not found
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

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/aapatil67/inventory-mcp'

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