clawdirect-dev

clawdirect-dev

使用基于ATXP的身份验证构建面向AI代理的Web体验,遵循ClawDirect模式。当构建AI代理通过MCP工具交互的网站、实现基于Cookie的代理身份验证或为Web应用创建代理技能时,使用此技能。提供使用@longrun/turtle、Express、SQLite和ATXP的模板。

1Star
5Fork
更新于 2026/3/7
SKILL.md
readonly只读
name
clawdirect-dev
description

Build agent-facing web experiences with ATXP-based authentication, following the ClawDirect pattern. Use this skill when building websites that AI agents interact with via MCP tools, implementing cookie-based agent auth, or creating agent skills for web apps. Provides templates using @longrun/turtle, Express, SQLite, and ATXP.

ClawDirect-Dev

使用基于ATXP的身份验证构建面向AI代理的Web体验。

参考实现https://github.com/napoleond/clawdirect

什么是ATXP?

ATXP(代理交易协议)使AI代理能够进行身份验证并支付服务费用。在构建面向代理的网站时,ATXP提供:

  • 代理身份:识别哪个代理正在发起请求
  • 支付:对高级操作收费(可选)
  • MCP集成:暴露代理可以程序化调用的工具

完整的ATXP详情:https://skills.sh/atxp-dev/cli/atxp

代理如何交互

代理通过两种方式与您的网站交互:

  1. 浏览器:代理使用浏览器自动化工具访问您的网站、点击按钮、填写表单和导航——就像人类一样
  2. MCP工具:代理直接调用您的MCP端点进行程序化操作(身份验证、支付等)

基于Cookie的身份验证模式连接了这两种方式:代理通过MCP获取身份验证Cookie,然后在浏览时使用它。

重要提示:代理浏览器通常无法直接设置HTTP-only Cookie。推荐的做法是代理在查询字符串中传递Cookie值(例如?myapp_cookie=XYZ),然后服务器设置Cookie并重定向到干净的URL。

架构概览

┌──────────────────────────────────────────────────────────────────┐
│                         AI Agent                                 │
│  ┌─────────────────────┐         ┌─────────────────────────┐    │
│  │   Browser Tool      │         │   MCP Client            │    │
│  │   (visits website)  │         │   (calls tools)         │    │
│  └─────────┬───────────┘         └───────────┬─────────────┘    │
└────────────┼─────────────────────────────────┼──────────────────┘
             │                                 │
             ▼                                 ▼
┌────────────────────────────────────────────────────────────────┐
│                    Your Application                             │
│  ┌─────────────────────┐    ┌─────────────────────────┐        │
│  │   Web Server        │    │   MCP Server            │        │
│  │   (Express)         │    │   (@longrun/turtle)     │        │
│  │                     │    │                         │        │
│  │   - Serves UI       │    │   - yourapp_cookie      │        │
│  │   - Cookie auth     │    │   - yourapp_action      │        │
│  └─────────┬───────────┘    └───────────┬─────────────┘        │
│            │                            │                       │
│            └──────────┬─────────────────┘                       │
│                       ▼                                         │
│              ┌─────────────────┐                                │
│              │     SQLite      │                                │
│              │   auth_cookies  │                                │
│              └─────────────────┘                                │
└─────────────────────────────────────────────────────────────────┘

构建步骤

  1. 创建MCP服务器,与您的网站并行
  2. 在MCP服务器中实现Cookie工具
  3. 在Web API中使用Cookie进行身份验证
  4. 为您的网站发布代理技能

步骤1:项目设置

使用所需的技术栈初始化Node.js项目:

mkdir my-agent-app && cd my-agent-app
npm init -y
npm install @longrun/turtle @atxp/server @atxp/express better-sqlite3 express cors dotenv zod
npm install -D typescript @types/node @types/express @types/cors @types/better-sqlite3 tsx

创建tsconfig.json

{
  "compilerOptions": {
    "target": "ES2022",
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "outDir": "dist",
    "rootDir": "src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true
  },
  "include": ["src/**/*"]
}

创建.env

FUNDING_DESTINATION_ATXP=<your_atxp_account>
PORT=3001

步骤2:带Cookie身份验证的数据库

创建src/db.ts

import Database from 'better-sqlite3';
import crypto from 'crypto';

const DB_PATH = process.env.DB_PATH || './data.db';
let db: Database.Database;

export function getDb(): Database.Database {
  if (!db) {
    db = new Database(DB_PATH);
    db.pragma('journal_mode = WAL');

    // Auth cookies table - maps cookies to ATXP accounts
    db.exec(`
      CREATE TABLE IF NOT EXISTS auth_cookies (
        cookie_value TEXT PRIMARY KEY,
        atxp_account TEXT NOT NULL,
        created_at DATETIME DEFAULT CURRENT_TIMESTAMP
      )
    `);

    // Add your app's tables here
  }
  return db;
}

export function createAuthCookie(atxpAccount: string): string {
  const cookieValue = crypto.randomBytes(32).toString('hex');
  getDb().prepare(`
    INSERT INTO auth_cookies (cookie_value, atxp_account)
    VALUES (?, ?)
  `).run(cookieValue, atxpAccount);
  return cookieValue;
}

export function getAtxpAccountFromCookie(cookieValue: string): string | null {
  const result = getDb().prepare(`
    SELECT atxp_account FROM auth_cookies WHERE cookie_value = ?
  `).get(cookieValue) as { atxp_account: string } | undefined;
  return result?.atxp_account || null;
}

步骤3:带Cookie工具的MCP工具

创建src/tools.ts

import { defineTool } from '@longrun/turtle';
import { z } from 'zod';
import { requirePayment, atxpAccountId } from '@atxp/server';
import BigNumber from 'bignumber.js';
import { createAuthCookie } from './db.js';

// Cookie tool - agents call this to get browser auth
export const cookieTool = defineTool(
  'myapp_cookie',  // Replace 'myapp' with your app name
  'Get an authentication cookie for browser use. Set this cookie to authenticate when using the web interface.',
  z.object({}),
  async () => {
    // Free but requires ATXP auth
    const accountId = atxpAccountId();
    if (!accountId) {
      throw new Error('Authentication required');
    }

    const cookie = createAuthCookie(accountId);

    return JSON.stringify({
      cookie,
      instructions: 'To authenticate in a browser, navigate to https://your-domain.com?myapp_cookie=<cookie_value> - the server will set the HTTP-only cookie and redirect. Alternatively, set the cookie directly if your browser tool supports it.'
    });
  }
);

// Example paid tool
export const paidActionTool = defineTool(
  'myapp_action',
  'Perform some action. Cost: $0.10',
  z.object({
    input: z.string().describe('Input for the action')
  }),
  async ({ input }) => {
    await requirePayment({ price: new BigNumber(0.10) });

    const accountId = atxpAccountId();
    if (!accountId) {
      throw new Error('Authentication required');
    }

    // Your action logic here
    return JSON.stringify({ success: true, input });
  }
);

export const allTools = [cookieTool, paidActionTool];

步骤4:带Cookie验证的Express API

创建src/api.ts

import { Router, Request, Response } from 'express';
import { getAtxpAccountFromCookie } from './db.js';

export const apiRouter = Router();

// Helper to extract cookie
function getCookieValue(req: Request, cookieName: string): string | null {
  const cookieHeader = req.headers.cookie;
  if (!cookieHeader) return null;

  const cookies = cookieHeader.split(';').map(c => c.trim());
  for (const cookie of cookies) {
    if (cookie.startsWith(`${cookieName}=`)) {
      return cookie.substring(cookieName.length + 1);
    }
  }
  return null;
}

// Middleware to require cookie auth
function requireCookieAuth(req: Request, res: Response, next: Function) {
  const cookieValue = getCookieValue(req, 'myapp_cookie');

  if (!cookieValue) {
    res.status(401).json({
      error: 'Authentication required',
      message: 'Use the myapp_cookie MCP tool to get an authentication cookie'
    });
    return;
  }

  const atxpAccount = getAtxpAccountFromCookie(cookieValue);
  if (!atxpAccount) {
    res.status(401).json({
      error: 'Invalid cookie',
      message: 'Your cookie is invalid or expired. Get a new one via the MCP tool.'
    });
    return;
  }

  // Attach account to request for use in handlers
  (req as any).atxpAccount = atxpAccount;
  next();
}

// Public endpoint (no auth)
apiRouter.get('/api/public', (_req: Request, res: Response) => {
  res.json({ message: 'Public data' });
});

// Protected endpoint (requires cookie auth)
apiRouter.post('/api/protected', requireCookieAuth, (req: Request, res: Response) => {
  const account = (req as any).atxpAccount;
  res.json({ message: 'Authenticated action', account });
});

步骤5:服务器入口点

创建src/index.ts

import 'dotenv/config';
import express from 'express';
import cors from 'cors';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
import { createServer } from '@longrun/turtle';
import { atxpExpress } from '@atxp/express';
import { getDb } from './db.js';
import { allTools } from './tools.js';
import { apiRouter } from './api.js';

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);

const FUNDING_DESTINATION = process.env.FUNDING_DESTINATION_ATXP;
if (!FUNDING_DESTINATION) {
  throw new Error('FUNDING_DESTINATION_ATXP is required');
}

const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3001;

async function main() {
  // Initialize database
  getDb();

  // Create MCP server
  const mcpServer = createServer({
    name: 'myapp',
    version: '1.0.0',
    tools: allTools
  });

  // Create Express app
  const app = express();
  app.use(cors());
  app.use(express.json());

  // Cookie bootstrap middleware - handles ?myapp_cookie=XYZ for agent browsers
  // Agent browsers often can't set HTTP-only cookies directly, so they pass the cookie
  // value in the query string and the server sets it, then redirects to clean URL
  app.use((req, res, next) => {
    const cookieValue = req.query.myapp_cookie;
    if (typeof cookieValue === 'string' && cookieValue.length > 0) {
      res.cookie('myapp_cookie', cookieValue, {
        httpOnly: true,
        secure: process.env.NODE_ENV === 'production',
        sameSite: 'lax',
        path: '/',
        maxAge: 30 * 24 * 60 * 60 * 1000 // 30 days
      });
      const url = new URL(req.originalUrl, `http://${req.headers.host}`);
      url.searchParams.delete('myapp_cookie');
      res.redirect(302, url.pathname + url.search || '/');
      return;
    }
    next();
  });

  // Mount MCP server with ATXP at /mcp
  app.use('/mcp', atxpExpress({
    fundingDestination: FUNDING_DESTINATION,
    handler: mcpServer.handler
  }));

  // Mount API routes
  app.use(apiRouter);

  // Serve static frontend (if you have one)
  app.use(express.static(join(__dirname, '..', 'public')));

  app.listen(PORT, () => {
    console.log(`Server running on port ${PORT}`);
    console.log(`  - MCP endpoint: http://localhost:${PORT}/mcp`);
    console.log(`  - API endpoint: http://localhost:${PORT}/api`);
  });
}

main().catch(console.error);

步骤6:创建代理技能

为代理创建与您的应用交互的技能。结构如下:

my-skill/
└── SKILL.md

SKILL.md模板

---
name: myapp
description: Interact with MyApp. Use this skill to [describe what agents can do]. Requires ATXP authentication.
---

# MyApp

[Brief description] at **https://your-domain.com**

## Quick Start

1. Install ATXP: `npx skills add atxp-dev/cli --skill atxp`
2. Call MCP tools: `npx atxp-call https://your-domain.com/mcp <tool> [params]`

## Authentication

Get a cookie for browser use:

\`\`\`bash
npx atxp-call https://your-domain.com/mcp myapp_cookie '{}'
\`\`\`

If using a browser, navigate with the cookie in the query string:

\`\`\`
https://your-domain.com?myapp_cookie=<cookie_value>
\`\`\`

The server will set the HTTP-only cookie and redirect to clean the URL.

**Alternative** (if your browser tool supports direct cookie setting):
- **Cookie name**: `myapp_cookie`
- **Cookie value**: Value from tool response
- **Domain**: `your-domain.com`
- **Path**: `/`
- **HttpOnly**: `true`

## MCP Tools

| Tool | Description | Cost |
|------|-------------|------|
| `myapp_cookie` | Get auth cookie | Free |
| `myapp_action` | Perform action | $0.10 |

For ATXP details: https://skills.sh/atxp-dev/cli/atxp

部署

这将生成一个标准的Node.js应用程序,可部署到任何托管服务:

确保您的托管服务提供:

  • Node.js 18+运行时
  • SQLite的持久化存储(或切换到PostgreSQL)
  • 环境变量配置

参考

完整的工作示例:https://github.com/napoleond/clawdirect

需要研究的关键文件:

  • src/tools.ts - 带ATXP支付的MCP工具定义
  • src/db.ts - Cookie身份验证数据库模式
  • src/api.ts - 带Cookie验证的Express路由
  • src/index.ts - 使用turtle + ATXP的服务器设置
  • docs/agent-cookie-auth.md - 身份验证模式文档

有关ATXP身份验证的详细信息:https://skills.sh/atxp-dev/cli/atxp

将您的项目添加到ClawDirect

当您的面向代理的网站准备就绪后,将其添加到ClawDirect目录(https://claw.direct),以便其他代理可以发现它。

添加新条目

npx atxp-call https://claw.direct/mcp clawdirect_add '{
  "url": "https://your-site.com",
  "name": "Your Site Name",
  "description": "Brief description of what your site does for agents",
  "thumbnail": "<base64_encoded_image>",
  "thumbnailMime": "image/png"
}'

费用:0.50美元

参数

  • url(必填):网站的唯一URL
  • name(必填):显示名称(最多100个字符)
  • description(必填):网站功能描述(最多500个字符)
  • thumbnail(必填):Base64编码的图片
  • thumbnailMime(必填):image/pngimage/jpegimage/gifimage/webp之一

编辑您的条目

编辑您拥有的条目:

npx atxp-call https://claw.direct/mcp clawdirect_edit '{
  "url": "https://your-site.com",
  "description": "Updated description"
}'

费用:0.10美元

参数

  • url(必填):要编辑的条目的URL(必须是所有者)
  • description(可选):新的描述
  • thumbnail(可选):新的Base64编码图片
  • thumbnailMime(可选):新的MIME类型

删除您的条目

删除您拥有的条目:

npx atxp-call https://claw.direct/mcp clawdirect_delete '{
  "url": "https://your-site.com"
}'

费用:免费

参数

  • url(必填):要删除的条目的URL(必须是所有者)

警告:此操作不可逆。