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_atin 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) — requirepos:intentsscope; 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.flowpos.app/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.
| Environment | MCP URL |
|---|---|
| Local | http://localhost:4000/mcp |
| Staging | https://api-staging.flowpos.app/mcp |
| Production | https://api.flowpos.app/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.flowpos.app/mcp",
"--header",
"Authorization: Bearer fp_mcp_a1b2c3d4e5f6..."
]
}
}
}
mcp-remotebridges the HTTP/SSE transport to the stdio format Claude Desktop expects. It is installed automatically bynpx— 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.flowpos.app/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.flowpos.app/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.flowpos.app/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.jsonto.gitignoreto keep real keys out of git. Commit a.mcp.json.examplewith 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.
- Open claude.ai and go to Settings → Integrations
- Click Add MCP server
- Enter the FlowPOS MCP URL:
https://api.flowpos.app/mcp - Add a custom header:
Authorization: Bearer fp_mcp_a1b2c3d4e5f6... - 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.flowpos.app/mcp",
"headers": {
"Authorization": "Bearer fp_mcp_a1b2c3d4e5f6..."
}
}
}
}
For local development, use http://localhost:4000/mcp instead.
Add
.cursor/mcp.jsonto.gitignoreto keep real keys out of git. Commit a.cursor/mcp.json.examplewith 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
- Open the Cursor chat panel (
Cmd+L/Ctrl+L) - Click the Tools icon near the input — flowpos should appear with its tools listed
- 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.flowpos.app/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.flowpos.app/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-4oorgpt-4o-mini. Thechat.completionsendpoint does not support MCP tool resources.
Gemini
Gemini has no native MCP support. Use a bridge adapter.
Option A — LangChain MCP Adapter (recommended)
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.flowpos.app/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.flowpos.app/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
| Symptom | Cause | Fix |
|---|---|---|
| Tools not appearing in Claude Desktop | JSON syntax error or npx not in PATH | Run npx mcp-remote --version in terminal |
| Tools not appearing in Claude Code VS Code | Extension not reloaded after config change | Run Claude Code: Reload MCP Servers from Command Palette |
Tools not appearing after editing .mcp.json | Server not reloaded | Run Claude Code: Reload MCP Servers or restart Claude Code |
401 Unauthorized | Invalid key or wrong format | Check the raw key value; no extra whitespace after Bearer |
ECONNREFUSED (local) | Backend not running | pnpm --filter backend run start:dev |
| Only some tools appear | Key has restricted scopes | Ask operator to check scopes column in mcp_api_key table |
| Intent tools missing | pos:intents not in key scopes | Ask operator to add pos:intents to the key's scopes array |
| Gemini bridge stops after one tool call | Missing agentic loop | Implement the while function_call loop shown in Option B above |
| Cursor shows server as disconnected | Remote URL unreachable | Check firewall, VPN, or CORS settings |