This is the first of a few PRs. Deploy to staging will fail until we
have `arcade-core`, `arcade-serve`, and `arcade-ai` released to PyPI.
This PR will release `arcade-core` to PyPI.
### PR Description
* Adds workflow that checks for changes in any pyproject.toml, and if
its version has changed, then tests, builds wheel, then publishes to
PyPI
* Updates the Dockerfile for our new structure
* Updates porter yamls
* Updates `make full-dist`
* Removes a couple unused workflows
Check out https://github.com/ArcadeAI/arcade-ai/actions/runs/15622059209
to see how the new workflow works (note that it failed publishing to
PyPI on purpose)
### Overview
Major restructuring from monolithic `arcade-ai` package to modular
library architecture with standardized uv-based dependency management.

### New Package Structure
- **`arcade-tdk`** - Lightweight toolkit development kit (core
decorators, auth)
- **`arcade-core`** - Core execution engine and catalog functionality
- **`arcade-serve`** - FastAPI/MCP server components
- **`arcade-ai`** - Meta package that includes CLI functionality.
Optionally include evals via the `evals` extra. Optionally include all
packages via the `all` extra.
### Key Benefits
- **Lighter Dependencies**: Toolkits now depend only on `arcade-tdk` (~2
deps) vs full `arcade-ai` (~30+ deps)
- **Faster Builds**: uv provides 10-100x faster dependency resolution
and installation
- **Better Modularity**: Clear separation of concerns, consumers import
only what they need
- **Standard Tooling**: Eliminates custom poetry scripts, uses standard
Python packaging
### Migration Impact
- All 20 toolkits converted from poetry → uv with `arcade-tdk`
dependencies plus `arcade-ai[evals]` and `arcade-serve` dev
dependencies. When developing locally, devs should install toolkits via
`make install-local`.
- Modern Python 3.10+ type hints throughout
- Standardized build system with hatchling backend
- Enhanced Makefile with robust toolkit management commands
- Removed `arcade dev` CLI command
- Reduce the number of files created by `arcade new` and add an option
to not generate a tests and evals folder.
This foundation enables faster development cycles and cleaner dependency
chains for the growing toolkit ecosystem.
### Todo After this PR is merged
- [ ] Post-merge workflow(s) (release & publish containers, etc)
- [ ] Release order plan. @EricGustin suggests releasing in the
following order:
1. `arcade-core` version 0.1.0
2. `arcade-serve` version 0.1.0 and `arcade-tdk` version 0.1.0
3. `arcade-ai` version 2.0.0
4. Patch release for all toolkits (all changes in toolkits are internal
refactors)
- [ ] [Update docs](https://github.com/ArcadeAI/docs/pull/318)
---------
Co-authored-by: Eric Gustin <eric@arcade.dev>
Co-authored-by: Eric Gustin <34000337+EricGustin@users.noreply.github.com>
Hello 👋 from Porter! Please merge this PR to finish setting up your
application.
---------
Co-authored-by: porter-deployment-app[bot] <87230664+porter-deployment-app[bot]@users.noreply.github.com>
Co-authored-by: sdreyer <sterling@arcade-ai.com>
Hello 👋 from Porter! Please merge this PR to finish setting up your
application.
Co-authored-by: porter-deployment-app[bot] <87230664+porter-deployment-app[bot]@users.noreply.github.com>
This repo has a readme that is basically a shadow version of our docs
that we aren't keeping up-to-date. So, let's remove all that and
encourage folks to head to our docs.
---------
Co-authored-by: Nate Barbettini <nate@arcade.dev>
12 tools for the new Confluence toolkit.
| Name | Description |
|----------------------------------|------------------------------------------------------------------------------------|
| Confluence.CreatePage | Create a new page at the root of the given
space. |
| Confluence.UpdatePageContent | Update a page's content. |
| Confluence.RenamePage | Rename a page by changing its title. |
| Confluence.GetPage | Retrieve a SINGLE page's content by its ID or
title. |
| Confluence.GetPagesById | Get the content of MULTIPLE pages by their
ID in a single efficient request. |
| Confluence.ListPages | Get the content of multiple pages by their ID.
|
| Confluence.ListAttachments | List attachments in a workspace. |
| Confluence.GetAttachmentsForPage | Get attachments for a page by its
ID or title. |
| Confluence.SearchContent | Search for content in Confluence. |
| Confluence.GetSpace | Get the details of a space by its ID or key. |
| Confluence.ListSpaces | List all spaces sorted by name in ascending
order. |
| Confluence.GetSpaceHierarchy | Retrieve the full hierarchical
structure of a Confluence space as a tree structure.|
### Confluence Clients
Confluence has deprecated most of their V1 endpoints, so most of the
tools use V2. However, we still need a V1 client to support search. The
V1 search API has not been deprecated yet, because there is no V2
equivalent. But we need to be aware in the future for when this
deprecation happens.
### Future work
* Content of pages are returned in the Confluence `storage` format. This
is the format that Confluence uses to store pages internally. We should
understand the storage format more deeply, and write utility function to
transform this format into plain text.
* Better protections against extremely large pages. I've tested up to
6,000 word pages.
* Tools for blog posts
* Tool for getting the children of a page. (`get_space_hierarchy` will
suffice for now)
* Allow for numerical titles
Add hot-reload capability
adds watchfiles dependency and changes uvicorn server logic
but does not have any breaking changes.
---------
Co-authored-by: Eric Gustin <eric@arcade.dev>
Co-authored-by: sdreyer <sterling@arcade-ai.com>
Co-authored-by: Eric Gustin <34000337+EricGustin@users.noreply.github.com>
Update our example with the latest version of `arcade-js`. This means we
can delete all the utility functions we created here, since we now have
first-class `Zod` support and they are no longer needed.
> [!WARNING]
> Don't merge until this
[PR](https://github.com/ArcadeAI/arcade-js/pull/127) is merged.
added additional pr guideline for toolkits -- separate pr for each
toolkit change
---------
Co-authored-by: Eric Gustin <34000337+EricGustin@users.noreply.github.com>
This PR fixes two bugs:
1. `serve_default_worker` was not registering toolkits to the worker
(non mcp). This caused workers created during `arcade workerup` and
`arcade serve` to have 0 tools.
2. We were logging the number of files in the toolkit as the number of
tools in the toolkit.
MCP stdio Implementation:
The PR adds support for standard input/output (stdio) as a transport
mechanism for the Message Control Protocol. This is a replacement to the
SSE (Server-Sent Events) transport that was worked on in PR #359 but
will not be merged as it's not deprecated.
This will allow developers to use Arcade tools (written by the dev or
Arcade) in Claude, Cursor, windsurf, etc.
The engine Gateway already supports adding HTTPS streamable (replacement
for SSE) MCP servers as tool servers, and will soon support full gateway
capability in the client API as well.
To use any existing Toolkit just
## Examples
### Quickstart setup with existing toolkits
```bash
pip install arcade-ai
pip install <name of toolkit> # ex. arcade-google
arcade serve --mcp
```
### Run with Claude
Just add the following to the Claude config
```json
{
"mcpServers": {
"arcade": {
"command": "bash",
"args": ["-c", "export ARCADE_API_KEY=arc_xxxx && /path/to/python /path/to/arcade serve --mcp"]
}
}
}
```
### Customizing the Tool Server
Developers can customize their served tools and server furthermore by
importing the worker sdk
```python
import arcade_google # pip install arcade_google
import arcade_search # pip install arcade_search
from arcade.core.catalog import ToolCatalog
from arcade.worker.mcp.stdio import StdioServer
# 2. Create and populate the tool catalog
catalog = ToolCatalog()
catalog.add_module(arcade_google) # Registers all tools in the package
catalog.add_module(arcade_search)
# 3. Main entrypoint
async def main():
# Create the worker with the tool catalog
worker = StdioServer(catalog)
# Run the worker
await worker.run()
if __name__ == "__main__":
import asyncio
asyncio.run(main())
```
Then to run with claude, just run this python file instead of the prebuilt server used in ``arcade serve --mcp``
The Asana toolkit is not published yet, so it cannot be added to the
worker's toolkit list. This is causing container build/publish on main
branch to fail.
* `arcade dashboard` opens the Arcade Dashboard in a web browser.
Defaults to `https://api.arcade.dev/dashboard`, but is configurable via
flags.
* `arcade dashboard --local` opens your locally hosted Arcade Dashboard
in a web browser.
* Performs a health check of the engine and will print a warning to the
console if the Engine is not healthy / not running.
----------------------------------------
* Inspiration from https://minikube.sigs.k8s.io/docs/handbook/dashboard/
| Name | Description |
|------------------------------|--------------------------------------------------------------------------------|
| Microsoft.CreateDraftEmail | Compose a new draft email in Outlook |
| Microsoft.UpdateDraftEmail | Update an existing draft email in Outlook
|
| Microsoft.CreateAndSendEmail | Create and immediately send a new email
in Outlook to the specified recipients |
| Microsoft.SendDraftEmail | Send an existing draft email in Outlook |
| Microsoft.ReplyToEmail | Reply only to the sender of an existing email
in Outlook |
| Microsoft.ReplyAllToEmail | Reply to all recipients of an existing
email in Outlook |
| Microsoft.ListEmails | List emails in the user's mailbox across all
folders |
| Microsoft.ListEmailsInFolder | List the user's emails in the specified
folder |
1. Paginate through all current level blocks before recursing into
children (before this PR we would go back and forth between paginate and
recurse)
2. For top-level blocks only, split blocks into 5 lists, and
concurrently get their content
---------
From my local timing benchmarks, this speeds up the tool call by ~60%
(23 seconds to 9.1 seconds) for larger Notion pages
Without optimization: Avg 22995
Attempt 1: 27503.49497795105
Attempt 2: 20863.977909088135
Attempt 3: 20888.309955596924
Attempt 4: 18574.61714744568
Attempt 5: 27147.75586128235
With optimization: Avg 9148.6
Attempt 1: 9941.372871398926
Attempt 2: 10097.685098648071
Attempt 3: 7855.895042419434
Attempt 4: 9078.719854354858
Attempt 5: 8772.69196510315
Reviewer:
1. DM me to get a client ID/secret for the Hubspot app and login
credentials for a sample Hubspot account
2. For now, you'll need to run the engine on the branch
`nate/token-introspection` for the auth flow to work with Hubspot
3. Add the following to `auth.providers` in your engine yaml:
```yaml
- id: arcade-hubspot
description: 'Hubspot provider'
enabled: true
type: oauth2
provider_id: hubspot
client_id: ${env:HUBSPOT_CLIENT_ID}
client_secret: ${env:HUBSPOT_CLIENT_SECRET}
```
Updating the auth provider's `id` to simply `salesforce`. We don't want
it to be confused with a future well-known `provider_id` of
`arcade-salesforce`.
Also, what the toolkit was referring to as `org_domain` is actually the
organization's SUBdomain. We changed all references to "subdomain" to be
more precise. The documentation has been updated accordingly.
## Google File Picker
The Google Picker lets users select or upload Google Drive files. Users
can grant permission to your apps to access their Drive data, providing
a secure and authorized way to interact with their files.
The `generate_google_file_picker_url` returns a URL to a Google File
Picker for the user.