mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-14 05:42:32 +00:00
src/upstream/credential.ts defines what this service holds on a user's behalf and how it reaches an upstream request. The only kind today is an Artcraft session (the signed_session JWT from sign-in) sent as the `session` header; `kind` is stored in grant props from the start so a backend-issued credential can replace it later without touching tools or the client (swap point 2 in mcp/CLAUDE.md). The contract includes non-leaking toString/toJSON: accidental string or JSON conversion yields describe(), never the secret (the secret lives in a private field). Sign-in values are rejected if empty, non-ASCII, or containing whitespace/CRLF (header injection). Unknown prop kinds are an error, not a fallthrough. Tests (9): header attached exactly once and nothing else set, replace semantics, props round-trip, no leak via describe/String/JSON/keys, and validation firing on empty, injection, unknown kind, missing secret, non-object props. Claude-Session: https://claude.ai/code/session_01H3gfN2NCx3hBXSrZXYHUQ3
Artcraft MCP server
Cloudflare Worker at mcp.getartcraft.com. Read CLAUDE.md first — it holds the constraints,
the architecture, and the working method; this file is only how to run things.
Run locally
corepack enable # once; provides the pinned pnpm
pnpm install
cp .dev.vars.example .dev.vars
pnpm --filter @artcraft/mcp-fake-upstream dev # fake API on http://localhost:12345
pnpm dev # MCP server on http://localhost:8787
Local never talks to production: wrangler.toml's top-level block points at the fake, and
src/config.ts refuses to start otherwise.
Check everything
pnpm check # typecheck (regenerates Worker types) · lint · format · test
pnpm test # vitest, inside workerd with the local bindings
Deploy
Deploys run from .github/workflows/mcp.yml on main once the Cloudflare secrets exist
(docs/infra-request.md). Manual deploys, when needed:
pnpm deploy:preview # workers.dev, talks to the deployed fake
pnpm deploy:production # mcp.getartcraft.com, talks to api.storyteller.ai
Layout
See CLAUDE.md → Layout.