Model Context Protocol (MCP) lets Claude and other MCP-compatible AI systems interact with your three.ws account directly. When connected, Claude can list your avatars, render them as interactive 3D viewers, validate and inspect glTF files, and generate optimization suggestions — all through natural language.
This document covers the MCP server's tools, authentication, client configuration, and how to test locally.
Model Context Protocol is an open standard that connects AI assistants to external tool servers via JSON-RPC 2.0. Once your MCP client points at the three.ws server, the LLM sees a curated set of tools it can call autonomously during a conversation.
For three.ws specifically, this means Claude can:
- Browse and search your avatar library without you copy-pasting URLs
- Render any avatar inline as an interactive
<model-viewer>HTML artifact - Run the Khronos glTF-Validator against any public GLB or glTF URL
- Inspect mesh/texture/animation counts and geometry stats
- Get actionable optimization suggestions (compression, LOD, texture transcoding)
| Property | Value |
|---|---|
| URL | https://three.ws/api/mcp |
| Transport | Streamable HTTP (POST /api/mcp) |
| Protocol | MCP 2025-06-18, JSON-RPC 2.0 |
| Auth | OAuth 2.1 (end-user) or API key (server-to-server) |
For local development:
npm run dev
# MCP endpoint: http://localhost:3000/api/mcp
# Auth is still enforced — use an API key or OAuth token.The MCP server configuration is at .mcp.json in the project root, which Claude Code auto-discovers.
This page documents the hosted avatar/3D server at /api/mcp, but it's one of 38 three.ws MCP servers — all listed in the official MCP registry, so any MCP-compatible client can discover them by name.
There are two kinds. Hosted remote servers run over Streamable HTTP with nothing to install — add them by URL. Install-and-run servers are published on npm under the @three-ws scope and run locally over stdio — add them in one line with npx.
Six hosted remote servers (Streamable HTTP, no install):
| Server | Endpoint | What it does |
|---|---|---|
| three.ws | /api/mcp |
Avatars, glTF/GLB validation, agent data, memory, copy-trading (this page) |
| 3D Studio | /api/mcp-3d |
Paid text/image→3D, rigging, retexture, optimization |
| Agent wallet | /api/mcp-agent |
The agent's custodial wallet: balance, find + pay services, and monetize_endpoint |
| x402 Bazaar | /api/mcp-bazaar |
Discover and price paid agent services across the facilitator network |
| pump.fun | /api/pump-fun-mcp |
Free, read-only pump.fun + Solana token tools |
| IBM x402 | /api/ibm-mcp |
Pay-per-use IBM Granite AI |
Thirty-two install-and-run servers on npm under the @three-ws scope — each runs over stdio with one command:
# 3D & avatars
npx -y @three-ws/scene-mcp # speak a 3D diorama into being from one sentence
npx -y @three-ws/avatar-mcp # drop a live 3D avatar into any chat
npx -y @three-ws/avatar-agent # turn any GLB into a riggable 3D AI agent
npx -y @three-ws/mcp-server # full 3D + agent toolkit, paid per call in USDC
# Payments & the agent economy
npx -y @three-ws/x402-mcp # self-custodial wallet: find, inspect & pay any x402 service in USDC
npx -y @three-ws/three-token-mcp # price, hold, and burn $THREE on Solana
npx -y @three-ws/mcp-bridge # bridge that pays any x402 endpoint on the open web
npx -y @three-ws/ibm-x402-mcp # pay-per-use IBM Granite AI
# Market data, intel & discovery
npx -y @three-ws/intel-mcp # smart-money, signal feeds, KOL & copy-trade intel
npx -y @three-ws/pumpfun-mcp # free pump.fun + Solana token discovery
npx -y @three-ws/vanity-mcp # Solana vanity-address bounty market + rarity gallery
npx -y @three-ws/marketplace-mcp # browse the agent marketplace + skills catalog
# Naming & AI
npx -y @three-ws/naming-mcp # resolve .sol names + check *.threews.sol identity availability
npx -y @three-ws/ibm-watsonx-mcp # IBM watsonx.ai on your own account
# Autonomous agent control plane
npx -y @three-ws/autopilot-mcp # set scopes + daily $THREE spend caps, then propose/execute/undo
npx -y @three-ws/portfolio-mcp # portfolio value, PnL, balances, trade feed & signed transfers
npx -y @three-ws/provenance-mcp # append-only, signed, on-chain-verifiable agent action log
# Trading, signals & alerts
npx -y @three-ws/copy-mcp # manage copy-trade follows, sizing & guard rules
npx -y @three-ws/signals-mcp # discover signal feeds by proven edge; rank publishers
npx -y @three-ws/alerts-mcp # pump.fun alert rules across in-app / webhook / Telegram
npx -y @three-ws/kol-mcp # per-wallet KOL portfolio + trade analytics
# Account, inbox & discovery
npx -y @three-ws/notifications-mcp # inbox, read state, delivery prefs & Web Push devices
npx -y @three-ws/billing-mcp # plan quotas, metered usage, invoices & receipts
npx -y @three-ws/activity-mcp # trending agents/coins, $THREE holder board & activity ticker
# More AI & capability
npx -y @three-ws/vision-mcp # analyze & describe images via the three.ws vision pipeline
npx -y @three-ws/brain-mcp # run any LLM through the multi-provider router
npx -y @three-ws/audio-mcp # TTS, STT, audio-to-face lipsync & motion-capture clips
# Coordination, gaming & learning
npx -y @three-ws/agenc-mcp # AgenC on-chain task marketplace + agent registry
npx -y @three-ws/agora-mcp # join Agora's agent economy: browse the board, claim & complete real work, earn $THREE
npx -y @three-ws/clash-mcp # Coin Clash faction battles
npx -y @three-ws/tutor-mcp # itemized learning-session ledger
npx -y @three-ws/loom-mcp # browse & contribute to the Loom 3D-creation galleryEvery one is also registered in the MCP registry under the io.github.nirholas/* namespace.
Deep dives — every tool, argument, env var, and example:
- Install-and-run: Scenes · x402 Wallet · Intel · Vanity · Naming · Marketplace
- Hosted remote: 3D Studio · Agent wallet · x402 Bazaar · IBM x402
Claude handles the OAuth handshake automatically via dynamic client registration (RFC 7591). When you first connect, it will:
- Register a client at
POST /oauth/register. - Open
GET /oauth/authorize?...in your browser for login and consent. - Exchange the authorization code at
POST /oauth/tokenwith PKCE (S256). - Cache the resulting JWT and refresh it automatically.
The access token carries scopes (avatars:read, avatars:delete, etc.) that gate which tools Claude can call. Metadata discovery endpoints follow RFC 8414 and RFC 9728:
GET /.well-known/oauth-authorization-server
GET /.well-known/oauth-protected-resource
On a 401, the WWW-Authenticate header points clients at the protected-resource metadata URL so they can begin the flow.
For scripts, CI, and server agents, generate a key at Dashboard → API Keys and pass it as a bearer token:
curl -X POST https://three.ws/api/mcp \
-H "Authorization: Bearer 3da_live_xxxxx" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'Keys are tied to a single user account and inherit that user's plan quotas.
Claude Code auto-discovers .mcp.json at the project root. Add your key to that file:
{
"mcpServers": {
"3d-agent": {
"url": "https://three.ws/api/mcp",
"headers": {
"Authorization": "Bearer 3da_live_xxxxx"
}
}
}
}Or add it globally in ~/.claude/settings.json under mcpServers with the same shape.
Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or the equivalent path on your OS:
{
"mcpServers": {
"3dagent": {
"command": "npx",
"args": ["-y", "@three-ws/mcp-server", "--url", "https://three.ws/"]
}
}
}This uses the standalone npm package, which handles OAuth locally. The --url flag lets you point at a local dev server.
Send POST /api/mcp with valid JSON-RPC 2.0 messages and a bearer token. The server is stateless — no session setup needed beyond the initialize handshake.
All tools return { content: [{ type, text }], structuredContent: {...} }. On error, isError: true is set and content[0].text contains the message.
Paginated list of the authenticated user's avatars.
Scope required: avatars:read
{
"type": "object",
"properties": {
"limit": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25 },
"cursor": { "type": "string", "description": "Opaque pagination cursor from previous response." },
"visibility": { "type": "string", "enum": ["private", "unlisted", "public"] }
},
"additionalProperties": false
}Returns each avatar's id, name, slug, size, visibility, and model_url (when publicly accessible).
Fetch a single avatar by id (UUID) or by your slug.
Scope required: avatars:read
{
"type": "object",
"properties": {
"id": { "type": "string", "format": "uuid" },
"slug": { "type": "string" }
},
"additionalProperties": false
}For private avatars, returns a short-lived signed URL (1-hour expiry). Public and unlisted avatars return a permanent CDN URL.
Full-text search over the public avatar gallery. No authentication required for the search itself.
{
"type": "object",
"properties": {
"q": { "type": "string", "description": "Free-text search over name and description." },
"tag": { "type": "string", "description": "Filter to one tag." },
"limit": { "type": "integer", "minimum": 1, "maximum": 50, "default": 12 }
},
"additionalProperties": false
}Returns a complete <model-viewer> HTML document for the specified avatar. Claude renders this as an inline HTML artifact — an interactive 3D viewer that supports orbit controls, auto-rotate, and AR on mobile.
Scope required: avatars:read
{
"type": "object",
"properties": {
"id": { "type": "string", "format": "uuid" },
"slug": { "type": "string" },
"auto_rotate": { "type": "boolean", "default": true },
"background": { "type": "string", "description": "CSS background color or gradient.", "default": "transparent" },
"height": { "type": "string", "default": "480px" },
"width": { "type": "string", "default": "100%" },
"camera_orbit": { "type": "string", "description": "model-viewer camera-orbit value, e.g. \"0deg 80deg 2m\"." },
"poster": { "type": "string", "description": "HTTPS URL of a poster image shown while loading." },
"ar": { "type": "boolean", "default": true, "description": "Include AR button for mobile." }
},
"additionalProperties": false
}The response contains two content entries: a short text summary (for the transcript) and a resource entry with mimeType: "text/html" that MCP clients render inline.
Note: Agents whose embed policy sets surfaces.mcp = false cannot be rendered via this tool. The server returns error code -32000 with message embed_denied_surface in that case.
Soft-delete an avatar you own. Irreversible from the API (contact support to recover).
Scope required: avatars:delete
{
"type": "object",
"properties": {
"id": { "type": "string", "format": "uuid" }
},
"required": ["id"],
"additionalProperties": false
}Run the Khronos glTF-Validator against any public HTTPS GLB or glTF URL. Returns error, warning, info, and hint counts with detailed per-issue messages. SSRF-hardened: only public https:// URLs are fetched.
Rate limit: 10 calls/minute per user.
{
"type": "object",
"properties": {
"url": { "type": "string", "format": "uri", "description": "Public https URL of a .glb or .gltf file." },
"max_issues": { "type": "integer", "minimum": 1, "maximum": 500, "default": 100 }
},
"required": ["url"],
"additionalProperties": false
}Example response text:
glTF-Validator report for avatar.glb (1842.3 KB)
Errors: 0, Warnings: 2, Infos: 4, Hints: 1
[WRN] ACCESSOR_ELEMENT_OUT_OF_RANGE: … @ /accessors/3
[WRN] MESH_PRIMITIVE_UNUSED_TEXCOORD: … @ /meshes/0/primitives/0
Parse a remote GLB/glTF and return structural statistics: scene/node/mesh counts, vertex and triangle totals, material and texture summaries, animation count, extensions used. Pure inspection — no pass/fail verdict, no spec compliance check.
Rate limit: 30 calls/minute per user.
{
"type": "object",
"properties": {
"url": { "type": "string", "format": "uri", "description": "Public https URL of a .glb or .gltf file." }
},
"required": ["url"],
"additionalProperties": false
}Example response text:
Model: avatar.glb (1.80 MB, glb)
Generator: Blender 4.1 · glTF 2.0
Scenes: 1, Nodes: 47, Meshes: 12, Materials: 8, Textures: 10
Animations: 3, Skins: 1
Vertices: 18,432, Triangles: 24,108
Indexed primitives: 12, Non-indexed: 0
Extensions used: KHR_materials_unlit
Textures:
• Albedo — image/jpeg 1024×1024, 184.2 KB
• Normal — image/png 512×512, 92.7 KB
structuredContent carries the full structured object for programmatic processing.
Inspect the model and return actionable suggestions for reducing file size and draw-call overhead: triangle budget, Draco/Meshopt compression, oversized textures, KTX2 transcoding, non-indexed primitives, redundant materials, and more. Each suggestion includes a severity (info, warn, critical) and a size-reduction estimate.
Rate limit: 10 calls/minute per user.
{
"type": "object",
"properties": {
"url": { "type": "string", "format": "uri", "description": "Public https URL of a .glb or .gltf file." }
},
"required": ["url"],
"additionalProperties": false
}Example response text:
[CRIT] large_textures: 3 textures exceed 512×512 — consider resizing. — estimated 60% size reduction
[WARN] no_draco: No geometry compression detected — apply Draco or Meshopt. — estimated 40% size reduction
[INFO] ktx2_transcoding: Convert PNG/JPEG textures to KTX2 for GPU-native compression.
| Scope | Limit |
|---|---|
| Per IP (all) | 600 requests / minute |
| Per user (all) | 1 200 requests / minute |
validate_model |
10 calls / minute / user |
inspect_model |
30 calls / minute / user |
optimize_model |
10 calls / minute / user |
Rate-limit errors return JSON-RPC error code -32000 with message rate_limited and a retry_after field (seconds).
Here is a realistic conversation showing how Claude uses the MCP tools end-to-end.
User:
I just uploaded a character called "storm-mage". Can you check if it's valid, show me its stats, and then render it?
Claude internally calls:
-
get_avatar({ slug: "storm-mage" })— resolves the UUID and model URL. -
validate_model({ url: "https://cdn.three.ws/u/…/storm-mage.glb" })— runs the Khronos validator.Response:
glTF-Validator report for storm-mage.glb (3241.0 KB) Errors: 0, Warnings: 1, Infos: 2, Hints: 0 [WRN] NODE_EMPTY: node "Armature" has no mesh and no children -
inspect_model({ url: "https://cdn.three.ws/u/…/storm-mage.glb" })— structural overview.Response:
Model: storm-mage.glb (3.17 MB, glb) Generator: Blender 4.2 · glTF 2.0 Scenes: 1, Nodes: 63, Meshes: 18, Materials: 11, Textures: 14 Animations: 7, Skins: 1 Vertices: 31,204, Triangles: 41,892 -
render_avatar({ slug: "storm-mage", auto_rotate: true, height: "520px" })— renders the HTML artifact.
Claude replies:
Your storm-mage avatar looks good! The validator found zero errors and one minor warning: an empty "Armature" node that has no mesh or children — harmless but you can clean it up in Blender.
Stats: 18 meshes, 11 materials, 7 animations, ~42K triangles — well within real-time budget. Here it is:
[inline 3D viewer appears as an interactive HTML artifact]
MCP errors follow the JSON-RPC error object shape:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32602,
"message": "unknown tool: load_model",
"data": null
}
}| Code | Meaning |
|---|---|
-32600 |
Invalid JSON-RPC request (e.g. wrong jsonrpc version) |
-32601 |
Method not found |
-32602 |
Invalid params or unknown tool name |
-32603 |
Internal server error |
-32002 |
Insufficient OAuth scope for the requested tool |
-32000 |
Server error: rate_limited (includes retry_after), embed_denied_surface |
Tool execution errors (avatar not found, fetch failure, validation library crash) do not use the JSON-RPC error channel. They return a normal result with isError: true and the message in content[0].text. This follows the MCP spec convention and allows tool-error recovery without aborting a batch.
Authentication errors return HTTP 401 with a WWW-Authenticate header. The header includes the protected-resource metadata URL so compliant clients (Claude Desktop, Claude Code) can start the OAuth flow automatically.
Clone the repo and start the dev server:
git clone https://github.com/nirholas/three.ws
npm install
npm run dev
# MCP endpoint: http://localhost:3000/api/mcpAuthentication is still enforced in dev mode. Use your API key in the Authorization header, or point a local OAuth client at the dev server.
Test the server with mcp-inspector:
npx @modelcontextprotocol/inspector http://localhost:3000/api/mcpmcp-inspector gives you a browser UI to call tools manually, inspect responses, and validate JSON schemas before wiring up a full Claude workflow.
To point Claude Code at your local server, update .mcp.json:
{
"mcpServers": {
"3d-agent": {
"url": "http://localhost:3000/api/mcp",
"headers": {
"Authorization": "Bearer 3da_live_xxxxx"
}
}
}
}Restart Claude Code after editing .mcp.json so the new server config is picked up.