Local stdio MCP server for Open Creator Rails operator tooling. Exposes 9 creator-facing tools to AI clients (Claude Desktop, Cursor). No hosted instance — runs as a subprocess of your AI client, communicates over stdin/stdout.
docs/design.md— transport model, security, operator-as-payer mechanics, testnet config snippet
| Tool | Description |
|---|---|
ocr_create_asset |
Deploy a new Asset contract via the registry |
ocr_revoke_subscription |
Revoke a subscriber's entitlement (asset owner) |
ocr_grant_subscription |
Sponsor a subscription — operator is payer |
ocr_extend_subscription |
Extend an existing subscription — operator is payer |
ocr_batch_revoke |
Revoke multiple subscribers on a single asset |
ocr_claim_fees_batch |
Claim registry fees for multiple subscribers |
ocr_list_assets |
List assets by registry address |
ocr_get_subscriptions |
List subscriptions for an asset |
ocr_check_subscription |
On-chain active-status check (ground truth) |
cp .env.example .env
# fill in .env
npm install
npm run build| Variable | Required | Description |
|---|---|---|
RPC_URL |
yes | HTTP RPC endpoint for the target chain |
PRIVATE_KEY |
yes | Operator signing key (pays gas + sponsors subscriptions) |
ASSET_REGISTRY_ADDRESS |
yes | Deployed AssetRegistry contract address |
CHAIN_ID |
yes | Chain ID (default: 84532 — Base Sepolia) |
INDEXER_URL |
no | Ponder indexer GraphQL endpoint — read tools fall back to on-chain event scan if absent |
Add to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"open-creator-rails": {
"command": "node",
"args": ["/absolute/path/to/open-creator-rails.mcp/dist/index.js"],
"env": {
"RPC_URL": "https://sepolia.base.org",
"PRIVATE_KEY": "0xyour_key",
"ASSET_REGISTRY_ADDRESS": "0xD27891D6244eDb5088E45B1AbF2791bB17fF7274",
"CHAIN_ID": "84532"
}
}
}
}npm run serve # tsx src/index.ts — stable stdio, no file watcher (use for manual testing)
npm run dev # tsx watch — live reload, clears terminal on restart
npm run typecheck # type-check without emitting
npm test # vitestSee .invariants. Key constraints:
operator_is_payer_not_subscriber(FROZEN) — operator wallet is payer in grant/extend; subscriber identity is always caller-suppliedwrite_tools_require_private_key(FROZEN) — server refuses to start with zero or missing keysubscriber_derivation_standard_formula(FROZEN) — all subscriber IDs usekeccak256(abi.encode(subscriberId, subscriberAddress))