An autonomous ElizaOS agent that licenses derivative IP on the Story Protocol aeneid testnet. The agent calls the story-ip-graph-mcp server (via @elizaos/plugin-mcp) to register a remix of a demo IP, then reads back and narrates the on-chain lineage.
This repo is the visible demo on top of that server — "Module 1, layer 2": the MCP server is the reusable on-chain toolbox, and this agent is the user-facing application that drives it autonomously from a natural-language goal.
-
One-time fixture (
npm run seed). A small, idempotent provisioning step uses the Storycore-sdkdirectly to create the base on-chain state the demo needs:- a parent IP,
- an SPG NFT collection, and
- commercial-remix license terms.
These are deliberately the base operations that the MCP server does not expose — the server focuses on graph operations (derivatives + lineage reads), so the demo bootstraps its own parent. The result is written to
fixtures.json(gitignored). Running it again is a no-op iffixtures.jsonalready exists for the current network. -
The agent runs autonomously. Given a goal like "Create a remix derivative of our demo IP and show me its lineage," the agent calls the MCP server's tools on its own:
register_ip_and_make_derivative— mints a derivative of the fixture parent and returns itsipId+txHash,get_parent_ips/get_ancestors— read the lineage back from chain so the agent can confirm and narrate the result.
The agent is instructed never to claim success without a
txHashand a confirming read.
Build the sibling MCP server first:
cd ../story-ip-graph-mcp && npm install && npm run buildThis produces ../story-ip-graph-mcp/dist/server.js, which both the agent and the deterministic test launch over stdio.
You also need:
- Node.js 20+,
- an Anthropic API key,
- a testnet wallet private key funded with aeneid test tokens.
Run these in order from the repo root:
-
Install dependencies.
npm install
If this fails on an ElizaOS transitive postinstall, use:
npm install --ignore-scripts
-
Create your
.env.cp .env.example .env
Fill in
ANTHROPIC_API_KEYand a funded testnetWALLET_PRIVATE_KEY. LeaveSTORY_NETWORK=aeneid. -
Provision fixtures.
npm run seed
Idempotent; provisions the parent IP + SPG collection + commercial-remix terms and writes
fixtures.json. Your.envis auto-loaded by this script (via dotenv), so justnpm run seedworks after filling.env— no manualexportneeded. -
Render the character.
npm run build:character
Renders
ip-licensor.character.json(gitignored) — the ElizaOS character file with the fixture IDs and MCP server path baked in, plus the testnet key injected for the server. Likeseed, this script auto-loads.env(via dotenv), so no manualexportis needed. -
Start the agent.
npm run start:agent
Then type a goal, e.g. "Create a remix derivative of our demo IP and show me its lineage."
A gated integration test proves the fixture → server → derivative path on-chain without involving the agent or an LLM. It is skipped by default and only runs when explicitly enabled:
RUN_AENEID_IT=1 STORY_NETWORK=aeneid WALLET_PRIVATE_KEY=0x<key> npx vitest run test/integration/derivative.aeneid.test.tsIt connects directly to the MCP server over stdio, calls register_ip_and_make_derivative against the fixture parent, and asserts that get_parent_ips reports the fixture parent in the new derivative's lineage. Requires npm run seed to have been run first.
The rest of the suite (config, fixture store, character builder) is pure unit tests and runs with npx vitest run.
- Testnet only. Use a throwaway aeneid key. Never use a mainnet or otherwise valuable key.
- The key lives only in your
.envand in the gitignoredip-licensor.character.json— neither is committed (see.gitignore). - The
story-ip-graph-mcpserver redacts the private key from any error output, and this repo'sredactKeyhelper does the same for local logging.
A live autonomous run. Goal given to the agent: "Create a remix derivative of our demo IP and show me its lineage." With no further instruction, the agent selected the register_ip_and_make_derivative tool, chose the parameters itself, wrote the derivative on-chain, and read the lineage back.
The agent's own logged reasoning:
"The user wants to create a derivative/remix of the demo IP. …use
register_ip_and_make_derivativewith spgNftContract=0xacaD37bF…, parentIpIds=[0x9A90F1C5…1f65], and licenseTermsIds=[1894]. This tool mints an NFT, registers it as an IP, and links it as a derivative in one transaction."
Result, confirmed on-chain:
| New (child) IP | 0x5efBB7999B859eDF0Ff95483E7176c3F8699D7d0 |
| Transaction | 0x46a0fdd1…435c — status 0x1, block 19020034 |
| Parent IP | 0x9A90F1C5d4875181747C3585f01b5c065bea1f65 |
| License terms | 1894 (commercial-remix PIL) |
The agent then narrated the lineage back: "Derivative IP Successfully Registered! … Direct parent: 0x9A90F1C5…1f65 ✓ … linked under license terms ID 1894 (commercial remix)." The deterministic test below exercises the same on-chain path without an LLM.
Built on top of story-ip-graph-mcp, which provides the on-chain derivative + lineage MCP tools this agent drives.
Built for the Story "AI × IP" direction, in two independent tracks:
Track A — agents
- story-ip-graph-mcp — MCP server: derivative/remix registration + IP-graph lineage reads
- story-ip-agent-demo — autonomous ElizaOS agent that drives the MCP server — this repo
Track B — data
- story-subgraph — open-source The Graph subgraph indexing live Story Protocol
- story-ip-explorer — Next.js dashboard + lineage explorer over the subgraph
MIT.