Building AI agents that can interact with documents represents a significant leap from basic chatbots to practical workflow automation. While AI models excel at generating and analyzing text, they typically lack the ability to directly create, edit, or manage documents in Google Workspace. This limitation prevents teams from automating document-heavy workflows that consume hours of manual work daily.
Arcade's Google Docs toolkit provides a pre-built set of tools for interacting with Google Docs, making it easy to build agents and AI apps that can create, update, list, and delete documents. This article walks through building a production-ready document editor assistant that can autonomously manage Google Docs on behalf of users, complete with secure authentication and multi-user support.
Overview of Arcade's Document Automation Architecture
AI agents need native API integrations, not hacky browser automation. Using official APIs and standard auth flows through code rather than trying to fake a web UI login is more robust and avoids the arms race of trying to dodge anti-bot measures. Arcade addresses this by providing a secure authentication layer between AI agents and Google Docs APIs.
The platform handles three critical challenges:
- OAuth Challenges: Managing Google's OAuth 2.0 flow for document access
- Token Management: Securely storing and refreshing access tokens for each user
- Permission Scoping: Ensuring agents only access documents with appropriate permissions
This toolkit currently requires a self-hosted instance of Arcade, which provides complete control over authentication flows and enables enterprise features like custom domains and audit logging.
Setting Up Your Development Environment
Prerequisites
Before starting, ensure you have:
- An Arcade.dev account with API key (Get started here)
- Google Cloud Console project with OAuth 2.0 credentials
- Python 3.10+ installed
- Access to deploy a self-hosted Arcade Engine
Installing the Arcade SDK
Start by setting up your Python environment and installing necessary packages:
# Create and activate virtual environment
python -m venv arcade-env
source arcade-env/bin/activate # On Windows: arcade-env\Scripts\activate
# Install Arcade packages
pip install arcade-mcp arcadepy
Configure your environment variables:
export ARCADE_API_KEY="your_arcade_api_key"
export GOOGLE_CLIENT_ID="your_google_client_id"
export GOOGLE_CLIENT_SECRET="your_google_client_secret"
Configuring the Google Docs Toolkit
Setting Up Google OAuth Provider
Configure Google auth provider for production with proper OAuth credentials and redirect URLs:
Access the Arcade Dashboard
To access the Arcade Cloud dashboard, go to 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 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.
Available Google Docs Tools
The toolkit currently includes four core tools: Google.GetDocumentById to retrieve documents, Google.InsertTextAtEndOfDocument to append text, Google.CreateBlankDocument to create new blank documents, and Google.CreateDocumentFromText to create documents with initial content.
Tool Specifications
| Tool Name | Description |
|---|---|
| GoogleDocs.WhoAmI | Get comprehensive user profile and Google Docs environment information. |
| GoogleDocs.GetDocumentById | Retrieve a Google Docs document by ID. |
| GoogleDocs.GetDocumentAsDocMD | Retrieve a Google Docs document by ID in DocMD format with metadata tags. |
| GoogleDocs.EditDocument | Edit a Google Docs document using natural language edit requests. |
| GoogleDocs.InsertTextAtEndOfDocument | Insert text at the end of a Google Docs document. |
| GoogleDocs.CreateBlankDocument | Create a new blank Google Docs document with a title. |
| GoogleDocs.CreateDocumentFromText | Create a new Google Docs document with specified text content. |
| GoogleDocs.SearchDocuments | Search for documents in the user's Google Drive. |
| GoogleDocs.SearchAndRetrieveDocuments | Search and retrieve the contents of Google documents in the user's Google Drive. |
| GoogleDocs.ListDocumentComments | List all comments on the specified Google Docs document. |
| GoogleDocs.CommentOnDocument | Comment on a specific document by its ID. |
Building the Document Editor Assistant
Core Assistant Implementation
Create a Python class that manages document operations with proper authentication:
from arcadepy import AsyncArcade
from typing import Dict, Any, Optional
import asyncio
class DocumentEditorAssistant:
def __init__(self):
self.client = AsyncArcade()
async def authenticate_user(self, user_id: str):
"""Handle OAuth flow for Google Calendar access"""
# Check if calendar tools require authorization
auth_response = await self.arcade.tools.authorize(
tool_name="Google.CreateBlankDocument",
user_id=user_id
)
if auth_response.status != "completed":
# User needs to complete OAuth flow
print(f"Authorize at: {auth_response.url}")
await self.arcade.auth.wait_for_completion(auth_response)
return {"authenticated": True}
async def create_document(self, user_id: str, title: str,
content: Optional[str] = None) -> Dict:
"""Create a new Google Doc with optional content"""
# Ensure authentication
auth_result = await self.authenticate_user(user_id)
if auth_result.get("authorization_required"):
return auth_result
# Choose appropriate tool based on content
if content:
tool_name = "Google.CreateDocumentFromText"
params = {"title": title, "text_content": content}
else:
tool_name = "Google.CreateBlankDocument"
params = {"title": title}
# Execute tool
result = await self.client.tools.execute(
tool_name=tool_name,
input=params,
user_id=user_id
)
return {"success": True, "document": result.output}
async def append_to_document(self, user_id: str, document_id: str,
text: str) -> Dict:
"""Append text to an existing document"""
# Ensure authentication
auth_result = await self.authenticate_user(user_id)
if auth_result.get("authorization_required"):
return auth_result
result = await self.client.tools.execute(
tool_name="Google.InsertTextAtEndOfDocument",
input={
"document_id": document_id,
"text_content": text
},
user_id=user_id
)
return {"success": True, "result": result.output}
async def get_document(self, user_id: str, document_id: str) -> Dict:
"""Retrieve document content"""
# Ensure authentication
auth_result = await self.authenticate_user(user_id)
if auth_result.get("authorization_required"):
return auth_result
result = await self.client.tools.execute(
tool_name="Google.GetDocumentById",
input={"document_id": document_id},
user_id=user_id
)
return {"success": True, "content": result.output}
Implementing Document Processing Workflows
Extend the assistant with intelligent document processing capabilities:
class IntelligentDocumentProcessor(DocumentEditorAssistant):
def __init__(self, llm_client):
super().__init__()
self.llm = llm_client
async def summarize_and_create_report(self, user_id: str,
source_doc_ids: list) -> Dict:
"""Read multiple documents and create a summary report"""
# Gather source documents
all_content = []
for doc_id in source_doc_ids:
doc_result = await self.get_document(user_id, doc_id)
if doc_result.get("success"):
all_content.append(doc_result["content"])
# Generate summary using LLM
summary_prompt = f"""
Analyze these documents and create an executive summary:
{' '.join(all_content)}
Include key findings, recommendations, and action items.
"""
summary = await self.llm.generate(summary_prompt)
# Create new report document
report_title = f"Executive Summary - {asyncio.get_event_loop().time()}"
return await self.create_document(
user_id=user_id,
title=report_title,
content=summary
)
async def collaborative_editing_session(self, user_id: str,
document_id: str,
instructions: str) -> Dict:
"""AI-assisted document editing based on instructions"""
# Retrieve current content
doc_result = await self.get_document(user_id, document_id)
if not doc_result.get("success"):
return doc_result
current_content = doc_result["content"]
# Generate improvements
edit_prompt = f"""
Current document content: {current_content}
User instructions: {instructions}
Provide the additional content to append to this document.
"""
new_content = await self.llm.generate(edit_prompt)
# Append improvements
return await self.append_to_document(
user_id=user_id,
document_id=document_id,
text=new_content
)
Integration with AI Frameworks
LangGraph Integration
Arcade offers methods to convert tools into Zod schemas, which is essential since LangGraph defines tools using Zod. Integrate your document assistant with LangGraph:
from langchain_arcade import ArcadeToolManager
# Initialize tool manager
manager = ArcadeToolManager(api_key=arcade_api_key)
# Get Google Docs tools
google_docs_tools = manager.get_tools(
tools=[
"Google.CreateBlankDocument",
"Google.CreateDocumentFromText",
"Google.InsertTextAtEndOfDocument",
"Google.GetDocumentById"
]
)
# Create LangGraph agent with document capabilities
from langgraph.graph import Graph
def create_document_agent():
graph = Graph()
# Add document processing nodes
graph.add_node("authenticate", authenticate_user)
graph.add_node("create_doc", create_document)
graph.add_node("edit_doc", edit_document)
graph.add_node("retrieve_doc", retrieve_document)
# Define edges based on document workflow
graph.add_edge("authenticate", "create_doc")
graph.add_edge("create_doc", "edit_doc")
graph.add_edge("edit_doc", "retrieve_doc")
return graph.compile()
Google ADK Integration
For Google's AI Development Kit users:
from google_adk_arcade.tools import get_arcade_tools
from google.adk import Agent, Runner
async def create_google_adk_document_agent():
client = AsyncArcade()
# Get Google Docs tools
docs_tools = await get_arcade_tools(
client,
tools=[
"Google.CreateDocumentFromText",
"Google.InsertTextAtEndOfDocument"
]
)
# Authorize tools for user
user_id = "user@example.com"
for tool in docs_tools:
result = await client.tools.authorize(
tool_name=tool.name,
user_id=user_id
)
if result.status != "completed":
print(f"Authorize at: {result.url}")
await client.auth.wait_for_completion(result)
# Create agent
document_agent = Agent(
model="gemini-2.0-flash",
name="document_editor",
instruction="Manage and edit Google Docs efficiently",
tools=docs_tools
)
return document_agent
Handling Multi-User Authentication
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. Implement secure multi-user document management:
class MultiUserDocumentManager:
def __init__(self):
self.arcade = AsyncArcade()
async def initialize_user_tools(self, user_id: str):
"""Cache user-specific tool configurations"""
# List available Google tools
googledocs_tools = await self.arcade.tools.list(
toolkit="GoogleDocs",
limit=30,
user_id=user_id
)
# collect the scopes
scopes = set()
for tool in googledocs_tools:
if tool.requirements.authorization.oauth2.scopes:
scopes |= set(tool.requirements.authorization.oauth2.scopes)
# start auth
auth_response = client.auth.start(user_id=user_id, scopes=list(scopes), provider="google")
# show the url to the user if needed
if auth_response.status != "complete":
print(f"Please click here to authorize: {auth_response.url}") # Wait for the authorization to complete
client.auth.wait_for_completion(auth_response)
async def process_document_request(self, user_id: str,
request: Dict) -> Dict:
"""Route document requests to appropriate tools"""
tools = await self.initialize_user_tools(user_id)
try:
# Map request to tool
tool_name = self.determine_tool(request)
params = self.parse_parameters(request)
result = await self.arcade.tools.execute(
tool_name=tool_name,
input=params,
user_id=user_id
)
return {"success": True, "data": result.output}
except Exception as e:
if getattr(e, "type", "") == "authorization_required":
return {
"success": False,
"authRequired": True,
"authUrl": getattr(e, "url", "")
}
raise
def determine_tool(self, request: Dict) -> str:
"""Map request actions to Google Docs tools"""
action_map = {
"create": "Google.CreateDocumentFromText",
"create_blank": "Google.CreateBlankDocument",
"append": "Google.InsertTextAtEndOfDocument",
"get": "Google.GetDocumentById"
}
return action_map.get(request.get("action"), "Google.GetDocumentById")
Advanced Use Cases
Automated Report Generation
Create a system that generates periodic reports from multiple documents:
async def generate_weekly_report(user_id: str, department: str):
"""Generate weekly department reports from various documents"""
assistant = DocumentEditorAssistant()
# Gather relevant documents
doc_ids = await get_department_documents(department)
# Process and analyze content
analysis = await analyze_documents(assistant, user_id, doc_ids)
# Create formatted report
report_content = format_weekly_report(analysis)
# Create and share report
result = await assistant.create_document(
user_id=user_id,
title=f"Weekly Report - {department} - {datetime.now().strftime('%Y-%m-%d')}",
content=report_content
)
return result
Template-Based Document Creation
Implement a template system for standardized documents:
class DocumentTemplateManager:
def __init__(self):
self.templates = {
"meeting_notes": self.meeting_notes_template,
"project_proposal": self.project_proposal_template,
"status_report": self.status_report_template
}
async def create_from_template(self, user_id: str,
template_name: str,
variables: Dict) -> Dict:
"""Create document from predefined template"""
if template_name not in self.templates:
return {"error": "Template not found"}
# Generate content from template
content = self.templates[template_name](variables)
# Create document
assistant = DocumentEditorAssistant()
return await assistant.create_document(
user_id=user_id,
title=variables.get("title", f"New {template_name}"),
content=content
)
def meeting_notes_template(self, vars: Dict) -> str:
"""Generate meeting notes template"""
return f"""
Meeting Notes
Date: {vars.get('date')}
Attendees: {', '.join(vars.get('attendees', []))}
Agenda:
{vars.get('agenda')}
Discussion Points:
{vars.get('discussion')}
Action Items:
{vars.get('action_items')}
Next Steps:
{vars.get('next_steps')}
"""
Monitoring and Observability
Track document operations for compliance and optimization:
class DocumentOperationMonitor:
def __init__(self):
self.metrics = {
"documents_created": 0,
"documents_edited": 0,
"documents_retrieved": 0,
"auth_attempts": 0,
"errors": 0
}
async def track_operation(self, user_id: str, operation: str,
success: bool):
"""Track document operations"""
if success:
self.metrics[f"documents_{operation}"] += 1
else:
self.metrics["errors"] += 1
# Send to monitoring system
await self.send_metrics({
"timestamp": datetime.now().isoformat(),
"user_id": self.hash_user_id(user_id),
"operation": operation,
"success": success,
"service": "google_docs"
})
def generate_health_report(self) -> Dict:
"""Generate system health metrics"""
total_ops = sum([
self.metrics["documents_created"],
self.metrics["documents_edited"],
self.metrics["documents_retrieved"]
])
return {
"status": "healthy",
"total_operations": total_ops,
"error_rate": self.metrics["errors"] / max(total_ops, 1),
"operations_breakdown": self.metrics
}
Conclusion
Building a document editor assistant with Arcade's Google Docs toolkit transforms how teams interact with their documentation. Less than 30% of AI projects reach production because agents can't access real systems. This disconnect between AI's intelligence and its ability to access real data and take action is why AI initiatives get stuck.
Arcade bridges this gap by providing secure, authenticated access to Google Docs through a production-ready toolkit. The platform handles OAuth challenges, token management, and multi-user authentication, allowing developers to focus on building intelligent document workflows rather than authentication infrastructure.
Key takeaways for successful implementation:
- Use self-hosted Arcade Engine for full control over document operations
- Implement proper error handling and token refresh mechanisms
- Cache frequently accessed documents to optimize performance
- Monitor all operations for compliance and debugging
- Design workflows that leverage AI for intelligent document processing
With these patterns and Arcade's infrastructure, your document editor assistant can move from proof-of-concept to production, automating document workflows that previously required manual intervention.
Start building your document assistant today by getting your Arcade API key and exploring the complete documentation. For additional support and examples, check out the GitHub repository or review the API reference.



