diff --git a/app/en/_meta.tsx b/app/en/_meta.tsx
index 691941933..2aea69066 100644
--- a/app/en/_meta.tsx
+++ b/app/en/_meta.tsx
@@ -6,16 +6,19 @@ const meta: MetaRecord = {
copyPage: false,
},
},
+ // 1.0 Home Section
home: {
type: "page",
title: "Home",
- href: "/get-started",
+ href: "/home",
},
+ // MCP Servers Section
"mcp-servers": {
type: "page",
title: "MCP Servers",
href: "/mcp-servers",
},
+ // API & SDKs Section
references: {
type: "page",
title: "API & SDKs",
diff --git a/app/en/home/_meta.tsx b/app/en/home/_meta.tsx
index ff7c4d069..56d5559cb 100644
--- a/app/en/home/_meta.tsx
+++ b/app/en/home/_meta.tsx
@@ -1,4 +1,4 @@
-import { BadgeHelp, Globe, HeartPulse, Home, Shield } from "lucide-react";
+import { Home } from "lucide-react";
import type { MetaRecord } from "nextra";
function TitleWithIcon({
@@ -17,11 +17,6 @@ function TitleWithIcon({
}
export const meta: MetaRecord = {
- "*": {
- theme: {
- copyPage: true,
- },
- },
index: {
title: Home,
theme: {
@@ -31,129 +26,105 @@ export const meta: MetaRecord = {
copyPage: false,
},
},
- arcade: {
- title: Arcade.dev,
- href: "https://arcade.dev",
- },
- "-- Getting Started": {
+ "-- Get Started": {
type: "separator",
- title: "Using Arcade",
- },
- quickstart: {
- title: "Hosted Tools Quickstart",
- },
- "custom-mcp-server-quickstart": {
- title: "Build MCP Server QuickStart",
- },
- "api-keys": {
- title: "Get an API key",
- },
- "-- Authoring Tools": {
+ title: "Get Started",
+ },
+ "about-arcade": "About Arcade",
+ setup: "Setup",
+ quickstarts: "Quickstarts",
+ "common-use-cases": "Common use cases",
+ "example-agents": "Example agents",
+ toolkits: {
+ title: "Toolkits",
+ href: "/en/mcp-servers",
+ },
+ glossary: "Glossary",
+ faq: "FAQ",
+ "changelog-page": "Changelog",
+ "-- Guides": {
type: "separator",
- title: "Authoring Tools",
- },
- "build-tools": {
- title: "Build tools",
- },
- "evaluate-tools": {
- title: "Evaluate tools",
- },
- "serve-tools": {
- title: "Serve tools",
+ title: "Guides",
},
- "-- Agent Frameworks and MCP": {
+ "configure-arcade-section": "Configure Arcade",
+ "calling-tools": "Call tools",
+ "creating-tools": "Create tools",
+ "agent-frameworks": "Agent frameworks",
+ "sharing-with-end-users": "Share your agent with end-users",
+ "observability-platforms": "Observability platforms",
+ "deployment-hosting": "Deployment and hosting",
+ "security-section": "Security and compliance",
+ "-- Learn": {
type: "separator",
- title: "Agent Frameworks and MCP",
- },
- "mcp-clients": {
- title: "MCP Clients",
- },
- langchain: {
- title: "LangChain",
- },
- crewai: {
- title: "CrewAI",
- },
- "google-adk": {
- title: "Google ADK",
- },
- mastra: {
- title: "Mastra",
- },
- "oai-agents": {
- title: "OpenAI Agents",
+ title: "Learn",
},
- vercelai: {
- title: "Vercel AI",
- },
- "-- Core Concepts": {
+ "what-is-agent": "What's an agent",
+ "auth-and-secrets": "How do auth and secrets work",
+ "agentic-architecture": "Agentic architectures & workflows",
+ "-- API Reference": {
type: "separator",
- title: "Core Concepts",
- },
- "use-tools": {
- title: "Tool Calling",
+ title: "API Reference",
},
- auth: {
- title: "Authorization",
+ api: "API",
+ "arcade-mcp": "Arcade MCP (MCP server SDK)",
+ "arcade-clients": "Arcade clients",
+ // Hide auto-discovered directories
+ "api-keys": {
+ display: "hidden",
},
- "mcp-gateways": {
- title: "MCP Gateways",
+ "auth-providers": {
+ display: "hidden",
},
- "arcade-cli": {
- title: "Arcade CLI",
+ changelog: {
+ display: "hidden",
},
- "-- Hosting options": {
- type: "separator",
- title: "Hosting options",
+ "contact-us": {
+ display: "hidden",
},
"hosting-overview": {
- title: "Overview",
- },
- deployment: {
- title: "Deployment",
+ display: "hidden",
},
- "auth-providers": {
- title: "Customizing Auth",
+ "mcp-clients": {
+ display: "hidden",
},
- "-- Guides": {
- type: "separator",
- title: "Guides",
+ "mcp-gateway-quickstart": {
+ display: "hidden",
},
- glossary: {
- title: "Glossary",
+ "python-quickstart": {
+ display: "hidden",
},
- faq: {
- title: "FAQ",
+ "registry-early-access": {
+ display: "hidden",
},
- "compare-server-types": {
- title: "Compare Server Types",
+ "sample-agents": {
+ display: "hidden",
},
- "agentic-development": {
- title: "Agentic Development",
+ "tool-calling-intro": {
+ display: "hidden",
},
- changelog: {
- title: "Changelog",
+ guides: {
+ display: "hidden",
},
- "-- Registry": {
- type: "separator",
- title: "Registry",
+ "add-external-mcp": {
+ display: "hidden",
},
- "registry-early-access": {
- title: "Registry Early Access",
+ "build-custom-mcp": {
+ display: "hidden",
},
- "-- Resources": {
- type: "separator",
- title: "Resources",
+ concepts: {
+ display: "hidden",
},
- "contact-us": {
- title: Contact us,
+ examples: {
+ display: "hidden",
},
security: {
- title: Security,
+ display: "hidden",
+ },
+ "turn-api-to-mcp": {
+ display: "hidden",
},
- status: {
- title: Status,
- href: "https://status.arcade.dev/",
+ "why-agents-call-tools": {
+ display: "hidden",
},
};
diff --git a/app/en/home/auth/how-arcade-helps/page.mdx b/app/en/home/about-arcade/page.mdx
similarity index 99%
rename from app/en/home/auth/how-arcade-helps/page.mdx
rename to app/en/home/about-arcade/page.mdx
index d6d63cd69..3dcc757f9 100644
--- a/app/en/home/auth/how-arcade-helps/page.mdx
+++ b/app/en/home/about-arcade/page.mdx
@@ -75,4 +75,4 @@ console.log(response.output.value);
````
-
+
\ No newline at end of file
diff --git a/app/en/home/add-external-mcp/page.mdx b/app/en/home/add-external-mcp/page.mdx
new file mode 100644
index 000000000..265b51036
--- /dev/null
+++ b/app/en/home/add-external-mcp/page.mdx
@@ -0,0 +1,3 @@
+# Add external MCP Servers to Arcade
+
+Learn how to integrate external MCP servers with Arcade.
\ No newline at end of file
diff --git a/app/en/home/agent-frameworks/_meta.tsx b/app/en/home/agent-frameworks/_meta.tsx
new file mode 100644
index 000000000..135490cfc
--- /dev/null
+++ b/app/en/home/agent-frameworks/_meta.tsx
@@ -0,0 +1,10 @@
+export default {
+ vanilla: "Vanilla",
+ langchain: "LangGraph",
+ "oai-agents": "OpenAI agents",
+ crewai: "CrewAI",
+ "open-agents": "OpenAgents",
+ "google-adk": "Google ADK",
+ mastra: "Mastra",
+ vercelai: "Vercel AI",
+};
diff --git a/app/en/home/crewai/_meta.tsx b/app/en/home/agent-frameworks/crewai/_meta.tsx
similarity index 66%
rename from app/en/home/crewai/_meta.tsx
rename to app/en/home/agent-frameworks/crewai/_meta.tsx
index 67edee61a..74c33d663 100644
--- a/app/en/home/crewai/_meta.tsx
+++ b/app/en/home/agent-frameworks/crewai/_meta.tsx
@@ -8,8 +8,11 @@ const meta: MetaRecord = {
copyPage: true,
},
},
- "use-arcade-tools": {
- title: "Using Arcade tools",
+ "quickstart-python": {
+ title: "Quickstart (Python)",
+ },
+ "quickstart-typescript": {
+ title: "Quickstart (Typescript)",
},
"custom-auth-flow": {
title: "Custom auth flow",
diff --git a/app/en/home/crewai/custom-auth-flow/page.mdx b/app/en/home/agent-frameworks/crewai/custom-auth-flow/page.mdx
similarity index 100%
rename from app/en/home/crewai/custom-auth-flow/page.mdx
rename to app/en/home/agent-frameworks/crewai/custom-auth-flow/page.mdx
diff --git a/app/en/home/agent-frameworks/crewai/quickstart-python/page.mdx b/app/en/home/agent-frameworks/crewai/quickstart-python/page.mdx
new file mode 100644
index 000000000..4b5421156
--- /dev/null
+++ b/app/en/home/agent-frameworks/crewai/quickstart-python/page.mdx
@@ -0,0 +1,7 @@
+# Quickstart (Python)
+
+Documentation coming soon.
+
+## Overview
+
+This section will contain detailed information about using CrewAI with Python.
\ No newline at end of file
diff --git a/app/en/home/agent-frameworks/crewai/quickstart-typescript/page.mdx b/app/en/home/agent-frameworks/crewai/quickstart-typescript/page.mdx
new file mode 100644
index 000000000..92c76c387
--- /dev/null
+++ b/app/en/home/agent-frameworks/crewai/quickstart-typescript/page.mdx
@@ -0,0 +1,7 @@
+# Quickstart (Typescript)
+
+Documentation coming soon.
+
+## Overview
+
+This section will contain detailed information about using CrewAI with TypeScript.
\ No newline at end of file
diff --git a/app/en/home/agent-frameworks/google-adk/_meta.tsx b/app/en/home/agent-frameworks/google-adk/_meta.tsx
new file mode 100644
index 000000000..e0b5f430e
--- /dev/null
+++ b/app/en/home/agent-frameworks/google-adk/_meta.tsx
@@ -0,0 +1,4 @@
+export default {
+ "quickstart-python": "Quickstart (Python)",
+ "quickstart-typescript": "Quickstart (Typescript)",
+};
diff --git a/app/en/home/google-adk/use-arcade-tools/page.mdx b/app/en/home/agent-frameworks/google-adk/quickstart-python/page.mdx
similarity index 99%
rename from app/en/home/google-adk/use-arcade-tools/page.mdx
rename to app/en/home/agent-frameworks/google-adk/quickstart-python/page.mdx
index 6bede0d04..dd73b04c8 100644
--- a/app/en/home/google-adk/use-arcade-tools/page.mdx
+++ b/app/en/home/agent-frameworks/google-adk/quickstart-python/page.mdx
@@ -219,4 +219,4 @@ Now that you have integrated Arcade tools into your Google ADK application, you
- Try out multi-agent systems using different Arcade tools
- Build your own custom tools with the Arcade Tool SDK
-Enjoy exploring Arcade and building powerful AI-enabled Python applications!
+Enjoy exploring Arcade and building powerful AI-enabled Python applications!
\ No newline at end of file
diff --git a/app/en/home/agent-frameworks/google-adk/quickstart-typescript/page.mdx b/app/en/home/agent-frameworks/google-adk/quickstart-typescript/page.mdx
new file mode 100644
index 000000000..712d31c41
--- /dev/null
+++ b/app/en/home/agent-frameworks/google-adk/quickstart-typescript/page.mdx
@@ -0,0 +1,7 @@
+# Quickstart (Typescript)
+
+Documentation coming soon.
+
+## Overview
+
+This section will contain detailed information about using Google ADK with TypeScript.
\ No newline at end of file
diff --git a/app/en/home/agent-frameworks/langchain/_meta.tsx b/app/en/home/agent-frameworks/langchain/_meta.tsx
new file mode 100644
index 000000000..fb7cc7bbc
--- /dev/null
+++ b/app/en/home/agent-frameworks/langchain/_meta.tsx
@@ -0,0 +1,5 @@
+export default {
+ "quickstart-python": "Quickstart (Python)",
+ "quickstart-typescript": "Quickstart (Typescript)",
+ "using-langgraph-tools": "Using LangGraph tools",
+};
diff --git a/app/en/home/agent-frameworks/langchain/quickstart-python/page.mdx b/app/en/home/agent-frameworks/langchain/quickstart-python/page.mdx
new file mode 100644
index 000000000..4297b33b3
--- /dev/null
+++ b/app/en/home/agent-frameworks/langchain/quickstart-python/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Quickstart (Python)"
+description: "Get started with LangChain using Python"
+---
+
+# Quickstart (Python)
+
+Coming soon!
\ No newline at end of file
diff --git a/app/en/home/agent-frameworks/langchain/quickstart-typescript/page.mdx b/app/en/home/agent-frameworks/langchain/quickstart-typescript/page.mdx
new file mode 100644
index 000000000..c6e04ac5a
--- /dev/null
+++ b/app/en/home/agent-frameworks/langchain/quickstart-typescript/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Quickstart (Typescript)"
+description: "Get started with LangChain using TypeScript"
+---
+
+# Quickstart (Typescript)
+
+Coming soon!
\ No newline at end of file
diff --git a/app/en/home/langchain/auth-langchain-tools/page.mdx b/app/en/home/agent-frameworks/langchain/using-langgraph-tools/page.mdx
similarity index 99%
rename from app/en/home/langchain/auth-langchain-tools/page.mdx
rename to app/en/home/agent-frameworks/langchain/using-langgraph-tools/page.mdx
index 5107888db..73522f6bb 100644
--- a/app/en/home/langchain/auth-langchain-tools/page.mdx
+++ b/app/en/home/agent-frameworks/langchain/using-langgraph-tools/page.mdx
@@ -219,4 +219,4 @@ for await (const event of events) {
### Next Steps
-Now you're ready to explore more LangChain tools with Arcade. Try integrating additional MCP Servers and crafting more complex queries to enhance your AI workflows.
+Now you're ready to explore more LangChain tools with Arcade. Try integrating additional MCP Servers and crafting more complex queries to enhance your AI workflows.
\ No newline at end of file
diff --git a/app/en/home/mastra/_meta.tsx b/app/en/home/agent-frameworks/mastra/_meta.tsx
similarity index 53%
rename from app/en/home/mastra/_meta.tsx
rename to app/en/home/agent-frameworks/mastra/_meta.tsx
index 9c7bbf1eb..5df9193ec 100644
--- a/app/en/home/mastra/_meta.tsx
+++ b/app/en/home/agent-frameworks/mastra/_meta.tsx
@@ -8,14 +8,8 @@ const meta: MetaRecord = {
copyPage: true,
},
},
- overview: {
- title: "Overview",
- },
- "use-arcade-tools": {
- title: "Using Arcade tools",
- },
- "user-auth-interrupts": {
- title: "Managing user authorization",
+ "quickstart-typescript": {
+ title: "Quickstart (Typescript)",
},
};
diff --git a/app/en/home/agent-frameworks/mastra/quickstart-typescript/page.mdx b/app/en/home/agent-frameworks/mastra/quickstart-typescript/page.mdx
new file mode 100644
index 000000000..4d05ea8f5
--- /dev/null
+++ b/app/en/home/agent-frameworks/mastra/quickstart-typescript/page.mdx
@@ -0,0 +1,7 @@
+# Quickstart (Typescript)
+
+Documentation coming soon.
+
+## Overview
+
+This section will contain detailed information about using Mastra with TypeScript.
\ No newline at end of file
diff --git a/app/en/home/agent-frameworks/oai-agents/_meta.tsx b/app/en/home/agent-frameworks/oai-agents/_meta.tsx
new file mode 100644
index 000000000..e0b5f430e
--- /dev/null
+++ b/app/en/home/agent-frameworks/oai-agents/_meta.tsx
@@ -0,0 +1,4 @@
+export default {
+ "quickstart-python": "Quickstart (Python)",
+ "quickstart-typescript": "Quickstart (Typescript)",
+};
diff --git a/app/en/home/agent-frameworks/oai-agents/quickstart-python/page.mdx b/app/en/home/agent-frameworks/oai-agents/quickstart-python/page.mdx
new file mode 100644
index 000000000..2c7ba7b17
--- /dev/null
+++ b/app/en/home/agent-frameworks/oai-agents/quickstart-python/page.mdx
@@ -0,0 +1,7 @@
+# Quickstart (Python)
+
+Documentation coming soon.
+
+## Overview
+
+This section will contain detailed information about using OpenAI Agents with Python.
\ No newline at end of file
diff --git a/app/en/home/agent-frameworks/oai-agents/quickstart-typescript/page.mdx b/app/en/home/agent-frameworks/oai-agents/quickstart-typescript/page.mdx
new file mode 100644
index 000000000..17a8cd8f1
--- /dev/null
+++ b/app/en/home/agent-frameworks/oai-agents/quickstart-typescript/page.mdx
@@ -0,0 +1,7 @@
+# Quickstart (Typescript)
+
+Documentation coming soon.
+
+## Overview
+
+This section will contain detailed information about using OpenAI Agents with TypeScript.
\ No newline at end of file
diff --git a/app/en/home/agent-frameworks/open-agents/_meta.tsx b/app/en/home/agent-frameworks/open-agents/_meta.tsx
new file mode 100644
index 000000000..27ad4a394
--- /dev/null
+++ b/app/en/home/agent-frameworks/open-agents/_meta.tsx
@@ -0,0 +1,3 @@
+export default {
+ "quickstart-python": "Quickstart (Python)",
+};
diff --git a/app/en/home/agent-frameworks/open-agents/quickstart-python/page.mdx b/app/en/home/agent-frameworks/open-agents/quickstart-python/page.mdx
new file mode 100644
index 000000000..eb1d1c511
--- /dev/null
+++ b/app/en/home/agent-frameworks/open-agents/quickstart-python/page.mdx
@@ -0,0 +1,7 @@
+# Quickstart (Python)
+
+Documentation coming soon.
+
+## Overview
+
+This section will contain detailed information about using OpenAgents with Python.
diff --git a/app/en/home/agent-frameworks/vanilla/_meta.tsx b/app/en/home/agent-frameworks/vanilla/_meta.tsx
new file mode 100644
index 000000000..48bb45a29
--- /dev/null
+++ b/app/en/home/agent-frameworks/vanilla/_meta.tsx
@@ -0,0 +1,4 @@
+export default {
+ "python-quickstart": "Python Quickstart",
+ "typescript-quickstart": "Typescript Quickstart",
+};
diff --git a/app/en/home/agent-frameworks/vanilla/python-quickstart/page.mdx b/app/en/home/agent-frameworks/vanilla/python-quickstart/page.mdx
new file mode 100644
index 000000000..3b95648e1
--- /dev/null
+++ b/app/en/home/agent-frameworks/vanilla/python-quickstart/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Python Quickstart"
+description: "Get started with building vanilla Python agents using Arcade"
+---
+
+# Python Quickstart
+
+Coming soon!
\ No newline at end of file
diff --git a/app/en/home/agent-frameworks/vanilla/typescript-quickstart/page.mdx b/app/en/home/agent-frameworks/vanilla/typescript-quickstart/page.mdx
new file mode 100644
index 000000000..d5ee537c6
--- /dev/null
+++ b/app/en/home/agent-frameworks/vanilla/typescript-quickstart/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Typescript Quickstart"
+description: "Get started with building vanilla TypeScript agents using Arcade"
+---
+
+# Typescript Quickstart
+
+Coming soon!
\ No newline at end of file
diff --git a/app/en/home/agent-frameworks/vercelai/_meta.tsx b/app/en/home/agent-frameworks/vercelai/_meta.tsx
new file mode 100644
index 000000000..c1d2a14cd
--- /dev/null
+++ b/app/en/home/agent-frameworks/vercelai/_meta.tsx
@@ -0,0 +1,3 @@
+export default {
+ "quickstart-typescript": "Quickstart (Typescript)",
+};
diff --git a/app/en/home/vercelai/using-arcade-tools/page.mdx b/app/en/home/agent-frameworks/vercelai/quickstart-typescript/page.mdx
similarity index 99%
rename from app/en/home/vercelai/using-arcade-tools/page.mdx
rename to app/en/home/agent-frameworks/vercelai/quickstart-typescript/page.mdx
index 5471ee846..3aadc6c3d 100644
--- a/app/en/home/vercelai/using-arcade-tools/page.mdx
+++ b/app/en/home/agent-frameworks/vercelai/quickstart-typescript/page.mdx
@@ -151,4 +151,4 @@ You just need to change the MCP Server parameter in the `list` method. For examp
const slackToolkit = await arcade.tools.list({ toolkit: "Slack", limit: 30 });
```
-Browse our [complete MCP Server catalog](/mcp-servers) to see all available MCP Servers and their capabilities. Each MCP Server comes with pre-built tools that are ready to use with your AI applications. Arcade also is the best way to create your own custom tools and MCP Servers - learn more [here](/home/build-tools/create-a-mcp-server).
+Browse our [complete MCP Server catalog](/mcp-servers) to see all available MCP Servers and their capabilities. Each MCP Server comes with pre-built tools that are ready to use with your AI applications. Arcade also is the best way to create your own custom tools and MCP Servers - learn more [here](/home/build-tools/create-a-mcp-server).
\ No newline at end of file
diff --git a/app/en/home/agentic-architecture/_meta.tsx b/app/en/home/agentic-architecture/_meta.tsx
new file mode 100644
index 000000000..996c7ffd3
--- /dev/null
+++ b/app/en/home/agentic-architecture/_meta.tsx
@@ -0,0 +1,4 @@
+export default {
+ "kinds-of-agents": "Kinds of agents",
+ "architecture-patterns": "Architecture Patterns",
+};
diff --git a/app/en/home/agentic-architecture/architecture-patterns/_meta.tsx b/app/en/home/agentic-architecture/architecture-patterns/_meta.tsx
new file mode 100644
index 000000000..ce3462a52
--- /dev/null
+++ b/app/en/home/agentic-architecture/architecture-patterns/_meta.tsx
@@ -0,0 +1,3 @@
+export default {
+ "supervisor-architecture": "Supervisor architecture",
+};
diff --git a/app/en/home/agentic-architecture/architecture-patterns/supervisor-architecture/page.mdx b/app/en/home/agentic-architecture/architecture-patterns/supervisor-architecture/page.mdx
new file mode 100644
index 000000000..b3967a4bb
--- /dev/null
+++ b/app/en/home/agentic-architecture/architecture-patterns/supervisor-architecture/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Supervisor architecture"
+description: "Learn about supervisor architecture patterns"
+---
+
+# Supervisor architecture
+
+Coming soon!
diff --git a/app/en/home/agentic-architecture/kinds-of-agents/_meta.tsx b/app/en/home/agentic-architecture/kinds-of-agents/_meta.tsx
new file mode 100644
index 000000000..cdd141983
--- /dev/null
+++ b/app/en/home/agentic-architecture/kinds-of-agents/_meta.tsx
@@ -0,0 +1,4 @@
+export default {
+ "background-agents": "Background agents + secrets",
+ "agent-apps": "Agent apps + auth",
+};
diff --git a/app/en/home/agentic-architecture/kinds-of-agents/agent-apps/page.mdx b/app/en/home/agentic-architecture/kinds-of-agents/agent-apps/page.mdx
new file mode 100644
index 000000000..526c40a3a
--- /dev/null
+++ b/app/en/home/agentic-architecture/kinds-of-agents/agent-apps/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Agent apps + auth"
+description: "Learn about agent apps with authentication"
+---
+
+# Agent apps + auth
+
+Coming soon!
diff --git a/app/en/home/agentic-architecture/kinds-of-agents/background-agents/page.mdx b/app/en/home/agentic-architecture/kinds-of-agents/background-agents/page.mdx
new file mode 100644
index 000000000..9952fba8f
--- /dev/null
+++ b/app/en/home/agentic-architecture/kinds-of-agents/background-agents/page.mdx
@@ -0,0 +1,3 @@
+# Background Agents
+
+Coming soon.
diff --git a/app/en/home/api/page.mdx b/app/en/home/api/page.mdx
new file mode 100644
index 000000000..0336b606d
--- /dev/null
+++ b/app/en/home/api/page.mdx
@@ -0,0 +1,137 @@
+---
+title: "API Reference"
+description: "Complete reference documentation for Arcade's APIs and SDKs"
+---
+
+import { Button } from "@arcadeai/design-system";
+import Link from "next/link";
+
+# API Reference
+
+Complete reference documentation for Arcade's APIs and SDKs.
+
+
+ {/* Engine API Section */}
+
+
+ API
+
+
+ Arcade's REST API is for orchestrating tools, managing
+ authentication, and controlling agent workflows at runtime. Use
+ this API to integrate Arcade's tool execution and permission
+ management into your agent applications.
+
+
+
+
+
+
+ {/* MCP Server SDK Section */}
+
+
+ Arcade MCP (MCP Server SDK)
+
+
+ Arcade MCP, the secure framework for building MCP servers,
+ provides a FastAPI-like interface for creating custom tools and
+ exposing them through the standardized MCP protocol.
+
+
+
+
+
+
+ {/* Arcade Clients Section */}
+
+
+ Arcade Clients
+
+
+ Arcade provides clients for several languages. These clients make
+ it easy to use Arcade's tools within your agents and applications.
+
+ Note: MCP-compatible versions of these clients are in development
+ and will be documented soon.
+
+
+
diff --git a/app/en/home/arcade-clients/_meta.tsx b/app/en/home/arcade-clients/_meta.tsx
new file mode 100644
index 000000000..ad5938d7d
--- /dev/null
+++ b/app/en/home/arcade-clients/_meta.tsx
@@ -0,0 +1,6 @@
+export default {
+ "python-client": "Python client",
+ "javascript-typescript-client": "JavaScript / TypeScript client",
+ "go-client": "Go client",
+ "java-client": "Java client",
+};
diff --git a/app/en/home/arcade-clients/go-client/page.mdx b/app/en/home/arcade-clients/go-client/page.mdx
new file mode 100644
index 000000000..c1086d6cd
--- /dev/null
+++ b/app/en/home/arcade-clients/go-client/page.mdx
@@ -0,0 +1,3 @@
+# Go Client
+
+Coming soon.
\ No newline at end of file
diff --git a/app/en/home/arcade-clients/java-client/page.mdx b/app/en/home/arcade-clients/java-client/page.mdx
new file mode 100644
index 000000000..79548c9b6
--- /dev/null
+++ b/app/en/home/arcade-clients/java-client/page.mdx
@@ -0,0 +1,3 @@
+# Java Client
+
+Coming soon.
\ No newline at end of file
diff --git a/app/en/home/arcade-clients/javascript-typescript-client/page.mdx b/app/en/home/arcade-clients/javascript-typescript-client/page.mdx
new file mode 100644
index 000000000..586070099
--- /dev/null
+++ b/app/en/home/arcade-clients/javascript-typescript-client/page.mdx
@@ -0,0 +1,3 @@
+# JavaScript / TypeScript Client
+
+Coming soon.
\ No newline at end of file
diff --git a/app/en/home/arcade-clients/python-client/page.mdx b/app/en/home/arcade-clients/python-client/page.mdx
new file mode 100644
index 000000000..34d0231d3
--- /dev/null
+++ b/app/en/home/arcade-clients/python-client/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Python Client"
+description: "Arcade's Python client library for building agents"
+---
+
+# Python Client
+
+Coming soon!
\ No newline at end of file
diff --git a/app/en/home/arcade-mcp/page.mdx b/app/en/home/arcade-mcp/page.mdx
new file mode 100644
index 000000000..c5a8d7ea7
--- /dev/null
+++ b/app/en/home/arcade-mcp/page.mdx
@@ -0,0 +1,3 @@
+# Arcade MCP
+
+Coming soon.
diff --git a/app/en/home/auth-and-secrets/page.mdx b/app/en/home/auth-and-secrets/page.mdx
new file mode 100644
index 000000000..408e68b93
--- /dev/null
+++ b/app/en/home/auth-and-secrets/page.mdx
@@ -0,0 +1,3 @@
+# How do auth and secrets work?
+
+Coming soon.
diff --git a/app/en/home/auth/_meta.tsx b/app/en/home/auth/_meta.tsx
deleted file mode 100644
index 025a383e3..000000000
--- a/app/en/home/auth/_meta.tsx
+++ /dev/null
@@ -1,7 +0,0 @@
-export default {
- "how-arcade-helps": "How Arcade Helps",
- "auth-tool-calling": "Authorized Tool Calling",
- "tool-auth-status": "Checking Authorization Status",
- "call-third-party-apis-directly": "Direct Third-Party API Call",
- "secure-auth-production": "Secure Auth in Production",
-};
diff --git a/app/en/home/auth/how-arcade-helps.mdx b/app/en/home/auth/how-arcade-helps.mdx
deleted file mode 100644
index 12ea2984f..000000000
--- a/app/en/home/auth/how-arcade-helps.mdx
+++ /dev/null
@@ -1,78 +0,0 @@
----
-title: "How Arcade helps"
-description: "Learn how Arcade helps with auth and tool calling"
----
-
-import { Tabs } from "nextra/components";
-
-# How Arcade helps with Agent Authorization
-
-### The challenges that Arcade solves
-
-Applications that use models to perform tasks (_agentic applications_) commonly require access to sensitive data and services. Authentication complexities often hinder AI from performing tasks that require user-specific information, like what emails you recently received or what's coming up on your calendar.
-
-To retrieve this information, agentic applications need to be able to authenticate and authorize access to external services you use like Gmail or Google Calendar.
-
-Authenticating to retrieve information, however, is not the only challenge. Agentic applications also need to authenticate in order to **act** on your behalf - like sending an email or updating your calendar.
-
-Without auth, AI agents are severely limited in what they can do.
-
-### How Arcade solves this
-
-Arcade provides an authorization system that handles OAuth 2.0, API keys, and user tokens needed by AI agents to access external services through tools. This means your AI agents can now act on behalf of users securely and privately.
-
-With Arcade, developers can now create agents that can _act as the end users of their application_ to perform tasks like:
-
-- Creating a new Zoom meeting
-- Sending or reading email
-- Answering questions about files in Google Drive.
-
-### Auth permissions and scopes
-
-Each tool in Arcade's MCP Servers has a set of required permissions - or, more commonly referred to in OAuth2, **scopes**. For example, the [`Gmail.SendEmail`](/mcp-servers/productivity/gmail#gmailsendemail) tool requires the [`https://www.googleapis.com/auth/gmail.send`](https://developers.google.com/identity/protocols/oauth2/scopes#gmail) scope.
-
-A scope is what the user has authorized someone else (in this case, the AI agent) to do on their behalf. In any OAuth2-compatible service, each kind of action requires a different set of permissions. This gives the user fine-grained control over what data third-party services can access and what actions can be executed in their accounts.
-
-When a tool is called, the Arcade Engine will check if the user has granted the required permissions. If not, it will automatically prompt the user to authorize the tool, coordinating the OAuth2 flow with the service provider.
-
-### How to implement OAuth2-authorized tool calling
-
-To learn how Arcade allows for actions (tools) to be authorized through OAuth2 and how to implement it, check out [Authorized Tool Calling](/home/auth/auth-tool-calling).
-
-### Tools that don't require authorization
-
-Some tools, like [`GoogleSearch.Search`](/mcp-servers/search/google_search#googlesearchsearch), allow AI agents to retrieve information or perform actions without needing user-specific authorization.
-
-
-
-```python
-from arcadepy import Arcade
-
-client = Arcade(api_key="arcade_api_key") # or set the ARCADE_API_KEY env var
-
-# Use the GoogleSearch.Searchtool to perform a web search
-
-response = await client.tools.execute(
-tool_name="GoogleSearch.Search",
-input={"query": "Latest AI advancements"},
-)
-print(response.output.value)
-
-````
-
-
-```javascript
-import { Arcade } from "@arcadeai/arcadejs";
-
-const client = new Arcade(api_key="arcade_api_key"); // or set the ARCADE_API_KEY env var
-
-// Use the GoogleSearch.Search tool to perform a web search
-const response = await client.tools.execute({
- tool_name: "GoogleSearch.Search",
- input: { query: "Latest AI advancements" },
-});
-console.log(response.output.value);
-````
-
-
-
diff --git a/app/en/home/auth/secure-auth-production/page.mdx b/app/en/home/auth/secure-auth-production/page.mdx
deleted file mode 100644
index cf7f07789..000000000
--- a/app/en/home/auth/secure-auth-production/page.mdx
+++ /dev/null
@@ -1,219 +0,0 @@
----
-title: "Secure Auth in Production"
-description: "How to secure and brand your auth flows in production"
----
-
-# Secure and Brand the Auth Flow in Production
-
-To keep your users safe, Arcade.dev performs a user verification check when a tool is authorized for the first time. This check verifies that the user who is authorizing the tool is the same user who started the authorization flow, which helps prevent phishing attacks.
-
-There are two ways to secure your auth flows with Arcade.dev:
-- Use the **Arcade user verifier** for development (enabled by default)
-- Implement a **custom user verifier** for production
-
-This setting is configured in the [Auth > Settings section](https://api.arcade.dev/dashboard/auth/settings) of the Arcade Dashboard.
-
-
-## Use the Arcade user verifier
-
-If you're building a proof-of-concept app or a solo project, use the Arcade user verifier. This option requires no custom development and is on by default when you create a new Arcade.dev account.
-
-This setting is configured in the [Auth > Settings section](https://api.arcade.dev/dashboard/auth/settings) of the Arcade Dashboard:
-
-
-
-When you authorize a tool, you'll be prompted to sign in to your Arcade.dev account. If you are already signed in (to the Arcade Dashboard, for example), this verification will succeed silently.
-
-The Arcade.dev user verifier helps keep your auth flows secure while you are building and testing your agent or app. When you're ready to share your work with others, implement a [custom user verifier](#build-a-custom-user-verifier) so your users don't need to sign in to Arcade.dev.
-
-
- Arcade's default OAuth apps can *only* be used with the Arcade user verifier.
- If you are building a multi-user production app, you must obtain your own OAuth app credentials and add them to Arcade.
- For example, see our docs on [configuring Google auth in the Arcade Dashboard](/home/auth-providers/google#access-the-arcade-dashboard).
-
-
-## Build a custom user verifier
-
-In a production application or agent, end-users are verified by your code, not Arcade.dev. This allows you to fully control the user experience of the auth flow. To enable this, build a custom verifier route and add the URL to the Arcade Dashboard.
-
-When your users authorize a tool, Arcade.dev will redirect the user's browser to your verifier route with some information in the query string. Your custom verifier route must send a response back to Arcade.dev to confirm the user's ID.
-
-If you need help, join the [Implementing a custom user verifier](https://github.com/ArcadeAI/arcade-ai/discussions/486) GitHub discussion and we'll be happy to assist.
-
-import { Steps, Tabs, Callout } from "nextra/components";
-
-
-
-### Build a new route
-
-Create a public route in your app or API that can accept a browser redirect (HTTP 303) from Arcade.dev after a user has authorized a tool.
-
-The route must gather the following information:
-
-- The `flow_id` from the current URL's query string
-- The unique ID of the user currently signed in, commonly an ID from your application's database, an email address, or similar.
-
-How the user's unique ID is retrieved varies depending on how your app is built, but it is typically retrieved from a session cookie or other secure storage. It **must** match the user ID that your code specified at the start of the authorization flow.
-
-
-### Verify the user's identity
-
-Use the Arcade SDK (or our REST API) to verify the user's identity.
-
-
- Because this request uses your Arcade API key, it *must not* be made from the client side (a browser or desktop app). This code must be run on a server.
-
-
-
-
-```ts {13-16}
-import { Arcade } from '@arcadeai/arcadejs';
-
-const client = new Arcade(); // Looks for process.env.ARCADE_API_KEY by default
-
-// Within a server GET handler:
-// Validate required parameters
-if (!flow_id) {
- throw new Error('Missing required parameters: flow_id');
-}
-
-// Confirm the user's identity
-try {
- const result = await client.auth.confirmUser({
- flow_id: flow_id as string,
- user_id: user_id_from_your_app_session, // Replace with the user's ID
- });
-} catch (error) {
- console.error('Error during verification', 'status code:', error.status, 'data:', error.data);
- throw error;
-}
-```
-
-
-```python {12-15}
-from arcadepy import AsyncArcade
-
-client = AsyncArcade() # Looks for ARCADE_API_KEY environment variable by default
-
-# Within a server GET handler:
-# Validate required parameters
-if not flow_id:
- raise Exception("Missing required parameters: flow_id")
-
-# Confirm the user's identity
-try:
- result = await client.auth.confirm_user(
- flow_id=flow_id,
- user_id=user_id_from_your_app_session, # Replace with the user's ID
- )
-except Exception as error:
- print("Error during verification:", error)
- raise Exception("Failed to verify the request")
-```
-
-
-```text
-POST https://cloud.arcade.dev/api/v1/oauth/confirm_user
-Authorization: Bearer
-Content-Type: application/json
-
-{
- "flow_id": "",
- "user_id": ""
-}
-```
-
-
-
-**Valid Response**
-
-If the user's ID matches the ID specified at the start of the authorization flow, the response will contain some information about the auth flow. You can either:
-
-- Redirect the user's browser to Arcade's `next_uri`
-- Redirect to a different route in your application
-- Look up the auth flow's status in the Arcade API and render a success page
-
-
-
-
-```ts
-// Either redirect to result.next_uri, or render a success page:
-const authResponse = await client.auth.waitForCompletion(result.auth_id);
-
-if (authResponse.status === "completed") {
- return "Thanks for authorizing!";
-} else {
- return "Something went wrong. Please try again.";
-}
-```
-
-
-```python
-# Either redirect to result.next_uri, or render a success page:
-auth_response = await client.auth.wait_for_completion(result.auth_id)
-
-if auth_response.status == "completed":
- return "Thanks for authorizing!"
-else:
- return "Something went wrong. Please try again."
-```
-
-
-```text
-HTTP 200 OK
-Content-Type: application/json
-
-{
- // Can be used to look up the auth flow's status in the Arcade API
- "auth_id": "ac_2zKml...",
-
- // Optional: URL to redirect the user to after the authorization flow is complete
- "next_uri": "https://..."
-}
-```
-
-
-
-
-**Invalid Response**
-
-If the user's ID does not match the ID specified at the start of the authorization flow, the response will contain an error.
-
-
-
-```ts
-console.error('Error during verification', 'status code:', error.status, 'data:', error.data);
-throw error;
-```
-
-
-```python
-print("Error during verification:", error)
-raise Exception("Failed to verify the request")
-```
-
-
-```text
-HTTP 400 Bad Request
-Content-Type: application/json
-
-{
- "code": 400,
- "msg": "An error occurred during verification"
-}
-```
-
-
-
-### Add your custom verifier route to Arcade
-
-In the [Auth > Settings section](https://api.arcade.dev/dashboard/auth/settings) of the Arcade Dashboard, pick the **Custom verifier** option and add the URL of your verifier route.
-
-
-
-
- Arcade's default OAuth apps *only* support the Arcade user verifier.
- Authorization flows using Arcade's default OAuth apps will use the Arcade user verifier even if you have a custom verifier route set up.
-
-
-
diff --git a/app/en/home/blog/page.mdx b/app/en/home/blog/page.mdx
new file mode 100644
index 000000000..f0018edfe
--- /dev/null
+++ b/app/en/home/blog/page.mdx
@@ -0,0 +1,7 @@
+# Blog
+
+Read the latest news and insights from the Arcade team.
+
+## Latest Posts
+
+Coming soon.
\ No newline at end of file
diff --git a/app/en/home/build-custom-mcp/page.mdx b/app/en/home/build-custom-mcp/page.mdx
new file mode 100644
index 000000000..9de711c26
--- /dev/null
+++ b/app/en/home/build-custom-mcp/page.mdx
@@ -0,0 +1,3 @@
+# Build a custom MCP Server
+
+Create custom MCP servers that you or others can use in agents.
\ No newline at end of file
diff --git a/app/en/home/build-tools/_meta.tsx b/app/en/home/build-tools/_meta.tsx
deleted file mode 100644
index 88373013a..000000000
--- a/app/en/home/build-tools/_meta.tsx
+++ /dev/null
@@ -1,11 +0,0 @@
-export default {
- "create-a-mcp-server": "Create an MCP Server",
- "create-a-tool-with-auth": "Create a tool with auth",
- "create-a-tool-with-secrets": "Create a tool with secrets",
- "tool-context": "Tools and Context",
- "organize-mcp-server-tools": "Organize MCP server tools",
- "providing-useful-tool-errors": "Providing useful tool errors",
- "retry-tools-with-improved-prompt": "Retry tools with improved prompt",
- "call-tools-from-mcp-clients": "Call tools from MCP clients",
- "migrate-from-toolkits": "Migrate from toolkits",
-};
diff --git a/app/en/home/build-tools/create-a-mcp-server/page.mdx b/app/en/home/build-tools/create-a-mcp-server/page.mdx
deleted file mode 100644
index c069316ed..000000000
--- a/app/en/home/build-tools/create-a-mcp-server/page.mdx
+++ /dev/null
@@ -1,326 +0,0 @@
----
-title: "Creating an MCP Server with Arcade"
-description: "Learn how to create, test, deploy, and publish a custom MCP Server with Arcade"
----
-
-import { Steps, Tabs, Callout } from "nextra/components";
-
-# Creating an MCP Server with Arcade
-
-The `arcade_mcp_server` package is the secure framework to build and run MCP servers with your Arcade tools. It is easiest to use with the `arcade-mcp` package (Arcade's CLI) which can scaffold your MCP server with all the necessary files and dependencies, configure MCP Clients to connect to your server, deploy your server to the cloud, and more. This guide walks you through the complete process of creating a custom MCP server with Arcade.
-
-
-
-
-Build and run a secure MCP server with tools that you define.
-
-
-
-
-
-- The [`uv` package manager](https://docs.astral.sh/uv/getting-started/installation/)
-
-
-
-
-
-- How to run MCP servers with Arcade tools using the [`arcade_mcp_server`](/references/mcp/python/overview) package
-- How to use `arcade new` from the `arcade-mcp` CLI to create your server project with all necessary files and dependencies.
-- How to run your local MCP Server with the Arcade CLI and register it with the Arcade Engine so that your agent can find and use your tool.
-
-
-
-
-
-
-## Install the Arcade CLI
-
-In your terminal, run the following command to install the `arcade-mcp` package - Arcade's CLI:
-
-
-
-
-```bash
-uv tool install arcade-mcp
-```
-
-{" "}
-
-
- This will install the Arcade CLI as a [uv
- tool](https://docs.astral.sh/uv/guides/tools/#installing-tools), making it
- available system wide.
-
-
-
-
-
-
-```bash
-pip install arcade-mcp
-```
-
-
-
-
-## Create Your Server
-
-In your terminal, run the following command to scaffold a new MCP Server called `my_server`:
-
-```bash
-arcade new my_server
-cd my_server/src/my_server
-```
-
-This generates a Python module with the following structure:
-
-```bash
-my_server/
-├── src/
-│ └── my_server/
-│ ├── __init__.py
-│ ├── .env.example
-│ └── server.py
-└── pyproject.toml
-```
-
-1. **server.py** Main server file with MCPApp and example tools. It creates an `MCPApp`, defines tools with `@app.tool`, and will start the server with `app.run()` when the file is executed directly.
-1. **pyproject.toml** Dependencies and project configuration
-1. **.env.example** Example `.env` file containing a secret required by one of the generated tools in `server.py`. Environments are loaded on server start, so **if you update the `.env` file, you will need to restart your server.**
-
-```python filename="server.py" showLineNumbers
-#!/usr/bin/env python3
-"""my_server MCP server"""
-
-import sys
-from typing import Annotated
-
-import httpx
-from arcade_mcp_server import Context, MCPApp
-from arcade_mcp_server.auth import Reddit
-
-app = MCPApp(name="my_server", version="1.0.0", log_level="DEBUG")
-
-
-@app.tool
-def greet(name: Annotated[str, "The name of the person to greet"]) -> str:
- """Greet a person by name."""
- return f"Hello, {name}!"
-
-
-# To use this tool locally, you need to either set the secret in the .env file or as an environment variable
-@app.tool(requires_secrets=["MY_SECRET_KEY"])
-def whisper_secret(context: Context) -> Annotated[str, "The last 4 characters of the secret"]:
- """Reveal the last 4 characters of a secret"""
- # Secrets are injected into the context at runtime.
- # LLMs and MCP clients cannot see or access your secrets
- # You can define secrets in a .env file.
- try:
- secret = context.get_secret("MY_SECRET_KEY")
- except Exception as e:
- return str(e)
-
- return "The last 4 characters of the secret are: " + secret[-4:]
-
-# To use this tool locally, you need to install the Arcade CLI (uv tool install arcade-mcp)
-# and then run 'arcade login' to authenticate.
-@app.tool(requires_auth=Reddit(scopes=["read"]))
-async def get_posts_in_subreddit(
- context: Context, subreddit: Annotated[str, "The name of the subreddit"]
-) -> dict:
- """Get posts from a specific subreddit"""
- # Normalize the subreddit name
- subreddit = subreddit.lower().replace("r/", "").replace(" ", "")
-
- # Prepare the httpx request
- # OAuth token is injected into the context at runtime.
- # LLMs and MCP clients cannot see or access your OAuth tokens.
- oauth_token = context.get_auth_token_or_empty()
- headers = {
- "Authorization": f"Bearer {oauth_token}",
- "User-Agent": "finally-mcp-server",
- }
- params = {"limit": 5}
- url = f"https://oauth.reddit.com/r/{subreddit}/hot"
-
- # Make the request
- async with httpx.AsyncClient() as client:
- response = await client.get(url, headers=headers, params=params)
- response.raise_for_status()
-
- # Return the response
- return response.json()
-
-# Run with specific transport
-if __name__ == "__main__":
- # Get transport from command line argument, default to "stdio"
- # - "stdio" (default): Standard I/O for Claude Desktop, CLI tools, etc.
- # Supports tools that require_auth or require_secrets out-of-the-box
- # - "http": HTTPS streaming for Cursor, VS Code, etc.
- # Does not support tools that require_auth or require_secrets unless the server is deployed
- # using 'arcade deploy' or added in the Arcade Developer Dashboard with 'Arcade' server type
- transport = sys.argv[1] if len(sys.argv) > 1 else "stdio"
-
- # Run the server
- app.run(transport=transport, host="127.0.0.1", port=8000)
-```
-
-## Setup the secrets in your environment
-
-Secrets are sensitive strings like passwords, API keys, or other tokens that grant access to a protected resource or API. Arcade includes the "whisper_secret" tool that requires a secret key to be set in your environment. If the secret is not set, the tool will return an error.
-
-
-
-You can create a `.env` file at the same directory as your entrypoint file (`server.py`) and add your secret:
-
-```env filename=".env"
-MY_SECRET_KEY="my-secret-value"
-```
-
-The generated project includes a `.env.example` file with the secret key name and example value.
-You can rename it to `.env` to start using it.
-
-```bash
-mv .env.example .env
-```
-
-
-
-You can set the environment variable in your terminal directly with this command:
-
-```bash
-export MY_SECRET_KEY="my-secret-value"
-```
-
-
-
-
-## Connect to Arcade to unlock authorized tool calling
-
-Since the Reddit tool accesses information only available to your Reddit account, you'll need to authorize it. For this, you'll need to create an Arcade account and connect to it from the terminal, run:
-
-```bash
-arcade login
-```
-
-Follow the instructions in your browser, and once you've finished, your terminal will be connected to your Arcade account.
-
-## Run your MCP Server
-
-Run your MCP Server using one of the following commands in your terminal:
-
-
-
-
-
-```bash
-uv run server.py stdio
-```
-
-
- When using the stdio transport, MCP clients typically launch the MCP server as
- a subprocess. Because of this, the server may run in a different environment
- and not have access to secrets defined in your local `.env` file. Please refer
- to the [create a tool with
- secrets](/home/build-tools/create-a-tool-with-secrets) guide for more
- information.
-
-
-
-
-
-```bash
-uv run server.py http
-```
-
-For HTTP transport, view your server's API docs at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
-
-
- For security reasons, Local HTTP servers do not currently support tool-level
- authorization and secrets. If you need to use tool-level authorization or
- secrets locally, you should use the stdio transport and configure the Arcade
- API key and secrets in your MCP connection settings. Otherwise, if you intend
- to expose your HTTP MCP server to the public internet with tool-level
- authorization and secrets, please follow the [deploying to the cloud with
- Arcade Deploy](/home/serve-tools/arcade-deploy) guide or the [on-prem MCP
- server](/home/deployment/on-prem-mcp) guide for secure remote deployment.
-
-
-
-
-
-You should see output like this in your terminal:
-
-```bash
-2025-11-03 13:46:11.041 | DEBUG | arcade_mcp_server.mcp_app:add_tool:242 - Added tool: greet
-2025-11-03 13:46:11.042 | DEBUG | arcade_mcp_server.mcp_app:add_tool:242 - Added tool: whisper_secret
-2025-11-03 13:46:11.043 | DEBUG | arcade_mcp_server.mcp_app:add_tool:242 - Added tool: get_posts_in_subreddit
-INFO | 13:46:11 | arcade_mcp_server.mcp_app:299 | Starting my_server v1.0.0 with 3 tools
-```
-
-## Configure your MCP Client(s)
-
-Now you can connect MCP Clients to your MCP server:
-
-
-
-
- ```bash
- # Configure Cursor to use your MCP server with the default transport (stdio)
- arcade configure cursor
-
- # Configure Cursor to use your MCP server with the http transport
- arcade configure cursor --transport http
- ```
-
-
-
-
- ```bash
- # Configure VS Code to use your MCP server with the default transport (stdio)
- arcade configure vscode
-
- # Configure VS Code to use your MCP server with the http transport
- arcade configure vscode --transport http
- ```
-
-
-
-
- ```bash
- # Configure Claude Desktop to use your MCP server with the default transport (stdio)
- arcade configure claude
-
- # Configure Claude Desktop to use your MCP server with the http transport
- arcade configure claude --transport http
- ```
-
-
-
-
-That's it! Your MCP server is running and connected to your AI assistant.
-
-
-
-## Key takeaways
-
-- **Minimal Setup** Create `MCPApp`, define tools with `@app.tool`, and run with `app.run()`
-- **Direct Execution** Run your server file directly with `uv run` or `python`
-- **Transport Flexibility** Works with both stdio and HTTP
-- **Type Annotations** Use `Annotated` from the builtin typing library to provide descriptions to the language model for parameters and return values
-- **Tool Docstrings** Use docstrings to provide a description of a tool to the language model
-- **Command Line Arguments** Pass transport type as command line argument
-
-### Next steps
-
-- **Create custom tools that use auth**: [Learn how to create tools with authorization](/home/build-tools/create-a-tool-with-auth)
-- **Create custom tools that use secrets**: [Learn how to create tools with secrets](/home/build-tools/create-a-tool-with-secrets)
-- **Learn the capabilities of the `Context` object**: [Understanding the Context object](/home/build-tools/tool-context)
-- **Evaluate your tools**: [Explore how to evaluate tool performance](/home/evaluate-tools/why-evaluate-tools)
-- **Deploy your MCP server**: [Learn how to deploy your MCP server](/home/serve-tools/arcade-deploy)
diff --git a/app/en/home/calling-tools/_meta.tsx b/app/en/home/calling-tools/_meta.tsx
new file mode 100644
index 000000000..fea9fb6e5
--- /dev/null
+++ b/app/en/home/calling-tools/_meta.tsx
@@ -0,0 +1,33 @@
+export default {
+ overview: "Overview",
+ "error-handling": "Handle errors",
+ "-- In 3rd party applications": {
+ type: "separator",
+ title: "In 3rd party applications",
+ },
+ "third-party-apps": "Call a tool in your IDEs, MCP clients, or agents",
+ "mcp-clients": "Connect to a MCP client",
+ "evaluation-suite": "Create an evaluation suite to test tools",
+ "mcp-gateway-auth": "Add authentication to your MCP gateway",
+ "-- In custom applications": {
+ type: "separator",
+ title: "In custom applications",
+ },
+ "calling-tools-custom-apps": "Call tools in your custom apps",
+ "authorized-tool-calling": "Authorize tool calls",
+ "auth-status-check": "Check authorization status",
+ "tool-formats": "Tool formats",
+ "connect-arcade-llm": "Connect Arcade tools to your LLM",
+ "ensure-consistent-evals": "Ensure consistent tool calls with evals",
+ "-- Trigger tool calls": {
+ type: "separator",
+ title: "Trigger tool calls",
+ },
+ "background-agents": "Set up a background agent using events",
+ "scheduled-executions": "Set up scheduled tool executions",
+ "-- Reference": {
+ type: "separator",
+ title: "Reference",
+ },
+ "direct-api-call": "Direct third-party API call",
+};
diff --git a/app/en/home/auth/tool-auth-status/page.mdx b/app/en/home/calling-tools/auth-status-check/page.mdx
similarity index 100%
rename from app/en/home/auth/tool-auth-status/page.mdx
rename to app/en/home/calling-tools/auth-status-check/page.mdx
diff --git a/app/en/home/auth/auth-tool-calling/page.mdx b/app/en/home/calling-tools/authorized-tool-calling/page.mdx
similarity index 99%
rename from app/en/home/auth/auth-tool-calling/page.mdx
rename to app/en/home/calling-tools/authorized-tool-calling/page.mdx
index 2143e4714..cc78cb73a 100644
--- a/app/en/home/auth/auth-tool-calling/page.mdx
+++ b/app/en/home/calling-tools/authorized-tool-calling/page.mdx
@@ -30,14 +30,14 @@ from arcadepy import Arcade
client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
-````
+```
```js
import Arcade from "@arcadeai/arcadejs";
const client = new Arcade(); // Automatically finds the `ARCADE_API_KEY` env variable
-````
+```
@@ -83,7 +83,7 @@ if (authResponse.status !== "completed") {
console.log(`Click this link to authorize: ${authResponse.url}`);
}
-````
+```
@@ -123,7 +123,7 @@ emails_response = client.tools.execute(
user_id=USER_ID,
)
print(emails_response)
-````
+```
diff --git a/app/en/home/calling-tools/background-agents/page.mdx b/app/en/home/calling-tools/background-agents/page.mdx
new file mode 100644
index 000000000..fb001edcf
--- /dev/null
+++ b/app/en/home/calling-tools/background-agents/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Set up a background agent using events"
+description: "Learn how to set up a background agent using events"
+---
+
+# Set up a background agent using events
+
+Coming soon!
diff --git a/app/en/home/calling-tools/calling-tools-custom-apps/page.mdx b/app/en/home/calling-tools/calling-tools-custom-apps/page.mdx
new file mode 100644
index 000000000..6616015f2
--- /dev/null
+++ b/app/en/home/calling-tools/calling-tools-custom-apps/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Calling tools in your custom apps"
+description: "Learn how to integrate and call tools within your custom applications"
+---
+
+# Calling tools in your custom apps
+
+Coming soon!
\ No newline at end of file
diff --git a/app/en/home/calling-tools/connect-arcade-llm/page.mdx b/app/en/home/calling-tools/connect-arcade-llm/page.mdx
new file mode 100644
index 000000000..679027ce6
--- /dev/null
+++ b/app/en/home/calling-tools/connect-arcade-llm/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Connecting Arcade tools to your LLM"
+description: "Learn how to connect Arcade tools to your LLM"
+---
+
+# Connecting Arcade tools to your LLM
+
+Coming soon!
diff --git a/app/en/home/auth/call-third-party-apis-directly/page.mdx b/app/en/home/calling-tools/direct-api-call/page.mdx
similarity index 99%
rename from app/en/home/auth/call-third-party-apis-directly/page.mdx
rename to app/en/home/calling-tools/direct-api-call/page.mdx
index fbc3d8c23..baf6e256c 100644
--- a/app/en/home/auth/call-third-party-apis-directly/page.mdx
+++ b/app/en/home/calling-tools/direct-api-call/page.mdx
@@ -90,7 +90,7 @@ provider="google",
scopes=["https://www.googleapis.com/auth/gmail.readonly"],
)
-````
+```
```javascript
@@ -103,7 +103,7 @@ const user_id = "{arcade_user_id}";
let auth_response = await client.auth.start(user_id, "google", {
scopes: ["https://www.googleapis.com/auth/gmail.readonly"],
});
-````
+```
@@ -165,7 +165,7 @@ gmail.users().messages().list(userId="me").execute().get("messages", [])
print(email_messages)
-````
+```
```javascript
@@ -180,7 +180,7 @@ const response = await gmail.users.messages.list({
const email_messages = response.data.messages || [];
console.log(email_messages);
-````
+```
diff --git a/app/en/home/calling-tools/ensure-consistent-evals/page.mdx b/app/en/home/calling-tools/ensure-consistent-evals/page.mdx
new file mode 100644
index 000000000..18987cf4d
--- /dev/null
+++ b/app/en/home/calling-tools/ensure-consistent-evals/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Ensure consistent tool calls with evals"
+description: "Learn how to ensure consistent tool calls with evaluations"
+---
+
+# Ensure consistent tool calls with evals
+
+Coming soon!
diff --git a/app/en/home/use-tools/error-handling/page.mdx b/app/en/home/calling-tools/error-handling/page.mdx
similarity index 99%
rename from app/en/home/use-tools/error-handling/page.mdx
rename to app/en/home/calling-tools/error-handling/page.mdx
index f9e83926c..9f3f7a649 100644
--- a/app/en/home/use-tools/error-handling/page.mdx
+++ b/app/en/home/calling-tools/error-handling/page.mdx
@@ -175,4 +175,4 @@ As of now, MCP Clients do not return structured error information, only an error
## Building tools with error handling
-To learn more about how to build tools with error handling, see the [Build Tools](/home/build-tools/providing-useful-tool-errors) section.
+To learn more about how to build tools with error handling, see the [Build Tools](/home/build-tools/providing-useful-tool-errors) section.
\ No newline at end of file
diff --git a/app/en/home/calling-tools/evaluation-suite/page.mdx b/app/en/home/calling-tools/evaluation-suite/page.mdx
new file mode 100644
index 000000000..38bf6fef8
--- /dev/null
+++ b/app/en/home/calling-tools/evaluation-suite/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Creating an evaluation suite to test tools"
+description: "Learn how to create evaluation suites to test your tools effectively"
+---
+
+# Creating an evaluation suite to test tools
+
+Coming soon!
\ No newline at end of file
diff --git a/app/en/home/calling-tools/mcp-clients/_meta.tsx b/app/en/home/calling-tools/mcp-clients/_meta.tsx
new file mode 100644
index 000000000..14b13976f
--- /dev/null
+++ b/app/en/home/calling-tools/mcp-clients/_meta.tsx
@@ -0,0 +1,5 @@
+export default {
+ cursor: "Cursor",
+ "claude-desktop": "Claude desktop",
+ "visual-studio-code": "Visual Studio Code",
+};
diff --git a/app/en/home/calling-tools/mcp-clients/claude-desktop/page.mdx b/app/en/home/calling-tools/mcp-clients/claude-desktop/page.mdx
new file mode 100644
index 000000000..3564263cd
--- /dev/null
+++ b/app/en/home/calling-tools/mcp-clients/claude-desktop/page.mdx
@@ -0,0 +1,42 @@
+import { Steps, Tabs, Callout } from "nextra/components";
+import { SignupLink } from "@/app/_components/analytics";
+
+# Use Arcade with Claude Desktop
+
+In this guide, you'll learn how to connect Claude Desktop to a local Arcade server.
+
+
+
+### Prerequisites
+
+1. Create an Arcade account
+2. Get an [Arcade API key](/home/api-keys)
+3. Create an [Arcade MCP Gateway](/home/mcp-gateways) and select the tools you want to use
+
+### Set up Claude Desktop
+
+1. Download and open [Claude Desktop](https://claude.ai/download)
+2. Claude Menu --> "Settings" --> "Developer" --> "Edit Config"
+3. Follow the guide [here](https://support.claude.com/en/articles/11175166-getting-started-with-custom-connectors-using-remote-mcp)
+4. Open the configuration file and replace the file contents with this:
+ * Give your MCP server a name, like `mcp-arcade`
+ * Use the the URL of your MCP Gateway.
+ * Add the API key as the bearer token within the `Authorization` header, and the email address that you used to sign up for the Arcade account as the `Arcade-User-ID` header
+
+```json
+{
+ "mcpServers": {
+ "arcade-mcp": {
+ "url": "https://api.arcade.dev/mcp/",
+ "headers": {
+ "Authorization": "Bearer {arcade_api_key}",
+ "Arcade-User-ID": "{arcade_user_id}"
+ }
+ }
+ }
+}
+```
+
+5. Restart Claude Desktop. Upon restarting, you should have access to the Arcade tools you installed.
+
+
diff --git a/app/en/home/calling-tools/mcp-clients/cursor/page.mdx b/app/en/home/calling-tools/mcp-clients/cursor/page.mdx
new file mode 100644
index 000000000..d22dc925f
--- /dev/null
+++ b/app/en/home/calling-tools/mcp-clients/cursor/page.mdx
@@ -0,0 +1,48 @@
+import { Steps, Callout } from "nextra/components";
+import { SignupLink } from "@/app/_components/analytics";
+
+
+# Use Arcade in Cursor
+
+In this guide, you'll learn how to connect Cursor to an Arcade MCP Gateway.
+
+
+
+### Prerequisites
+
+1. Create an Arcade account
+2. Get an [Arcade API key](/home/api-keys)
+3. Create an [Arcade MCP Gateway](/home/mcp-gateways) and select the tools you want to use
+
+### Set up Cursor
+
+3. Download and open [Cursor](https://cursor.com/download)
+4. Open the command palette and select **Open MCP Settings...**
+5. Choose **HTTP**
+6. Paste the URL of your MCP Gateway
+7. Give your MCP server a name, like `mcp-arcade`
+8. Add the API key as the bearer token within the `Authorization` header, and the email address that you used to sign up for the Arcade account as the `Arcade-User-ID` header
+
+Cursor will update your `settings.json` file with the following
+
+```json
+{
+ "mcpServers": {
+ "mcp-arcade": {
+ "url": "https://api.arcade.dev/mcp/",
+ "headers": {
+ "Authorization": "Bearer {arcade_api_key}",
+ "Arcade-User-ID": "{arcade_user_id}"
+ }
+ }
+ }
+}
+```
+
+### Try it out
+
+1. Open the chat pane (typically command-l)
+1. Make sure you are in **Agent** mode
+1. Ask the agent to use a tool!
+
+
diff --git a/app/en/home/calling-tools/mcp-clients/visual-studio-code/page.mdx b/app/en/home/calling-tools/mcp-clients/visual-studio-code/page.mdx
new file mode 100644
index 000000000..bcb494226
--- /dev/null
+++ b/app/en/home/calling-tools/mcp-clients/visual-studio-code/page.mdx
@@ -0,0 +1,42 @@
+import { Steps, Callout } from "nextra/components";
+import { SignupLink } from "@/app/_components/analytics";
+
+# Use Arcade in Visual Studio Code
+
+In this guide, you'll learn how to connect Visual Studio Code to an Arcade MCP Gateway.
+
+
+
+### Prerequisites
+
+1. Create an Arcade account
+2. Get an [Arcade API key](/home/api-keys)
+3. Create an [Arcade MCP Gateway](/home/mcp-gateways) and select the tools you want to use
+
+### Set up Visual Studio Code
+
+3. Download and open [Visual Studio Code](https://code.visualstudio.com/download) (version 1.100.0 or higher)
+4. Open the command palette and select **MCP: Add Server...**
+5. Choose **HTTP**
+6. Paste the URL of your MCP Gateway. You may see a warning about Dynamic Client Registration. You can ignore this.
+7. Give your MCP server a name, like `mcp-arcade`
+8. Add the API key as the bearer token within the `Authorization` header, and the email address that you used to sign up for the Arcade account as the `Arcade-User-ID` header
+
+Visual Studio Code will update your `mcp.json` file, but you will manually need to add the headers above:
+
+```json
+{
+ "servers": {
+ "mcp-arcade": {
+ "url": "https://api.arcade.dev/mcp/",
+ "type": "http",
+ "headers": {
+ "Authorization": "Bearer {arcade_api_key}",
+ "Arcade-User-ID": "{arcade_user_id}"
+ }
+ }
+ }
+}
+```
+
+
diff --git a/app/en/home/calling-tools/mcp-gateway-auth/page.mdx b/app/en/home/calling-tools/mcp-gateway-auth/page.mdx
new file mode 100644
index 000000000..610325536
--- /dev/null
+++ b/app/en/home/calling-tools/mcp-gateway-auth/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Adding authentication to your MCP Gateway"
+description: "Learn how to add authentication to your MCP Gateway setup"
+---
+
+# Adding authentication to your MCP Gateway
+
+Coming soon!
\ No newline at end of file
diff --git a/app/en/home/use-tools/tools-overview/page.mdx b/app/en/home/calling-tools/overview/page.mdx
similarity index 99%
rename from app/en/home/use-tools/tools-overview/page.mdx
rename to app/en/home/calling-tools/overview/page.mdx
index 231f09542..113870fc5 100644
--- a/app/en/home/use-tools/tools-overview/page.mdx
+++ b/app/en/home/calling-tools/overview/page.mdx
@@ -94,4 +94,4 @@ This process shows the general outline of the Tool Augmented Generation (TAG) pr
### Next steps
- Explore the [MCP Servers](/mcp-servers) available on Arcade
-- Build your own [custom MCP Server](/home/build-tools/create-a-mcp-server)
+- Build your own [custom MCP Server](/home/build-tools/create-a-mcp-server)
\ No newline at end of file
diff --git a/app/en/home/calling-tools/scheduled-executions/page.mdx b/app/en/home/calling-tools/scheduled-executions/page.mdx
new file mode 100644
index 000000000..f9c311b2e
--- /dev/null
+++ b/app/en/home/calling-tools/scheduled-executions/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Set up scheduled tool executions"
+description: "Learn how to set up scheduled tool executions"
+---
+
+# Set up scheduled tool executions
+
+Coming soon!
diff --git a/app/en/home/calling-tools/third-party-apps/page.mdx b/app/en/home/calling-tools/third-party-apps/page.mdx
new file mode 100644
index 000000000..b7249ea0d
--- /dev/null
+++ b/app/en/home/calling-tools/third-party-apps/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Call a tool in your IDEs, MCP clients, or agents"
+description: "Learn how to call tools in third-party applications"
+---
+
+# Call a tool in your IDEs, MCP clients, or agents
+
+See our [quickstart guide](/home/quickstarts/call-tool-personal-agent) to learn how to call Arcade tools in third-party applications like IDEs, MCP clients, or agent frameworks.
diff --git a/app/en/home/use-tools/get-tool-definitions/page.mdx b/app/en/home/calling-tools/tool-formats/page.mdx
similarity index 100%
rename from app/en/home/use-tools/get-tool-definitions/page.mdx
rename to app/en/home/calling-tools/tool-formats/page.mdx
diff --git a/app/en/home/changelog-page/page.mdx b/app/en/home/changelog-page/page.mdx
new file mode 100644
index 000000000..abf6fdd55
--- /dev/null
+++ b/app/en/home/changelog-page/page.mdx
@@ -0,0 +1,520 @@
+---
+title: "Changelog"
+description: "What's new at Arcade.dev"
+---
+
+import { Callout } from "nextra/components";
+
+# Changelog
+
+_Here's what's new at Arcade.dev!_
+
+## 2025-12-05
+
+
+[A medium-severity security vulnerability](https://github.com/ArcadeAI/arcade-mcp/security/advisories/GHSA-g2jx-37x6-6438) has been identified and fixed in the Arcade MCP. Please upgrade to version 1.9.1 or higher of `arcade-mcp-server` to fix this issue.
+
+
+
+As of December 1, 2025, we have migrated the MCP servers deployed via `arcade deploy` to our own managed infrastructure. Please ensure you have the latest version of the arcade CLI installed and that you are using the latest version of the `arcade-mcp-server` package.
+
+
+**Arcade MCP Servers**
+- `[feature - 🚀]` Add tools for project management, pull request, and projects to the Github MCP Server
+- `[feature - 🚀]` Add Optimized Linear toolkit
+- `[feature - 🚀]` Add Optimized Ashby toolkit
+- `[feature - 🚀]` Shorten Jira tool names exceeding Cursor limit
+- `[feature - 🚀]` Host both the latest and previous major version of optimized Arcade toolkits for backwards compatibility
+
+**Arcade MCP**
+- `[feature - 🚀]` Add startup warnings for missing secrets
+- `[bugfix - 🐛]` Handle client disconnect for large payloads
+- `[bugfix - 🐛]` Only serve worker endpoints if `ARCADE_WORKER_SECRET` environment variable is set
+- `[maintenance - 🔧]` Increase Worker Termination Grace Period
+
+**Arcade CLI**
+- `[feature - 🚀]` CLI config and WhoAmI endpoints
+
+**Platform and Engine**
+- `[feature - 🚀]` New users can be invited to projects by email, regardless of whether they have an account on Arcade, or already belong to your organization.
+- `[maintenance - 🔧]` Allows users to update organization and project names\
+
+
+## 2025-11-21
+
+**MCP Servers**
+- `[feature - 🚀]` Updated Github MCP Sever to support projects, issues, and pull requests
+
+**Platform and Engine**
+- `[feature - 🚀]` Invite users to projects by email
+
+## 2025-11-14
+
+**MCP Servers**
+- `[feature - 🚀]` Customer.io Starter MCP Servers added
+- `[feature - 🚀]` Intercom Starter MCP Server added
+
+**Arcade MCP**
+- `[maintenance - 🔧]` Do not require entrypoint for `arcade configure` for HTTP server
+
+**Platform and Engine**
+- `[maintenance - 🔧]` Update `arcade deploy` command to support MCP Servers built with `arcade-mcp`
+- `[maintenance - 🔧]` Improve performance of tool execution with large collections of tools
+
+## 2025-11-07
+
+**Toolkits**
+- `[feature - 🚀]` AddedMailchimp market toolkit
+- `[feature - 🚀]` Enhanced Hubspot Marketing & CRM toolkit
+
+**MCP Servers**
+- `[maintenance - 🔧]` Better Handling of MCP-specific `Context` usage for managed servers
+- `[maintenance - 🔧]` Set server version for `@app.tool` and `MCPApp.add_tool`
+- `[maintenance - 🔧]` Better errors in UI and CLI if `arcade deploy` fails
+t
+**Platform and Engine**
+- `[feature - 🚀]` Optional customization of OAuth request header format for upstrem MCP Servers
+- `[bugfix - 🐛]` Fix MCP token refresh
+- `[maintenance - 🔧]` Add log viewing for managed MCP Servers
+
+**Misc**
+- `[documentation - 📝]` Fix site search
+
+
+## 2025-10-31
+
+**Toolkits**
+
+- `[feature - 🚀]` Added new HubSpot Marketing & CRM starter tools
+- `[feature - 🚀]` Added Exa.ai Starter MCP Server
+- `[feature - 🚀]` Added Asana starter toolkit
+- `[feature - 🚀]` Added Github starter toolkit
+- `[feature - 🚀]` Added Pylon Starter Toolkit
+- `[feature - 🚀]` Added Posthog Starter Toolkit
+- `[feature - 🚀]` Added Clickup Starter Toolkit
+
+**CLI and TDK**
+
+- `[feature - 🚀]` `arcade deploy` CLI Command
+
+**Platform and Engine**
+
+- `[feature - 🚀]` Add non-root user to platform image for improved security
+
+**Misc**
+- `[documentation - 📝]` Fix MCP reference examples
+
+
+## 2025-10-24
+
+**Toolkits**
+
+- `[feature - 🚀]` [Toolkits/Ticktick] Added Ticktick Starter Toolkit
+- `[feature - 🚀]` [Toolkits/Weaviate] Added Weaviate Starter Toolkit
+- `[feature - 🚀]` [Toolkits/Vercel] Added Vercel Starter Toolkit
+- `[feature - 🚀]` [Toolkits/Datadog] Added Datadog Starter Toolkit
+- `[feature - 🚀]` [Toolkits/Freshservice] New Freshservice MCP tools with complex objects handling
+
+**Platform and Engine**
+
+- `[feature - 🚀]` Dashboard: Add redirect_uri to MCP Servers
+- `[feature - 🚀]` Dashboard: Add OAuth fields to MCP Servers
+
+
+## 2025-10-17
+
+
+ We've updated our documentation to be more clear, consistent, and easier to navigate. This includes updated quickstarts, guides, and reference information. [Let us know what you think](/home/contact-us)!
+
+
+
+
+ This week we released `arcade-mcp`, the best way to build MCP Servers. `arcade-mcp` supersedes the Arcade TDK. Learn more about it [here](/home/quickstarts/call-tool-personal-agent)! Detailed reference information for `arcade-mcp` is available [here](/references/mcp/python/overview).
+
+
+
+ This week MCP Gateways are now generally available! MCP Gateways allow you to federate the tools from multiple MCP Servers into a single collection for easier management, control, and access. Learn more about them [here](/home/mcp-gateways)!
+
+
+
+ This week projects are now generally available! Projects are a new way to organize your MCP Servers, tools, and secrets for easier management, control, and access.
+
+
+
+**Toolkits**
+
+- `[feature - 🚀]` `arcade-mcp` is now generally available! Learn more about it [here](/home/quickstarts/call-tool-personal-agent)!
+- `[feature - 🚀]` [Toolkits/BrightData] Added BrightData Toolkit
+- `[feature - 🚀]` [Toolkits/Figma] Added Figma Starter MCP Server
+- `[feature - 🚀]` [Toolkits/Freshservice] Added Freshservice Starter MCP Server
+- `[feature - 🚀]` [Toolkits/Cursor Agents] Added Cursor Agents Starter MCP Server
+- `[feature - 🚀]` [Toolkits/AirTable] Added AirTable starter MCP Server
+- `[feature - 🚀]` [Toolkits/Miro] Added Miro Starter MCP Server
+- `[feature - 🚀]` [Toolkits/PagerDuty] Added PagerDuty Starter MCP Server
+- `[feature - 🚀]` `arcade deploy` for MCP Servers built with `arcade-mcp`
+
+**Platform and Engine**
+
+- `[feature - 🚀]` Dashboard: Allow OAuth on MCP Servers
+- `[feature - 🚀]` MCP Gateways are now generally available! Learn more about them [here](/home/mcp-gateways)!
+- `[feature - 🚀]` Projects are now generally available.
+- `[maintenance - 🔧]` Support remote MCP servers which require DCR (dynamic client registration).
+
+**Misc**
+
+- `[documentation - 📝]` Updated documentation to be more clear, consistent, and easier to navigate. This includes updated quickstarts, guides, and reference information.
+- `[documentation - 📝]` `llms.txt` is now kept up to date and simplified. We've also added a new section to the docs for [agentic development](/home/agentic-architecture).
+
+## 2025-10-10
+
+**Toolkits**
+
+- `[feature - 🚀]` [Toolkits/Trello] Added Trello tools
+- `[feature - 🚀]` [Toolkits/Calendly] Added Calendly starter toolkit
+- `[feature - 🚀]` [Toolkits/SquareUp] Added SquareUp toolkit
+- `[feature - 🚀]` [Toolkits/Xero] Xero API Starter MCP server
+
+**MCP Servers**
+
+- `[feature - 🚀]` Added reference area to `arcade-mcp` docs ([PR #488](https://github.com/ArcadeAI/docs/pull/488))
+
+**Platform and Engine**
+
+- `[feature - 🚀]` [Engine/OAuth] Adding SquareUp OAuth
+
+**Platform and Engine**
+
+- `[bugfix - 🔧]` Dashboard: Hide edit and delete button text in mobile
+
+## 2025-10-03
+
+**Toolkits**
+
+- `[feature - 🚀]` Box.com Starter MCP Server released ([docs](/en/mcp-servers/productivity/box-api))
+- `[feature - 🚀]` Stripe Starter MCP Server released ([docs](/en/mcp-servers/payments/stripe_api))
+
+**Misc**
+
+- `[documentation - 📝]` Add FAQ explaining personal vs project API keys
+
+## 2025-09-26
+
+**Toolkits**
+
+- `[feature - 🚀]` Introduce [Starter Tools](/home/use-tools/types-of-tools), a new type of tool that mirrors the original HTTP API design of the upstream service.
+- `[feature - 🚀]` Release Slack started MCP Server which contains support for most of the Slack API.
+- `[feature - 🚀]` Include advanced error handling in the following MCP Servers: Google, Microsoft, Slack, and Asana. Learn more about handling tool errors [here](/home/build-tools/providing-useful-tool-errors).
+- `[bugfix - 🐛]` [MCP Servers/MS Teams] Fix get_chat_metadata by chat's users
+- `[feature - 🚀]` [MCP Servers/confluence] Adding WhoAmI tools for Confluence
+
+**CLI and TDK**
+
+- `[bugfix - 🐛]` Fix reference in `arcade docs` Python example template to USER_ID instead of TOOL_NAME
+
+**Misc**
+
+- `[documentation - 📝]` Documents API wrapper vs LLM-native MCP Servers; includes Slack API wrapper MCP Server docs
+
+## 2025-09-19
+
+**Toolkits**
+
+- `[feature - 🚀]` [Toolkits/ClickUp] Removing no content additional messages in Evals
+- `[feature - 🚀]` [Toolkits/MongoDB] Add analytics MongoDB MCP Server ([PR #548](https://github.com/ArcadeAI/arcade-ai/pull/548))
+- `[feature - 🚀]` [MCP Servers/HubSpot] Adding HubSpot MCP Server enhancements ([PR #441](https://github.com/ArcadeAI/docs/pull/441))
+
+**CLI and TDK**
+
+- `[maintenance - 🔧]` Update Mastra example MCP Server project
+
+**Misc**
+
+- `[documentation - 📝]` Term consistency ([PR #445](https://github.com/ArcadeAI/docs/pull/445))
+- `[documentation - 📝]` Update Tool Error Handling ([PR #438](https://github.com/ArcadeAI/docs/pull/438))
+- `[maintenance - 🔧]` Update Mastra example docs to better match the example repo ([PR #444](https://github.com/ArcadeAI/docs/pull/444))
+
+## 2025-09-12
+
+**CLI and TDK**
+
+- `[feature - 🚀]` Added support for multiple types of errors from tools, and updated client libraries to aid in disambiguating rate-limiting and other forms of upstream errors ([Docs](https://github.com/ArcadeAI/docs/pull/438/files)). Added in v1.10.0 in `aracde-js`, v1.8.0 in `aracde-py`, and v0.1.0-alpha.6 in `aracde-go`.
+- `[maintenance - 🔧]`Update langchain version for Arcade integrations
+
+**Toolkits**
+
+- `[feature - 🚀]` Google Calendar improvements to video call scheduling ([Docs](https://github.com/ArcadeAI/docs/pull/436))
+- `[feature - 🚀]` [MCP Servers/Jira] Added `WhoAmI` tool to Jira, Google, Clickup, Slack, and Zendesk MCP Servers ([Docs](https://github.com/ArcadeAI/docs/pull/426))
+
+**Platform and Engine**
+
+- `[bugfix - 🐛]` Engine: Fix rate limiting algorithm
+- `[feature - 🚀]` Engine: Improve Tool Error Handling
+
+**Misc**
+
+- `[documentation - 📝]` Add a FAQ for requesting over-scoped permissions for Google Drive and similar tools ([docs PR #440](https://github.com/ArcadeAI/docs/pull/440))
+
+## 2025-09-05
+
+**Toolkits**
+
+- `[feature - 🚀]` Imgflip MCP Server: tools for memes ([docs PR #424](https://github.com/ArcadeAI/docs/pull/424))
+- `[feature - 🚀]` Edit Google Document Tool ([docs PR #427](https://github.com/ArcadeAI/docs/pull/427))
+- `[bugfix - 🐛]` [Toolkits/clickup] fix fuzzy match search
+
+**Platform and Engine**
+
+- `[maintenance - 🔧]` Engine: updated stainless to generate SDK specs
+- `[feature - 🚀]` Dashboard: New sidebar and user-verification page & prepare for project-based resources
+
+**CLI and TDK**
+
+- `[maintenance - 🔧]` upgraded langchain_arcade ([PR #546](https://github.com/ArcadeAI/arcade-ai/pull/546))
+
+**Misc**
+
+- `[documentation - 📝]` Adding ClickUp documentation ([PR #413](https://github.com/ArcadeAI/docs/pull/413))
+- `[documentation - 📝]` updated instructions on GH OAuth customization ([PR #425](https://github.com/ArcadeAI/docs/pull/425))
+
+## 2025-08-29
+
+**Toolkits**
+
+- `[feature - 🚀]` Re-add GoogleNews MCP Server
+
+**Platform and Engine**
+
+- `[feature - 🚀]` Dashboard: Update MCP Server and tool selection UI in playground
+- `[feature - 🚀]` Dashboard: Add MCP Servers and OAuth providers from the design system
+- `[feature - 🚀]` Dashboard: Add optional request parameters when adding OAuth providers
+
+**CLI and TDK**
+
+- `[feature - 🚀]` Improve Typedict and Basemodel support ([PR #523](https://github.com/ArcadeAI/arcade-ai/pull/523))
+
+**Misc**
+
+- `[documentation - 📝]` Add ClickUp auth provider documentation ([PR #404](https://github.com/ArcadeAI/docs/pull/404))
+- `[documentation - 📝]` Fix glossary: change 'Authentication Scope' to 'Authorization Scope' ([PR #419](https://github.com/ArcadeAI/docs/pull/419))
+- `[documentation - 📝]` Added missing parameter to the usage example templates ([PR #537](https://github.com/ArcadeAI/arcade-ai/pull/537))
+
+## 2025-08-22
+
+
+ This week we released a new pricing model for Arcade which will be better for
+ hobbyists and enterprises alike. Learn more here:
+ [https://blog.arcade.dev/pricing-updates](https://blog.arcade.dev/pricing-updates)
+
+
+**Toolkits**
+
+- `[feature - 🚀]` [X (Twitter)] Reply to Tweet ([PR #415](https://github.com/ArcadeAI/docs/pull/415))
+- `[feature - 🚀]` [Jira Toolkit] Add "Add To Sprint" and "Remove from Sprint" tools ([PR #412](https://github.com/ArcadeAI/docs/pull/412))
+- `[bugfix - 🐛]` [Google Drive, Docs, Sheets, Slides Toolkits] Remove file picker url from tool response
+
+**Platform and Engine**
+
+- `[feature - 🚀]` Arcade Cloud: New pricing model
+- `[feature - 🚀]` Authenticate communication between Engine and Coordinator via key exchange
+- `[feature - 🚀]` Engine: Add additional redis cert check options
+
+## 2025-08-15
+
+
+ This week we enforced a new requirement for all OAuth providers: they must
+ have a unique callback URL. This is a minor security change, but does require
+ you to update your OAuth configuration. This can be updated from the
+ dashboard.
+
+
+**Toolkits**
+
+- `[feature - 🚀]` Sharepoint Toolkit added ([docs](/mcp-servers/productivity/sharepoint))
+- `[feature - 🚀]` Google Slides Toolkit added
+- `[feature - 🚀]` Commenting on Google Docs added
+- `[bugfix - 🐛]` Improvements in Microsoft Teams message search tool for better agentic experience. Fix bug when no messages match the search query.
+- `[bugfix - 🐛]` Fix bugs in Google Workspace search tools
+
+**Platform and Engine**
+
+- `[feature - 🚀]` Custom OAuth providers now require a unique callback URL
+- `[bugfix - 🐛]` Engine: Resolve dynamic provider IDs when checking auth status
+- `[bugfix - 🐛]` Engine: Refresh token when checking the status of a completed request
+
+**Misc**
+
+- `[documentation - 📝]` Document Microsoft scopes required by Arcade MCP Servers ([PR #409](https://github.com/ArcadeAI/docs/pull/409))
+- `[documentation - 📝]` Microsoft SharePoint MCP Server documentation ([PR #400](https://github.com/ArcadeAI/docs/pull/400))
+
+## 2025-08-08
+
+**Toolkits**
+
+- `[feature - 🚀]` Clickhouse Toolkit ([PR #527](https://github.com/ArcadeAI/arcade-ai/pull/527))
+- `[feature - 🚀]` Add search to Google Drive
+- `[bugfix - 🐛]` Fix and docstring improvement in MS Teams MCP Server
+
+**Platform and Engine**
+
+- `[feature - 🚀]` Add support for GPT-5 models
+- `[feature - 🚀]` Per-app redirect URI info
+
+## 2025-08-01
+
+**Toolkits**
+
+- `[feature - 🚀]` Microsoft Teams MCP Server added
+- `[feature - 🚀]` Jira Toolkit: Add List Sprints & Boards tools
+- `[feature - 🚀]` Google Sheets MCP Server: Add pagination to GetSpreadsheet
+- `[bugfix - 🐛]` Jira MCP Server: Return UI URL for items again
+- `[feature - 🚀]` Salesforce MCP Server: Configure subdomain & max concurrency through secrets
+- `[feature - 🚀]` Confluence MCP Server supports Atlassian multi-cloud
+
+**CLI and TDK**
+
+- `[bugfix - 🐛]` Fixes for the CLI docs generator ([PR #524](https://github.com/ArcadeAI/arcade-ai/pull/524))
+- `[feature - 🚀]` CLI: Rename auto-docs command to 'docs' and other improvements ([PR #518](https://github.com/ArcadeAI/arcade-ai/pull/518))
+
+## 2025-07-25
+
+
+ Most Arcade MCP Servers have been removed from the
+ `github.com/ArcadeAI/arcade-ai` repository, and transitioned to closed-source.
+ Toolkit source code remains available upon request for our paying customers.
+ This enables us to iterate more quickly and provide a better experience for
+ our customers. The previously open-sourced MCP Servers are still available in the
+ public repository's git history.
+
+
+**Toolkits**
+
+- `[feature - 🚀]` Support for multiple Atlassian Clouds in the Jira Toolkit ([PR #506](https://github.com/ArcadeAI/arcade-ai/pull/506))
+
+**CLI and TDK**
+
+- `[bugfix - 🐛]` Fix `arcade worker list` endpoints ([PR #504](https://github.com/ArcadeAI/arcade-ai/pull/504))
+- `[feature - 🚀]` Support Tool Output in ValueSchema of ToolDefinition ([PR #487](https://github.com/ArcadeAI/arcade-ai/pull/487))
+
+**Platform and Engine**
+
+- `[feature - 🚀]` Self-service plan selection for Arcade Cloud and payment is now available.
+- `[bugfix - 🐛]` Dashboard: Userinfo config must respect response_map property
+- `[feature - 🚀]` Dashboard: Add Tool Types in Metrics
+
+**Misc**
+
+- `[documentation - 📝]` Update OAuth docs with user_info_request.response_map ([PR #360](https://github.com/ArcadeAI/docs/pull/360))
+- `[documentation - 📝]` Update Zendesk Custom OAuth ([PR #359](https://github.com/ArcadeAI/docs/pull/359))
+- `[documentation - 📝]` Add code samples & screenshots to user verification doc ([PR #363](https://github.com/ArcadeAI/docs/pull/363))
+
+## 2025-07-18
+
+
+ Version 2.0.0 of the Arcade Engine was released this week. Upgrading to version 2.0.0 is recommended for all self-hosted developers, and includes an important security fix for [secure OAuth flows](/home/auth/secure-auth-production). After upgrading, all projects will default to using the Arcade user verifier. If desired, you can then implement a custom user verifier in your application/agent and make the switch via the Arcade Dashboard.
+
+Self-hosed Arcade developers cannot be grandfathered into the old (insecure) behavior of skipping user verification once the Engine is upgraded to version 2.0.0 or higher.
+
+
+
+**Frameworks**
+
+**Toolkits**
+
+- `[feature - 🚀]` Add Linear Toolkit ([PR #465](https://github.com/ArcadeAI/arcade-ai/pull/465))
+- `[feature - 🚀]` Add Zendesk Toolkit ([PR #458](https://github.com/ArcadeAI/arcade-ai/pull/458))
+- `[bugfix - 🐛]` Fix bug in Slack user processing ([PR #488](https://github.com/ArcadeAI/arcade-ai/pull/488))
+- `[bugfix - 🐛]` fix URL expansion in Twitter ([PR #500](https://github.com/ArcadeAI/arcade-ai/pull/500))
+
+**CLI and TDK**
+
+- `[feature - 🚀]` Toolkit docs generator command for Arcade CLI ([PR #414](https://github.com/ArcadeAI/arcade-ai/pull/414))
+- `[feature - 🚀]` custom `callback_host` for arcade login ([PR #481](https://github.com/ArcadeAI/arcade-ai/pull/481))
+
+**Platform and Engine**
+
+- `[feature - 🚀]` Dashboard: Add filter for user id and providers in Connected Accounts
+- `[feature - 🚀]` Add new endpoint for upcoming scheduled subs
+- `[bugfix - 🐛]` Engine OAuth hardening: secure defaults, config updates, validation, additional API flags, and route for user confirmation
+- `[feature - 🚀]` Dashboard: UI for security settings
+- `[bugfix - 🐛]` Engine: Correctly handle nils in auth provider responses
+- `[bugfix - 🐛]` Platform: Improved success & error pages for OAuth
+
+**Misc**
+
+- `[documentation - 📝]` replaced creating MCP Server video with full tutorial ([PR #349](https://github.com/ArcadeAI/docs/pull/349))
+- `[documentation - 📝]` Add secure/brand auth in production doc ([PR #341](https://github.com/ArcadeAI/docs/pull/341))
+
+## 2025-07-11
+
+**Frameworks**
+
+**Toolkits**
+
+- `[feature - 🚀]` Split previously combined Google, Microsoft, and other Toolkits into separate MCP Servers to aid in retrieval and maintenance ([PR #438](https://github.com/ArcadeAI/arcade-ai/pull/438))
+- `[feature - 🚀]` Slack Toolkit: Major refactor and improvements ([PR #453](https://github.com/ArcadeAI/arcade-ai/pull/453))
+
+**CLI and TDK**
+
+- `[feature - 🚀]` `--debug` flag added for CLI commands ([PR #454](https://github.com/ArcadeAI/arcade-ai/pull/454))
+
+**Platform and Engine**
+
+- `[bugfix - 🐛]` Fix token refresh bug
+
+**Misc**
+
+- `[documentation - 📝]` Document the OAuth scopes required by the Slack MCP Server ([PR #344](https://github.com/ArcadeAI/docs/pull/344))
+
+## 2025-07-04
+
+**Toolkits**
+
+- `[bugfix - 🐛]` patching MCP Server template generator for outside the main repo ([PR #460](https://github.com/ArcadeAI/arcade-ai/pull/460))
+- `[bugfix - 🐛]` Filter out unneeded files/directories before deploying workers ([PR #464](https://github.com/ArcadeAI/arcade-ai/pull/464))
+
+**Platform and Engine**
+
+- `[feature - 🚀]` Concurrent auth requests for the same user and same scopes use the same authentication flow and URLs. This means that your users only have to authenticate once if the agent chooses to use multiple tools at once with the same scopes.
+- `[bugfix - 🐛]` Fix secret deletion
+
+**Cloud**
+
+- `[bugfix - 🐛]` Update cross-origin-opener-policy header to allow Google Drive File Picker popup
+
+**Platform and Engine**
+
+- `[feature - 🚀]` Dashboard: Allow editing the description of a secret
+- `[feature - 🚀]` Dashboard: Preserve tools when resetting parameters
+
+## 2025-06-28
+
+**Toolkits**
+
+- `[bugfix - 🐛]` Jira MCP Server: deduplicate cloud data in Atlassian's available-resources response ([PR #456](https://github.com/ArcadeAI/arcade-ai/pull/456))
+
+## 2025-06-20
+
+**Frameworks**
+
+- `[feature - 🚀]` Support for OpenAI Agent SDK in Typescript ([docs](/home/oai-agents/overview) and [example](https://github.com/ArcadeAI/arcade-ai/tree/main/examples/openai-agents-ts))
+
+**Toolkits**
+
+- `[feature - 🚀]` Jira MCP Server released ([docs](/mcp-servers/productivity/jira))
+
+**CLI and TDK**
+
+- `[feature - 🚀]` V2.0 of Python Tool Development Kit (TDK)
+- `[feature - 🚀]` Admin API client support
+ - Requires v1.6.0 of `arcade-py`, or v1.8.0 of `arcade-js`, or v0.1.0-alpha.4 of `arcade-go`
+
+**Platform and Engine**
+
+- `[feature - 🚀]` Admin APIs released for managing users, secrets, and tools ([API References](https://reference.arcade.dev/api-reference#tag/admin))
+- `[bugfix - 🐛]` Unauthenticated MCP servers can be called anonymously
+- `[feature - 🚀]` End-user credentials and auth status can be fetched in batches ([docs](/home/auth/tool-auth-status))
+
+**Misc**
+
+- `[feature - 🚀]` Launched Github Discussions for product feedback and support ([link](https://github.com/ArcadeAI/arcade-ai/discussions))
+- `[feature - 🚀]` Launched status.arcade.dev for monitoring platform status ([link](https://status.arcade.dev))
\ No newline at end of file
diff --git a/app/en/home/common-use-cases/_meta.tsx b/app/en/home/common-use-cases/_meta.tsx
new file mode 100644
index 000000000..910b56fc7
--- /dev/null
+++ b/app/en/home/common-use-cases/_meta.tsx
@@ -0,0 +1,7 @@
+export default {
+ "build-agent": "Build an agent that uses Arcade MCP servers",
+ "add-external-mcp-servers": "Add external MCP servers to Arcade",
+ "build-custom-mcp-server":
+ "Build a custom MCP server that you or others can put in your agent",
+ "turn-external-api-into-mcp-server": "Turn an external API into a MCP server",
+};
diff --git a/app/en/home/common-use-cases/add-external-mcp-servers/page.mdx b/app/en/home/common-use-cases/add-external-mcp-servers/page.mdx
new file mode 100644
index 000000000..ce8f61bc6
--- /dev/null
+++ b/app/en/home/common-use-cases/add-external-mcp-servers/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Add external MCP Servers to Arcade."
+description: "Learn how to add external MCP Servers to Arcade"
+---
+
+# Add external MCP Servers to Arcade.
+
+Coming soon!
diff --git a/app/en/home/common-use-cases/build-agent/page.mdx b/app/en/home/common-use-cases/build-agent/page.mdx
new file mode 100644
index 000000000..affcf84bb
--- /dev/null
+++ b/app/en/home/common-use-cases/build-agent/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Build an agent that uses Arcade MCP Servers."
+description: "Learn how to build an agent that uses Arcade MCP Servers"
+---
+
+# Build an agent that uses Arcade MCP Servers.
+
+Coming soon!
diff --git a/app/en/home/common-use-cases/build-custom-mcp-server/page.mdx b/app/en/home/common-use-cases/build-custom-mcp-server/page.mdx
new file mode 100644
index 000000000..4c1217c82
--- /dev/null
+++ b/app/en/home/common-use-cases/build-custom-mcp-server/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Build a custom MCP Server. that you or others can put in your agent."
+description: "Learn how to build a custom MCP Server for your agent"
+---
+
+# Build a custom MCP Server. that you or others can put in your agent.
+
+Coming soon!
diff --git a/app/en/home/common-use-cases/turn-external-api-into-mcp-server/page.mdx b/app/en/home/common-use-cases/turn-external-api-into-mcp-server/page.mdx
new file mode 100644
index 000000000..523dbba18
--- /dev/null
+++ b/app/en/home/common-use-cases/turn-external-api-into-mcp-server/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Turn an external API into a MCP Server."
+description: "Learn how to turn an external API into a MCP Server"
+---
+
+# Turn an external API into a MCP Server.
+
+Coming soon!
diff --git a/app/en/home/concepts/_meta.tsx b/app/en/home/concepts/_meta.tsx
new file mode 100644
index 000000000..fe11ad060
--- /dev/null
+++ b/app/en/home/concepts/_meta.tsx
@@ -0,0 +1,6 @@
+export default {
+ index: {
+ display: "hidden",
+ },
+ "tool-types": "Tool types",
+};
diff --git a/app/en/home/concepts/page.mdx b/app/en/home/concepts/page.mdx
new file mode 100644
index 000000000..009dc67b6
--- /dev/null
+++ b/app/en/home/concepts/page.mdx
@@ -0,0 +1,7 @@
+# Concepts
+
+Core concepts and principles of Arcade.
+
+## Overview
+
+Learn about fundamental concepts like tool types and more.
\ No newline at end of file
diff --git a/app/en/home/concepts/tool-types/page.mdx b/app/en/home/concepts/tool-types/page.mdx
new file mode 100644
index 000000000..83dd82a47
--- /dev/null
+++ b/app/en/home/concepts/tool-types/page.mdx
@@ -0,0 +1,7 @@
+# Tool Types
+
+Learn about different types of tools in Arcade.
+
+## Overview
+
+Understand the various categories and types of tools available.
\ No newline at end of file
diff --git a/app/en/home/configure-arcade-section/_meta.tsx b/app/en/home/configure-arcade-section/_meta.tsx
new file mode 100644
index 000000000..85d132d11
--- /dev/null
+++ b/app/en/home/configure-arcade-section/_meta.tsx
@@ -0,0 +1,6 @@
+export default {
+ "dashboard-section": "Dashboard",
+ "create-tenants-section": "Create organization",
+ "create-projects-section": "Create projects",
+ "arcade-cli-section": "Use Arcade's CLI",
+};
diff --git a/app/en/home/arcade-cli/page.mdx b/app/en/home/configure-arcade-section/arcade-cli-section/page.mdx
similarity index 99%
rename from app/en/home/arcade-cli/page.mdx
rename to app/en/home/configure-arcade-section/arcade-cli-section/page.mdx
index 094c3bebf..2764fc086 100644
--- a/app/en/home/arcade-cli/page.mdx
+++ b/app/en/home/configure-arcade-section/arcade-cli-section/page.mdx
@@ -410,4 +410,4 @@ Usage: arcade secret [OPTIONS] COMMAND [ARGS]...
│ list List all tool secrets in Arcade Cloud │
│ unset Delete tool secret(s) by key names │
╰────────────────────────────────────────────────────────────────────────────────────╯
-```
+```
\ No newline at end of file
diff --git a/app/en/home/configure-arcade-section/create-projects-section/page.mdx b/app/en/home/configure-arcade-section/create-projects-section/page.mdx
new file mode 100644
index 000000000..6cbf0f75d
--- /dev/null
+++ b/app/en/home/configure-arcade-section/create-projects-section/page.mdx
@@ -0,0 +1,7 @@
+# Create Projects
+
+Documentation coming soon.
+
+## Overview
+
+This section will contain detailed information about creating projects.
\ No newline at end of file
diff --git a/app/en/home/configure-arcade-section/create-tenants-section/page.mdx b/app/en/home/configure-arcade-section/create-tenants-section/page.mdx
new file mode 100644
index 000000000..b6ed20f6c
--- /dev/null
+++ b/app/en/home/configure-arcade-section/create-tenants-section/page.mdx
@@ -0,0 +1,7 @@
+# Create Tenants
+
+Documentation coming soon.
+
+## Overview
+
+This section will contain detailed information about creating tenants.
\ No newline at end of file
diff --git a/app/en/home/configure-arcade-section/dashboard-section/page.mdx b/app/en/home/configure-arcade-section/dashboard-section/page.mdx
new file mode 100644
index 000000000..a1c464252
--- /dev/null
+++ b/app/en/home/configure-arcade-section/dashboard-section/page.mdx
@@ -0,0 +1,7 @@
+# Dashboard
+
+Documentation coming soon.
+
+## Overview
+
+This section will contain detailed information about the Arcade dashboard.
\ No newline at end of file
diff --git a/app/en/home/creating-tools/_meta.tsx b/app/en/home/creating-tools/_meta.tsx
new file mode 100644
index 000000000..9c20d9e81
--- /dev/null
+++ b/app/en/home/creating-tools/_meta.tsx
@@ -0,0 +1,10 @@
+export default {
+ "tool-basics": "Build a tool",
+ "evaluating-tools": "Evaluate tools",
+ "performance-tools": "Improve an existing toolkit",
+ "new-functionality":
+ "Build tools with agent functionality that doesn't exist",
+ "newest-models": "Ensure tools work with the newest models",
+ "error-handling": "Handle errors",
+ "registry-early-access": "Registry early access",
+};
diff --git a/app/en/home/creating-tools/error-handling/_meta.tsx b/app/en/home/creating-tools/error-handling/_meta.tsx
new file mode 100644
index 000000000..76b8981cc
--- /dev/null
+++ b/app/en/home/creating-tools/error-handling/_meta.tsx
@@ -0,0 +1,4 @@
+export default {
+ "useful-tool-errors": "Providing useful tool errors",
+ "retry-tools": "Retry tools with improved prompt",
+};
diff --git a/app/en/home/build-tools/retry-tools-with-improved-prompt/page.mdx b/app/en/home/creating-tools/error-handling/retry-tools/page.mdx
similarity index 100%
rename from app/en/home/build-tools/retry-tools-with-improved-prompt/page.mdx
rename to app/en/home/creating-tools/error-handling/retry-tools/page.mdx
diff --git a/app/en/home/build-tools/providing-useful-tool-errors/page.mdx b/app/en/home/creating-tools/error-handling/useful-tool-errors/page.mdx
similarity index 100%
rename from app/en/home/build-tools/providing-useful-tool-errors/page.mdx
rename to app/en/home/creating-tools/error-handling/useful-tool-errors/page.mdx
diff --git a/app/en/home/creating-tools/evaluating-tools/_meta.tsx b/app/en/home/creating-tools/evaluating-tools/_meta.tsx
new file mode 100644
index 000000000..39a1896e7
--- /dev/null
+++ b/app/en/home/creating-tools/evaluating-tools/_meta.tsx
@@ -0,0 +1,5 @@
+export default {
+ "why-evaluate": "Why evaluate tools?",
+ "create-evaluation-suite": "Create an evaluation suite",
+ "run-evaluations": "Run evaluations",
+};
diff --git a/app/en/home/evaluate-tools/create-an-evaluation-suite/page.mdx b/app/en/home/creating-tools/evaluating-tools/create-evaluation-suite/page.mdx
similarity index 99%
rename from app/en/home/evaluate-tools/create-an-evaluation-suite/page.mdx
rename to app/en/home/creating-tools/evaluating-tools/create-evaluation-suite/page.mdx
index c82f8e626..0907959a8 100644
--- a/app/en/home/evaluate-tools/create-an-evaluation-suite/page.mdx
+++ b/app/en/home/creating-tools/evaluating-tools/create-evaluation-suite/page.mdx
@@ -316,4 +316,4 @@ suite.add_case(
## Next steps
- **See an example MCP server with evaluations**: [Source code of a server with evaluations](https://github.com/ArcadeAI/arcade-mcp/tree/139cc2e54db0e5815f1c79dbe9e3285b4fe2bd66/examples/mcp_servers/server_with_evaluations)
-- **Learn how to run evaluations**: [Run evaluations](/home/evaluate-tools/run-evaluations)
+- **Learn how to run evaluations**: [Run evaluations](/home/evaluate-tools/run-evaluations)
\ No newline at end of file
diff --git a/app/en/home/evaluate-tools/run-evaluations/page.mdx b/app/en/home/creating-tools/evaluating-tools/run-evaluations/page.mdx
similarity index 100%
rename from app/en/home/evaluate-tools/run-evaluations/page.mdx
rename to app/en/home/creating-tools/evaluating-tools/run-evaluations/page.mdx
diff --git a/app/en/home/evaluate-tools/why-evaluate-tools/page.mdx b/app/en/home/creating-tools/evaluating-tools/why-evaluate/page.mdx
similarity index 100%
rename from app/en/home/evaluate-tools/why-evaluate-tools/page.mdx
rename to app/en/home/creating-tools/evaluating-tools/why-evaluate/page.mdx
diff --git a/app/en/home/creating-tools/new-functionality/_meta.tsx b/app/en/home/creating-tools/new-functionality/_meta.tsx
new file mode 100644
index 000000000..76bfd969c
--- /dev/null
+++ b/app/en/home/creating-tools/new-functionality/_meta.tsx
@@ -0,0 +1,4 @@
+export default {
+ "eval-new-functionality": "Write eval for functionality you want",
+ "custom-toolkit": "Write custom toolkit",
+};
diff --git a/app/en/home/creating-tools/new-functionality/custom-toolkit/page.mdx b/app/en/home/creating-tools/new-functionality/custom-toolkit/page.mdx
new file mode 100644
index 000000000..b43b5bfdb
--- /dev/null
+++ b/app/en/home/creating-tools/new-functionality/custom-toolkit/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Write custom toolkit"
+description: "Learn how to write custom toolkits"
+---
+
+# Write custom toolkit
+
+Coming soon!
diff --git a/app/en/home/creating-tools/new-functionality/eval-new-functionality/page.mdx b/app/en/home/creating-tools/new-functionality/eval-new-functionality/page.mdx
new file mode 100644
index 000000000..8d37291fc
--- /dev/null
+++ b/app/en/home/creating-tools/new-functionality/eval-new-functionality/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Write eval for functionality you want"
+description: "Learn how to write evaluations for functionality you want"
+---
+
+# Write eval for functionality you want
+
+Coming soon!
diff --git a/app/en/home/creating-tools/newest-models/_meta.tsx b/app/en/home/creating-tools/newest-models/_meta.tsx
new file mode 100644
index 000000000..0bc71b765
--- /dev/null
+++ b/app/en/home/creating-tools/newest-models/_meta.tsx
@@ -0,0 +1,4 @@
+export default {
+ "run-eval-new-model": "Run existing eval and observe outcome with new model",
+ "modify-tool-new-model": "Modify tool to work well with new model",
+};
diff --git a/app/en/home/creating-tools/newest-models/modify-tool-new-model/page.mdx b/app/en/home/creating-tools/newest-models/modify-tool-new-model/page.mdx
new file mode 100644
index 000000000..653e21c2f
--- /dev/null
+++ b/app/en/home/creating-tools/newest-models/modify-tool-new-model/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Modify tool to work well with new model"
+description: "Learn how to modify tools to work well with new models"
+---
+
+# Modify tool to work well with new model
+
+Coming soon!
diff --git a/app/en/home/creating-tools/newest-models/run-eval-new-model/page.mdx b/app/en/home/creating-tools/newest-models/run-eval-new-model/page.mdx
new file mode 100644
index 000000000..3da62f894
--- /dev/null
+++ b/app/en/home/creating-tools/newest-models/run-eval-new-model/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Run existing eval and observe outcome with new model"
+description: "Learn how to run existing evaluations with new models"
+---
+
+# Run existing eval and observe outcome with new model
+
+Coming soon!
diff --git a/app/en/home/creating-tools/performance-tools/_meta.tsx b/app/en/home/creating-tools/performance-tools/_meta.tsx
new file mode 100644
index 000000000..04730e0f9
--- /dev/null
+++ b/app/en/home/creating-tools/performance-tools/_meta.tsx
@@ -0,0 +1,7 @@
+export default {
+ "types-of-tools": "Types of tools",
+ "eval-starter-tools": "Write eval to assess combo of starter tools",
+ "custom-tool-improvements":
+ "Write custom tool that improves on relevant Starter tools",
+ "run-evaluations-2": "Run evaluations",
+};
diff --git a/app/en/home/creating-tools/performance-tools/custom-tool-improvements/page.mdx b/app/en/home/creating-tools/performance-tools/custom-tool-improvements/page.mdx
new file mode 100644
index 000000000..21b27b5ca
--- /dev/null
+++ b/app/en/home/creating-tools/performance-tools/custom-tool-improvements/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Write custom tool that improves on relevant Starter tools"
+description: "Learn how to write custom tools that improve on Starter tools"
+---
+
+# Write custom tool that improves on relevant Starter tools
+
+Coming soon!
diff --git a/app/en/home/creating-tools/performance-tools/eval-starter-tools/page.mdx b/app/en/home/creating-tools/performance-tools/eval-starter-tools/page.mdx
new file mode 100644
index 000000000..d5d282edd
--- /dev/null
+++ b/app/en/home/creating-tools/performance-tools/eval-starter-tools/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Write eval to assess combo of starter tools"
+description: "Learn how to write evaluations for combinations of starter tools"
+---
+
+# Write eval to assess combo of starter tools
+
+Coming soon!
diff --git a/app/en/home/creating-tools/performance-tools/run-evaluations-2/page.mdx b/app/en/home/creating-tools/performance-tools/run-evaluations-2/page.mdx
new file mode 100644
index 000000000..0920ed24c
--- /dev/null
+++ b/app/en/home/creating-tools/performance-tools/run-evaluations-2/page.mdx
@@ -0,0 +1,217 @@
+---
+title: "Run evaluations"
+description: "Learn how to run evaluations using Arcade"
+---
+
+# Run evaluations with the Arcade CLI
+
+The Arcade Evaluation Framework allows you to run evaluations of your tool-enabled language models conveniently using the Arcade CLI. This enables you to execute your evaluation suites, gather results, and analyze the performance of your models in an efficient and streamlined manner.
+
+
+
+
+Run evaluations of your tool-enabled language models using the Arcade CLI.
+
+
+
+
+
+- [Arcade CLI](/home/arcade-cli)
+- [An MCP Server](/home/build-tools/create-a-mcp-server)
+- [Create an evaluation suite](/home/evaluate-tools/create-an-evaluation-suite)
+
+
+
+
+
+- How to use the `arcade evals` CLI command to run evaluations.
+
+
+
+
+### Using the `arcade evals` Command
+
+To run evaluations, use the `arcade evals` command provided by the Arcade CLI. This command searches for evaluation files in the specified directory, executes any functions decorated with `@tool_eval`, and displays the results.
+
+#### Basic Usage
+
+```bash
+arcade evals
+```
+
+- ``: The directory containing your evaluation files. By default, it searches the current directory (`.`).
+
+For example, to run evaluations in the current directory:
+
+```bash
+arcade evals
+```
+
+#### Evaluation File Naming Convention
+
+The `arcade evals` command looks for Python files that start with `eval_` and end with `.py` (e.g., `eval_math_tools.py`, `eval_slack_messaging.py`). These files should contain your evaluation suites.
+
+#### Command Options
+
+The `arcade evals` command supports several options to customize the evaluation process:
+
+- `--details`, `-d`: Show detailed results for each evaluation case, including critic feedback.
+
+ Example:
+
+ ```bash
+ arcade evals --details .
+ ```
+
+- `--models`, `-m`: Specify the models to use for evaluation. Provide a comma-separated list of model names.
+
+ Example:
+
+ ```bash
+ arcade evals --models gpt-4o,gpt-5 .
+ ```
+
+- `--max-concurrent`, `-c`: Set the maximum number of concurrent evaluations to run in parallel.
+
+ Example:
+
+ ```bash
+ arcade evals --max-concurrent 4 .
+ ```
+
+- `--provider`, `-p`: The provider of the models to use for evaluation. Uses OpenAI by default.
+
+ Example:
+
+ ```bash
+ arcade evals --provider openai .
+ ```
+
+- `--provider-api-key`, `-k`: The model provider API key. If not provided, will look for the appropriate environment variable based on the provider (e.g., OPENAI_API_KEY for openai provider), first in the current environment, then in the current working directory's .env file.
+
+ Example:
+
+ ```bash
+ arcade evals --provider-api-key my-api-key .
+ ```
+
+- `--debug`: Show debug information in the CLI.
+
+ Example:
+
+ ```bash
+ arcade evals --debug .
+ ```
+
+- `--help`: Show help information and exit.
+
+ Example:
+
+ ```bash
+ arcade evals --help
+ ```
+
+#### Example Command
+
+Running evaluations in the `arcade_my_tools/evals` directory, showing detailed results, using the `gpt-5` model:
+
+```bash
+arcade evals arcade_my_tools/evals --details --models gpt-5 -k my-openai-api-key
+```
+
+### Execution Process
+
+When you run the `arcade evals` command, the following steps occur:
+
+1. **Preparation**: The CLI loads the evaluation suites from the specified directory, looking for files that match the naming convention.
+
+2. **Execution**: The evaluation suites are executed asynchronously. Each suite's evaluation function, decorated with `@tool_eval`, is called with the appropriate configuration, including the model and concurrency settings.
+
+3. **Concurrency**: Evaluations can run concurrently based on the `--max-concurrent` setting, improving efficiency.
+
+4. **Result Aggregation**: Results from all evaluation cases and models are collected and aggregated.
+
+### Displaying Results
+
+After the evaluations are complete, the results are displayed in a concise and informative format, similar to testing frameworks like `pytest`. The output includes:
+
+- **Summary**: Shows the total number of cases, how many passed, failed, or issued warnings.
+
+ Example:
+
+ ```
+ Summary -- Total: 5 -- Passed: 4 -- Failed: 1
+ ```
+
+- **Detailed Case Results**: For each evaluation case, the status (PASSED, FAILED, WARNED), the case name, and the score are displayed.
+
+ Example:
+
+ ```
+ PASSED Add two large numbers -- Score: 1.00
+ FAILED Send DM with ambiguous username -- Score: 0.75
+ ```
+
+- **Critic Feedback**: If the `--details` flag is used, detailed feedback from each critic is provided, highlighting matches, mismatches, and scores for each evaluated field.
+
+ Example:
+
+ ```
+ Details:
+ user_name:
+ Match: False, Score: 0.00/0.50
+ Expected: johndoe
+ Actual: john_doe
+ message:
+ Match: True, Score: 0.50/0.50
+ ```
+
+### Interpreting the Results
+
+- **Passed**: The evaluation case met or exceeded the fail threshold specified in the rubric.
+
+- **Failed**: The evaluation case did not meet the fail threshold.
+
+- **Warnings**: If the score is between the warn threshold and the fail threshold, a warning is issued.
+
+Use the detailed feedback to understand where the model's performance can be improved, particularly focusing on mismatches identified by critics.
+
+### Customizing Evaluations
+
+You can customize the evaluation process by adjusting:
+
+- **Rubrics**: Modify fail and warn thresholds, and adjust weights to emphasize different aspects of evaluation.
+
+- **Critics**: Add or modify critics in your evaluation cases to target specific arguments or behaviors.
+
+- **Concurrency**: Adjust the `--max-concurrent` option to optimize performance based on your environment.
+
+### Handling Multiple Models
+
+You can evaluate multiple models in a single run by specifying them in the `--models` option as a comma-separated list. This allows you to compare the performance of different models across the same evaluation suites.
+
+Example:
+
+```bash
+arcade evals . --models gpt-4o,gpt-5
+```
+
+### Considerations
+
+- **Evaluation Files**: Ensure your evaluation files are correctly named and contain the evaluation suites decorated with `@tool_eval`.
+
+- **Provider API Keys**: If you are using a different provider, you will need to set the appropriate API key in an environment variable, or use the `--provider-api-key` option.
+
+- **Tool Catalog**: Ensure your tool catalog is correctly defined and includes all the tools you want to evaluate.
+
+- **Weight distribution**: Ensure your weight distribution reflects the importance of each critic and that the sum of the weights is `1.0`.
+
+## Conclusion
+
+Running evaluations using the Arcade CLI provides a powerful and convenient way to assess the tool-calling capabilities of your language models. By leveraging the `arcade evals` command, you can efficiently execute your evaluation suites, analyze results, and iterate on your models and tools.
+
+Integrating this evaluation process into your development workflow helps ensure that your models interact with tools as expected, enhances reliability, and builds confidence in deploying actionable language models in production environments.
+
+## Next steps
+
+- **See an example MCP server with evaluations**: [Source code of a server with evaluations](https://github.com/ArcadeAI/arcade-mcp/tree/139cc2e54db0e5815f1c79dbe9e3285b4fe2bd66/examples/mcp_servers/server_with_evaluations)
diff --git a/app/en/home/use-tools/types-of-tools/page.mdx b/app/en/home/creating-tools/performance-tools/types-of-tools/page.mdx
similarity index 100%
rename from app/en/home/use-tools/types-of-tools/page.mdx
rename to app/en/home/creating-tools/performance-tools/types-of-tools/page.mdx
diff --git a/app/en/home/creating-tools/registry-early-access/page.mdx b/app/en/home/creating-tools/registry-early-access/page.mdx
new file mode 100644
index 000000000..10cbd2fbd
--- /dev/null
+++ b/app/en/home/creating-tools/registry-early-access/page.mdx
@@ -0,0 +1,25 @@
+---
+title: "Arcade Registry Early Access"
+description: "Learn about the Arcade Registry and how to get early access"
+---
+
+import { EarlyAccessRegistrySurvey } from "@/app/_components/early-access-registry-survey";
+import { Callout } from "nextra/components";
+import { TakeSurvey } from "./take-survey";
+
+# The Arcade Registry
+
+The **Arcade Registry** is how agentic tool developers share their work with the world. Arcade.dev is collecting all the integrations that agents will ever need in one place - think HuggingFace or Pypi but for LLM tools. A powerful community of open source and for-profit developers building out robust and evaluated workflows is how agents can be elevated to being _truly_ useful.
+
+
+
+**_The components of the Arcade Registry_**
+
+
+Unlike traditional read-only tool libraries, Arcade.dev couples the runtime with the registry. This way we can collect real metrics and usage information about your tools, sharing meaningful information and feedback back to the developers. You'll get error reports and statistics about how your tools are getting used. Arcade.dev also makes it possible for developers to optionally choose to sell their tools with a markup on top of the Arcade platform fees.
+
+Thanks to the Arcade Engine, your MCP Servers will be available via all the protocols Arcade supports - be that MCP for locally-running applications, OXP for server applications, and whatever comes next. Use the open-source Arcade SDKs to future-proof your tools.
+
+We are seeking beta testers who are interested in building, maintaining, and sharing MCP Servers with the world in either a free-to-use or for-profit manner. Sign up today to join the Arcade Registry Beta.
+
+
\ No newline at end of file
diff --git a/app/en/home/creating-tools/registry-early-access/take-survey.tsx b/app/en/home/creating-tools/registry-early-access/take-survey.tsx
new file mode 100644
index 000000000..89bf472d5
--- /dev/null
+++ b/app/en/home/creating-tools/registry-early-access/take-survey.tsx
@@ -0,0 +1,16 @@
+"use client";
+
+import { Button } from "@arcadeai/design-system";
+
+export const TakeSurvey = () => (
+
+);
diff --git a/app/en/home/creating-tools/tool-basics/_meta.tsx b/app/en/home/creating-tools/tool-basics/_meta.tsx
new file mode 100644
index 000000000..16d64d3b8
--- /dev/null
+++ b/app/en/home/creating-tools/tool-basics/_meta.tsx
@@ -0,0 +1,11 @@
+export default {
+ "when-build-tools": "When to build tools",
+ "compare-server-types": "Compare Server Types",
+ "build-mcp-server": "Build MCP Server to write custom tools",
+ "create-tool-auth": "Create a tool with auth",
+ "create-tool-secrets": "Create a tool with secrets",
+ "runtime-data-access": "Accessing runtime data (Tools and Context)",
+ "call-tools-mcp": "Call tools from MCP clients",
+ "organize-mcp-tools": "Organize MCP server tools",
+ "migrate-toolkits": "Migrate from toolkits to MCP Servers",
+};
diff --git a/app/en/home/custom-mcp-server-quickstart/page.mdx b/app/en/home/creating-tools/tool-basics/build-mcp-server/page.mdx
similarity index 99%
rename from app/en/home/custom-mcp-server-quickstart/page.mdx
rename to app/en/home/creating-tools/tool-basics/build-mcp-server/page.mdx
index e4701d707..987c5a78b 100644
--- a/app/en/home/custom-mcp-server-quickstart/page.mdx
+++ b/app/en/home/creating-tools/tool-basics/build-mcp-server/page.mdx
@@ -271,4 +271,4 @@ Ensure you have set the environment variable in your terminal or `.env` file, an
- **Learn how to write a tool with secrets**: [Create a tool with secrets](/home/build-tools/create-a-tool-with-secrets)
- **Learn more about the Context object**: [Tools and Context](/home/build-tools/tool-context)
- **Learn how to write tool evaluations**: [Create an evaluation suite](/home/evaluate-tools/create-an-evaluation-suite) to optimize them for LLM usage
-- **Learn how to deploy your MCP server**: [Deploy your MCP server](/home/serve-tools/arcade-deploy)
+- **Learn how to deploy your MCP server**: [Deploy your MCP server](/home/serve-tools/arcade-deploy)
\ No newline at end of file
diff --git a/app/en/home/build-tools/call-tools-from-mcp-clients/page.mdx b/app/en/home/creating-tools/tool-basics/call-tools-mcp/page.mdx
similarity index 99%
rename from app/en/home/build-tools/call-tools-from-mcp-clients/page.mdx
rename to app/en/home/creating-tools/tool-basics/call-tools-mcp/page.mdx
index c6873890f..3f86d1684 100644
--- a/app/en/home/build-tools/call-tools-from-mcp-clients/page.mdx
+++ b/app/en/home/creating-tools/tool-basics/call-tools-mcp/page.mdx
@@ -320,4 +320,4 @@ Then, your MCP client's configuration file should look like this:
-
+
\ No newline at end of file
diff --git a/app/en/home/compare-server-types/page.mdx b/app/en/home/creating-tools/tool-basics/compare-server-types/page.mdx
similarity index 99%
rename from app/en/home/compare-server-types/page.mdx
rename to app/en/home/creating-tools/tool-basics/compare-server-types/page.mdx
index 3dfecf1ff..a0f87c64a 100644
--- a/app/en/home/compare-server-types/page.mdx
+++ b/app/en/home/creating-tools/tool-basics/compare-server-types/page.mdx
@@ -14,4 +14,4 @@ Depending on the transport you use and where you want to run your MCP server, Ar
| http | remote ([unprotected](/home/glossary#unprotected-mcp-servers)) | ✅ | ❌ | ❌ | ❌ |
| http | local ([protected](/home/glossary#protected-mcp-servers)) `coming soon` | ✅ | ✅ | ✅ | ✅ |
| http | remote ([protected](/home/glossary#protected-mcp-servers)) | ✅ | ✅ | ✅ | ✅ |
-| http | Arcade Cloud | ✅ | ✅ | ✅ | ✅ |
+| http | Arcade Cloud | ✅ | ✅ | ✅ | ✅ |
\ No newline at end of file
diff --git a/app/en/home/build-tools/create-a-tool-with-auth/page.mdx b/app/en/home/creating-tools/tool-basics/create-tool-auth/page.mdx
similarity index 98%
rename from app/en/home/build-tools/create-a-tool-with-auth/page.mdx
rename to app/en/home/creating-tools/tool-basics/create-tool-auth/page.mdx
index 7b1b3e0b0..7c76600e0 100644
--- a/app/en/home/build-tools/create-a-tool-with-auth/page.mdx
+++ b/app/en/home/creating-tools/tool-basics/create-tool-auth/page.mdx
@@ -32,7 +32,7 @@ Create and use an MCP tool that requires OAuth to access Reddit, prompting users
-An auth provider is the service that issues and manages the OAuth token your tool uses. It is the identity “source of truth” your tool integrates with to request permissions and obtain OAuth tokens.
+An auth provider is the service that issues and manages the OAuth token your tool uses. It is the identity "source of truth" your tool integrates with to request permissions and obtain OAuth tokens.
When you create a tool with `requires_auth`, you specify which provider to use. In this example, **`arcade_mcp_server.auth.Reddit` specifies the Reddit auth provider.**
@@ -335,4 +335,4 @@ if __name__ == "__main__":
# - "http": HTTP streamable transport
app.run(transport=transport, host="127.0.0.1", port=8000)
-```
+```
\ No newline at end of file
diff --git a/app/en/home/build-tools/create-a-tool-with-secrets/page.mdx b/app/en/home/creating-tools/tool-basics/create-tool-secrets/page.mdx
similarity index 99%
rename from app/en/home/build-tools/create-a-tool-with-secrets/page.mdx
rename to app/en/home/creating-tools/tool-basics/create-tool-secrets/page.mdx
index 18c347df8..078cf3625 100644
--- a/app/en/home/build-tools/create-a-tool-with-secrets/page.mdx
+++ b/app/en/home/creating-tools/tool-basics/create-tool-secrets/page.mdx
@@ -292,4 +292,4 @@ For HTTP transport, view your server's API docs at [http://127.0.0.1:8000/docs](
-
+
\ No newline at end of file
diff --git a/app/en/home/build-tools/migrate-from-toolkits/page.mdx b/app/en/home/creating-tools/tool-basics/migrate-toolkits/page.mdx
similarity index 100%
rename from app/en/home/build-tools/migrate-from-toolkits/page.mdx
rename to app/en/home/creating-tools/tool-basics/migrate-toolkits/page.mdx
diff --git a/app/en/home/build-tools/organize-mcp-server-tools/page.mdx b/app/en/home/creating-tools/tool-basics/organize-mcp-tools/page.mdx
similarity index 100%
rename from app/en/home/build-tools/organize-mcp-server-tools/page.mdx
rename to app/en/home/creating-tools/tool-basics/organize-mcp-tools/page.mdx
diff --git a/app/en/home/build-tools/tool-context/page.mdx b/app/en/home/creating-tools/tool-basics/runtime-data-access/page.mdx
similarity index 97%
rename from app/en/home/build-tools/tool-context/page.mdx
rename to app/en/home/creating-tools/tool-basics/runtime-data-access/page.mdx
index 970768202..a5fba8974 100644
--- a/app/en/home/build-tools/tool-context/page.mdx
+++ b/app/en/home/creating-tools/tool-basics/runtime-data-access/page.mdx
@@ -97,7 +97,7 @@ await context.log.log("info", "Info message") # equivalent to await context.log.
#### Sampling
-[Sampling in MCP](https://modelcontextprotocol.io/specification/2025-06-18/client/sampling) is a way for servers to request LLM sampling (“completions” or “generations”) from language models via clients. This flow allows clients to maintain control over model access, selection, and permissions while enabling servers to leverage AI capabilities—with no server API keys necessary.
+[Sampling in MCP](https://modelcontextprotocol.io/specification/2025-06-18/client/sampling) is a way for servers to request LLM sampling ("completions" or "generations") from language models via clients. This flow allows clients to maintain control over model access, selection, and permissions while enabling servers to leverage AI capabilities—with no server API keys necessary.
```python
await context.sampling.create_message(messages, system_prompt)
@@ -293,4 +293,4 @@ For HTTP transport, view your server's API docs at [http://127.0.0.1:8000/docs](
### Next Steps
- [Build a custom tool that requires user authorization](/home/build-tools/create-a-tool-with-auth)
-- [Build a custom tool with secrets](/home/build-tools/create-a-tool-with-secrets)
+- [Build a custom tool with secrets](/home/build-tools/create-a-tool-with-secrets)
\ No newline at end of file
diff --git a/app/en/home/creating-tools/tool-basics/when-build-tools/page.mdx b/app/en/home/creating-tools/tool-basics/when-build-tools/page.mdx
new file mode 100644
index 000000000..213ac1e75
--- /dev/null
+++ b/app/en/home/creating-tools/tool-basics/when-build-tools/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "When to build tools"
+description: "Learn when to build tools"
+---
+
+# When to build tools
+
+Coming soon!
diff --git a/app/en/home/crewai/use-arcade-tools/page.mdx b/app/en/home/crewai/use-arcade-tools/page.mdx
deleted file mode 100644
index 555dc8e87..000000000
--- a/app/en/home/crewai/use-arcade-tools/page.mdx
+++ /dev/null
@@ -1,148 +0,0 @@
----
-title: "Use Arcade tools with CrewAI"
-description: "Integrate Arcade tools into your CrewAI applications"
----
-
-import { Steps } from "nextra/components";
-import ToggleContent from "@/app/_components/toggle-content";
-
-## Use CrewAI with Arcade
-
-In this guide, we will explore how to integrate Arcade tools into your CrewAI application. Follow the step-by-step instructions below. If a tool requires authorization, an authorization URL will appear in the console, waiting for your approval. This process ensures that only the tools you choose to authorize are executed.
-
-To tailor the tool authorization flow to meet your application's specific needs, check out the [Custom Auth Flow with CrewAI](/home/crewai/custom-auth-flow) guide.
-
-
-
-### Prerequisites
-
-- [Obtain an Arcade API key](/home/api-keys)
-
-### Set up your environment
-
-Install the required package, and ensure your environment variables are set with your Arcade and OpenAI API keys:
-
-```bash
-pip install crewai-arcade
-```
-
-### Configure API keys
-
-Provide your Arcade and OpenAI API keys. You can store them in environment variables like so:
-
-```bash
-export ARCADE_API_KEY="your_arcade_api_key"
-export OPENAI_API_KEY="your_openai_api_key"
-```
-
-### Get Arcade tools
-
-Use the `ArcadeToolManager` to initialize, add, and get Arcade tools:
-
-```python
-from crewai_arcade import ArcadeToolManager
-
-manager = ArcadeToolManager(default_user_id="{arcade_user_id}")
-
-"""
-Retrieves the provided tools and/or MCP Servers as CrewAI StructuredTools.
-"""
-tools = manager.get_tools(tools=["Gmail.ListEmails"], toolkits=["Slack"])
-```
-
-### Use tools in your CrewAI agent team
-
-Create a Crew that uses your tools. When the tool is called, you will be prompted to go visit an authorization page to authorize the tool before it executes.
-
-```python
-from crewai import Agent, Crew, Task
-from crewai.llm import LLM
-
-crew_agent = Agent(
- role="Main Agent",
- backstory="You are a helpful assistant",
- goal="Help the user with their requests",
- tools=tools,
- allow_delegation=False,
- verbose=True,
- llm=LLM(model="gpt-4o"),
-)
-
-task = Task(
- description="Get the 5 most recent emails from the user's inbox and summarize them and recommend a response for each.",
- expected_output="A bulleted list with a one sentence summary of each email and a recommended response to the email.",
- agent=crew_agent,
- tools=crew_agent.tools,
-)
-
-crew = Crew(
- agents=[crew_agent],
- tasks=[task],
- verbose=True,
- memory=True,
-)
-
-result = crew.kickoff()
-
-print("\n\n\n ------------ Result ------------ \n\n\n")
-print(result)
-```
-
-
-
-
-
-```python
-from crewai import Agent, Crew, Task
-from crewai.llm import LLM
-from crewai_arcade import ArcadeToolManager
-
-manager = ArcadeToolManager(default_user_id="{arcade_user_id}")
-
-tools = manager.get_tools(tools=["Gmail.ListEmails"])
-
-
-crew_agent = Agent(
- role="Main Agent",
- backstory="You are a helpful assistant",
- goal="Help the user with their requests",
- tools=tools,
- allow_delegation=False,
- verbose=True,
- llm=LLM(model="gpt-4o"),
-)
-
-task = Task(
- description="Get the 5 most recent emails from the user's inbox and summarize them and recommend a response for each.",
- expected_output="A bulleted list with a one sentence summary of each email and a recommended response to the email.",
- agent=crew_agent,
- tools=crew_agent.tools,
-)
-
-crew = Crew(
- agents=[crew_agent],
- tasks=[task],
- verbose=True,
- memory=True,
-)
-
-result = crew.kickoff()
-
-print("\n\n\n ------------ Result ------------ \n\n\n")
-print(result)
-```
-
-
-
-## Tips for selecting tools
-
-- **Relevance**: Pick only the tools you need. Avoid using all tools at once.
-- **Avoid conflicts**: Be mindful of duplicate or overlapping functionality.
-
-## Next steps
-
-Now that you have integrated Arcade tools into your CrewAI agent team, you can:
-
-- Experiment with different toolkits, such as "Math" or "Search."
-- Customize the agent's prompts for specific tasks.
-- Customize the tool authorization and execution flow to meet your application's requirements.
diff --git a/app/en/home/deployment-hosting/_meta.tsx b/app/en/home/deployment-hosting/_meta.tsx
new file mode 100644
index 000000000..c2e074fd8
--- /dev/null
+++ b/app/en/home/deployment-hosting/_meta.tsx
@@ -0,0 +1,9 @@
+export default {
+ overview: "Overview",
+ "cloud-infrastructure": "Use Arcade's cloud infrastructure",
+ "on-premise-mcp": "Use on-premise MCP servers",
+ "configure-engine": "Configure Arcade's engine",
+ "oauth-provider": "Configure an OAuth provider",
+ "evals-cicd": "Set evals on CI/CD",
+ "arcade-deploy": "Arcade deploy",
+};
diff --git a/app/en/home/serve-tools/arcade-deploy/page.mdx b/app/en/home/deployment-hosting/arcade-deploy/page.mdx
similarity index 99%
rename from app/en/home/serve-tools/arcade-deploy/page.mdx
rename to app/en/home/deployment-hosting/arcade-deploy/page.mdx
index 7157bbd00..422936989 100644
--- a/app/en/home/serve-tools/arcade-deploy/page.mdx
+++ b/app/en/home/deployment-hosting/arcade-deploy/page.mdx
@@ -162,4 +162,4 @@ You can use any of the available [Arcade clients](/references) to call the tools
-Your MCP Server is now deployed and managed by Arcade, and ready to be used in your MCP clients!
+Your MCP Server is now deployed and managed by Arcade, and ready to be used in your MCP clients!
\ No newline at end of file
diff --git a/app/en/home/deployment/arcade-cloud-infra/page.mdx b/app/en/home/deployment-hosting/cloud-infrastructure/page.mdx
similarity index 97%
rename from app/en/home/deployment/arcade-cloud-infra/page.mdx
rename to app/en/home/deployment-hosting/cloud-infrastructure/page.mdx
index cce088b45..4f25bac1f 100644
--- a/app/en/home/deployment/arcade-cloud-infra/page.mdx
+++ b/app/en/home/deployment-hosting/cloud-infrastructure/page.mdx
@@ -25,4 +25,4 @@ Traffic from Arcade Cloud will be existing our infrastructure from the following
## VPC Peering
-VPC Peering is available for our enterprise customers upon request. If you are interested in VPC Peering, please [contact us](/home/contact-us).
+VPC Peering is available for our enterprise customers upon request. If you are interested in VPC Peering, please [contact us](/home/contact-us).
\ No newline at end of file
diff --git a/app/en/home/deployment/engine-configuration/page.mdx b/app/en/home/deployment-hosting/configure-engine/page.mdx
similarity index 95%
rename from app/en/home/deployment/engine-configuration/page.mdx
rename to app/en/home/deployment-hosting/configure-engine/page.mdx
index 5ec5e8445..97b51502f 100644
--- a/app/en/home/deployment/engine-configuration/page.mdx
+++ b/app/en/home/deployment-hosting/configure-engine/page.mdx
@@ -77,7 +77,7 @@ export PATH=$PATH:/path/to/your/binary
docker run -d -p 9099:9099 -v ./engine.yaml:/bin/engine.yaml ghcr.io/arcadeai/engine:latest
```
- where config.yaml is the path to the [configuration file](/home/deployment/engine-configuration).
+ where config.yaml is the path to the [configuration file](/home/deployment-hosting/configure-engine).
@@ -88,7 +88,7 @@ Let's explore each file to understand their purpose and how to locate them.
## Engine configuration file
-The `engine.yaml` file controls Arcade Engine settings. It supports variable expansion so you can integrate secrets and environment values seamlessly. You can customize this file to suit your setup. For more details, check the [Engine Configuration](/home/deployment/engine-configuration) page.
+The `engine.yaml` file controls Arcade Engine settings. It supports variable expansion so you can integrate secrets and environment values seamlessly. You can customize this file to suit your setup. For more details, check the [Engine Configuration](/home/deployment-hosting/configure-engine) page.
Choose your installation method to view the default location of `engine.yaml`:
@@ -107,7 +107,7 @@ Choose your installation method to view the default location of `engine.yaml`:
```bash
$HOME/.arcade/engine.yaml
```
- To manually download the engine.yaml, you can get an example from the [Configuration Templates](/home/deployment/engine-configuration#engineyaml) and add it to `$HOME/.arcade/engine.yaml`.
+ To manually download the engine.yaml, you can get an example from the [Configuration Templates](/home/deployment-hosting/configure-engine#engineyaml) and add it to `$HOME/.arcade/engine.yaml`.
@@ -132,7 +132,7 @@ Select your installation method below to see the default path for `engine.env`:
```bash
$HOME/.arcade/engine.env
```
- To manually download the `engine.env`, refer to the [Configuration Templates](/home/deployment/engine-configuration#engineenv).
+ To manually download the `engine.env`, refer to the [Configuration Templates](/home/deployment-hosting/configure-engine#engineenv).
@@ -234,11 +234,11 @@ For local development, set `api.development = true`.
## Auth configuration
-Arcade Engine manages auth for [AI tools](/home/auth/auth-tool-calling) and [direct API calls](/home/auth/call-third-party-apis-directly). It supports many built-in [auth providers](/home/auth-providers), and can also connect to any [OAuth 2.0](/home/auth-providers/oauth2) authorization server.
+Arcade Engine manages auth for [AI tools](/home/auth/auth-tool-calling) and [direct API calls](/home/auth/call-third-party-apis-directly). It supports many built-in [auth providers](/home/sharing-with-end-users/custom-auth), and can also connect to any [OAuth 2.0](/home/sharing-with-end-users/custom-auth/oauth2) authorization server.
The `auth.providers` section defines the providers that users can authorize with. Each provider must have a unique `id` in the array. There are two ways to configure a provider:
-For [built-in providers](/home/auth-providers), use the `provider_id` field to reference the pre-built configuration. For example:
+For [built-in providers](/home/sharing-with-end-users/custom-auth), use the `provider_id` field to reference the pre-built configuration. For example:
```yaml
auth:
@@ -252,7 +252,7 @@ auth:
client_secret: ${env:GITHUB_CLIENT_SECRET}
```
-For custom OAuth 2.0 providers, specify the full connection details in the `oauth2` sub-section. For full documentation on the custom provider configuration, see the [OAuth 2.0 provider configuration](/home/auth-providers/oauth2) page.
+For custom OAuth 2.0 providers, specify the full connection details in the `oauth2` sub-section. For full documentation on the custom provider configuration, see the [OAuth 2.0 provider configuration](/home/sharing-with-end-users/custom-auth/oauth2) page.
You can specify a mix of built-in and custom providers.
@@ -308,7 +308,7 @@ openssl rand -base64 32
### Default root key
-When you [install Arcade Engine locally](/home/deployment/engine-configuration), an `engine.env` file is created with a default root key:
+When you [install Arcade Engine locally](/home/deployment-hosting/configure-engine), an `engine.env` file is created with a default root key:
```bash
# Encryption keys (change this when deploying to production)
@@ -686,4 +686,4 @@ X_CLIENT_SECRET=
ZOOM_CLIENT_ID=""
ZOOM_CLIENT_SECRET=
-```
+```
\ No newline at end of file
diff --git a/app/en/home/deployment-hosting/evals-cicd/page.mdx b/app/en/home/deployment-hosting/evals-cicd/page.mdx
new file mode 100644
index 000000000..9b7f9a658
--- /dev/null
+++ b/app/en/home/deployment-hosting/evals-cicd/page.mdx
@@ -0,0 +1,3 @@
+# Set evals on CI/CD
+
+Coming soon.
\ No newline at end of file
diff --git a/app/en/home/deployment-hosting/oauth-provider/page.mdx b/app/en/home/deployment-hosting/oauth-provider/page.mdx
new file mode 100644
index 000000000..77427ac50
--- /dev/null
+++ b/app/en/home/deployment-hosting/oauth-provider/page.mdx
@@ -0,0 +1,3 @@
+# Configure an OAuth provider
+
+Coming soon.
\ No newline at end of file
diff --git a/app/en/home/deployment/on-prem-mcp/page.mdx b/app/en/home/deployment-hosting/on-premise-mcp/page.mdx
similarity index 99%
rename from app/en/home/deployment/on-prem-mcp/page.mdx
rename to app/en/home/deployment-hosting/on-premise-mcp/page.mdx
index 21f55a3de..9378f783f 100644
--- a/app/en/home/deployment/on-prem-mcp/page.mdx
+++ b/app/en/home/deployment-hosting/on-premise-mcp/page.mdx
@@ -317,4 +317,4 @@ You can now test your MCP Server by making requests using the Playground, or an
- [Create custom tools](/home/build-tools/create-a-mcp-server) for your MCP Server
- [Set up authentication](/home/build-tools/create-a-tool-with-auth) for secure access to resources
-- [Configure secrets](/home/build-tools/create-a-tool-with-secrets) for your MCP Server
+- [Configure secrets](/home/build-tools/create-a-tool-with-secrets) for your MCP Server
\ No newline at end of file
diff --git a/app/en/home/deployment-hosting/overview/page.mdx b/app/en/home/deployment-hosting/overview/page.mdx
new file mode 100644
index 000000000..fce95e99a
--- /dev/null
+++ b/app/en/home/deployment-hosting/overview/page.mdx
@@ -0,0 +1,57 @@
+---
+title: "Hosting Overview"
+description: "Learn about the different ways to host Arcade"
+---
+
+# Hosting Options
+
+The easiest and best way to use Arcade is via the Arcade Cloud service - sign up for free at [https://api.arcade.dev](https://api.arcade.dev). However, you might need to connect your tools to local resources (e.g. a local database or filesystem) or keep data within your own infrastructure. Don't worry, Arcade has you covered via either Arcade Cloud or our on-premise deployment options.
+
+## Arcade Cloud
+
+Arcade Cloud is the default option — sign up and start building immediately:
+
+- **Zero Infrastructure**: No servers or databases to manage
+- **Automatic Updates**: Always access the latest tools and features
+- **Built-in Scaling**: Handles traffic spikes automatically
+- **Free Tier**: Start building without a credit card
+
+### MCP Server Deployment
+
+You can route and manage tool calls from your agents to MCP servers hosted anywhere—on your machine, on your own infrastructure, in a private cloud, or on Arcade Cloud. This allows you to mix the best public tools with your own private tools.
+
+Connect on-premises MCP servers to Arcade Cloud for a hybrid deployment:
+
+- **Private Resources**: Access databases and APIs within your network
+- **Data Control**: Keep sensitive data in your environment
+- **Custom Dependencies**: Use specific runtime requirements or configurations
+- **Compliance**: Meet regulatory requirements while using Arcade's capabilities
+
+See [On-premise MCP Servers](/home/deployment/on-prem-mcp) for more information about how to use your own MCP servers running anywhere, and see [Arcade Deploy](/home/serve-tools/arcade-deploy) to learn how to deploy to Arcade Cloud.
+
+### Customizing Auth
+
+You don't have to self-host Arcade to customize your auth experiences. Arcade Cloud supports a number of auth providers out of the box, and you can provide your own OAuth app credentials to brand your end-user experience. We recommend doing this for all production use cases, so that you can have isolated rate limits with the OAuth service provider and you can give your users a consistent experience when they go through an auth flow.
+You can still use the same tools when you customize your auth, no code changes are required.
+
+See [Customizing Auth](/home/auth-providers) for more information.
+
+### Arcade Cloud Pricing
+
+Arcade Cloud offers a generous free tier to get started:
+
+- **Free Tier**: Includes access to all public MCP Servers and basic features
+- **Usage-Based**: Pay only for what you use as you scale
+
+Visit [https://api.arcade.dev](https://api.arcade.dev) for current pricing details.
+
+## On-Premise Deployments
+
+Fully on-premise deployments of the Arcade platform are available! Arcade can be deployed on Kubernetes via our Helm chart and Docker images as part of our enterprise offering. [Contact us to learn more](/home/contact-us).
+
+The requirements for deploying Arcade on-premise are:
+* Kubernetes cluster (1.30+) (We have tested this helm chart on AKS, GKE, and EKS).
+* Helm 3.x
+* kubectl configured to access your cluster
+* Cert Manager for securing Redis and Postgres and public ingress (see below)
+* Nginx Ingress for accessing Arcade.dev from outside the cluster (see below)
\ No newline at end of file
diff --git a/app/en/home/deployment/_meta.tsx b/app/en/home/deployment/_meta.tsx
deleted file mode 100644
index 33ad997c1..000000000
--- a/app/en/home/deployment/_meta.tsx
+++ /dev/null
@@ -1,22 +0,0 @@
-import type { MetaRecord } from "nextra";
-
-const meta: MetaRecord = {
- "*": {
- theme: {
- breadcrumb: true,
- toc: true,
- copyPage: true,
- },
- },
- "arcade-cloud-infra": {
- title: "Arcade Cloud Infrastructure",
- },
- "on-prem-mcp": {
- title: "On-premises MCP servers",
- },
- "engine-configuration": {
- title: "Engine configuration",
- },
-};
-
-export default meta;
diff --git a/app/en/home/evaluate-tools/_meta.tsx b/app/en/home/evaluate-tools/_meta.tsx
deleted file mode 100644
index bc4929294..000000000
--- a/app/en/home/evaluate-tools/_meta.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-export default {
- "why-evaluate-tools": "Why evaluate tools?",
- "create-an-evaluation-suite": "Create an evaluation suite",
- "run-evaluations": "Run evaluations",
-};
diff --git a/app/en/home/example-agents/page.mdx b/app/en/home/example-agents/page.mdx
new file mode 100644
index 000000000..5d7988312
--- /dev/null
+++ b/app/en/home/example-agents/page.mdx
@@ -0,0 +1,11 @@
+# Example Agents
+
+Explore these example agents to see what's possible with Arcade.
+
+## Turn Confluence into Jira Tickets / Google Docs into Linear Tickets
+
+Example agent that converts Confluence pages into Jira tickets or Google docs into Linear tickets.
+
+## Daily Digest: Summarize your Google Calendar / Email
+
+Example agent that creates daily digests from your Google Calendar and email.
\ No newline at end of file
diff --git a/app/en/home/examples/page.mdx b/app/en/home/examples/page.mdx
new file mode 100644
index 000000000..b9109387a
--- /dev/null
+++ b/app/en/home/examples/page.mdx
@@ -0,0 +1,7 @@
+# Examples (tutorials and sample code)
+
+Practical tutorials and sample code for building with Arcade.
+
+## Overview
+
+Turn Confluence into Jira Tickets, create daily digests, and more.
diff --git a/app/en/home/google-adk/_meta.tsx b/app/en/home/google-adk/_meta.tsx
deleted file mode 100644
index e208ebdc0..000000000
--- a/app/en/home/google-adk/_meta.tsx
+++ /dev/null
@@ -1,4 +0,0 @@
-export default {
- overview: "Overview",
- "use-arcade-tools": "Using Arcade tools",
-};
diff --git a/app/en/home/google-adk/overview/page.mdx b/app/en/home/google-adk/overview/page.mdx
deleted file mode 100644
index c13cc7eaa..000000000
--- a/app/en/home/google-adk/overview/page.mdx
+++ /dev/null
@@ -1,133 +0,0 @@
----
-title: "Arcade with Google ADK overview"
-description: "Comprehensive guide to using Arcade with the Google ADK library"
----
-
-# Arcade with Google ADK
-
-The `google-adk-arcade` package provides a seamless integration between
-[Arcade](https://arcade.dev) and the [Google ADK](https://github.com/google/adk-python/). This integration allows you to enhance your AI agents with powerful Arcade tools including Google Mail, LinkedIn, GitHub, and many more.
-
-## Installation
-
-Install the necessary packages to get started:
-
-```bash
-pip install google-adk-arcade
-```
-
-Make sure you have your Arcade API key ready. [Get an API key](/home/api-keys) if you don't already have one.
-
-## Key features
-
-- **Easy integration** with the Google ADK framework
-- **Access to all Arcade MCP Servers** including Google, GitHub, LinkedIn, X, and more
-- **Create custom tools** with the Arcade Tool SDK
-- **Manage user authentication** for tools that require it
-- **Asynchronous support** compatible with Google's ADK framework
-
-## Basic usage
-
-Here's a simple example of using Arcade tools with OpenAI Agents:
-
-```python
-import asyncio
-
-from arcadepy import AsyncArcade
-from google.adk import Agent, Runner
-from google.adk.artifacts import InMemoryArtifactService
-from google.adk.sessions import InMemorySessionService
-from google.genai import types
-
-from google_adk_arcade.tools import get_arcade_tools
-
-
-async def main():
- app_name = 'my_app'
- user_id = '{arcade_user_id}'
- session_service = InMemorySessionService()
- artifact_service = InMemoryArtifactService()
- client = AsyncArcade()
-
- google_tools = await get_arcade_tools(client, tools=["Gmail.ListEmails"])
-
- # authorize the tools
- for tool in google_tools:
- result = await client.tools.authorize(
- tool_name=tool.name,
- user_id=user_id
- )
- if result.status != "completed":
- print(f"Click this link to authorize {tool.name}:\n{result.url}")
- await client.auth.wait_for_completion(result)
-
- # create the agent
- google_agent = Agent(
- model="gemini-2.0-flash",
- name="google_tool_agent",
- instruction="I can use Google tools to manage an inbox!",
- description="An agent equipped with tools to read Gmail emails."
- tools=google_tools,
- )
-
- #create the session and pass the user ID to the state
- session = await session_service.create_session(
- app_name=app_name, user_id=user_id, state={
- "user_id": user_id,
- }
- )
-
- runner = Runner(
- app_name=app_name,
- agent=google_agent,
- artifact_service=artifact_service,
- session_service=session_service,
- )
-
- user_input = "summarize my latest 3 emails"
- content = types.Content(
- role='user', parts=[types.Part.from_text(text=user_input)]
- )
- for event in runner.run(
- user_id=user_id,
- session_id=session.id,
- new_message=content,
- ):
- if event.content.parts and event.content.parts[0].text:
- print(f'** {event.author}: {event.content.parts[0].text}')
-
-if __name__ == '__main__':
- asyncio.run(main())
-```
-
-## Handling authorization
-
-When a user needs to authorize access to a tool (like Google or GitHub),
-the agent will reply with a URL for the user to visit, which will be displayed
-to the user.
-
-After visiting the URL and authorizing access, the user can run the agent again
-with the same `user_id`, and it will work without requiring re-authorization.
-
-Alternatively, you can authorize the tool before running the agent:
-
-```python
-# authorize the tools
-for tool in google_tools:
- result = await client.tools.authorize(
- tool_name=tool.name,
- user_id=user_id
- )
- if result.status != "completed":
- print(f"Click this link to authorize {tool.name}:\n{result.url}")
- await client.auth.wait_for_completion(result)
-```
-
-## Next steps
-
-Ready to start building with Arcade and OpenAI Agents? Check out these guides:
-
-- [Using Arcade tools](/home/google-adk/use-arcade-tools) - Learn the basics of using Arcade tools with Google ADK
-- [Creating custom tools](/home/build-tools/create-a-mcp-server) - Build your own tools with the Arcade Tool SDK
-
-Enjoy exploring Arcade and building powerful AI-enabled applications!
diff --git a/app/en/home/guides/_meta.tsx b/app/en/home/guides/_meta.tsx
new file mode 100644
index 000000000..ff8b4c563
--- /dev/null
+++ b/app/en/home/guides/_meta.tsx
@@ -0,0 +1 @@
+export default {};
diff --git a/app/en/home/guides/page.mdx b/app/en/home/guides/page.mdx
new file mode 100644
index 000000000..f03d92aef
--- /dev/null
+++ b/app/en/home/guides/page.mdx
@@ -0,0 +1,7 @@
+# Guides
+
+Comprehensive guides for building with Arcade.
+
+## Overview
+
+Learn how to use tools, create tools, and set up authentication.
diff --git a/app/en/home/landing-page.tsx b/app/en/home/landing-page.tsx
index 90a4d2dcb..26d5a30e7 100644
--- a/app/en/home/landing-page.tsx
+++ b/app/en/home/landing-page.tsx
@@ -57,7 +57,7 @@ export function LandingPage() {
initial={{ opacity: 0, y: 20 }}
transition={{ duration: ANIMATION_DURATION }}
>
- Welcome to Arcade!
+ Ship AI agents that take action
- Arcade enables your AI agent to securely take real-world actions
- through user-specific permissions, pre-built MCP Servers for
- Gmail, Slack, GitHub, and more. You can also build your own
- agentic tools and MCP servers with our authoring and testing
- suite. Arcade is your tool{" "}
- engine,{" "}
- registry, and{" "}
- runtime.
-
-
- Get started with a 5-minute quickstart.
+ Give your agents the ability to send emails, update calendars,
+ manage files, and interact with any system—not just answer
+ questions. Arcade handles authentication, permissions, and API
+ integrations so your agents can work on behalf of real users,
+ securely.
+ Custom tools Build and deploy your own with our
+ SDK
+
+
+ Built on MCP Model Context Protocol for
+ universal agent compatibility
+
+
-
+
Get Started
@@ -119,9 +127,9 @@ export function LandingPage() {
size="lg"
variant="outline"
>
-
+
- Build a tool
+ Browse the tools
@@ -135,13 +143,13 @@ export function LandingPage() {
}}
>
- Don't write code yourself - let your AI IDE do it for you!
+ Arcade works with your AI IDE:
+
- Learn how to give your coding agents access to Arcade.dev's
- documentation
+ Give your coding agent access to Arcade.dev's documentation
@@ -337,28 +345,28 @@ export function LandingPage() {
diff --git a/app/en/home/langchain/_meta.tsx b/app/en/home/langchain/_meta.tsx
deleted file mode 100644
index a2708a562..000000000
--- a/app/en/home/langchain/_meta.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-export default {
- "use-arcade-tools": "Using Arcade tools",
- "user-auth-interrupts": "User authorization",
- "auth-langchain-tools": "Authorizing existing tools",
-};
diff --git a/app/en/home/langchain/use-arcade-tools/page.mdx b/app/en/home/langchain/use-arcade-tools/page.mdx
deleted file mode 100644
index 1ff3964c9..000000000
--- a/app/en/home/langchain/use-arcade-tools/page.mdx
+++ /dev/null
@@ -1,243 +0,0 @@
----
-title: "Use Arcade tools with LangGraph"
-description: "Integrate Arcade tools into your LangGraph applications"
----
-
-import { Steps, Tabs, Callout } from "nextra/components";
-
-## Use LangGraph with Arcade
-
-In this guide, let's explore how to integrate Arcade tools into your LangGraph application. Follow the step-by-step instructions below. For complete working examples, see our [Python](https://github.com/ArcadeAI/arcade-ai/blob/main/examples/langchain/langgraph_arcade_minimal.py) and [JavaScript](https://github.com/ArcadeAI/arcade-ai/blob/main/examples/langchain-ts/langgraph-arcade-minimal.ts) examples.
-
-
-
-### Prerequisites
-
-- [Obtain an Arcade API key](/home/api-keys)
-
-### Set up your environment
-
-Install the required packages, and ensure your environment variables are set with your Arcade and OpenAI API keys:
-
-
-
-```bash
-pip install langchain-arcade langchain-openai langgraph
-```
-
-
-```bash
-npm install @arcadeai/arcadejs @langchain/openai @langchain/core @langchain/langgraph
-```
-
-
-
-
-### Configure API keys
-
-Provide your Arcade and OpenAI API keys. You can store them in environment variables or directly in your code:
-
-> Need an Arcade API key? Visit the [Get an API key](/home/api-keys) page to create one.
-
-
-
-```python
-import os
-
-arcade_api_key = os.environ.get("ARCADE_API_KEY", "YOUR_ARCADE_API_KEY")
-openai_api_key = os.environ.get("OPENAI_API_KEY", "YOUR_OPENAI_API_KEY")
-```
-
-
-```bash
-ARCADE_API_KEY=
-OPENAI_API_KEY=
-```
-
-
-
-### Create and manage Arcade tools
-
-
-
-Use the ArcadeToolManager to retrieve specific tools or entire MCP Servers:
-
-```python
-from langchain_arcade import ArcadeToolManager
-
-manager = ArcadeToolManager(api_key=arcade_api_key)
-
-# Fetch the "ScrapeUrl" tool from the "Firecrawl" MCP Server
-tools = manager.get_tools(tools=["Firecrawl.ScrapeUrl"])
-print(manager.tools)
-
-# Get all tools from the "Gmail" MCP Server
-tools = manager.get_tools(toolkits=["Gmail"])
-print(manager.tools)
-```
-
-
-Arcade offers methods to convert tools into Zod schemas, which is essential since LangGraph defines tools using Zod. The `toZod` method is particularly useful, as it simplifies this integration and makes it easier to use Arcade's tools with LangGraph. Learn more about Arcade's Zod integration options [here](/home/use-tools/get-tool-definitions#get-zod-tool-definitions).
-```javascript
-import { Arcade } from "@arcadeai/arcadejs";
-import { executeOrAuthorizeZodTool, toZod } from "@arcadeai/arcadejs/lib";
-import { tool } from "@langchain/core/tools";
-
-// Initialize the Arcade client
-const arcade = new Arcade();
-
-// Get the Arcade tools, you can customize the MCP Server (e.g. "github", "notion", "gmail", etc.)
-const googleToolkit = await arcade.tools.list({ toolkit: "gmail", limit: 30 });
-const arcadeTools = toZod({
- tools: googleToolkit.items,
- client: arcade,
- userId: "", // Replace this with your application's user ID (e.g. email address, UUID, etc.)
-});
-// Convert Arcade tools to LangGraph tools
-const tools = arcadeTools.map(({ name, description, execute, parameters }) =>
- tool(execute, {
- name,
- description,
- schema: parameters,
- }),
-);
-console.log(tools);
-```
-
-
-
-
-### Set up the language model and memory
-
-Create an AI model and bind your tools. Use MemorySaver for checkpointing:
-
-
-
-```python
-from langchain_openai import ChatOpenAI
-from langgraph.checkpoint.memory import MemorySaver
-
-model = ChatOpenAI(model="gpt-4o", api_key=openai_api_key)
-bound_model = model.bind_tools(tools)
-
-memory = MemorySaver()
-```
-
-
-```javascript
-import { ChatOpenAI } from "@langchain/openai";
-import { MemorySaver } from "@langchain/langgraph";
-
-const model = new ChatOpenAI({ model: "gpt-4o", apiKey: process.env.OPENAI_API_KEY });
-const boundModel = model.bindTools(tools);
-const memory = new MemorySaver();
-```
-
-
-
-### Create a ReAct-style agent
-
-Use the prebuilt ReAct agent from LangGraph to handle your Arcade tools:
-
-
-```python
-from langgraph.prebuilt import create_react_agent
-
-graph = create_react_agent(model=bound_model, tools=tools, checkpointer=memory)
-```
-
-
-```javascript
-import { createReactAgent } from "@langchain/langgraph/prebuilt";
-
-const graph = createReactAgent({ llm: boundModel, tools, checkpointer: memory });
-```
-
-
-
-### Provide configuration and user query
-
-Supply a basic config dictionary and a user query. Notice that user_id is required for tool authorization:
-
-
-```python
-config = {
- "configurable": {
- "thread_id": "1",
- "user_id": "{arcade_user_id}"
- }
-}
-user_input = {
- "messages": [
- ("user", "List any new and important emails in my inbox.")
- ]
-}
-```
-
-
-```javascript
-const config = {
- configurable: {
- thread_id: "1",
- user_id: "{arcade_user_id}",
- },
- streamMode: "values" as const,
-};
-const user_input = {
- messages: [
- {
- role: "user",
- content: "List any new and important emails in my inbox.",
- },
- ],
-};
-```
-
-
-
-### Stream the response
-
-Stream the assistant's output. If the tool requires authorization, the agent will ask the user to authorize the tool.
-
-
-
-```python
-from langgraph.errors import NodeInterrupt
-
-try:
- for chunk in graph.stream(user_input, config, stream_mode="values"):
- chunk["messages"][-1].pretty_print()
-except NodeInterrupt as exc:
- print(f"\nNodeInterrupt occurred: {exc}")
- print("Please authorize the tool or update the request, then re-run.")
-```
-
-
-```javascript
-try {
- const stream = await graph.stream(user_input, config);
- for await (const chunk of stream) {
- console.log(chunk.messages[chunk.messages.length - 1]);
- }
-} catch (error) {
- console.error("Error streaming response:", error);
-}
-```
-
-
-
-
-## Tips for selecting tools
-
-- **Relevance**: Pick only the tools you need. Avoid using all tools at once.
-- **Avoid conflicts**: Be mindful of duplicate or overlapping functionality.
-
-## Next steps
-
-Now that you have integrated Arcade tools into your LangGraph agent, you can:
-
-- Experiment with different MCP Servers, such as "Math" or "Search."
-- Customize the agent's prompts for specific tasks.
-- Try out other language models and compare their performance.
-
-Enjoy exploring Arcade and building powerful AI-enabled Python applications!
diff --git a/app/en/home/langchain/user-auth-interrupts/page.mdx b/app/en/home/langchain/user-auth-interrupts/page.mdx
deleted file mode 100644
index b03a57735..000000000
--- a/app/en/home/langchain/user-auth-interrupts/page.mdx
+++ /dev/null
@@ -1,373 +0,0 @@
----
-title: "Using Arcade User Auth"
-description: "Build a custom LangGraph that handles tool authorization with Arcade"
----
-
-import { Steps, Tabs, Callout } from "nextra/components";
-
-## User Authorization in LangGraph
-
-In this guide, you will create a LangGraph workflow that requires user authorization before running certain Arcade tools. When a tool needs authorization, the graph displays an authorization URL and waits for the user's approval. This ensures that only the tools you explicitly authorize are available to the language model. For complete working examples, see our [Python](https://github.com/ArcadeAI/arcade-ai/blob/main/examples/langchain/langgraph_with_user_auth.py) and [JavaScript](https://github.com/ArcadeAI/arcade-ai/blob/main/examples/langchain-ts/langgraph-with-user-auth.ts) examples.
-
-
-
-### Prerequisites
-
-- [Obtain an Arcade API key](/home/api-keys)
-
-### Install the required packages
-
-Set up your environment with the following installations:
-
-
-
-```bash
-pip install langchain-arcade langchain-openai langgraph
-```
-
-
-```bash
-npm install @arcadeai/arcadejs @langchain/openai @langchain/core @langchain/langgraph
-```
-
-
-
-### Configure your Arcade environment
-
-Make sure you have set your Arcade API key (and any other relevant keys) in the environment, or assign them directly in the code:
-
-> Need an Arcade API key? Visit the [Get an API key](/home/api-keys) page to create one.
-
-
-
-```python
-import os
-
-# Import necessary classes and modules
-from langchain_arcade import ArcadeToolManager
-from langchain_openai import ChatOpenAI
-from langgraph.checkpoint.memory import MemorySaver
-from langgraph.graph import END, START, MessagesState, StateGraph
-from langgraph.prebuilt import ToolNode
-from langchain_core.runnables import RunnableConfig
-
-arcade_api_key = os.environ["ARCADE_API_KEY"]
-
-# Initialize the tool manager and fetch tools compatible with langgraph
-tool_manager = ArcadeToolManager(api_key=arcade_api_key)
-tools = tool_manager.get_tools(toolkits=["Gmail"])
-tool_node = ToolNode(tools)
-
-# Create a language model instance and bind it with the tools
-model = ChatOpenAI(model="gpt-4o")
-model_with_tools = model.bind_tools(tools)
-```
-
-Here are the main code elements:
-
-- arcade_api_key is your Arcade key.
-- tool_manager fetches your Arcade tools, for example the "Gmail" MCP Server.
-- tool_node encapsulates these tools for usage in LangGraph.
-- model_with_tools binds your tools to the "gpt-4o" language model, enabling tool calls.
-
-
-
-```javascript
-import { pathToFileURL } from "node:url";
-import { Arcade } from "@arcadeai/arcadejs";
-import { toZod } from "@arcadeai/arcadejs/lib";
-import type { AIMessage } from "@langchain/core/messages";
-import { tool } from "@langchain/core/tools";
-import { MessagesAnnotation, StateGraph } from "@langchain/langgraph";
-import { ToolNode } from "@langchain/langgraph/prebuilt";
-import { ChatOpenAI } from "@langchain/openai";
-
-// Initialize Arcade with API key from environment
-const arcade = new Arcade();
-
-// Replace with your application's user ID (e.g. email address, UUID, etc.)
-const USER_ID = "{arcade_user_id}";
-
-// Initialize tools from Gmail MCP Server
-const googleToolkit = await arcade.tools.list({ toolkit: "gmail", limit: 30 });
-const arcadeTools = toZod({
- tools: googleToolkit.items,
- client: arcade,
- userId: USER_ID,
-});
-
-// Convert Arcade tools to LangGraph tools
-const tools = arcadeTools.map(({ name, description, execute, parameters }) =>
- tool(execute, {
- name,
- description,
- schema: parameters,
- }),
-);
-
-// Initialize the prebuilt tool node
-const toolNode = new ToolNode(tools);
-
-// Create a language model instance and bind it with the tools
-const model = new ChatOpenAI({
- model: "gpt-4o",
- apiKey: process.env.OPENAI_API_KEY,
-});
-const modelWithTools = model.bindTools(tools);
-```
-
-Here are the main code elements:
-
-- arcade.tools.list fetches your Arcade tools, for example the "Gmail" MCP Server.
-- toZod converts Arcade tools to Zod schemas, which are required by LangGraph.
-- ToolNode encapsulates these tools for usage in LangGraph.
-- modelWithTools binds your tools to the "gpt-4o" language model, enabling tool calls.
-
-
-
-
-### Define the workflow steps
-
-You will create three primary functions to handle AI interaction, tool authorization, and flow control.
-
-
-```python
-# Function to invoke the model and get a response
-def call_agent(state: MessagesState):
- messages = state["messages"]
- response = model_with_tools.invoke(messages)
- # Return the updated message history
- return {"messages": [response]}
-
-
-# Function to determine the next step in the workflow based on the last message
-def should_continue(state: MessagesState):
- if state["messages"][-1].tool_calls:
- for tool_call in state["messages"][-1].tool_calls:
- if tool_manager.requires_auth(tool_call["name"]):
- return "authorization"
- return "tools" # Proceed to tool execution if no authorization is needed
- return END # End the workflow if no tool calls are present
-
-
-# Function to handle authorization for tools that require it
-def authorize(state: MessagesState, config: RunnableConfig | None = None):
- if config is None:
- raise ValueError("Config is required for authorization")
-
- user_id = config["configurable"].get("user_id")
- for tool_call in state["messages"][-1].tool_calls:
- tool_name = tool_call["name"]
- if not tool_manager.requires_auth(tool_name):
- continue
- auth_response = tool_manager.authorize(tool_name, user_id)
- if auth_response.status != "completed":
- # Prompt the user to visit the authorization URL
- print(f"Visit the following URL to authorize: {auth_response.url}")
-
- # Wait for the user to complete the authorization
- # and then check the authorization status again
- tool_manager.wait_for_auth(auth_response.id)
- if not tool_manager.is_authorized(auth_response.id):
- # This stops execution if authorization fails
- raise ValueError("Authorization failed.")
-
- return {"messages": []}
-```
-Explanations for these functions:
-
-- call_agent: Invokes the language model using the latest conversation state.
-- should_continue: Checks the last AI message for any tool calls. If a tool requires authorization, the flow transitions to authorization. Otherwise, it goes straight to tool execution or ends if no tools are called.
-- authorize: Prompts the user to authorize any required tools, blocking until authorization is completed successfully or fails.
-
-
-```javascript
-// Function to check if a tool requires authorization
-async function requiresAuth(toolName: string): Promise<{
- needsAuth: boolean;
- id: string;
- authUrl: string;
-}> {
- const authResponse = await arcade.tools.authorize({
- tool_name: toolName,
- user_id: USER_ID,
- });
- return {
- needsAuth: authResponse.status === "pending",
- id: authResponse.id ?? "",
- authUrl: authResponse.url ?? "",
- };
-}
-
-// Function to invoke the model and get a response
-async function callAgent(
- state: typeof MessagesAnnotation.State,
-): Promise {
- const messages = state.messages;
- const response = await modelWithTools.invoke(messages);
- return { messages: [response] };
-}
-
-// Function to determine the next step in the workflow based on the last message
-async function shouldContinue(
- state: typeof MessagesAnnotation.State,
-): Promise {
- const lastMessage = state.messages[state.messages.length - 1] as AIMessage;
- if (lastMessage.tool_calls?.length) {
- for (const toolCall of lastMessage.tool_calls) {
- const { needsAuth } = await requiresAuth(toolCall.name);
- if (needsAuth) {
- return "authorization";
- }
- }
- return "tools"; // Proceed to tool execution if no authorization is needed
- }
- return "__end__"; // End the workflow if no tool calls are present
-}
-
-// Function to handle authorization for tools that require it
-async function authorize(
- state: typeof MessagesAnnotation.State,
-): Promise {
- const lastMessage = state.messages[state.messages.length - 1] as AIMessage;
- for (const toolCall of lastMessage.tool_calls || []) {
- const toolName = toolCall.name;
- const { needsAuth, id, authUrl } = await requiresAuth(toolName);
- if (needsAuth) {
- // Prompt the user to visit the authorization URL
- console.log(`Visit the following URL to authorize: ${authUrl}`);
-
- // Wait for the user to complete the authorization
- const response = await arcade.auth.waitForCompletion(id);
- if (response.status !== "completed") {
- throw new Error("Authorization failed");
- }
- }
- }
-
- return { messages: [] };
-}
-```
-
-Explanations for these functions:
-
-- requiresAuth: Checks if a tool requires authorization.
-- callAgent: Invokes the language model using the latest conversation state.
-- shouldContinue: Checks the last AI message for any tool calls. If a tool requires authorization, the flow transitions to authorization. Otherwise, it goes straight to tool execution or ends if no tools are called.
-- authorize: Prompts the user to authorize any required tools, blocking until authorization is completed successfully or fails.
-
-
-
-
-### Build and compile your LangGraph workflow
-
-Use StateGraph to assemble the nodes and edges, then compile the graph with a MemorySaver.
-
-
-
-```python
-if __name__ == "__main__":
- # Build the workflow graph using StateGraph
- workflow = StateGraph(MessagesState)
-
- # Add nodes (steps) to the graph
- workflow.add_node("agent", call_agent)
- workflow.add_node("tools", tool_node)
- workflow.add_node("authorization", authorize)
-
- # Define the edges and control flow between nodes
- workflow.add_edge(START, "agent")
- workflow.add_conditional_edges("agent", should_continue, ["authorization", "tools", END])
- workflow.add_edge("authorization", "tools")
- workflow.add_edge("tools", "agent")
-
- # Set up memory for checkpointing the state
- memory = MemorySaver()
-
- # Compile the graph with the checkpointer
- graph = workflow.compile(checkpointer=memory)
-```
-
-
-```javascript
-// Build the workflow graph
-const workflow = new StateGraph(MessagesAnnotation)
- .addNode("agent", callAgent)
- .addNode("tools", toolNode)
- .addNode("authorization", authorize)
- .addEdge("__start__", "agent")
- .addConditionalEdges("agent", shouldContinue, [
- "authorization",
- "tools",
- "__end__",
- ])
- .addEdge("authorization", "tools")
- .addEdge("tools", "agent");
-
-// Compile the graph
-const graph = workflow.compile();
-```
-
-
-
-### Provide inputs and run the graph
-
-Finally, define user-supplied messages, authorization config, and stream the outputs. The graph will pause for any required tool authorization.
-
-
-
-```python
-# Define the input messages from the user
-inputs = {
- "messages": [
- {
- "role": "user",
- "content": "Check and see if I have any emails in my inbox",
- }
- ],
-}
-
-# Configuration with thread and user IDs for authorization purposes
-config = {"configurable": {"thread_id": "4", "user_id": "{arcade_user_id}"}}
-
-# Run the graph and stream the outputs
-for chunk in graph.stream(inputs, config=config, stream_mode="values"):
- # Pretty-print the last message in the chunk
- chunk["messages"][-1].pretty_print()
-```
-
-
-```javascript
-const inputs = {
- messages: [
- {
- role: "user",
- content: "Check and see if I have any important emails in my inbox",
- },
- ],
-};
-// Run the graph and stream the outputs
-const stream = await graph.stream(inputs, { streamMode: "values" });
-for await (const chunk of stream) {
- // Print the last message in the chunk
- console.log(chunk.messages[chunk.messages.length - 1].content);
-}
-```
-
-
-
-In this example:
-
-- The user prompts the agent to check emails.
-- The message triggers a potential need for the "Gmail" MCP Server.
-- If authorization is required, the code prints a URL and waits until you permit the tool call.
-
-
-
-## Next steps
-
-- Experiment with more Arcade MCP Servers for expanded capabilities.
-- Explore advanced authorization logic, such as multi-user or role-based checks.
-- Integrate additional nodes to handle more complex flows or multi-step tasks in your LangGraph.
-
-By combining Arcade's authorization features with stateful management in LangGraph, you can build AI-driven workflows that respect user permissions at every step. Have fun exploring Arcade!
diff --git a/app/en/home/mastra/overview/page.mdx b/app/en/home/mastra/overview/page.mdx
deleted file mode 100644
index e61b3f3c5..000000000
--- a/app/en/home/mastra/overview/page.mdx
+++ /dev/null
@@ -1,33 +0,0 @@
----
-title: "Integrating Arcade with Mastra"
-description: "Leverage Arcade's tool ecosystem within your Mastra applications."
----
-
-import { Callout } from "nextra/components";
-
-## Overview: Arcade Tools in Mastra
-
-[Mastra](https://mastra.ai/docs) is an open-source TypeScript agent framework that provides essential primitives for building AI applications. Integrate Arcade's extensive tool ecosystem to enhance your Mastra agents and enable them to interact seamlessly with numerous third-party services.
-
-This integration enables you to:
-
-- **Access a wide range of tools:** Use Arcade's [pre-built tools](/mcp-servers) for GitHub, Google Workspace, Slack, and more directly within your Mastra agent.
-- **Simplify tool management:** Let Arcade handle the complexities of tool discovery, execution, and authentication.
-- **Build sophisticated agents:** Combine Mastra's agent framework (including memory, workflows, and RAG) with Arcade's powerful tool capabilities.
-
-### How it Works
-
-The integration works through three key mechanisms:
-
-1. **Tool Discovery:** Access available tools through a unified API (`arcade.tools.list`).
-2. **Schema Conversion:** Transform Arcade's tool definitions into Mastra-compatible Zod schemas with the `toZodToolSet` utility, enabling seamless integration between the two frameworks without manual schema mapping.
-3. **Execution Delegation:** Seamlessly route tool calls from your Mastra agent through Arcade's API, which handles all the complexities of third-party service authentication and execution.
-
-
- Before starting, obtain an [Arcade API key](/home/api-keys).
-
-
-### Next Steps
-
-- Learn how to [use Arcade tools](/home/mastra/use-arcade-tools) in a Mastra agent
-- Implement [user authentication handling](/home/mastra/user-auth-interrupts) for tools in multi-user applications
diff --git a/app/en/home/mastra/use-arcade-tools/page.mdx b/app/en/home/mastra/use-arcade-tools/page.mdx
deleted file mode 100644
index 1e7b0919f..000000000
--- a/app/en/home/mastra/use-arcade-tools/page.mdx
+++ /dev/null
@@ -1,161 +0,0 @@
----
-title: "Using Arcade tools with Mastra"
-description: "Integrate Arcade tools into your Mastra applications for basic use cases."
----
-
-import { Steps, Tabs, Callout } from "nextra/components";
-
-This guide shows you how to integrate and use Arcade tools within a Mastra agent. For the complete working example, check out our [GitHub repository](https://github.com/ArcadeAI/arcade-ai/tree/main/examples/mastra).
-
-
-
-### Prerequisites
-
-- [Obtain an Arcade API key](/home/api-keys)
-- Basic familiarity with TypeScript and Mastra concepts
-
-### Create a Mastra project
-
-Start by creating a new Mastra project using the official CLI:
-
-```bash
-# Create a new Mastra project
-npx create-mastra@latest my-arcade-agent
-
-# Navigate to the project
-cd my-arcade-agent
-```
-
-For more details on setting up a Mastra project, refer to the [Mastra documentation](https://mastra.ai/docs/getting-started/installation).
-
-### Install Arcade client
-
-Install the Arcade client:
-
-
-
-
-
-```bash
-pnpm add @arcadeai/arcadejs
-```
-
-
-
-
-
-```bash
-npm install @arcadeai/arcadejs
-```
-
-
-
-
-
-```bash
-yarn install @arcadeai/arcadejs
-```
-
-
-
-
-
-### Configure API keys
-
-Set up your environment with the required API keys:
-
-```typescript
-// Set your API keys in your environment variables or .env file
-process.env.ARCADE_API_KEY = "your_arcade_api_key";
-process.env.ANTHROPIC_API_KEY = "your_anthropic_api_key"; // or another supported model provider
-```
-
-### Convert Arcade tools to Mastra tools
-
-Arcade offers methods to convert tools into Zod schemas, which is essential since Mastra defines tools using Zod. The `toZodToolSet` method is particularly useful, as it simplifies this integration and makes it easier to use Arcade's tools with Mastra. Learn more about Arcade's Zod integration options [here](/home/use-tools/get-tool-definitions#get-zod-tool-definitions).
-
-```ts
-import { Arcade } from "@arcadeai/arcadejs";
-import {
- executeOrAuthorizeZodTool,
- toZodToolSet,
-} from "@arcadeai/arcadejs/lib";
-
-// Initialize Arcade
-const arcade = new Arcade();
-
-// Get Gmail MCP Server
-// MCP Server names can be found in the Arcade dashboard via Tools > view > MCP Server or via the CLI `arcade workers list`
-const gmailToolkit = await arcade.tools.list({ toolkit: "Gmail", limit: 30 });
-
-// Get Gmail tools
-export const gmailTools = toZodToolSet({
- tools: gmailToolkit.items,
- client: arcade,
- userId: "", // Your app's internal ID for the user (an email, UUID, etc). It's used internally to identify your user in Arcade
- executeFactory: executeOrAuthorizeZodTool, // Checks if tool is authorized and executes it, or returns authorization URL if needed
-});
-
-```
-
-### Create and configure your Mastra agent
-
-Now create a Mastra agent that uses Arcade tools:
-
-```typescript
-import { Agent } from "@mastra/core/agent";
-import { anthropic } from "@ai-sdk/anthropic";
-
-// Create the Mastra agent with Arcade tools
-export const gmailAgent = new Agent({
- name: "gmailAgent",
- instructions: `You are a Gmail assistant that helps users manage their inbox.
-
-When helping users:
-- Always verify their intent before performing actions
-- Keep responses clear and concise
-- Confirm important actions before executing them
-- Respect user privacy and data security
-
-Use the gmailTools to interact with various Gmail services and perform related tasks.`,
- model: anthropic("claude-3-7-sonnet-20250219"),
- tools: gmailTools,
-});
-```
-
-### Interact with your agent
-
-You can interact with your agent in two main ways:
-
-**1. Using the Mastra Development Playground:**
-
-Start the Mastra development server:
-
-```bash
-npm run dev
-```
-
-This will launch a local development playground, typically accessible at `http://localhost:4111`. Open this URL in your browser, select the `gmailAgent` from the list of available agents, and start chatting with it directly in the UI.
-
-**2. Programmatically:**
-
-Alternatively, you can interact with the agent directly in your code:
-
-```typescript
-// Generate a response from the agent
-const response = await gmailAgent.generate(
- "Read my last email and summarize it in a few sentences",
-);
-console.log(response.text);
-
-// Or stream the response for a more interactive experience
-const stream = await gmailAgent.stream("Send an email to dev@arcade.dev with the subject 'Hello from Mastra'");
-
-for await (const chunk of stream.textStream) {
- process.stdout.write(chunk);
-}
-```
-
-
-
-When running your agent for the first time with tools that require user consent (like Google or Github), the agent will return an authorization reponse (e.g., `{ authorization_required: true, url: '...', message: '...' }`). Your agent's instructions should guide it to present this URL to the user. After the user visits this URL and grants permissions, the tool can be used successfully. See the [Managing user authorization](/home/mastra/user-auth-interrupts) guide for more details on handling authentication flows.
diff --git a/app/en/home/mastra/user-auth-interrupts/page.mdx b/app/en/home/mastra/user-auth-interrupts/page.mdx
deleted file mode 100644
index eea1f31dc..000000000
--- a/app/en/home/mastra/user-auth-interrupts/page.mdx
+++ /dev/null
@@ -1,153 +0,0 @@
----
-title: "Managing user authorization"
-description: "Handle user-specific authorization for Arcade tools in Mastra applications."
----
-
-import { Callout } from "nextra/components";
-
-## Dynamic Tool Loading with Toolsets
-
-Mastra lets you dynamically provide tools to an agent at runtime using toolsets. This approach is essential when integrating Arcade tools in web applications where each user needs their own authentication flow.
-
-### Per-User Tool Authentication in Web Applications
-
-In web applications serving multiple users, implement user-specific authentication flows with these steps:
-
-First, set up your Mastra configuration and agents in separate files:
-
-```typescript
-// @/mastra/index.ts
-import { Mastra } from "@mastra/core";
-import { githubAgent } from "./agents/githubAgent";
-
-// Initialize Mastra
-export const mastra = new Mastra({
- agents: {
- githubAgent,
- },
-});
-```
-
-```typescript
-// @/mastra/agents/githubAgent.ts
-import { Agent } from "@mastra/core/agent";
-import { anthropic } from "@ai-sdk/anthropic";
-
-// Create the agent without tools - we'll add them at runtime
-export const githubAgent = new Agent({
- name: "githubAgent",
- instructions: `You are a GitHub Agent that helps with repository management.
-
- You can help with tasks like:
- - Listing repositories
- - Creating and managing issues
- - Viewing pull requests
- - Managing repository settings
-
- If a tool requires authorization, you will receive an authorization URL.
- When that happens, clearly present this URL to the user and ask them to visit it to grant permissions.`,
- model: anthropic("claude-3-7-sonnet-20250219"),
- // No tools defined here - will be provided dynamically at runtime
-});
-```
-
-Then, create an API endpoint that provides tools dynamically:
-
-```typescript
-// app/api/chat/route.ts
-import { NextRequest, NextResponse } from "next/server";
-import { mastra } from "@/mastra";
-import { Arcade } from "@arcadeai/arcadejs";
-import { getUserSession } from "@/lib/auth"; // Your authentication handling
-import { toZodToolSet } from "@arcadeai/arcadejs/lib";
-import { executeOrAuthorizeZodTool } from "@arcadeai/arcadejs/lib";
-
-export async function POST(req: NextRequest) {
- // Extract request data
- const { messages, threadId } = await req.json();
-
- // Authenticate the user
- const session = await getUserSession(req);
- if (!session) {
- return NextResponse.json({ message: "Unauthorized" }, { status: 401 });
- }
-
- try {
- // Get the agent from Mastra
- const githubAgent = mastra.getAgent("githubAgent");
-
- const arcade = new Arcade();
- const githubToolkit = await arcade.tools.list({ toolkit: "github", limit: 30 });
-
- // Fetch user-specific Arcade tools for GitHub
- const arcadeTools = toZodToolSet({
- tools: githubToolkit.items,
- client: arcade,
- userId: session.user.email,
- executeFactory: executeOrAuthorizeZodTool,
- });
-
- // Stream the response with dynamically provided tools
- const response = await githubAgent.stream(messages, {
- threadId, // Optional: For maintaining conversation context
- resourceId: session.user.id, // Optional: For associating memory with user
- toolChoice: "auto",
- toolsets: {
- arcade: arcadeTools, // Provide tools in a named toolset
- },
- });
-
- // Return streaming response
- return response.toDataStreamResponse();
- } catch (error) {
- console.error("Error processing GitHub request:", error);
- return NextResponse.json(
- { message: "Failed to process request" },
- { status: 500 },
- );
- }
-}
-```
-
-This approach provides several benefits:
-
-- Each user gets their own separate authentication flow with Arcade tools
-- A single agent instance works with multiple user-specific toolsets
-
-The toolsets parameter provides tools only for the current request without modifying the agent's base configuration. This makes it ideal for multi-user applications where each user needs their own secure OAuth flow with Arcade.
-
-## Handling Tool Authorization
-
-When a tool requires user authorization, the agent receives a response with:
-
-```typescript
-{
- authorization_required: true,
- url: "https://auth.arcade.com/...",
- message: "Forward this url to the user for authorization"
-}
-```
-
-Your agent should recognize this pattern and present the URL to the user. To create a better user experience:
-
-- Display the authorization URL as a clickable link in your UI
-- Explain which service needs authorization and why
-- Provide a way for users to retry their request after authorization
-
-## Tips for Selecting Tools
-
-- **Focus on relevance**: Choose tools that directly support your agent's specific purpose
-- **Consider performance**: Some tools may have higher latency than others
-- **Handle errors gracefully**: Implement robust error handling for third-party service failures
-- **Create clear user flows**: Design intuitive authorization experiences
-
-## Next Steps
-
-After integrating Arcade tools into your Mastra agent, you can:
-
-- Add [memory capabilities](https://mastra.ai/docs/agents/agent-memory) to maintain context between interactions
-- Implement [structured workflows](https://mastra.ai/docs/workflows/overview) for complex multi-step operations
-- Enhance your agent with [RAG capabilities](https://mastra.ai/docs/rag/overview) for domain-specific knowledge
-- Set up [logging and tracing](https://mastra.ai/docs/observability/logging) to monitor performance
-
-For more detailed information on Mastra's capabilities, visit the [Mastra documentation](https://mastra.ai/docs).
diff --git a/app/en/home/mcp-gateway-quickstart/page.mdx b/app/en/home/mcp-gateway-quickstart/page.mdx
new file mode 100644
index 000000000..28d4b7d4b
--- /dev/null
+++ b/app/en/home/mcp-gateway-quickstart/page.mdx
@@ -0,0 +1,25 @@
+# MCP Gateway Quickstart
+
+This is a placeholder page for the MCP Gateway quickstart guide.
+
+## Overview
+
+Learn how to call tools in 3rd party agents, apps, or IDEs using the MCP Gateway.
+
+## Prerequisites
+
+- Arcade API key
+- Supported MCP client
+
+## Setup Steps
+
+1. Configure your MCP Gateway
+2. Connect to your client application
+3. Test tool calling functionality
+
+## Supported Clients
+
+- Cursor
+- Claude Desktop
+- Visual Studio Code
+- Other MCP-compatible applications
\ No newline at end of file
diff --git a/app/en/home/mcp-gateways/page.mdx b/app/en/home/mcp-gateways/page.mdx
deleted file mode 100644
index 17cd6f869..000000000
--- a/app/en/home/mcp-gateways/page.mdx
+++ /dev/null
@@ -1,29 +0,0 @@
----
-title: "MCP Gateways"
-description: "Comprehensive guide to using MCP Gateways"
----
-
-# MCP Gateways
-
-MCP Gateways are a way to connect multiple MCP Servers to your agent, application, or IDE. MCP Gateways allow you to federate the tools from multiple MCP Servers into a single collection for easier management, control, and access. You can mix and match tools from different MCP Servers in the same project, and not all tools from a MCP server need to be available to the same LLM.
-
-## Configure MCP Gateways
-
-To configure an MCP Gateway, go to the [MCP Gateways dashboard](https://api.arcade.dev/dashboard/mcp-gateways) and click on the "Create MCP Gateway" button.
-
-When configuring an MCP Gateway, you can select the tools you want to include in the Gateway from any MCP Servers available to the project:
-
-
-
-The options available when configuring an MCP Gateway are:
-- **Name**: The name of the MCP Gateway. Informative only.
-- **Description**: The description of the MCP Gateway. If set, this information will be returned to the LLM to hint at the purpose of the tools within the MCP Gateway.
-- **Slug**: The slug of the MCP Gateway. This is the URL slug that will be used to access the MCP Gateway. It must be unique.
-- **Allowed Tools**: If set, only the tools in the MCP Servers that are selected will be available to the MCP Gateway. If left blank, all tools from the MCP Servers available to the project will be available through the MCP Gateway.
-
-## How to use MCP Gateways
-
-Any MCP client that supports the Streamable HTTP transport can use an Arcade MCP Gateway. To use an Arcade MCP Gateway, you can use the `https://api.arcade.dev/mcp/` URL in your MCP client. Learn how to use MCP Gateways with:
-* [Cursor](/home/mcp-clients/cursor)
-* [Claude Desktop](/home/mcp-clients/claude-desktop)
-* [Visual Studio Code](/home/mcp-clients/visual-studio-code)
diff --git a/app/en/home/oai-agents/_meta.tsx b/app/en/home/oai-agents/_meta.tsx
deleted file mode 100644
index cdb53979a..000000000
--- a/app/en/home/oai-agents/_meta.tsx
+++ /dev/null
@@ -1,5 +0,0 @@
-export default {
- overview: "Overview",
- "use-arcade-tools": "Using Arcade tools",
- "user-auth-interrupts": "Managing user authorization",
-};
diff --git a/app/en/home/oai-agents/overview/page.mdx b/app/en/home/oai-agents/overview/page.mdx
deleted file mode 100644
index 27eaa1f72..000000000
--- a/app/en/home/oai-agents/overview/page.mdx
+++ /dev/null
@@ -1,184 +0,0 @@
----
-title: "Arcade with OpenAI Agents overview"
-description: "Comprehensive guide to using Arcade with the OpenAI Agents library"
----
-
-import { Steps, Tabs, Callout } from "nextra/components";
-
-# Arcade with OpenAI Agents
-
-Arcade provides seamless integration with the [OpenAI Agents Library](https://github.com/openai/openai-python) and [OpenAI Agents JS](https://openai.github.io/openai-agents-js/), allowing you to enhance your AI agents with powerful tools including Gmail, LinkedIn, GitHub, and many more. This integration is available through the `agents-arcade` package for Python and our [JavaScript client library](https://github.com/ArcadeAI/arcade-js).
-
-## Installation
-
-Install the necessary packages to get started:
-
-
-
-
-```bash
-pip install agents-arcade arcadepy
-```
-
-
-
-
-
-```bash
-npm install @openai/agents @arcadeai/arcadejs
-```
-
-
-
-
-
-Make sure you have your Arcade API key ready. [Get an API key](/home/api-keys) if you don't already have one.
-
-## Key features
-
-- **Easy integration** with the OpenAI Agents framework
-- **Access to all Arcade MCP Servers** including Google, GitHub, LinkedIn, X, and more
-- **Create custom tools** with the Arcade Tool SDK
-- **Manage user authentication** for tools that require it
-- **Asynchronous support** compatible with OpenAI's Agent framework
-
-## Basic usage
-
-Here's a simple example of using Arcade tools with OpenAI Agents:
-
-
-
-
-```python
-from agents import Agent, Runner
-from arcadepy import AsyncArcade
-from agents_arcade import get_arcade_tools
-from agents_arcade.errors import AuthorizationError
-
-async def main():
- # Initialize the Arcade client
- client = AsyncArcade()
-
- # Get tools from the "gmail" MCP Server
- tools = await get_arcade_tools(client, toolkits=["gmail"])
-
- # Create an agent with Gmail tools
- google_agent = Agent(
- name="Gmail agent",
- instructions="You are a helpful assistant that can assist with Gmail API calls.",
- model="gpt-4o-mini",
- tools=tools,
- )
-
- try:
- # Run the agent with a unique user_id for authorization
- result = await Runner.run(
- starting_agent=google_agent,
- input="What are my latest emails?",
- context={"user_id": "{arcade_user_id}"},
- )
- print("Final output:\n\n", result.final_output)
- except AuthorizationError as e:
- print("Please Login to Google:", e)
-
-if __name__ == "__main__":
- import asyncio
- asyncio.run(main())
-```
-
-
-
-
-
-Check out the complete working example in our [GitHub repository](https://github.com/ArcadeAI/arcade-ai/tree/main/examples/openai-agents-ts/src/index.ts).
-
-```javascript
-import Arcade from "@arcadeai/arcadejs";
-import { executeOrAuthorizeZodTool, toZod } from "@arcadeai/arcadejs/lib";
-import { Agent, run, tool } from "@openai/agents";
-
-// 1) Initialize Arcade client
-const client = new Arcade();
-
-// 2) Fetch Gmail MCP Server from Arcade and prepare tools for OpenAI Agents
-const googleToolkit = await client.tools.list({ toolkit: "gmail", limit: 30 });
-const tools = toZod({
- tools: googleToolkit.items,
- client,
- userId: "", // Replace this with your application's user ID (e.g. email address, UUID, etc.)
- executeFactory: executeOrAuthorizeZodTool,
-}).map(tool);
-
-// 3) Create a new agent with the Gmail MCP Server
-const googleAgent = new Agent({
- name: "Gmail agent",
- instructions:
- "You are a helpful assistant that can assist with Google API calls.",
- model: "gpt-4o-mini",
- tools,
-});
-
-// 4) Run the agent
-const result = await run(googleAgent, "What are my latest emails?");
-
-// 5) Print the result
-console.log(result.finalOutput);
-```
-
-
-
-
-
-## Handling authorization
-
-
-
-
-When a user needs to authorize access to a tool (like Google or GitHub), the agent will raise an `AuthorizationError` with a URL for the user to visit:
-
-```python
-try:
- # Run agent code
- # ...
-except AuthorizationError as e:
- # Display the authorization URL to the user
- print(f"Please visit this URL to authorize: {e}")
-```
-
-
-
-
-
-When a user needs to authorize access to a tool (like Google or GitHub), the agent will show a message like this:
-
-```bash
-[Authorize Gmail Access](https://accounts.google.com/o/oauth2/v2/auth?access_type=offline...)
-Once you have authorized access, I can retrieve your latest emails.
-```
-
-
-
-
-After visiting the URL and authorizing access, the user can run the agent again with the same `user_id`, and it will work without requiring re-authorization.
-
-## Available MCP Servers
-
-Arcade provides a variety of MCP Servers you can use with your agents:
-
-- **Google Suite**: Gmail, Calendar, Drive, Docs
-- **Social Media**: LinkedIn, X
-- **Development**: GitHub
-- **Web**: Web search, content extraction
-- **And more**: Weather, financial data, etc.
-
-For a full list of available MCP Servers, visit the [Arcade MCP Servers](/mcp-servers) documentation.
-
-## Next steps
-
-Ready to start building with Arcade and OpenAI Agents? Check out these guides:
-
-- [Using Arcade tools](/home/oai-agents/use-arcade-tools) - Learn the basics of using Arcade tools with OpenAI Agents
-- [Managing user authorization](/home/oai-agents/user-auth-interrupts) - Handle tool authorization efficiently
-- [Creating custom tools](/home/build-tools/create-a-mcp-server) - Build your own tools with the Arcade Tool SDK
-
-Enjoy exploring Arcade and building powerful AI-enabled applications!
diff --git a/app/en/home/oai-agents/use-arcade-tools/page.mdx b/app/en/home/oai-agents/use-arcade-tools/page.mdx
deleted file mode 100644
index 0b098f28c..000000000
--- a/app/en/home/oai-agents/use-arcade-tools/page.mdx
+++ /dev/null
@@ -1,346 +0,0 @@
----
-title: "Use Arcade with OpenAI Agents"
-description: "Integrate Arcade tools into your OpenAI Agents applications"
----
-import { Steps, Tabs, Callout } from "nextra/components";
-
-## Use Arcade with OpenAI Agents
-
-In this guide, let's explore how to integrate Arcade tools into your OpenAI Agents application. Follow the step-by-step instructions below.
-
-
-
-### Prerequisites
-
-- [Obtain an Arcade API key](/home/api-keys)
-
-### Set up your environment
-
-Install the required packages, and ensure your environment variables are set with your Arcade API key:
-
-
-
-
-
-```bash
-pip install agents-arcade arcadepy
-```
-
-
-
-
-
-```bash
-npm install @openai/agents @arcadeai/arcadejs
-```
-
-
-
-
-
-### Configure API keys
-
-Provide your Arcade API key. You can store it in environment variables or directly in your code:
-
-> Need an Arcade API key? Visit the [Get an API key](/home/api-keys) page to create one.
-
-
-
-
-```python
-import os
-
-os.environ["ARCADE_API_KEY"] = "YOUR_ARCADE_API_KEY"
-# Or set it directly when initializing the client
-```
-
-
-
-
-
-```bash
-# In your .env file
-ARCADE_API_KEY=YOUR_ARCADE_API_KEY
-```
-
-
-
-
-
-
-
-### Create and manage Arcade tools
-
-
-
-
-Use the `get_arcade_tools` function to retrieve tools from specific MCP Servers:
-
-```python
-from arcadepy import AsyncArcade
-from agents_arcade import get_arcade_tools
-
-# Initialize the Arcade client
-client = AsyncArcade()
-
-# Get all tools from the "Gmail" MCP Server
-tools = await get_arcade_tools(client, toolkits=["gmail"])
-
-# You can request multiple MCP Servers at once
-tools = await get_arcade_tools(client, toolkits=["gmail", "github", "linkedin"])
-
-# You can request specific tools
-tools = await get_arcade_tools(client, tools=["Gmail_ListEmails", "Slack_ListUsers", "Slack_SendDmToUser"])
-```
-
-
-
-
-
-```javascript
-import Arcade from '@arcadeai/arcadejs';
-import { executeOrAuthorizeZodTool, toZod } from "@arcadeai/arcadejs/lib";
-import { tool } from '@openai/agents';
-
-const client = new Arcade();
-
-// Option 1: Get tools from a single MCP Server
-const googleTools = await client.tools.list({ toolkit: "gmail", limit: 30 });
-const toolsFromGoogle = googleTools.items;
-
-// Option 2: Get tools from multiple MCP Servers
-const [google, github, linkedin] = await Promise.all([
- client.tools.list({ toolkit: "gmail", limit: 30 }),
- client.tools.list({ toolkit: "github", limit: 30 }),
- client.tools.list({ toolkit: "linkedin", limit: 30 })
-]);
-const toolsFromMultiple = [...google.items, ...github.items, ...linkedin.items];
-
-// Option 3: Get specific tools by name
-const specificTools = await Promise.all([
- client.tools.get("Gmail_ListEmails"),
- client.tools.get("Slack_ListUsers"),
- client.tools.get("Slack_SendDmToUser"),
-]);
-
-// Convert any of the above to OpenAI Agents format
-const convertToAgents = (arcadeTools) => {
- return toZod({
- tools: arcadeTools,
- client,
- userId: "", // Replace this with your application's user ID (e.g. email address, UUID, etc.)
- executeFactory: executeOrAuthorizeZodTool,
- }).map(tool);
-};
-
-// Use with any of the options above
-const tools = convertToAgents(toolsFromGoogle); // or toolsFromMultiple or specificTools
-```
-
-
-
-
-
-### Set up the agent with Arcade tools
-
-Create an agent and provide it with the Arcade tools:
-
-
-
-
-```python
-from agents import Agent, Runner
-
-# Create an agent with Gmail tools
-google_agent = Agent(
- name="Gmail agent",
- instructions="You are a helpful assistant that can assist with Google API calls.",
- model="gpt-4o-mini",
- tools=tools,
-)
-```
-
-
-
-
-
-```javascript
-import { Agent, Runner, tool } from '@openai/agents';
-
-// Create an agent with Arcade tools
-const googleAgent = new Agent({
- name: "Gmail agent",
- instructions: "You are a helpful assistant that can assist with Google API calls.",
- model: "gpt-4o-mini",
- tools
-});
-```
-
-
-
-
-### Run the agent
-
-
-
-
-Run the agent, providing a user_id for tool authorization:
-
-```python
-try:
- result = await Runner.run(
- starting_agent=google_agent,
- input="What are my latest emails?",
- context={"user_id": "{arcade_user_id}"},
- )
- print("Final output:\n\n", result.final_output)
-except AuthorizationError as e:
- print("Please Login to Google:", e)
-```
-
-
-
-
-```javascript
-const result = await run(googleAgent, "What are my latest emails?");
-```
-
-
-
-
-
-
-### Handle authentication
-
-
-
-
-If a tool requires authorization, an `AuthorizationError` will be raised with an authorization URL:
-
-```python
-from agents_arcade.errors import AuthorizationError
-
-try:
- # Run agent code from earlier examples
- # ...
-except AuthorizationError as e:
- print(f"Please visit this URL to authorize: {e}")
- # The URL contained in the error will take the user to the authorization page
-```
-
-
-
-
-
-If a tool requires authorization, the agent will show a message like this:
-
-```bash
-[Authorize Gmail Access](https://accounts.google.com/o/oauth2/v2/auth?access_type=offline...)
-Once you have authorized access, I can retrieve your latest emails.
-```
-
-
-
-
-
-### Complete example
-
-Here's a complete example putting everything together:
-
-
-
-
-```python
-from agents import Agent, Runner
-from arcadepy import AsyncArcade
-
-from agents_arcade import get_arcade_tools
-from agents_arcade.errors import AuthorizationError
-
-
-async def main():
- client = AsyncArcade()
- tools = await get_arcade_tools(client, toolkits=["gmail"])
-
- google_agent = Agent(
- name="Google agent",
- instructions="You are a helpful assistant that can assist with Google API calls.",
- model="gpt-4o-mini",
- tools=tools,
- )
-
- try:
- result = await Runner.run(
- starting_agent=google_agent,
- input="What are my latest emails?",
- context={"user_id": "{arcade_user_id}"},
- )
- print("Final output:\n\n", result.final_output)
- except AuthorizationError as e:
- print("Please Login to Google:", e)
-
-
-if __name__ == "__main__":
- import asyncio
-
- asyncio.run(main())
-```
-
-
-
-
-
-Check out the complete working example in our [GitHub repository](https://github.com/ArcadeAI/arcade-ai/tree/main/examples/openai-agents-ts/src/index.ts).
-
-```javascript
-import Arcade from '@arcadeai/arcadejs';
-import { executeOrAuthorizeZodTool, toZod } from "@arcadeai/arcadejs/lib";
-import { Agent, run, tool } from '@openai/agents';
-
-// 1) Initialize Arcade client
-const client = new Arcade();
-
-// 2) Fetch Gmail MCP Server from Arcade and prepare tools for OpenAI Agents
-const googleToolkit = await client.tools.list({ toolkit: "gmail", limit: 30 });
-const tools = toZod({
- tools: googleToolkit.items,
- client,
- userId: "", // Replace this with your application's user ID (e.g. email address, UUID, etc.)
- executeFactory: executeOrAuthorizeZodTool,
-}).map(tool);
-
-// 3) Create a new agent with the Gmail MCP Server
-const googleAgent = new Agent({
- name: "Gmail agent",
- instructions: "You are a helpful assistant that can assist with Google API calls.",
- model: "gpt-4o-mini",
- tools
-});
-
-// 4) Run the agent
-const result = await run(googleAgent, "What are my latest emails?");
-
-// 5) Print the result
-console.log(result.finalOutput);
-```
-
-
-
-
-
-
-## Tips for selecting tools
-
-- **Relevance**: Pick only the tools you need. Avoid using all tools at once.
-- **User identification**: Always provide a unique and consistent `user_id` for each user. Use your internal or database user ID, not something entered by the user.
-
-## Next steps
-
-Now that you have integrated Arcade tools into your OpenAI Agents application, you can:
-
-- Experiment with different MCP Servers, such as "Github" or "LinkedIn"
-- Customize the agent's instructions for specific tasks
-- Try out multi-agent systems using different Arcade tools
-- Build your own custom tools with the Arcade Tool SDK
-
-Enjoy exploring Arcade and building powerful AI-enabled Python applications!
diff --git a/app/en/home/oai-agents/user-auth-interrupts/page.mdx b/app/en/home/oai-agents/user-auth-interrupts/page.mdx
deleted file mode 100644
index d76bc6b63..000000000
--- a/app/en/home/oai-agents/user-auth-interrupts/page.mdx
+++ /dev/null
@@ -1,442 +0,0 @@
----
-title: "Managing user authorization"
-description: "Handle tool authorization with Arcade and OpenAI Agents"
----
-
-import { Steps, Tabs, Callout } from "nextra/components";
-
-## User authorization with OpenAI Agents
-
-In this guide, you will learn how to handle user authorization for Arcade tools in your OpenAI Agents application. When a tool requires authorization, the agent will raise an `AuthorizationError` with a URL for the user to visit and grant permissions.
-
-
-
-### Prerequisites
-
-- [Obtain an Arcade API key](/home/api-keys)
-
-### Install the required packages
-
-Set up your environment with the following installations:
-
-
-
-
-```bash
-pip install agents-arcade arcadepy
-```
-
-
-
-
-
-```bash
-npm install @openai/agents @arcadeai/agents-arcade
-```
-
-
-
-
-
-### Configure your Arcade environment
-
-Make sure you have set your Arcade API key in the environment, or assign it directly in the code:
-
-> Need an Arcade API key? Visit the [Get an API key](/home/api-keys) page to create one.
-
-
-
-
-```python
-import os
-from arcadepy import AsyncArcade
-from agents import Agent, Runner
-from agents_arcade import get_arcade_tools
-from agents_arcade.errors import AuthorizationError
-
-# Set your API key
-os.environ["ARCADE_API_KEY"] = "YOUR_ARCADE_API_KEY"
-
-# Initialize the Arcade client
-client = AsyncArcade()
-```
-
-
-
-
-
-Add your API key to your environment variables:
-
-```bash
-# In your .env file
-ARCADE_API_KEY=YOUR_ARCADE_API_KEY
-```
-
-```javascript
-import Arcade from '@arcadeai/arcadejs';
-import { isAuthorizationRequiredError, toZod } from "@arcadeai/arcadejs/lib";
-import { Agent, run, tool } from '@openai/agents';
-
-const client = new Arcade();
-```
-
-
-
-
-### Fetch Arcade tools
-
-Get the tools you need for your agent. In this example, we'll use GitHub tools:
-
-
-
-
-```python
-# Get GitHub tools for this example
-tools = await get_arcade_tools(client, toolkits=["github"])
-
-# Create an agent with GitHub tools
-github_agent = Agent(
- name="GitHub agent",
- instructions="You are a helpful assistant that can assist with GitHub API calls.",
- model="gpt-4o-mini",
- tools=tools,
-)
-```
-
-
-
-
-
-```javascript
-const githubToolkit = await client.tools.list({ toolkit: "github", limit: 30 });
-const arcadeTools = toZod({
- tools: githubToolkit.items,
- client,
- userId: "", // Replace this with your application's user ID (e.g. email address, UUID, etc.)
-})
-```
-
-
-
-
-
-
-### Handle authorization errors
-
-
-
-
-When a user needs to authorize access to a tool, the agent will raise an `AuthorizationError`. You can handle it like this:
-
-```python
-try:
- result = await Runner.run(
- starting_agent=github_agent,
- input="Star the arcadeai/arcade-ai repo",
- # Pass a unique user_id for authentication
- context={"user_id": "{arcade_user_id}"},
- )
- print("Final output:\n\n", result.final_output)
-except AuthorizationError as e:
- # Display the authorization URL to the user
- print(f"Please Login to GitHub: {e}")
- # The error contains the authorization URL that the user should visit
-```
-
-
-
-
-
-Choose how to handle authorization errors based on your needs:
-
-**Default behavior (throws errors):**
-```javascript
-const arcadeTools = toZod({
- tools: githubToolkit.items,
- client,
- userId: "", // Replace with your user ID
-});
-```
-
-Use this when you want to handle authorization flow yourself with custom logic.
-
-**Auto-handle authorization (recommended):**
-```javascript
-import { executeOrAuthorizeZodTool } from "@arcadeai/arcadejs/lib";
-
-const arcadeTools = toZod({
- tools: githubToolkit.items,
- client,
- userId: "", // Replace with your user ID
- executeFactory: executeOrAuthorizeZodTool,
-});
-```
-
-This automatically returns authorization URLs instead of throwing errors.
-
-**Custom error handling:**
-
-```javascript
-import { isAuthorizationRequiredError } from "@arcadeai/arcadejs/lib";
-
-const tools = arcadeTools.map((arcadeTool) => {
- return tool({
- ...arcadeTool,
- errorFunction: async (_, error) => {
- if (error instanceof Error && isAuthorizationRequiredError(error)) {
- const response = await client.tools.authorize({
- tool_name: arcadeTool.name,
- user_id: "",
- });
- return `Please login to Google: ${response.url}`;
- }
- return "Error executing tool"
- }
- })
-});
-```
-
-
-
-
-
-### Wait for authorization completion
-
-You can also wait for the user to complete the authorization before continuing:
-
-
-
-
-```python
-from arcadepy import AsyncArcade
-import asyncio
-
-client = AsyncArcade()
-
-async def handle_auth_flow(auth_id):
- # Display a message to the user
- print("Please visit the authorization URL in your browser")
-
-
- # Wait for the user to authenticate
- await client.auth.wait_for_completion(auth_id)
-
- # Check if authorization was successful
- if await is_authorized(auth_id):
- print("Authorization successful! You can now use the tool.")
- return True
- else:
- print("Authorization failed or timed out.")
- return False
-
-# In your main function
-try:
- # Run agent code
- # ...
-except AuthorizationError as e:
- auth_id = e.auth_id
- if await handle_auth_flow(auth_id):
- # Try running the agent again
- result = await Runner.run(
- starting_agent=github_agent,
- input="Star the arcadeai/arcade-ai repo",
- context={"user_id": "{arcade_user_id}"},
- )
- print("Final output:\n\n", result.final_output)
-```
-
-
-
-
-
-To wait for authorization completion, follow this approach:
-
-1. Throw the error to the agent
-2. Catch and handle the error while waiting for completion
-
-
-
-```javascript
-const tools = arcadeTools.map((arcadeTool) => {
- return tool({
- ...arcadeTool,
- errorFunction: (_, error) => { throw error } // Throw the error to the agent for handling
- })
-});
-
-while (true) {
- try {
- const result = await run(googleAgent, "What are my latest emails?");
- console.log(result.finalOutput);
- } catch (error) {
- // Catch the authorization error and wait for completion
- if (error instanceof Error && isAuthorizationRequiredError(error)) {
- const response = await client.tools.authorize({
- tool_name: "Gmail_ListEmails",
- user_id: "",
- });
- if (response.status !== "completed") {
- console.log(`Please complete the authorization challenge in your browser: ${response.url}`);
- }
-
- // Wait for the authorization to complete
- await client.auth.waitForCompletion(response);
- console.log("Authorization completed, retrying...");
- }
- }
- }
-```
-
-
-
-
-
-
-
-### Complete example
-
-Here's a full example that demonstrates the authorization flow with waiting for authentication:
-
-
-
-
-```python
-from arcadepy.auth import wait_for_authorization_completion
-
-import time
-
-from agents import Agent, Runner
-from arcadepy import AsyncArcade
-
-from agents_arcade import get_arcade_tools
-from agents_arcade.errors import AuthorizationError
-
-
-async def main():
- client = AsyncArcade()
- # Use the "github" MCP Server for this example
- tools = await get_arcade_tools(client, toolkits=["github"])
-
- github_agent = Agent(
- name="GitHub agent",
- instructions="You are a helpful assistant that can assist with GitHub API calls.",
- model="gpt-4o-mini",
- tools=tools,
- )
-
- user_id = "{arcade_user_id}" # Make sure to use a unique user ID
-
- while True:
- try:
- result = await Runner.run(
- starting_agent=github_agent,
- input="Star the arcadeai/arcade-ai repo",
- # Pass the user_id for auth
- context={"user_id": user_id},
- )
- print("Final output:\n\n", result.final_output)
- break # Exit the loop if successful
-
- except AuthorizationError as e:
- auth_url = str(e)
- print(f"{auth_url}. Please authenticate to continue.")
-
- # Wait for the user to authenticate
- await client.auth.wait_for_completion(e.result.id)
-
-
-if __name__ == "__main__":
- import asyncio
-
- asyncio.run(main())
-```
-
-
-
-
-
-Check out the complete working example in our [GitHub repository](https://github.com/ArcadeAI/arcade-ai/tree/main/examples/openai-agents-ts/src/waitForCompletion.ts).
-
-```javascript
-import Arcade from '@arcadeai/arcadejs';
-import { isAuthorizationRequiredError, toZod } from "@arcadeai/arcadejs/lib";
-import { Agent, run, tool } from '@openai/agents';
-
-async function main() {
- // 1) Initialize Arcade client
- const client = new Arcade();
-
- // 2) Fetch Gmail MCP Server from Arcade and prepare tools for OpenAI Agents
- const googleToolkit = await client.tools.list({ toolkit: "gmail", limit: 30 });
- const tools = toZod({
- tools: googleToolkit.items,
- client,
- userId: "", // Replace this with your application's user ID (e.g. email address, UUID, etc.)
- }).map(tool);
-
- // 3) Create a new agent with the Gmail MCP Server
- const googleAgent = new Agent({
- name: "Gmail agent",
- instructions: "You are a helpful assistant that can assist with Google API calls.",
- model: "gpt-4o-mini",
- tools
- });
-
- // 4) Run the agent, if authorization is required, wait for it to complete and retry
- while (true) {
- try {
- const result = await run(googleAgent, "What are my latest emails?");
- console.log(result.finalOutput);
- break; // Exit the loop if the result is successful
- } catch (error) {
- if (error instanceof Error && isAuthorizationRequiredError(error)) {
- const response = await client.tools.authorize({
- tool_name: "Gmail_ListEmails",
- user_id: "",
- });
- if (response.status !== "completed") {
- console.log(`Please complete the authorization challenge in your browser: ${response.url}`);
- }
-
- // Wait for the authorization to complete
- await client.auth.waitForCompletion(response);
- console.log("Authorization completed, retrying...");
- }
- }
- }
-}
-
-main();
-```
-
-
-This example handles the authentication flow by:
-
-1. Attempting to run the agent
-2. Catching any AuthorizationError
-3. Open the authentication URL in a browser
-4. Waiting for the user to complete authentication
-5. Retrying the operation after a wait period
-
-
-
-
-## Authentication persistence
-
-Once a user authorizes with an auth provider, Arcade will remember the authorization for that specific user_id and MCP Server. You don't need to re-authorize each time you run the agent.
-
-Key points to remember:
-
-- Always use a consistent and unique `user_id` for each user
-- Store the `user_id` securely in your application
-- Different MCP Servers require separate authorization flows
-- Authorization tokens are managed by Arcade, not your application
-
-## Next steps
-
-- Build a user interface to handle authorization flows smoothly
-- Explore other Arcade MCP Servers like Google, LinkedIn, or X
-- Create multi-step workflows with multiple tools and authorizations
-- Learn to build your own custom tools with the Arcade Tool SDK
-
-By handling Arcade's authorization flow correctly, you can build AI-driven applications that securely integrate with various services while respecting user permissions. Have fun exploring Arcade!
diff --git a/app/en/home/observability-platforms/_meta.tsx b/app/en/home/observability-platforms/_meta.tsx
new file mode 100644
index 000000000..22b2653f5
--- /dev/null
+++ b/app/en/home/observability-platforms/_meta.tsx
@@ -0,0 +1,4 @@
+export default {
+ "quickstarts-placeholder":
+ "Placeholder for Quickstarts of various observability platforms",
+};
diff --git a/app/en/home/observability-platforms/quickstarts-placeholder/page.mdx b/app/en/home/observability-platforms/quickstarts-placeholder/page.mdx
new file mode 100644
index 000000000..6f3cdb56d
--- /dev/null
+++ b/app/en/home/observability-platforms/quickstarts-placeholder/page.mdx
@@ -0,0 +1,7 @@
+# Placeholder for Quickstarts of various observability platforms
+
+Documentation coming soon.
+
+## Overview
+
+This section will contain detailed information about integrating Arcade with various observability platforms.
\ No newline at end of file
diff --git a/app/en/home/python-quickstart/page.mdx b/app/en/home/python-quickstart/page.mdx
new file mode 100644
index 000000000..04ef6b4c2
--- /dev/null
+++ b/app/en/home/python-quickstart/page.mdx
@@ -0,0 +1,38 @@
+# Python Quickstart
+
+This is a placeholder page for the Python quickstart guide.
+
+## Overview
+
+Get started with Arcade tools in Python applications quickly and easily.
+
+## Prerequisites
+
+- Python 3.8 or higher
+- Arcade API key
+- Virtual environment (recommended)
+
+## Installation
+
+```bash
+pip install arcade-ai
+```
+
+## Quick Setup
+
+```python
+import arcade
+
+# Initialize the client
+client = arcade.Arcade(api_key="your-api-key")
+
+# Call a tool
+result = client.tools.call("example-tool", {"param": "value"})
+print(result)
+```
+
+## Next Steps
+
+- [Tool Calling Introduction](/en/home/tool-calling-intro)
+- [Authorized Tool Calling](/en/home/authorized-tool-calling)
+- [Error Handling](/en/home/error-handling)
\ No newline at end of file
diff --git a/app/en/home/quickstart/page.mdx b/app/en/home/quickstart/page.mdx
deleted file mode 100644
index 212aba924..000000000
--- a/app/en/home/quickstart/page.mdx
+++ /dev/null
@@ -1,206 +0,0 @@
----
-title: "Start using Arcade's Hosted Tools"
-description: "Learn how to get started with Arcade's Hosted Tools"
----
-
-import { Steps, Tabs, Callout } from "nextra/components";
-import { SignupLink } from "@/app/_components/analytics";
-
-# Arcade's Hosted Tools Quickstart
-
-Arcade gives your AI agents the power to act. With Arcade's Hosted Tools, your AI can send Gmail, update Notion, message in Slack, and more.
-
-
-
-
-Install and use the Arcade client to call Arcade Hosted Tools.
-
-
-
-
-
-- An Arcade account
-- An [Arcade API key](/home/api-keys)
-- The [`uv` package manager](https://docs.astral.sh/uv/getting-started/installation/)
-
-
-
-
-
-- Install the Arcade client
-- Execute your first tool using the Arcade client
-- Authorize a tool to star a GitHub repository on your behalf
-
-
-
-
-
-
-### Install the Arcade client
-
-
-
-
- In your terminal, run the following command to install the Python client package `arcadepy`:
-
-```bash
-uv pip install arcadepy
-```
-
-
-
-
- In your terminal, run the following command to install the JavaScript client package `@arcadeai/arcadejs`:
-
-```bash
-npm install @arcadeai/arcadejs
-```
-
-
-
-
-
-### Instantiate and use the client
-
-
-
-
-
-Create a new script called `example.py`:
-
-```python filename="example.py"
-from arcadepy import Arcade
-
-# You can also set the `ARCADE_API_KEY` environment variable instead of passing it as a parameter.
-
-client = Arcade(api_key="{arcade_api_key}")
-
-# Arcade needs a unique identifier for your application user (this could be an email address, a UUID, etc).
-
-# In this example, use the email you used to sign up for Arcade.dev:
-
-user_id = "{arcade_user_id}"
-
-# Let's use the `Math.Sqrt` tool from the Arcade Math MCP Server to get the square root of a number.
-
-response = client.tools.execute(
- tool_name="Math.Sqrt",
- input={"a": '625'},
- user_id=user_id,
-)
-
-print(f"The square root of 625 is {response.output.value}")
-
-# Now, let's use a tool that requires authentication to star a GitHub repository
-
-auth_response = client.tools.authorize(
-tool_name="GitHub.SetStarred",
-user_id=user_id,
-)
-
-if auth_response.status != "completed":
- print(f"Click this link to authorize: `{auth_response.url}`. The process will continue once you have authorized the app." ) # Wait for the user to authorize the app
- client.auth.wait_for_completion(auth_response.id);
-
-response = client.tools.execute(
- tool_name="GitHub.SetStarred",
- input={
- "owner": "ArcadeAI",
- "name": "arcade-mcp",
- "starred": True,
- },
- user_id=user_id,
-)
-
-print(response.output.value)
-
-```
-
-
-
-
-
-Create a new script called `example.mjs`:
-
-```javascript filename="example.mjs"
-import Arcade from "@arcadeai/arcadejs";
-
-// You can also set the `ARCADE_API_KEY` environment variable instead of passing it as a parameter.
-const client = new Arcade({
- apiKey: "{arcade_api_key}",
-});
-
-// Arcade needs a unique identifier for your application user (this could be an email address, a UUID, etc).
-// In this example, use the email you used to sign up for Arcade.dev:
-let userId = "{arcade_user_id}";
-
-// Let's use the `Math.Sqrt` tool from the Arcade Math MCP Server to get the square root of a number.
-const response_sqrt = await client.tools.execute({
- tool_name: "Math.Sqrt",
- input: { a: "625" },
- user_id: userId,
-});
-
-console.log(response_sqrt.output.value);
-
-// Now, let's use a tool that requires authentication
-
-const authResponse = await client.tools.authorize({
- tool_name: "GitHub.SetStarred",
- user_id: userId,
-});
-
-if (authResponse.status !== "completed") {
- console.log(
- `Click this link to authorize: \`${authResponse.url}\`. The process will continue once you have authorized the app.`
- );
- // Wait for the user to authorize the app
- await client.auth.waitForCompletion(authResponse.id);
-}
-
-const response_github = await client.tools.execute({
- tool_name: "GitHub.SetStarred",
- input: {
- owner: "ArcadeAI",
- name: "arcade-mcp",
- starred: true,
- },
- user_id: userId,
-});
-
-console.log(response_github.output.value);
-```
-
-
-
-
-
-### Run the code
-
-
-
-
-
- ```bash
- uv run example.py
- > The square root of 625 is 25
- > Successfully starred the repository ArcadeAI/arcade-mcp
- ```
-
-
-
-
- ```bash
- node example.mjs
- > The square root of 625 is 25
- > Successfully starred the repository ArcadeAI/arcade-mcp
- ```
-
-
-
-
-
-
-## Next Steps
-
-In this simple example, we call the tool methods directly. In your real applications and agents, you'll likely be letting the LLM decide which tools to call - learn more about using Arcade with Frameworks in the [Frameworks](/home/langchain/use-arcade-tools) section, or [how to build your own tools](/home/build-tools/create-a-mcp-server).
diff --git a/app/en/home/quickstarts/_meta.tsx b/app/en/home/quickstarts/_meta.tsx
new file mode 100644
index 000000000..1bb896833
--- /dev/null
+++ b/app/en/home/quickstarts/_meta.tsx
@@ -0,0 +1,5 @@
+export default {
+ "call-tool-easy": "Call a tool in your agent",
+ "call-tool-personal-agent":
+ "Call a tool in your IDEs, MCP clients, or agents",
+};
diff --git a/app/en/home/quickstarts/call-tool-easy/page.mdx b/app/en/home/quickstarts/call-tool-easy/page.mdx
new file mode 100644
index 000000000..b041167f0
--- /dev/null
+++ b/app/en/home/quickstarts/call-tool-easy/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Call a tool in your agent"
+description: "The simplest way to call an Arcade tool in your agent"
+---
+
+# Call a tool in your agent
+
+Coming soon!
\ No newline at end of file
diff --git a/app/en/home/quickstarts/call-tool-personal-agent/page.mdx b/app/en/home/quickstarts/call-tool-personal-agent/page.mdx
new file mode 100644
index 000000000..fddd5f371
--- /dev/null
+++ b/app/en/home/quickstarts/call-tool-personal-agent/page.mdx
@@ -0,0 +1,25 @@
+# Call a tool from your personal agent
+
+Learn how to integrate Arcade tools with your personal AI agent.
+
+## Overview
+
+Learn how to call tools in 3rd party agents, apps, or IDEs using the MCP Gateway.
+
+## Prerequisites
+
+- Arcade API key
+- Supported MCP client
+
+## Setup Steps
+
+1. Configure your MCP Gateway
+2. Connect to your client application
+3. Test tool calling functionality
+
+## Supported Clients
+
+- Cursor
+- Claude Desktop
+- Visual Studio Code
+- Other MCP-compatible applications
\ No newline at end of file
diff --git a/app/en/home/sample-agents/page.mdx b/app/en/home/sample-agents/page.mdx
new file mode 100644
index 000000000..454b662a9
--- /dev/null
+++ b/app/en/home/sample-agents/page.mdx
@@ -0,0 +1,26 @@
+# Sample Agents with Tool Calling
+
+This is a placeholder page for sample agents with tool calling examples.
+
+## Overview
+
+Explore a suite of example agents you can duplicate and build off of for your custom applications.
+
+## Available Examples
+
+- Customer support agent
+- Data analysis agent
+- Content creation agent
+- Task automation agent
+
+## Getting Started
+
+Each sample agent includes:
+- Complete source code
+- Setup instructions
+- Tool configuration
+- Deployment guidelines
+
+## Template Repository
+
+Find all sample agents in our GitHub repository with ready-to-deploy examples.
\ No newline at end of file
diff --git a/app/en/home/security-section/_meta.tsx b/app/en/home/security-section/_meta.tsx
new file mode 100644
index 000000000..216e236f4
--- /dev/null
+++ b/app/en/home/security-section/_meta.tsx
@@ -0,0 +1,5 @@
+export default {
+ "platform-security": "Platform security",
+ "enterprise-sso": "Enterprise single sign on",
+ "rbac-config": "Configure role-based access control for your organization",
+};
diff --git a/app/en/home/security-section/enterprise-sso/page.mdx b/app/en/home/security-section/enterprise-sso/page.mdx
new file mode 100644
index 000000000..009719dab
--- /dev/null
+++ b/app/en/home/security-section/enterprise-sso/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Enterprise Single Sign On"
+description: "Learn about enterprise SSO integration"
+---
+
+# Enterprise Single Sign On
+
+Coming soon!
diff --git a/app/en/home/security-section/platform-security/page.mdx b/app/en/home/security-section/platform-security/page.mdx
new file mode 100644
index 000000000..0a0971791
--- /dev/null
+++ b/app/en/home/security-section/platform-security/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Platform Security"
+description: "Learn about Arcade platform security"
+---
+
+# Platform Security
+
+Coming soon!
\ No newline at end of file
diff --git a/app/en/home/security-section/rbac-config/page.mdx b/app/en/home/security-section/rbac-config/page.mdx
new file mode 100644
index 000000000..48c351e9b
--- /dev/null
+++ b/app/en/home/security-section/rbac-config/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Configuring Role Based Access Control for your organization"
+description: "Learn how to configure RBAC for your organization"
+---
+
+# Configuring Role Based Access Control for your organization
+
+Coming soon!
diff --git a/app/en/home/security/page.mdx b/app/en/home/security/page.mdx
index 1bed172bd..7621354ee 100644
--- a/app/en/home/security/page.mdx
+++ b/app/en/home/security/page.mdx
@@ -1,49 +1,7 @@
----
-title: "Security Research Program"
-description: "Report security vulnerabilities and help us build safe and reliable tools"
----
+# Security
-# Security Research Program
+Security best practices for Arcade applications.
-At Arcade, security is fundamental to our mission of building safe and reliable tools. We recognize that the security research community plays a valuable role in identifying potential vulnerabilities.
-
-## Scope
-
-Our program covers security issues in:
-* Arcade production services and APIs
-* Agent authentication and authorization mechanisms
-* Data handling and storage systems
-* Published open-source components
-
-## What we're looking for
-
-We're interested in reports about:
-* Authentication or authorization bypasses
-* Data exposure or leakage
-* Injection vulnerabilities
-* Logic flaws affecting agent behavior
-* Issues that could compromise user data or agent integrity
-
-## Reporting process
-
-Please email [security@arcade.dev](mailto:security@arcade.dev) with:
-* A clear description of the issue
-* Steps to reproduce
-* Potential impact assessment
-* Any relevant proof-of-concept code (please be responsible)
-
-We'll acknowledge receipt within 72 hours and aim to provide an initial assessment within one week.
-
-## Guidelines
-
-* Please allow us reasonable time to address issues before public disclosure
-* Avoid automated scanning that could impact service availability
-* Do not access or modify other users' data
-* Keep any discovered vulnerabilities confidential until resolved
-
-## Recognition
-
-While we're a small team with limited resources, we appreciate the effort researchers put into improving our security. We'll credit researchers (with permission) in our security updates and may provide modest rewards for significant findings on a case-by-case basis.
-
-For questions about this program, please contact [security@arcade.dev](mailto:security@arcade.dev).
+## Overview
+Learn about security considerations and best practices.
diff --git a/app/en/home/serve-tools/_meta.tsx b/app/en/home/serve-tools/_meta.tsx
deleted file mode 100644
index c7e61f707..000000000
--- a/app/en/home/serve-tools/_meta.tsx
+++ /dev/null
@@ -1,4 +0,0 @@
-export default {
- "arcade-deploy": "Arcade Deploy",
- "securing-arcade-mcp": "Securing Arcade MCP",
-};
diff --git a/app/en/home/serve-tools/securing-arcade-mcp/page.mdx b/app/en/home/serve-tools/securing-arcade-mcp/page.mdx
deleted file mode 100644
index 4b3a8a287..000000000
--- a/app/en/home/serve-tools/securing-arcade-mcp/page.mdx
+++ /dev/null
@@ -1,15 +0,0 @@
-# Securing Arcade MCP Deployments
-
-You may have noticed that when you connected to the MCP serer you created with `arcade-mcp`, you could immediately call your tools from local MCP Clients and agents, like Claude and Cursor. This is because the `arcade-mcp` server is *not* secured by any mechanism by default. Most use-cases for MCP servers today are local development or local to a single machine, and we optimize for that use-case.
-
-However, you can secure your MCP server by deploying it to Arcade (available today) or using OAuth (coming soon).
-
-## Arcade Deploy
-When you `arcade deploy` your MCP server, it will be secured behind the Arcade platform.
-
-Under the hood, we disable the MCP routes provided by `arcade-mcp`, and use the Arcade Engine as a gateway for your MCP server, which has a number of additional features. Arcade will create a randomized secure secret for your MCP server (via the `ARCADE_WORKER_SECRET` environment variable) so that your server is protected from unauthorized access, as well as being isolated from direct access from outside of the Arcade platform. Servers managed by Arcade (servers that are `arcade deploy`ed) serve `/worker` endpoints that are protected by this secret. The worker endpoints are `worker/health`, `/worker/tools`, and `/worker/tools/invoke`. The health endpoint is not protected by this secret, but the listing tools and tool invocations are. You can explore this locally by setting the same environment variable in your locally.
-
-Learn more about how to deploy your MCP server to Arcade [here](/home/serve-tools/arcade-deploy).
-
-## OAuth (Coming soon)
-Coming soon, you will be able to secure your MCP server's `/mcp` endpoints with a OAuth Authorization Server (AS) - either using Dynamic Client Registration (DCR) or Client ID Metadata Documents (CIMD). Learn more about how MCP integrates with OAuth [here](https://blog.modelcontextprotocol.io/posts/client_registration/).
diff --git a/app/en/home/setup/_meta.tsx b/app/en/home/setup/_meta.tsx
new file mode 100644
index 000000000..d624b2d59
--- /dev/null
+++ b/app/en/home/setup/_meta.tsx
@@ -0,0 +1,4 @@
+export default {
+ "api-key": "Get an API key",
+ "connect-arcade-docs": "Connect Arcade docs to your IDE",
+};
diff --git a/app/en/home/setup/api-key/page.mdx b/app/en/home/setup/api-key/page.mdx
new file mode 100644
index 000000000..b1c436f3e
--- /dev/null
+++ b/app/en/home/setup/api-key/page.mdx
@@ -0,0 +1,108 @@
+---
+title: "Getting Your API Key"
+description: "Learn how to obtain and manage your Arcade API key"
+---
+
+import { Steps, Tabs, Callout } from "nextra/components";
+import { SignupLink } from "@/app/_components/analytics";
+
+# Getting Your API Key
+
+Before you begin, you'll need an Arcade account - if you haven't created one yet, you can sign up here. Once you have an account, you can generate API keys through either our dashboard or CLI.
+
+
+
+
+
+### Using the Dashboard
+
+
+
+
+
+
+### Navigate to API Keys page
+Visit the [API Keys page](https://api.arcade.dev/dashboard/api-keys) in Arcade Dashboard.
+
+### Create a new API key
+
+1. Click the `Create API Key` button in the top right
+2. Enter a descriptive name to help identify your key
+3. Click `Create API Key` to generate your key
+
+### Save your API key securely
+
+1. Copy your API key immediately - it will only be shown once
+2. Store it securely
+3. You can always generate new keys if needed
+
+
+
+
+
+
+
+### Using the CLI
+
+
+
+### Install and login
+
+1. Install the Arcade CLI:
+
+
+
+
+```bash
+uv tool install arcade-mcp
+```
+
+
+This will install the Arcade CLI as a [uv tool](https://docs.astral.sh/uv/guides/tools/), making it available system wide.
+
+
+
+
+```bash
+pip install arcade-mcp
+```
+
+
+
+2. Start the login process:
+
+```bash
+arcade login
+```
+
+### Complete setup
+
+The CLI will automatically:
+
+- Print your API key to the console
+- Save your credentials to `~/.arcade/credentials.yaml`
+
+
+
+
+
+
+
+ API keys are administrator credentials. Anyone who has your API key can make
+ requests to Arcade as you. Always store your API keys in a safe place, such as
+ system environment variables, and never commit them to version control, share
+ them publicly, or use them in browser or frontend code.
+
+## Next Steps
+
+Once you have your API key, you can:
+
+- [Start using tools](/home/quickstart)
+- [Create custom tools](/home/build-tools/create-a-mcp-server)
\ No newline at end of file
diff --git a/app/en/home/agentic-development/page.mdx b/app/en/home/setup/connect-arcade-docs/page.mdx
similarity index 96%
rename from app/en/home/agentic-development/page.mdx
rename to app/en/home/setup/connect-arcade-docs/page.mdx
index 40845e0e1..d575d5d7c 100644
--- a/app/en/home/agentic-development/page.mdx
+++ b/app/en/home/setup/connect-arcade-docs/page.mdx
@@ -23,4 +23,4 @@ Context7 is an MCP server designed to provide Large Language Models (LLMs) and A
To use Context7, you first need to add the [Context7 MCP server](https://github.com/upstash/context7) to your editor, and then select the [`arcadeai/docs` project](https://context7.com/arcadeai/docs).
-Learn more about Context7 [here](https://context7.com/).
+Learn more about Context7 [here](https://context7.com/).
\ No newline at end of file
diff --git a/app/en/home/sharing-with-end-users/_meta.tsx b/app/en/home/sharing-with-end-users/_meta.tsx
new file mode 100644
index 000000000..a5b904275
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/_meta.tsx
@@ -0,0 +1,4 @@
+export default {
+ "multi-user-auth": "Set up secure multi-user auth for your app",
+ "custom-auth": "Customize auth",
+};
diff --git a/app/en/home/sharing-with-end-users/custom-auth/_meta.tsx b/app/en/home/sharing-with-end-users/custom-auth/_meta.tsx
new file mode 100644
index 000000000..3cc51dc10
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/_meta.tsx
@@ -0,0 +1,32 @@
+export default {
+ overview: "Overview",
+ oauth2: "OAuth 2.0",
+ airtable: "Airtable",
+ asana: "Asana",
+ atlassian: "Atlassian",
+ calendly: "Calendly",
+ clickup: "ClickUp",
+ discord: "Discord",
+ figma: "Figma",
+ github: "GitHub",
+ google: "Google",
+ hubspot: "Hubspot",
+ linear: "Linear",
+ linkedin: "LinkedIn",
+ mailchimp: "Mailchimp",
+ microsoft: "Microsoft",
+ miro: "Miro",
+ notion: "Notion",
+ pagerduty: "PagerDuty",
+ reddit: "Reddit",
+ salesforce: "Salesforce",
+ slack: "Slack",
+ spotify: "Spotify",
+ square: "Square",
+ ticktick: "TickTick",
+ twitch: "Twitch",
+ x: "X",
+ zendesk: "Zendesk",
+ zoho: "Zoho",
+ zoom: "Zoom",
+};
diff --git a/app/en/home/sharing-with-end-users/custom-auth/airtable/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/airtable/page.mdx
new file mode 100644
index 000000000..7c58a9d75
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/airtable/page.mdx
@@ -0,0 +1,302 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Airtable
+
+The Airtable auth provider enables tools and agents to call [Airtable APIs](https://airtable.com/developers/web/api/introduction) on behalf of a user using OAuth 2.0 authentication.
+
+
+ Want to quickly get started with Airtable in your agent or AI app? The pre-built
+ [Arcade Airtable MCP Server](/mcp-servers/productivity/airtable-api) is what you
+ want!
+
+
+### What's documented here
+
+This page describes how to use and configure Airtable auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade Airtable MCP Server](/mcp-servers/productivity/airtable-api), which provides pre-built tools for interacting with Airtable
+- Your [app code](#using-airtable-auth-in-app-code) that needs to call the Airtable API
+- Or, your [custom tools](#using-airtable-auth-in-custom-tools) that need to call the Airtable API
+
+## Configuring Airtable auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Airtable app credentials. This way, your users will see your application's name requesting permission.
+
+Before showing how to configure your Airtable app credentials, let's go through the steps to create an Airtable app.
+
+### Create an Airtable app
+
+To integrate with Airtable's API, you'll need to create an OAuth integration:
+
+
+
+#### Access the Airtable Developer Hub
+
+Navigate to the [Airtable Developer Hub](https://airtable.com/developers/web) and sign in with your Airtable account.
+
+#### Create a new OAuth integration
+
+1. Go to the [Create OAuth Integration](https://airtable.com/create/oauth) page
+2. Fill in the required details:
+ - **Integration Name**: Choose a descriptive name for your application
+ - **Description**: Provide a brief description of your app's purpose
+
+#### Configure OAuth settings
+
+1. Set the **Redirect URL** to the redirect URL generated by Arcade (see configuration section below)
+2. Configure the required **Scopes** for your application:
+ - `data.records:read` - Read records from tables
+ - `data.records:write` - Create, update, and delete records
+ - `schema.bases:read` - Read base schema
+ - Add other scopes as needed for your use case
+
+#### Obtain your credentials
+
+1. After creating your integration, you'll receive a **Client ID**
+2. Generate a **Client Secret** from your integration settings
+3. Copy both values for use in Arcade configuration
+
+
+
+For detailed instructions, refer to Airtable's [OAuth documentation](https://airtable.com/developers/web/guides/oauth-integrations).
+
+Next, add the Airtable app to Arcade.
+
+## Configuring your own Airtable Auth Provider in Arcade
+
+
+
+
+### Configure Airtable Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **OAuth** section of the Arcade Dashboard left-side menu, click **Providers**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **OAuth 2.0** tab at the top.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "arcade-airtable").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Airtable integration.
+- Configure the OAuth 2.0 endpoints:
+ - **Authorization URL**: `https://airtable.com/oauth2/v1/authorize`
+ - **Token URL**: `https://airtable.com/oauth2/v1/token`
+- Note the **Redirect URL** generated by Arcade. This must be set as your Airtable integration's Redirect URL.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+
+
+
+
+### Configure Airtable Auth Using Configuration File
+
+
+ This method is only available when you are [self-hosting the
+ engine](/home/deployment/on-prem-mcp)
+
+
+
+
+#### Set environment variables
+
+Set the following environment variables:
+
+```bash
+export AIRTABLE_CLIENT_ID=""
+export AIRTABLE_CLIENT_SECRET=""
+```
+
+Or, you can set these values in a `.env` file:
+
+```bash
+AIRTABLE_CLIENT_ID=""
+AIRTABLE_CLIENT_SECRET=""
+```
+
+#### Edit the Engine configuration
+
+Edit the `engine.yaml` file and add a new item to the `auth.providers` section:
+
+```yaml
+auth:
+ providers:
+ - id: arcade-airtable
+ description: Airtable OAuth 2.0 provider
+ enabled: true
+ type: oauth2
+ client_id: ${env:AIRTABLE_CLIENT_ID}
+ client_secret: ${env:AIRTABLE_CLIENT_SECRET}
+ oauth2:
+ scope_delimiter: " "
+ pkce:
+ enabled: true
+ code_challenge_method: S256
+ authorize_request:
+ endpoint: "https://airtable.com/oauth2/v1/authorize"
+ params:
+ response_type: code
+ client_id: "{{client_id}}"
+ redirect_uri: "{{redirect_uri}}"
+ scope: "{{scopes}}"
+ state: "{{state}}"
+ token_request:
+ endpoint: "https://airtable.com/oauth2/v1/token"
+ params:
+ grant_type: authorization_code
+ client_id: "{{client_id}}"
+ redirect_uri: "{{redirect_uri}}"
+ response_content_type: application/json
+```
+
+
+
+
+
+
+When you use tools that require Airtable auth using your Arcade account credentials, Arcade will automatically use this Airtable OAuth provider. If you have multiple Airtable providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+## Using Airtable auth in app code
+
+Use the Airtable auth provider in your own agents and AI apps to get a user token for the Airtable API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Airtable API:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="arcade-airtable",
+ scopes=["data.records:read", "data.records:write", "schema.bases:read"]
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-11}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade();
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+const authResponse = await client.auth.start(
+ userId,
+ "arcade-airtable",
+ ["data.records:read", "data.records:write", "schema.bases:read"]
+);
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using Airtable auth in custom tools
+
+You can use the pre-built [Arcade Airtable MCP Server](/mcp-servers/productivity/airtable-api) to quickly build agents and AI apps that interact with Airtable.
+
+If the pre-built tools in the Airtable MCP Server don't meet your needs, you can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Airtable API.
+
+Use the `OAuth2()` auth class to specify that a tool requires authorization with Airtable. The `context.authorization.token` field will be automatically populated with the user's Airtable token:
+
+```python {8-12,22}
+from typing import Annotated
+
+import httpx
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import OAuth2
+
+
+@tool(
+ requires_auth=OAuth2(
+ provider_id="arcade-airtable",
+ scopes=["data.records:read", "schema.bases:read"]
+ )
+)
+async def list_bases(
+ context: ToolContext,
+) -> Annotated[dict, "The user's bases."]:
+ """
+ Retrieve the list of bases accessible to the authenticated user.
+ """
+ url = "https://api.airtable.com/v0/meta/bases"
+ headers = {
+ "Authorization": context.authorization.token,
+ }
+
+ async with httpx.AsyncClient() as client:
+ response = await client.get(url, headers=headers)
+ response.raise_for_status()
+ return dict(response.json())
+```
+
+## Available Scopes
+
+Airtable supports various OAuth scopes that determine the level of access your application has:
+
+- `data.records:read` - Read records from tables
+- `data.records:write` - Create, update, and delete records
+- `data.recordComments:read` - Read comments on records
+- `data.recordComments:write` - Create and update comments on records
+- `schema.bases:read` - Read base schema information
+- `schema.bases:write` - Modify base schema
+- `webhook:manage` - Create and manage webhooks
+- `user.email:read` - Read user email address
+
+For a complete list of available scopes, refer to the [Airtable Scopes documentation](https://airtable.com/developers/web/api/scopes).
+
diff --git a/app/en/home/sharing-with-end-users/custom-auth/asana/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/asana/page.mdx
new file mode 100644
index 000000000..62eb9c257
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/asana/page.mdx
@@ -0,0 +1,307 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Asana
+
+The Asana auth provider enables tools and agents to call Asana APIs on behalf of a user.
+
+
+ Want to quickly get started with Asana services in your agent or AI app? The
+ pre-built [Arcade Asana MCP Server](/mcp-servers/productivity/asana) is what you
+ want!
+
+
+## What's documented here
+
+This page describes how to use and configure Asana auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade Asana MCP Server](/mcp-servers/productivity/asana), which provides pre-built tools for interacting with Asana
+- Your [app code](#using-asana-auth-in-app-code) that needs to call Asana APIs
+- Or, your [custom tools](#using-asana-auth-in-custom-tools) that need to call Asana APIs
+
+## Use Arcade's Default Asana Auth Provider
+
+Arcade offers a default Asana auth provider that you can use in the Arcade Cloud Platform. In this case, your users will see `Arcade` as the name of the application that's requesting permission.
+
+If you choose to use Arcade's Asana auth, you don't need to configure anything. Follow the [Asana MCP Server examples](/mcp-servers/productivity/asana) to get started calling Asana tools.
+
+## Use Your Own Asana App Credentials
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Asana app credentials. This way, your users will see your application's name requesting permission.
+
+
+Before showing how to configure your Asana app credentials, let's go through the steps to create an Asana app.
+
+## Create an Asana App
+
+Follow the documentation on [Building an App with Asana](https://developers.asana.com/docs/overview). You may create a [developer sandbox account](https://developers.asana.com/docs/developer-sandbox) to test your app before moving to production.
+
+When creating your app, use the following settings:
+
+- Set an appropriate App name, description and icon. This will be visible to your users authorizing access to your app.
+- Take note of the **Client ID** and **Client Secret**.
+- In the OAuth settings:
+ - Under "Redirect URLs", click **Add Redirect URL** and add the redirect URL generated by Arcade (see below).
+ - Under "Permission Scopes", select "Full Permissions"
+- In the "App Listing Details" section, optionally add more information about your app.
+- In the "Manage Distribution" section, under "Choose a distribution method", select "Any workspace".
+- Optionally, submit your app for the Asana team review.
+
+
+ Asana [recently
+ introduced](https://forum.asana.com/t/new-oauth-permission-scopes/1048556)
+ granular permission scopes. This feature is still in preview and the scopes
+ available at the moment do not include all endpoints/actions that the Asana
+ MCP Servers needs. For those reasons, Arcade uses the "Full Permissions"
+ scope.
+
+
+## Configuring your own Asana Auth Provider in Arcade
+
+
+
+
+
+### Configure Asana Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Included Providers** tab at the top.
+- In the **Provider** dropdown, select **Asana**.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "my-asana-provider").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Asana app.
+- Note the **Redirect URL** generated by Arcade. This must be added to your Asana app's Redirect URLs.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+When you use tools that require Asana auth using your Arcade account credentials, Arcade will automatically use this Asana OAuth provider. If you have multiple Asana providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+
+
+
+## Using the Arcade Asana MCP Servers
+
+The [Arcade Asana MCP Server](/mcp-servers/productivity/asana) provides tools to interact with various Asana objects, such as tasks, projects, teams, and users.
+
+Refer to the [MCP Server documentation and examples](/mcp-servers/productivity/asana) to learn how to use the MCP Server to build agents and AI apps that interact with Asana services.
+
+## Using Asana auth in app code
+
+Use the Asana auth provider in your own agents and AI apps to get a user-scoped token for the Asana API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Asana API:
+
+
+ As explained [above](#create-an-asana-app), the Asana granular permission
+ scopes are in preview and not yet supported. The `"default"` scope should be
+ used to authorize any action/endpoint you need to call in the Asana API.
+
+
+
+
+
+
+```python {21-22}
+from arcadepy import Arcade
+
+client = Arcade(base_url="https://api.arcade.dev") # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="asana",
+ scopes=["default"],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+# Do something interesting with the token...
+auth_token = auth_response.context.token
+```
+
+
+
+
+
+
+```javascript {20-21}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade({ baseURL: "https://api.arcade.dev" }); // Automatically finds the `ARCADE_API_KEY` env variable
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+const authResponse = await client.auth.start(userId, "asana", {
+ scopes: ["default"],
+});
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+const response = await client.auth.waitForCompletion(authResponse);
+
+// Do something interesting with the token...
+const auth_token = response.context.token;
+```
+
+
+
+
+You can use the auth token to call the [Get multiple tasks endpoint](https://developers.asana.com/reference/gettasks) and read information about tasks, for example. Any Asana API endpoint can be called with the auth token.
+
+## Using Asana auth in custom tools
+
+You can use the pre-built [Arcade Asana MCP Server](/mcp-servers/productivity/asana) to quickly build agents and AI apps that interact with Asana.
+
+If the pre-built tools in the Asana MCP Server don't meet your needs, you can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with Asana API.
+
+Use the `Asana()` auth class to specify that a tool requires authorization with Asana. The authentication token needed to call the Asana API is available in the tool context through the `context.get_auth_token_or_empty()` method.
+
+
+ As explained [above](#create-an-asana-app), the Asana granular permission
+ scopes are in preview and not yet supported. The `"default"` scope should be
+ used as the only scope in all tools.
+
+
+```python {9,17}
+from typing import Annotated
+
+import httpx
+
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import Asana
+
+
+@tool(requires_auth=Asana(scopes=["default"]))
+async def delete_task(
+ context: ToolContext,
+ task_id: Annotated[str, "The ID of the task to delete."],
+) -> Annotated[dict, "Details of the deletion response"]:
+ """Deletes a task."""
+ url = f"https://api.asana.com/api/1.0/tasks/{task_id}"
+ headers = {
+ "Authorization": f"Bearer {context.get_auth_token_or_empty()}",
+ "Accept": "application/json",
+ }
+
+ async with httpx.AsyncClient() as client:
+ response = await client.delete(url, headers=headers)
+ response.raise_for_status()
+ return response.json()
+```
+
+
+Your new tool can be called like demonstrated below:
+
+
+
+
+ If you are self-hosting, change the `base_url` parameter in the `Arcade` constructor to match your Arcade Engine URL. By default, the Engine will be available at `http://localhost:9099`.
+
+
+```python
+from arcadepy import Arcade
+
+client = Arcade(base_url="https://api.arcade.dev") # Automatically finds the `ARCADE_API_KEY` env variable
+
+USER_ID = "{arcade_user_id}"
+TOOL_NAME = "Asana.DeleteTask"
+
+auth_response = client.tools.authorize(tool_name=TOOL_NAME, user_id=USER_ID)
+
+if auth_response.status != "completed":
+ print(f"Click this link to authorize: {auth_response.url}")
+
+# Wait for the authorization to complete
+client.auth.wait_for_completion(auth_response)
+
+tool_input = {
+ "task_id": "1234567890",
+}
+
+response = client.tools.execute(
+ tool_name=TOOL_NAME,
+ input=tool_input,
+ user_id=USER_ID,
+)
+print(response.output.value)
+```
+
+
+
+
+ If you are self-hosting, change the `baseURL` parameter in the `Arcade` constructor to match your Arcade Engine URL. By default, the Engine will be available at `http://localhost:9099`.
+
+
+```javascript
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade({ baseURL: "https://api.arcade.dev" }); // Automatically finds the `ARCADE_API_KEY` env variable
+
+const USER_ID = "{arcade_user_id}";
+const TOOL_NAME = "Asana.DeleteTask";
+
+// Start the authorization process
+const authResponse = await client.tools.authorize({
+ tool_name: TOOL_NAME,
+ user_id: USER_ID,
+});
+
+if (authResponse.status !== "completed") {
+ console.log(`Click this link to authorize: ${authResponse.url}`);
+}
+
+// Wait for the authorization to complete
+await client.auth.waitForCompletion(authResponse);
+
+const toolInput = {
+ task_id: "1234567890",
+};
+
+const response = await client.tools.execute({
+ tool_name: TOOL_NAME,
+ input: toolInput,
+ user_id: USER_ID,
+});
+
+console.log(response.output.value);
+```
+
+
+
diff --git a/app/en/home/sharing-with-end-users/custom-auth/atlassian/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/atlassian/page.mdx
new file mode 100644
index 000000000..ec4bc6519
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/atlassian/page.mdx
@@ -0,0 +1,182 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Atlassian
+
+
+ At this time, Arcade does not offer a default Atlassian Auth Provider. To use
+ Atlassian auth, you must create a custom Auth Provider with your own Atlassian
+ OAuth 2.0 credentials as described below.
+
+
+The Atlassian auth provider enables tools and agents to call the Atlassian API on behalf of a user.
+
+### What's documented here
+
+This page describes how to use and configure Atlassian auth with Arcade.
+
+This auth provider is used by:
+
+- Your [app code](#using-atlassian-auth-in-app-code) that needs to call Atlassian APIs
+- Or, your [custom tools](#using-atlassian-auth-in-custom-tools) that need to call Atlassian APIs
+
+## Configuring Atlassian auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Atlassian app credentials. This way, your users will see your application's name requesting permission.
+
+
+Before showing how to configure your Atlassian app credentials, let's go through the steps to create an Atlassian app.
+
+### Create an Atlassian app
+
+- Create a Atlassian app in the [Atlassian developer console](https://developer.atlassian.com/console/myapps/)
+- In the Authorization tab, click the "Add" action button and set the Callback URL to the redirect URL generated by Arcade (see below)
+- In the Permissions tab, enable any permissions you need for your app
+- In the Settings tab, copy the Client ID and Secret to use below
+
+## Configuring your own Atlassian Auth Provider in Arcade
+
+
+
+
+
+### Configure Atlassian Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Included Providers** tab at the top.
+- In the **Provider** dropdown, select **Atlassian**.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "my-atlassian-provider").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Atlassian app.
+- Note the **Redirect URL** generated by Arcade. This must be added to your Atlassian app as a Callback URL.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+When you use tools that require Atlassian auth using your Arcade account credentials, Arcade will automatically use this Atlassian OAuth provider. If you have multiple Atlassian providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+
+
+## Using Atlassian auth in app code
+
+Use the Atlassian auth provider in your own agents and AI apps to get a user token for the Atlassian API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Atlassian API:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="atlassian",
+ scopes=["read:me", "read:jira-user", "read:confluence-user"],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-10}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade(); // Automatically finds the `ARCADE_API_KEY` env variable
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+let authResponse = await client.auth.start(userId, "atlassian", {
+ scopes: ["read:me", "read:jira-user", "read:confluence-user"],
+});
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using Atlassian auth in custom tools
+
+You can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Atlassian API.
+
+Use the `Atlassian()` auth class to specify that a tool requires authorization with Atlassian. The `context.authorization.token` field will be automatically populated with the user's Atlassian token:
+
+```python {5-6,9-13,23}
+from typing import Annotated, Optional
+
+import httpx
+
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import Atlassian
+
+
+@tool(
+ requires_auth=Atlassian(
+ scopes=["read:jira-work"],
+ )
+)
+async def list_projects(
+ context: ToolContext,
+ query: Annotated[
+ Optional[str],
+ "The query to filter the projects by. Defaults to empty string to list all projects.",
+ ] = "",
+) -> Annotated[dict, "The list of projects in a user's Jira instance"]:
+ """List a Jira user's projects."""
+ url = f"https://api.atlassian.com/ex/jira//rest/api/3/project/search?query={query}"
+ headers = {"Authorization": f"Bearer {context.authorization.token}"}
+
+ async with httpx.AsyncClient() as client:
+ response = await client.get(url, headers=headers)
+ response.raise_for_status()
+ return response.json()
+```
diff --git a/app/en/home/sharing-with-end-users/custom-auth/calendly/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/calendly/page.mdx
new file mode 100644
index 000000000..a2693d9ab
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/calendly/page.mdx
@@ -0,0 +1,272 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Calendly
+
+The Calendly auth provider enables tools and agents to call [Calendly APIs](https://developer.calendly.com/api-docs) on behalf of a user using OAuth 2.0 authentication.
+
+
+ Want to quickly get started with Calendly in your agent or AI app? The
+ pre-built [Arcade Calendly MCP Server](/mcp-servers/productivity/calendly-api)
+ is what you want!
+
+
+### What's documented here
+
+This page describes how to use and configure Calendly auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade Calendly MCP Server](/mcp-servers/productivity/calendly-api), which provides pre-built tools for interacting with Calendly
+- Your [app code](#using-calendly-auth-in-app-code) that needs to call the Calendly API
+- Or, your [custom tools](#using-calendly-auth-in-custom-tools) that need to call the Calendly API
+
+## Configuring Calendly auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Calendly app credentials. This way, your users will see your application's name requesting permission.
+
+Before showing how to configure your Calendly app credentials, let's go through the steps to create a Calendly app.
+
+### Create a Calendly app
+
+To integrate with Calendly's API, you'll need to create a developer account and register an OAuth application:
+
+
+
+#### Create a Calendly developer account
+
+1. Navigate to [developer.calendly.com/create-a-developer-account](https://developer.calendly.com/create-a-developer-account)
+2. Sign up using your GitHub or Google account
+3. Complete the registration process
+
+#### Register a new OAuth application
+
+1. Click on **Create New App** or **Register an App**
+2. Fill in the required details:
+ - **Application Name**: Choose a descriptive name for your application
+ - **Type**: Select **Web** or **Native** based on your application type
+ - **Environment**: Choose **Sandbox** (for testing) or **Production**
+ - **Redirect URI**: Add the redirect URL generated by Arcade (see configuration section below)
+ - For Sandbox: HTTP with localhost is allowed (e.g., `http://localhost:1234`)
+ - For Production: HTTPS is required
+
+#### Save your credentials
+
+1. After registration, you'll receive your **Client ID**, **Client Secret**, and **Webhook Signing Key**
+2. **Important**: Copy and save these credentials immediately, as the Client Secret and Webhook Signing Key won't be accessible again
+
+
+
+For detailed instructions, refer to Calendly's [Getting Started guide](https://developer.calendly.com/getting-started) and [OAuth documentation](https://developer.calendly.com/api-docs/0b07b0a0b0b07-get-authorization-code).
+
+Next, add the Calendly app to Arcade.
+
+## Configuring your own Calendly Auth Provider in Arcade
+
+
+
+
+### Configure Calendly Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **OAuth 2.0** tab at the top.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "arcade-calendly").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Calendly app.
+- Configure the OAuth 2.0 endpoints:
+ - **Authorization URL**: `https://auth.calendly.com/oauth/authorize`
+ - **Token URL**: `https://auth.calendly.com/oauth/token`
+- Note the **Redirect URL** generated by Arcade. This must be set as your Calendly app's Redirect URI.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+
+
+
+
+### Configure Calendly Auth Using Configuration File
+
+
+ This method is only available when you are [self-hosting the
+ engine](/home/deployment/on-prem-mcp)
+
+
+
+
+#### Set environment variables
+
+Set the following environment variables:
+
+```bash
+export CALENDLY_CLIENT_ID=""
+export CALENDLY_CLIENT_SECRET=""
+```
+
+Or, you can set these values in a `.env` file:
+
+```bash
+CALENDLY_CLIENT_ID=""
+CALENDLY_CLIENT_SECRET=""
+```
+
+#### Edit the Engine configuration
+
+Edit the `engine.yaml` file and add a new item to the `auth.providers` section:
+
+```yaml
+auth:
+ providers:
+ - id: arcade-calendly
+ description: Calendly OAuth 2.0 provider
+ enabled: true
+ type: oauth2
+ client_id: ${env:CALENDLY_CLIENT_ID}
+ client_secret: ${env:CALENDLY_CLIENT_SECRET}
+ oauth2:
+ authorize_request:
+ endpoint: "https://auth.calendly.com/oauth/authorize"
+ params:
+ response_type: code
+ client_id: "{{client_id}}"
+ redirect_uri: "{{redirect_uri}}"
+ state: "{{state}}"
+ token_request:
+ endpoint: "https://auth.calendly.com/oauth/token"
+ params:
+ grant_type: authorization_code
+ client_id: "{{client_id}}"
+ client_secret: "{{client_secret}}"
+ redirect_uri: "{{redirect_uri}}"
+ response_content_type: application/json
+```
+
+
+
+
+
+
+When you use tools that require Calendly auth using your Arcade account credentials, Arcade will automatically use this Calendly OAuth provider. If you have multiple Calendly providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+## Using Calendly auth in app code
+
+Use the Calendly auth provider in your own agents and AI apps to get a user token for the Calendly API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Calendly API:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="arcade-calendly"
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-11}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade();
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+const authResponse = await client.auth.start(userId, "arcade-calendly");
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using Calendly auth in custom tools
+
+You can use the pre-built [Arcade Calendly MCP Server](/mcp-servers/productivity/calendly-api) to quickly build agents and AI apps that interact with Calendly.
+
+If the pre-built tools in the Calendly MCP Server don't meet your needs, you can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Calendly API.
+
+Use the `OAuth2()` auth class to specify that a tool requires authorization with Calendly. The `context.authorization.token` field will be automatically populated with the user's Calendly token:
+
+```python {8-12,22}
+from typing import Annotated
+
+import httpx
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import OAuth2
+
+
+@tool(
+ requires_auth=OAuth2(provider_id="arcade-calendly")
+)
+async def get_user_info(
+ context: ToolContext,
+) -> Annotated[dict, "The user information."]:
+ """
+ Retrieve the authenticated user's information from Calendly.
+ """
+ url = "https://api.calendly.com/users/me"
+ headers = {
+ "Authorization": context.authorization.token,
+ }
+
+ async with httpx.AsyncClient() as client:
+ response = await client.get(url, headers=headers)
+ response.raise_for_status()
+ return dict(response.json())
+```
+
+For more details about Calendly's authentication, refer to the [Calendly Authentication documentation](https://developer.calendly.com/how-to-guides/authentication).
diff --git a/app/en/home/sharing-with-end-users/custom-auth/clickup/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/clickup/page.mdx
new file mode 100644
index 000000000..5a5139587
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/clickup/page.mdx
@@ -0,0 +1,171 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# ClickUp
+
+The ClickUp auth provider enables tools and agents to call the ClickUp API on behalf of a user.
+
+### What's documented here
+
+This page describes how to use and configure ClickUp auth with Arcade.
+
+This auth provider is used by:
+
+- Your [app code](#using-clickup-auth-in-app-code) that needs to call ClickUp APIs
+- Or, your [custom tools](#using-clickup-auth-in-custom-tools) that need to call ClickUp APIs
+
+## Configuring ClickUp auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+In a production environment, you will most likely want to use your own ClickUp app
+credentials. This way, your users will see your application's name requesting permission.
+
+
+Before showing how to configure your ClickUp app credentials, let's go through the steps to create a ClickUp app.
+
+### Create a ClickUp app
+
+- Navigate to your ClickUp workspace and go to **Settings → Apps**
+- Click **Create new app** in the OAuth Apps section
+- Fill in your app name and description
+- Set the OAuth Redirect URL to: `https://cloud.arcade.dev/api/v1/oauth/callback`
+- Copy the Client ID and Client Secret, which you'll need below
+
+## Configuring your own ClickUp Auth Provider in Arcade
+
+
+
+
+### Configure ClickUp Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at `http://localhost:9099/dashboard`. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Included Providers** tab at the top.
+- In the **Provider** dropdown, select **ClickUp**.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "my-clickup-provider").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your ClickUp app.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+When you use tools that require ClickUp auth using your Arcade account credentials, Arcade will automatically use this ClickUp OAuth provider. If you have multiple ClickUp providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+
+
+
+## Using ClickUp auth in app code
+
+Use the ClickUp auth provider in your own agents and AI apps to get a user-scoped token for the ClickUp API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the ClickUp API:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="clickup",
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# TODO: Do something interesting with the token...
+```
+
+
+
+
+```javascript {8-10}
+import { Arcade } from "arcade-js";
+
+const client = new Arcade();
+
+const auth = await client.auth.start({
+ provider: "clickup",
+});
+
+if (auth.status !== "completed") {
+ console.log("Finish authorization at:", auth.url);
+ await client.auth.waitForCompletion(auth);
+}
+
+const { token } = auth.context;
+// Use the token in ClickUp API requests
+```
+
+
+
+
+## Using ClickUp auth in custom tools
+
+You can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the ClickUp API.
+
+Use the `ClickUp()` auth class to specify that a tool requires authorization with ClickUp. The `context.authorization.token` field will be automatically populated with the user's ClickUp token:
+
+```python {5-6,9-13,20}
+import httpx
+from arcade_tdk import tool, ToolContext
+from arcade_tdk.auth import ClickUp
+
+@tool(requires_auth=ClickUp())
+async def get_my_workspaces(context: ToolContext) -> dict:
+ """Get the authenticated user's workspaces (teams) from ClickUp."""
+ token = context.authorization.token
+
+ # Make authenticated request to ClickUp API
+ async with httpx.AsyncClient() as client:
+ response = await client.get(
+ "https://api.clickup.com/api/v2/team",
+ headers={
+ "Authorization": token,
+ "Content-Type": "application/json"
+ }
+ )
+
+ if response.status_code == 200:
+ data = response.json()
+ teams = data.get("teams", [])
+ return {
+ "success": True,
+ "teams": [{"id": team["id"], "name": team["name"]} for team in teams]
+ }
+ else:
+ return {
+ "success": False,
+ "error": f"ClickUp API error: {response.status_code} - {response.text}"
+ }
+```
diff --git a/app/en/home/sharing-with-end-users/custom-auth/discord/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/discord/page.mdx
new file mode 100644
index 000000000..c291cf398
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/discord/page.mdx
@@ -0,0 +1,183 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Discord
+
+
+ At this time, Arcade does not offer a default Discord Auth Provider. To use
+ Discord auth, you must create a custom Auth Provider with your own Discord
+ OAuth 2.0 credentials as described below.
+
+
+The Discord auth provider enables tools and agents to call the Discord API on behalf of a user.
+
+### What's documented here
+
+This page describes how to use and configure Discord auth with Arcade.
+
+This auth provider is used by:
+
+- Your [app code](#using-discord-auth-in-app-code) that needs to call Discord APIs
+- Or, your [custom tools](#using-discord-auth-in-custom-tools) that need to call Discord APIs
+
+## Configuring Discord auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Discord app credentials. This way, your users will see your application's name requesting permission.
+
+
+Before showing how to configure your Discord app credentials, let's go through the steps to create a Discord app.
+
+### Create a Discord app
+
+- Create a Discord Application in the [Discord developer portal](https://discord.com/developers/applications)
+- In the OAuth2 tab, set the redirect URI to the redirect URL generated by Arcade (see below)
+- Copy the Client ID and Client Secret (you may need to reset the secret to see it)
+
+## Configuring your own Discord Auth Provider in Arcade
+
+
+
+
+
+### Configure Discord Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Included Providers** tab at the top.
+- In the **Provider** dropdown, select **Discord**.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "my-discord-provider").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Discord app.
+- Note the **Redirect URL** generated by Arcade. This must be added to your Discord app's Redirect URIs.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+When you use tools that require Discord auth using your Arcade account credentials, Arcade will automatically use this Discord OAuth provider. If you have multiple Discord providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+
+
+
+## Using Discord auth in app code
+
+Use the Discord auth provider in your own agents and AI apps to get a user token for the Discord API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Discord API:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="discord",
+ scopes=["identify", "email", "guilds", "guilds.join"],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-10}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade();
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+const authResponse = await client.auth.start(userId, "discord", {
+ scopes: ["identify", "email", "guilds", "guilds.join"],
+});
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using Discord auth in custom tools
+
+You can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Discord API.
+
+Use the `Discord()` auth class to specify that a tool requires authorization with Discord. The `context.authorization.token` field will be automatically populated with the user's Discord token:
+
+```python {5-6,9-13,23}
+from typing import Annotated, Optional
+
+import httpx
+
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import Discord
+
+
+@tool(
+ requires_auth=Discord(
+ scopes=["guilds"],
+ )
+)
+async def list_servers(
+ context: ToolContext,
+ user_id: Annotated[
+ Optional[str],
+ "The user's user ID. Defaults to '@me' for the current user.",
+ ] = "@me",
+) -> Annotated[dict, "List of servers the user is a member of"]:
+ """List a Discord user's servers they are a member of."""
+ url = f"https://discord.com/api/users/{user_id}/guilds"
+ headers = {"Authorization": f"Bearer {context.authorization.token}"}
+
+ async with httpx.AsyncClient() as client:
+ response = await client.get(url, headers=headers)
+ response.raise_for_status()
+ return response.json()
+```
diff --git a/app/en/home/sharing-with-end-users/custom-auth/dropbox/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/dropbox/page.mdx
new file mode 100644
index 000000000..302d308a5
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/dropbox/page.mdx
@@ -0,0 +1,185 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Dropbox
+
+
+ At this time, Arcade does not offer a default Dropbox Auth Provider. To use
+ Dropbox auth, you must create a custom Auth Provider with your own Dropbox
+ OAuth 2.0 credentials as described below.
+
+
+The Dropbox auth provider enables tools and agents to call the Dropbox API on behalf of a user.
+
+### What's documented here
+
+This page describes how to use and configure Dropbox auth with Arcade.
+
+This auth provider is used by:
+
+- Your [app code](#using-dropbox-auth-in-app-code) that needs to call Dropbox APIs
+- Or, your [custom tools](#using-dropbox-auth-in-custom-tools) that need to call Dropbox APIs
+
+## Configuring Dropbox auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Dropbox app credentials. This way, your users will see your application's name requesting permission.
+
+
+Before showing how to configure your Dropbox app credentials, let's go through the steps to create a Dropbox app.
+
+### Create a Dropbox app
+
+- Create a Dropbox Application in the [Dropbox App Console](https://www.dropbox.com/developers/apps)
+- In the Settings tab, under the "OAuth 2" section, set the redirect URI to the redirect URL generated by Arcade (see below)
+- In the Permissions tab, add any scopes that your app will need
+- In the Settings tab, copy the App key (Client ID) and App secret (Client Secret), which you'll need below
+
+Next, add the Dropbox app to Arcade.
+
+## Configuring your own Dropbox Auth Provider in Arcade
+
+
+
+
+### Configure Dropbox Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Included Providers** tab at the top.
+- In the **Provider** dropdown, select **Dropbox**.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "my-dropbox-provider").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Dropbox app.
+- Note the **Redirect URL** generated by Arcade. This must be added to your Dropbox app's Redirect URIs.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+When you use tools that require Dropbox auth using your Arcade account credentials, Arcade will automatically use this Dropbox OAuth provider. If you have multiple Dropbox providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+
+
+
+## Using Dropbox auth in app code
+
+Use the Dropbox auth provider in your own agents and AI apps to get a user-scoped token for the Dropbox API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Dropbox API:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="dropbox",
+ scopes=["openid", "sharing.read", "files.metadata.read"],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-10}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade();
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+const authResponse = await client.auth.start(userId, "dropbox", {
+ scopes: ["openid", "sharing.read", "files.metadata.read"],
+});
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using Dropbox auth in custom tools
+
+You can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Dropbox API.
+
+Use the `Dropbox()` auth class to specify that a tool requires authorization with Dropbox. The `context.authorization.token` field will be automatically populated with the user's Dropbox token:
+
+```python {5-6,9-13,23}
+from typing import Annotated, Optional
+
+import httpx
+
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import Dropbox
+
+
+@tool(
+ requires_auth=Dropbox(
+ scopes=["files.metadata.read"],
+ )
+)
+async def list_files(
+ context: ToolContext,
+ path: Annotated[
+ Optional[str],
+ "The path to the folder to list the contents of. Defaults to empty string to list the root folder.",
+ ] = "",
+) -> Annotated[dict, "List of servers the user is a member of"]:
+ """Starts returning the contents of a folder."""
+ url = "https://api.dropboxapi.com/2/files/list_folder"
+ headers = {"Authorization": f"Bearer {context.authorization.token}"}
+
+ async with httpx.AsyncClient() as client:
+ response = await client.post(url, headers=headers, json={"path": path})
+ response.raise_for_status()
+ return response.json()
+```
\ No newline at end of file
diff --git a/app/en/home/sharing-with-end-users/custom-auth/figma/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/figma/page.mdx
new file mode 100644
index 000000000..643f92a21
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/figma/page.mdx
@@ -0,0 +1,294 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Figma
+
+The Figma auth provider enables tools and agents to call [Figma APIs](https://www.figma.com/developers/api) on behalf of a user using OAuth 2.0 authentication.
+
+
+ Want to quickly get started with Figma in your agent or AI app? The pre-built
+ [Arcade Figma MCP Server](/mcp-servers/productivity/figma-api) is what you
+ want!
+
+
+### What's documented here
+
+This page describes how to use and configure Figma auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade Figma MCP Server](/mcp-servers/productivity/figma-api), which provides pre-built tools for interacting with Figma
+- Your [app code](#using-figma-auth-in-app-code) that needs to call the Figma API
+- Or, your [custom tools](#using-figma-auth-in-custom-tools) that need to call the Figma API
+
+## Configuring Figma auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Figma app credentials. This way, your users will see your application's name requesting permission.
+
+Before showing how to configure your Figma app credentials, let's go through the steps to create a Figma app.
+
+### Create a Figma app
+
+To integrate with Figma's API, you'll need to set up OAuth 2.0 authentication by creating an app in the Figma Developer Portal:
+
+
+
+#### Access the Figma Developer Portal
+
+Navigate to the [Figma Developer Portal](https://www.figma.com/developers/) and sign in with your existing Figma credentials or create a new account.
+
+#### Create a new app
+
+1. Once logged in, go to your developer dashboard and select "My Apps"
+2. Click on "Create a new app"
+3. Fill in the required details:
+ - **App Name**: Choose a descriptive name for your application
+ - **Website**: Provide the URL of your application's website
+ - **App Logo**: Upload a 100x100px PNG image representing your app
+
+#### Set up OAuth configuration
+
+1. After creating your app, you'll receive a `client_id` and `client_secret`
+2. Set the redirect URI to the redirect URL generated by Arcade (see configuration section below)
+3. Configure the required scopes for your application:
+ - `files:read` - Read access to files
+ - `file_comments:write` - Write access to file comments
+ - Add other scopes as needed for your use case
+
+
+
+For detailed instructions, refer to Figma's official [Authentication documentation](https://developers.figma.com/docs/rest-api/authentication/).
+
+Next, add the Figma app to Arcade.
+
+## Configuring your own Figma Auth Provider in Arcade
+
+
+
+
+### Configure Figma Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **OAuth 2.0** tab at the top.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "arcade-figma").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Figma app.
+- Configure the OAuth 2.0 endpoints:
+ - **Authorization URL**: `https://www.figma.com/oauth`
+ - **Token URL**: `https://www.figma.com/api/oauth/token`
+- Note the **Redirect URL** generated by Arcade. This must be set as your Figma app's redirect URI.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+
+
+
+
+### Configure Figma Auth Using Configuration File
+
+
+ This method is only available when you are [self-hosting the
+ engine](/home/deployment/on-prem-mcp)
+
+
+
+
+#### Set environment variables
+
+Set the following environment variables:
+
+```bash
+export FIGMA_CLIENT_ID=""
+export FIGMA_CLIENT_SECRET=""
+```
+
+Or, you can set these values in a `.env` file:
+
+```bash
+FIGMA_CLIENT_ID=""
+FIGMA_CLIENT_SECRET=""
+```
+
+#### Edit the Engine configuration
+
+Edit the `engine.yaml` file and add a new item to the `auth.providers` section:
+
+```yaml
+auth:
+ providers:
+ - id: arcade-figma
+ description: Figma OAuth 2.0 provider
+ enabled: true
+ type: oauth2
+ client_id: ${env:FIGMA_CLIENT_ID}
+ client_secret: ${env:FIGMA_CLIENT_SECRET}
+ oauth2:
+ scope_delimiter: ","
+ authorize_request:
+ endpoint: "https://www.figma.com/oauth"
+ params:
+ response_type: code
+ client_id: "{{client_id}}"
+ redirect_uri: "{{redirect_uri}}"
+ scope: "{{scopes}}"
+ state: "{{state}}"
+ token_request:
+ endpoint: "https://www.figma.com/api/oauth/token"
+ auth_method: client_secret_basic
+ params:
+ grant_type: authorization_code
+ client_id: "{{client_id}}"
+ client_secret: "{{client_secret}}"
+ redirect_uri: "{{redirect_uri}}"
+ response_content_type: application/json
+```
+
+
+
+
+
+
+When you use tools that require Figma auth using your Arcade account credentials, Arcade will automatically use this Figma OAuth provider. If you have multiple Figma providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+## Using Figma auth in app code
+
+Use the Figma auth provider in your own agents and AI apps to get a user token for the Figma API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Figma API:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="arcade-figma",
+ scopes=["files:read", "file_comments:write"]
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-11}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade();
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+const authResponse = await client.auth.start(userId, "arcade-figma", [
+ "files:read",
+ "file_comments:write",
+]);
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using Figma auth in custom tools
+
+You can use the pre-built [Arcade Figma MCP Server](/mcp-servers/productivity/figma-api) to quickly build agents and AI apps that interact with Figma.
+
+If the pre-built tools in the Figma MCP Server don't meet your needs, you can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Figma API.
+
+Use the `OAuth2()` auth class to specify that a tool requires authorization with Figma. The `context.authorization.token` field will be automatically populated with the user's Figma token:
+
+```python {8-12,22}
+from typing import Annotated
+
+import httpx
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import OAuth2
+
+
+@tool(
+ requires_auth=OAuth2(
+ provider_id="arcade-figma",
+ scopes=["files:read"]
+ )
+)
+async def get_figma_file(
+ context: ToolContext,
+ file_key: Annotated[str, "The Figma file key to retrieve."],
+) -> Annotated[dict, "The Figma file data."]:
+ """
+ Retrieve a Figma file by its key.
+ """
+ url = f"https://api.figma.com/v1/files/{file_key}"
+ headers = {
+ "Authorization": context.authorization.token,
+ }
+
+ async with httpx.AsyncClient() as client:
+ response = await client.get(url, headers=headers)
+ response.raise_for_status()
+ return dict(response.json())
+```
+
+## Available Scopes
+
+Figma supports various OAuth scopes that determine the level of access your application has:
+
+- `files:read` - Read access to files
+- `file_comments:write` - Write access to file comments
+- `file_dev_resources:write` - Write access to dev resources
+- `file_variables:read` - Read access to variables
+- `file_variables:write` - Write access to variables
+- `webhooks:write` - Write access to webhooks
+
+For a complete list of available scopes and their descriptions, refer to the [Figma API documentation](https://www.figma.com/developers/api#authentication).
diff --git a/app/en/home/sharing-with-end-users/custom-auth/github/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/github/page.mdx
new file mode 100644
index 000000000..eced918bb
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/github/page.mdx
@@ -0,0 +1,1215 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# GitHub
+
+The GitHub auth provider enables tools and agents to call [GitHub APIs](https://docs.github.com/en/rest/overview/resources-in-the-rest-api) on behalf of a user.
+
+
+ Want to quickly get started with GitHub in your agent or AI app? The pre-built
+ [Arcade GitHub MCP Server](/mcp-servers/development/github) is what you want!
+
+
+## What's documented here
+
+This page describes how to use and configure GitHub auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade GitHub MCP Server](/mcp-servers/development/github), which provides pre-built tools for interacting with GitHub
+- Your [app code](#using-github-auth-in-app-code) that needs to call the GitHub API
+- Or, your [custom tools](#using-github-auth-in-custom-tools) that need to call the GitHub API
+
+---
+
+## Why Arcade Uses GitHub Apps (Not OAuth Apps)
+
+### Arcade's Decision
+
+Arcade's security team selected **GitHub Apps** over OAuth Apps for the GitHub toolkit based on three critical factors:
+
+1. **🎯 GitHub's Recommendation**: OAuth Apps are soft-deprecated. GitHub actively recommends Apps for new integrations and invests in their development.
+
+2. **🔐 Fine-Grained Security**: GitHub Apps support granular permissions (e.g., "Read pull requests"), while OAuth Apps only offer coarse scopes (e.g., `repo` = full repository access).
+
+3. **🏢 Enterprise Control**: Admins can approve exact permissions and see all app installations. OAuth Apps bypass organizational oversight.
+
+
+ **Important**: When creating your GitHub integration with Arcade, you must use
+ a **GitHub App** (not an OAuth App). GitHub Apps provide the security and
+ permission model required for production use.
+
+
+### Quick Comparison
+
+| Aspect | 🏆 GitHub Apps (Required) | OAuth Apps (Not Supported) |
+| ---------------- | ------------------------------------ | ----------------------------------------- |
+| **Permissions** | Fine-grained (e.g., "Read contents") | Broad scopes (e.g., `repo` = full access) |
+| **Installation** | Per repository/org (admin approval) | Per user (no approval) |
+| **Access** | Only installed repositories | All user repositories |
+| **Tokens** | Scoped, short-lived | Broad, long-lived |
+| **Identity** | Acts as app | Acts as user |
+| **Security** | ⭐⭐⭐⭐⭐ Highest | ⭐⭐⭐ Good |
+| **Best For** | Production, CI/CD, Enterprise | Personal, Prototypes |
+
+
+**GitHub Enterprise Server (GHES) Limitation**
+
+GitHub Apps created on github.com **cannot** be installed on GitHub Enterprise Server instances, and vice versa. Each GHES instance requires its own separate GitHub App registration.
+
+- ✅ Apps on github.com work for all github.com users
+- ❌ Apps on github.com **DO NOT** work for GHES instances
+- ✅ Each GHES instance must register its own GitHub App
+- ✅ You can use the same manifest/configuration for multiple instances
+
+[Learn more about GHES GitHub Apps](https://docs.github.com/en/apps/sharing-github-apps/making-your-github-app-available-for-github-enterprise-server)
+
+
+
+### Why Enterprises Choose GitHub Apps
+
+
+
+
+
🔐 Permission Model
+
+Least-privilege access. Grant only exact permissions needed (e.g., "Read contents" vs full repo access). Minimizes blast radius and supports compliance (SOC 2, ISO 27001).
+
+
+
+
+
+ 🏢 Installation
+
+
+ Centralized control. IT/security teams see all app
+ installations, enforce policies, prevent shadow IT. Admin approval ensures
+ integrations are vetted and documented.
+
+
+
+
+
+ 🎯 Access Scope
+
+
+ Reduced attack surface. Apps only access explicitly
+ installed repositories. Critical for organizations with repositories at
+ different sensitivity levels.
+
+
+
+
+
+ 🔑 Token Type
+
+
+ Better security posture. Tokens are scoped and revocable
+ instantly. Long-lived OAuth tokens remain valid for months if compromised.
+
+
+
+
+
+ 👤 Identity
+
+
+ Clear accountability. Actions attributed to app, not users.
+ Essential for compliance audits and security investigations.
+
+
+
+
+
📊 Audit Trail
+
+Clear audit logs. Easy to identify automated vs human actions. Essential for SOC 2, HIPAA compliance.
+
+
+
+
+
+---
+
+## Creating a GitHub App
+
+
+
+
+
+
+ You **must** create a GitHub App (not an OAuth App). The "OAuth App" option in
+ GitHub does not provide the fine-grained permissions model required for secure
+ production use.
+
+
+
+
+### Navigate to GitHub App Settings
+
+1. Log in to GitHub and click your profile picture (top-right corner)
+2. Click **Settings** from the dropdown menu
+3. Scroll down in the left sidebar and click **Developer settings**
+4. Click **GitHub Apps** in the left sidebar
+5. Click **New GitHub App** button
+
+### Configure Basic Information
+
+Fill in the following fields:
+
+- **GitHub App name**: Enter a descriptive name (e.g., "My Company GitHub Integration")
+ - This name will be visible to users when installing the app
+- **Homepage URL**: Your application homepage URL
+- **User authorization callback URL**: The redirect URL generated by Arcade (you'll get this in step 4)
+- **Webhook URL**: Leave blank unless you need webhooks
+- **Webhook secret**: Leave blank unless you need webhooks
+
+**Important settings:**
+
+- Leave "Expire user authorization tokens" **checked** ✅
+- **Enable** "Request user authorization (OAuth) during installation" **checked** ✅
+ - **Critical**: This enables user-to-server authentication flow
+ - Allows the app to act on behalf of authenticated users
+ - Required for Arcade's authentication model
+ - [Learn more about user authorization](https://docs.github.com/en/apps/using-github-apps/authorizing-github-apps)
+- Leave "Setup URL" blank and "Redirect on update" **unchecked** ❌
+- Ensure "Optional features > User-to-server token expiration" is **enabled** ✅
+
+### Set Permissions
+
+Configure permissions based on your needs. At minimum:
+
+**Repository Permissions:**
+
+- **Contents**: Read (required for most tools), Write (for file operations and branch creation)
+- **Issues**: Read & Write (for issue management and labels)
+- **Metadata**: Read (automatically selected)
+- **Pull requests**: Read & Write (for PR management and reviews)
+- **Statuses**: Read (for CI/CD status checks)
+
+**Organization Permissions:**
+
+- **Members**: Read (for collaborators, teams, org projects)
+- **Projects**: Read & Write (for Projects V2 management)
+
+**User Permissions:**
+
+- **Email addresses**: Read (minimum required)
+- **Read user profile**: Read (for user context tools)
+- **Act on behalf of user**: Enable for user-attributed actions (starring repos, user activity feed)
+
+
+**"Act on behalf of user"** is only needed when actions should be attributed to the user rather than the app. Without this permission:
+
+- ✅ The app can still access and read user/org data
+- ✅ The app can perform actions (attributed to the app, not the user)
+- ❌ User-specific actions (starring repos) won't work
+- ❌ Actions won't appear in the user's activity feed
+
+**When you need it**: Starring repositories, user activity attribution, user-specific rate limits.
+
+[Learn more](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/authenticating-with-a-github-app-on-behalf-of-a-user)
+
+
+
+
+ See the [Complete Permissions Reference](#tool-permissions-reference) below
+ for detailed permissions needed by each tool.
+
+
+### Set Installation Options
+
+- **Personal use**: Select "Only on this account"
+- **Organization use**: Select "Any account"
+
+### Create the App
+
+1. Review all settings
+2. Click **Create GitHub App**
+3. You'll be redirected to your app's settings page
+
+### Note Your Credentials
+
+After creating the app, you'll need these credentials for Arcade configuration:
+
+1. **Client ID**: Found in the "About" section of your app settings
+2. **Client Secret**:
+ - Click **Generate a new client secret**
+ - Copy it immediately (you cannot view it again!)
+ - Store it securely
+
+
+**Arcade Does Not Require Private Keys or Installation IDs**
+
+Unlike some GitHub App integrations, Arcade's architecture uses user-to-server tokens (OAuth flow) rather than installation tokens. This means:
+
+- ✅ You only need: Client ID and Client Secret
+- ❌ You do NOT need: Private Key (.pem file) or Installation ID
+- ✅ Simpler setup with fewer credentials to manage
+- ✅ Users authorize the app directly when they use your agent
+
+[Learn more about GitHub App authentication methods](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/about-authentication-with-a-github-app)
+
+
+
+### Install the App
+
+After creating your GitHub App, you need to install it to make it functional. Installation grants the app access to specific repositories.
+
+1. In your GitHub App settings page, click **Install App** in the left sidebar
+2. Click **Install** next to the account where you want to install the app
+3. Choose repository access:
+ - **All repositories**: Access to all current and future repos (convenient but less secure)
+ - **Only select repositories**: Only specific repos (recommended for production)
+4. If selecting specific repositories, choose which repos the app can access
+5. Click **Install** to complete the installation
+
+
+ **For Organizations**: If you're installing on an organization, an admin may
+ need to approve the installation. Organization members can request
+ installation, which sends a notification to org owners. [Learn more about
+ GitHub App
+ installations](https://docs.github.com/en/apps/using-github-apps/installing-a-github-app-from-a-third-party)
+
+
+
+ **Important**: Users must authorize the app separately from installation. When
+ a user first uses your agent/app, Arcade will redirect them to GitHub to
+ authorize the app. This grants the app permission to act on their behalf.
+ [Learn more about
+ authorization](https://docs.github.com/en/apps/using-github-apps/authorizing-github-apps)
+
+
+
+
+### For Private Organization Repositories
+
+If you need to access private repositories in an organization:
+
+1. **Make the app public**: In app settings → **Advanced** → **Make public**
+ - Public apps can be installed on any account
+ - Private apps can only be installed on the owning account
+2. **Install on the organization**: **Install app** → Select your organization
+3. **Organization admin approval**: An org owner must approve the installation
+4. **User authorization**: Each user must authorize the app when they first use it
+
+
+ Organization admins can review and manage all GitHub App installations at:
+ Settings → Integrations → Applications → Installed GitHub Apps. [Learn more
+ about reviewing
+ installations](https://docs.github.com/en/apps/using-github-apps/reviewing-your-authorized-integrations)
+
+
+---
+
+## Understanding GitHub App Authorization Flow
+
+GitHub Apps use a two-step process that separates installation from authorization:
+
+### 1. Installation (One-time, Admin Action)
+
+**Who**: Repository admin or organization owner
+**What**: Installs the app on specific repositories
+**Grants**: App can access those repositories' data
+
+This happens once when setting up the app. [Installation guide](https://docs.github.com/en/apps/using-github-apps/installing-your-own-github-app)
+
+### 2. User Authorization (Per-User, First Use)
+
+**Who**: Each individual user
+**What**: Authorizes the app to act on their behalf
+**Grants**: App can perform actions as that user
+
+This happens when a user first interacts with your agent/app. Arcade handles this automatically. [Authorization guide](https://docs.github.com/en/apps/using-github-apps/authorizing-github-apps)
+
+### Key Differences
+
+| Aspect | Installation | Authorization |
+| ---------------- | ----------------------- | ---------------------- |
+| **When** | Once per repository/org | Once per user |
+| **Who** | Admin/Owner | Individual user |
+| **Grants** | Repository access | User-level permissions |
+| **Revocable by** | Admin or user | User only |
+| **Required for** | App to see repos | App to act as user |
+
+
+**Why Both?** This two-layer model provides security and control:
+
+- **Installation** = "Which repos can this app access?"
+- **Authorization** = "Can this app act on my behalf?"
+
+Users can revoke authorization without affecting the installation. Admins can remove installations without affecting other users' authorizations.
+
+
+
+---
+
+## Managing User Authorizations
+
+### How Users Revoke Authorization
+
+Users can revoke their authorization to your GitHub App at any time. This is important for user privacy and security.
+
+**Steps for Users:**
+
+1. Go to GitHub Settings → Applications → Authorized GitHub Apps
+2. Find your app in the list
+3. Click **Revoke** next to the app name
+4. Confirm the revocation
+
+**Direct Link**: [github.com/settings/apps/authorizations](https://github.com/settings/apps/authorizations)
+
+
+When a user revokes authorization:
+
+- Their access token is immediately invalidated
+- The app can no longer act on their behalf
+- The app installation remains active (admin can still manage it)
+- User can reauthorize later by using your agent/app again
+
+[Learn more about reviewing and revoking authorizations](https://docs.github.com/en/apps/using-github-apps/reviewing-and-revoking-authorization-of-github-apps)
+
+
+
+### How Admins Revoke App Installation
+
+Organization owners and repository admins can remove app installations:
+
+**Steps for Admins:**
+
+1. Go to Settings → Applications → Installed GitHub Apps
+2. Find the app in the list
+3. Click **Configure** next to the app
+4. Scroll to the bottom and click **Uninstall**
+5. Confirm the uninstallation
+
+**Direct Link**: [github.com/settings/installations](https://github.com/settings/installations)
+
+
+When an admin uninstalls an app:
+
+- The app loses access to all repositories in that installation
+- All user authorizations for that installation are revoked
+- Users will need to wait for reinstallation before reauthorizing
+- This affects all users who were using the app
+
+
+
+### Difference: Revoke Authorization vs Uninstall
+
+| Action | Who Can Do It | What Happens | Scope |
+| ------------------------ | --------------- | ------------------------ | -------------- |
+| **Revoke Authorization** | Individual user | User's token invalidated | Only that user |
+| **Uninstall App** | Admin/Owner | App loses repo access | All users |
+
+**Best Practices:**
+
+- Users should revoke authorization when they stop using your agent
+- Admins should uninstall when the app is no longer needed organization-wide
+- After permission changes, users should revoke and reauthorize to get updated permissions
+
+---
+
+## Configuring GitHub Auth in Arcade
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+
+
+
+### Configure via Arcade Dashboard
+
+
+
+#### Access the Arcade Dashboard
+
+Go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If self-hosting, use `http://localhost:9099/dashboard` (adjust host/port as needed).
+
+#### Navigate to OAuth Providers
+
+- Under **OAuth** section, click **Providers**
+- Click **Add OAuth Provider** (top-right)
+- Select **Included Providers** tab
+- In **Provider** dropdown, select **GitHub**
+
+#### Enter Provider Details
+
+- **ID**: Choose unique ID (e.g., "my-github-provider")
+- **Description**: Optional description
+- **Client ID**: From your GitHub app
+- **Client Secret**: From your GitHub app
+- **Redirect URL**: Note the URL generated by Arcade - add this to your GitHub app's "Callback URL"
+
+#### Create the Provider
+
+Click **Create** button. The provider is now ready to use.
+
+
+
+When you use tools requiring GitHub auth with your Arcade account, Arcade automatically uses this provider.
+For multiple providers, see [using multiple auth providers](/home/auth-providers#using-multiple-providers-of-the-same-type).
+
+
+
+
+---
+
+## GitHub Enterprise Server Setup
+
+If your organization uses GitHub Enterprise Server (GHES), you'll need to create a separate GitHub App and configure a custom OAuth provider in Arcade.
+
+
+ **Important**: The included GitHub provider in Arcade is configured for
+ github.com only. For GHES, you must create a **Custom Provider** with your
+ instance-specific URLs.
+
+
+### GHES vs GitHub.com: Key Differences
+
+| Aspect | GitHub.com | GitHub Enterprise Server |
+| ------------------------ | ---------------------------------- | --------------------------------------------- |
+| **App Creation** | Apps work for all github.com users | Each GHES instance needs its own app |
+| **Arcade Provider Type** | Use "Included Provider" (GitHub) | Use "Custom Provider" |
+| **Base URL** | github.com | Your GHES hostname (e.g., ghes.mycompany.com) |
+| **API Endpoint** | api.github.com | `{your-ghes-host}/api/v3` |
+| **Rate Limits** | Fixed by GitHub | Configurable by GHES admin |
+| **Feature Availability** | Latest features | May lag behind github.com |
+
+### Creating a GitHub App on GHES
+
+
+
+#### Access Your GHES Instance
+
+1. Log in to your GitHub Enterprise Server instance
+2. Click your profile picture (top-right corner)
+3. Follow the same steps as [Creating a GitHub App](#creating-a-github-app) above
+
+**Note**: All permission requirements and settings are identical to the github.com setup.
+
+#### Important GHES-Specific Settings
+
+- **Homepage URL**: Use your GHES-accessible application URL
+- **Callback URL**: Use the redirect URL from your Arcade custom provider (see next section)
+- All other settings match the github.com configuration
+
+
+
+### Configuring Custom Provider in Arcade
+
+
+
+#### Navigate to OAuth Providers
+
+1. Go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard)
+2. Click **OAuth** → **Providers** → **Add OAuth Provider**
+3. Select **Custom Providers** tab (NOT "Included Providers")
+
+
+ You **cannot** use the "Included Providers" option for GHES. The included
+ GitHub provider only works with github.com.
+
+
+#### Enter Basic Information
+
+- **ID**: Unique identifier (e.g., `my-company-github-enterprise`)
+- **Description**: Optional (e.g., "MyCompany GHES Production")
+- **Client ID**: From your GHES GitHub App
+- **Client Secret**: From your GHES GitHub App
+- **Copy the Redirect URL**: You'll need this for your GHES GitHub App callback URL
+
+#### Configure Endpoint URLs
+
+Replace `{your-ghes-host}` with your actual GHES hostname (e.g., `ghes.mycompany.com`):
+
+| Endpoint | GitHub.com | GitHub Enterprise Server |
+| ----------------- | --------------------------------------------- | --------------------------------------------------- |
+| **Authorization** | `https://github.com/login/oauth/authorize` | `https://{your-ghes-host}/login/oauth/authorize` |
+| **Token** | `https://github.com/login/oauth/access_token` | `https://{your-ghes-host}/login/oauth/access_token` |
+| **User Info** | `https://api.github.com/user` | `https://{your-ghes-host}/api/v3/user` |
+
+**Example** (for GHES at `ghes.mycompany.com`):
+
+- Authorization: `https://ghes.mycompany.com/login/oauth/authorize`
+- Token: `https://ghes.mycompany.com/login/oauth/access_token`
+- User Info: `https://ghes.mycompany.com/api/v3/user`
+
+#### PKCE Settings
+
+- **PKCE**: Leave **disabled** (default)
+
+#### Authorization & Token Settings
+
+- **Authorization Settings**: No changes needed (use defaults)
+- **Token Settings**: No changes needed (use defaults)
+
+#### Refresh Token Settings
+
+- **Refresh Token Endpoint**: Set to the **same URL** as Token Endpoint
+ - Example: `https://{your-ghes-host}/login/oauth/access_token`
+
+#### Token Introspection Settings
+
+**Enable** Token Introspection and configure:
+
+- **Introspection Endpoint**: `https://{your-ghes-host}/api/v3/user`
+- **Authentication Method**: **Bearer Access Token** (change from default "Basic")
+- **Request Content Type**: **application/json** (change from default)
+- **Trigger**: Enable both:
+ - ✅ **OnTokenGrant**
+ - ✅ **OnTokenRefresh**
+
+
+ These Token Introspection settings are critical for GHES. They allow Arcade to
+ verify tokens against your GHES instance's API.
+
+
+#### Create the Provider
+
+Click **Create** to save your custom GHES provider.
+
+
+
+### Using Your GHES Provider
+
+When calling Arcade tools or auth methods, specify your custom provider ID:
+
+
+
+
+```python {4}
+client = Arcade()
+
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="my-company-github-enterprise", # Your custom provider ID
+)
+```
+
+
+
+
+```javascript {3}
+const client = new Arcade();
+
+let authResponse = await client.auth.start(
+ userId,
+ "my-company-github-enterprise" // Your custom provider ID
+);
+```
+
+
+
+
+### GHES Version Compatibility
+
+
+**Version Differences**: GitHub Enterprise Server may not have all the latest features available on github.com. API responses include an `x-github-enterprise-version` header to help identify the GHES version.
+
+- New REST endpoints, GraphQL objects, and webhooks are released to GHES later than github.com
+- Older GHES versions may have different API capabilities
+- Your app code should handle version differences gracefully
+
+[Check GHES version differences](https://docs.github.com/en/enterprise-server/admin/overview/about-upgrades-to-new-releases)
+
+
+
+### Rate Limits on GHES
+
+Unlike github.com's fixed rate limits, GHES administrators can configure custom rate limits for their instance.
+
+**If you hit rate limits:**
+
+1. Verify your app is properly implementing rate limit headers
+2. Contact your GHES administrator about the configured limits
+3. Request an increase if needed for your use case
+
+[Learn more about GHES rate limit configuration](https://docs.github.com/en/enterprise-server/admin/configuration/configuring-rate-limits)
+
+---
+
+## Using GitHub Auth in App Code
+
+Use the GitHub auth provider to get a user token for the GitHub API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) for details.
+
+Use `client.auth.start()` to get a user token:
+
+
+
+
+```python {21-24}
+import requests
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+"""
+In this example, we use Arcade to authenticate with GitHub and retrieve
+the number of stargazers of the ArcadeAI/arcade-ai repository.
+
+There is a tool for that in the Arcade SDK, which simplifies the process.
+Below we're showing how to use Arcade as an auth provider directly.
+"""
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="github",
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+if not auth_response.context.token:
+ raise ValueError("No token found in auth response")
+
+token = auth_response.context.token
+
+owner = "ArcadeAI"
+name = "arcade-ai"
+headers = {
+ "Accept": "application/vnd.github+json",
+ "Authorization": f"Bearer {token}",
+ "X-GitHub-Api-Version": "2022-11-28",
+}
+url = f"https://api.github.com/repos/{owner}/{name}"
+
+response = requests.get(url, headers=headers)
+response.raise_for_status()
+
+print(response.json().get("stargazers_count"))
+```
+
+
+
+
+```javascript {20}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade(); // Automatically finds the `ARCADE_API_KEY` env variable
+
+const userId = "{arcade_user_id}";
+
+/*
+In this example, we use Arcade to authenticate with GitHub and retrieve
+the number of stargazers of the ArcadeAI/arcade-ai repository.
+
+There is a tool for that in the Arcade SDK, which simplifies the process.
+Below we're showing how to use Arcade as an auth provider directly.
+*/
+
+// Start the authorization process
+let authResponse = await client.auth.start(userId, "github");
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+if (!authResponse.context.token) {
+ throw new Error("No token found in auth response");
+}
+
+const token = authResponse.context.token;
+
+const owner = "ArcadeAI";
+const name = "arcade-ai";
+const headers = {
+ Accept: "application/vnd.github+json",
+ Authorization: `Bearer ${token}`,
+ "X-GitHub-Api-Version": "2022-11-28",
+};
+const url = `https://api.github.com/repos/${owner}/${name}`;
+
+const response = await fetch(url, { headers });
+if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+}
+const data = await response.json();
+console.log(data.stargazers_count);
+```
+
+
+
+
+---
+
+## Using GitHub Auth in Custom Tools
+
+Use the pre-built [Arcade GitHub MCP Server](/mcp-servers/development/github) for quick GitHub integration.
+
+For custom tools, use the `GitHub()` auth class. The `context.authorization.token` field will be automatically populated:
+
+```python {3-4,7,15}
+from typing import Annotated
+
+import httpx
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import GitHub
+
+@tool(requires_auth=GitHub())
+async def count_stargazers(
+ context: ToolContext,
+ owner: Annotated[str, "The owner of the repository"],
+ name: Annotated[str, "The name of the repository"],
+) -> Annotated[int, "The number of stargazers (stars) for the specified repository"]:
+ """Count the number of stargazers (stars) for a GitHub repository."""
+ if not context.authorization or not context.authorization.token:
+ raise ValueError("No token found in context")
+
+ headers = {
+ "Accept": "application/vnd.github+json",
+ "Authorization": f"Bearer {context.authorization.token}",
+ "X-GitHub-Api-Version": "2022-11-28",
+ }
+ url = f"https://api.github.com/repos/{owner}/{name}"
+
+ async with httpx.AsyncClient() as client:
+ response = await client.get(url, headers=headers)
+ response.raise_for_status()
+ return response.json().get("stargazers_count", 0)
+```
+
+---
+
+## Tool Permissions Reference
+
+This section lists the GitHub App permissions required by tools in the Arcade GitHub MCP Server.
+
+### Summary Table
+
+| Tool Category | Required Permissions |
+| ----------------- | --------------------------------------------------------------------------------- |
+| **Issues** | Contents (Read), Issues (Read/Write), Metadata (Read) |
+| **Pull Requests** | Contents (Read), Pull requests (Read/Write), Metadata (Read) |
+| **Projects** | Contents (Read), Metadata (Read), Projects (Read/Write), Members (Read) |
+| **Repositories** | Contents (Read/Write for file ops), Metadata (Read), Members (Read for org repos) |
+| **Reviews** | Contents (Read), Pull requests (Read/Write), Metadata (Read) |
+| **User Context** | Read user profile, Members (Read for orgs) |
+| **Notifications** | ⚠️ Classic PAT with `notifications` scope (GitHub Apps limitation) |
+
+### Detailed Permissions by Category
+
+
+
+
+**Issues Tools** (7 tools):
+
+- `create_issue`, `update_issue`, `create_issue_comment`, `list_issues`, `get_issue`, `list_repository_labels`, `manage_labels` (for issues)
+
+**Required:**
+
+- Repository: Contents (Read), Issues (Read/Write), Metadata (Read)
+- Organization: Projects (Read/Write) - only for `create_issue` when adding to org project
+
+
+
+
+**Pull Request Tools** (16 tools):
+
+**Read-only tools:**
+
+- `list_pull_requests`, `get_pull_request`, `list_pull_request_commits`, `list_review_comments_on_pull_request`
+- Required: Contents (Read), Pull requests (Read), Metadata (Read)
+
+**Write tools:**
+
+- `update_pull_request`, `create_pull_request`, `merge_pull_request`, `submit_pull_request_review`,
+ `manage_pull_request`, `manage_pull_request_reviewers`, `create_reply_for_review_comment`, `create_review_comment`, `resolve_review_thread`, `manage_labels` (for pull requests)
+- Required: Contents (Read), Pull requests (Write), Metadata (Read)
+- `merge_pull_request` also needs: Contents (Read & Write)
+
+**Special:**
+
+- `assign_pull_request_user`: Needs Issues (Write) + Members (Read)
+- `check_pull_request_merge_status`: Needs Statuses (Read)
+
+
+
+
+**Projects Tools** (5 tools):
+
+- `list_projects`, `list_project_items`, `search_project_item`, `list_project_fields`, `update_project_item`
+
+**Required:**
+
+- Repository: Contents (Read), Metadata (Read)
+- Organization: Projects (Read/Write), Members (Read)
+
+
+
+
+**Repository Tools** (11 tools):
+
+**Basic (Read-only):**
+
+- `count_stargazers`, `get_repository`, `list_repository_activities`, `list_stargazers`, `get_file_contents`
+- Required: Contents (Read), Metadata (Read)
+
+**Write Operations:**
+
+- `create_branch`, `create_or_update_file`, `update_file_lines`
+- Required: Contents (Read & Write), Metadata (Read)
+
+**User Actions:**
+
+- `set_starred`
+- Required: Contents (Read), Metadata (Read), "Act on behalf of user" permission
+
+**Organization:**
+
+- `list_org_repositories`, `search_my_repos`, `list_repository_collaborators`
+- Required: Contents (Read), Metadata (Read), Members (Read)
+
+**Reviews:**
+
+- `list_review_comments_in_a_repository`
+- Required: Contents (Read), Pull requests (Read), Metadata (Read)
+
+
+
+
+**User Context Tools** (4 tools):
+
+- `who_am_i`: Members (Read), Read user profile
+- `get_user_recent_activity`, `get_user_open_items`: Contents (Read), Metadata (Read), Read user profile
+- `get_review_workload`: Contents (Read), Pull requests (Read), Metadata (Read), Read user profile
+
+
+
+
+**⚠️ Notifications Tools**
+
+GitHub Apps **cannot** access the notifications API. This is a [platform limitation by design](https://docs.github.com/en/rest/activity/notifications).
+
+**Workaround:**
+
+- Tools: `get_notification_summary`, `list_notifications`
+- **Required**: Classic Personal Access Token with `notifications` scope
+- **Create at**: [github.com/settings/tokens](https://github.com/settings/tokens)
+- **Why**: Notifications are personal user data, not accessible to apps by GitHub's design
+
+**User-on-Behalf-of Actions:**
+
+The "Act on behalf of user" permission is only needed for specific user-attributed actions:
+
+- **When needed**: Starring repositories, actions appearing in user's activity feed
+- **Not needed for**: Reading data, app-attributed actions, organization operations
+- Enable in app settings: **User permissions** → "Act on behalf of user"
+- These actions act as the user (with user's avatar/name), not as the app
+- Users must authorize these permissions during their first use
+- [Learn more about user-to-server authentication](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/authenticating-with-a-github-app-on-behalf-of-a-user)
+
+
+
+
+---
+
+## Important Gotchas
+
+
+ These are common issues users encounter. Read this section to avoid
+ frustration!
+
+
+### Permission Changes Require User Reauthorization
+
+When you modify permissions in your GitHub App settings, existing user authorizations don't automatically receive the new permissions.
+
+**What Happens:**
+
+1. You update permissions in GitHub App settings
+2. Organization admins may need to approve the changes
+3. Existing user tokens still have old permissions
+4. Users must reauthorize to get new permissions
+
+**Solution:**
+
+- Users should revoke their authorization in Arcade and reauthorize
+- Or, admins can revoke all authorizations in GitHub App settings
+- New users will automatically get the updated permissions
+
+[Learn more about permission updates](https://docs.github.com/en/apps/using-github-apps/approving-updated-permissions-for-a-github-app)
+
+### 404 Errors Can Mean Missing Permissions or Installation
+
+GitHub returns `404 Not Found` (not 403 Forbidden) in several scenarios:
+
+**Possible Causes:**
+
+1. App not installed on the target repository
+2. Permissions not approved by organization admin
+3. Repository doesn't exist or you lack access
+4. User hasn't authorized the app yet
+
+**Why 404 Instead of 403?**
+GitHub doesn't reveal which repositories exist when you lack access (security by obscurity).
+
+**Solution:**
+
+1. Verify the app is installed on the target repository
+2. Check that all required permissions are approved
+3. Ensure the user has authorized the app
+4. Confirm the repository path is correct
+
+### Installing on Additional Repositories
+
+After initial installation, you can add more repositories:
+
+**Via GitHub Settings:**
+
+1. Go to Settings → Applications → Installed GitHub Apps
+2. Click on your app name
+3. Click **Configure**
+4. Under "Repository access", click **Select repositories**
+5. Choose additional repositories
+6. Click **Save**
+
+[Official guide for managing installations](https://docs.github.com/en/apps/using-github-apps/reviewing-your-authorized-integrations)
+
+### Permissions ≠ Scopes
+
+- GitHub Apps use **permissions** (fine-grained), not **scopes** (OAuth Apps)
+- Scopes aren't present in GitHub App tokens
+- User is still limited by their own GitHub permissions (can't elevate privileges)
+
+### Personal vs Organization GitHub Apps
+
+**Functionally the same**, but:
+
+- **Personal account app**: You own and manage it
+- **Organization app**: Org owns it, can be managed by org admins
+- Both can be installed on any account if "Any account" is selected
+
+---
+
+## Troubleshooting
+
+### Common Errors
+
+| Error | Cause | Solution |
+| -------------------------------------------- | --------------------------------------------------- | ------------------------------------------------ |
+| **"Resource not accessible by integration"** | Missing permissions or not installed on repo | Verify permissions and installation |
+| **"Installation not found"** | Wrong Installation ID | Check Installation ID in URL |
+| **"403 Forbidden"** | Missing permissions, not installed, or rate limited | Review permissions, check installation |
+| **"404 Not Found" on existing repo** | Permissions not approved by admin | Check app settings → verify permissions approved |
+| **Notifications not working** | GitHub Apps can't access notifications | Use classic PAT with `notifications` scope |
+| **Can't star repositories** | Missing "Act on behalf of user" permission | Enable in User permissions settings |
+
+### Debugging Steps
+
+1. **Verify Installation**
+
+ - Go to Settings → Applications → Installed GitHub Apps
+ - Confirm app is installed on target repository
+ - [Review your installations](https://docs.github.com/en/apps/using-github-apps/reviewing-your-authorized-integrations)
+
+2. **Check User Authorization**
+
+ - Verify the user has authorized the app
+ - Users can check at: Settings → Applications → Authorized GitHub Apps
+ - If not authorized, user needs to use your agent/app to trigger authorization flow
+
+3. **Check Permissions**
+
+ - Review app settings → Permissions & events
+ - Ensure all required permissions are granted
+ - Verify organization approval (if applicable)
+ - **After changing permissions**: Users must reauthorize
+
+4. **Test Credentials**
+
+ - Verify Client ID and Client Secret are correct in Arcade dashboard
+ - Ensure redirect URL in GitHub matches Arcade's generated URL
+ - Check that "Request user authorization (OAuth) during installation" is enabled
+
+---
+
+## Frequently Asked Questions
+
+### General
+
+**Q: Is GitHub Apps free?**
+A: Yes! Free GitHub accounts support GitHub Apps. No paid plan needed.
+
+**Q: Can I use one app for multiple projects?**
+A: Yes! Install the same app on multiple repositories. Each gets a unique Installation ID.
+
+**Q: What if I lose my private key?**
+A: Generate a new one from app settings. The old key will be invalidated. You cannot recover lost keys.
+
+### Installation
+
+**Q: Do I need to be an org owner?**
+A: To **create** an app: No (any user can create). To **install** on org: Yes (or need owner approval). Organization owners control which apps can be installed. [Learn more](https://docs.github.com/en/apps/using-github-apps/installing-a-github-app-from-a-third-party)
+
+**Q: How do I install the app on additional repositories?**
+A: Settings → Applications → Installed GitHub Apps → Click your app → Configure → Select additional repositories.
+
+**Q: Can I change permissions later?**
+A: Yes, anytime. After changing:
+
+- Organization installs require admin approval for new permissions
+- **Users must reauthorize** for new permissions to take effect
+- Best practice: Users should revoke old authorization and reauthorize
+- [Guide to updating permissions](https://docs.github.com/en/apps/using-github-apps/approving-updated-permissions-for-a-github-app)
+
+### Usage
+
+**Q: Which tools need org permissions?**
+A: Project management, collaborators listing, org repo listing, and user search within org context.
+
+**Q: What's the rate limit?**
+A: GitHub Apps: 5,000/hour per installation + 12,500/hour for user endpoints. OAuth: 5,000/hour total.
+
+**Q: Can I use with GitHub Enterprise Server?**
+A: Yes! See the [GitHub Enterprise Server Setup](#github-enterprise-server-setup) section above. You'll need to create a custom provider with your GHES instance URLs.
+
+**Q: Why can't I star repositories?**
+A: Starring repositories requires the "Act on behalf of user" permission:
+
+- Enable "Act on behalf of user" in User permissions section
+- This permission makes actions appear as the user (not the app)
+- Users must authorize this permission when they first use your agent
+- The app can still read and perform other actions without this permission
+- [Why this permission exists](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/authenticating-with-a-github-app-on-behalf-of-a-user)
+
+**Q: Why can't I access notifications?**
+A: Notifications require a classic PAT (GitHub Apps cannot access notifications API by design):
+
+- This is a platform limitation, not an Arcade limitation
+- Create a classic PAT at [github.com/settings/tokens](https://github.com/settings/tokens) with `notifications` scope
+- [Why GitHub Apps can't access notifications](https://docs.github.com/en/rest/activity/notifications)
+
+### Security
+
+**Q: What if my credentials are compromised?**
+A: Immediately take these steps:
+
+1. Revoke the Client Secret in GitHub App settings
+2. Generate a new Client Secret
+3. Update your Arcade OAuth provider configuration
+4. Review GitHub audit logs for suspicious activity
+5. Consider revoking all user authorizations
+6. Notify affected users if necessary
+
+[GitHub security best practices](https://docs.github.com/en/apps/creating-github-apps/setting-up-a-github-app/best-practices-for-creating-a-github-app)
+
+**Q: Why can't the app access all my repositories?**
+A: Security by design. Apps only access repositories they're explicitly installed on. This limits blast radius if compromised.
+
+### GitHub Enterprise Server
+
+**Q: Can I use the same GitHub App for github.com and GHES?**
+A: No. GitHub Apps created on github.com cannot be installed on GHES instances, and vice versa. Each GHES instance requires its own separate GitHub App registration. This is a GitHub platform limitation, not an Arcade limitation.
+
+**Q: Can I use the same app configuration for multiple GHES instances?**
+A: Yes! You can share the same manifest or URL parameters with multiple GHES instances. Each instance will register their own GitHub App with identical settings, but you'll need to create separate custom providers in Arcade for each instance.
+
+**Q: Does GHES support all the same features as github.com?**
+A: Not always. GHES may have feature differences and typically receives new API endpoints, GraphQL objects, and webhooks later than github.com. Check the `x-github-enterprise-version` header in API responses to identify the GHES version. [Learn more about GHES version differences](https://docs.github.com/en/enterprise-server/admin/overview/about-upgrades-to-new-releases)
+
+**Q: How do I know what GHES version my instance is running?**
+A: Contact your GHES administrator, or check the API response headers which include `x-github-enterprise-version`. You can also see the version in the GHES footer when logged in.
+
+**Q: Can I use the "Included Provider" for GHES?**
+A: No. The included GitHub provider in Arcade is configured for github.com only. You must create a custom provider with your GHES instance URLs. See the [GHES setup guide](#github-enterprise-server-setup) above.
+
+**Q: Do GHES rate limits work the same as github.com?**
+A: No. GHES administrators can configure custom rate limits for their instance. If you're hitting rate limits, contact your GHES admin about the configured limits and request an increase if needed.
+
+---
+
+## Configuration Checklist
+
+Use this checklist to ensure proper setup:
+
+- [ ] Created GitHub App (not OAuth App)
+- [ ] Set all required permissions (Contents, Issues, Pull requests, etc.)
+- [ ] **Enabled** "Request user authorization (OAuth) during installation" ✅
+- [ ] Enabled "Act on behalf of user" for user-level actions
+- [ ] Generated and securely stored Client Secret
+- [ ] Noted Client ID
+- [ ] Installed app on target repositories (or made public for any account)
+- [ ] Added Arcade redirect URL to GitHub app callback URL
+- [ ] Configured OAuth provider in Arcade dashboard
+- [ ] Tested with a simple tool call
+- [ ] ~~Generated private key~~ (Not needed for Arcade)
+- [ ] ~~Noted Installation ID~~ (Not needed for Arcade)
+
+### For GitHub Enterprise Server:
+
+- [ ] Created Custom Provider in Arcade (NOT included provider)
+- [ ] Configured all endpoint URLs with correct GHES hostname
+- [ ] Set Authorization endpoint: `https://{your-ghes-host}/login/oauth/authorize`
+- [ ] Set Token endpoint: `https://{your-ghes-host}/login/oauth/access_token`
+- [ ] Set User Info endpoint: `https://{your-ghes-host}/api/v3/user`
+- [ ] Set Refresh Token endpoint (same as Token endpoint)
+- [ ] Enabled Token Introspection with correct settings:
+ - [ ] Introspection endpoint: `https://{your-ghes-host}/api/v3/user`
+ - [ ] Authentication Method: Bearer Access Token
+ - [ ] Content-Type: application/json
+ - [ ] Triggers: OnTokenGrant and OnTokenRefresh enabled
+- [ ] Tested with GHES-specific provider ID in auth calls
+- [ ] Verified GHES version compatibility with required features
+
+---
+
+## Additional Resources
+
+### Official GitHub Documentation
+
+- [GitHub Apps Overview](https://docs.github.com/en/apps)
+- [Installing Your Own GitHub App](https://docs.github.com/en/apps/using-github-apps/installing-your-own-github-app)
+- [Installing a GitHub App from a Third Party](https://docs.github.com/en/apps/using-github-apps/installing-a-github-app-from-a-third-party)
+- [Authorizing GitHub Apps](https://docs.github.com/en/apps/using-github-apps/authorizing-github-apps)
+- [Reviewing and Revoking Authorization](https://docs.github.com/en/apps/using-github-apps/reviewing-and-revoking-authorization-of-github-apps)
+- [Approving Updated Permissions](https://docs.github.com/en/apps/using-github-apps/approving-updated-permissions-for-a-github-app)
+- [GitHub API Documentation](https://docs.github.com/en/rest)
+- [Security Best Practices](https://docs.github.com/en/apps/creating-github-apps/setting-up-a-github-app/best-practices-for-creating-a-github-app)
+
+### Arcade Resources
+
+- [Arcade GitHub MCP Server](/mcp-servers/development/github)
+- [Arcade Authorization Guide](/home/auth/how-arcade-helps)
+- [Video Tutorial: GitHub App Setup](https://www.youtube.com/watch?v=KcO2SruCdt0)
+
+---
+
+_💡 Remember: Always use GitHub Apps (not OAuth Apps), enable user authorization during installation, and store credentials securely!_
diff --git a/app/en/home/sharing-with-end-users/custom-auth/google/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/google/page.mdx
new file mode 100644
index 000000000..7c43ce697
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/google/page.mdx
@@ -0,0 +1,258 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Google
+
+The Google auth provider enables tools and agents to call Google/Google Workspace APIs on behalf of a user.
+
+
+ Want to quickly get started with Google services in your agent or AI app? The
+ pre-built [Arcade Gmail MCP Server](/mcp-servers/productivity/gmail) is what you
+ want!
+
+
+### What's documented here
+
+This page describes how to use and configure Google auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade Gmail MCP Server](/mcp-servers/productivity/gmail), which provides pre-built tools for interacting with Google services
+- Your [app code](#using-google-auth-in-app-code) that needs to call Google APIs
+- Or, your [custom tools](#using-google-auth-in-custom-tools) that need to call Google APIs
+
+## Configuring Google auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Google app credentials. This way, your users will see your application's name requesting permission.
+
+
+Before showing how to configure your Google app credentials, let's go through the steps to create a Google app.
+
+### Create a Google app
+
+- Follow Google's guide to [setting up OAuth credentials](https://support.google.com/cloud/answer/6158849?hl=en)
+- Choose the [scopes](https://developers.google.com/identity/protocols/oauth2/scopes) (permissions) you need for your app
+- At a minimum, you must enable these scopes:
+ - `https://www.googleapis.com/auth/userinfo.email`
+ - `https://www.googleapis.com/auth/userinfo.profile`
+- Add the redirect URL generated by Arcade (see below) to the Authorized redirect URIs list
+- Copy the client ID and client secret to use below
+
+Next, add the Google app to Arcade.
+
+## Configuring your own Google Auth Provider in Arcade
+
+
+
+
+
+### Configure Google Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Included Providers** tab at the top.
+- In the **Provider** dropdown, select **Google**.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "my-google-provider").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Google app.
+- Note the **Redirect URL** generated by Arcade. This must be added to your Google app's Authorized redirect URIs list.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+When you use tools that require Google auth using your Arcade account credentials, Arcade will automatically use this Google OAuth provider. If you have multiple Google providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+
+
+
+## Using Google auth in app code
+
+Use the Google auth provider in your own agents and AI apps to get a user token for Google APIs. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for Google APIs:
+
+
+
+
+```python {22-26}
+from arcadepy import Arcade
+from google.oauth2.credentials import Credentials
+from googleapiclient.discovery import build
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+"""
+In this example, we will use Arcade to authenticate with Google and
+retrieve Gmail messages.
+
+There is a tool for that in the Arcade SDK, which simplifies the process for
+you to retrieve email messages either through our Python or JavaScript
+SDKs or via LLM tool calling.
+
+Below we are just showing how to use Arcade as an auth provider, if you ever
+need to.
+"""
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="google",
+ scopes=["https://www.googleapis.com/auth/gmail.readonly"],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+
+if not token:
+ raise ValueError("No token found in auth response")
+
+credentials = Credentials(token)
+gmail = build("gmail", "v1", credentials=credentials)
+
+email_messages = (
+ gmail.users().messages().list(userId="me").execute().get("messages", [])
+)
+
+print(email_messages)
+```
+
+
+
+
+
+```javascript {20-22}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade(); // Automatically finds the `ARCADE_API_KEY` env variable
+
+const userId = "{arcade_user_id}";
+
+/*
+In this example, we will use Arcade to authenticate with Google and
+retrieve Gmail messages.
+
+There is a tool for that in the Arcade SDK, which simplifies the process for
+you to retrieve email messages either through our Python or JavaScript
+SDKs or via LLM tool calling.
+
+Below we are just showing how to use Arcade as an auth provider, if you ever
+need to.
+*/
+
+// Start the authorization process
+let authResponse = await client.auth.start(userId, "google", {
+ scopes: ["https://www.googleapis.com/auth/gmail.readonly"],
+});
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+if (!authResponse.context.token) {
+ throw new Error("No token found in auth response");
+}
+
+const token = authResponse.context.token;
+
+// Use the Google Gmail API
+const response = await fetch(
+ "https://gmail.googleapis.com/gmail/v1/users/me/messages",
+ {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ }
+);
+
+if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+}
+
+const data = await response.json();
+const emailMessages = data.messages || [];
+
+// Return a list of ids and thread ids
+console.log(emailMessages);
+```
+
+
+
+
+
+## Using Google auth in custom tools
+
+You can use the pre-built Arcade Google MCP Servers, like [Arcade Gmail MCP Server](/mcp-servers/productivity/gmail), to quickly build agents and AI apps that interact with Google services like Gmail, Calendar, Drive, and more.
+
+If the pre-built tools in the Google MCP Servers don't meet your needs, you can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with Google APIs.
+
+Use the `Google()` auth class to specify that a tool requires authorization with Google. The `context.authorization.token` field will be automatically populated with the user's Google token:
+
+```python {3-4,10-14,26}
+from typing import Annotated
+
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import Google
+
+from google.oauth2.credentials import Credentials
+from googleapiclient.discovery import build
+
+
+@tool(
+ requires_auth=Google(
+ scopes=["https://www.googleapis.com/auth/gmail.readonly"],
+ )
+)
+async def list_emails(
+ context: ToolContext,
+ subject: Annotated[str, "The subject of the email"],
+ body: Annotated[str, "The body of the email"],
+ recipient: Annotated[str, "The recipient of the email"],
+) -> Annotated[str, "A confirmation message with the sent email ID and URL"]:
+ """
+ Send an email using the Gmail API.
+ """
+ if not context.authorization or not context.authorization.token:
+ raise ValueError("No token found in context")
+
+ credentials = Credentials(context.authorization.token)
+ gmail = build("gmail", "v1", credentials=credentials)
+
+ email_messages = (
+ gmail.users().messages().list(userId="me").execute().get("messages", [])
+ )
+
+ return email_messages
+```
diff --git a/app/en/home/sharing-with-end-users/custom-auth/hubspot/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/hubspot/page.mdx
new file mode 100644
index 000000000..c14bf8150
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/hubspot/page.mdx
@@ -0,0 +1,304 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Hubspot
+
+The Hubspot auth provider enables tools and agents to call Hubspot APIs on behalf of a user.
+
+
+ Want to quickly get started with Hubspot services in your agent or AI app? The
+ pre-built [Arcade Hubspot MCP Server](/mcp-servers/sales/hubspot) is what you
+ want!
+
+
+## What's documented here
+
+This page describes how to use and configure Hubspot auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade Hubspot MCP Server](/mcp-servers/sales/hubspot), which provides pre-built tools for interacting with Hubspot
+- Your [app code](#using-hubspot-auth-in-app-code) that needs to call Hubspot APIs
+- Or, your [custom tools](#using-hubspot-auth-in-custom-tools) that need to call Hubspot APIs
+
+## Use Arcade's Default Hubspot Auth Provider
+
+Arcade offers a default Hubspot auth provider that you can use in the Arcade Cloud Platform. In this case, your users will see `Arcade` as the name of the application that's requesting permission.
+
+If you choose to use Arcade's Hubspot auth, you don't need to configure anything. Follow the [Hubspot MCP Server examples](/mcp-servers/sales/hubspot) to get started calling Hubspot tools.
+
+## Use Your Own Hubspot App Credentials
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Hubspot app credentials. This way, your users will see your application's name requesting permission.
+
+
+Before showing how to configure your Hubspot app credentials, let's go through the steps to create a Hubspot app.
+
+## Create a Hubspot App
+
+Hubspot has two types of apps: Public and Private. You will need to create a Public one.
+
+Follow [Hubspot's tutorial](https://developers.hubspot.com/docs/guides/apps/public-apps/overview) to create your Public App. You will need a [developer account](https://app.hubspot.com/signup-hubspot/developers) to do this.
+
+When creating your app, use the following settings:
+
+- Under **App Info**, choose a name, description, and logo for your app
+- Under **Auth**, enter the **Redirect URL** generated by Arcade (see below)
+- In the **Scopes** section, click **Add Scope** and add the following scopes with the **Conditionally Required** scope type:
+ - `crm.objects.companies.read`
+ - `crm.objects.contacts.read`
+ - `crm.objects.contacts.write`
+ - `crm.objects.deals.read`
+ - `sales-email-read`
+
+Create the app and take note of the **Client ID** and **Client Secret**. You don't need to follow Hubspot's instructions to install the app.
+
+
+ If you are implementing your own [Hubspot custom
+ tools](#using-hubspot-auth-in-custom-tools), make sure to also add [any extra
+ scopes](https://developers.hubspot.com/docs/guides/apps/authentication/scopes)
+ necessary for the actions your tools need to perform. All extra scopes must be
+ added to the app as `Conditionally Required` or `Optional`, never as
+ `Required`, otherwise the Arcade Hubspot MCP Server will not work. Read more
+ about [Hubspot scope
+ types](https://developers.hubspot.com/changelog/advanced-auth-and-scope-settings-for-public-apps).
+
+
+## Configuring your own Hubspot Auth Provider in Arcade
+
+
+
+
+
+### Configure Hubspot Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Included Providers** tab at the top.
+- In the **Provider** dropdown, select **Hubspot**.
+
+#### Enter the provider details
+
+- Enter `hubspot` as the **ID** for your provider
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Hubspot app.
+- Note the **Redirect URL** generated by Arcade. This must be set as your Hubspot app's Redirect URL.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+When you use tools that require Hubspot auth using your Arcade account credentials, Arcade will automatically use this Hubspot OAuth provider. If you have multiple Hubspot providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+
+
+
+## Using the Arcade Hubspot MCP Servers
+
+The [Arcade Hubspot MCP Server](/mcp-servers/sales/hubspot) provides tools to interact with various Hubspot objects, such as companies, contacts, deals, and email messages.
+
+Refer to the [MCP Server documentation and examples](/mcp-servers/sales/hubspot) to learn how to use the MCP Server to build agents and AI apps that interact with Hubspot services.
+
+## Using Hubspot auth in app code
+
+Use the Hubspot auth provider in your own agents and AI apps to get a user-scoped token for the Hubspot API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Hubspot API:
+
+
+
+
+```python {21}
+from arcadepy import Arcade
+
+client = Arcade(base_url="https://api.arcade.dev") # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="hubspot",
+ scopes=["oauth", "crm.objects.companies.read"],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+
+```javascript {20}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade({ baseURL: "https://api.arcade.dev" }); // Automatically finds the `ARCADE_API_KEY` env variable
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+const authResponse = await client.auth.start(userId, "hubspot", {
+ scopes: ["oauth", "crm.objects.companies.read"],
+});
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+const response = await client.auth.waitForCompletion(authResponse);
+
+const token = response.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+You can use the auth token to call [Hubspot Companies endpoints](https://developers.hubspot.com/docs/guides/api/crm/objects/companies) and read information about companies. By changing or adding scopes to the `client.auth.start` call, you can call other Hubspot endpoints.
+
+The scopes supported by the Arcade Hubspot auth provider are the ones [listed above](#create-a-hubspot-app). If you created your own Hubspot app, make sure to add the scopes you intend to use in the `client.auth.start` call.
+
+## Using Hubspot auth in custom tools
+
+You can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Hubspot API.
+
+Use the `Hubspot()` auth class to specify that a tool requires authorization with Hubspot. The authentication token needed to call the Hubspot API is available in the tool context through the `context.get_auth_token_or_empty()` method.
+
+```python {10,23}
+from typing import Annotated
+
+import httpx
+
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import Hubspot
+
+
+@tool(
+ requires_auth=Hubspot(
+ scopes=["oauth", "crm.objects.companies.read"],
+ )
+)
+async def get_company_details(
+ context: ToolContext,
+ company_id: Annotated[
+ str,
+ "The ID of the company to get the details of.",
+ ],
+) -> Annotated[dict, "Details of the company"]:
+ """Gets the details of a company."""
+ url = f"https://api.hubapi.com/crm//v3/objects/companies/{company_id}"
+ headers = {"Authorization": f"Bearer {context.get_auth_token_or_empty()}"}
+
+ async with httpx.AsyncClient() as client:
+ response = await client.get(url, headers=headers)
+ response.raise_for_status()
+ return response.json()
+```
+
+
+Your new tool can be called like demonstrated below:
+
+
+
+
+ If you are self-hosting, change the `base_url` parameter in the `Arcade` constructor to match your Arcade Engine URL. By default, the Engine will be available at `http://localhost:9099`.
+
+
+```python
+from arcadepy import Arcade
+
+client = Arcade(base_url="https://api.arcade.dev") # Automatically finds the `ARCADE_API_KEY` env variable
+
+USER_ID = "{arcade_user_id}"
+TOOL_NAME = "Hubspot.GetCompanyDetails"
+
+auth_response = client.tools.authorize(tool_name=TOOL_NAME, user_id=USER_ID)
+
+if auth_response.status != "completed":
+ print(f"Click this link to authorize: {auth_response.url}")
+
+# Wait for the authorization to complete
+client.auth.wait_for_completion(auth_response)
+
+tool_input = {
+ "company_id": "32134490789",
+}
+
+response = client.tools.execute(
+ tool_name=TOOL_NAME,
+ input=tool_input,
+ user_id=USER_ID,
+)
+print(response.output.value)
+```
+
+
+
+
+ If you are self-hosting, change the `baseURL` parameter in the `Arcade` constructor to match your Arcade Engine URL. By default, the Engine will be available at `http://localhost:9099`.
+
+
+```javascript
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade({ baseURL: "https://api.arcade.dev" }); // Automatically finds the `ARCADE_API_KEY` env variable
+
+const USER_ID = "{arcade_user_id}";
+const TOOL_NAME = "Hubspot.GetCompanyDetails";
+
+// Start the authorization process
+const authResponse = await client.tools.authorize({
+ tool_name: TOOL_NAME,
+ user_id: USER_ID,
+});
+
+if (authResponse.status !== "completed") {
+ console.log(`Click this link to authorize: ${authResponse.url}`);
+}
+
+// Wait for the authorization to complete
+await client.auth.waitForCompletion(authResponse);
+
+const toolInput = {
+ company_id: "1234567890",
+};
+
+const response = await client.tools.execute({
+ tool_name: TOOL_NAME,
+ input: toolInput,
+ user_id: USER_ID,
+});
+
+console.log(response.output.value);
+```
+
+
+
diff --git a/app/en/home/sharing-with-end-users/custom-auth/linear/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/linear/page.mdx
new file mode 100644
index 000000000..aa7c8667e
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/linear/page.mdx
@@ -0,0 +1,288 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Linear
+
+The Linear auth provider enables tools and agents to call [Linear APIs](https://linear.app/developers/graphql) on behalf of a user.
+
+
+ Want to quickly get started with Linear in your agent or AI app? The pre-built
+ [Arcade Linear MCP Server](/mcp-servers/productivity/linear) is what you want!
+
+
+### What's documented here
+
+This page describes how to use and configure Linear auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade Linear MCP Server](/mcp-servers/productivity/linear), which provides pre-built tools for interacting with Linear
+- Your [app code](#using-linear-auth-in-app-code) that needs to call Linear APIs
+- Or, your [custom tools](#using-linear-auth-in-custom-tools) that need to call Linear APIs
+
+## Configuring Linear auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Linear app credentials. This way, your users will see your application's name requesting permission.
+
+Before showing how to configure your Linear app credentials, let's go through the steps to create a Linear app.
+
+### Create a Linear app
+
+- It is **highly recommended** to first [create a new Linear workspace](https://linear.app/join) for the purpose of managing the OAuth2 Application, as each admin user will have access
+- Create a new public OAuth2 Application in your [integration settings page](https://linear.app/settings/api/applications/new)
+- Fill out your application specific information such as application name and description
+- Choose the [scopes](https://linear.app/developers/oauth-2-0-authentication#redirect-user-access-requests-to-linear) (permissions) you need for your app
+- Add the redirect URL generated by Arcade (see below) to the Callback URL field
+- Toggle the **Public** switch if you want other workspaces to be able to use your application
+- Copy the client ID and client secret to use below
+
+Next, add the Linear app to Arcade.
+
+## Configuring your own Linear Auth Provider in Arcade
+
+
+
+
+### Configure Linear Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Included Providers** tab at the top.
+- In the **Provider** dropdown, select **Linear**.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "my-linear-provider").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Linear app.
+- Note the **Redirect URL** generated by Arcade. This must be added to your Linear app's Callback URL field.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+When you use tools that require Linear auth using your Arcade account credentials, Arcade will automatically use this Linear OAuth provider. If you have multiple Linear providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+
+
+
+## Using Linear auth in app code
+
+Use the Linear auth provider in your own agents and AI apps to get a user token for Linear APIs. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for Linear APIs:
+
+
+
+
+```python {22-26}
+from arcadepy import Arcade
+import httpx
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+"""
+In this example, we will use Arcade to authenticate with Linear and
+retrieve teams.
+
+There is a tool for that in the Arcade Linear MCP Server, which simplifies
+the process for you to interact with Linear either through our Python or
+JavaScript SDKs or via LLM tool calling.
+
+Below we are just showing how to use Arcade as an auth provider, if you ever
+need to.
+"""
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="linear",
+ scopes=["read"],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+
+if not token:
+ raise ValueError("No token found in auth response")
+
+# Use the Linear GraphQL API
+url = "https://api.linear.app/graphql"
+headers = {
+ "Authorization": f"Bearer {token}",
+ "Content-Type": "application/json",
+}
+
+query = """
+query Teams {
+ teams {
+ nodes {
+ id
+ name
+ key
+ }
+ }
+}
+"""
+
+response = httpx.post(url, json={"query": query}, headers=headers)
+data = response.json()
+teams = data["data"]["teams"]["nodes"]
+
+print(teams)
+```
+
+
+
+
+
+```javascript {20-22}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade(); // Automatically finds the `ARCADE_API_KEY` env variable
+
+const userId = "{arcade_user_id}";
+
+/*
+In this example, we will use Arcade to authenticate with Linear and
+retrieve teams.
+
+There is a tool for that in the Arcade Linear MCP Server, which simplifies
+the process for you to interact with Linear either through our Python or
+JavaScript SDKs or via LLM tool calling.
+
+Below we are just showing how to use Arcade as an auth provider, if you ever
+need to.
+*/
+
+// Start the authorization process
+let authResponse = await client.auth.start(userId, "linear", {
+ scopes: ["read"],
+});
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+if (!authResponse.context.token) {
+ throw new Error("No token found in auth response");
+}
+
+const token = authResponse.context.token;
+
+// Use the Linear GraphQL API
+const response = await fetch("https://api.linear.app/graphql", {
+ method: "POST",
+ headers: {
+ Authorization: `Bearer ${token}`,
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ query: `
+ query Teams {
+ teams {
+ nodes {
+ id
+ name
+ key
+ }
+ }
+ }
+ `,
+ }),
+});
+
+if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+}
+
+const data = await response.json();
+const teams = data.data.teams.nodes;
+
+console.log(teams);
+```
+
+
+
+
+
+## Using Linear auth in custom tools
+
+You can use the pre-built [Arcade Linear MCP Server](/mcp-servers/productivity/linear) to quickly build agents and AI apps that interact with Linear.
+
+If the pre-built tools in the Linear MCP Server don't meet your needs, you can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Linear API.
+
+Use the `Linear()` auth class to specify that a tool requires authorization with Linear. The `context.authorization.token` field will be automatically populated with the user's Linear token:
+
+```python {3-4,10-14,26}
+from typing import Annotated, Any
+
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import Linear
+
+import httpx
+
+
+@tool(requires_auth=Linear(scopes=["read"]))
+async def get_teams(
+ context: ToolContext,
+) -> Annotated[dict[str, Any], "Teams in the workspace with member information"]:
+ """Get Linear teams and team information including team members"""
+ if not context.authorization or not context.authorization.token:
+ raise ValueError("No token found in context")
+
+ token = context.authorization.token
+ url = "https://api.linear.app/graphql"
+ headers = {
+ "Authorization": f"Bearer {token}",
+ "Content-Type": "application/json",
+ }
+
+ query = """
+ query Teams {
+ teams {
+ nodes {
+ id
+ name
+ key
+ }
+ }
+ }
+ """
+
+ async with httpx.AsyncClient() as client:
+ resp = await client.post(url, json={"query": query}, headers=headers)
+ resp.raise_for_status()
+ data = resp.json()
+ teams = data["data"]["teams"]["nodes"]
+ return teams
+```
diff --git a/app/en/home/sharing-with-end-users/custom-auth/linkedin/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/linkedin/page.mdx
new file mode 100644
index 000000000..a9047589a
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/linkedin/page.mdx
@@ -0,0 +1,275 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# LinkedIn
+
+The LinkedIn auth provider enables tools and agents to call the LinkedIn API on behalf of a user.
+
+### What's documented here
+
+This page describes how to use and configure LinkedIn auth with Arcade.
+
+This auth provider is used by:
+
+- Your [app code](#using-linkedin-auth-in-app-code) that needs to call LinkedIn APIs
+- Or, your [custom tools](#using-linkedin-auth-in-custom-tools) that need to call LinkedIn APIs
+
+## Configuring LinkedIn auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own LinkedIn app credentials. This way, your users will see your application's name requesting permission.
+
+
+Before showing how to configure your LinkedIn app credentials, let's go through the steps to create a LinkedIn app.
+
+### Create a LinkedIn app
+
+- Follow LinkedIn's guide to [setting up user authorization](https://learn.microsoft.com/en-us/linkedin/shared/authentication/authentication)
+- On the Products tab, add the products you need for your app (e.g. "Share on LinkedIn")
+ - At a minimum, you _must_ add the "Sign In with LinkedIn using OpenID Connect" product
+- On the Auth tab, set the redirect URL to the redirect URL generated by Arcade (see below)
+- Copy the client ID and client secret to use below
+
+Next, add the LinkedIn app to Arcade.
+
+## Configuring your own LinkedIn Auth Provider in Arcade
+
+
+
+
+
+## Using LinkedIn auth in app code
+
+Use the LinkedIn auth provider in your own agents and AI apps to get a user token for LinkedIn APIs. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for LinkedIn APIs:
+
+
+
+
+```python {23-27}
+import requests
+
+from arcadepy import Arcade
+
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+"""
+In this example, we will use Arcade to authenticate with LinkedIn and post a
+message to the user's LinkedIn feed.
+
+There is a tool for that in the Arcade SDK, which simplifies the process for
+you to post messages to the user's LinkedIn feed either through our Python or
+JavaScript SDKs or via LLM tool calling.
+
+Below we are just showing how to use Arcade as an auth provider, if you ever
+need to.
+"""
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="linkedin",
+ scopes=["w_member_social"],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+if not auth_response.context.token:
+ raise ValueError("No token found in auth response")
+
+token = auth_response.context.token
+
+user_id = (
+ None
+ if not auth_response.context.authorization
+ else auth_response.context.authorization.user_info.get("sub")
+)
+
+if not user_id:
+ raise ValueError("User ID not found.")
+
+# Prepare the payload data for the LinkedIn API
+message = "Hello, from Arcade.dev!"
+payload = {
+ "author": f"urn:li:person:{user_id}",
+ "lifecycleState": "PUBLISHED",
+ "specificContent": {
+ "com.linkedin.ugc.ShareContent": {
+ "shareCommentary": {"text": message},
+ "shareMediaCategory": "NONE",
+ }
+ },
+ "visibility": {"com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC"},
+}
+
+response = requests.post(
+ "https://api.linkedin.com/v2/ugcPosts",
+ headers={"Authorization": f"Bearer {token}"},
+ json=payload,
+)
+response.raise_for_status()
+print(response.json())
+```
+
+
+
+
+
+```javascript {20-22}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade(); // Automatically finds the `ARCADE_API_KEY` env variable
+
+const userId = "{arcade_user_id}";
+
+/*
+In this example, we will use Arcade to authenticate with LinkedIn and post a
+message to the user's LinkedIn feed.
+
+There is a tool for that in the Arcade SDK, which simplifies the process for
+you to post messages to the user's LinkedIn feed either through our Python or
+JavaScript SDKs or via LLM tool calling.
+
+Below we are just showing how to use Arcade as an auth provider, if you ever
+need to.
+*/
+
+// Start the authorization process
+let authResponse = await client.auth.start(userId, "linkedin", {
+ scopes: ["w_member_social"],
+});
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+if (!authResponse.context.token) {
+ throw new Error("No token found in auth response");
+}
+
+const token = authResponse.context.token;
+
+const linkedInUserId = authResponse.context.authorization?.user_info?.sub;
+
+if (!linkedInUserId) {
+ throw new Error("User ID not found.");
+}
+
+// Prepare the payload data for the LinkedIn API
+const message = "Hello, from Arcade.dev!";
+const payload = {
+ author: `urn:li:person:${linkedInUserId}`,
+ lifecycleState: "PUBLISHED",
+ specificContent: {
+ "com.linkedin.ugc.ShareContent": {
+ shareCommentary: { text: message },
+ shareMediaCategory: "NONE",
+ },
+ },
+ visibility: { "com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC" },
+};
+
+const response = await fetch("https://api.linkedin.com/v2/ugcPosts", {
+ method: "POST",
+ headers: {
+ Authorization: `Bearer ${token}`,
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(payload),
+});
+
+if (!response.ok) {
+ throw new Error(`HTTP error! status: ${response.status}`);
+}
+
+const data = await response.json();
+console.log(data);
+```
+
+
+
+
+
+## Using LinkedIn auth in custom tools
+
+You can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with LinkedIn APIs.
+
+Use the `LinkedIn()` auth class to specify that a tool requires authorization with LinkedIn. The `context.authorization.token` field will be automatically populated with the user's LinkedIn token:
+
+```python {6-7,10-14,33}
+from typing import Annotated
+
+import httpx
+
+from arcade_tdk.errors import ToolExecutionError
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import LinkedIn
+
+
+@tool(
+ requires_auth=LinkedIn(
+ scopes=["w_member_social"],
+ )
+)
+async def create_text_post(
+ context: ToolContext,
+ text: Annotated[str, "The text content of the post"],
+) -> Annotated[str, "URL of the shared post"]:
+ """Share a new text post to LinkedIn."""
+ endpoint = "/ugcPosts"
+
+ # The LinkedIn user ID is required to create a post, even though we're using the user's access token.
+ # Arcade Engine gets the current user's info from LinkedIn and automatically populates context.authorization.user_info.
+ # LinkedIn calls the user ID "sub" in their user_info data payload. See:
+ # https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/sign-in-with-linkedin-v2#api-request-to-retreive-member-details
+ user_id = context.authorization.user_info.get("sub")
+ if not user_id:
+ raise ToolExecutionError(
+ "User ID not found.",
+ developer_message="User ID not found in `context.authorization.user_info.sub`",
+ )
+
+ headers = {"Authorization": f"Bearer {context.authorization.token}"}
+
+ author_id = f"urn:li:person:{user_id}"
+ payload = {
+ "author": author_id,
+ "lifecycleState": "PUBLISHED",
+ "specificContent": {
+ "com.linkedin.ugc.ShareContent": {
+ "shareCommentary": {"text": text},
+ "shareMediaCategory": "NONE",
+ }
+ },
+ "visibility": {"com.linkedin.ugc.MemberNetworkVisibility": "PUBLIC"},
+ }
+
+ async with httpx.AsyncClient() as client:
+ response = await client.post(
+ url=f"https://api.linkedin.com/v2/{endpoint}",
+ headers=headers,
+ json=payload,
+ )
+ response.raise_for_status()
+ share_id = response.json().get("id")
+ return f"https://www.linkedin.com/feed/update/{share_id}/"
+```
diff --git a/app/en/home/sharing-with-end-users/custom-auth/mailchimp/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/mailchimp/page.mdx
new file mode 100644
index 000000000..ba67a49f1
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/mailchimp/page.mdx
@@ -0,0 +1,331 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Mailchimp
+
+The Mailchimp auth provider enables tools and agents to call [Mailchimp Marketing APIs](https://mailchimp.com/developer/marketing/api/) on behalf of a user using OAuth 2.0 authentication.
+
+
+ Want to quickly get started with Mailchimp in your agent or AI app? The
+ pre-built [Arcade Mailchimp Marketing MCP Server](/mcp-servers/productivity/mailchimp-marketing-api)
+ is what you want!
+
+
+### What's documented here
+
+This page describes how to use and configure Mailchimp auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade Mailchimp Marketing MCP Server](/mcp-servers/productivity/mailchimp-marketing-api), which provides pre-built tools for interacting with Mailchimp
+- Your [app code](#using-mailchimp-auth-in-app-code) that needs to call the Mailchimp API
+- Or, your [custom tools](#using-mailchimp-auth-in-custom-tools) that need to call the Mailchimp API
+
+## Configuring Mailchimp auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Mailchimp app credentials. This way, your users will see your application's name requesting permission.
+
+Before showing how to configure your Mailchimp app credentials, let's go through the steps to create a Mailchimp app.
+
+### Create a Mailchimp app
+
+To integrate with Mailchimp's API, you'll need to register an OAuth application:
+
+
+
+#### Log into your Mailchimp account
+
+1. Navigate to [mailchimp.com](https://mailchimp.com) and log in to your account
+2. Go to **Account** > **Extras** > **Registered Apps**
+3. Alternatively, you can directly access the [Registered Apps page](https://admin.mailchimp.com/account/oauth2/)
+
+#### Register a new OAuth application
+
+1. Click on **Register an App**
+2. Fill in the required details:
+ - **Application Name**: Choose a descriptive name for your application
+ - **Company/Organization**: Enter your company or organization name
+ - **Website URL**: Your application's website URL
+ - **Description**: Brief description of your application
+ - **Redirect URI**: Add the redirect URL generated by Arcade (see configuration section below)
+ - This is the URL where Mailchimp will redirect users after authorization
+ - For development, you can use `http://localhost:9099/oauth/callback` or your Arcade instance URL
+
+#### Save your credentials
+
+1. After registration, you'll receive your **Client ID** and **Client Secret**
+2. **Important**: Copy and save these credentials immediately in a secure location
+3. You can always view your Client ID later, but the Client Secret should be stored securely
+
+
+
+For detailed instructions, refer to Mailchimp's [OAuth 2.0 documentation](https://mailchimp.com/developer/marketing/guides/access-user-data-oauth-2/) and [API documentation](https://mailchimp.com/developer/marketing/api/).
+
+Next, add the Mailchimp app to Arcade.
+
+## Configuring your own Mailchimp Auth Provider in Arcade
+
+
+
+
+### Configure Mailchimp Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **OAuth 2.0** tab at the top.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "arcade-mailchimp").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Mailchimp app.
+- Configure the OAuth 2.0 endpoints:
+ - **Authorization URL**: `https://login.mailchimp.com/oauth2/authorize`
+ - **Token URL**: `https://login.mailchimp.com/oauth2/token`
+- Note the **Redirect URL** generated by Arcade. This must be set as your Mailchimp app's Redirect URI.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+
+
+
+
+### Configure Mailchimp Auth Using Configuration File
+
+
+ This method is only available when you are [self-hosting the
+ engine](/home/deployment/on-prem-mcp)
+
+
+
+
+#### Set environment variables
+
+Set the following environment variables:
+
+```bash
+export MAILCHIMP_CLIENT_ID=""
+export MAILCHIMP_CLIENT_SECRET=""
+```
+
+Or, you can set these values in a `.env` file:
+
+```bash
+MAILCHIMP_CLIENT_ID=""
+MAILCHIMP_CLIENT_SECRET=""
+```
+
+#### Edit the Engine configuration
+
+Edit the `engine.yaml` file and add a new item to the `auth.providers` section:
+
+```yaml
+auth:
+ providers:
+ - id: arcade-mailchimp
+ description: Mailchimp OAuth 2.0 provider
+ enabled: true
+ type: oauth2
+ client_id: ${env:MAILCHIMP_CLIENT_ID}
+ client_secret: ${env:MAILCHIMP_CLIENT_SECRET}
+ oauth2:
+ authorize_request:
+ endpoint: "https://login.mailchimp.com/oauth2/authorize"
+ params:
+ response_type: code
+ client_id: "{{client_id}}"
+ redirect_uri: "{{redirect_uri}}"
+ state: "{{state}}"
+ token_request:
+ endpoint: "https://login.mailchimp.com/oauth2/token"
+ params:
+ grant_type: authorization_code
+ client_id: "{{client_id}}"
+ client_secret: "{{client_secret}}"
+ redirect_uri: "{{redirect_uri}}"
+ response_content_type: application/json
+```
+
+
+
+
+
+
+When you use tools that require Mailchimp auth using your Arcade account credentials, Arcade will automatically use this Mailchimp OAuth provider. If you have multiple Mailchimp providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+## Using Mailchimp auth in app code
+
+Use the Mailchimp auth provider in your own agents and AI apps to get a user token for the Mailchimp API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Mailchimp API:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="arcade-mailchimp"
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-11}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade();
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+const authResponse = await client.auth.start(userId, "arcade-mailchimp");
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+### Getting the API endpoint
+
+Mailchimp requires you to determine the correct API endpoint for each user. After obtaining the access token, make a request to the metadata endpoint:
+
+
+
+
+```python
+import httpx
+
+# Get the user's API endpoint
+async with httpx.AsyncClient() as client:
+ metadata_response = await client.get(
+ "https://login.mailchimp.com/oauth2/metadata",
+ headers={"Authorization": f"Bearer {token}"}
+ )
+ metadata = metadata_response.json()
+ api_endpoint = metadata["api_endpoint"]
+
+# Now use the api_endpoint for all API calls
+# Example: f"{api_endpoint}/3.0/lists"
+```
+
+
+
+
+
+```javascript
+// Get the user's API endpoint
+const metadataResponse = await fetch(
+ "https://login.mailchimp.com/oauth2/metadata",
+ {
+ headers: { Authorization: `Bearer ${token}` }
+ }
+);
+const metadata = await metadataResponse.json();
+const apiEndpoint = metadata.api_endpoint;
+
+// Now use the apiEndpoint for all API calls
+// Example: `${apiEndpoint}/3.0/lists`
+```
+
+
+
+
+
+## Using Mailchimp auth in custom tools
+
+You can use the pre-built [Arcade Mailchimp Marketing MCP Server](/mcp-servers/productivity/mailchimp-marketing-api) to quickly build agents and AI apps that interact with Mailchimp.
+
+If the pre-built tools in the Mailchimp MCP Server don't meet your needs, you can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Mailchimp API.
+
+Use the `OAuth2()` auth class to specify that a tool requires authorization with Mailchimp. The `context.authorization.token` field will be automatically populated with the user's Mailchimp token:
+
+```python {8-12,24}
+from typing import Annotated
+
+import httpx
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import OAuth2
+
+
+@tool(
+ requires_auth=OAuth2(provider_id="arcade-mailchimp")
+)
+async def get_mailchimp_lists(
+ context: ToolContext,
+) -> Annotated[dict, "The user's Mailchimp lists."]:
+ """
+ Retrieve all mailing lists from the authenticated user's Mailchimp account.
+ """
+ # First, get the API endpoint for this user
+ async with httpx.AsyncClient() as client:
+ metadata_response = await client.get(
+ "https://login.mailchimp.com/oauth2/metadata",
+ headers={"Authorization": f"Bearer {context.authorization.token}"}
+ )
+ api_endpoint = metadata_response.json()["api_endpoint"]
+
+ # Now get the lists
+ response = await client.get(
+ f"{api_endpoint}/3.0/lists",
+ headers={"Authorization": f"Bearer {context.authorization.token}"}
+ )
+ response.raise_for_status()
+ return dict(response.json())
+```
+
+
+ **Important**: Mailchimp access tokens do not expire unless the user revokes access. However, it's good practice to handle potential errors gracefully and provide users with options to re-authenticate if necessary.
+
+
+For more details about Mailchimp's authentication, refer to the [Mailchimp OAuth 2.0 documentation](https://mailchimp.com/developer/marketing/guides/access-user-data-oauth-2/).
+
diff --git a/app/en/home/sharing-with-end-users/custom-auth/microsoft/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/microsoft/page.mdx
new file mode 100644
index 000000000..baf44bdb4
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/microsoft/page.mdx
@@ -0,0 +1,197 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Microsoft
+
+
+ At this time, Arcade does not offer a default Microsoft Auth Provider. To use
+ Microsoft auth, you must create a custom Auth Provider with your own Microsoft
+ OAuth 2.0 credentials as described below.
+
+
+The Microsoft auth provider enables tools and agents to call the Microsoft Graph API on behalf of a user.
+
+### What's documented here
+
+This page describes how to use and configure Microsoft auth with Arcade.
+
+This auth provider is used by:
+
+- Your [app code](#using-microsoft-auth-in-app-code) that needs to call Microsoft Graph APIs
+- Or, your [custom tools](#using-microsoft-auth-in-custom-tools) that need to call Microsoft Graph APIs
+
+## Configuring Microsoft auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Microsoft app credentials. This way, your users will see your application's name requesting permission.
+
+
+Before showing how to configure your Microsoft app credentials, let's go through the steps to create a Microsoft app.
+
+### Create a Microsoft app
+
+- Follow Microsoft's guide to [registering an app with the Microsoft identity platform](https://learn.microsoft.com/en-us/entra/identity-platform/quickstart-register-app)
+- Choose the permissions (scopes) you need for your app. Refer to the [section below](#arcade-microsoft-MCP Servers-scopes) for a list of scopes needed by the Arcade Microsoft MCP Servers, in case you intend to use them.
+- Set the redirect URL to the redirect URL generated by Arcade (see below)
+- Copy the client ID and client secret to use below
+
+Next, add the Microsoft app to Arcade.
+### Arcade Microsoft MCP Servers Scopes
+
+Below is the list of scopes required by the Arcade Microsoft MCP Servers:
+
+| MCP Server | Required Permissions |
+| -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| [Outlook Calendar](/mcp-servers/productivity/outlook-calendar) | `Calendars.ReadBasic` `Calendars.ReadWrite` `MailboxSettings.Read` |
+| [Outlook Mail](/mcp-servers/productivity/outlook-mail) | `Mail.Read` `Mail.ReadWrite` `Mail.Send` |
+| [Teams](/mcp-servers/social-communication/microsoft-teams) | `Channel.ReadBasic.All` `ChannelMessage.Read.All` `ChannelMessage.Send` `Chat.Create` `Chat.Read` `ChatMessage.Read` `ChatMessage.Send` `People.Read` `Team.ReadBasic.All` `TeamMember.Read.All` `User.Read` |
+| [SharePoint](/mcp-servers/productivity/sharepoint) | `Sites.Read.All` |
+
+## Configuring your own Microsoft Auth Provider in Arcade
+
+
+
+
+
+
+### Configure Microsoft Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Included Providers** tab at the top.
+- In the **Provider** dropdown, select **Microsoft**.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "my-microsoft-provider").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Microsoft app.
+- Note the **Redirect URL** generated by Arcade. This must be set as your Microsoft app's redirect URL.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+When you use tools that require Microsoft auth using your Arcade account credentials, Arcade will automatically use this Microsoft OAuth provider. If you have multiple Microsoft providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+
+
+
+## Using Microsoft auth in app code
+
+Use the Microsoft auth provider in your own agents and AI apps to get a user token for Microsoft Graph APIs. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for Microsoft Graph APIs:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="microsoft",
+ scopes=["User.Read", "Files.Read"],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# TODO: Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-10}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade();
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+let authResponse = await client.auth.start(userId, "microsoft", {
+ scopes: ["User.Read", "Files.Read"],
+});
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// TODO: Do something interesting with the token...
+```
+
+
+
+
+
+## Using Microsoft auth in custom tools
+
+You can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with Microsoft Graph APIs.
+
+Use the `Microsoft()` auth class to specify that a tool requires authorization with Microsoft. The `context.authorization.token` field will be automatically populated with the user's Microsoft token:
+
+```python {5-6,9-13,20}
+from typing import Annotated
+
+import httpx
+
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import Microsoft
+
+
+@tool(
+ requires_auth=Microsoft(
+ scopes=["User.Read", "Files.Read"],
+ )
+)
+async def get_file_contents(
+ context: ToolContext,
+ file_id: Annotated[str, "The ID of the file to get the contents of"],
+) -> Annotated[str, "The contents of the file"]:
+ """Get the contents of a file from Microsoft Graph."""
+ url = f"https://graph.microsoft.com/v1.0/me/drive/items/{file_id}"
+ headers = {"Authorization": f"Bearer {context.authorization.token}"}
+
+ async with httpx.AsyncClient() as client:
+ response = await client.get(
+ url=url,
+ headers=headers,
+ )
+ response.raise_for_status()
+ return response.json()
+```
diff --git a/app/en/home/sharing-with-end-users/custom-auth/miro/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/miro/page.mdx
new file mode 100644
index 000000000..912241f10
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/miro/page.mdx
@@ -0,0 +1,298 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Miro
+
+The Miro auth provider enables tools and agents to call [Miro APIs](https://developers.miro.com/reference/api-reference) on behalf of a user using OAuth 2.0 authentication.
+
+
+ Want to quickly get started with Miro in your agent or AI app? The pre-built
+ [Arcade Miro MCP Server](/mcp-servers/productivity/miro-api) is what you
+ want!
+
+
+### What's documented here
+
+This page describes how to use and configure Miro auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade Miro MCP Server](/mcp-servers/productivity/miro-api), which provides pre-built tools for interacting with Miro
+- Your [app code](#using-miro-auth-in-app-code) that needs to call the Miro API
+- Or, your [custom tools](#using-miro-auth-in-custom-tools) that need to call the Miro API
+
+## Configuring Miro auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Miro app credentials. This way, your users will see your application's name requesting permission.
+
+Before showing how to configure your Miro app credentials, let's go through the steps to create a Miro app.
+
+### Create a Miro app
+
+To integrate with Miro's API, you'll need to create an app in the Miro Developer Platform:
+
+
+
+#### Access the Miro Developer Platform
+
+Navigate to the [Miro Developer Platform](https://developers.miro.com/) and sign in with your Miro account or create a new one.
+
+#### Create a new app
+
+1. Go to [Your Apps](https://miro.com/app/settings/user-profile/apps) in your Miro profile settings
+2. Click on "Create new app"
+3. Fill in the required details:
+ - **App Name**: Choose a descriptive name for your application
+ - **Description**: Provide a brief description of your app
+
+#### Configure OAuth settings
+
+1. After creating your app, navigate to the **OAuth & Permissions** section
+2. Set the **Redirect URI** to the redirect URL generated by Arcade (see configuration section below)
+3. Configure the required **Scopes** for your application:
+ - `boards:read` - Read board information
+ - `boards:write` - Create and modify boards
+ - Add other scopes as needed for your use case
+
+#### Obtain your credentials
+
+1. In your app's settings, you'll find your **Client ID** and **Client Secret**
+2. Copy both values for use in Arcade configuration
+
+
+
+For detailed instructions, refer to Miro's [OAuth documentation](https://developers.miro.com/docs/getting-started-with-oauth).
+
+Next, add the Miro app to Arcade.
+
+## Configuring your own Miro Auth Provider in Arcade
+
+
+
+
+### Configure Miro Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **OAuth 2.0** tab at the top.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "arcade-miro").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Miro app.
+- Configure the OAuth 2.0 endpoints:
+ - **Authorization URL**: `https://miro.com/oauth/authorize`
+ - **Token URL**: `https://api.miro.com/v1/oauth/token`
+- Note the **Redirect URL** generated by Arcade. This must be set as your Miro app's Redirect URI.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+
+
+
+
+### Configure Miro Auth Using Configuration File
+
+
+ This method is only available when you are [self-hosting the
+ engine](/home/deployment/on-prem-mcp)
+
+
+
+
+#### Set environment variables
+
+Set the following environment variables:
+
+```bash
+export MIRO_CLIENT_ID=""
+export MIRO_CLIENT_SECRET=""
+```
+
+Or, you can set these values in a `.env` file:
+
+```bash
+MIRO_CLIENT_ID=""
+MIRO_CLIENT_SECRET=""
+```
+
+#### Edit the Engine configuration
+
+Edit the `engine.yaml` file and add a new item to the `auth.providers` section:
+
+```yaml
+auth:
+ providers:
+ - id: arcade-miro
+ description: Miro OAuth 2.0 provider
+ enabled: true
+ type: oauth2
+ client_id: ${env:MIRO_CLIENT_ID}
+ client_secret: ${env:MIRO_CLIENT_SECRET}
+ oauth2:
+ scope_delimiter: " "
+ authorize_request:
+ endpoint: "https://miro.com/oauth/authorize"
+ params:
+ response_type: code
+ client_id: "{{client_id}}"
+ redirect_uri: "{{redirect_uri}}"
+ scope: "{{scopes}}"
+ state: "{{state}}"
+ token_request:
+ endpoint: "https://api.miro.com/v1/oauth/token"
+ params:
+ grant_type: authorization_code
+ client_id: "{{client_id}}"
+ client_secret: "{{client_secret}}"
+ redirect_uri: "{{redirect_uri}}"
+ response_content_type: application/json
+```
+
+
+
+
+
+
+When you use tools that require Miro auth using your Arcade account credentials, Arcade will automatically use this Miro OAuth provider. If you have multiple Miro providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+## Using Miro auth in app code
+
+Use the Miro auth provider in your own agents and AI apps to get a user token for the Miro API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Miro API:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="arcade-miro",
+ scopes=["boards:read", "boards:write"]
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-11}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade();
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+const authResponse = await client.auth.start(
+ userId,
+ "arcade-miro",
+ ["boards:read", "boards:write"]
+);
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using Miro auth in custom tools
+
+You can use the pre-built [Arcade Miro MCP Server](/mcp-servers/productivity/miro-api) to quickly build agents and AI apps that interact with Miro.
+
+If the pre-built tools in the Miro MCP Server don't meet your needs, you can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Miro API.
+
+Use the `OAuth2()` auth class to specify that a tool requires authorization with Miro. The `context.authorization.token` field will be automatically populated with the user's Miro token:
+
+```python {8-12,22}
+from typing import Annotated
+
+import httpx
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import OAuth2
+
+
+@tool(
+ requires_auth=OAuth2(
+ provider_id="arcade-miro",
+ scopes=["boards:read"]
+ )
+)
+async def get_user_boards(
+ context: ToolContext,
+) -> Annotated[dict, "The user's boards."]:
+ """
+ Retrieve the list of boards for the authenticated user.
+ """
+ url = "https://api.miro.com/v2/boards"
+ headers = {
+ "Authorization": context.authorization.token,
+ }
+
+ async with httpx.AsyncClient() as client:
+ response = await client.get(url, headers=headers)
+ response.raise_for_status()
+ return dict(response.json())
+```
+
+## Available Scopes
+
+Miro supports various OAuth scopes that determine the level of access your application has:
+
+- `boards:read` - Read board information
+- `boards:write` - Create and modify boards
+- `team:read` - Read team information
+- `team:write` - Manage team settings
+- `organizations:read` - Read organization information
+- `organizations:teams:read` - Read organization teams
+
+For a complete list of available scopes, refer to the [Miro Scopes documentation](https://developers.miro.com/docs/scopes).
+
diff --git a/app/en/home/sharing-with-end-users/custom-auth/notion/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/notion/page.mdx
new file mode 100644
index 000000000..c188bae78
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/notion/page.mdx
@@ -0,0 +1,178 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Notion
+
+The Notion auth provider enables tools and agents to call [Notion APIs](https://developers.notion.com/reference/intro) on behalf of a user.
+
+### What's documented here
+
+This page describes how to use and configure Notion auth with Arcade.
+
+This auth provider is used by:
+
+- Your [app code](#using-notion-auth-in-app-code) that needs to call the Notion API
+- Or, your [custom tools](#using-notion-auth-in-custom-tools) that need to call the Notion API
+
+## Configuring Notion auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Notion app credentials. This way, your users will see your application's name requesting permission.
+
+
+Before showing how to configure your Notion app credentials, let's go through the steps to create a Notion app.
+
+### Create a Notion app
+
+- Create a new public integration in your [integration's settings page](https://www.notion.so/profile/integrations)
+- Set the redirect URI to the redirect URL generated by Arcade (see below)
+- Once you complete creating your integration, copy the client ID and client secret to use below
+
+Next, add the Notion app to Arcade.
+
+## Configuring your own Notion Auth Provider in Arcade
+
+
+
+
+
+
+### Configure Notion Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Included Providers** tab at the top.
+- In the **Provider** dropdown, select **Notion**.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "my-notion-provider").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Notion app.
+- Note the **Redirect URL** generated by Arcade. This must be set as your Notion app's redirect URI.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+When you use tools that require Notion auth using your Arcade account credentials, Arcade will automatically use this Notion OAuth provider. If you have multiple Notion providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+
+
+
+## Using Notion auth in app code
+
+Use the Notion auth provider in your own agents and AI apps to get a user token for the Notion API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Notion API:
+
+
+
+
+```python {8-11}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="notion"
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade();
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+const authResponse = await client.auth.start(userId, "notion");
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using Notion auth in custom tools
+
+You can use the pre-built [Arcade Notion MCP Server](/mcp-servers/productivity/notion) to quickly build agents and AI apps that interact with Notion.
+
+If the pre-built tools in the Notion MCP Server don't meet your needs, you can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Notion API.
+
+Use the `Notion()` auth class to specify that a tool requires authorization with Notion. The `context.authorization.token` field will be automatically populated with the user's Notion token:
+
+```python {8,18}
+from typing import Annotated
+
+import httpx
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import Notion
+
+
+@tool(requires_auth=Notion())
+async def search_page_by_title(
+ context: ToolContext,
+ title_includes: Annotated[str, "The text to compare against page and database titles."],
+) -> Annotated[dict, "The matching pages."]:
+ """
+ Search for a Notion page by its title.
+ """
+ url = "https://api.notion.com/v1/search"
+ headers = {
+ "Authorization": context.authorization.token,
+ "Content-Type": "application/json",
+ "Notion-Version": "2022-06-28",
+ }
+ payload = {"query": title_includes, "filter": {"property": "object", "value": "page"}}
+
+ async with httpx.AsyncClient() as client:
+ response = await client.post(url, headers=headers, json=payload)
+ response.raise_for_status()
+ return dict(response.json())
+```
diff --git a/app/en/home/sharing-with-end-users/custom-auth/oauth2/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/oauth2/page.mdx
new file mode 100644
index 000000000..af5559c6b
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/oauth2/page.mdx
@@ -0,0 +1,619 @@
+---
+title: OAuth 2.0
+description: Authorize tools and agents with any OAuth 2.0-compatible provider
+---
+
+import { Tabs, Callout, Steps } from "nextra/components";
+import ToggleContent from "@/app/_components/toggle-content";
+
+# OAuth 2.0
+
+The OAuth 2.0 auth provider enables tools and agents to authorize with any OAuth 2.0-compatible API on behalf of a user.
+
+
+ Arcade has [pre-built auth providers](/home/auth-providers) for many popular
+ OAuth 2.0 services. Use this OAuth 2.0 provider to connect to other systems
+ that aren't pre-built.
+
+
+### What's documented here
+
+This page describes how to configure OAuth 2.0 with Arcade, and use it in:
+
+- Your [app code](#using-oauth-20-in-app-code) that needs to call APIs protected by OAuth 2.0
+- Or, your [custom tools](#using-oauth-20-in-custom-tools) that need to call APIs protected by OAuth 2.0
+
+### Supported OAuth 2.0 flows
+
+The only supported OAuth 2.0 flow is the authorization code grant flow (with or without PKCE).
+
+## Configuring OAuth 2.0
+
+How you configure the OAuth 2.0 provider depends on whether you use the Arcade Cloud Engine or a [self-hosted Engine](/home/deployment/on-prem-mcp). If you use the Cloud Engine, you must configure your provider in the Dashboard.
+
+
+ When configuring your app in the OAuth 2.0 enabled service, you must use the
+ redirect URL generated by Arcade (see below) as the redirect URL (sometimes
+ called the redirect URI or callback URL).
+
+
+### Using the Arcade Dashboard
+
+
+ When using the Arcade Cloud Platform, the Dashboard is available at
+ [`https://api.arcade.dev/dashboard`](https://api.arcade.dev/dashboard). If you
+ are [self-hosting Arcade](/home/deployment/on-prem-mcp), by default
+ the Dashboard is available at
+ [`http://localhost:9099/dashboard`](http://localhost:9099/dashboard). Adjust
+ the host and port, if necessary, to match your environment.
+
+
+1. Navigate to the OAuth section of the Arcade Dashboard and click **Add OAuth Provider**.
+2. Select **OAuth 2.0** as the provider.
+3. Choose a unique **ID** for your provider (e.g. "my-oauth2-provider") with an optional **Description**.
+4. Enter your **Client ID** and **Client Secret** from your OAuth 2.0 provider.
+5. Note the **Redirect URL** generated by Arcade. This must be set as the redirect URL in the external service's configuration.
+6. Click **Save**.
+
+When you use tools that require OAuth 2.0 authorization using your Arcade account credentials, Arcade will automatically use this OAuth 2.0 provider.
+
+### Using the `engine.yaml` configuration file
+
+
+ This method is only available when you are [self-hosting the
+ engine](/home/deployment/on-prem-mcp)
+
+
+
+
+### Set environment variables
+
+Set the following environment variables. Replace `HOOLI` with the name of the OAuth 2.0 provider you are configuring:
+
+```bash
+export HOOLI_CLIENT_ID=""
+export HOOLI_CLIENT_SECRET=""
+```
+
+Or, you can set these values in a `.env` file:
+
+```bash
+HOOLI_CLIENT_ID=""
+HOOLI_CLIENT_SECRET=""
+```
+
+
+ See [configuration](/home/deployment/engine-configuration) for more
+ information on how to set environment variables and configure the Arcade
+ Engine.
+
+
+### Edit the Engine configuration
+
+
+ To locate the `engine.yaml` file in your OS after installing the Arcade
+ Engine, check the [Engine configuration
+ file](/home/deployment/engine-configuration)
+ documentation.
+
+
+Edit the `engine.yaml` file and add a new item to the `auth.providers` section:
+
+```yaml
+auth:
+ providers:
+ - id: default-github
+ description: The default GitHub provider
+ enabled: true
+ type: oauth2
+ provider_id: github
+ client_id: ${env:GITHUB_CLIENT_ID}
+ client_secret: ${env:GITHUB_CLIENT_SECRET}
+
+ - id: hooli
+ description: Hooli OAuth 2.0 provider
+ enabled: true
+ type: oauth2
+ client_id: ${env:HOOLI_CLIENT_ID}
+ client_secret: ${env:HOOLI_CLIENT_SECRET}
+ oauth2:
+ # For a custom OAuth 2.0 provider, specify the full OAuth configuration:
+```
+
+The ID of the provider (`hooli` in this example) can be any string. It's used to reference the provider in your app code and must be unique.
+
+Each service expects a slightly different set of values in the `oauth2` section. Refer to the configuration reference below, and to your service's documentation to understand what values are required.
+
+
+ If you need help configuring a specific provider, [get in touch with
+ us](mailto:contact@arcade.dev)!
+
+
+
+
+### Configuration reference
+
+For a full example, see the [full configuration example](#full-configuration-example) below.
+
+`scope_delimiter` _(optional, defaults to the space character)_: The delimiter to use between scopes.
+
+`pkce` _(optional)_:
+
+- `enabled` _(optional, default `false`)_: If `true`, PKCE will be used.
+- `code_challenge_method` _(optional, default `S256`)_: The code challenge method to use. The only supported method is `S256`. This parameter is ignored if PKCE is not enabled.
+
+#### `authorize_request`
+
+This section configures the initial authorization request.
+
+- `endpoint`: The authorization endpoint for your OAuth 2.0 server, e.g. `/oauth2/authorize`
+- `params`: A map of parameter keys and values to include in the authorization request.
+
+These placeholders are available in `params`:
+
+- `{{client_id}}`: The configured client ID.
+- `{{redirect_uri}}`: The redirect URI managed by Arcade.
+- `{{scopes}}`: The scopes to request, if any
+- `{{existing_scopes}}`: The scopes that the user has already granted, if any.
+
+
+ The `state` parameter is automatically added to the request, and does not need
+ to be included in `params`. If PKCE is enabled, `code_challenge` and
+ `code_challenge_method` are also added automatically.
+
+
+For most providers, `oauth2.authorize_request` will look like:
+
+```yaml
+authorize_request:
+ endpoint: "https://example.com/oauth2/authorize"
+ params:
+ response_type: code
+ client_id: "{{client_id}}"
+ redirect_uri: "{{redirect_uri}}"
+ scope: "{{scopes}} {{existing_scopes}}"
+```
+
+Some providers support additional parameters in the authorization request. These can be added to `params` as well. For example:
+
+```yaml
+authorize_request:
+ endpoint: "https://example.com/oauth2/authorize"
+ params:
+ response_type: code
+ client_id: "{{client_id}}"
+ redirect_uri: "{{redirect_uri}}"
+ scope: "{{scopes}} {{existing_scopes}}"
+ prompt: consent
+ access_type: offline
+```
+
+#### `token_request`
+
+This section configures the code/token exchange request, after the user has approved access to your app.
+
+- `endpoint`: The token endpoint for your OAuth 2.0 server, e.g. `/oauth2/token`
+- `auth_method` _(optional, default none)_: The authentication method to use. Supported values are none (omitted) and `client_secret_basic`.
+- `params`: A map of parameter keys and values to include in the token request.
+
+These placeholders are available in `params`:
+
+- `{{client_id}}`: The configured client ID.
+- `{{client_secret}}`: The configured client secret.
+- `{{redirect_uri}}`: The redirect URI managed by Arcade.
+
+
+ The `code` parameter is automatically added to the request, and does not need
+ to be included in `params`. If PKCE is enabled, the `code_verifier` parameter
+ is also added to the request automatically.
+
+
+For most providers, `oauth2.token_request.params` will look like:
+
+```yaml
+token_request:
+ endpoint: "https://example.com/oauth2/token"
+ params:
+ grant_type: authorization_code
+ redirect_uri: "{{redirect_uri}}"
+ client_id: "{{client_id}}"
+ client_secret: "{{client_secret}}" # Omit if using PKCE
+```
+
+- `response_content_type` _(optional, default `application/json`)_: The expected content type of the response. Supported values are `application/json` and `application/x-www-form-urlencoded`.
+- `response_map` _(optional)_: A map of keys and values to extract from the response. Supported keys are `access_token`, `expires_in`, `refresh_token`, `scope`, and `token_type`. Supports simple JSONPath expressions. Only applicable if `response_content_type` is `application/json`. See the [JSONPath reference](#jsonpath-expressions-in-response_map) for details on extracting values using JSONPath.
+
+#### `refresh_request`
+
+This section configures the refresh token request, if your OAuth 2.0 server supports refresh tokens. If not provided, refresh tokens will not be used.
+
+- `endpoint`: The refresh token endpoint for your OAuth 2.0 server, e.g. `/oauth2/token`
+- `auth_method` _(optional, default none)_: The authentication method to use. Supported values are none (omitted), `client_secret_basic`, and `bearer_access_token`.
+- `params`: A map of parameter keys and values to include in the refresh token request.
+
+These placeholders are available in `params`:
+
+- `{{refresh_token}}`: The refresh token to use.
+- `{{client_id}}`: The configured client ID.
+- `{{client_secret}}`: The configured client secret.
+
+For most providers, `oauth2.refresh_request.params` will look like:
+
+```yaml
+refresh_request:
+ endpoint: "https://example.com/oauth2/token"
+ params:
+ grant_type: refresh_token
+ client_id: "{{client_id}}"
+ client_secret: "{{client_secret}}"
+```
+
+- `response_content_type` _(optional, default `application/json`)_: The expected content type of the response. Supported values are `application/json` and `application/x-www-form-urlencoded`.
+- `response_map` _(optional)_: A map of keys and values to extract from the response. Supported keys are `access_token`, `expires_in`, `refresh_token`, `scope`, and `token_type`. Supports simple JSONPath expressions. Only applicable if `response_content_type` is `application/json`. See the [JSONPath reference](#jsonpath-expressions-in-response_map) for details on extracting values using JSONPath.
+
+#### `user_info_request`
+
+Some OAuth 2.0 APIs provide a user info endpoint that returns information about the user. Arcade Engine can automatically request user info from servers that support it. If the `user_info_request` section is omitted, user info will not be requested.
+
+- `endpoint`: The user info endpoint for your OAuth 2.0 server, e.g. `/oauth2/userinfo`
+- `auth_method` _(optional, default `bearer_access_token`)_: The authentication method to use. The only supported value is `bearer_access_token`.
+- `response_content_type` _(optional, default `application/json`)_: The expected content type of the response. The only supported value is `application/json`.
+- `response_map` _(optional)_: A map of keys and values to extract from the response. If no `response_map` is provided, the entire response will be extracted verbatim. Supports simple JSONPath expressions. Only applicable if `response_content_type` is `application/json`. See the [JSONPath reference](#jsonpath-expressions-in-response_map) for details on extracting values using JSONPath.
+- `triggers`: Controls when the user info request is made.
+ - `on_token_grant`: If `true`, the user info request will be made when a token is granted. This is typically only once for each user, unless new scopes are granted.
+ - `on_token_refresh`: If `true`, the user info request will be made every time a token is refreshed.
+
+#### `token_introspection_request`
+
+Some OAuth 2.0 APIs provide a token introspection endpoint that can be used to check the validity of a token and retrieve additional information such as token expiration time.
+
+An example of a token introspection request configuration:
+
+```yaml
+auth:
+ providers:
+ - id: custom-provider
+ description: "Custom provider"
+ enabled: true
+ type: oauth2
+ client_id: ${env:CUSTOM_CLIENT_ID}
+ client_secret: ${env:CUSTOM_CLIENT_SECRET}
+ oauth2:
+ token_introspection_request:
+ enabled: true
+ endpoint: "https://example.oauth.com/services/oauth2/introspect"
+ method: POST
+ params:
+ token: "{{access_token}}"
+ auth_method: "client_secret_basic"
+ request_content_type: application/x-www-form-urlencoded
+ response_content_type: application/json
+ response_map:
+ expires_in: "$.exp"
+ scope: "$.scope"
+ expiration_format: absolute_unix_timestamp
+ triggers:
+ on_token_grant: true
+ on_token_refresh: true
+```
+
+- `enabled` _(optional, default `false`)_: If `true`, the token introspection request will be made.
+- `endpoint` _(required)_: The endpoint to use for the token introspection request.
+- `method` _(optional, default `GET`)_: The HTTP method to use for the token introspection request.
+- `params` _(optional)_: A map of parameter keys and values to include in the token introspection request. Currently, only mapping a field to the internal `access_token` field is supported.
+- `auth_method` _(optional, default `client_secret_basic`)_: The authentication method to use for the token introspection request. Supported values are `client_secret_basic` and `bearer_access_token`.
+- `request_content_type` _(optional, default `application/x-www-form-urlencoded`)_: The content type of the request body.
+- `response_content_type` _(optional, default `application/json`)_: The content type of the response body.
+- `response_map` _(required)_: A map of keys and values to extract from the response. Supported keys are `expires_in` and `scope`. Supports simple JSONPath expressions.
+- `expiration_format` _(optional, default `absolute_unix_timestamp`)_: The format of the expiration time. Supported values are `absolute_unix_timestamp` and `relative_seconds`.
+- `triggers` _(required)_: Controls when the token introspection request is made.
+ - `on_token_grant`: If `true`, the token introspection request will be made when a token is granted. This is typically only once for each user, unless new scopes are granted.
+ - `on_token_refresh`: If `true`, the token introspection request will be made every time a token is refreshed.
+
+#### JSONPath expressions in `response_map`
+
+In the `token_request`, `refresh_request`, `token_introspection_request`, and `user_info_request` sections, you can specify a `response_map`. Configuring a response map is useful if your OAuth 2.0 server returns a JSON object with nested properties, or properties with non-standard names.
+
+For example, for the token request, most OAuth 2.0 servers return a JSON payload that looks like this:
+
+```json
+{
+ "access_token": "...",
+ "refresh_token": "...",
+ "expires_in": 3600,
+ "scope": "scope1 scope2"
+}
+```
+
+If your server returns a payload of this shape, you don't need `response_map`!
+
+But if your server returns:
+
+```json
+{
+ "data": {
+ "access_token": "...",
+ "expires_in": 3600,
+ "refresh_token": "...",
+ "scope": "scope1 scope2"
+ }
+}
+```
+
+Then you need to configure `response_map` to extract the nested properties from inside the `data` object. Use [JSONPath](https://en.wikipedia.org/wiki/JSONPath) expressions to select the properties you need:
+
+```yaml
+token_request:
+ response_map:
+ access_token: "$.data.access_token"
+ expires_in: "$.data.expires_in"
+ refresh_token: "$.data.refresh_token" # Only needed if refresh tokens are used
+ scope: "$.data.scope" # Only needed if scopes are used
+```
+
+Similarly, for user info or token introspection requests, you can use `response_map` to extract custom properties from the response.
+
+#### Handling scope arrays
+
+Most OAuth 2.0 servers return scopes as a delimited string, such as `scope1 scope2` or `scope1,scope2`. If your server follows this convention, configuring the top-level `scope_delimiter` property in the `oauth2` section is all you need to do.
+
+Some OAuth 2.0 servers return an array of scopes instead of a delimited string. For example:
+
+```json
+{
+ "access_token": "...",
+ "expires_in": 3600,
+ "scope": ["scope1", "scope2"]
+}
+```
+
+In this case, you need to use the `join()` function in `response_map` to join the scopes into a delimited string:
+
+```yaml
+token_request:
+ response_map:
+ access_token: "$.access_token"
+ expires_in: "$.expires_in"
+ scope: "join('$.scope', ' ')"
+```
+
+`join()` takes two arguments:
+
+- `path`: The JSONPath expression to select the array to join.
+- `delimiter`: The delimiter to use between array elements. Make sure this matches the `scope_delimiter` setting in the `oauth2` section.
+
+#### Extracting values from JWTs
+
+Some OAuth 2.0 servers return JWT tokens that contain claims you might need to extract. For example, the token might contain scopes or other information about the user. You can use the `jwt_decode()` function in `response_map` to extract values from JWT tokens:
+
+```yaml
+token_request:
+ response_map:
+ access_token: "$.access_token"
+ expires_in: "$.expires_in"
+ scope: "jwt_decode('$.access_token', '$.scope')"
+```
+
+`jwt_decode()` takes two arguments:
+
+- `token_path`: The JSONPath expression to select the JWT token.
+- `claim_path`: The JSONPath expression to select the claim within the decoded JWT payload.
+
+If the claim is an array (like scopes often are), you can combine `jwt_decode()` with `join()` to extract and format the values:
+
+```yaml
+token_request:
+ response_map:
+ access_token: "$.access_token"
+ expires_in: "$.expires_in"
+ scope: "join(jwt_decode('$.access_token', '$.scp'), ' ')"
+```
+
+This is particularly useful when the JWT token contains scopes in an array format (like `scp: ["scope1", "scope2"]`) and you need to convert them to a space-delimited string.
+
+You can also extract nested claims from the JWT payload using dot notation in the claim path:
+
+```yaml
+token_request:
+ response_map:
+ access_token: "$.access_token"
+ expires_in: "$.expires_in"
+ scope: "jwt_decode('$.access_token', '$.nested.scopes')"
+```
+
+#### Full configuration example
+
+Here's a full example of the YAML configuration for a custom OAuth 2.0 provider:
+
+
+
+```yaml
+auth:
+ providers:
+ - id: default-github
+ description: The default GitHub provider
+ enabled: true
+ type: oauth2
+ provider_id: github
+ client_id: ${env:GITHUB_CLIENT_ID}
+ client_secret: ${env:GITHUB_CLIENT_SECRET}
+
+ - id: hooli
+ description: Hooli OAuth 2.0 provider
+ enabled: true
+ type: oauth2
+ client_id: ${env:HOOLI_CLIENT_ID}
+ client_secret: ${env:HOOLI_CLIENT_SECRET}
+ oauth2:
+ # For a custom OAuth 2.0 provider, specify the full OAuth configuration:
+ scope_delimiter: " "
+ pkce: # Optional
+ enabled: true
+ code_challenge_method: S256
+ authorize_request:
+ endpoint: "https://example.com/oauth/authorize"
+ params:
+ response_type: code
+ client_id: "{{client_id}}"
+ redirect_uri: "{{redirect_uri}}"
+ scope: "{{scopes}} {{existing_scopes}}"
+ token_request:
+ endpoint: "https://example.com/oauth/token"
+ auth_method: client_secret_basic # Optional
+ params:
+ grant_type: authorization_code
+ client_id: "{{client_id}}"
+ client_secret: "{{client_secret}}"
+ redirect_uri: "{{redirect_uri}}"
+ response_content_type: application/json # Optional
+ response_map: # Optional
+ access_token: "$.access_token"
+ refresh_token: "$.refresh_token"
+ expires_in: "$.expires_in"
+ scope: "$.scope"
+ token_type: "$.token_type"
+ refresh_request: # Optional
+ endpoint: "https://example.com/oauth/token"
+ auth_method: client_secret_basic # Optional
+ params:
+ grant_type: refresh_token
+ client_id: "{{client_id}}"
+ client_secret: "{{client_secret}}"
+ refresh_token: "{{refresh_token}}"
+ response_content_type: application/json # Optional
+ response_map: # Optional
+ access_token: "$.access_token"
+ refresh_token: "$.refresh_token"
+ expires_in: "$.expires_in"
+ scope: "$.scope"
+ token_type: "$.token_type"
+ token_introspection_request: # Optional
+ endpoint: "https://example.com/oauth/introspect"
+ method: POST
+ params:
+ token: "{{access_token}}"
+ auth_method: client_secret_basic # Optional
+ request_content_type: application/x-www-form-urlencoded # Optional
+ response_content_type: application/json # Optional
+ response_map: # Optional
+ expires_in: "$.data.expires_in"
+ scope: "$.data.scope"
+ expiration_format: relative_seconds # or absolute_unix_timestamp
+ triggers:
+ on_token_grant: true
+ on_token_refresh: true
+ user_info_request: # Optional
+ endpoint: "https://example.com/oauth/userinfo"
+ auth_method: bearer_access_token
+ response_content_type: application/json
+ response_map:
+ custom_property: "$.data.custom_property"
+ triggers:
+ on_token_grant: true
+ on_token_refresh: true
+```
+
+
+
+## Using OAuth 2.0 in app code
+
+Use the OAuth 2.0 auth provider in your own agents and AI apps to get a user token for any OAuth 2.0-compatible APIs. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get an access token:
+
+
+
+
+```python {9-13}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="hooli",
+ scopes=["scope1", "scope2"],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# TODO: Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-11}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade(); // Automatically finds the `ARCADE_API_KEY` env variable
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+let authResponse = await client.auth.start(userId, "hooli", [
+ "scope1",
+ "scope2",
+]);
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// TODO: Do something interesting with the token...
+```
+
+
+
+
+
+## Using OAuth 2.0 in custom tools
+
+You can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with any OAuth 2.0-compatible APIs.
+
+Use the `OAuth2()` auth class to specify that a tool requires OAuth 2.0 authorization. In your tool function, `context.authorization` will be automatically populated with the following properties:
+
+- `context.authorization.token` contains the user's access token.
+- If `oauth2.user_info_request` is configured, the user info will be fetched and placed in `context.authorization.user_info`. The data payload is specific to each provider.
+
+```python {3-4,7-12,19-24}
+from typing import Annotated
+
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import OAuth2
+
+
+@tool(
+ requires_auth=OAuth2(
+ provider_id="hooli",
+ scopes=["scope1", "scope2"],
+ )
+)
+async def reticulate_splines(
+ context: ToolContext,
+ num_splines: Annotated[int, "The number of splines to reticulate"],
+):
+ """Reticulate the specified number of splines."""
+
+ # Get an access token to call an API
+ token = context.authorization.token
+
+ # Get user info (if configured and supported by the OAuth 2.0 server):
+ user_id = context.authorization.user_info.get("sub")
+```
diff --git a/app/en/home/sharing-with-end-users/custom-auth/overview/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/overview/page.mdx
new file mode 100644
index 000000000..7876d1e01
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/overview/page.mdx
@@ -0,0 +1,182 @@
+---
+title: Auth Providers
+description: Registry of all auth providers available in the Arcade ecosystem
+---
+
+# Auth Providers
+
+import { ToolCard } from "@/app/_components/tool-card";
+
+Auth providers enable users to seamlessly and securely allow Arcade tools to access their data.
+
+Arcade has several auth providers available in the Arcade Cloud Platform so you don't have to configure your own. However, using Arcade's auth providers means that your users will see the Arcade brand (name and logo) on the auth screen and your authentications will share any rate limits from those providers with other Arcade customers.
+
+It can be useful to configure your own auth provider for the following reasons:
+
+- You want to use your own brand on the auth screen
+- You want to isolate your rate limits from other Arcade customers
+- You want to use a service that Arcade [does not have a built-in auth provider for](/home/auth-providers/oauth2)
+
+After adding an auth provider used by an Arcade tool, executing the tool will automatically use your auth provider. Even in the Arcade Cloud Platform, your auth provider will take precedence over the arcade-provided auth provider.
+
+Adding multiple providers of the same type, not including the arcade-provided ones, can cause Arcade's tool authorization to fail, see [Using multiple providers of the same type](#using-multiple-providers-of-the-same-type) for more information.
+
+## Catalog of providers
+
+For more information on how to customize your auth provider, select an auth provider from the list below:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+If the auth provider you need is not listed, try the [OAuth 2.0](/home/auth-providers/oauth2) provider, or [get in touch](mailto:contact@arcade.dev) with us!
+
+## Using multiple providers of the same type
+
+You can create multiple auth providers of the same type, for example, you can have multiple Google auth providers, each with their own client ID and secret. This might be useful if you want separate Google clients to handle calendar and email scopes, for example.
+
+However, Arcade's tools are configured to select an auth provider by the type. This means that if you have multiple auth providers of the same type, Arcade will not know which one to use and authorizing the tool will fail.
+
+To work around this, you can fork Arcade's tools and modify them to specify your own auth provider by the unique ID that you give each of them. For example, if you have two Google auth providers, `acme-google-calendar` and `acme-google-email`, you can modify Arcade's Gmail.ListEmails tool like this:
+
+```python
+@tool(
+ requires_auth=Google(
+ id="acme-google-email", # This is the unique ID you gave your auth provider
+ scopes=["https://www.googleapis.com/auth/gmail.readonly"],
+ )
+)
+async def list_emails(
+# ...
+```
+
+This is similar to the pattern used in the generic OAuth2 provider, but instead of using the `OAuth2` class, you use the `Google` class and specify the `id` of the auth provider you want to use.
+
+See the docs about [Authoring Tools](/home/build-tools/create-a-mcp-server) for more information on how to create and serve a MCP Server.
\ No newline at end of file
diff --git a/app/en/home/sharing-with-end-users/custom-auth/pagerduty/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/pagerduty/page.mdx
new file mode 100644
index 000000000..992dcb5ed
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/pagerduty/page.mdx
@@ -0,0 +1,293 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# PagerDuty
+
+The PagerDuty auth provider enables tools and agents to call [PagerDuty APIs](https://developer.pagerduty.com/api-reference/) on behalf of a user using OAuth 2.0 authentication.
+
+
+ Want to quickly get started with PagerDuty in your agent or AI app? The
+ pre-built [Arcade PagerDuty MCP
+ Server](/mcp-servers/development/pagerduty-api) is what you want!
+
+
+### What's documented here
+
+This page describes how to use and configure PagerDuty auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade PagerDuty MCP Server](/mcp-servers/development/pagerduty-api), which provides pre-built tools for interacting with PagerDuty
+- Your [app code](#using-pagerduty-auth-in-app-code) that needs to call the PagerDuty API
+- Or, your [custom tools](#using-pagerduty-auth-in-custom-tools) that need to call the PagerDuty API
+
+## Configuring PagerDuty auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own PagerDuty app credentials. This way, your users will see your application's name requesting permission.
+
+Before showing how to configure your PagerDuty app credentials, let's go through the steps to create a PagerDuty app.
+
+### Create a PagerDuty app
+
+To integrate with PagerDuty's API using OAuth 2.0, you'll need to register an app in your PagerDuty account:
+
+
+
+#### Access PagerDuty App Registration
+
+1. Log in to your PagerDuty account
+2. Navigate to **Integrations** → **App Registration**
+3. This is where you'll create and manage your OAuth applications
+
+#### Create a new app
+
+1. Click on **New App** or **Register New App**
+2. Fill in the required details:
+ - **Application Name**: Choose a descriptive name for your application
+ - **Description**: Provide a brief description of your app's purpose
+ - **Functionality**: Select both **OAuth 2.0** and **Events Integration** (if needed)
+
+#### Configure OAuth settings
+
+1. Choose **Scoped OAuth** as the authorization method
+2. Select the required **permission scopes** based on your application's needs:
+ - Common scopes include: `read`, `write`, `analytics.read`, `users.read`, `teams.read`, etc.
+3. Add the **Redirect URL** generated by Arcade (see configuration section below) to your app's redirect URLs
+
+#### Save your credentials
+
+1. After creating your app, you'll receive your **Client ID** and **Client Secret**
+2. **Important**: Copy and save these credentials immediately, as the Client Secret won't be accessible again
+
+
+
+For detailed instructions, refer to PagerDuty's [OAuth 2.0 guide](https://www.pagerduty.com/blog/insights/build-sophisticated-apps-for-your-pagerduty-environment-using-oauth-2-0-and-api-scopes/) and [OAuth documentation](https://developer.pagerduty.com/docs/ZG9jOjExMDI5NTgx-o-auth-2-functionality).
+
+Next, add the PagerDuty app to Arcade.
+
+## Configuring your own PagerDuty Auth Provider in Arcade
+
+
+
+
+### Configure PagerDuty Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **OAuth 2.0** tab at the top.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "arcade-pagerduty").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your PagerDuty app.
+- Configure the OAuth 2.0 endpoints:
+ - **Authorization URL**: `https://app.pagerduty.com/oauth/authorize`
+ - **Token URL**: `https://app.pagerduty.com/oauth/token`
+- Note the **Redirect URL** generated by Arcade. This must be set as one of your PagerDuty app's Redirect URLs.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+
+
+
+
+### Configure PagerDuty Auth Using Configuration File
+
+
+ This method is only available when you are [self-hosting the
+ engine](/home/deployment/on-prem-mcp)
+
+
+
+
+#### Set environment variables
+
+Set the following environment variables:
+
+```bash
+export PAGERDUTY_CLIENT_ID=""
+export PAGERDUTY_CLIENT_SECRET=""
+```
+
+Or, you can set these values in a `.env` file:
+
+```bash
+PAGERDUTY_CLIENT_ID=""
+PAGERDUTY_CLIENT_SECRET=""
+```
+
+#### Edit the Engine configuration
+
+Edit the `engine.yaml` file and add a new item to the `auth.providers` section:
+
+```yaml
+auth:
+ providers:
+ - id: arcade-pagerduty
+ description: PagerDuty OAuth 2.0 provider
+ enabled: true
+ type: oauth2
+ client_id: ${env:PAGERDUTY_CLIENT_ID}
+ client_secret: ${env:PAGERDUTY_CLIENT_SECRET}
+ oauth2:
+ scope_delimiter: " "
+ authorize_request:
+ endpoint: "https://app.pagerduty.com/oauth/authorize"
+ params:
+ response_type: code
+ client_id: "{{client_id}}"
+ redirect_uri: "{{redirect_uri}}"
+ scope: "{{scopes}}"
+ state: "{{state}}"
+ token_request:
+ endpoint: "https://app.pagerduty.com/oauth/token"
+ params:
+ grant_type: authorization_code
+ client_id: "{{client_id}}"
+ client_secret: "{{client_secret}}"
+ redirect_uri: "{{redirect_uri}}"
+ response_content_type: application/json
+```
+
+
+
+
+
+
+When you use tools that require PagerDuty auth using your Arcade account credentials, Arcade will automatically use this PagerDuty OAuth provider. If you have multiple PagerDuty providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+## Using PagerDuty auth in app code
+
+Use the PagerDuty auth provider in your own agents and AI apps to get a user token for the PagerDuty API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the PagerDuty API:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="arcade-pagerduty",
+ scopes=["read", "write"]
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-11}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade();
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+const authResponse = await client.auth.start(userId, "arcade-pagerduty", [
+ "read",
+ "write",
+]);
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using PagerDuty auth in custom tools
+
+You can use the pre-built [Arcade PagerDuty MCP Server](/mcp-servers/development/pagerduty-api) to quickly build agents and AI apps that interact with PagerDuty.
+
+If the pre-built tools in the PagerDuty MCP Server don't meet your needs, you can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the PagerDuty API.
+
+Use the `OAuth2()` auth class to specify that a tool requires authorization with PagerDuty. The `context.authorization.token` field will be automatically populated with the user's PagerDuty token:
+
+```python {8-12,22}
+from typing import Annotated
+
+import httpx
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import OAuth2
+
+
+@tool(
+ requires_auth=OAuth2(
+ provider_id="arcade-pagerduty",
+ scopes=["read"]
+ )
+)
+async def get_current_user(
+ context: ToolContext,
+) -> Annotated[dict, "The current user information."]:
+ """
+ Retrieve information about the authenticated user from PagerDuty.
+ """
+ url = "https://api.pagerduty.com/users/me"
+ headers = {
+ "Authorization": context.authorization.token,
+ "Accept": "application/vnd.pagerduty+json;version=2",
+ }
+
+ async with httpx.AsyncClient() as client:
+ response = await client.get(url, headers=headers)
+ response.raise_for_status()
+ return dict(response.json())
+```
+
+## Available Scopes
+
+PagerDuty uses a simplified scope system with the following scopes:
+
+- `read` - Read-only access to PagerDuty resources
+- `write` - Full read and write access to PagerDuty resources
+
+For more details about PagerDuty's OAuth scopes and permissions, refer to the [PagerDuty OAuth Scopes documentation](https://developer.pagerduty.com/docs/ZG9jOjExMDI5NTgx-o-auth-2-functionality#scopes).
diff --git a/app/en/home/sharing-with-end-users/custom-auth/reddit/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/reddit/page.mdx
new file mode 100644
index 000000000..42caa0d05
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/reddit/page.mdx
@@ -0,0 +1,184 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Reddit
+
+
+ At this time, Arcade does not offer a default Reddit Auth Provider. To use
+ Reddit auth, you must create a custom Auth Provider with your own Reddit OAuth
+ 2.0 credentials as described below.
+
+
+The Reddit auth provider enables tools and agents to call the Reddit API on behalf of a user.
+
+### What's documented here
+
+This page describes how to use and configure Reddit auth with Arcade.
+
+This auth provider is used by:
+
+- Your [app code](#using-reddit-auth-in-app-code) that needs to call Reddit APIs
+- Or, your [custom tools](#using-reddit-auth-in-custom-tools) that need to call Reddit APIs
+
+## Configuring Reddit auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Reddit app credentials. This way, your users will see your application's name requesting permission.
+
+
+Before showing how to configure your Reddit app credentials, let's go through the steps to create a Reddit app.
+
+### Create a Reddit app
+
+- Create a Reddit Application in the [Reddit App Console](https://www.reddit.com/prefs/apps)
+- Set the OAuth Redirect URL to the redirect URL generated by Arcade (see below)
+- Copy the App key (Client ID) and App secret (Client Secret), which you'll need below
+
+Next, add the Reddit app to Arcade.
+
+## Configuring your own Reddit Auth Provider in Arcade
+
+
+
+
+
+### Configure Reddit Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Included Providers** tab at the top.
+- In the **Provider** dropdown, select **Reddit**.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "my-reddit-provider").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Reddit app.
+- Note the **Redirect URL** generated by Arcade. This must be set as your Reddit app's OAuth Redirect URL.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+When you use tools that require Reddit auth using your Arcade account credentials, Arcade will automatically use this Reddit OAuth provider. If you have multiple Reddit providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+
+
+
+## Using Reddit auth in app code
+
+Use the Reddit auth provider in your own agents and AI apps to get a user-scoped token for the Reddit API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Reddit API:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="reddit",
+ scopes=["identity"],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# TODO: Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-10}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade();
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+const authResponse = await client.auth.start(userId, "reddit", {
+ scopes: ["identity"],
+});
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using Reddit auth in custom tools
+
+You can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Reddit API.
+
+Use the `Reddit()` auth class to specify that a tool requires authorization with Reddit. The `context.authorization.token` field will be automatically populated with the user's Reddit token:
+
+```python {5-6,9-13,20}
+from typing import Annotated
+
+import httpx
+
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import Reddit
+
+
+@tool(
+ requires_auth=Reddit(
+ scopes=["identity"],
+ )
+)
+async def get_user_info(
+ context: ToolContext,
+) -> Annotated[dict, "The user info"]:
+ """Get the user info for the current user."""
+ url = "https://oauth.reddit.com/api/v1/me"
+ headers = {
+ "Authorization": f"Bearer {context.authorization.token}",
+ "User-Agent": "YourAppName v1.0 by u/YourRedditUsername",
+ }
+
+ async with httpx.AsyncClient() as client:
+ response = await client.get(url, headers=headers)
+ response.raise_for_status()
+ return response.json()
+```
diff --git a/app/en/home/sharing-with-end-users/custom-auth/salesforce/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/salesforce/page.mdx
new file mode 100644
index 000000000..13cdc985c
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/salesforce/page.mdx
@@ -0,0 +1,566 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+import ToggleContent from "@/app/_components/toggle-content";
+import { SignupLink } from "@/app/_components/analytics";
+
+# Salesforce
+
+
+
+The Salesforce auth provider enables tools and agents to call Salesforce APIs on behalf of a user.
+
+## What's documented here
+
+This page describes how to use and configure Salesforce auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade Salesforce MCP Server](/mcp-servers/sales/salesforce), which provides pre-built tools for interacting with Salesforce services
+- Your [app code](#calling-salesforce-apis-directly) that needs to call Salesforce APIs
+- Or, your [custom tools](#create-your-own-salesforce-tools) that need to call Salesforce APIs
+
+## Create a Salesforce app
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+Salesforce has two types of apps: **Connected App** and **Lightning App**. For this guide, we'll create a **Connected App**. Make sure to follow the instructions below while you [create your Connected App](https://help.salesforce.com/s/articleView?id=xcloud.connected_app_create.htm&type=5).
+
+When creating your app, make sure to:
+
+- Under "API (Enable OAuth Settings)", check the **Enable OAuth Settings** box
+- Set the callback URL to the redirect URL generated by Arcade (see below)
+- In the **Available OAuth Scopes**, add the two following scopes:
+ - "Manage User Data Via APIs (api)"
+ - "Perform requests at any time (refresh_token, offline_access)"
+- Uncheck the **Require Proof Key for Code Exchange (PKCE)** option, unless you want to use PKCE (in which case, you'll also need to enable PKCE in the Salesforce auth configuration as [described below](#configuring-salesforce-auth))
+- Check "Enable Token Exchange Flow"
+- Check "Enable Refresh Token Rotation"
+- Leave all other settings as default and save your app
+
+Right after creating the app, Salesforce will redirect you to the app's page. In the "API (Enable OAuth Settings)" section, click on the **Manage Consumer Details** button and take note of the **API Key** and **Client Secret** values.
+
+Then, go back to the App's page and click on the **Manage** button at the top, then click on the **Edit Policies** button, at the top of the Manage page, and follow the instructions below:
+
+- In "IP Relaxation", select **Relax IP Restrictions**.
+- In "Refresh Token Policy", make sure the option **Refresh token is valid until revoked** is checked.
+
+With that, your Salesforce app is ready to be used with Arcade.
+
+## Get your Salesforce Org Subdomain
+
+Follow the steps below to find your Salesforce Org Subdomain:
+
+1. In the Setup menu, click on **Quick Find** in the top left corner and type `"my domain"`.
+1. In the search results, under **Company Settings**, click on **My Domain**.
+1. Under **My Domain Details**, check the value of the **Current My Domain URL** field.
+
+Your **Salesforce Org Subdomain** is the value before the `.my.salesforce.com` part. For example, if your Salesforce domain is `https://acme-inc.my.salesforce.com`, your Salesforce Org Subdomain is `acme-inc`. If you have a developer account, your URL might look like `https://acme-inc.develop.my.salesforce.com`. In this case, your Salesforce Org Subdomain is `acme-inc.develop`.
+
+Take note of your Salesforce Org Subdomain. You will need this value in the next steps.
+
+## Set the Salesforce Org Subdomain Environment Variable
+
+{/* The step is right before, but the note is intended for people coming from different pages that link directly to this sub-heading */}
+
+
+ Refer to the [previous step](#get-your-salesforce-org-subdomain) to find your
+ Salesforce Org Subdomain.
+
+
+Set the `SALESFORCE_ORG_SUBDOMAIN` environment variable in the same runtime where your Arcade Worker is executed:
+
+```bash
+export SALESFORCE_ORG_SUBDOMAIN={your-salesforce-subdomain}
+```
+
+## Create and Assign Custom Scopes to your Connected App
+
+The Salesforce API requires the App developer to create [OAuth custom scopes](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_oauth_customscopes.htm&type=5) defining granular permissions for their application users to authorize.
+
+The custom scopes required by the [Arcade Salesforce MCP Server](/mcp-servers/sales/salesforce) are listed below, along with their descriptions:
+
+
+ The custom scopes listed below are only required if you are using the [Arcade Salesforce MCP Server](/mcp-servers/sales/salesforce).
+
+If you're creating your own [custom Salesforce tools](/home/build-tools/create-a-mcp-server) or using Arcade to authorize users and call Salesforce APIs directly, you are free to define custom scope(s) that fit best your application use cases. Observe that you must have at least one custom scope assigned to your Salesforce app in order to use the Salesforce API.
+
+
+
+- `read_account`: Read access to account data.
+- `read_contact`: Read access to contact data.
+- `read_lead`: Read access to lead data.
+- `read_note`: Read access to note data.
+- `read_opportunity`: Read access to opportunity data.
+- `read_task`: Read access to task data.
+- `write_contact`: Write access to create contact.
+
+Follow the [Create an OAuth Custom Scope](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_oauth_customscopes_create.htm&type=5) and [Assign an OAuth Custom Scope to a Connected App](https://help.salesforce.com/s/articleView?id=xcloud.remoteaccess_oauth_customscopes_assign.htm&type=5) Salesforce documentation to understand how to define and assign these scopes to your Salesforce app.
+
+
+ The scope names aren't really attached to any endpoint or action. It's the
+ developer's job to honor the permissions communicated to the user when
+ authorizing the app. You could, in theory, assign one single scope (e.g.
+ `fullaccess`) and use it to query any Salesforce API endpoint.
+
+
+## Configuring Salesforce Auth
+
+
+
+
+
+
+
+### Configure Salesforce Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+By default, the Arcade Dashboard will be available at http://localhost:9099/dashboard (if you're accessing it from the same machine where it's running). Change the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Custom Provider** tab at the top.
+
+#### Enter the provider details
+
+- Enter `salesforce` as the **ID** for your provider (the ID must be `salesforce` in order to use the [Arcade Salesforce MCP Server](/mcp-servers/sales/salesforce)).
+- Optionally enter a **Description**.
+- Enter your **Client ID** and **Client Secret** from your Salesforce app.
+- Note the **Redirect URL** generated by Arcade. This must be set as your Salesforce app's callback URL.
+
+#### Configure the auth endpoints
+
+
+ Replace `salesforce-org-subdomain` with your [Salesforce Org
+ Subdomain](#get-your-salesforce-org-subdomain).
+
+
+- Enter the auth endpoints:
+ - **Authorization Endpoint**: `https://salesforce-org-subdomain.my.salesforce.com/services/oauth2/authorize`
+ - **Token Endpoint**: `https://salesforce-org-subdomain.my.salesforce.com/services/oauth2/token`
+- Under **Refresh Token Settings**:
+ - Enter the **Refresh Token Endpoint**: `https://salesforce-org-subdomain.my.salesforce.com/services/oauth2/token`
+ - In **Response Content Type**, select `application/json`.
+- Under **Token Introspection Settings**:
+ - Check the **Enable Token Introspection** option.
+ - Enter the **Token Introspection Endpoint**: `https://salesforce-org-subdomain.my.salesforce.com/services/oauth2/introspect`
+ - In **HTTP Method**, select `POST`
+ - In **Authentication Method**, select `Client Secret Basic`
+ - In **Request Content Type**, select `application/x-www-form-urlencoded`.
+ - Under **Request Parameters** section, add the following key-value pair:
+ - **Key**: `token`
+ - **Value**: `{{access_token}}`
+ - In **Response Content Type**, select `application/json`.
+ - In **Expiration Format**, select `Absolute Unix Timestamp`.
+ - Under the **Response Map** section:
+ - Set the **expires_in** field to `$.exp`
+ - Set the **scope** field to `$.scope`
+ - Leave the other fields as default
+ - Under **Triggers** section, enable the **On Token Grant** and **On Token Refresh** options.
+
+#### Optional Auth Settings
+
+- Under **PKCE Settings**, check the **Enable PKCE** option if you have enabled PKCE when creating your Salesforce app.
+- Leave the **Authorization Settings** and **Token Settings** sections as default.
+
+#### Create the provider
+
+Click the **Create** button and the provider will be ready to be used in the Arcade Engine.
+
+
+
+
+
+## Using the Arcade Salesforce MCP Server
+
+The [Arcade Salesforce MCP Server](/mcp-servers/sales/salesforce) provides tools to interact with various Salesforce objects, such as accounts, contacts, leads, opportunities, notes, tasks, email messages, call logs, etc.
+
+Refer to the [MCP Server documentation and examples](/mcp-servers/sales/salesforce) to learn how to use the MCP Server to build agents and AI apps that interact with Salesforce services.
+
+
+ Check our introductory documentation to understand what are tools and how
+ [tool calling works](/home/use-tools/tools-overview).
+
+
+## Calling Salesforce APIs directly
+
+Use the Salesforce auth provider to get a user authorization token and call Salesforce API endpoints directly, without the use of any tools. See [How Arcade helps with Agent Authorization](/home/auth/how-arcade-helps) to understand how this works.
+
+### Prerequisites
+
+1. Create an Arcade account
+1. Get an [Arcade API key](/home/api-keys).
+1. Set the `ARCADE_API_KEY` environment variable with `export ARCADE_API_KEY=`.
+1. Make sure to have Python 3.10+ or Node.js 18+ installed.
+
+
+
+
+
+### Install the Arcade Python Client
+
+```python
+pip install arcadepy
+```
+
+### Import necessary modules and instantiate the client
+
+Create a new script called `salesforce_example.py`. Import the necessary modules and instantiate the Arcade client:
+
+
+ The Arcade Engine service is available at `http://localhost:9099` by default.
+ Replace the host and port, if necessary, to match your environment.
+
+
+```python
+import requests
+from arcadepy import Arcade
+
+client = Arcade(base_url="http://localhost:9099") # Automatically finds the `ARCADE_API_KEY` env variable
+```
+
+### Set the values required for the Salesforce API call
+
+```python
+salesforce_provider_id = "salesforce"
+salesforce_org_subdomain = "salesforce-org-subdomain"
+user_id = "{arcade_user_id}"
+scopes = ["read_account"]
+```
+
+Here's a break down of each value:
+
+- **`salesforce_provider_id`**: the ID you entered when setting up the [Salesforce auth provider](#configuring-salesforce-auth);
+- **`salesforce_org_subdomain`**: your [Salesforce Org Subdomain](#get-your-salesforce-org-subdomain);
+- **`user_id`**: an internal identifier for your application user (it could be an email address, a username, UUID, etc); for demonstration purposes, in this example, enter your own email address;
+- **`scopes`**: the list of scopes you want to request from the user; if you assigned the [custom scopes required by the Arcade Salesforce MCP Server](#create-and-assign-custom-scopes-to-your-connected-app) use `["read_account"]` in this example.
+
+### Start the authorization process and wait for completion
+
+The Arcade client will prompt the user to access a URL and authorize the app to access their Salesforce data. At the end of the auth process, you will have a token that can be used to call Salesforce APIs on behalf of that user.
+
+```python
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider=salesforce_provider_id,
+ scopes=scopes,
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+
+if not token:
+ raise ValueError("No token found in auth response")
+```
+
+
+ If the same scopes have already been authorized by the user before and the
+ token is still valid, the auth process will be skipped and the token will be
+ returned immediately, without prompting with the authorization URL. The Arcade
+ Engine associates a previously authorized token with the `user_id` you
+ provided.
+
+
+### Call the Salesforce API
+
+We will now call the Salesforce `/parameterizedSearch` API endpoint to search and retrieve account data.
+
+
+ Replace the `q` value of `"acme"` with any keyword combination of your choice.
+ In a real-world scenario, this value would most likely come from a user's
+ input. Observe that the `q` argument must be a string with two or more
+ characters.
+
+
+```python
+response = requests.post(
+ f"https://{salesforce_org_subdomain}.my.salesforce.com/services/data/v63.0/parameterizedSearch",
+ headers={"Authorization": f"Bearer {token}"},
+ json={
+ "q": "acme",
+ "sobjects": [
+ {"name": "Account", "fields": ["Id", "Name", "Website", "Phone"]},
+ ],
+ "in": "ALL",
+ "overallLimit": 10,
+ "offset": 0,
+ },
+)
+
+if not response.ok:
+ raise ValueError(
+ f"Failed to retrieve Salesforce data: {response.status_code} - {response.text}"
+ )
+```
+
+
+
+
+```python
+import requests
+from arcadepy import Arcade
+
+client = Arcade(base_url="http://localhost:9099") # Automatically finds the `ARCADE_API_KEY` env variable
+
+salesforce_provider_id = "salesforce"
+salesforce_org_subdomain = "salesforce-org-subdomain"
+user_id = "{arcade_user_id}"
+scopes = ["read_account"]
+
+# Start the authorization process
+
+auth_response = client.auth.start(
+user_id=user_id,
+provider=salesforce_provider_id,
+scopes=scopes,
+)
+
+if auth_response.status != "completed":
+print("Please complete the authorization challenge in your browser:")
+print(auth_response.url)
+
+# Wait for the authorization to complete
+
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+
+if not token:
+raise ValueError("No token found in auth response")
+
+# Use the Salesforce API
+
+response = requests.post(
+f"https://{salesforce_org_subdomain}.my.salesforce.com/services/data/v63.0/parameterizedSearch",
+headers={"Authorization": f"Bearer {token}"},
+json={
+"q": "acme",
+"sobjects": [
+{"name": "Account", "fields": ["Id", "Name", "Website", "Phone"]},
+],
+"in": "ALL",
+"overallLimit": 10,
+"offset": 0,
+},
+)
+
+if not response.ok:
+raise ValueError(
+f"Failed to retrieve Salesforce data: {response.status_code} - {response.text}"
+)
+
+print(response.json())
+
+````
+
+
+
+
+
+
+
+
+### Install the Arcade JavaScript Client
+
+```javascript
+npm install @arcadeai/arcadejs
+````
+
+### Import necessary modules and instantiate the client
+
+Create a new script called `salesforce_example.js`. Import the necessary modules and instantiate the Arcade client:
+
+
+ Replace `http://localhost:9099` with the URL of your Arcade Engine.
+
+
+```javascript
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade((baseURL = "http://localhost:9099")); // Automatically finds the `ARCADE_API_KEY` env variable
+```
+
+### Set the values required for the Salesforce API call
+
+```javascript
+const salesforceProviderId = "salesforce";
+const salesforceOrgSubdomain = "salesforce-org-subdomain";
+const userId = "{arcade_user_id}";
+const scopes = ["read_account"];
+```
+
+Here's a break down of each value:
+
+- **`salesforceProviderId`**: the ID you entered when setting up the [Salesforce auth provider](#configuring-salesforce-auth);
+- **`salesforceOrgSubdomain`**: your [Salesforce Org Subdomain](#get-your-salesforce-org-subdomain);
+- **`userId`**: an internal identifier for your application user (it could be an email address, a username, UUID, etc); for demonstration purposes, in this example, enter your own email address;
+- **`scopes`**: the list of scopes you want to request from the user; if you assigned the [custom scopes required by the Arcade Salesforce MCP Server](#create-and-assign-custom-scopes-to-your-connected-app) use `["read_account"]` in this example.
+
+### Start the authorization process and wait for completion
+
+The Arcade client will prompt the user to access a URL and authorize the app to access their Salesforce data. At the end of the auth process, you will have a token that can be used to call Salesforce APIs on behalf of that user.
+
+```javascript
+let authResponse = await client.auth.start(userId, {
+ provider: salesforceProviderId,
+ scopes: scopes,
+});
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+if (!authResponse.context.token) {
+ throw new Error("No token found in auth response");
+}
+
+const token = authResponse.context.token;
+
+if (!token) {
+ throw new Error("No token found in auth response");
+```
+
+
+ If the same scopes have already been authorized by the user before and the
+ token is still valid, the auth process will be skipped and the token will be
+ returned immediately, without prompting with the authorization URL. The Arcade
+ Engine associates a previously authorized token with the `user_id` you
+ provide.
+
+
+### Call the Salesforce API
+
+We will now call the Salesforce `/parameterizedSearch` API endpoint to search and retrieve account data.
+
+
+ Replace the `q` value of `"acme"` with any keyword combination of your choice.
+ In a real-world scenario, this value would most likely come from a user's
+ input. Observe that the `q` argument must be a string with two or more
+ characters.
+
+
+```javascript
+// Use the Salesforce API
+const response = await fetch(
+ `https://${salesforceOrgSubdomain}.my.salesforce.com/services/data/v63.0/parameterizedSearch`,
+ {
+ headers: {
+ Authorization: `Bearer ${token}`,
+ },
+ method: "POST",
+ body: JSON.stringify({
+ q: "acme",
+ sobjects: [
+ { name: "Account", fields: ["Id", "Name", "Website", "Phone"] },
+ ],
+ in: "ALL",
+ overallLimit: 10,
+ offset: 0,
+ }),
+ },
+);
+
+if (!response.ok) {
+ throw new Error(
+ `HTTP error! status: ${response.status} - ${await response.text()}`,
+ );
+```
+
+
+
+
+```javascript
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade((baseURL = "http://localhost:9099")); // Automatically finds the `ARCADE_API_KEY` env variable
+
+const salesforceProviderId = "salesforce";
+const salesforceOrgSubdomain = "salesforce-org-subdomain";
+const userId = "{arcade_user_id}";
+const scopes = ["read_account"];
+
+// Start the authorization process
+let authResponse = await client.auth.start(userId, {
+provider: salesforceProviderId,
+scopes: scopes,
+});
+
+if (authResponse.status !== "completed") {
+console.log("Please complete the authorization challenge in your browser:");
+console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+if (!authResponse.context.token) {
+throw new Error("No token found in auth response");
+}
+
+const token = authResponse.context.token;
+
+if (!token) {
+throw new Error("No token found in auth response");
+}
+
+// Use the Salesforce API
+const response = await fetch(
+`https://${salesforceOrgSubdomain}.my.salesforce.com/services/data/v63.0/parameterizedSearch`,
+{
+headers: {
+Authorization: `Bearer ${token}`,
+},
+method: "POST",
+body: JSON.stringify({
+q: "acme",
+sobjects: [
+{ name: "Account", fields: ["Id", "Name", "Website", "Phone"] },
+],
+in: "ALL",
+overallLimit: 10,
+offset: 0,
+}),
+},
+);
+
+if (!response.ok) {
+throw new Error(
+`HTTP error! status: ${response.status} - ${await response.text()}`,
+);
+}
+
+console.log(await response.json());
+
+```
+
+
+
+
+
+
+
+## Create your own Salesforce Tools
+
+If the pre-built tools in the [Arcade Salesforce MCP Server](/mcp-servers/sales/salesforce) don't meet your needs, you can create your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Salesforce APIs.
+
+The code implemented in the Arcade Salesforce tools is the best guide for you to understand how to implement your own. Check the [Contact](https://github.com/ArcadeAI/arcade-ai/blob/main/mcp-servers/salesforce/arcade_salesforce/tools/crm/contact.py) and [Account](https://github.com/ArcadeAI/arcade-ai/blob/main/mcp-servers/salesforce/arcade_salesforce/tools/crm/account.py) tools in our public Github repository.
+```
diff --git a/app/en/home/sharing-with-end-users/custom-auth/slack/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/slack/page.mdx
new file mode 100644
index 000000000..a65bd14bb
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/slack/page.mdx
@@ -0,0 +1,238 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Slack
+
+The Slack auth provider enables tools and agents to call [Slack APIs](https://api.slack.com/docs) on behalf of a user.
+
+
+ Want to quickly get started with Slack in your agent or AI app? The pre-built
+ [Arcade Slack MCP Server](/mcp-servers/social-communication/slack) is what you
+ want!
+
+
+### What's documented here
+
+This page describes how to use and configure Slack auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade Slack MCP Server](/mcp-servers/social-communication/slack), which provides pre-built tools for interacting with Slack
+- Your [app code](#using-slack-auth-in-app-code) that needs to call the Slack API
+- Or, your [custom tools](#using-slack-auth-in-custom-tools) that need to call the Slack API
+
+## Configuring Slack auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Slack app credentials. This way, your users will see your application's name requesting permission.
+
+
+Before showing how to configure your Slack app credentials, let's go through the steps to create a Slack app.
+
+### Create a Slack app
+
+
+ In May 29, 2025, [Slack announced](https://api.slack.com/changelog/2025-05-terms-rate-limit-update-and-faq) changes to their API rate-limits and terms of service for apps that are not approved for the Slack Marketplace.
+
+The `conversations.history` and `conversations.replies` endpoints are now limited to 1 request/minute and up to 15 objects returned per request. This affects various tools in the [Arcade Slack MCP Server](/mcp-servers/social-communication/slack). Additionally, the [API Terms of Service](https://slack.com/terms-of-service/api) now requires [Slack Marketplace](https://api.slack.com/slack-marketplace/using) approval for commercial distribution.
+
+
+
+- Follow Slack's guide to [registering a Slack app](https://api.slack.com/quickstart)
+- If you plan to use the [Arcade Slack MCP Server](/mcp-servers/social-communication/slack), select the scopes below (include additional scopes for your application's authorization needs or custom tools, in any):
+ - `channels:history`
+ - `channels:read`
+ - `chat:write`
+ - `groups:read`
+ - `groups:history`
+ - `groups:write`
+ - `im:history`
+ - `im:read`
+ - `im:write`
+ - `mpim:history`
+ - `mpim:read`
+ - `mpim:write`
+ - `users:read`
+ - `users:read.email`
+- Set the redirect URL to the redirect URL generated by Arcade (see below)
+- Copy the client ID and client secret
+
+Next, add the Slack app to Arcade.
+
+## Configuring your own Slack Auth Provider in Arcade
+
+
+
+
+
+### Configure Slack Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Included Providers** tab at the top.
+- In the **Provider** dropdown, select **Slack**.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "my-slack-provider").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Slack app.
+- Note the **Redirect URL** generated by Arcade. This must be set as your Slack app's redirect URL.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+When you use tools that require Slack auth using your Arcade account credentials, Arcade will automatically use this Slack OAuth provider. If you have multiple Slack providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+
+
+
+## Using Slack auth in app code
+
+Use the Slack auth provider in your own agents and AI apps to get a user token for the Slack API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Slack API:
+
+
+
+
+```python {8-17}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="slack",
+ scopes=[
+ "chat:write",
+ "im:write",
+ "users.profile:read",
+ "users:read",
+ ],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-10}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade(); // Automatically finds the `ARCADE_API_KEY` env variable
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+let authResponse = await client.auth.start(userId, "slack", {
+ scopes: ["chat:write", "im:write", "users.profile:read", "users:read"],
+});
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using Slack auth in custom tools
+
+You can use the pre-built [Arcade Slack MCP Server](/mcp-servers/social-communication/slack) to quickly build agents and AI apps that interact with Slack.
+
+If the pre-built tools in the Slack MCP Server don't meet your needs, you can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Slack API.
+
+Use the `Slack()` auth class to specify that a tool requires authorization with Slack. The `context.authorization.token` field will be automatically populated with the user's Slack token:
+
+```python {5-6,10-19,30}
+from typing import Annotated
+
+from slack_sdk import WebClient
+
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import Slack
+from arcade_tdk.errors import RetryableToolError
+
+
+@tool(
+ requires_auth=Slack(
+ scopes=[
+ "chat:write",
+ "im:write",
+ "users.profile:read",
+ "users:read",
+ ],
+ )
+)
+def send_dm_to_user(
+ context: ToolContext,
+ user_name: Annotated[
+ str,
+ "The Slack username of the person you want to message. Slack usernames are ALWAYS lowercase.",
+ ],
+ message: Annotated[str, "The message you want to send"],
+):
+ """Send a direct message to a user in Slack."""
+
+ slackClient = WebClient(token=context.authorization.token)
+
+ # Retrieve the user's Slack ID based on their username
+ userListResponse = slackClient.users_list()
+ user_id = None
+ for user in userListResponse["members"]:
+ if user["name"].lower() == user_name.lower():
+ user_id = user["id"]
+ break
+
+ if not user_id:
+ raise RetryableToolError(
+ "User not found",
+ developer_message=f"User with username '{user_name}' not found.",
+ )
+
+ # Step 2: Retrieve the DM channel ID with the user
+ im_response = slackClient.conversations_open(users=[user_id])
+ dm_channel_id = im_response["channel"]["id"]
+
+ # Step 3: Send the message as if it's from you (because we're using a user token)
+ slackClient.chat_postMessage(channel=dm_channel_id, text=message)
+```
diff --git a/app/en/home/sharing-with-end-users/custom-auth/spotify/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/spotify/page.mdx
new file mode 100644
index 000000000..979b70ee3
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/spotify/page.mdx
@@ -0,0 +1,188 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Spotify
+
+
+ At this time, Arcade does not offer a default Spotify Auth Provider. To use
+ Spotify auth, you must create a custom Auth Provider with your own Spotify
+ OAuth 2.0 credentials as described below.
+
+
+The Spotify auth provider enables tools and agents to call the Spotify API on behalf of a user.
+
+### What's documented here
+
+This page describes how to use and configure Spotify auth with Arcade.
+
+This auth provider is used by:
+
+- Your [app code](#using-spotify-auth-in-app-code) that needs to call Spotify APIs
+- Or, your [custom tools](#using-spotify-auth-in-custom-tools) that need to call Spotify APIs
+
+## Configuring Spotify auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Spotify app credentials. This way, your users will see your application's name requesting permission.
+
+
+Before showing how to configure your Spotify app credentials, let's go through the steps to create a Spotify app.
+
+### Create a Spotify app
+
+- Follow Spotify's guide to [registering an app](https://developer.spotify.com/documentation/web-api/tutorials/getting-started)
+- Choose the "Web API" product (at a minimum)
+- Set the redirect URL to the redirect URL generated by Arcade (see below)
+- Copy the client ID and client secret to use below
+
+Next, add the Spotify app to Arcade.
+## Configuring your own Spotify Auth Provider in Arcade
+
+
+
+
+
+
+### Configure Spotify Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Included Providers** tab at the top.
+- In the **Provider** dropdown, select **Spotify**.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "my-spotify-provider").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Spotify app.
+- Note the **Redirect URL** generated by Arcade. This must be set as your Spotify app's redirect URL.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+When you use tools that require Spotify auth using your Arcade account credentials, Arcade will automatically use this Spotify OAuth provider. If you have multiple Spotify providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+
+
+
+## Using Spotify auth in app code
+
+Use the Spotify auth provider in your own agents and AI apps to get a user token for the Spotify API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Spotify API:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="spotify",
+ scopes=["user-read-playback-state"],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-10}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade(); // Automatically finds the `ARCADE_API_KEY` env variable
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+let authResponse = await client.auth.start(userId, "spotify", [
+ "user-read-playback-state",
+]);
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using Spotify auth in custom tools
+
+You can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Spotify API.
+
+Use the `Spotify()` auth class to specify that a tool requires authorization with Spotify. The `context.authorization.token` field will be automatically populated with the user's Spotify token:
+
+```python {5-6,9-13,19}
+from typing import Annotated
+
+import httpx
+
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import Spotify
+
+
+@tool(
+ requires_auth=Spotify(
+ scopes=["user-read-playback-state"],
+ )
+)
+async def get_playback_state(
+ context: ToolContext,
+) -> Annotated[dict, "Information about the user's current playback state"]:
+ """Get information about the user's current playback state, including track or episode, progress, and active device."""
+ endpoint = "/me/player"
+ headers = {"Authorization": f"Bearer {context.authorization.token}"}
+
+ async with httpx.AsyncClient() as client:
+ response = await client.get(
+ f"https://api.spotify.com/v1/{endpoint}",
+ headers=headers,
+ )
+ response.raise_for_status()
+
+ if response.status_code == 204:
+ return {"status": "Playback not available or active"}
+ return response.json()
+```
diff --git a/app/en/home/sharing-with-end-users/custom-auth/square/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/square/page.mdx
new file mode 100644
index 000000000..d924676e3
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/square/page.mdx
@@ -0,0 +1,304 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Square
+
+The Square auth provider enables tools and agents to call [Square APIs](https://developer.squareup.com/reference/square) on behalf of a user using OAuth 2.0 authentication.
+
+
+ Want to quickly get started with Square in your agent or AI app? The pre-built
+ [Arcade Square MCP Server](/mcp-servers/productivity/squareup-api) is what you
+ want!
+
+
+### What's documented here
+
+This page describes how to use and configure Square auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade Square MCP Server](/mcp-servers/productivity/squareup-api), which provides pre-built tools for interacting with Square
+- Your [app code](#using-square-auth-in-app-code) that needs to call the Square API
+- Or, your [custom tools](#using-square-auth-in-custom-tools) that need to call the Square API
+
+## Configuring Square auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Square app credentials. This way, your users will see your application's name requesting permission.
+
+Before showing how to configure your Square app credentials, let's go through the steps to create a Square app.
+
+### Create a Square app
+
+To integrate with Square's API, you'll need to create an application in the Square Developer Dashboard:
+
+
+
+#### Access the Square Developer Dashboard
+
+Navigate to the [Square Developer Portal](https://developer.squareup.com/) and sign in with your Square account or create a new one.
+
+#### Create a new application
+
+1. Once logged in, go to the [Developer Dashboard](https://developer.squareup.com/apps)
+2. Click on "Create App" or "+" button
+3. Fill in the required details:
+ - **App Name**: Choose a descriptive name for your application
+ - **Description**: Provide a brief description of your app's purpose
+
+#### Configure OAuth settings
+
+1. After creating your app, navigate to the **OAuth** tab
+2. Set the **Redirect URL** to the redirect URL generated by Arcade (see configuration section below)
+3. Configure the required **Permissions** (scopes) for your application:
+ - `MERCHANT_PROFILE_READ` - Read merchant profile information
+ - `PAYMENTS_READ` - Read payment information
+ - `PAYMENTS_WRITE` - Process payments
+ - Add other scopes as needed for your use case
+
+#### Obtain your credentials
+
+1. In your app's dashboard, go to the **Credentials** tab
+2. You'll find your **Application ID** (Client ID) and **Application Secret** (Client Secret)
+3. Copy both values for use in Arcade configuration
+
+
+
+For detailed instructions, refer to Square's [OAuth documentation](https://developer.squareup.com/docs/oauth-api/overview).
+
+Next, add the Square app to Arcade.
+
+## Configuring your own Square Auth Provider in Arcade
+
+
+
+
+### Configure Square Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **OAuth 2.0** tab at the top.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "arcade-square").
+- Optionally enter a **Description**.
+- Enter the **Client ID** (Application ID) and **Client Secret** (Application Secret) from your Square app.
+- Configure the OAuth 2.0 endpoints:
+ - **Authorization URL**: `https://connect.squareup.com/oauth2/authorize`
+ - **Token URL**: `https://connect.squareup.com/oauth2/token`
+- Note the **Redirect URL** generated by Arcade. This must be set as your Square app's Redirect URL.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+
+
+
+
+### Configure Square Auth Using Configuration File
+
+
+ This method is only available when you are [self-hosting the
+ engine](/home/deployment/on-prem-mcp)
+
+
+
+
+#### Set environment variables
+
+Set the following environment variables:
+
+```bash
+export SQUARE_CLIENT_ID=""
+export SQUARE_CLIENT_SECRET=""
+```
+
+Or, you can set these values in a `.env` file:
+
+```bash
+SQUARE_CLIENT_ID=""
+SQUARE_CLIENT_SECRET=""
+```
+
+#### Edit the Engine configuration
+
+Edit the `engine.yaml` file and add a new item to the `auth.providers` section:
+
+```yaml
+auth:
+ providers:
+ - id: arcade-square
+ description: Square OAuth 2.0 provider
+ enabled: true
+ type: oauth2
+ client_id: ${env:SQUARE_CLIENT_ID}
+ client_secret: ${env:SQUARE_CLIENT_SECRET}
+ oauth2:
+ scope_delimiter: " "
+ authorize_request:
+ endpoint: "https://connect.squareup.com/oauth2/authorize"
+ params:
+ response_type: code
+ client_id: "{{client_id}}"
+ redirect_uri: "{{redirect_uri}}"
+ scope: "{{scopes}}"
+ state: "{{state}}"
+ token_request:
+ endpoint: "https://connect.squareup.com/oauth2/token"
+ params:
+ grant_type: authorization_code
+ client_id: "{{client_id}}"
+ client_secret: "{{client_secret}}"
+ redirect_uri: "{{redirect_uri}}"
+ response_content_type: application/json
+```
+
+
+
+
+
+
+When you use tools that require Square auth using your Arcade account credentials, Arcade will automatically use this Square OAuth provider. If you have multiple Square providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+## Using Square auth in app code
+
+Use the Square auth provider in your own agents and AI apps to get a user token for the Square API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Square API:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="arcade-square",
+ scopes=["MERCHANT_PROFILE_READ", "PAYMENTS_READ"]
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-11}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade();
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+const authResponse = await client.auth.start(
+ userId,
+ "arcade-square",
+ ["MERCHANT_PROFILE_READ", "PAYMENTS_READ"]
+);
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using Square auth in custom tools
+
+You can use the pre-built [Arcade Square MCP Server](/mcp-servers/productivity/squareup-api) to quickly build agents and AI apps that interact with Square.
+
+If the pre-built tools in the Square MCP Server don't meet your needs, you can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Square API.
+
+Use the `OAuth2()` auth class to specify that a tool requires authorization with Square. The `context.authorization.token` field will be automatically populated with the user's Square token:
+
+```python {8-12,22}
+from typing import Annotated
+
+import httpx
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import OAuth2
+
+
+@tool(
+ requires_auth=OAuth2(
+ provider_id="arcade-square",
+ scopes=["MERCHANT_PROFILE_READ"]
+ )
+)
+async def get_merchant_info(
+ context: ToolContext,
+) -> Annotated[dict, "The merchant information."]:
+ """
+ Retrieve merchant profile information from Square.
+ """
+ url = "https://connect.squareup.com/v2/merchants/me"
+ headers = {
+ "Authorization": context.authorization.token,
+ "Content-Type": "application/json",
+ }
+
+ async with httpx.AsyncClient() as client:
+ response = await client.get(url, headers=headers)
+ response.raise_for_status()
+ return dict(response.json())
+```
+
+## Available Scopes
+
+Square supports various OAuth scopes that determine the level of access your application has:
+
+- `MERCHANT_PROFILE_READ` - Read merchant profile information
+- `PAYMENTS_READ` - Read payment information
+- `PAYMENTS_WRITE` - Process payments
+- `CUSTOMERS_READ` - Read customer information
+- `CUSTOMERS_WRITE` - Create and update customers
+- `ORDERS_READ` - Read order information
+- `ORDERS_WRITE` - Create and update orders
+- `INVENTORY_READ` - Read inventory information
+- `INVENTORY_WRITE` - Update inventory
+
+For a complete list of available scopes, refer to the [Square OAuth Permissions documentation](https://developer.squareup.com/docs/oauth-api/square-permissions).
+
diff --git a/app/en/home/sharing-with-end-users/custom-auth/ticktick/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/ticktick/page.mdx
new file mode 100644
index 000000000..f9f070a34
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/ticktick/page.mdx
@@ -0,0 +1,320 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# TickTick
+
+The TickTick auth provider enables tools and agents to call [TickTick APIs](https://developer.ticktick.com/docs) on behalf of a user using OAuth 2.0 authentication.
+
+
+ Want to quickly get started with TickTick in your agent or AI app? The
+ pre-built [Arcade TickTick API MCP
+ Server](/mcp-servers/productivity/ticktick-api) is what you want!
+
+
+### What's documented here
+
+This page describes how to use and configure TickTick auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade TickTick API MCP Server](/mcp-servers/productivity/ticktick-api), which provides pre-built tools for interacting with TickTick
+- Your [app code](#using-ticktick-auth-in-app-code) that needs to call the TickTick API
+- Or, your [custom tools](#using-ticktick-auth-in-custom-tools) that need to call the TickTick API
+
+## Configuring TickTick auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own TickTick app credentials. This way, your users will see your application's name requesting permission.
+
+Before showing how to configure your TickTick app credentials, let's go through the steps to create a TickTick app.
+
+### Create a TickTick app
+
+To integrate with TickTick's API, you'll need to set up OAuth 2.0 authentication by creating an app in the TickTick Developer Portal:
+
+
+
+#### Access the TickTick Developer Portal
+
+Navigate to the [TickTick Developer Portal](https://developer.ticktick.com/manage) and sign in with your existing TickTick credentials or create a new account.
+
+#### Create a new app
+
+1. Once logged in, click on "New App"
+2. Fill in the required details:
+ - **App Name**: Choose a descriptive name for your application
+ - **App Description**: Provide a brief description of your application's purpose
+ - **App Icon**: Upload an icon to represent your application (optional)
+
+#### Configure OAuth settings
+
+1. After creating your app, you'll receive a `Client ID` and `Client Secret`
+2. Set the **Redirect URI** to the redirect URL generated by Arcade (see configuration section below)
+3. Configure the required scopes for your application:
+ - `tasks:read` - Read access to tasks
+ - `tasks:write` - Write access to tasks (create, update, delete)
+ - Add other scopes as needed for your use case
+
+
+
+For detailed instructions, refer to TickTick's official [API Documentation](https://developer.ticktick.com/docs).
+
+Next, add the TickTick app to Arcade.
+
+## Configuring your own TickTick Auth Provider in Arcade
+
+
+
+
+### Configure TickTick Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **OAuth 2.0** tab at the top.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "arcade-ticktick").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your TickTick app.
+- Configure the OAuth 2.0 endpoints:
+ - **Authorization URL**: `https://ticktick.com/oauth/authorize`
+ - **Token URL**: `https://ticktick.com/oauth/token`
+- Note the **Redirect URL** generated by Arcade. This must be set as your TickTick app's redirect URI.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+
+
+
+
+### Configure TickTick Auth Using Configuration File
+
+
+ This method is only available when you are [self-hosting the
+ engine](/home/deployment/on-prem-mcp)
+
+
+
+
+#### Set environment variables
+
+Set the following environment variables:
+
+```bash
+export TICKTICK_CLIENT_ID=""
+export TICKTICK_CLIENT_SECRET=""
+```
+
+Or, you can set these values in a `.env` file:
+
+```bash
+TICKTICK_CLIENT_ID=""
+TICKTICK_CLIENT_SECRET=""
+```
+
+#### Edit the Engine configuration
+
+Edit the `engine.yaml` file and add a new item to the `auth.providers` section:
+
+```yaml
+auth:
+ providers:
+ - id: arcade-ticktick
+ description: TickTick OAuth 2.0 provider
+ enabled: true
+ type: oauth2
+ client_id: ${env:TICKTICK_CLIENT_ID}
+ client_secret: ${env:TICKTICK_CLIENT_SECRET}
+ oauth2:
+ scope_delimiter: " "
+ authorize_request:
+ endpoint: "https://ticktick.com/oauth/authorize"
+ params:
+ response_type: code
+ client_id: "{{client_id}}"
+ redirect_uri: "{{redirect_uri}}"
+ scope: "{{scopes}}"
+ state: "{{state}}"
+ token_request:
+ endpoint: "https://ticktick.com/oauth/token"
+ auth_method: client_secret_post
+ params:
+ grant_type: authorization_code
+ client_id: "{{client_id}}"
+ client_secret: "{{client_secret}}"
+ code: "{{code}}"
+ redirect_uri: "{{redirect_uri}}"
+ response_content_type: application/x-www-form-urlencoded
+ refresh_request:
+ endpoint: "https://ticktick.com/oauth/token"
+ auth_method: client_secret_post
+ params:
+ grant_type: refresh_token
+ client_id: "{{client_id}}"
+ client_secret: "{{client_secret}}"
+ refresh_token: "{{refresh_token}}"
+ response_content_type: application/x-www-form-urlencoded
+```
+
+
+
+
+
+
+When you use tools that require TickTick auth using your Arcade account credentials, Arcade will automatically use this TickTick OAuth provider. If you have multiple TickTick providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+## Using TickTick auth in app code
+
+Use the TickTick auth provider in your own agents and AI apps to get a user token for the TickTick API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the TickTick API:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="arcade-ticktick",
+ scopes=["tasks:read", "tasks:write"]
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-11}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade();
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+const authResponse = await client.auth.start(userId, "arcade-ticktick", [
+ "tasks:read",
+ "tasks:write",
+]);
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using TickTick auth in custom tools
+
+You can use the pre-built [Arcade TickTick API MCP Server](/mcp-servers/productivity/ticktick-api) to quickly build agents and AI apps that interact with TickTick.
+
+If the pre-built tools in the TickTick MCP Server don't meet your needs, you can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the TickTick API.
+
+Use the `OAuth2()` auth class to specify that a tool requires authorization with TickTick. The `context.authorization.token` field will be automatically populated with the user's TickTick token:
+
+```python {8-12,22}
+from typing import Annotated
+
+import httpx
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import OAuth2
+
+
+@tool(
+ requires_auth=OAuth2(
+ provider_id="arcade-ticktick",
+ scopes=["tasks:read"]
+ )
+)
+async def get_ticktick_projects(
+ context: ToolContext,
+) -> Annotated[dict, "The list of projects."]:
+ """
+ Retrieve all projects from TickTick.
+ """
+ url = "https://api.ticktick.com/open/v1/project"
+ headers = {
+ "Authorization": f"Bearer {context.authorization.token}",
+ }
+
+ async with httpx.AsyncClient() as client:
+ response = await client.get(url, headers=headers)
+ response.raise_for_status()
+ return dict(response.json())
+```
+
+## Available Scopes
+
+TickTick supports the following OAuth scopes that determine the level of access your application has:
+
+- `tasks:read` - Read access to tasks, projects, and related data
+- `tasks:write` - Full access to create, update, and delete tasks and projects
+
+For a complete list of available API endpoints and their required scopes, refer to the [TickTick API documentation](https://developer.ticktick.com/docs).
+
+## API Endpoints
+
+TickTick provides a comprehensive REST API for managing tasks and projects. The base URL for all API requests is:
+
+```
+https://api.ticktick.com/open/v1
+```
+
+Common endpoints include:
+
+- `/project` - Manage projects
+- `/task` - Manage tasks
+- `/user` - Get user information
+
+All API requests must include the OAuth access token in the `Authorization` header:
+
+```
+Authorization: Bearer {access_token}
+```
+
+For detailed API documentation, including request/response formats and examples, visit the [TickTick API Reference](https://developer.ticktick.com/docs).
diff --git a/app/en/home/sharing-with-end-users/custom-auth/twitch/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/twitch/page.mdx
new file mode 100644
index 000000000..2a7a8d495
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/twitch/page.mdx
@@ -0,0 +1,211 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Twitch
+
+
+ At this time, Arcade does not offer a default Twitch Auth Provider. To use
+ Twitch auth, you must create a custom Auth Provider with your own Twitch OAuth
+ 2.0 credentials as described below.
+
+
+The Twitch auth provider enables tools and agents to call the Twitch API on behalf of a user.
+
+### What's documented here
+
+This page describes how to use and configure Twitch auth with Arcade.
+
+This auth provider is used by:
+
+- Your [app code](#using-twitch-auth-in-app-code) that needs to call Twitch APIs
+- Or, your [custom tools](#using-twitch-auth-in-custom-tools) that need to call Twitch APIs
+
+## Configuring Twitch auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Twitch app credentials. This way, your users will see your application's name requesting permission.
+
+
+Before showing how to configure your Twitch app credentials, let's go through the steps to create a Twitch app.
+
+### Create a Twitch app
+
+- Twitch requires that you have two-factor authentication enabled for your account. Enable in your [account security seetings](https://www.twitch.tv/settings/security)
+- Create a Twitch Application in the [Twitch App Console](https://dev.twitch.tv/console/apps)
+- Set the OAuth Redirect URL to the redirect URL generated by Arcade (see below)
+- Select your Application category
+- Select the 'Confidential' Client Type
+- Copy the App key (Client ID) and App secret (Client Secret), which you'll need below
+
+Next, add the Twitch app to Arcade.
+
+## Configuring your own Twitch Auth Provider in Arcade
+
+
+
+
+
+
+### Configure Twitch Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Included Providers** tab at the top.
+- In the **Provider** dropdown, select **Twitch**.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "my-twitch-provider").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Twitch app.
+- Note the **Redirect URL** generated by Arcade. This must be set as your Twitch app's OAuth Redirect URL.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+When you use tools that require Twitch auth using your Arcade account credentials, Arcade will automatically use this Twitch OAuth provider. If you have multiple Twitch providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+
+
+
+## Using Twitch auth in app code
+
+Use the Twitch auth provider in your own agents and AI apps to get a user-scoped token for the Twitch API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Twitch API:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="twitch",
+ scopes=["channel:manage:polls"],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-10}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade();
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+const authResponse = await client.auth.start(userId, "twitch", {
+ scopes: ["channel:manage:polls"],
+});
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using Twitch auth in custom tools
+
+You can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Twitch API.
+
+Use the `Twitch()` auth class to specify that a tool requires authorization with Twitch. The `context.authorization.token` field will be automatically populated with the user's Twitch token:
+
+```python {5-6,9-13,36}
+from typing import Annotated, Optional
+
+import httpx
+
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import Twitch
+
+
+@tool(
+ requires_auth=Twitch(
+ scopes=["channel:manage:polls"],
+ )
+)
+async def create_poll(
+ context: ToolContext,
+ broadcaster_id: Annotated[
+ str,
+ "The ID of the broadcaster to create the poll for.",
+ ],
+ title: Annotated[
+ str,
+ "The title of the poll.",
+ ],
+ choices: Annotated[
+ list[str],
+ "The choices of the poll.",
+ ],
+ duration: Annotated[
+ int,
+ "The duration of the poll in seconds.",
+ ],
+) -> Annotated[dict, "The poll that was created"]:
+ """Create a poll for a Twitch channel."""
+ url = "https://api.twitch.tv/helix/polls"
+ headers = {
+ "Authorization": f"Bearer {context.authorization.token}",
+ "Client-Id": "your_client_id",
+ "Content-Type": "application/json",
+ }
+ payload = {
+ "broadcaster_id": broadcaster_id,
+ "title": title,
+ "choices": [{"title": choice} for choice in choices],
+ "duration": duration,
+ }
+
+ async with httpx.AsyncClient() as client:
+ response = await client.post(url, headers=headers, json=payload)
+ response.raise_for_status()
+ return response.json()
+```
diff --git a/app/en/home/sharing-with-end-users/custom-auth/x/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/x/page.mdx
new file mode 100644
index 000000000..13dcdb022
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/x/page.mdx
@@ -0,0 +1,195 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# X
+
+The X auth provider enables tools and agents to call the X (Twitter) API on behalf of a user.
+
+
+ Want to quickly get started with X services in your agent or AI app? The
+ pre-built [Arcade X MCP Server](/mcp-servers/social-communication/x) is what you
+ want!
+
+
+### What's documented here
+
+This page describes how to use and configure X auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade X MCP Server](/mcp-servers/social-communication/x), which provides pre-built tools for interacting with X
+- Your [app code](#using-x-auth-in-app-code) that needs to call X APIs
+- Or, your [custom tools](#using-x-auth-in-custom-tools) that need to call X APIs
+
+## Configuring X auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own X app credentials. This way, your users will see your application's name requesting permission.
+
+
+Before showing how to configure your X app credentials, let's go through the steps to create a X app.
+
+### Create an X app
+
+- Follow X's guide to [creating an app](https://developer.x.com/en/docs/x-api/getting-started/getting-access-to-the-x-api)
+- Enable user authentication for your new app, and set its type to "Web App, Automated App or Bot"
+- Set the redirect URL to the redirect URL generated by Arcade (see below)
+- Copy the client ID and client secret to use below
+
+Next, add the X app to Arcade.
+
+## Configuring your own X Auth Provider in Arcade
+
+
+
+
+
+
+### Configure X Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Included Providers** tab at the top.
+- In the **Provider** dropdown, select **X**.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "my-x-provider").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your X app.
+- Note the **Redirect URL** generated by Arcade. This must be set as your X app's redirect URL.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+When you use tools that require X auth using your Arcade account credentials, Arcade will automatically use this X OAuth provider. If you have multiple X providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+
+
+
+## Using X auth in app code
+
+Use the X auth provider in your own agents and AI apps to get a user token for the X API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for X:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="x",
+ scopes=["tweet.read", "tweet.write", "users.read"],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-12}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade(); // Automatically finds the `ARCADE_API_KEY` env variable
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+let authResponse = await client.auth.start(userId, "x", [
+ "tweet.read",
+ "tweet.write",
+ "users.read",
+]);
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using X auth in custom tools
+
+You can use the pre-built [Arcade X MCP Server](/mcp-servers/social-communication/x) to quickly build agents and AI apps that interact with X.
+
+If the pre-built tools in the X MCP Server don't meet your needs, you can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the X API.
+
+Use the `X()` auth class to specify that a tool requires authorization with X. The `context.authorization.token` field will be automatically populated with the user's X token:
+
+```python {5-6,9-13,21}
+from typing import Annotated
+
+import httpx
+
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import X
+
+
+@tool(
+ requires_auth=X(
+ scopes=["tweet.read", "tweet.write", "users.read"],
+ )
+)
+async def post_tweet(
+ context: ToolContext,
+ tweet_text: Annotated[str, "The text content of the tweet you want to post"],
+) -> Annotated[str, "Success string and the URL of the tweet"]:
+ """Post a tweet to X (Twitter)."""
+ url = "https://api.x.com/2/tweets"
+ headers = {
+ "Authorization": f"Bearer {context.authorization.token}",
+ "Content-Type": "application/json",
+ }
+ payload = {"text": tweet_text}
+
+ async with httpx.AsyncClient() as client:
+ response = await client.post(url, headers=headers, json=payload)
+ response.raise_for_status()
+
+ tweet_id = response.json()["data"]["id"]
+ return f"Tweet with id {tweet_id} posted successfully. URL: https://x.com/x/status/{tweet_id}"
+```
diff --git a/app/en/home/sharing-with-end-users/custom-auth/zendesk/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/zendesk/page.mdx
new file mode 100644
index 000000000..8d07a6b2b
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/zendesk/page.mdx
@@ -0,0 +1,223 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+import { SignupLink } from "@/app/_components/analytics";
+
+# Zendesk
+
+
+ Arcade does not offer a default Zendesk Auth Provider. To use Zendesk auth,
+ you must create a [custom provider configuration](/home/auth-providers/oauth2)
+ as described below.
+
+
+The Zendesk auth provider enables tools and agents to call Zendesk APIs on behalf of a user.
+
+## What's documented here
+
+This page describes how to use and configure Zendesk auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade Zendesk MCP Server](/mcp-servers/customer-support/zendesk), which provides pre-built tools for interacting with Zendesk services
+- Your [app code](#using-zendesk-auth-in-app-code) that needs to call Zendesk APIs
+- Or, your [custom tools](#using-zendesk-auth-in-custom-tools) that need to call Zendesk APIs
+
+## Create a Zendesk app
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+### Additional guides
+
+The following three guides from Zendesk will be helpful additional information as you progress through this guide:
+
+1. [Using OAuth authentication with your application](https://support.zendesk.com/hc/en-us/articles/4408845965210-Using-OAuth-authentication-with-your-application)
+2. [Set up a global OAuth client](https://developer.zendesk.com/documentation/marketplace/building-a-marketplace-app/set-up-a-global-oauth-client/)
+3. [Getting a trial or sponsored account for development](https://developer.zendesk.com/documentation/api-basics/getting-started/getting-a-trial-or-sponsored-account-for-development/)
+
+### Creating a Zendesk app for Arcade
+
+1. Create your Organization in the [Zendesk Marketplace portal](https://apps.zendesk.com/).
+1. Create a Zendesk support account at https://www.zendesk.com/login . If you need a global OAuth client, then the subdomain MUST begin with "d3v-". You will need a global OAuth client if your app will use tools for multiple customers with their own Zendesk instances (multiple subdomains).
+1. In [the Admin Center](https://support.zendesk.com/hc/en-us/articles/4581766374554#topic_hfg_dyz_1hb), click "Apps and integrations" in the sidebar, then select APIs > OAuth clients > Add OAuth client.
+ - Ensure your identifier is prefixed with "zdg-" if you will need a global OAuth client.
+ - Select "Public" for "Client kind".
+ - Use the redirect URL generated by Arcade (see below) as your "Redirect URL".
+1. Copy and store your identifier for later. This will be your **Client ID**.
+1. Copy and store your generated secret for later. This will be your **Client Secret**.
+1. (Only for Global OAuth client) Request a global OAuth client.
+ - First, you will need to request a sponsored account and wait for approval from Zendesk. You can request a sponsored account [here](https://developer.zendesk.com/documentation/api-basics/getting-started/getting-a-trial-or-sponsored-account-for-development/#requesting-a-sponsored-test-account).
+ - When filling out the sponsored account request form, ensure you select "App Developer / ISV" as your Developer Type.
+ - After you have a sponsored account, sign into the [Zendesk Marketplace portal](https://apps.zendesk.com/)
+ - Organization > Global OAuth Request and fill out the form. Zendesk will typically review your request within 1 week.
+
+## Get your Zendesk subdomain
+
+Your Zendesk subdomain is the value before the `.zendesk.com` part. For example, if your Zendesk domain is `https://d3v-acme-inc.zendesk.com`, your Zendesk subdomain is `d3v-acme-inc`. Take note of your Zendesk subdomain. You will need this value in the next steps.
+
+## Set the Zendesk Subdomain Secret
+
+Set the `ZENDESK_SUBDOMAIN` secret in the [Arcade Dashboard](https://api.arcade.dev/dashboard/auth/secrets).
+
+## Configuring Zendesk Auth
+
+
+
+
+
+
+### Configure Zendesk Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+Navigate to the [Arcade Dashboard](https://api.arcade.dev/dashboard/auth/oauth) OAuth Providers page.
+
+#### Navigate to the Add Custom Provider page
+
+- Click **Add OAuth Provider** in the top right corner.
+- Click the **Custom Provider** tab at the top.
+
+#### Enter the provider details
+
+- ID: `zendesk`
+- Description: ``
+- Client ID: `` (This is prefixed with `zdg-` if you are using a global OAuth client)
+- Client Secret: ``
+- Authorization Endpoint: `https://.zendesk.com/oauth/authorizations/new`
+- Token Endpoint: `https://.zendesk.com/oauth/tokens`
+- PKCE Settings:
+ - Enable PKCE: `enabled`
+ - PKCE Method: `S256` (Default)
+- Authorization Settings:
+ - Response Type: `code` (Default)
+ - Scope: `{{scopes}} {{existing_scopes}}` (Default)
+- Token Settings:
+ - Authentication Method: `Client Secret Basic` (Default)
+ - Response Content Type: `application/json` (Default)
+- Refresh Token Settings:
+ - Refresh Token Endpoint: `https://.zendesk.com/oauth/tokens`
+ - Authentication Method: `Client Secret Basic` (Default)
+ - Response Content Type: `application/json`
+- Token Introspection Settings:
+ - Enable Token Introspection: `disabled` (Default)
+
+Note the **Redirect URL** generated by Arcade. This must be set as your Zendesk app's redirect URL.
+
+
+
+
+
+
+
+## Using Zendesk auth in app code
+
+Use the Zendesk auth provider you just created in your own agents and AI apps to get a user token for Zendesk APIs. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for Zendesk APIs:
+
+
+
+
+```python {6-10}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id="{arcade_user_id}",
+ provider="zendesk",
+ scopes=["read_account"],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-11}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade(); // Automatically finds the `ARCADE_API_KEY` env variable
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+let authResponse = await client.auth.start(userId, {
+ provider: "zendesk",
+ scopes: ["read_account"],
+});
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using Zendesk auth in custom tools
+
+If the [Arcade Zendesk MCP Server](/mcp-servers/customer-support/zendesk) does not meet your needs, you can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with Zendesk APIs.
+
+Use the `OAuth2()` auth class to specify that a tool requires authorization with Zendesk. The `context.authorization.token` field will be automatically populated with the user's Zendesk token:
+
+```python
+from typing import Annotated, Any
+
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import OAuth2
+
+import httpx
+
+
+@tool(
+ requires_auth=OAuth2(id="zendesk", scopes=["read"]),
+ requires_secrets=["ZENDESK_SUBDOMAIN"],
+)
+async def get_tickets(
+ context: ToolContext
+) -> Annotated[dict[str, Any], "Recent tickets from Zendesk"]:
+ """Get recent tickets from Zendesk including basic ticket information"""
+ token = context.get_auth_token_or_empty()
+ subdomain = context.get_secret("ZENDESK_SUBDOMAIN")
+ url = f"https://{subdomain}.zendesk.com/api/v2/tickets.json"
+ headers = {
+ "Authorization": f"Bearer {token}",
+ "Content-Type": "application/json",
+ "Accept": "application/json",
+ }
+
+ async with httpx.AsyncClient() as client:
+ resp = await client.get(url, headers=headers)
+ resp.raise_for_status()
+ data = resp.json()
+
+ return {"tickets": data}
+```
diff --git a/app/en/home/sharing-with-end-users/custom-auth/zoho/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/zoho/page.mdx
new file mode 100644
index 000000000..c1edb0f3c
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/zoho/page.mdx
@@ -0,0 +1,357 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Zoho
+
+The Zoho auth provider enables tools and agents to call [Zoho APIs](https://www.zoho.com/developer/) on behalf of a user using OAuth 2.0 authentication.
+
+
+ Want to quickly get started with Zoho in your agent or AI app? Check out the
+ pre-built Arcade Zoho MCP Servers: - [Zoho Books API MCP
+ Server](/mcp-servers/payments/zoho-books-api) - [Zoho Creator API MCP
+ Server](/mcp-servers/development/zoho-creator-api)
+
+
+### What's documented here
+
+This page describes how to use and configure Zoho auth with Arcade.
+
+This auth provider is used by:
+
+- The [Arcade Zoho Books API MCP Server](/mcp-servers/payments/zoho-books-api), which provides pre-built tools for interacting with Zoho Books
+- The [Arcade Zoho Creator API MCP Server](/mcp-servers/development/zoho-creator-api), which provides pre-built tools for interacting with Zoho Creator
+- Your [app code](#using-zoho-auth-in-app-code) that needs to call Zoho APIs
+- Or, your [custom tools](#using-zoho-auth-in-custom-tools) that need to call Zoho APIs
+
+## Configuring Zoho auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Zoho app credentials. This way, your users will see your application's name requesting permission.
+
+Before showing how to configure your Zoho app credentials, let's go through the steps to create a Zoho app.
+
+### Create a Zoho app
+
+To integrate with Zoho's APIs, you'll need to set up OAuth 2.0 authentication by creating a client in the Zoho API Console:
+
+
+
+#### Access the Zoho API Console
+
+Navigate to the [Zoho API Console](https://api-console.zoho.com/) and sign in with your existing Zoho credentials or create a new account.
+
+#### Create a new client
+
+1. Once logged in, click on "Add Client" or "Get Started"
+2. Select "Server-based Applications" as the client type
+3. Fill in the required details:
+ - **Client Name**: Choose a descriptive name for your application
+ - **Homepage URL**: Provide the URL of your application's website
+ - **Authorized Redirect URIs**: Add the redirect URL generated by Arcade (see configuration section below)
+
+#### Configure client settings
+
+1. After creating your client, you'll receive a `Client ID` and `Client Secret`
+2. Configure the required scopes for your application based on which Zoho services you'll be using:
+ - For Zoho Books: `ZohoBooks.fullaccess.all` or specific scopes like `ZohoBooks.invoices.READ`
+ - For Zoho Creator: `ZohoCreator.meta.READ`, `ZohoCreator.report.READ`, etc.
+ - Add other scopes as needed for your use case
+
+#### Note your data center
+
+Zoho operates in multiple data centers. Make note of which data center your account uses, as this affects the API endpoints:
+
+- **US**: `.com` (e.g., `https://accounts.zoho.com`)
+- **EU**: `.eu` (e.g., `https://accounts.zoho.eu`)
+- **India**: `.in` (e.g., `https://accounts.zoho.in`)
+- **Australia**: `.com.au` (e.g., `https://accounts.zoho.com.au`)
+- **China**: `.com.cn` (e.g., `https://accounts.zoho.com.cn`)
+
+
+
+For detailed instructions, refer to Zoho's official documentation:
+
+- [Zoho OAuth 2.0 Authentication](https://www.zoho.com/accounts/protocol/oauth.html)
+- [Zoho Books API Documentation](https://www.zoho.com/books/api/v3/)
+- [Zoho Creator API Documentation](https://www.zoho.com/creator/help/api/v2/)
+
+Next, add the Zoho app to Arcade.
+
+## Configuring your own Zoho Auth Provider in Arcade
+
+
+
+
+### Configure Zoho Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **OAuth 2.0** tab at the top.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "arcade-zoho").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Zoho client.
+- Configure the OAuth 2.0 endpoints (adjust the domain based on your data center):
+ - **Authorization URL**: `https://accounts.zoho.com/oauth/v2/auth` (or `.eu`, `.in`, `.com.au`, `.com.cn`)
+ - **Token URL**: `https://accounts.zoho.com/oauth/v2/token` (or `.eu`, `.in`, `.com.au`, `.com.cn`)
+- Note the **Redirect URL** generated by Arcade. This must be set as your Zoho client's authorized redirect URI.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+
+
+
+
+### Configure Zoho Auth Using Configuration File
+
+
+ This method is only available when you are [self-hosting the
+ engine](/home/deployment/on-prem-mcp)
+
+
+
+
+#### Set environment variables
+
+Set the following environment variables:
+
+```bash
+export ZOHO_CLIENT_ID=""
+export ZOHO_CLIENT_SECRET=""
+```
+
+Or, you can set these values in a `.env` file:
+
+```bash
+ZOHO_CLIENT_ID=""
+ZOHO_CLIENT_SECRET=""
+```
+
+#### Edit the Engine configuration
+
+Edit the `engine.yaml` file and add a new item to the `auth.providers` section.
+
+For US data center:
+
+```yaml
+auth:
+ providers:
+ - id: arcade-zoho
+ description: Zoho OAuth 2.0 provider
+ enabled: true
+ type: oauth2
+ client_id: ${env:ZOHO_CLIENT_ID}
+ client_secret: ${env:ZOHO_CLIENT_SECRET}
+ oauth2:
+ scope_delimiter: ","
+ authorize_request:
+ endpoint: "https://accounts.zoho.com/oauth/v2/auth"
+ params:
+ response_type: code
+ client_id: "{{client_id}}"
+ redirect_uri: "{{redirect_uri}}"
+ scope: "{{scopes}}"
+ state: "{{state}}"
+ access_type: offline
+ prompt: consent
+ token_request:
+ endpoint: "https://accounts.zoho.com/oauth/v2/token"
+ auth_method: client_secret_post
+ params:
+ grant_type: authorization_code
+ client_id: "{{client_id}}"
+ client_secret: "{{client_secret}}"
+ redirect_uri: "{{redirect_uri}}"
+ response_content_type: application/json
+ refresh_request:
+ endpoint: "https://accounts.zoho.com/oauth/v2/token"
+ auth_method: client_secret_post
+ params:
+ grant_type: refresh_token
+ client_id: "{{client_id}}"
+ client_secret: "{{client_secret}}"
+ response_content_type: application/json
+```
+
+
+ If your Zoho account is in a different data center (EU, India, Australia, or
+ China), replace `accounts.zoho.com` with the appropriate domain: - EU:
+ `accounts.zoho.eu` - India: `accounts.zoho.in` - Australia:
+ `accounts.zoho.com.au` - China: `accounts.zoho.com.cn`
+
+
+
+
+
+
+
+When you use tools that require Zoho auth using your Arcade account credentials, Arcade will automatically use this Zoho OAuth provider. If you have multiple Zoho providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+## Using Zoho auth in app code
+
+Use the Zoho auth provider in your own agents and AI apps to get a user token for Zoho APIs. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for Zoho APIs:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="arcade-zoho",
+ scopes=["ZohoBooks.fullaccess.all"]
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-11}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade();
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+const authResponse = await client.auth.start(userId, "arcade-zoho", [
+ "ZohoBooks.fullaccess.all",
+]);
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using Zoho auth in custom tools
+
+You can use the pre-built Arcade Zoho MCP Servers ([Zoho Books](/mcp-servers/payments/zoho-books-api), [Zoho Creator](/mcp-servers/development/zoho-creator-api)) to quickly build agents and AI apps that interact with Zoho.
+
+If the pre-built tools don't meet your needs, you can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with Zoho APIs.
+
+Use the `OAuth2()` auth class to specify that a tool requires authorization with Zoho. The `context.authorization.token` field will be automatically populated with the user's Zoho token:
+
+```python {8-12,22}
+from typing import Annotated
+
+import httpx
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import OAuth2
+
+
+@tool(
+ requires_auth=OAuth2(
+ provider_id="arcade-zoho",
+ scopes=["ZohoBooks.invoices.READ"]
+ )
+)
+async def get_zoho_invoices(
+ context: ToolContext,
+ organization_id: Annotated[str, "The Zoho Books organization ID."],
+) -> Annotated[dict, "The list of invoices."]:
+ """
+ Retrieve invoices from Zoho Books.
+ """
+ url = f"https://books.zoho.com/api/v3/invoices?organization_id={organization_id}"
+ headers = {
+ "Authorization": f"Zoho-oauthtoken {context.authorization.token}",
+ }
+
+ async with httpx.AsyncClient() as client:
+ response = await client.get(url, headers=headers)
+ response.raise_for_status()
+ return dict(response.json())
+```
+
+## Available Scopes
+
+Zoho supports various OAuth scopes that determine the level of access your application has. Scopes vary by Zoho service:
+
+### Zoho Books Scopes
+
+- `ZohoBooks.fullaccess.all` - Full access to all Zoho Books data
+- `ZohoBooks.invoices.READ` - Read access to invoices
+- `ZohoBooks.invoices.CREATE` - Create invoices
+- `ZohoBooks.invoices.UPDATE` - Update invoices
+- `ZohoBooks.invoices.DELETE` - Delete invoices
+- `ZohoBooks.contacts.READ` - Read access to contacts
+- `ZohoBooks.contacts.CREATE` - Create contacts
+- And many more...
+
+### Zoho Creator Scopes
+
+- `ZohoCreator.meta.READ` - Read access to application metadata
+- `ZohoCreator.report.READ` - Read access to reports
+- `ZohoCreator.report.CREATE` - Create records in reports
+- `ZohoCreator.report.UPDATE` - Update records in reports
+- `ZohoCreator.report.DELETE` - Delete records from reports
+- And many more...
+
+For a complete list of available scopes, refer to the official documentation:
+
+- [Zoho Books API Scopes](https://www.zoho.com/books/api/v3/oauth/#scopes)
+- [Zoho Creator API Scopes](https://www.zoho.com/creator/help/api/v2/oauth-scopes.html)
+
+## Data Center Considerations
+
+Zoho operates in multiple data centers around the world. When making API calls, you must use the correct domain for your account's data center:
+
+| Data Center | Accounts Domain | API Domain Example |
+| ----------- | ---------------------- | ------------------------------------------ |
+| US | `accounts.zoho.com` | `books.zoho.com`, `creator.zoho.com` |
+| EU | `accounts.zoho.eu` | `books.zoho.eu`, `creator.zoho.eu` |
+| India | `accounts.zoho.in` | `books.zoho.in`, `creator.zoho.in` |
+| Australia | `accounts.zoho.com.au` | `books.zoho.com.au`, `creator.zoho.com.au` |
+| China | `accounts.zoho.com.cn` | `books.zoho.com.cn`, `creator.zoho.com.cn` |
+
+Make sure to configure your OAuth provider and API calls to use the correct domain for your account's data center.
diff --git a/app/en/home/sharing-with-end-users/custom-auth/zoom/page.mdx b/app/en/home/sharing-with-end-users/custom-auth/zoom/page.mdx
new file mode 100644
index 000000000..f288a1eae
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/custom-auth/zoom/page.mdx
@@ -0,0 +1,187 @@
+import { Tabs, Callout, Steps } from "nextra/components";
+
+# Zoom
+
+
+ At this time, Arcade does not offer a default Zoom Auth Provider. To use Zoom
+ auth, you must create a custom Auth Provider with your own Zoom OAuth 2.0
+ credentials as described below.
+
+
+The Zoom auth provider enables tools and agents to call the Zoom API on behalf of a user.
+
+### What's documented here
+
+This page describes how to use and configure Zoom auth with Arcade.
+
+This auth provider is used by:
+
+- Your [app code](#using-zoom-auth-in-app-code) that needs to call Zoom APIs
+- Or, your [custom tools](#using-zoom-auth-in-custom-tools) that need to call Zoom APIs
+
+## Configuring Zoom auth
+
+
+ When using your own app credentials, make sure you configure your project to
+ use a [custom user
+ verifier](/home/auth/secure-auth-production#build-a-custom-user-verifier).
+ Without this, your end-users will not be able to use your app or agent in
+ production.
+
+
+In a production environment, you will most likely want to use your own Zoom app credentials. This way, your users will see your application's name requesting permission.
+
+
+Before showing how to configure your Zoom app credentials, let's go through the steps to create a Zoom app.
+
+### Create a Zoom app
+
+- Follow Zoom's guide to [registering an app](https://developers.zoom.us/docs/integrations/create/) on the Zoom marketplace
+- Set the redirect URL to the redirect URL generated by Arcade (see below) and enable Strict Mode
+- Enable the Zoom features and permissions (scopes) that your app needs
+- Copy the client ID and client secret to use below
+
+Next, add the Zoom app to Arcade.
+
+## Configuring your own Zoom Auth Provider in Arcade
+
+
+
+
+
+
+### Configure Zoom Auth Using the Arcade Dashboard GUI
+
+
+
+#### Access the Arcade Dashboard
+
+To access the Arcade Cloud dashboard, go to [api.arcade.dev/dashboard](https://api.arcade.dev/dashboard). If you are self-hosting, by default the dashboard will be available at http://localhost:9099/dashboard. Adjust the host and port number to match your environment.
+
+#### Navigate to the OAuth Providers page
+
+- Under the **Connections** section of the Arcade Dashboard left-side menu, click **Connected Apps**.
+- Click **Add OAuth Provider** in the top right corner.
+- Select the **Included Providers** tab at the top.
+- In the **Provider** dropdown, select **Zoom**.
+
+#### Enter the provider details
+
+- Choose a unique **ID** for your provider (e.g. "my-zoom-provider").
+- Optionally enter a **Description**.
+- Enter the **Client ID** and **Client Secret** from your Zoom app.
+- Note the **Redirect URL** generated by Arcade. This must be set as your Zoom app's redirect URL.
+
+#### Create the provider
+
+Hit the **Create** button and the provider will be ready to be used.
+
+
+
+When you use tools that require Zoom auth using your Arcade account credentials, Arcade will automatically use this Zoom OAuth provider. If you have multiple Zoom providers, see [using multiple auth providers of the same type](/home/auth-providers#using-multiple-providers-of-the-same-type) for more information.
+
+
+
+
+## Using Zoom auth in app code
+
+Use the Zoom auth provider in your own agents and AI apps to get a user token for the Zoom API. See [authorizing agents with Arcade](/home/auth/how-arcade-helps) to understand how this works.
+
+Use `client.auth.start()` to get a user token for the Zoom API:
+
+
+
+
+```python {8-12}
+from arcadepy import Arcade
+
+client = Arcade() # Automatically finds the `ARCADE_API_KEY` env variable
+
+user_id = "{arcade_user_id}"
+
+# Start the authorization process
+auth_response = client.auth.start(
+ user_id=user_id,
+ provider="zoom",
+ scopes=["meeting:read:list_upcoming_meetings"],
+)
+
+if auth_response.status != "completed":
+ print("Please complete the authorization challenge in your browser:")
+ print(auth_response.url)
+
+# Wait for the authorization to complete
+auth_response = client.auth.wait_for_completion(auth_response)
+
+token = auth_response.context.token
+# Do something interesting with the token...
+```
+
+
+
+
+
+```javascript {8-10}
+import { Arcade } from "@arcadeai/arcadejs";
+
+const client = new Arcade(); // Automatically finds the `ARCADE_API_KEY` env variable
+
+const userId = "{arcade_user_id}";
+
+// Start the authorization process
+let authResponse = await client.auth.start(userId, "zoom", [
+ "meeting:read:list_upcoming_meetings",
+]);
+
+if (authResponse.status !== "completed") {
+ console.log("Please complete the authorization challenge in your browser:");
+ console.log(authResponse.url);
+}
+
+// Wait for the authorization to complete
+authResponse = await client.auth.waitForCompletion(authResponse);
+
+const token = authResponse.context.token;
+// Do something interesting with the token...
+```
+
+
+
+
+
+## Using Zoom auth in custom tools
+
+You can author your own [custom tools](/home/build-tools/create-a-mcp-server) that interact with the Zoom API.
+
+Use the `Zoom()` auth class to specify that a tool requires authorization with Zoom. The `context.authorization.token` field will be automatically populated with the user's Zoom token:
+
+```python {5-6,9-13,23}
+from typing import Annotated, Optional
+
+import httpx
+
+from arcade_tdk import ToolContext, tool
+from arcade_tdk.auth import Zoom
+
+
+@tool(
+ requires_auth=Zoom(
+ scopes=["meeting:read:list_upcoming_meetings"],
+ )
+)
+async def list_upcoming_meetings(
+ context: ToolContext,
+ user_id: Annotated[
+ Optional[str],
+ "The user's user ID or email address. Defaults to 'me' for the current user.",
+ ] = "me",
+) -> Annotated[dict, "List of upcoming meetings within the next 24 hours"]:
+ """List a Zoom user's upcoming meetings within the next 24 hours."""
+ url = f"https://api.zoom.us/v2/users/{user_id}/upcoming_meetings"
+ headers = {"Authorization": f"Bearer {context.authorization.token}"}
+
+ async with httpx.AsyncClient() as client:
+ response = await client.get(url, headers=headers)
+ response.raise_for_status()
+ return response.json()
+```
diff --git a/app/en/home/sharing-with-end-users/multi-user-auth/page.mdx b/app/en/home/sharing-with-end-users/multi-user-auth/page.mdx
new file mode 100644
index 000000000..4895d75a9
--- /dev/null
+++ b/app/en/home/sharing-with-end-users/multi-user-auth/page.mdx
@@ -0,0 +1,8 @@
+---
+title: "Set-up secure multi-user auth for your app"
+description: "Learn how to set up secure multi-user authentication for your application"
+---
+
+# Set-up secure multi-user auth for your app
+
+Coming soon!
diff --git a/app/en/home/status-page/page.mdx b/app/en/home/status-page/page.mdx
new file mode 100644
index 000000000..25d2f5862
--- /dev/null
+++ b/app/en/home/status-page/page.mdx
@@ -0,0 +1,7 @@
+# Status
+
+View the current status of Arcade services.
+
+## Overview
+
+This page shows the current operational status of all Arcade services.
\ No newline at end of file
diff --git a/app/en/home/tool-calling-intro/page.mdx b/app/en/home/tool-calling-intro/page.mdx
new file mode 100644
index 000000000..749e2f6f9
--- /dev/null
+++ b/app/en/home/tool-calling-intro/page.mdx
@@ -0,0 +1,31 @@
+# Tool Calling Introduction
+
+This is a placeholder page for an introduction to tool calling.
+
+## Overview
+
+Learn the fundamentals of tool calling with Arcade and how it enhances AI applications.
+
+## What is Tool Calling?
+
+Tool calling allows AI models to interact with external systems and APIs to perform actions beyond text generation.
+
+## Key Concepts
+
+- **Tools**: Functions that can be called by AI models
+- **Schemas**: Descriptions of tool parameters and return values
+- **Authorization**: Managing access to authenticated tools
+- **Context**: Runtime data passed to tools
+
+## Benefits
+
+- Extend AI capabilities beyond text
+- Connect to real-world systems
+- Perform actions on behalf of users
+- Access live data and services
+
+## Next Steps
+
+- [Error Handling](/en/home/error-handling)
+- [Tool Formats](/en/home/tool-formats)
+- [Authorized Tool Calling](/en/home/authorized-tool-calling)
\ No newline at end of file
diff --git a/app/en/home/turn-api-to-mcp/page.mdx b/app/en/home/turn-api-to-mcp/page.mdx
new file mode 100644
index 000000000..9e25c3671
--- /dev/null
+++ b/app/en/home/turn-api-to-mcp/page.mdx
@@ -0,0 +1,3 @@
+# Turn an external API into a MCP Server
+
+Transform external APIs into MCP servers for use in agents.
\ No newline at end of file
diff --git a/app/en/home/use-tools/_meta.tsx b/app/en/home/use-tools/_meta.tsx
deleted file mode 100644
index 7661d8b0b..000000000
--- a/app/en/home/use-tools/_meta.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import type { MetaRecord } from "nextra";
-
-export default {
- "tools-overview": "Introduction",
- "get-tool-definitions": "Tool formats",
- "types-of-tools": "Types of tools",
- "error-handling": "Error handling",
-} satisfies MetaRecord;
diff --git a/app/en/home/vercelai/_meta.tsx b/app/en/home/vercelai/_meta.tsx
deleted file mode 100644
index 6305a7f2b..000000000
--- a/app/en/home/vercelai/_meta.tsx
+++ /dev/null
@@ -1,3 +0,0 @@
-export default {
- "using-arcade-tools": "Using Arcade tools",
-};
diff --git a/app/en/home/what-is-agent/_meta.tsx b/app/en/home/what-is-agent/_meta.tsx
new file mode 100644
index 000000000..5ace1f9a3
--- /dev/null
+++ b/app/en/home/what-is-agent/_meta.tsx
@@ -0,0 +1,4 @@
+export default {
+ "why-agents-call-tools": "Why and how do agents call tools",
+ "intro-to-tag": "Intro to TAG",
+};
diff --git a/app/en/home/what-is-agent/intro-to-tag/page.mdx b/app/en/home/what-is-agent/intro-to-tag/page.mdx
new file mode 100644
index 000000000..2229639cf
--- /dev/null
+++ b/app/en/home/what-is-agent/intro-to-tag/page.mdx
@@ -0,0 +1,3 @@
+# Intro to TAG
+
+Coming soon.
\ No newline at end of file
diff --git a/app/en/home/what-is-agent/why-agents-call-tools/page.mdx b/app/en/home/what-is-agent/why-agents-call-tools/page.mdx
new file mode 100644
index 000000000..40df4c774
--- /dev/null
+++ b/app/en/home/what-is-agent/why-agents-call-tools/page.mdx
@@ -0,0 +1,3 @@
+# Why and how do agents call tools?
+
+Coming soon.
\ No newline at end of file
diff --git a/app/en/home/why-agents-call-tools/page.mdx b/app/en/home/why-agents-call-tools/page.mdx
new file mode 100644
index 000000000..7efa78eb0
--- /dev/null
+++ b/app/en/home/why-agents-call-tools/page.mdx
@@ -0,0 +1,7 @@
+# Why and how do agents call tools?
+
+Learn why agents need tools and how tool calling works.
+
+## Overview
+
+Understand the relationship between agents and tools.