fixture: reference MCP server (echo/add/whoami); finding: arcade deploy is cloud-only

This commit is contained in:
2026-06-18 11:14:50 -04:00
parent 619e6d833e
commit beb17c0a8f
6 changed files with 108 additions and 3 deletions
+10 -1
View File
@@ -48,4 +48,13 @@ Self-hosted on `backstage-wus2-v4` via Flux; vendor Helm chart **1.8.8**
7 main-catalog tools (Slack ×2, GoogleDocs ×4, Brightdata ×1). See `config/targets.yaml`.
Confirmed live 2026-06-18: tool list is gateway-wide (same for all `Arcade-User-ID`s).
- **Shared reference server:** _name + tools echo/whoami/add (Task 1.4)_
- **`whoami` identity field:** _exact field the server reads (Task 1.4 / 2.4)_
- **`whoami` identity field:** server reads `context.user_id` (arcade_mcp_server `Context`), populated by the Engine from the calling user (`Arcade-User-ID` / auth `sub`).
## Known behaviors (findings)
- **`arcade deploy` is cloud-only.** It validates the server locally fine (health, tool + secret
discovery — our ref server: 3 tools, 0 secrets), but POSTs the deployment to `api.arcade.dev`
(`PROD_ENGINE_HOST`), ignoring the `arcade login --host` coordinator — so against our self-hosted
instance it returns **401**. `deploy` exposes no `--host`. **Implication:** self-hosted custom
servers must be **registered** (run the server + dashboard "Add Server", type Arcade, URL + worker
secret) — the tunnel pattern for local dev, or an in-cluster deploy for prod — not `arcade deploy`.
Relevant to cat-4 (SDK/deploy), cat-8 (deployment), cat-9 (DX).
+3 -2
View File
@@ -13,6 +13,7 @@
## Remaining for cat-1 scoring
- [ ] 2.2 — connect a **second real MCP client (Claude Code)** to the gateway (no-adapter evidence).
- [x] 2.5 — **dynamic registration**: PASS — saved add/remove (Brightdata, +Youtube) reflected on next list, no restart; draft didn't propagate until Save.
- [ ] 2.7 — **mixed prebuilt + custom**: compose a gateway with a `main` tool + a `lib/mcp_server` tool. (needs reference server → `arcade login`/`arcade deploy`)
- [ ] 2.4**`whoami` execution proof** that calls run as the calling user. (needs reference server)
- Reference server built at `lib/mcp_server` (echo/add/whoami); locally validated by `arcade deploy` (3 tools, 0 secrets). **`arcade deploy` is cloud-only (finding)** — see LIVE-POC.
- [ ] 2.7**mixed prebuilt + custom**: needs the ref server behind the self-hosted Engine via the **register path** (run `server.py --transport http` + cloudflared tunnel + dashboard Add Server), then compose a gateway (a `main` tool + `echo`). Doubles as cat-9 Stage-2.
- [ ] 2.4 — **`whoami` execution proof**: once registered, call whoami as A vs B (expect A→A, B→B).
- [ ] 2.8 — finalize scores once the above land.
+13
View File
@@ -0,0 +1,13 @@
# Environment variables for mcp_server MCP server
#
# Copy this file to .env and fill in your values:
# cp .env.example .env
#
# The .env file will be automatically discovered when running your server,
# even from subdirectories like src/mcp_server/.
#
# IMPORTANT: Never commit your .env file to version control!
# Example secret used by the whisper_secret tool
# Replace with your actual secret value
MY_SECRET_KEY="Your tools can have secrets injected at runtime!"
+38
View File
@@ -0,0 +1,38 @@
[project]
name = "mcp_server"
version = "0.1.0"
description = "MCP Server created with Arcade.dev"
requires-python = ">=3.10"
dependencies = [
"arcade-mcp-server>=1.17.0,<2.0.0",
"httpx>=0.28.0,<1.0.0",
]
[project.optional-dependencies]
dev = [
"arcade-mcp[all]>=1.15.0,<2.0.0",
"pytest>=7.0.0",
"pytest-asyncio>=0.21.0",
"mypy>=1.0.0",
"ruff>=0.1.0",
]
# Tell Arcade.dev that this package has Arcade tools
[project.entry-points.arcade_toolkits]
toolkit_name = "mcp_server"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/mcp_server"]
[tool.ruff]
line-length = 100
target-version = "py312"
[tool.mypy]
python_version = "3.12"
warn_unused_configs = true
disallow_untyped_defs = false
+44
View File
@@ -0,0 +1,44 @@
#!/usr/bin/env python3
"""arcade-eval reference MCP server.
Deterministic, no-auth tools used as a shared eval fixture across categories:
- echo(text) -> returns text unchanged (protocol / curation / mixed-gateway)
- add(a, b) -> a + b (deterministic invocation)
- whoami() -> the calling user's id, server-side (per-user EXECUTION proof — cat 1/2)
`whoami` reads `context.user_id`, which the Engine populates from the calling user's identity
(the `Arcade-User-ID` header / auth-server `sub`). If a call as User A returns A and a call as
User B returns B, the tool provably executes as the calling user.
"""
import sys
from typing import Annotated
from arcade_mcp_server import Context, MCPApp
app = MCPApp(name="arcade_eval_ref", version="1.0.0")
@app.tool
def echo(text: Annotated[str, "Text to echo back"]) -> Annotated[str, "The same text"]:
"""Echo the input text unchanged."""
return text
@app.tool
def add(
a: Annotated[int, "First addend"],
b: Annotated[int, "Second addend"],
) -> Annotated[int, "The sum a + b"]:
"""Add two integers."""
return a + b
@app.tool
def whoami(context: Context) -> Annotated[str, "The calling user's id as seen server-side"]:
"""Return the calling user's identity as the server sees it (proves per-user execution)."""
return context.user_id or "<no user_id in context>"
if __name__ == "__main__":
transport = sys.argv[1] if len(sys.argv) > 1 else "stdio"
app.run(transport=transport, host="127.0.0.1", port=8000)