Skip to content

ArcadeAI/tool-building-workshop

Repository files navigation

Build MCP tools with OAuth, deploy to the cloud, and connect them to AI agents.


Reminder App + Arcade MCP Tools + LangChain Agent

This repo demonstrates how to build a full-stack AI agent workflow with Arcade:

  1. reminder-app/ — A FastAPI app with OAuth 2.0 + PKCE that manages reminders
  2. reminder_tools/ — An Arcade MCP server that wraps the Reminder App API as agent-callable tools
  3. reminder-agent/ — A LangChain agent that uses the tools via Arcade Cloud, with a Flask user verifier

Architecture

┌──────────────┐     ┌──────────────────┐     ┌───────────────┐
│  LangChain   │────▶│   Arcade Cloud   │────▶│  Reminder App │
│    Agent     │     │  (MCP runtime)   │     │   (FastAPI)   │
└──────────────┘     └──────────────────┘     └───────────────┘
                            │
                     ┌──────┴───────┐
                     │ OAuth + PKCE │
                     │  (per-user)  │
                     └──────────────┘

Authorization Flow

When the agent calls a tool that requires OAuth, Arcade orchestrates a multi-step authorization flow across the agent, the user's browser, the custom verifier, and the reminder app:

sequenceDiagram
    participant Agent as LangChain Agent
    participant Arcade as Arcade Cloud
    participant Browser as User's Browser
    participant App as Reminder App<br/>(via ngrok)
    participant Verifier as Flask Verifier<br/>(localhost:4000)

    Note over Agent,Verifier: 1. Agent requests authorization
    Agent->>Arcade: tools.authorize(tool_name, user_id)
    Arcade-->>Agent: {status: "pending", url, auth_id}
    Note over Agent: Agent prints the URL for the user<br/>and starts polling
    Agent->>Arcade: auth.wait_for_completion(auth_id)

    Note over Browser,App: 2. User opens the URL → OAuth consent
    Browser->>App: GET /oauth/authorize (via ngrok URL)
    App-->>Browser: Login form (if not logged in)
    Browser->>App: POST /oauth/login
    App-->>Browser: Session cookie + redirect back
    App-->>Browser: Consent page
    Browser->>App: POST /oauth/authorize (approve)
    App-->>Browser: 302 → Arcade callback?code=xyz

    Note over Arcade,App: 3. Arcade exchanges the code for tokens
    Browser->>Arcade: GET /callback?code=xyz
    Arcade->>App: POST /oauth/token (code + PKCE verifier)
    App-->>Arcade: {access_token, refresh_token}

    Note over Browser,Verifier: 4. Arcade redirects to the custom verifier
    Arcade-->>Browser: 303 → /verify?flow_id=abc123
    Browser->>Verifier: GET /verify?flow_id=abc123

    Note over Verifier,Arcade: 5. Verifier confirms the user's identity
    Verifier->>Arcade: auth.confirm_user(flow_id, user_id=email)
    Arcade-->>Verifier: {auth_id}
    Verifier->>Arcade: auth.wait_for_completion(auth_id)
    Arcade-->>Verifier: status: "completed"
    Verifier-->>Browser: Redirect → /success

    Note over Agent,Verifier: 6. Agent's polling completes
    Arcade-->>Agent: wait_for_completion → "completed"

    Note over Agent,App: 7. Agent executes the tool
    Agent->>Arcade: tools.execute(tool_name, input, user_id)
    Arcade->>App: API call with Bearer token
    App-->>Arcade: Response data
    Arcade-->>Agent: Tool result
Loading

Prerequisites

  • Python 3.11+
  • uv — fast Python package manager
  • ngrok — tunnel your local server to the internet
  • Arcade account — for deploying MCP tools and managing OAuth
  • OpenAI API key — for the LangChain agent's LLM

Install uv if you don't have it:

curl -LsSf https://astral.sh/uv/install.sh | sh

Install the Arcade CLI:

uv tool install arcade-mcp
arcade login

1. Set Up the Reminder App

cd reminder-app
uv sync

Create a .env file (or export the variables):

# Optional — random defaults are generated if not set
JWT_SECRET=your-jwt-secret
SESSION_SECRET=your-session-secret
PUBLIC_URL=https://your-subdomain.ngrok-free.app

Start the app:

uv run uvicorn reminder_app.main:app --reload --port 8000

Start the ngrok tunnel (in a separate terminal):

./tunnel.sh

Seed the database with demo users and reminders:

uv run seed.py

This creates 3 users (alice, bob, charlie — password: asdf) with 10 reminders each. Or register manually via the web UI at http://localhost:8000.

Configure Arcade OAuth Provider

  1. Go to the Arcade Dashboard > Auth > Providers
  2. Add a Custom OAuth2 provider with ID reminder-app
  3. Get the endpoints and client credentials from:
    http://localhost:8000/api/clients/arcade-config
    
  4. Copy the authorization endpoint, token endpoint, client ID, client secret, and scopes into the Arcade form

2. Deploy the MCP Tools

cd reminder_tools
uv sync

Set the Reminder App URL as an Arcade secret:

arcade secret set REMINDER_APP_URL="https://your-subdomain.ngrok-free.app"

Deploy to Arcade Cloud:

arcade deploy -e src/reminder_tools/server.py

Available Tools

Tool Description Scopes
get_profile Get the authenticated user's profile profile:read
list_reminders List reminders with optional filters (priority, status, date range) reminders:read
search_reminders Search reminders by title with fuzzy matching reminders:read
get_reminder Get a single reminder by ID reminders:read
create_reminder Create a new reminder reminders:write
update_reminder Update an existing reminder reminders:write
mark_reminder_done Mark a reminder as done reminders:write
delete_reminder Delete a reminder reminders:write

3. Run the LangChain Agent

cd reminder-agent
uv sync

Create a .env file:

ARCADE_API_KEY=your-arcade-api-key
OPENAI_API_KEY=your-openai-api-key
ARCADE_USER_ID=your-email@example.com

Start the Flask verifier (in a separate terminal):

uv run verifier.py

Configure the verifier URL in the Arcade Dashboard > Auth > Settings as:

http://localhost:4000/verify

Run the agent:

uv run main.py

Example Prompts

You: add a reminder to buy groceries tomorrow, high priority
You: show me all my reminders
You: delete the groceries reminder
You: what's my profile?

Project Structure

tool-building/
├── reminder-app/          # FastAPI app with OAuth 2.0 provider
│   ├── src/reminder_app/
│   │   ├── main.py        # App entrypoint
│   │   ├── models.py      # SQLAlchemy models
│   │   ├── auth/          # Session + JWT auth
│   │   ├── api/           # REST endpoints (reminders, clients)
│   │   └── oauth/         # OAuth 2.0 + PKCE provider
│   ├── tunnel.sh          # ngrok tunnel script
│   └── pyproject.toml
│
├── reminder_tools/        # Arcade MCP server
│   ├── src/reminder_tools/
│   │   ├── server.py      # MCPApp entrypoint
│   │   ├── client.py      # HTTP client wrapper
│   │   ├── tools/         # Tool definitions (queries + commands)
│   │   └── models/        # Enums and TypedDict outputs
│   └── pyproject.toml
│
├── reminder-agent/        # LangChain agent
│   ├── main.py            # Agent with Arcade tool integration
│   ├── verifier.py        # Flask user verifier for Arcade auth
│   ├── globals.py         # Shared config
│   └── pyproject.toml
│
└── .gitignore

Resources

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors