Skip to main content

Quick Start

Connect to Lovelace and complete your first MCP workflow

This guide walks through connecting to the public MCP Gateway, from authentication to a full agent workflow. Choose the path that matches your setup.

Fast path — Claude Code

If you have Claude Code installed, this is all you need:

bash
claude mcp add lovelace --transport streamable-http \
  --url https://mcp.uselovelace.com/mcp

Claude Code handles OAuth automatically on first use. Then ask Claude:

text
List my Lovelace workspaces

For full programmatic control, continue below.

Prerequisites

  • A Lovelace account
  • For programmatic use: Python 3.10+ or Node.js 18+

Install the MCP SDK:

bash
# Python
pip install mcp

# TypeScript / Node.js
npm install @modelcontextprotocol/sdk

Step 1: Configure your client

Use the public gateway endpoint:

  • URL: https://mcp.uselovelace.com/mcp
  • Transport: Streamable HTTP
  • Authorization: The client follows the gateway's 401 challenge and Protected Resource Metadata discovery flow
bash
bash
claude mcp add lovelace --transport streamable-http \
  --url https://mcp.uselovelace.com/mcp

For full client-specific instructions, see Client Setup.

Step 2: Let the client authorize

On first connection, the gateway challenges the client and points it to:

https://mcp.uselovelace.com/.well-known/oauth-protected-resource

The client discovers Lovelace Accounts as the authorization server, completes OAuth 2.1 authorization, and sends bearer tokens on subsequent requests. See Authentication for the complete flow.

For programmatic clients, pass the token directly:

python
import os

TOKEN = os.environ["LOVELACE_TOKEN"]  # from your OAuth flow
typescript
const TOKEN = process.env.LOVELACE_TOKEN!; // from your OAuth flow

Step 3: Verify access

AI client — Ask your client:

text
List my Lovelace workspaces

Python:

python
import asyncio, json, os
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

TOKEN = os.environ["LOVELACE_TOKEN"]

async def main():
    async with streamablehttp_client(
        "https://mcp.uselovelace.com/mcp",
        headers={"Authorization": f"Bearer {TOKEN}"},
    ) as (read, write, _):
        async with ClientSession(read, write) as session:
            await session.initialize()
            result = await session.call_tool("lovelace_list_workspaces", {})
            workspaces = json.loads(result.content[0].text)
            for ws in workspaces["workspaces"]:
                print(ws["id"], ws["name"])

asyncio.run(main())

TypeScript:

typescript
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const TOKEN = process.env.LOVELACE_TOKEN!;

const client = new Client({ name: "my-app", version: "1.0.0" });
await client.connect(
  new StreamableHTTPClientTransport(
    new URL("https://mcp.uselovelace.com/mcp"),
    { requestInit: { headers: { Authorization: `Bearer ${TOKEN}` } } },
  ),
);

const result = await client.callTool("lovelace_list_workspaces", {});
const workspaces = JSON.parse((result.content[0] as { text: string }).text);
console.log(workspaces.workspaces);

That invokes lovelace_list_workspaces and returns the workspaces you can access.

Step 4: Launch an agent

Pick a workspace ID from the previous step, then spawn an agent:

AI client:

text
Spawn a Lovelace agent in workspace ws_abc123 to review our API performance bottlenecks

Python:

python
spawn_result = await session.call_tool("lovelace_spawn_agent", {
    "workspaceId": "ws_abc123",
    "agentType": "general",
    "task": "Review our API performance bottlenecks and list the top three",
})
agent = json.loads(spawn_result.content[0].text)
agent_id = agent["agentId"]
print(f"Spawned: {agent_id}")

TypeScript:

typescript
const spawnResult = await client.callTool("lovelace_spawn_agent", {
  workspaceId: "ws_abc123",
  agentType: "general",
  task: "Review our API performance bottlenecks and list the top three",
});
const agent = JSON.parse((spawnResult.content[0] as { text: string }).text);
const agentId = agent.agentId as string;
console.log(`Spawned: ${agentId}`);

Step 5: Check status and fetch results

AI client:

text
Check the status of Lovelace agent agent_123
Get the result for Lovelace agent agent_123

Python:

python
import asyncio

# Poll until complete
while True:
    status_result = await session.call_tool(
        "lovelace_get_agent_status", {"agentId": agent_id}
    )
    status = json.loads(status_result.content[0].text)
    if status["status"] in ("completed", "failed"):
        break
    await asyncio.sleep(2)

# Fetch output
output = await session.call_tool("lovelace_get_agent_result", {"agentId": agent_id})
print(json.loads(output.content[0].text))

TypeScript:

typescript
// Poll until complete
while (true) {
  const statusResult = await client.callTool("lovelace_get_agent_status", {
    agentId,
  });
  const status = JSON.parse((statusResult.content[0] as { text: string }).text);
  if (status.status === "completed" || status.status === "failed") break;
  await new Promise((r) => setTimeout(r, 2000));
}

// Fetch output
const output = await client.callTool("lovelace_get_agent_result", { agentId });
console.log(JSON.parse((output.content[0] as { text: string }).text));

Step 6: Read matching resources

You can also read resources directly:

  • lovelace://workspaces
  • lovelace://workspaces/ws_abc123
  • lovelace://knowledge/doc_456

What's next