BactoAI MCP server
BactoAI exposes a Model Context Protocol (MCP) server so external AI assistants — Claude, ChatGPT, Cursor, Codex or any MCP-compatible client — can read BactoAI content and, for authorised internal users, review website submissions. Every call is authenticated with OAuth 2.1 and executes under the same row-level security rules as the web app.
Endpoint
The server speaks MCP over Streamable HTTP. Point your client at the URL below; it handles discovery, authorization and JSON-RPC on the same path.
https://bactoai.lovable.app/mcpProtected-resource metadata is published at /.well-known/oauth-protected-resource, which clients fetch automatically to discover the authorization server.
OAuth 2.1 & consent flow
The MCP server is a resource server: it only verifies bearer tokens. Authorization is handled by BactoAI's managed auth service, with dynamic client registration enabled so clients self-register — no manual client ID or secret to copy.
- You add the server URL in your MCP client and start the connection. The client reads
/.well-known/oauth-protected-resourceand the authorization server's discovery document. - The client registers itself dynamically (RFC 7591) and opens the authorize URL in your browser with PKCE.
- If you are not signed in you land on
/auth. Sign in (or create an account) with the same email you use for the BactoAI console; the consent URL is preserved and you are returned to it afterwards. - The consent screen at
/.lovable/oauth/consent?authorization_id=…names the requesting client and explains that it will act as you. Choose Approve or Deny. - On approval you are redirected back to the client, which exchanges the code for an access token and calls the MCP endpoint with
Authorization: Bearer <token>. Already-approved clients skip the consent screen on reconnect.
Tokens are issued only through this OAuth flow. Pasting an app session token will not work — the server requires a token that carries an OAuth client_id claim.
Permissions. The token identifies you, and database access runs as your account. list_articles works for any signed-in user. The submission tools return rows only if your account holds the admin role; otherwise they return an empty result rather than an error.
Transport & request format
All calls are JSON-RPC 2.0 over HTTP POST. Streamable HTTP requires both content types in the Accept header — omitting either returns 406 Not Acceptable.
POST https://bactoai.lovable.app/mcp
Content-Type: application/json
Accept: application/json, text/event-stream
Authorization: Bearer <access_token>{
"jsonrpc": "2.0",
"id": 0,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": { "name": "my-assistant", "version": "1.0.0" }
}
}{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}curl -X POST https://bactoai.lovable.app/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer $BACTOAI_MCP_TOKEN" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'Client configuration
Most clients only need the URL. For editors that use a JSON config file, use a remote HTTP server entry:
{
"mcpServers": {
"bactoai": {
"type": "http",
"url": "https://bactoai.lovable.app/mcp"
}
}
}In Claude or ChatGPT, add BactoAI as a custom connector using the same URL and complete the browser sign-in when prompted.
Tool reference
Three tools are advertised. All are read-only and idempotent — nothing in this server mutates or deletes data.
list_contact_submissionsAdmin role requiredread-onlyLists website submissions (demo requests, partner inquiries, newsletter signups, general contact). Rows are returned through row-level security as the signed-in user, so non-admin accounts see none.
{
"type": "object",
"properties": {
"form_type": {
"type": "string",
"enum": ["demo", "partner", "newsletter", "contact"],
"description": "Filter by submission type."
},
"limit": {
"type": "integer",
"description": "Max rows to return (default 25, max 100)."
}
}
}{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "list_contact_submissions",
"arguments": { "form_type": "demo", "limit": 10 }
}
}submission_statsAdmin role requiredread-onlySummarises submissions by form type and returns the most recent submission timestamp. Takes no arguments.
{
"type": "object",
"properties": {}
}{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": { "name": "submission_stats", "arguments": {} }
}list_articlesAny signed-in accountread-onlyLists published BactoAI blog and resource articles with title, excerpt, category, publication date and reading time. Optionally filtered by category.
{
"type": "object",
"properties": {
"category": {
"type": "string",
"enum": ["Research", "Clinical", "Public Health", "Product"],
"description": "Filter articles by category."
}
}
}{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "list_articles",
"arguments": { "category": "Clinical" }
}
}Responses & errors
Every tool returns MCP content: a human-readable text block containing JSON, plus structuredContent for programmatic use.
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{ "type": "text", "text": "{\"total\": 42, \"by_form_type\": {\"demo\": 18, \"newsletter\": 21, \"partner\": 3}, \"latest\": \"2026-08-11T09:14:02.331Z\"}" }
],
"structuredContent": {
"total": 42,
"by_form_type": { "demo": 18, "newsletter": 21, "partner": 3 },
"latest": "2026-08-11T09:14:02.331Z"
}
}
}401 Unauthorized— missing, expired or non-OAuth token. Re-run the connection flow; the response includes aWWW-Authenticateheader pointing at the metadata document.406 Not Acceptable— theAcceptheader is missingapplication/jsonortext/event-stream.- Tool-level failures come back as a normal result with
isError: trueand a message — for example "Not authenticated", or a note that no submissions are visible because the account lacks the admin role.
Access & support
Admin access to submission data is granted manually by the BactoAI team. Sign up at /auth, then email bactoai01@gmail.com with the address you registered and we will attach the admin role.
