>_

MCP integration

This app exposes a Model Context Protocol server so agents like Claude, ChatGPT, Cursor and Codex can read and write your prompt library on your behalf.

Use your prompts with AI assistants

Copy an uPaLe prompt and continue in ChatGPT, Claude, Grok, or Gemini using your existing account. uPaLe does not receive access to your AI account, subscription, conversations, or responses.

Automatic response import and account synchronization are not available in this version.

Available now

  • Copy an authorized prompt.
  • Select an AI assistant.
  • Open the assistant.
  • Continue using your existing account.

Future integrations

  • Retrieve uPaLe prompts from supported assistants.
  • Save assistant output back to uPaLe after explicit approval.
  • Use authenticated MCP integrations where officially supported.
  • Maintain provider-specific connection and consent states.

Endpoint

Streamable HTTP endpoint:

https://your-app.lovable.app/mcp

Discovery document: https://your-app.lovable.app/.well-known/oauth-protected-resource

Authentication (OAuth 2.1 + PKCE)

  1. MCP client fetches /.well-known/oauth-protected-resource from this app.
  2. It discovers the Supabase authorization server and (optionally) registers itself with dynamic client registration.
  3. It sends the user to the authorize URL. The user signs in with the same account they use in this app, then approves consent at /.lovable/oauth/consent.
  4. The client exchanges the authorization code for an access token and calls /mcp with Authorization: Bearer <access_token>.

Every tool call runs under Postgres RLS as the signed-in user, so a client can only ever read and write that user's own data.

Content kinds and pricing

A library entry is one of four kinds, and every tool accepts or reports it through content_type:

  • single — one prompt body in text.
  • chain — ordered steps, returned with the entry.
  • skill — Markdown instructions plus skill_description and when_to_use.
  • goal — a structured brief in goal_spec (role, context, goal statement, success criteria, constraints, output format, tone and audience). Its prompt text is composed from those fields.

Read results also carry price_cents and is_free. An entry with no active price is free. Buying or pricing a prompt is not exposed over MCP — that stays in the app.

Data boundaries

  • Your library only. Every tool filters on the signed-in user, including get_prompt and get_prompts. Another member's prompt is reported as not found even when it is published in the public feed, and even if the id is known.
  • Your instance only. Agent access is a main-instance feature. A call that arrives on another instance's domain is refused with instance_not_enabled instead of being answered with main-instance data.
  • Tokens from this app only. An access token minted by any other backend is refused with issuer_not_recognized.
  • Approved clients only. A newly seen OAuth client stays pending until you approve it in connected clients; revoking it stops all further calls immediately.
  • Refused calls are recorded as denied in your activity log, with the machine-readable code in the tool result.

Rate limits

Per authenticated user:

  • 30 tool calls per minute
  • 300 tool calls per hour
  • 2000 tool calls per day
  • create_prompt is additionally capped at 60 writes per day

Over-limit calls return isError: true with a rate-limit message and are recorded in your activity log.

Connecting a client

In Claude Desktop, ChatGPT (Custom GPTs / Connectors), Cursor, or any MCP client, add a new HTTP MCP server:

URL:  https://your-app.lovable.app/mcp
Auth: OAuth (the client discovers everything from the URL)

When the client redirects you to sign in, use the same account you use in this app.

Connecting from Claude

  1. In Claude, open Settings → Connectors → Add custom connector.
  2. Paste the endpoint URL https://your-app.lovable.app/mcp and confirm. Claude discovers OAuth automatically.
  3. Sign in with your account and approve the consent screen. Claude then lists the prompt tools.
  4. Ask Claude things like “find my prompt about cold emails” — it calls search_prompts and then get_prompt.

Claude cannot reach the preview sandbox — the app must be published for the connector to work.

Tools

List categories

list_categoriesread

List the category tree: shared top-level categories plus your own sub-categories.

curl -X POST 'https://your-app.lovable.app/mcp' \
  -H 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_categories","arguments":{}}}'

Search prompts

search_promptsread

Keyword search across your prompts; returns ranked hits with a snippet and prompt id.

Input: query*: string, category_id: uuid, subcategory_id: uuid, visibility: string (private|published), content_type: string (single|chain|skill|goal), limit: integer 1-50
curl -X POST 'https://your-app.lovable.app/mcp' \
  -H 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"search_prompts","arguments":{"query":"cold email","limit":5}}}'

List my prompts

list_my_promptsread

List your prompts with optional text search, category/sub-category scope, labels, paging and full text. Every row reports price_cents and is_free.

Input: query: string, category_id: uuid, subcategory_id: uuid, labels: string[], visibility: string (private|published), content_type: string (single|chain|skill|goal), include_text: boolean, limit: integer 1-100, offset: integer
curl -X POST 'https://your-app.lovable.app/mcp' \
  -H 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_my_prompts","arguments":{"query":"marketing","limit":10,"include_text":true}}}'

Get prompt

get_promptread

Fetch a single prompt (including its text, chain steps or goal_spec, plus price_cents / is_free) by id. RLS decides what the caller can read.

Input: id*: uuid
curl -X POST 'https://your-app.lovable.app/mcp' \
  -H 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_prompt","arguments":{"id":"00000000-0000-0000-0000-000000000000"}}}'

Get prompts (batch)

get_promptsread

Fetch up to 20 prompts with their full text, chain steps, goal_spec and pricing in one call, instead of many single fetches.

Input: ids*: uuid[] (max 20)
curl -X POST 'https://your-app.lovable.app/mcp' \
  -H 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_prompts","arguments":{"ids":["00000000-0000-0000-0000-000000000000","11111111-1111-1111-1111-111111111111"]}}}'

Get prompt chain

get_prompt_chainread

Fetch one of your prompt chains by id with its content_type metadata and every step in order.

Input: id*: uuid
curl -X POST 'https://your-app.lovable.app/mcp' \
  -H 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_prompt_chain","arguments":{}}}'

List my skills

list_my_skillsread

List your skills with their metadata (labels, category, sub-category, model, visibility, skill description, when to use).

Input: query: string, category_id: uuid, subcategory_id: uuid, labels: string[], visibility: string (private|published), include_text: boolean, limit: integer 1-100, offset: integer
curl -X POST 'https://your-app.lovable.app/mcp' \
  -H 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"list_my_skills","arguments":{}}}'

Get skill

get_skillread

Fetch one of your skills by id with its full Markdown instructions, skill description and when-to-use.

Input: id*: uuid
curl -X POST 'https://your-app.lovable.app/mcp' \
  -H 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_skill","arguments":{}}}'

Create prompt, chain, skill or goal

create_promptwrite

Create a new library entry. content_type selects the kind: single (needs text), chain (needs at least two steps), skill (needs a skill description plus instructions) or goal (needs a goal_spec with role and goal statement). Defaults to private visibility.

Input: title*: string 1-300, content_type: string (single|chain|skill|goal), text: string, steps: step[] (max 25), skill_description: string, when_to_use: string, goal_spec: object, category_id*: uuid, subcategory_id: uuid, model*: string, visibility: string (private|published), labels: string[] (max 8)
curl -X POST 'https://your-app.lovable.app/mcp' \
  -H 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"create_prompt","arguments":{"title":"My prompt","text":"Write a haiku about pgvector.","category_id":"00000000-0000-0000-0000-000000000000","model":"gpt-5","visibility":"private"}}}'

Update prompt, chain, skill or goal

update_promptwrite

Update an existing entry; only the supplied fields change. Pass steps to replace a chain's ordered steps atomically, or goal_spec to rewrite a goal brief.

Input: id*: uuid, title: string 1-300, text: string, steps: step[] (2-25), skill_description: string, when_to_use: string, goal_spec: object, category_id: uuid, subcategory_id: uuid | null, model: string, visibility: string (private|published), labels: string[] (max 8)
curl -X POST 'https://your-app.lovable.app/mcp' \
  -H 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"update_prompt","arguments":{}}}'

Replace prompt chain steps

set_prompt_chainwrite

Replace the ordered steps of an existing prompt with the supplied list (at least two), converting it to a chain. Written atomically; previous steps are removed.

Input: prompt_id*: uuid, steps*: step[] (2-25)
curl -X POST 'https://your-app.lovable.app/mcp' \
  -H 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"set_prompt_chain","arguments":{}}}'

Delete prompt, chain, skill or goal

delete_promptwrite

Permanently delete one library entry. Chain steps are removed with it.

Input: id*: uuid
curl -X POST 'https://your-app.lovable.app/mcp' \
  -H 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"delete_prompt","arguments":{}}}'