Koskamo

Le Confidant MCP

An MCP server that allows AI assistants to read quantitative statistics from WhatsApp chat exports, such as message counts, reply times, and average lengths, while also providing public tools for link creation and text formatting.

Endpoint and access

No sign-in to connect and list tools. Individual tools may still need a vendor account, credentials, or permissions; check the documented prerequisites.

Le Confidant MCP logo, by Le ConfidantVendor evidenceStreamable HTTPNo sign-inEndpoint checked 2026-11-01Operated by Le Confidant
MCP endpoint (Streamable HTTP)
https://leconfidant.ai/api/mcp
Vendor documentation

What you can do with it

  • Read statistics from a connected WhatsApp analysis
  • Create a wa.me link
  • Format WhatsApp text
  • Normalize phone numbers

Source and maintenance

Vendor evidenceRegistry 0.4.0

Protocol and capabilities

Server
le-confidant 0.4.0
MCP protocol
2025-06-18
Tools
7 advertised
Resources
1 advertised
Resource templates
0 advertised
Prompts
Not advertised
Server-advertised capabilities
{
  "tools": {
    "listChanged": true
  },
  "resources": {
    "listChanged": true
  }
}

Server-provided instructions

Untrusted server output shown for inspection. It is not Koskamo guidance and is excluded from knowledge search.

Public WhatsApp utilities and the clearly fictional demo require no account. They do not access WhatsApp or send messages. Use the demo only for synthetic examples, never for a user’s real conversation. get_conversation_snapshot returns whole-session numerical statistics from the explicitly connected WhatsApp export analysis; call it only to retrieve or explain those statistics. If source.fictional is true, identify the results as fictional review data, not a personal conversation. Comparing months, date windows, trends or changes over time is unsupported: call NO tool for such a request, including get_conversation_snapshot, explain that period comparison is unavailable, and never substitute whole-session totals for it. Explain definitions and sample sizes. Do not infer intentions or relationship diagnoses. No file upload, analysis initiation, payments or message sending is available. Disconnect only for an explicit request to revoke access.

Tools

7 advertised

generate_whatsapp_link — Create a WhatsApp click-to-chat link
Advertised by the server during the last successful anonymous check.
Advertised read-only

Create a wa.me URL with an optional prefilled message for copying or sharing. Requires a valid phone number; does not verify WhatsApp registration. Inputs are processed by this server to return the result; this tool does not store or log phone numbers or text. It does not access an account or send messages.

generate_whatsapp_link input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "phone"
  ],
  "properties": {
    "phone": {
      "type": "string",
      "maxLength": 80,
      "minLength": 1,
      "description": "International phone number beginning with +, or a national number with defaultCountry."
    },
    "locale": {
      "enum": [
        "en",
        "es",
        "pt-br",
        "de",
        "fr",
        "it"
      ],
      "type": "string",
      "default": "en"
    },
    "message": {
      "type": "string",
      "maxLength": 4000
    },
    "defaultCountry": {
      "type": "string",
      "maxLength": 2,
      "minLength": 2
    }
  },
  "additionalProperties": false
}
generate_whatsapp_link output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "e164",
    "url",
    "messageSent"
  ],
  "properties": {
    "url": {
      "type": "string",
      "format": "uri"
    },
    "e164": {
      "type": "string"
    },
    "locale": {
      "enum": [
        "en",
        "es",
        "pt-br",
        "de",
        "fr",
        "it"
      ],
      "type": "string",
      "default": "en"
    },
    "messageSent": {
      "type": "boolean",
      "const": false
    }
  },
  "additionalProperties": false
}
generate_whatsapp_link annotations
{
  "title": "Create a WhatsApp click-to-chat link",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
format_whatsapp_text — Format text for WhatsApp
Advertised by the server during the last successful anonymous check.
Advertised read-only

Convert the user's Markdown source to text ready to paste into WhatsApp. Before calling, copy the supplied source unchanged into text: do not Markdown-escape it or pre-convert it. Example: source **Meeting tomorrow** must be passed as **Meeting tomorrow**; the tool returns *Meeting tomorrow*. Preserve backslashes the user actually supplied, but never insert extra ones. After calling, display structuredContent.formattedText verbatim in a plain-text fenced code block, without escaping or reformatting it. Supports # headings, bold, italics, strikethrough, lists and links. Preserves URL destinations, literal text and fenced/inline code. Unsupported blocks remain literal; does not render HTML, summarize or translate. Inputs are processed by this server to return the result; this tool does not store or log phone numbers or text. It does not access an account or send messages.

format_whatsapp_text input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "text"
  ],
  "properties": {
    "text": {
      "type": "string",
      "maxLength": 12000,
      "minLength": 1,
      "description": "The user's original Markdown source, up to 12,000 UTF-16 code units. Copy it unchanged: do not render it, pre-convert formatting, or add backslashes before Markdown punctuation. For **Meeting tomorrow**, pass exactly **Meeting tomorrow** as the decoded text value. Preserve backslashes only when present in the user's source; normal JSON string encoding must not change the decoded text."
    },
    "locale": {
      "enum": [
        "en",
        "es",
        "pt-br",
        "de",
        "fr",
        "it"
      ],
      "type": "string",
      "default": "en"
    }
  },
  "additionalProperties": false
}
format_whatsapp_text output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "formattedText",
    "messageSent"
  ],
  "properties": {
    "locale": {
      "enum": [
        "en",
        "es",
        "pt-br",
        "de",
        "fr",
        "it"
      ],
      "type": "string",
      "default": "en"
    },
    "messageSent": {
      "type": "boolean",
      "const": false
    },
    "formattedText": {
      "type": "string",
      "description": "Finished WhatsApp text, ready to copy. Display this value verbatim in a plain-text fenced code block; do not add backslash escapes, change emphasis markers, or format it again. Choose a fence that does not conflict with code already in the returned text."
    }
  },
  "additionalProperties": false
}
format_whatsapp_text annotations
{
  "title": "Format text for WhatsApp",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
normalize_whatsapp_numbers — Normalize phone numbers for WhatsApp
Advertised by the server during the last successful anonymous check.
Advertised read-only

Validate up to 100 phone numbers and return E.164 numbers and wa.me links with per-row status and duplicate positions. National numbers require defaultCountry. Never guess a country from language. Does not check WhatsApp registration or contact people. Inputs are processed by this server to return the result; this tool does not store or log phone numbers or text. It does not access an account or send messages.

normalize_whatsapp_numbers input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "numbers"
  ],
  "properties": {
    "locale": {
      "enum": [
        "en",
        "es",
        "pt-br",
        "de",
        "fr",
        "it"
      ],
      "type": "string",
      "default": "en"
    },
    "numbers": {
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 80,
        "minLength": 1
      },
      "maxItems": 100,
      "minItems": 1
    },
    "defaultCountry": {
      "type": "string",
      "maxLength": 2,
      "minLength": 2,
      "description": "Country for national numbers; never inferred from locale."
    }
  },
  "additionalProperties": false
}
normalize_whatsapp_numbers output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "rows",
    "validCount",
    "uniqueValidCount",
    "invalidCount",
    "registrationChecked"
  ],
  "properties": {
    "rows": {
      "type": "array",
      "items": {
        "anyOf": [
          {
            "type": "object",
            "required": [
              "index",
              "valid",
              "error"
            ],
            "properties": {
              "error": {
                "type": "string",
                "const": "invalid_number"
              },
              "index": {
                "type": "integer",
                "minimum": 0
              },
              "valid": {
                "type": "boolean",
                "const": false
              }
            },
            "additionalProperties": false
          },
          {
            "type": "object",
            "required": [
              "index",
              "valid",
              "e164",
              "waLink"
            ],
            "properties": {
              "e164": {
                "type": "string"
              },
              "index": {
                "type": "integer",
                "minimum": 0
              },
              "valid": {
                "type": "boolean",
                "const": true
              },
              "waLink": {
                "type": "string",
                "format": "uri"
              },
              "duplicateOf": {
                "type": "integer",
                "minimum": 0
              }
            },
            "additionalProperties": false
          }
        ]
      },
      "maxItems": 100
    },
    "locale": {
      "enum": [
        "en",
        "es",
        "pt-br",
        "de",
        "fr",
        "it"
      ],
      "type": "string",
      "default": "en"
    },
    "validCount": {
      "type": "integer",
      "maximum": 100,
      "minimum": 0
    },
    "invalidCount": {
      "type": "integer",
      "maximum": 100,
      "minimum": 0
    },
    "uniqueValidCount": {
      "type": "integer",
      "maximum": 100,
      "minimum": 0
    },
    "registrationChecked": {
      "type": "boolean",
      "const": false
    }
  },
  "additionalProperties": false
}
normalize_whatsapp_numbers annotations
{
  "title": "Normalize phone numbers for WhatsApp",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
demo_whatsapp_wrapped — Show a fictional WhatsApp Wrapped recap
Advertised by the server during the last successful anonymous check.
Advertised read-only

Show a synthetic WhatsApp recap without an account, upload or private conversation access. Use only for a demo or example, never to answer questions about the user's real conversation. All numbers are fictional and fixed; no relationship diagnosis. Returns a text and structured recap, without image export.

demo_whatsapp_wrapped input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "locale": {
      "enum": [
        "en",
        "es",
        "pt-br",
        "de",
        "fr",
        "it"
      ],
      "type": "string",
      "default": "en"
    }
  },
  "additionalProperties": false
}
demo_whatsapp_wrapped output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "source",
    "title",
    "scope",
    "participants",
    "totalMessages",
    "activeDays",
    "topEmojis",
    "limitations",
    "learnMore"
  ],
  "properties": {
    "scope": {
      "type": "string",
      "const": "whole_conversation"
    },
    "title": {
      "type": "string"
    },
    "locale": {
      "enum": [
        "en",
        "es",
        "pt-br",
        "de",
        "fr",
        "it"
      ],
      "type": "string",
      "default": "en"
    },
    "source": {
      "type": "object",
      "required": [
        "fictional",
        "synthetic",
        "privateDataAccessed"
      ],
      "properties": {
        "fictional": {
          "type": "boolean",
          "const": true
        },
        "synthetic": {
          "type": "boolean",
          "const": true
        },
        "privateDataAccessed": {
          "type": "boolean",
          "const": false
        }
      },
      "additionalProperties": false
    },
    "learnMore": {
      "type": "object",
      "required": [
        "title",
        "url"
      ],
      "properties": {
        "url": {
          "type": "string",
          "format": "uri"
        },
        "title": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "topEmojis": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "emoji",
          "count"
        ],
        "properties": {
          "count": {
            "type": "integer",
            "minimum": 0
          },
          "emoji": {
            "type": "string"
          }
        },
        "additionalProperties": false
      },
      "maxItems": 3
    },
    "activeDays": {
      "type": "integer",
      "minimum": 0
    },
    "limitations": {
      "type": "array",
      "items": {
        "type": "string"
      },
      "maxItems": 4
    },
    "participants": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "label",
          "messages",
          "share"
        ],
        "properties": {
          "label": {
            "enum": [
              "A",
              "B"
            ],
            "type": "string"
          },
          "share": {
            "type": "number",
            "maximum": 1,
            "minimum": 0
          },
          "messages": {
            "type": "integer",
            "minimum": 0
          }
        },
        "additionalProperties": false
      },
      "maxItems": 2,
      "minItems": 2
    },
    "totalMessages": {
      "type": "integer",
      "minimum": 0
    }
  },
  "additionalProperties": false
}
demo_whatsapp_wrapped annotations
{
  "title": "Show a fictional WhatsApp Wrapped recap",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
style_whatsapp_text — Restyle text with decorative letters
Advertised by the server during the last successful anonymous check.
Advertised read-only

Rewrite the user's text in one decorative Unicode style to paste into WhatsApp. Styles: bold, italic, monospace, bubble, gothic, double (double-struck), strikethrough, upside-down. Call it once the user has picked a style from this list. These are lookalike characters, not real fonts: accented letters and digits usually stay plain, and screen readers can read the result badly. After calling, display structuredContent.styledText verbatim in a plain-text fenced code block. Inputs are processed by this server to return the result; this tool does not store or log phone numbers or text. It does not access an account or send messages.

style_whatsapp_text input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "text",
    "style"
  ],
  "properties": {
    "text": {
      "type": "string",
      "maxLength": 4000,
      "minLength": 1,
      "description": "The user's text, copied unchanged."
    },
    "style": {
      "enum": [
        "bold",
        "italic",
        "monospace",
        "bubble",
        "gothic",
        "double",
        "strikethrough",
        "upside-down"
      ],
      "type": "string",
      "description": "The style the user chose."
    },
    "locale": {
      "enum": [
        "en",
        "es",
        "pt-br",
        "de",
        "fr",
        "it"
      ],
      "type": "string",
      "default": "en"
    }
  },
  "additionalProperties": false
}
style_whatsapp_text output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "style",
    "styledText",
    "messageSent"
  ],
  "properties": {
    "style": {
      "enum": [
        "bold",
        "italic",
        "monospace",
        "bubble",
        "gothic",
        "double",
        "strikethrough",
        "upside-down"
      ],
      "type": "string"
    },
    "locale": {
      "enum": [
        "en",
        "es",
        "pt-br",
        "de",
        "fr",
        "it"
      ],
      "type": "string",
      "default": "en"
    },
    "styledText": {
      "type": "string",
      "description": "Finished text, ready to copy. Display this value verbatim in a plain-text fenced code block; do not normalize, translate or format it again."
    },
    "messageSent": {
      "type": "boolean",
      "const": false
    }
  },
  "additionalProperties": false
}
style_whatsapp_text annotations
{
  "title": "Restyle text with decorative letters",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
get_conversation_snapshot — Read whole-session statistics
Advertised by the server during the last successful anonymous check.
Advertised read-only

Use only to retrieve or explain WHOLE-SESSION numerical statistics from the user's explicitly authorized WhatsApp export analysis. DO NOT call for date-window, month-to-month, trend or period-comparison requests, even to check available data. For example, 'Compare September and November in my own connected WhatsApp analysis' needs NO tool call: explain that period comparison is unavailable. This tool returns only stored whole-session totals and cannot answer that request. For supported requests, returns neutral A/B labels, counts/shares, starts, reply timing/sample sizes, mean message length, definitions, limitations and expiry from the OAuth-selected session. No raw messages, names, excerpts, paid insights or new analysis. Set locale to the user's supported language.

get_conversation_snapshot input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "locale": {
      "enum": [
        "en",
        "es",
        "pt-br",
        "de",
        "fr",
        "it"
      ],
      "type": "string",
      "default": "en"
    }
  },
  "additionalProperties": false
}
get_conversation_snapshot output schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "required": [
    "kind",
    "source",
    "expiresAt",
    "snapshot",
    "definitions",
    "limitations"
  ],
  "properties": {
    "kind": {
      "type": "string",
      "const": "free_snapshot"
    },
    "locale": {
      "enum": [
        "en",
        "es",
        "pt-br",
        "de",
        "fr",
        "it"
      ],
      "type": "string",
      "default": "en"
    },
    "source": {
      "type": "object",
      "required": [
        "fictional",
        "analysis",
        "participantsArePseudonyms"
      ],
      "properties": {
        "analysis": {
          "type": "string",
          "const": "stored_free_quantitative"
        },
        "fictional": {
          "type": "boolean"
        },
        "participantsArePseudonyms": {
          "type": "boolean",
          "const": true
        }
      },
      "additionalProperties": false
    },
    "snapshot": {
      "type": "object",
      "required": [
        "totalMessages",
        "participants"
      ],
      "properties": {
        "participants": {
          "type": "array",
          "items": {
            "type": "object",
            "required": [
              "label",
              "messages",
              "messageSharePercent",
              "observedStarts",
              "replyPairs",
              "meanReplyMinutes",
              "medianReplyMinutes",
              "p25ReplyMinutes",
              "p75ReplyMinutes",
              "meanMessageCharacters"
            ],
            "properties": {
              "label": {
                "enum": [
                  "A",
                  "B"
                ],
                "type": "string"
              },
              "messages": {
                "type": "integer",
                "minimum": 0
              },
              "replyPairs": {
                "$ref": "#/properties/snapshot/properties/participants/items/properties/observedStarts"
              },
              "observedStarts": {
                "anyOf": [
                  {
                    "type": "number",
                    "minimum": 0
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "p25ReplyMinutes": {
                "$ref": "#/properties/snapshot/properties/participants/items/properties/observedStarts"
              },
              "p75ReplyMinutes": {
                "$ref": "#/properties/snapshot/properties/participants/items/properties/observedStarts"
              },
              "meanReplyMinutes": {
                "$ref": "#/properties/snapshot/properties/participants/items/properties/observedStarts"
              },
              "medianReplyMinutes": {
                "$ref": "#/properties/snapshot/properties/participants/items/properties/observedStarts"
              },
              "messageSharePercent": {
                "anyOf": [
                  {
                    "type": "number",
                    "maximum": 100,
                    "minimum": 0
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "meanMessageCharacters": {
                "$ref": "#/properties/snapshot/properties/participants/items/properties/observedStarts"
              }
            },
            "additionalProperties": false
          },
          "maxItems": 2,
          "minItems": 2
        },
        "totalMessages": {
          "type": "integer",
          "minimum": 0
        }
      },
      "additionalProperties": false
    },
    "expiresAt": {
      "type": "string",
      "format": "date-time"
    },
    "definitions": {
      "type": "object",
      "required": [
        "messages",
        "replies",
        "initiation",
        "labels"
      ],
      "properties": {
        "labels": {
          "type": "string"
        },
        "replies": {
          "type": "string"
        },
        "messages": {
          "type": "string"
        },
        "initiation": {
          "type": "string"
        }
      },
      "additionalProperties": false
    },
    "limitations": {
      "type": "array",
      "items": {
        "type": "string"
      }
    }
  },
  "additionalProperties": false
}
get_conversation_snapshot annotations
{
  "title": "Read whole-session statistics",
  "readOnlyHint": true,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": false
}
disconnect_conversation — Disconnect your selected conversation
Advertised by the server during the last successful anonymous check.
Advertised destructive

Use only when the user explicitly asks to disconnect or revoke this connection. Permanently revoke its current OAuth grant immediately; the revoked credential cannot be restored. Fresh explicit consent creates a new grant while the original session is eligible. Stops future reads without deleting the source session or results already in this conversation. Other connections can be revoked on the website. This tool changes access and is destructive access revocation; it does not retrieve statistics or answer period comparisons.

disconnect_conversation input schema
{
  "type": "object",
  "$schema": "http://json-schema.org/draft-07/schema#",
  "properties": {
    "locale": {
      "enum": [
        "en",
        "es",
        "pt-br",
        "de",
        "fr",
        "it"
      ],
      "type": "string",
      "default": "en"
    }
  },
  "additionalProperties": false
}
disconnect_conversation annotations
{
  "title": "Disconnect your selected conversation",
  "readOnlyHint": false,
  "openWorldHint": false,
  "idempotentHint": true,
  "destructiveHint": true
}

Prompts

Not advertised

No prompt definitions available.

Resources

1 advertised

conversation-results-card — Le Confidant results

Advertised by the server during the last successful anonymous check.

conversation-results-card URI
ui://le-confidant/results-v3.html

MIME type: text/html;profile=mcp-app

30-day availability

Aggregated from read-only remote checks; this is not a tool-execution or security guarantee.

Successful checks
1 of 1 (100%)
Average latency
745 ms
95th percentile latency
745 ms

Maintenance history

Public check and source-refresh events. Editorial and ownership records remain private.

  • · probe · passed · 745 ms · metadata changed · 7 tool(s), 1 resource(s), 0 resource template(s)

Connect from your client

Each snippet registers the same endpoint; pick the client you use.

This server is operated by the named third party. Listing and endpoint checks are not an endorsement or a security audit. Review the operator's permissions, terms, and data handling before connecting. How listings are checked and corrected.

Claude Code

Run this once in a terminal. It registers the remote server. Use --scope project to write .mcp.json for the repo.
Claude Code configuration
claude mcp add --transport http le-confidant-mcp https://leconfidant.ai/api/mcp

Codex

Run this once. Codex stores MCP servers in ~/.codex/config.toml (or .codex/config.toml in a trusted project).
Codex configuration
codex mcp add le-confidant-mcp --url https://leconfidant.ai/api/mcp

Cursor

Merge this server into .cursor/mcp.json in your project, then enable le-confidant-mcp in your MCP settings.
Cursor configuration
{
  "mcpServers": {
    "le-confidant-mcp": {
      "url": "https://leconfidant.ai/api/mcp"
    }
  }
}

Cline

Merge this into cline_mcp_settings.json (Cline → MCP Servers → Configure).
Cline configuration
{
  "mcpServers": {
    "le-confidant-mcp": {
      "type": "streamableHttp",
      "url": "https://leconfidant.ai/api/mcp",
      "disabled": false
    }
  }
}

VS Code

Merge this server into .vscode/mcp.json. Use MCP: List Servers to start le-confidant-mcp and inspect its tools.
VS Code configuration
{
  "servers": {
    "le-confidant-mcp": {
      "type": "http",
      "url": "https://leconfidant.ai/api/mcp"
    }
  }
}

Gemini CLI

Run this once. It writes .gemini/settings.json in the current project; pass --scope user for ~/.gemini/settings.json.
Gemini CLI configuration
gemini mcp add --transport http le-confidant-mcp https://leconfidant.ai/api/mcp

Claude Desktop

Merge this into claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/, Windows: %APPDATA%\Claude\), then restart Claude Desktop.
Claude Desktop configuration
{
  "mcpServers": {
    "le-confidant-mcp": {
      "url": "https://leconfidant.ai/api/mcp"
    }
  }
}

Windsurf

Merge this into ~/.codeium/windsurf/mcp_config.json, then refresh MCP in Cascade. Windsurf remote servers use serverUrl, not url.
Windsurf configuration
{
  "mcpServers": {
    "le-confidant-mcp": {
      "serverUrl": "https://leconfidant.ai/api/mcp"
    }
  }
}

Let your agent find its tools

Find servers like Le Confidant MCP from your agent. Add Koskamo once to search the index for endpoints, access requirements, and client setup. Public discovery needs no key.

Do you run Le Confidant MCP?

Prove ownership with a DNS record, a well-known file, or your Official MCP Registry entry, and your edits publish immediately. Proofs are re-checked weekly; admins can still hide or remove a listing.

Claim this listing