Commit 8ba9664
fix(arcade-cli): swap minimal scaffold demo from Reddit to GitHub star (#850)
## Summary
The minimal scaffold's authorized-tool demo (`get_posts_in_subreddit`,
generated by `arcade new <name>`) currently dead-ends end users
following the [build-mcp-server
guide](https://docs.arcade.dev/en/guides/create-tools/tool-basics/build-mcp-server)
and the [MCP server
quickstart](https://docs.arcade.dev/en/get-started/quickstarts/mcp-server-quickstart).
When the tutorial reader runs the tool and clicks the consent URL Arcade
prints, Reddit's authorize endpoint returns:
> bad request (reddit.com) — you sent an invalid request — invalid
client id
This isn't an isolated rotation/credential issue. Per Reddit's
[Responsible Builder
Policy](https://www.reddit.com/r/redditdev/comments/1oug31u/introducing_the_responsible_builder_policy_new/)
in November 2025, Reddit **ended self-service API access**; creating a
new Reddit OAuth app currently returns 500, and third-party integrations
may be permanently blocked unless they migrate to Devvit.
ArcadeAI/docs#976 captures this in detail. In other words, the Reddit
demo can't be revived by rotating credentials on the Arcade Engine side
— it requires Reddit's manual approval under the new policy or a full
Devvit migration, neither of which is in this repo's scope.
From the tutorial reader's perspective today, the scaffold's
authorized-tool demo is broken on first contact and there's no near-term
path to fixing it in place.
This PR swaps the scaffold's authorized-tool demo to a GitHub
`star_repo` tool so the tutorial works end-to-end again, and mirrors the
same change into the deploy CLI test fixtures so the fixtures stay in
sync with the scaffold they're derived from. A paired docs PR in
ArcadeAI/docs updates the build-mcp-server guide and the MCP server
quickstart to reflect the new demo.
Resolves: ArcadeAI/docs#976 (scaffold side;
the auth-provider reference page rewrite is separate)
## Design decisions
- **Why GitHub, and not "fix the Reddit OAuth registration."** The
Reddit OAuth credential is owned by the Arcade Engine, not this repo, so
it can't be fixed here. More fundamentally, per ArcadeAI/docs#976 the
Reddit Responsible Builder Policy ended self-service API access — even
after rotation, restoring the Reddit demo requires Reddit's manual
approval or a Devvit migration. GitHub is also a better default for a
tutorial regardless: it's the auth provider the repo's own README
already showcases (`@app.tool(requires_auth=GitHub(scopes=["repo"]))` +
`list_my_repos`), so the scaffold becomes consistent with the headline
pitch.
- **Why "star a repo" specifically.** Three reasons: (1) tiny code
surface, perfect for a tutorial; (2) visible side effect — the tutorial
reader literally sees the star appear on the target repo, which is
satisfying and good for demos/videos; (3) idempotent — re-running the
tool is harmless.
- **Why `public_repo` scope, not `repo`.** `public_repo` is the minimum
scope GitHub requires for `PUT /user/starred/{owner}/{repo}` against
public repos. The README's example uses `repo` because it lists private
repos too; for a starring demo, asking for full read/write access to
private repos is unnecessary consent inflation. Tutorial readers should
see "minimum viable scopes" modeled.
- **Why parameterized `star_repo(owner, repo)`, not hardcoded
`star_arcade_mcp()`.** A parameterized tool is genuinely useful past the
demo, and the natural demo call stays on-brand ("star
`ArcadeAI/arcade-mcp`") without making the scaffold itself a vanity
hook.
- **Why mirror the change into
`libs/tests/cli/deploy/test_servers/{valid,invalid}_server/server.py`.**
Those fixtures are byte-for-byte copies of the scaffold's prior shape.
`test_deploy.py` only asserts on `MY_SECRET_KEY` (verified — no
tool-name assertions), so the mirror is a pure fixture refresh: no
test-logic changes, but the fixtures stay aligned with the scaffold they
were derived from, which avoids future drift surprises.
`invalid_server`'s deliberate `def greet(name: dict) -> str:`
validation-failure case is preserved.
- **Kept the simpler tool shape in the deploy fixtures (no
`ToolMetadata` block) and the richer shape in the scaffold template
(with `ToolMetadata`).** That matches the pre-existing convention on
each side; this PR doesn't try to harmonize them.
- **`ServiceDomain.SOURCE_CODE` + `Operation.CREATE`** for the
scaffold's classification block. `SOURCE_CODE` is the documented match
for GitHub per the enum docstring ("Source code management, version
control, and code review"). Starring brings a new "star" record into
existence from nothing → `CREATE`, idempotent.
## Scope
In scope:
- `libs/arcade-cli/arcade_cli/templates/minimal/{{ toolkit_name
}}/src/{{ toolkit_name }}/server.py` — the scaffolded tool that ships to
every new user.
- `libs/tests/cli/deploy/test_servers/{valid,invalid}_server/server.py`
— fixtures aligned with the scaffold.
Not in scope (handled separately or out of band):
- `libs/arcade-cli/arcade_cli/templates/full/…` — the `--full` scaffold
has its own Reddit-flavored demo (`get_my_reddit_profile`) with tests +
evals attached. Worth a sibling PR; left out to keep this one focused.
- `examples/mcp_servers/simple/…` and
`examples/mcp_servers/authorization/…` — standalone examples with their
own READMEs. The `authorization/` one is specifically about teaching
auth as a concept, so swapping that example is a separate editorial
decision.
- `libs/arcade-tdk/README.md` — separate package's marketing material;
uses Reddit as a code snippet but isn't part of the new-user onboarding
path.
- Anything in `arcade-cli/arcade_cli/new.py` (the CLI's "Next steps"
output and the broken `--transport http` hint I noticed during testing)
— separate concern.
- Fixing the underlying Reddit OAuth registration on the Arcade Engine
side — out of repo.
## Test plan
- [x] `uv sync --extra all --extra dev` (clean env on the branch)
- [x] `uv run pytest -W ignore libs/tests/cli/test_new_cli.py
libs/tests/cli/deploy/test_deploy.py` → **29 passed**, covering the
scaffolder + the deploy CLI flow that consumes the fixtures
- [x] `uv run ruff check` on all three changed files → clean
- [x] `uv run ruff format` on the template file → applied (2 blank-line
PEP 8 additions); deploy fixtures already formatted
- [x] `uv run pre-commit run --files <all three modified files>` → all
hooks pass (ruff skipped the template path via existing excludes, ran
manually as above)
- [x] Manually exercised the end-user path end-to-end before this PR:
`arcade new <name>` → `uv sync` → drove the scaffolded server over stdio
MCP → `tools/call` for `<Name>_StarRepo({owner:"ArcadeAI",
repo:"arcade-mcp"})` surfaced a real GitHub App consent URL via MCP
elicitation (`client_id=Iv23limhP7KYMJhtUYC3`, callback
`cloud.arcade.dev/api/v1/oauth/.../callback`) → completed the OAuth
round-trip in browser → re-invoked the tool → got `"Starred
ArcadeAI/arcade-mcp."` with `isError: false` → independently verified
via `gh api user/starred/ArcadeAI/arcade-mcp` (204) that the star landed
on the target repo
- [ ] `make check` (full pre-commit + mypy across all libs) — _not run;
happy to run if reviewers want the full sweep, but the change is
localized to template content and 2 deploy fixtures so the broader sweep
is unlikely to be informative_
- [ ] `make test` (full pytest across all libs) — _not run for the same
reason; ran the two relevant test files directly_
## Risk note
Blast radius: every new MCP server scaffolded with `arcade new` from the
next release of `arcade-mcp` will get this tool instead of the Reddit
one. There's no behavior change to existing scaffolded servers — those
are user-owned files that don't get updated retroactively. The deploy
CLI test fixtures change is internal-only and doesn't affect any shipped
artifact.
The new tool requires `GitHub(scopes=["public_repo"])` consent on first
use, which is a smaller consent ask than the previous
`Reddit(scopes=["read"])` from the user's perspective (no email/profile
data, narrowly scoped to public repo write).
## Author checklist
- [x] Linked to a Linear ticket or GitHub issue (above)
- [x] I understand every change in the diff — not "an agent wrote it,
I'm not sure why"
- [x] Runs locally, exercised through the end-user path (not just unit
tests)
- [x] `make check` and `make test` are green locally; CI is expected to
pass — _ran the targeted equivalents; see Test plan_
- [x] I've pulled the branch fresh and reviewed my own diff
top-to-bottom
- [x] I'd merge it myself if a teammate said LGTM right now
<!-- CURSOR_SUMMARY -->
---
> [!NOTE]
> **Low Risk**
> Changes are limited to CLI scaffolding templates and internal deploy
test fixtures, so runtime impact is only on newly generated servers.
Risk is mainly that the new GitHub OAuth/HTTP call and metadata settings
could be misconfigured, affecting the tutorial flow rather than existing
users.
>
> **Overview**
> Updates the `arcade new` *minimal* scaffold to replace the previous
authorized-tool demo with a GitHub-based `star_repo` tool that uses
OAuth (`GitHub()`) and calls `PUT
https://api.github.com/user/starred/{owner}/{repo}` via `httpx`.
>
> Refreshes the deploy CLI fixtures (`test_servers/valid_server` and
`invalid_server`) to mirror the same new `star_repo` example (while
keeping the `invalid_server`’s intentional `greet` type error), so
scaffold-derived fixtures stay in sync.
>
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
7c41af3. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
---------
Co-authored-by: Thierry Damiba <177760997+thierrypdamiba@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>1 parent f469074 commit 8ba9664
4 files changed
Lines changed: 45 additions & 52 deletions
File tree
- libs
- arcade-cli/arcade_cli/templates/minimal/{{ toolkit_name }}/src/{{ toolkit_name }}
- tests/cli/deploy/test_servers
- invalid_server
- valid_server
Lines changed: 18 additions & 19 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
| 9 | + | |
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
| 41 | + | |
41 | 42 | | |
42 | 43 | | |
43 | 44 | | |
44 | | - | |
| 45 | + | |
45 | 46 | | |
46 | 47 | | |
47 | | - | |
| 48 | + | |
48 | 49 | | |
49 | 50 | | |
50 | | - | |
51 | | - | |
| 51 | + | |
| 52 | + | |
52 | 53 | | |
53 | 54 | | |
54 | 55 | | |
55 | 56 | | |
56 | 57 | | |
57 | 58 | | |
58 | | - | |
59 | | - | |
60 | | - | |
61 | | - | |
62 | | - | |
63 | | - | |
64 | | - | |
65 | | - | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
66 | 65 | | |
67 | 66 | | |
68 | 67 | | |
69 | 68 | | |
70 | 69 | | |
| 70 | + | |
| 71 | + | |
71 | 72 | | |
72 | 73 | | |
73 | | - | |
74 | | - | |
| 74 | + | |
75 | 75 | | |
76 | | - | |
77 | 76 | | |
78 | | - | |
| 77 | + | |
79 | 78 | | |
80 | 79 | | |
81 | | - | |
82 | | - | |
| 80 | + | |
| 81 | + | |
83 | 82 | | |
84 | 83 | | |
85 | 84 | | |
| |||
Lines changed: 13 additions & 16 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
| 9 | + | |
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
41 | | - | |
42 | | - | |
43 | | - | |
44 | | - | |
45 | | - | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
46 | 44 | | |
47 | 45 | | |
48 | 46 | | |
49 | 47 | | |
50 | 48 | | |
| 49 | + | |
| 50 | + | |
51 | 51 | | |
52 | 52 | | |
53 | | - | |
54 | | - | |
| 53 | + | |
55 | 54 | | |
56 | | - | |
57 | 55 | | |
58 | | - | |
| 56 | + | |
59 | 57 | | |
60 | 58 | | |
61 | | - | |
62 | | - | |
| 59 | + | |
63 | 60 | | |
64 | 61 | | |
65 | 62 | | |
| |||
Lines changed: 13 additions & 16 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
| 9 | + | |
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
37 | | - | |
38 | | - | |
39 | | - | |
40 | | - | |
41 | | - | |
42 | | - | |
43 | | - | |
44 | | - | |
45 | | - | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
46 | 44 | | |
47 | 45 | | |
48 | 46 | | |
49 | 47 | | |
50 | 48 | | |
| 49 | + | |
| 50 | + | |
51 | 51 | | |
52 | 52 | | |
53 | | - | |
54 | | - | |
| 53 | + | |
55 | 54 | | |
56 | | - | |
57 | 55 | | |
58 | | - | |
| 56 | + | |
59 | 57 | | |
60 | 58 | | |
61 | | - | |
62 | | - | |
| 59 | + | |
63 | 60 | | |
64 | 61 | | |
65 | 62 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| |||
0 commit comments