> For the complete documentation index, see [llms.txt](https://docs.wildmeta.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.wildmeta.ai/trading-terminal/x402-support-and-extension/wildmeta-ai-skill-development-guide/quick-start.md).

# Quick Start

### **1. Initialize the Project**

```bash
mkdir my-trading-skill
cd my-trading-skill
npm init -y
```

### **2. Install Dependencies**

`package.json`:

```json
{
  "name": "my-trading-skill",
  "version": "1.0.0",
  "type": "module",
  "main": "server.js",
  "scripts": {
    "start": "node server.js",
    "dev": "node --watch server.js"
  },
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.0.0",
    "dotenv": "^16.6.1",
    "express": "^4.18.2"
  }
}
```

Install packages:

```bash
npm install
```

***

## **Core Implementation**

### **Base Server Structure**

```jsx
import express from 'express';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';
import {
  CallToolRequestSchema,
  ListToolsRequestSchema
} from '@modelcontextprotocol/sdk/types.js';
import dotenv from 'dotenv';

dotenv.config();

const app = express();
app.use(express.json());

const PORT = process.env.PORT || 3015;
const TRADE_API_BASE = process.env.TRADE_API_BASE || 'https://test-dex-api.heima.network';

// Create MCP protocol handler
const mcpServer = new Server(
  {
    name: 'my-trading-skill',
    version: '1.0.0'
  },
  {
    capabilities: {
      tools: {}
    }
  }
);
```

***

## **Defining Trading Tools**

The Skill exposes abilities to the AI Agent through **Tools**.\
Example: *open position* tool.

```jsx
mcpServer.setRequestHandler(ListToolsRequestSchema, async () => {
  return {
    tools: [
      {
        name: 'open_position',
        description: 'Open a position on the DEX. Requires skill_token authorization.',
        inputSchema: {
          type: 'object',
          properties: {
            skill_token: { type: 'string', description: 'WildMeta authorization token' },
            dex: { type: 'string', description: 'DEX identifier (e.g. hyperliquid)' },
            coin: { type: 'string', description: 'Trading asset (e.g. BTC, ETH)' },
            isBuy: { type: 'boolean', description: 'true=long, false=short' },
            limitPx: { type: 'string', description: 'Limit order price' },
            sz: { type: 'string', description: 'Position size' },
            orderType: { type: 'object', description: 'Order type configuration' }
          },
          required: ['skill_token', 'dex', 'coin', 'isBuy', 'sz']
        }
      }
    ]
  };
});
```

***

## **Tool Handler Implementation**

```jsx
mcpServer.setRequestHandler(CallToolRequestSchema, async (request) => {
  const { name, arguments: args } = request.params;

  if (name === 'open_position') {
    return await handleOpenPosition(args);
  }

  throw new Error(`Unknown tool: ${name}`);
});
```

***

## **Trading Operations Implementation**

### **Open Position**

```jsx
async function handleOpenPosition(args) {
  const { skill_token, dex, coin, isBuy, limitPx, sz, orderType } = args;

  if (!skill_token) {
    return {
      content: [{
        type: 'text',
        text: JSON.stringify({
          success: false,
          error: 'skill_token is required for authorization'
        })
      }]
    };
  }

  console.log(`📈 Open position: ${isBuy ? 'LONG' : 'SHORT'} ${sz} ${coin}`);

  try {
    const requestBody = {
      dex: dex || 'hyperliquid',
      coin,
      isBuy,
      limitPx: limitPx || '0',
      sz,
      orderType: orderType || {
        limit: { tif: 'Gtc' },
        trigger: { isMarket: false, triggerPx: '0', tpsl: '' }
      },
      cloid: `order_${Date.now()}`
    };

    const response = await fetch(`${TRADE_API_BASE}/openapi/trade/v1/open_position`, {
      method: 'POST',
      headers: {
        'X-Language': 'zh',
        'skill-token': skill_token,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(requestBody)
    });

    const data = await response.json();

    return {
      content: [{
        type: 'text',
        text: JSON.stringify({
          success: response.ok,
          order: requestBody,
          response: data
        })
      }]
    };
  } catch (error) {
    return {
      content: [{
        type: 'text',
        text: JSON.stringify({
          success: false,
          error: error.message
        })
      }]
    };
  }
}
```

***

## **HTTP Endpoints**

The Skill must expose an HTTP endpoint for MCP communication:

```jsx
// MCP endpoint
app.all('/message', async (req, res) => {
  try {
    const transport = new StreamableHTTPServerTransport({
      sessionIdGenerator: undefined,
      enableJsonResponse: true
    });

    res.on('close', () => transport.close());

    await mcpServer.connect(transport);
    await transport.handleRequest(req, res, req.body);
  } catch (error) {
    console.error('Request error:', error);
    res.status(500).json({ error: error.message });
  }
});

// Health check endpoint
app.get('/health', (req, res) => {
  res.json({
    status: 'healthy',
    server: 'my-trading-skill',
    version: '1.0.0',
    timestamp: new Date().toISOString()
  });
});

app.listen(PORT, () => {
  console.log(`🚀 Skill service running on port ${PORT}`);
});
```

***

## **Authorization Mechanism**

### **Skill Token Workflow**

```
1. User initiates a request
2. Frontend detects that a Skill requires signature authorization
3. Frontend requests wallet signature from the user
4. AI Agent automatically injects skill_token into tool parameters
5. Skill uses the token to call the WildMeta DEX API
```

#### Notes

* `skill_token` is generated by WildMeta frontend via wallet signature
* AI Agent automatically injects the token into tool calls
* Skills *must* include this token when calling WildMeta DEX API

***

## **Security Best Practices**

### **1. Token Validation**

```jsx
if (!skill_token) {
  return {
    content: [{
      type: 'text',
      text: JSON.stringify({
        success: false,
        error: 'skill_token is required'
      })
    }]
  };
}
```

### **2. Risk Controls**

```jsx
const MAX_SIZE = {
  BTC: 0.01,
  ETH: 0.1
};

if (parseFloat(sz) > MAX_SIZE[coin]) {
  return {
    success: false,
    error: `Position size exceeds max limit for ${coin}: ${MAX_SIZE[coin]}`
  };
}
```

### **3. Logging**

```jsx
console.log(`📈 Open position: ${isBuy ? 'LONG' : 'SHORT'} ${sz} ${coin}`);
console.log(`🔑 Token: ${skill_token.substring(0, 20)}...`);
console.log('📤 Request body:', JSON.stringify(requestBody, null, 2));
console.log('📥 Response:', data);
```

### **4. Error Handling**

```jsx
try {
  // trading logic
} catch (error) {
  console.error('❌ Trading error:', error);
  return {
    content: [{
      type: 'text',
      text: JSON.stringify({
        success: false,
        error: error.message,
        timestamp: new Date().toISOString()
      })
    }]
  };
}
```

***

## **Testing**

Create a script: `test.sh`

```bash
#!/bin/bash

echo "=== Health Check ==="
curl -s http://localhost:3015/health | jq .

echo -e "\n=== List Tools ==="
curl -s -X POST http://localhost:3015/message \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/list"
  }' | jq .

echo -e "\n=== Test Open Position (requires valid skill_token) ==="
curl -s -X POST http://localhost:3015/message \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "open_position",
      "arguments": {
        "skill_token": "test-token",
        "dex": "hyperliquid",
        "coin": "BTC",
        "isBuy": true,
        "sz": "0.001"
      }
    }
  }' | jq .
```

***

## **Full Example**

For a complete example, refer to:

`mcp-wildmeat-trader/server.js`

It includes:

* Full Skill server setup
* Multiple tools (open, close, cancel order)
* WildMeta DEX API integration
* Error handling
* Logging
* Security checks
