Skip to main content

FlowPOS MCP — AI Client Integration Guide (V1 · API Key)

Connect AI assistants to FlowPOS using a long-lived API key. V1 is the recommended path for internal developer tooling, platform operators, CI/CD pipelines, and quick exploration.

See also: V2 OAuth Token guide for merchant-facing assistants, multi-business switching, and intent tools.


What V1 gives you​

  • All domain tools: get_products, get_inventory, list_orders, get_sales_report, get_top_products, get_sales_by_location, PSA tools, and more
  • Platform operator tools: list_tenants, set_active_tenant
  • Sessions are in-memory — no Redis required
  • Key never expires unless you set expires_at in the DB

What V1 does NOT give you​

  • set_active_business (multi-business switching) — V2 only
  • Intent tools (summarize_day, summarize_period, get_inventory_health, get_client_health) — require pos:intents scope; add it manually to your key if needed
  • Automatic token refresh — keys are long-lived; rotate manually

Get your API key​

UI shortcut: If you have access to the FlowPOS PWA, go to Settings → AI Assistant → V1 API Key Generator (/settings/mcp/v1) to create a key through the UI — no curl required.

Use POST /mcp/keys with a Firebase Bearer token. The raw key is returned once — store it immediately.

curl -s -X POST https://api.flowandgrow.tech/mcp/keys \
-H "Authorization: Bearer <firebase-id-token>" \
-H "Content-Type: application/json" \
-d '{
"businessId": "<business-uuid>",
"role": "tenant_developer",
"scopes": ["pos:read", "reports:read"],
"label": "My Dev Key"
}'

Response:

{
"rawKey": "fp_mcp_a1b2c3d4e5f6...",
"key": { "id": "...", "role": "tenant_developer", "scopes": [...], "isActive": true }
}

The server stores only the SHA-256 hash — the raw key cannot be recovered after this response. Store it in a password manager or secret vault.

Use it as a Bearer token on every MCP request:

Authorization: Bearer fp_mcp_a1b2c3d4e5f6...

Environments​

Replace the MCP URL in any config block below to target a different environment.

EnvironmentMCP URL
Localhttp://localhost:4000/mcp
Staginghttps://api.staging.flowandgrow.tech/mcp
Productionhttps://api.flowandgrow.tech/mcp

For local development, the backend must be running: pnpm --filter backend run start:dev


Claude​

Claude has full native MCP support. Sessions, tool discovery, and multi-turn tool use all work out of the box.

Claude Desktop (Mac / Windows)​

Config file location:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"flowpos": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://api.flowandgrow.tech/mcp",
"--header",
"Authorization: Bearer fp_mcp_a1b2c3d4e5f6..."
]
}
}
}

mcp-remote bridges the HTTP/SSE transport to the stdio format Claude Desktop expects. It is installed automatically by npx — no pre-install needed.

Save the file and restart Claude Desktop. The FlowPOS tools appear in the tool picker (hammer icon). Test with:

"List my products using FlowPOS"

Local development: Replace the URL with http://localhost:4000/mcp while running the backend locally.


Claude Code (CLI)​

# Add globally (available in all projects)
claude mcp add flowpos \
--transport http \
--url https://api.flowandgrow.tech/mcp \
--header "Authorization: Bearer fp_mcp_a1b2c3d4e5f6..."

# Add at project scope only (writes to .mcp.json)
claude mcp add flowpos \
--transport http \
--url https://api.flowandgrow.tech/mcp \
--header "Authorization: Bearer fp_mcp_a1b2c3d4e5f6..." \
--scope project

Verify and use:

claude mcp list
claude "What are my top 5 products this month?"

Remove:

claude mcp remove flowpos

Claude Code (.mcp.json — project scope)​

Alternatively, edit .mcp.json at the root of your project directly. This is equivalent to running claude mcp add --scope project and is useful when you already have other MCP servers configured in that file.

{
"mcpServers": {
"flowpos": {
"type": "http",
"url": "https://api.flowandgrow.tech/mcp",
"headers": {
"Authorization": "Bearer fp_mcp_a1b2c3d4e5f6..."
}
}
}
}

For local development, use http://localhost:4000/mcp instead.

After saving, reload the MCP servers without restarting Claude Code by running Claude Code: Reload MCP Servers from the Command Palette (Cmd+Shift+P / Ctrl+Shift+P). FlowPOS tools will be available natively in the next conversation — no manual curl sessions required.

Add .mcp.json to .gitignore to keep real keys out of git. Commit a .mcp.json.example with a placeholder for teammates.


Claude Code (VS Code Extension)​

The extension shares its MCP config with the CLI. Any server added via claude mcp add or defined in .mcp.json is immediately available in the extension — no extra steps.

Open the Claude Code side panel, start a conversation, and type naturally. FlowPOS tools (get_products, get_sales_report, etc.) are available automatically.


Claude.ai (web)​

Claude.ai supports custom MCP servers via Settings → Integrations.

  1. Open claude.ai and go to Settings → Integrations
  2. Click Add MCP server
  3. Enter the FlowPOS MCP URL: https://api.flowandgrow.tech/mcp
  4. Add a custom header: Authorization: Bearer fp_mcp_a1b2c3d4e5f6...
  5. Save and start a new conversation — FlowPOS tools will appear in the tool picker

Note: The Integrations panel is available on Pro and Team plans. If you do not see it, use Claude Desktop or Claude Code instead.


Cursor​

Cursor supports MCP through a per-project .cursor/mcp.json file. There is no global MCP config in Cursor — each project gets its own.

Step 1 — Create the config file​

mkdir -p .cursor && touch .cursor/mcp.json

Step 2 — Add the FlowPOS server​

{
"mcpServers": {
"flowpos": {
"url": "https://api.flowandgrow.tech/mcp",
"headers": {
"Authorization": "Bearer fp_mcp_a1b2c3d4e5f6..."
}
}
}
}

For local development, use http://localhost:4000/mcp instead.

Add .cursor/mcp.json to .gitignore to keep real keys out of git. Commit a .cursor/mcp.json.example with a placeholder for teammates.

Step 3 — Reload Cursor​

Open the Command Palette (Cmd+Shift+P / Ctrl+Shift+P) and run Cursor: Reload Window, or quit and reopen Cursor.

Step 4 — Verify​

  1. Open the Cursor chat panel (Cmd+L / Ctrl+L)
  2. Click the Tools icon near the input — flowpos should appear with its tools listed
  3. Test with: "Using FlowPOS, list the first 10 products"

Token refresh: V1 keys are long-lived. Update the Authorization header in .cursor/mcp.json and reload Cursor when you rotate a key.


ChatGPT​

The ChatGPT chat interface does not support MCP. Use the OpenAI API.

Option A — OpenAI Agents SDK (Python)​

pip install openai-agents
import asyncio
from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHTTP

async def main():
async with MCPServerStreamableHTTP(
url="https://api.flowandgrow.tech/mcp",
headers={"Authorization": "Bearer fp_mcp_a1b2c3d4e5f6..."},
) as flowpos_server:
agent = Agent(
name="FlowPOS Assistant",
instructions=(
"You are a POS assistant. Use the FlowPOS tools to answer "
"questions about products, inventory, orders, and sales."
),
mcp_servers=[flowpos_server],
)
result = await Runner.run(agent, "What are my top 5 products this month?")
print(result.final_output)

asyncio.run(main())

Option B — OpenAI Responses API (direct HTTP)​

from openai import OpenAI

client = OpenAI() # uses OPENAI_API_KEY env var

response = client.responses.create(
model="gpt-4o",
tools=[{
"type": "mcp",
"server_label": "flowpos",
"server_url": "https://api.flowandgrow.tech/mcp",
"headers": {
"Authorization": "Bearer fp_mcp_a1b2c3d4e5f6..."
},
# Optionally restrict which tools the model can call:
# "allowed_tools": ["get_products", "get_sales_report"]
}],
input="What are my top-selling products this week?",
)

print(response.output_text)

Requires gpt-4o or gpt-4o-mini. The chat.completions endpoint does not support MCP tool resources.


Gemini​

Gemini has no native MCP support. Use a bridge adapter.

pip install langchain-mcp-adapters langchain-google-genai langgraph
import asyncio
from langchain_mcp_adapters.client import MultiServerMCPClient
from langchain_google_genai import ChatGoogleGenerativeAI
from langgraph.prebuilt import create_react_agent

async def main():
async with MultiServerMCPClient(
{
"flowpos": {
"url": "https://api.flowandgrow.tech/mcp",
"transport": "streamable_http",
"headers": {
"Authorization": "Bearer fp_mcp_a1b2c3d4e5f6..."
},
}
}
) as client:
tools = await client.get_tools()

model = ChatGoogleGenerativeAI(
model="gemini-2.0-flash",
google_api_key="YOUR_GOOGLE_API_KEY",
)
agent = create_react_agent(model, tools)

result = await agent.ainvoke({
"messages": [{"role": "user", "content": "Show me today's sales summary"}]
})
print(result["messages"][-1].content)

asyncio.run(main())

Option B — Manual function bridge​

import asyncio
import httpx
import google.generativeai as genai
from google.generativeai.types import FunctionDeclaration, Tool

MCP_URL = "https://api.flowandgrow.tech/mcp"
API_KEY = "Bearer fp_mcp_a1b2c3d4e5f6..."


async def init_mcp_session() -> tuple[httpx.AsyncClient, str]:
client = httpx.AsyncClient(headers={"Authorization": API_KEY})
resp = await client.post(MCP_URL, json={
"jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {"name": "gemini-bridge", "version": "1.0"},
},
})
return client, resp.headers["mcp-session-id"]


async def list_mcp_tools(client: httpx.AsyncClient, sid: str) -> list[dict]:
resp = await client.post(MCP_URL,
json={"jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {}},
headers={"mcp-session-id": sid},
)
return resp.json()["result"]["tools"]


async def call_mcp_tool(client: httpx.AsyncClient, sid: str, name: str, args: dict) -> str:
resp = await client.post(MCP_URL,
json={"jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": {"name": name, "arguments": args}},
headers={"mcp-session-id": sid},
)
return resp.json()["result"]["content"][0]["text"]


def to_gemini_tool(mcp_tool: dict) -> FunctionDeclaration:
schema = mcp_tool.get("inputSchema", {})
return FunctionDeclaration(
name=mcp_tool["name"],
description=mcp_tool["description"],
parameters=schema if schema.get("properties") else {"type": "object", "properties": {}},
)


async def main():
genai.configure(api_key="YOUR_GOOGLE_API_KEY")

client, sid = await init_mcp_session()
mcp_tools = await list_mcp_tools(client, sid)

model = genai.GenerativeModel(
"gemini-2.0-flash",
tools=[Tool(function_declarations=[to_gemini_tool(t) for t in mcp_tools])],
)
chat = model.start_chat()
response = chat.send_message("What are my top 5 products this month?")

# Agentic loop — keep running until the model stops requesting tools
while response.candidates[0].content.parts[0].function_call.name:
fc = response.candidates[0].content.parts[0].function_call
result = await call_mcp_tool(client, sid, fc.name, dict(fc.args))
response = chat.send_message(
genai.protos.Part(
function_response=genai.protos.FunctionResponse(
name=fc.name,
response={"result": result},
)
)
)

print(response.text)
await client.aclose()

asyncio.run(main())

Troubleshooting​

SymptomCauseFix
Tools not appearing in Claude DesktopJSON syntax error or npx not in PATHRun npx mcp-remote --version in terminal
Tools not appearing in Claude Code VS CodeExtension not reloaded after config changeRun Claude Code: Reload MCP Servers from Command Palette
Tools not appearing after editing .mcp.jsonServer not reloadedRun Claude Code: Reload MCP Servers or restart Claude Code
401 UnauthorizedInvalid key or wrong formatCheck the raw key value; no extra whitespace after Bearer
ECONNREFUSED (local)Backend not runningpnpm --filter backend run start:dev
Only some tools appearKey has restricted scopesAsk operator to check scopes column in mcp_api_key table
Intent tools missingpos:intents not in key scopesAsk operator to add pos:intents to the key's scopes array
Gemini bridge stops after one tool callMissing agentic loopImplement the while function_call loop shown in Option B above
Cursor shows server as disconnectedRemote URL unreachableCheck firewall, VPN, or CORS settings