73 Smartsheet tools · 80 formulas · 5 LLM providers · 246 green tests · Full voice control · One conversation.
A community-built AI agent that speaks the Smartsheet API fluently — built for developers and power-users. Read, write, analyze, automate, share, and visualize — by just asking. BYOT (bring your own token) · server-side memory · audit log · real-time webhooks · MCP-ready.
Built on top of the official @smartsheet REST API v2.0 — community project, not affiliated with Smartsheet Inc.
Quick Start · The Power · What You Can Say · 73 Tools · MCP Server · Tests · Deploy
You know the drill. Open Smartsheet. Navigate. Click. Scroll. Find the right column. Write a formula. Test it. Fix it. Click again. Repeat for every single sheet.
What if you could just... say it?
| Before | After |
|---|---|
| Open sheet, scroll to row 47, find the column, manually edit the cell | "Update row 47, set Status to Done" |
| Google the SUMIFS syntax, write it, debug the brackets | "What's the total revenue for Q1?" |
| Navigate to sharing settings, add email, choose permission | "Share this sheet with Marie as Editor" |
| Open 3 sheets, cross-reference manually, copy-paste values | "Pull the budget total from the Finance sheet into this one" |
| Export data, open another tool, build a chart | "Generate a visual of my project timeline" |
Ask a question in plain English (or French). The AI reads your sheet, understands the structure, and answers with formatted tables, rich Markdown, and inline images. Not raw JSON. Not a wall of text. Clean, structured, actionable answers.
Every Smartsheet operation — from reading a cell to creating a webhook — is a tool the agent can call autonomously. You describe what you want. The agent decides which API calls to make, chains them together, and delivers the result. You never touch the API.
The agent doesn't just know Smartsheet formulas — it thinks in them. SUMIFS, INDEX(COLLECT(...)), cross-sheet {{references}}, hierarchy functions like CHILDREN() and ANCESTORS(). Ask for a formula and get the exact Smartsheet syntax, not a generic spreadsheet guess.
Click the mic. Speak. The agent transcribes, understands, and executes. Voice-first, keyboard-optional. Your Smartsheet has ears now.
Responses flow token by token, just like ChatGPT. You see the agent thinking in real time. No waiting for a wall of text — words appear as they're generated. The app breathes.
After every response, the agent suggests 2-4 follow-up actions as clickable chips. You never face a blank input. The AI guides you forward.
Jump between sheets instantly from a dropdown in the header. No disconnecting, no re-configuring. Multi-sheet workflows in one session.
Every conversation is saved locally and accessible from a sidebar. Reload past analyses, formulas, and decisions anytime. Your Smartsheet memory never fades.
Every tool call the agent makes is visible in real-time. You see the API call, the parameters, the response. Full transparency. Full control. No black box.
Need a diagram? A chart concept? A visual representation of your data architecture? The agent generates DALL-E 3 images and live Chart.js bar/line/pie/doughnut/scatter charts directly in the conversation. Your chat is a canvas.
Five LLM providers, one chat. Switch model mid-conversation — the context follows you. The agent keeps the same tool repertoire and the same Smartsheet expert prompt no matter which brain you plug in.
| Provider | What it's great at | Models exposed |
|---|---|---|
| OpenAI | The reference. Best tool-calling reliability + DALL-E 3 image gen. | gpt-4o, gpt-4o-mini, gpt-4-turbo |
| Anthropic | Long-form analysis, careful reasoning, dense tables. | claude-3-5-sonnet, claude-3-5-haiku, claude-3-opus |
| OpenRouter | One API key, hundreds of models. Try Llama, Gemini, DeepSeek without managing extra keys. | Any OpenRouter slug |
| Mistral | EU-hosted, fast, cost-efficient. | mistral-large-latest, mistral-small-latest |
| Groq | Sub-second token speed thanks to LPU inference. | llama-3.3-70b-versatile, mixtral-8x7b |
The header dropdown lists only the providers whose key is detected in .env — set just the ones you actually have.
A live token-usage counter is displayed under the chat for the active provider, and a per-session rate-limiter (60 LLM calls / min, 120 WebSocket frames / min) protects you from runaway loops.
The server isn't a stateless proxy. It owns a small SQLite store so your account remembers things across sessions and tabs:
- Conversations — auto-saved on every message, reloadable from the sidebar (with optional auto-generated titles).
- Favorites — pin sheets to the header for one-click switching.
- Audit log — every tool call (especially destructive ones) is timestamped and stored.
GET /api/auditandGET /api/exportgive you the full history (RGPD-friendly). - Webhook events — incoming Smartsheet webhooks land in
POST /api/smartsheet-webhook, are persisted, and fan out in real time to every active WebSocket session that pinned the affected sheet. - Watch mode — the UI can subscribe to a sheet and surface new rows / changes the moment they happen.
Combined with the per-session token bucket and Smartsheet 429 retry-with-backoff, the backend stays steady under fast-fire conversations.
pip install -r requirements.txtcp .env.example .envSMARTSHEET_TOKEN=your_smartsheet_api_token
SHEET_ID=your_default_sheet_id
OPENAI_API_KEY=sk-...Smartsheet API token — app.smartsheet.com > Personal Settings > API Access
Sheet ID — Open any sheet, check the URL or go to File > Properties
uvicorn backend.app:app --reload --port 8000Open http://localhost:8000 — hit Quick Connect — start talking.
That's it. Three commands. You're in.
Every one of these is a real command the agent executes.
"Show me the full structure of my sheet as a table"
"Read rows 1 to 50 and give me a summary"
"What are the 10 largest amounts in the Budget column?"
"Are there any errors or inconsistencies in my data?"
"Write a SUMIFS formula to total sales by region"
"Create a cross-sheet formula that pulls the status from the Projects sheet"
"What's the correct syntax for INDEX(COLLECT(...)) with two criteria?"
"Add a PICKLIST column 'Priority' with options High, Medium, Low"
"Move completed rows to the Archive sheet"
"Who has access to this sheet? Show me the permissions"
"Generate an image that illustrates my sheet architecture"
"Create a visual for the project tracking dashboard"
73 tools organized in 16 categories. The agent picks the right ones automatically.
Account & Navigation — 10 tools
| Tool | What it does |
|---|---|
get_current_user |
Your Smartsheet profile |
list_sheets |
Every sheet you have access to |
search |
Search across your entire account |
search_sheet |
Search within a specific sheet |
list_workspaces |
All your workspaces |
get_workspace |
Workspace contents and structure |
list_folders |
Home-level folders |
get_folder |
Folder contents |
create_folder |
Create a new folder |
get_recent_items |
Recent items and favorites |
Sheet Reading & Analysis — 7 tools
| Tool | What it does |
|---|---|
get_sheet_summary |
Sheet structure: columns, types, row count |
read_rows |
Read rows with optional range |
get_row |
Get a single row by ID |
get_cell_history |
Full audit trail for any cell |
get_summary_fields |
Sheet-level KPI fields |
analyze_sheet |
Deep analysis: structure, patterns, formulas |
detect_issues |
Find errors, empty columns, inconsistencies |
Data Manipulation — 6 tools
| Tool | What it does |
|---|---|
add_rows |
Add new rows with values |
update_rows |
Update cells (values or formulas) |
delete_rows |
Delete rows by ID |
move_rows |
Move rows to another sheet |
copy_rows |
Copy rows to another sheet |
sort_sheet |
Sort by one or more columns |
Column Management — 3 tools
| Tool | What it does |
|---|---|
add_column |
Add column (TEXT_NUMBER, DATE, PICKLIST, CHECKBOX, CONTACT_LIST, DURATION, PREDECESSOR) |
update_column |
Update column title or description |
delete_column |
Delete a column |
Sheet Management — 5 tools
| Tool | What it does |
|---|---|
create_sheet |
Create a new sheet with columns |
delete_sheet |
Delete a sheet |
rename_sheet |
Rename a sheet |
copy_sheet |
Copy a sheet |
move_sheet |
Move sheet to folder/workspace |
Cross-sheet References — 2 tools
| Tool | What it does |
|---|---|
list_cross_sheet_refs |
List all cross-sheet references |
create_cross_sheet_ref |
Create a ref for INDEX(COLLECT(...)) formulas |
Sharing & Collaboration — 4 tools
| Tool | What it does |
|---|---|
list_shares |
List sharing permissions |
share_sheet |
Share with a user (VIEWER / EDITOR / ADMIN) |
update_share |
Update permission level |
delete_share |
Remove access |
Discussions & Comments — 4 tools
| Tool | What it does |
|---|---|
list_discussions |
Sheet-level discussions |
list_row_discussions |
Discussions on a specific row |
add_comment |
Reply to a discussion |
create_row_discussion |
Start a new discussion on a row |
Attachments — 6 tools
| Tool | What it does |
|---|---|
list_attachments |
List all attachments on a sheet |
list_row_attachments |
List attachments on a single row |
get_attachment |
Get details and download URL |
attach_url_to_sheet |
Attach a URL/link (Drive, Dropbox, OneDrive, web) to a sheet |
attach_url_to_row |
Attach a URL/link to a specific row |
delete_attachment |
Delete an attachment by ID |
Forms — 1 tool
| Tool | What it does |
|---|---|
list_sheet_forms |
List forms on a sheet (falls back to permalink — Smartsheet API exposure is limited) |
Update Requests — 3 tools
| Tool | What it does |
|---|---|
list_update_requests |
List pending update requests |
create_update_request |
Send an update request to one or more emails for specific row(s) |
delete_update_request |
Cancel an outstanding update request |
Proofs (Premium) — 2 tools
| Tool | What it does |
|---|---|
list_row_proofs |
List proofs on a row (Premium feature) |
create_row_proof_from_url |
Create a proof from a URL on a row |
Reports & Dashboards — 4 tools
| Tool | What it does |
|---|---|
list_reports |
List all reports |
get_report |
Get report data |
list_dashboards |
List all dashboards |
get_dashboard |
Dashboard details and widgets |
Templates & Webhooks — 5 tools
| Tool | What it does |
|---|---|
list_templates |
Public templates |
list_webhooks |
Configured webhooks |
create_webhook |
Create a webhook |
update_webhook |
Enable/disable or reconfigure a webhook in place |
delete_webhook |
Delete a webhook |
Automations — 4 tools
| Tool | What it does |
|---|---|
list_automations |
List automation rules |
get_automation |
Get details of one rule |
update_automation |
Enable/disable or rename a rule (CREATE not supported by Smartsheet API) |
delete_automation |
Delete an automation rule |
Workspace Sharing — 4 tools
| Tool | What it does |
|---|---|
list_workspace_shares |
List sharing on a workspace |
share_workspace |
Share workspace with a user (cascades to all sheets inside) |
update_workspace_share |
Change a user's access level on a workspace |
delete_workspace_share |
Remove a user from a workspace |
Cell Linking & AI — 3 tools
| Tool | What it does |
|---|---|
create_cell_link |
One-way live link from a source cell to a target cell (distinct from cross-sheet refs) |
generate_image |
Generate visuals with DALL-E 3 (inline in chat) |
generate_chart |
Render a Chart.js bar/line/pie/etc. inline in chat |
| Category | Count | Functions |
|---|---|---|
| Numeric | 25 | ABS AVG AVGW CEILING CHAR COUNT FLOOR INT LARGE LEN MAX MEDIAN MIN MOD MROUND RANKAVG RANKEQ ROUND ROUNDDOWN ROUNDUP SMALL SUM UNICHAR DECTOHEX HEXTODEC |
| Logic | 16 | AND CONTAINS HAS IF IFERROR ISBLANK ISBOOLEAN ISCRITICAL ISDATE ISERROR ISEVEN ISNUMBER ISODD ISTEXT NOT OR |
| Text | 10 | FIND JOIN LEFT LOWER MID REPLACE RIGHT SUBSTITUTE UPPER VALUE |
| Date | 14 | DATE DATEONLY DAY MONTH NETDAYS NETWORKDAY NETWORKDAYS TIME TODAY WEEKDAY WEEKNUMBER WORKDAY YEAR YEARDAY |
| Advanced / Lookup | 18 | AVERAGEIF COLLECT COUNTIF COUNTIFS COUNTM DISTINCT INDEX MATCH NPV PERCENTILE PRORATE STDEVA STDEVP STDEVPA STDEVS SUMIF SUMIFS VLOOKUP |
| Hierarchy | 6 | ANCESTORS CHILDREN DESCENDANTS PARENT SUCCESSORS TOTALFLOAT |
Beyond functions — the agent masters:
[Column]@rowreferences,[Column]:[Column]ranges, absolute row refs- Cross-sheet
{{reference}}patterns:INDEX(COLLECT({{Values}}, {{Keys}}, [Key]@row), 1) - Column formulas, Summary fields, Conditional formatting rules
- Reports (multi-sheet aggregation), Dashboards (live KPI widgets)
- Gantt, Calendar, Card/Kanban views
- Automations, Forms, Proofing, Cell history, Row locking
A complete Model Context Protocol server — plug Smartsheet into Claude Desktop, Cursor, or any MCP client. 52 of the 73 tools are exposed through MCP (the chat-only ones — generate_image, generate_chart, etc. — stay in the web app).
# stdio (Claude Desktop / Cursor)
SMARTSHEET_TOKEN=your_token python -m backend
# HTTP
SMARTSHEET_TOKEN=your_token python -m backend --transport http{
"mcpServers": {
"smartsheet": {
"command": "python",
"args": ["-m", "backend"],
"cwd": "/path/to/smartsheet-controller",
"env": { "SMARTSHEET_TOKEN": "your_token_here" }
}
}
}{
"mcpServers": {
"smartsheet": {
"command": "python",
"args": ["-m", "backend"],
"cwd": "/path/to/smartsheet-controller",
"env": { "SMARTSHEET_TOKEN": "your_token_here" }
}
}
}| MCP Resources | |
|---|---|
smartsheet://sheets |
All sheets in the account |
smartsheet://user |
Authenticated user profile |
smartsheet://sheets/{id}/summary |
Sheet structure |
| MCP Prompts | |
|---|---|
| Analyze Sheet | Deep structure analysis with suggestions |
| Sheet Audit | Security, sharing & quality audit |
| Explore Account | Full account exploration |
smartsheet-controller/
├── backend/
│ ├── app.py → FastAPI + WebSocket + session mgmt + 20+ HTTP routes
│ ├── agent.py → AI agent loop, expert prompt, tool dispatch, suggestions
│ ├── tools.py → 73 tool definitions + dispatcher + DALL-E + Chart.js
│ ├── llm_router.py → 5-provider streaming router (OpenAI / Anthropic / OpenRouter / Mistral / Groq)
│ ├── smartsheet_client.py → Smartsheet REST wrapper (httpx, retry, in-memory cache)
│ ├── db.py → SQLite persistence (users, sessions, conversations, favorites, audit, webhooks)
│ ├── rate_limit.py → Token-bucket rate limiter (per-session LLM + WS)
│ ├── logging_config.py → Structured JSON logs with token redaction
│ ├── mcp_server.py → MCP server (52 tools, 3 resources, 3 prompts)
│ └── __main__.py → MCP CLI entry point (stdio / http)
├── frontend/
│ ├── index.html → Glassmorphism SPA (voice, streaming, history, suggestions, watch)
│ └── assets/ → Brand & marketing assets (PNG, SVG)
├── tests/
│ ├── unit/ → 196 fast tests (no I/O, mocked transports)
│ │ ├── test_rate_limit.py rate limiter
│ │ ├── test_llm_router.py provider parsing + usage tracking
│ │ ├── test_tools.py intent routing + chart generation
│ │ ├── test_tools_dispatch.py contract: every tool dispatchable
│ │ ├── test_smartsheet_client.py mock-transport CRUD + retry + cache
│ │ ├── test_db.py SQLite layer (every CRUD path)
│ │ ├── test_agent.py agent helpers
│ │ ├── test_agent_loop.py run() loop: tools, confirm, MAX_ROUNDS
│ │ ├── test_app_helpers.py _friendly_error, provider detection
│ │ └── test_mcp_smoke.py MCP server boot + tool registry
│ ├── integration/ → 41 tests against the real Smartsheet API
│ │ ├── test_smartsheet_live.py read + create→modify→delete lifecycle
│ │ └── test_app_endpoints*.py every FastAPI HTTP route
│ ├── e2e/ → 9 full-stack WebSocket flow tests
│ │ ├── test_websocket_flow.py handshake + agent + suggestions
│ │ └── test_websocket_advanced.py cancel, confirm/reject, rate-limit, multi-turn
│ └── README.md → How to run, what each layer covers
├── data/ → SQLite DB (created at first launch, git-ignored)
├── Dockerfile → Slim Python 3.11 image, non-root, /health probe
├── docker-compose.yml → One-command stack with bind-mount for data/
├── pytest.ini → markers: unit / integration / e2e / live_llm
├── ROADMAP.md → 7+ sprints, journal, deliverables
├── requirements.txt → Runtime deps
├── requirements-dev.txt → + pytest, pytest-asyncio, pytest-cov
├── .env → API keys (LLM providers + optional SMARTSHEET_TOKEN)
└── README.md
You (voice or text)
│
▼
WebSocket ──→ FastAPI ──→ Agent ──→ LLM Router
│ ┌──────────┐
├─────▶│ OpenAI │
├─────▶│ Anthropic│
├─────▶│OpenRouter│
├─────▶│ Mistral │
└─────▶│ Groq │
│ └──────────┘
73 tool calls
│
▼
Smartsheet API v2.0 ◀──── webhooks ──┐
│ │
▼ │
Streaming · Tables · Images · Charts │
│ │
▼ │
Chat UI ◀────── live fan-out ──────┘
│
▼
SQLite (conversations · favorites · audit)
pip install -r requirements-dev.txt
pytest # everything (246 tests, ~3min37s)
pytest -m unit # 196 fast tests, <2s, no network
pytest -m integration # 41 real Smartsheet API tests
pytest -m e2e # 9 WebSocket end-to-end (stubbed LLM, no cost)
pytest --cov=backend --cov-report=html # coverage report → htmlcov/| Layer | Count | Speed | Network | Notable coverage |
|---|---|---|---|---|
unit |
196 | < 2 s | none | Rate limiter · LLM router · _friendly_error (no secrets leaked) · dispatch contract for all 73 tools · agent.run() loop (confirm, parse-error recovery, MAX_TOOL_ROUNDS, image/chart events) · SQLite CRUD · MCP smoke (52 tools registered) |
integration |
41 | medium | Smartsheet | Real read calls + create→modify→delete lifecycle on a throwaway sheet · all FastAPI routes including /api/csv-to-sheet, /api/smartsheet-webhook (challenge + payload fan-out), favorites, conversations CRUD, audit, RGPD export, model switching |
e2e |
9 | medium | Smartsheet | Full FastAPI lifespan · WebSocket handshake · agent loop with stubbed LLM · suggestions extraction · mid-stream cancel · destructive-tool confirm/reject · WS rate-limit response · multi-turn in one connection |
Integration & e2e tests skip cleanly when
SMARTSHEET_TOKEN/SHEET_IDaren't in.env. Tests never touch the production SQLite DB — each test gets its own temp file. LLM calls are stubbed by default; setENABLE_LIVE_LLM=1to opt into real provider calls.
cp .env.example .env # fill in at least OPENAI_API_KEY (SMARTSHEET_TOKEN is optional - users now BYOT)
docker compose up -d --build
# → http://localhost:8000 (health: http://localhost:8000/health)The container runs uvicorn backend.app:app as a non-root user on port 8000, exposes a /health endpoint for orchestrator probes, and reads secrets from .env.
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
uvicorn backend.app:app --host 0.0.0.0 --port 8000 --proxy-headers --forwarded-allow-ips '*'Example /etc/systemd/system/smartsheet-controller.service:
[Unit]
Description=Smartsheet Controller
After=network.target
[Service]
Type=simple
User=smartsheet
WorkingDirectory=/opt/smartsheet-controller
EnvironmentFile=/opt/smartsheet-controller/.env
ExecStart=/opt/smartsheet-controller/.venv/bin/uvicorn backend.app:app \
--host 127.0.0.1 --port 8000 --proxy-headers --forwarded-allow-ips '*'
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now smartsheet-controller
sudo journalctl -u smartsheet-controller -fserver {
listen 443 ssl http2;
server_name chat.example.com;
ssl_certificate /etc/letsencrypt/live/chat.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/chat.example.com/privkey.pem;
client_max_body_size 2m;
location / {
proxy_pass http://127.0.0.1:8000;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
# WebSocket upgrade (used by /ws/{session_id})
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_read_timeout 3600s;
proxy_send_timeout 3600s;
}
location = /health { proxy_pass http://127.0.0.1:8000/health; access_log off; }
}
server {
listen 80;
server_name chat.example.com;
return 301 https://$host$request_uri;
}- BYOT flow — end users paste their own Smartsheet token in the UI. The server stores it only in-memory for the session; sessions auto-expire after
SESSION_IDLE_TIMEOUTseconds (default1800). - Secrets — only LLM provider keys need to live in
.envon the server (OPENAI_API_KEY,ANTHROPIC_API_KEY, ...). TheSMARTSHEET_TOKENin.envis only used for the "Quick Connect (dev)" button. - Rate limiting — per-session token buckets (LLM 60/min, WS 120/min) are applied automatically; Smartsheet 429s are retried with exponential backoff.
- Logging — stdout is redacted of API tokens; set
LOG_LEVEL=DEBUGto see more. - Health probe —
GET /healthreturns{"status": "ok", "sessions": N, "uptime": ...}.
| Smartsheet — official GitHub org | @smartsheet (verified, SDKs Python · JS · Java · C#) |
| Smartsheet Platform — DevRel GitHub | @smartsheet-platform (incl. their own MCP server) |
| Smartsheet API Docs | smartsheet.redoc.ly |
| Smartsheet Developer Portal | developers.smartsheet.com |
| Smartsheet Functions | help.smartsheet.com/functions |
| Smartsheet Learning Center | help.smartsheet.com |
| Smartsheet Community | community.smartsheet.com |
| Model Context Protocol | modelcontextprotocol.io |
| OpenAI Platform | platform.openai.com |
| Anthropic Docs | docs.anthropic.com |
73 tools · 80 formulas · 5 LLMs · 246 green tests · Full voice · Streaming · History · Audit · MCP.
Your data listens. Your sheets respond. Your workflow accelerates.
Built with FastAPI · Smartsheet API · OpenAI · Anthropic · OpenRouter · Mistral · Groq · MCP
Smartsheet® and the Smartsheet logo are trademarks of Smartsheet Inc. (@smartsheet). This project is an independent community tool and is not endorsed by or affiliated with Smartsheet Inc.


