MCP is a way for an AI application to discover and call named tools. Connecting an MCP server does not give Iris unrestricted access to a business system. There are two different connections:
| Connection | Who uses it? | Authentication | Purpose |
|---|---|---|---|
| Your AI app → Flowlith | You, the business owner | Flowlith browser OAuth | Set up and manage Iris, teaching and approved Actions |
| Iris → your external MCP server | Iris during a customer conversation | A privately saved token/header, or no auth for deliberately public tools | Execute only the customer Actions you explicitly selected, tested and enabled |
The first connection does not automatically create the second. Your customer's WhatsApp account does not sign them into your CRM, ERP or HIS either. Your backend still owns record authorization. See the backend readiness guide.
1. Connect your AI app to Flowlith
Use a client that supports remote MCP and browser OAuth. Add a connection named Flowlith with this public endpoint:
https://mcp.flowlith.com/mcp
For clients with this JSON configuration format, the configuration contains no credentials:
{
"mcpServers": {
"iris": { "url": "https://mcp.flowlith.com/mcp" }
}
}
- Add the remote connection or install the public client package, using the instructions for your app. App plans and workspace policies may restrict custom connections.
- Complete Flowlith sign-in in your browser: email, email code, then Allow. Never paste the code, a token or an Authorization header into chat or configuration.
- Enable Flowlith in the conversation if your app requires it. Ask for this read-only check:
Call list_businesses using Flowlith. Do not start onboarding or change anything.
If more than one business is returned, ask which one I want to manage.
If sign-in or tool access is missing, explain that instead of guessing.
An empty business list can be a valid signed-in result. A tool list or an installed skill is not proof of access: Flowlith allows discovery before sign-in, but business tools require authorization. An unsigned tool call asks the client to complete sign-in; it does not read your business.
| What you see | What it proves |
|---|---|
| Package installed | The client has the package, not necessarily a working connection. |
| Tools discovered | The server can describe its tools, not that you are authorized. |
| Browser sign-in completed | An account authorized the app; verify business access next. |
Successful list_businesses |
The app can access your authorized business list. |
| A successful customer preview | That preview worked; it does not prove external-system or channel delivery. |
The owner connection can help with onboarding, business information, teaching drafts/Apply, business status, approved launch, customer previews and external Action setup. It is not a customer inbox, transcript export or contact-list browser. Website API keys, Meta sign-in and account settings remain secure browser steps. Read Iris capabilities for the full boundary.
2. Decide whether your backend needs MCP
MCP is optional. If the system already provides a suitable HTTPS API or automation webhook, use a direct API Action instead. A CRM/ERP/HIS does not need to install the Flowlith owner plugin.
Use external MCP when your team already runs a compatible tool server or wants to expose narrowly defined business operations. A database address, admin website, local command or vendor name is not an MCP endpoint. If your system only offers an interactive OAuth login, this external connection cannot use it yet; provide a supported token API, token MCP server or secure integration adapter. Do not reuse a personal session cookie.
3. Register your external MCP system
In your connected AI app, first call list_businesses, select the business, then list_systems to avoid duplicate setup. For multiple businesses, include the returned business identifier in setup calls.
The following are non-secret arguments for add_system. This is a fictional inventory server, not a hosted Flowlith integration:
{
"name": "Inventory tools",
"kind": "mcp",
"base_url": "https://inventory.example.com/mcp",
"auth": { "kind": "bearer" },
"headers": []
}
- Save the system, then call get_key_link with the returned
connection_idand requiredslot(normallyauth). Enter the token only on that secure page. The single-save link expires after 15 minutes; do not share it. - Call list_systems again after saving a key. Use the current connection version, not the version from before the key save.
- Call list_system_tools with that
connection_idandversion. This refreshes the tool menu and can mark changed Actions for review; it is not a customer tool execution. - Choose one task-specific tool with no refusal reason. Do not choose discovery, installation or tool-management tools. Review its meaning, inputs and actual effects; a
readOnlyHintis not proof that it cannot write. - Save the Action draft, Preview, Test with permission, then separately approve activation. Detailed steps follow below.
External MCP supports Bearer, a named credential header, or None for an intentionally public server. Basic/query-key authentication and interactive OAuth are not supported for external MCP. Additional fixed headers are allowed; secret values still go through the private key-entry flow, never JSON examples or tool arguments.
4. What your MCP server must implement
Use one final, publicly reachable HTTPS endpoint on port 443, with valid TLS and no redirects. Iris sends JSON-RPC POST requests. It accepts application/json responses or JSON-RPC messages in text/event-stream response frames.
Iris → initialize
Server → protocolVersion + capabilities.tools
Iris → notifications/initialized
Server → HTTP 202 or 204
Iris → tools/list (and any cursor pages)
Server → named tools and supported input schemas
Iris → tools/call for the selected, approved tool
Server → matching JSON-RPC result or error
Iris currently negotiates protocol versions 2025-11-25, 2025-06-18 or 2025-03-26. It proposes 2025-11-25. If initialization returns an Mcp-Session-Id, subsequent requests carry it along with MCP-Protocol-Version. Match each request's JSON-RPC ID in the response. Treat an initialized notification as a notification, not a request requiring a JSON-RPC result.
Do not require a local stdio process, a separate legacy GET/SSE endpoint, sampling, elicitation, or another server-initiated request. This connection calls tools; it does not automatically import your prompts, download resources, browse files, or install extra tools. Keep each response at most 64 KiB and operations short enough for the configured Action timeout, at most 10 seconds. That time budget includes initialization and tool discovery, not just your tool handler. A large reporting job should return a bounded status/result through a purpose-built endpoint, not block the chat.
A compatible tool definition
Return this tool inside the tools array of your tools/list result. It checks public product availability, not a private customer record:
{
"name": "get_availability",
"description": "Read current availability for a public product SKU.",
"inputSchema": {
"type": "object",
"additionalProperties": false,
"properties": {
"sku": { "type": "string", "maxLength": 40 }
},
"required": ["sku"]
},
"annotations": { "readOnlyHint": true }
}
Use a flat object with at most 12 input fields: bounded strings, booleans, bounded numbers/integers, or arrays of up to 20 strings. Strings are limited to 500 characters. Nested input objects, unions, nullable types, references such as $ref, and arbitrary JSON Schema features are not supported. Expose a simpler task-specific tool if your backend has a more complex native schema. Do not make Iris supply credentials as tool arguments.
The call and response
After setup and activation, the call for this example looks like this. The ID is illustrative; echo the actual request ID:
{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "get_availability",
"arguments": { "sku": "MUG-001" }
}
}
A successful JSON response can contain both a short text summary and structured fields:
{
"jsonrpc": "2.0",
"id": 4,
"result": {
"isError": false,
"content": [{ "type": "text", "text": "MUG-001 is available." }],
"structuredContent": { "sku": "MUG-001", "available": true, "quantity": 12 }
}
}
The Action can select text, structured.sku, structured.available and structured.quantity as returned fields. Image/binary content is not forwarded as customer knowledge. Linked resources are not fetched automatically. Return only the fields needed for the task, not the whole account or record. isError: true is a tool failure, not a successful business operation. An HTTP 200 alone is not proof of success.
5. Turn one selected tool into an Action
Use save_action_draft with the exact tool name/hash returned by list_system_tools. The sample below uses a placeholder connection ID, version and hash; replace them with current returned values. It is read-only only because the example endpoint truly does not change data:
{
"name": "product_availability",
"display_label": "Check product availability",
"hard": {
"mode": "mcp",
"connection_id": "11111111-1111-4111-8111-111111111111",
"connection_version": 2,
"input_schema": {
"type": "object", "additionalProperties": false,
"properties": { "sku": { "type": "string", "maxLength": 40 } },
"required": ["sku"]
},
"fixed_fields": {}, "system_fields": {},
"requires_confirmation": false,
"bind_customer_path": "", "link_hosts": [],
"timeout_ms": 10000, "idempotent_retry": false,
"mcp": {
"tool_name": "get_availability",
"tool_hash": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
},
"soft": {
"when_to_use": "When a customer asks whether a product is available.",
"synonyms": ["stock", "availability"],
"field_hints": { "sku": { "hint": "Ask which product to check.", "examples": ["MUG-001"] } },
"response_paths": ["text", "structured.sku", "structured.available", "structured.quantity"]
}
}
This example intentionally has no private-record customer binding. Do not copy that choice for private CRM, ERP or patient records. Your backend must authorize the specific customer and the Action must apply the appropriate customer check. A customer-typed record number or phone number is not proof of identity. See backend requirements.
- preview_action: use the returned
action_id. Read the destination, inputs, customer check, selected output, warnings and exactrevisionto the owner. - test_action: use that
action_id,revisionand fictionalinput. Test reaches the real system. Explain effects and obtain permission first; providereal_write_ok: trueonly after the requested permission. An MCP Test can require this flag because its transport uses POST even when the business operation is read-only. - Inspect the actual result. For writes, also verify the external record; never automatically repeat a sent write after a failed or uncertain response.
- Ask whether Iris should use this exact version with customers. Only after a clear yes, call turn_on_action with the exact
action_id,revisionandowner_said_yes: true.
Activation requires a successful, recent Test of that exact version. Customer writes also require confirmation in a later customer turn. Owner Test permission and customer write confirmation are separate. A draft, discovered tool or saved key is never activation.
6. Keep the connection working
Changed or removed tool definitions require fresh review, Test and approval; even a changed tool description can invalidate the saved selection. Do not silently substitute a similarly named tool. After key rotation or system edits, reload the current version and review affected Actions. Use turn_off_action to stop new calls; it cannot undo work already sent to your backend.
Before customer use, test a normal request, unavailable record, invalid input, expired key, lost response and customer-authorization rejection. Check the Action from each intended customer channel. Keep read and write credentials narrowly scoped, with a test environment where possible.
Backend readiness · What Iris can do · Direct APIs and Actions · AI workspace