@clervo/mcp
Advanced tools
+1
-1
| { | ||
| "name": "@clervo/mcp", | ||
| "version": "0.1.0", | ||
| "version": "0.2.0", | ||
| "description": "Clervo x402 Gateway MCP server — 23 AI models, 8 free. One wallet, pay per call in USDC.", | ||
@@ -5,0 +5,0 @@ "type": "module", |
+73
-15
@@ -7,5 +7,7 @@ /** | ||
| * Tools exposed: | ||
| * clervo_chat — call any model (free or paid) | ||
| * clervo_models — list available models with pricing | ||
| * clervo_status — check operation status / receipt | ||
| * clervo_chat — call any model (free or paid) | ||
| * clervo_models — list available models with pricing | ||
| * clervo_search — web search (free, no API key) | ||
| * clervo_scrape — URL to markdown (free, no API key) | ||
| * clervo_status — check operation status / receipt | ||
| */ | ||
@@ -21,3 +23,3 @@ | ||
| name: 'clervo_chat', | ||
| description: 'Call an AI model through Clervo x402 Gateway. 8 free models available without payment. Use model "groq/llama-3.1-8b-instant" for fastest free response (170ms).', | ||
| description: 'Call an AI model through Clervo x402 Gateway. 13 free models available without payment. Use "groq/llama-3.1-8b-instant" for fastest (170ms) or "groq/llama-3.3-70b" for best free quality.', | ||
| inputSchema: { | ||
@@ -29,3 +31,3 @@ type: 'object', | ||
| type: 'string', | ||
| description: 'Model ID. Free: groq/llama-3.1-8b-instant, groq/llama-3.3-70b, sambanova/deepseek-v3.2, sambanova/llama-3.3-70b, hcn/qwen3.6-35b, hcn/step-3.7-flash, hcn/deepseek-v4-pro, hcn/auto. Paid: tongkhokr/claude-haiku-4.5, tongkhokr/claude-sonnet-5, tongkhokr/claude-opus-5, quickai/gpt-5.4-mini, quickai/gpt-5.5, quickai/gpt-5.6-sol (and more).', | ||
| description: 'Model ID. Free: groq/llama-3.1-8b-instant, groq/llama-3.3-70b, groq/qwen3.6-27b, groq/gpt-oss-120b, sambanova/llama-3.3-70b, nvidia/nemotron-ultra-550b, nvidia/deepseek-v4-flash. Paid: tongkhokr/claude-sonnet-5, tongkhokr/claude-opus-5, quickai/gpt-5.4-mini, quickai/gpt-5.5.', | ||
| }, | ||
@@ -39,4 +41,27 @@ message: { type: 'string', description: 'The user message to send.' }, | ||
| { | ||
| name: 'clervo_search', | ||
| description: 'Search the web. Returns structured results with titles, URLs, and snippets. Free, no API key needed. Use for finding current information, documentation, or research.', | ||
| inputSchema: { | ||
| type: 'object', | ||
| required: ['query'], | ||
| properties: { | ||
| query: { type: 'string', description: 'Search query (max 500 chars).' }, | ||
| max_results: { type: 'number', description: 'Number of results (1-10, default 5).' }, | ||
| }, | ||
| }, | ||
| }, | ||
| { | ||
| name: 'clervo_scrape', | ||
| description: 'Convert any URL to clean markdown. Free, no API key needed. Use for reading web pages, documentation, or extracting content from URLs.', | ||
| inputSchema: { | ||
| type: 'object', | ||
| required: ['url'], | ||
| properties: { | ||
| url: { type: 'string', description: 'The URL to scrape and convert to markdown.' }, | ||
| }, | ||
| }, | ||
| }, | ||
| { | ||
| name: 'clervo_models', | ||
| description: 'List all available Clervo models with pricing. Shows free models (no payment needed) and paid models (x402 USDC). 23 models across Groq, SambaNova, HCN, Claude, and GPT families.', | ||
| description: 'List all available Clervo models with pricing. Shows free models (no payment needed) and paid models (x402 USDC on Base). 26 models across Groq, SambaNova, Nvidia, Claude, and GPT families.', | ||
| inputSchema: { type: 'object', properties: {} }, | ||
@@ -65,6 +90,3 @@ }, | ||
| method: 'POST', | ||
| headers: { | ||
| 'content-type': 'application/json', | ||
| 'idempotency-key': crypto.randomUUID(), | ||
| }, | ||
| headers: { 'content-type': 'application/json', 'idempotency-key': crypto.randomUUID() }, | ||
| body: JSON.stringify({ model, messages, max_completion_tokens: max_tokens || 1024 }), | ||
@@ -74,3 +96,3 @@ }); | ||
| if (r.status === 402) { | ||
| return { content: [{ type: 'text', text: `Payment required for model "${model}". This is a paid model — use a free model like "groq/llama-3.1-8b-instant" or fund a wallet for paid calls.\n\nFree models: groq/llama-3.1-8b-instant, groq/llama-3.3-70b, sambanova/deepseek-v3.2, hcn/qwen3.6-35b` }] }; | ||
| return { content: [{ type: 'text', text: `Payment required for "${model}". Use a free model instead:\n- groq/llama-3.1-8b-instant (fastest, 170ms)\n- groq/llama-3.3-70b (best free quality)\n- nvidia/nemotron-ultra-550b (largest free model)` }] }; | ||
| } | ||
@@ -91,2 +113,36 @@ | ||
| async function handleSearch({ query, max_results }) { | ||
| const r = await fetch(`${API}/v1/search`, { | ||
| method: 'POST', | ||
| headers: { 'content-type': 'application/json' }, | ||
| body: JSON.stringify({ query, max_results: max_results || 5 }), | ||
| }); | ||
| const j = await r.json(); | ||
| if (r.status !== 200) { | ||
| return { content: [{ type: 'text', text: `Search error: ${j.error?.message || 'unavailable'}` }], isError: true }; | ||
| } | ||
| let text = `Search results for "${j.query}":\n\n`; | ||
| (j.results || []).forEach((result, i) => { | ||
| text += `${i + 1}. ${result.title}\n ${result.url}\n ${result.snippet}\n\n`; | ||
| }); | ||
| return { content: [{ type: 'text', text: text.trim() }] }; | ||
| } | ||
| async function handleScrape({ url }) { | ||
| const r = await fetch(`${API}/v1/scrape`, { | ||
| method: 'POST', | ||
| headers: { 'content-type': 'application/json' }, | ||
| body: JSON.stringify({ url }), | ||
| }); | ||
| const j = await r.json(); | ||
| if (r.status !== 200) { | ||
| return { content: [{ type: 'text', text: `Scrape error: ${j.error?.message || j.message || 'failed'}` }], isError: true }; | ||
| } | ||
| return { content: [{ type: 'text', text: j.content || 'No content returned.' }] }; | ||
| } | ||
| async function handleModels() { | ||
@@ -99,6 +155,6 @@ const r = await fetch(`${API}/v1/models`); | ||
| let text = `Clervo x402 Gateway — ${j.data.length} models\n\n`; | ||
| let text = `Clervo x402 Gateway — ${j.data.length} models | Base mainnet USDC\n\n`; | ||
| text += `FREE (no wallet needed, just call):\n`; | ||
| free.forEach(m => { text += ` ${m.id} — ${m.description || m.name}\n`; }); | ||
| text += `\nPAID (x402 USDC per request, 10-20% cheaper than BlockRun):\n`; | ||
| text += `\nPAID (x402 USDC on Base, 20% cheaper than BlockRun):\n`; | ||
| paid.forEach(m => { | ||
@@ -108,2 +164,3 @@ const price = m.paid_pricing?.amount || m.pricing?.amount || '?'; | ||
| }); | ||
| text += `\nServices: search (POST /v1/search), scrape (POST /v1/scrape) — both FREE`; | ||
| text += `\nQuickstart: ${API}/quickstart.md`; | ||
@@ -136,3 +193,3 @@ return { content: [{ type: 'text', text }] }; | ||
| capabilities: { tools: {} }, | ||
| serverInfo: { name: 'clervo', version: '0.1.0' }, | ||
| serverInfo: { name: 'clervo', version: '0.2.0' }, | ||
| }}); | ||
@@ -148,2 +205,4 @@ } else if (msg.method === 'notifications/initialized') { | ||
| if (name === 'clervo_chat') result = await handleChat(args); | ||
| else if (name === 'clervo_search') result = await handleSearch(args); | ||
| else if (name === 'clervo_scrape') result = await handleScrape(args); | ||
| else if (name === 'clervo_models') result = await handleModels(); | ||
@@ -162,5 +221,4 @@ else if (name === 'clervo_status') result = await handleStatus(args); | ||
| rl.on('close', () => { | ||
| // Give pending async operations time to complete | ||
| setTimeout(() => process.exit(0), 100); | ||
| }); | ||
| } |
10587
27.34%193
35.92%5
66.67%