https://github.com/dougborg/frontapp-openapi-client
Pythonic Frontapp API client ecosystem with transport-layer retries, rate-limit awareness, and auto-pagination. Python + TypeScript clients + MCP server.
https://github.com/dougborg/frontapp-openapi-client
api front frontapp mcp-server openapi python typescript
Last synced: 22 days ago
JSON representation
Pythonic Frontapp API client ecosystem with transport-layer retries, rate-limit awareness, and auto-pagination. Python + TypeScript clients + MCP server.
- Host: GitHub
- URL: https://github.com/dougborg/frontapp-openapi-client
- Owner: dougborg
- License: mit
- Created: 2026-04-24T17:11:34.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-05-04T15:52:45.000Z (about 1 month ago)
- Last Synced: 2026-05-04T17:28:26.800Z (about 1 month ago)
- Topics: api, front, frontapp, mcp-server, openapi, python, typescript
- Language: Python
- Size: 1.32 MB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 26
-
Metadata Files:
- Readme: README.md
- Contributing: docs/CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Code of conduct: docs/CODE_OF_CONDUCT.md
- Codeowners: .github/CODEOWNERS
Awesome Lists containing this project
README
# Frontapp — API Client Ecosystem
Multi-language client ecosystem for the
[Front](https://dev.frontapp.com/reference/introduction) customer-communication
platform. Front is a shared-inbox product that unifies email, SMS, chat, and social
channels into one place for support and sales teams. Their
[Core API](https://dev.frontapp.com/reference/introduction) exposes conversations,
messages, contacts, teammates, tags, inboxes, and more.
This monorepo ships:
- A production-grade **Python client** with transport-layer retries, rate-limit
awareness, and pagination handling for Front's cursor-token paging.
- A **TypeScript client** generated from the same OpenAPI spec via
[hey-api](https://heyapi.dev).
- An **MCP server** exposing Frontapp operations as tools to AI assistants like Claude
Desktop and Cursor.
[](https://www.python.org/downloads/)
[](https://www.typescriptlang.org/)
[](https://spec.openapis.org/oas/v3.0.0)
The OpenAPI spec is vendored from
[frontapp/front-api-specs](https://github.com/frontapp/front-api-specs) and sanitized by
`scripts/vendor_spec.py` (strips binary attachment-download paths and normalizes a few
upstream quirks that trip the generators).
## Packages
| Package | Language | Version | Description |
| ------------------------------------------------------ | ---------- | ------- | ----------------------------------------------------------- |
| [frontapp-openapi-client](frontapp_public_api_client/) | Python | 0.1.0 | API client with transport-layer resilience + domain helpers |
| [frontapp-mcp-server](frontapp_mcp_server/) | Python | 0.1.0 | Model Context Protocol server for AI assistants |
| [frontapp-client](packages/frontapp-client/) | TypeScript | 0.1.0 | Generated TypeScript/JavaScript client |
## Features
| Feature | Python | TypeScript | MCP Server |
| ---------------------------------------------- | ------ | ---------- | ----------------------- |
| Automatic retries (network + 5xx) | Yes | Yes | Yes (via Python client) |
| Rate-limit retry with exponential backoff | Yes | Yes | Yes |
| Cursor-token pagination helpers | Yes | Yes | Yes |
| Two-step confirm on mutations (ctx.elicit) | — | — | Yes |
| Full type safety (attrs + Pydantic / TS types) | Yes | Yes | Yes |
| AI tool surface | — | — | Claude Desktop, Cursor |
## Quick Start
### Python Client
```bash
pip install frontapp-openapi-client
```
```python
import asyncio
from frontapp_public_api_client import FrontappClient
async def main():
async with FrontappClient() as client:
# List recent open conversations tagged "urgent"
conversations = await client.conversations.list(
q="status:open tag:urgent", limit=25
)
for conv in conversations:
assignee = conv.assignee.username if conv.assignee else "unassigned"
print(f"{conv.id}: {conv.subject!r} — {conv.status} ({assignee})")
asyncio.run(main())
```
### TypeScript Client
```bash
npm install frontapp-client
```
```typescript
import { FrontappClient } from "frontapp-client";
const client = await FrontappClient.create();
const { data } = await client.listConversations({ query: { q: "status:open" } });
console.log(`${data._results.length} open conversations`);
```
### MCP Server (Claude Desktop)
```bash
pip install frontapp-mcp-server
```
Add to Claude Desktop config
(`~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"frontapp": {
"command": "uvx",
"args": ["frontapp-mcp-server"],
"env": {
"FRONTAPP_API_KEY": "your-api-key-here"
}
}
}
}
```
Get an API key at Front → Settings → Developers → API tokens.
## Configuration
All packages authenticate with a Front API token via bearer auth:
1. **Environment variable**: `FRONTAPP_API_KEY`
2. **`.env` file**: `FRONTAPP_API_KEY=your-key`
3. **Direct parameter**: `FrontappClient(api_key="...")`
4. **`~/.netrc`**: `machine api2.frontapp.com` + `password your-key`
```bash
# .env
FRONTAPP_API_KEY=your-api-key-here
FRONTAPP_BASE_URL=https://api2.frontapp.com # optional override
```
## API Coverage
The generated clients cover Front's full Core API — **139 paths, 233 operations**
spanning conversations, messages, contacts, teammates, accounts, tags, inboxes,
channels, rules, custom fields, drafts, message templates, analytics, and more. Browse
`frontapp_public_api_client/api/` (Python) or
`packages/frontapp-client/src/generated/sdk.gen.ts` (TS) for the full surface.
Hand-written ergonomic helpers (Python `client..…`) and MCP tools wrap the
highest-value subset. Current status:
| Resource | Python helper (`client.X.…`) | MCP tools |
| --------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Conversations | ✅ `.conversations` | list / get / search / list_messages / list_comments / update / add_comment |
| Drafts | ✅ `.drafts` | list_conversation_drafts / create_draft_on_channel / create_draft_reply / edit_draft / delete_draft |
| Contacts | ✅ `.contacts` | list / get / lookup_by_email / list_team / list_teammate / list_conversations / list_notes / create (+ team/teammate variants) / update / merge / delete / add_note / add_handle / delete_handle |
| Contact Lists | ✅ `.contact_lists` | list (+ team/teammate scopes) / list_members / create (+ team/teammate variants) / delete / add_contacts / remove_contacts |
| Contact Groups (deprecated) | ✅ `.contact_groups` | Same shape as contact_lists; Front has deprecated this surface — prefer contact_lists for new code |
| Messages | ✅ `.messages` | get / seen_status / mark_seen |
| Tags | ✅ `.tags` | list (+ company/team/teammate scopes) / get / list_children / list_tagged_conversations / add_tag_to_conversation / remove_tag_from_conversation / create / create_child / update / delete |
| Inboxes | ✅ `.inboxes` | list (+ team/teammate scopes) / get / list_conversations / list_channels / list_access / create (+ team) / grant_access / revoke_access |
| Teammates | ✅ `.teammates` | list / get / list_inboxes / list_assigned_conversations / update |
| Attachments | ✅ `.attachments` | download_attachment + `attachment_paths` parameter on every draft / reply / comment tool |
| Analytics | ⏳ planned | ⏳ planned (create→poll recipe) |
See the [issue tracker](https://github.com/dougborg/frontapp-openapi-client/issues) for
the roadmap. The full generated surface is usable today via direct imports from
`frontapp_public_api_client.api.` — helpers and MCP tools just add ergonomic polish
on top.
### Front Search Syntax
Conversation list/search endpoints accept Front's `q=` search syntax:
| Query | Description |
| ------------------- | --------------------------- |
| `status:open` | Open conversations |
| `status:archived` | Archived |
| `tag:urgent` | Tagged urgent |
| `assignee:me` | Assigned to the token owner |
| `is:unassigned` | Unassigned |
| `inbox:support` | In a named inbox |
| `after:2024-01-01` | Updated after a date |
| `before:2024-12-31` | Updated before a date |
Combine with `AND` / `OR`: `status:open AND tag:urgent`.
## MCP Tools
Mutations use a two-step confirm pattern — call with `confirm=false` for a preview, then
`confirm=true` to apply (which also elicits explicit user approval via `ctx.elicit`).
Customer-facing replies always go through the drafts vertical: agents draft, humans
send.
### Conversations
| Tool | Mutation? | Description |
| ---------------------------- | --------- | -------------------------------------------------------- |
| `list_conversations` | no | Filter + cursor-paginate, reverse chronological |
| `get_conversation` | no | Full detail for one conversation |
| `search_conversations` | no | Full Front search syntax as the primary filter |
| `list_conversation_messages` | no | Messages inside a conversation (most recent first) |
| `list_conversation_comments` | no | Internal teammate comments on a conversation |
| `update_conversation` | yes | Archive/reopen, reassign, retag, move inbox |
| `add_conversation_comment` | yes | Add a teammate-only comment (never reaches the customer) |
### Drafts (drafts-first outbound)
| Tool | Mutation? | Description |
| -------------------------- | --------- | -------------------------------------------------- |
| `list_conversation_drafts` | no | Existing drafts on a conversation |
| `create_draft_on_channel` | yes | Brand-new outbound draft on a channel |
| `create_draft_reply` | yes | Draft a reply on an existing conversation |
| `edit_draft` | yes | Full-replacement edit (body + channel_id required) |
| `delete_draft` | yes | Discard a draft |
Front exposes no programmatic `send_draft` — drafts are reviewed and sent by a human in
Front's UI. There is intentionally no `reply_to_conversation` tool.
Reads are cached for 30s via `ResponseCachingMiddleware`.
## Resilience (Python client)
Every endpoint inherits these transport-layer behaviors automatically — no decorators or
wrappers needed:
- **Retries**: `httpx-retries` retries idempotent methods on 502/503/504 and any method
on 429 (safe because 429 means "not processed"). Configurable via `max_retries`.
- **Rate-limit awareness**: `Retry-After` headers are honored when present; otherwise
exponential backoff.
- **Sensitive-data redaction**: `Authorization` headers and common secret field names
(`api_key`, `password`, `token`, etc.) are scrubbed from log output.
**Auto-pagination** for Front's cursor-token paging — every paginated list method has an
`iter_*` async-iterator counterpart:
| Helper | `iter_all` | Variant iterators |
| ---------------------- | ------------------------- | -------------------------------------------------------------------------- |
| `client.conversations` | yes | `iter_search`, `iter_messages` |
| `client.contacts` | yes | `iter_for_team`, `iter_for_teammate`, `iter_conversations` |
| `client.tags` | yes | `iter_company`, `iter_for_team`, `iter_for_teammate`, `iter_conversations` |
| `client.inboxes` | (no top-level pagination) | `iter_conversations` |
```python
async for conv in client.conversations.iter_all(q="status:open", max_items=500):
print(conv.id, conv.subject)
```
The iterator walks `_pagination.next` until exhausted or a safety limit (`max_items`,
`max_pages`) trips. Pass `page_token` manually to the underlying `list()` if you need
cursor control instead.
## Project Structure
```text
frontapp-openapi-client/ # Monorepo root
├── pyproject.toml # uv workspace configuration
├── pnpm-workspace.yaml # pnpm TS workspace
├── scripts/vendor_spec.py # download + sanitize Front's OpenAPI spec
├── docs/
│ ├── frontapp-openapi.yaml # OpenAPI 3.0.0 spec (vendored + sanitized)
│ ├── FRONTAPP_API_ENDPOINTS.md # Prioritization reference
│ └── *.md # Shared documentation
├── frontapp_public_api_client/ # Python client
│ ├── frontapp_client.py # Resilient client + transport layer
│ ├── domain/ # Pydantic domain models (Conversation, …)
│ ├── helpers/ # Ergonomic facades (client.conversations)
│ ├── utils.py # unwrap/is_success + error types
│ ├── api/, models/ # Generated from the OpenAPI spec
│ └── docs/ # Package documentation
├── frontapp_mcp_server/ # MCP server (FastMCP)
│ └── src/frontapp_mcp/
│ ├── server.py # Lifespan, auth, caching middleware
│ ├── tools/ # MCP tool modules (conversations, …)
│ └── resources/ # help + workspace-orientation resources
└── packages/
└── frontapp-client/ # TypeScript client (hey-api)
├── src/
│ ├── client.ts # createClient + transport stack
│ ├── transport/ # resilient.ts, pagination.ts
│ └── generated/ # Generated from the same spec
└── openapi-ts.config.ts
```
## Development
### Prerequisites
- **Python 3.12+** for Python packages
- **Node.js 18+** for the TypeScript package
- **uv** ([install](https://docs.astral.sh/uv/getting-started/installation/))
- **pnpm** ([install](https://pnpm.io/installation))
### Setup
```bash
git clone https://github.com/dougborg/frontapp-openapi-client.git
cd frontapp-openapi-client
uv sync --extra dev # install Python deps including dev tools
uv run pre-commit install # install git hooks
pnpm install # install TS deps
cp .env.example .env # add FRONTAPP_API_KEY
```
### Common Commands
```bash
uv run python scripts/vendor_spec.py # refresh docs/frontapp-openapi.yaml from upstream
uv run poe regenerate-client # regenerate the Python client from the spec
pnpm --filter frontapp-client generate # regenerate the TypeScript client
uv run poe test # pytest -n 4
uv run poe quick-check # format + lint
uv run poe check # format + lint + typecheck + test
```
### Commit Standards
Conventional commits drive per-package semantic-release versioning:
```bash
git commit -m "feat(client): add contacts helper"
git commit -m "fix(client): handle empty paginated response"
git commit -m "feat(mcp): add tools for tag management"
git commit -m "feat(ts): export retry middleware"
git commit -m "docs: update quick-start"
```
Use `!` for breaking changes: `feat(client)!: drop Python 3.11 support`.
See [MONOREPO_SEMANTIC_RELEASE.md](docs/MONOREPO_SEMANTIC_RELEASE.md) for details.
## Acknowledgements
- Scaffolding pattern lifted from
[dougborg/statuspro-openapi-client](https://github.com/dougborg/statuspro-openapi-client)
and
[dougborg/katana-openapi-client](https://github.com/dougborg/katana-openapi-client),
which established the shape of this ecosystem (Python + TS client + FastMCP server,
transport-layer resilience, two-step confirm mutations, etc.).
- OpenAPI spec from
[frontapp/front-api-specs](https://github.com/frontapp/front-api-specs).
## License
MIT License — see [LICENSE](LICENSE).
## Contributing
Contributions welcome. See [CONTRIBUTING.md](docs/CONTRIBUTING.md) for guidelines.