Self-hosting
Deploy your own Papertrade AI remote MCP server to Cloudflare Workers in five minutes, with OAuth, KV storage and the trading widget.
The hosted server is one Cloudflare Worker. You can run your own copy so that you, and only you, hold the encrypted session keys.
Requirements#
- A Cloudflare account (the free plan works)
- Node.js 20.10+
Deploy#
git clone https://github.com/nirholas/papertrade-ai
cd papertrade-ai
npm install
npx wrangler kv namespace create OAUTH_KV
Edit wrangler.jsonc:
- set
kv_namespaces[0].idto the id printed above; - set
nameto your Worker name; - set
vars.PUBLIC_URLto the URL the Worker will be served from (for examplehttps://papertrade.example.com).
Then set a random server secret and deploy:
openssl rand -base64 48 | npx wrangler secret put SERVER_SECRET
npm run deploy
SERVER_SECRET seals connect handles and signs trade quotes. Rotating it invalidates in-flight connects and previews only; connected apps keep working because their grants are encrypted with their own tokens.
After a deploy, npm run seo:indexnow asks Bing, Yandex and the other IndexNow search engines to recrawl every page in your sitemap. On your own domain, first replace the key in scripts/indexnow-key.mjs with your own 32 hex characters (openssl rand -hex 16); the site build publishes it as /<key>.txt so the engines can verify ownership.
Local development#
cp .dev.vars.example .dev.vars # then set SERVER_SECRET
npm run dev # http://127.0.0.1:8787
Set PUBLIC_URL=http://127.0.0.1:8787 in .dev.vars. OAuth allows plain HTTP only on loopback.
Architecture#
| Path | Handler |
|---|---|
/mcp | Authenticated MCP (Streamable HTTP, stateless) |
/public/mcp | Unauthenticated MCP with public tools |
/authorize, /token, /register | OAuth 2.1 via @cloudflare/workers-oauth-provider |
/account | Wallet sign-in to list and revoke connected apps |
/api/v1/*, /openapi.json | REST API |
| everything else | Static site from public/ |
Tool logic lives in src/tools/registry.ts and is shared by the Worker, the stdio CLI and the npm library, so all three behave identically.
Tests#
npm test # unit tests
npm run test:live # read-only checks against Papertrade mainnet
npm run typecheck
Edit this page on GitHub