Saltar al contenido principal

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.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.

EnvironmentMCP URL
Localhttp://localhost:4000/mcp
Staginghttps://api-staging.flowpos.app/mcp
Productionhttps://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-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.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.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.flowpos.app/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.flowpos.app/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.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-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.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

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