@clervo/mcp
Advanced tools
| #!/usr/bin/env node | ||
| export {}; |
+13
| #!/usr/bin/env node | ||
| import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; | ||
| import { createClervoMcpServer } from './server.js'; | ||
| const server = createClervoMcpServer(); | ||
| const transport = new StdioServerTransport(); | ||
| try { | ||
| await server.connect(transport); | ||
| } | ||
| catch (error) { | ||
| process.stderr.write(`clervo-mcp failed: ${error instanceof Error ? error.message : 'unknown_error'}\n`); | ||
| process.exitCode = 1; | ||
| } | ||
| //# sourceMappingURL=run.js.map |
| {"version":3,"file":"run.js","sourceRoot":"","sources":["../src/run.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAEjF,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,MAAM,GAAG,qBAAqB,EAAE,CAAC;AACvC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAE7C,IAAI,CAAC;IACH,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,IAAI,CAAC,CAAC;IACzG,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC"} |
| import { type ClervoSearchRequest } from '@clervo/sdk'; | ||
| import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; | ||
| export declare const CLERVO_MCP_TOOLS: readonly [Readonly<{ | ||
| name: "search_web"; | ||
| operationId: "search.web"; | ||
| }>, Readonly<{ | ||
| name: "search_answer"; | ||
| operationId: "search.answer"; | ||
| }>]; | ||
| export interface ClervoSearchClient { | ||
| search: { | ||
| web(request: ClervoSearchRequest, options?: { | ||
| idempotencyKey?: string; | ||
| mode?: 'preview' | 'challenge'; | ||
| }): Promise<unknown>; | ||
| answer(request: ClervoSearchRequest, options?: { | ||
| idempotencyKey?: string; | ||
| mode?: 'preview' | 'challenge'; | ||
| }): Promise<unknown>; | ||
| }; | ||
| } | ||
| export interface ToolInput { | ||
| query: string; | ||
| maxResults?: number | undefined; | ||
| language?: string | undefined; | ||
| region?: string | undefined; | ||
| idempotencyKey?: string | undefined; | ||
| mode?: 'preview' | 'challenge' | undefined; | ||
| } | ||
| export interface ToolResult { | ||
| [key: string]: unknown; | ||
| content: Array<{ | ||
| type: 'text'; | ||
| text: string; | ||
| }>; | ||
| isError?: boolean; | ||
| } | ||
| export declare function createToolHandlers(client: ClervoSearchClient): { | ||
| search_web(input: ToolInput): Promise<ToolResult>; | ||
| search_answer(input: ToolInput): Promise<ToolResult>; | ||
| }; | ||
| export declare function createClervoMcpServer(options?: { | ||
| client?: ClervoSearchClient; | ||
| baseUrl?: string; | ||
| }): McpServer; |
+105
| import { ClervoClient, ClervoPaymentRequiredError, ClervoProblemError, recoveryActionFor, } from '@clervo/sdk'; | ||
| import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; | ||
| import { z } from 'zod'; | ||
| export const CLERVO_MCP_TOOLS = Object.freeze([ | ||
| Object.freeze({ name: 'search_web', operationId: 'search.web' }), | ||
| Object.freeze({ name: 'search_answer', operationId: 'search.answer' }), | ||
| ]); | ||
| function text(value) { | ||
| return { content: [{ type: 'text', text: JSON.stringify(value) }] }; | ||
| } | ||
| function failure(error) { | ||
| const recovery = recoveryActionFor(error); | ||
| if (error instanceof ClervoPaymentRequiredError) { | ||
| return { | ||
| content: [{ | ||
| type: 'text', | ||
| text: JSON.stringify({ | ||
| error: 'payment_required', | ||
| status: 402, | ||
| payable: false, | ||
| problem: error.problem, | ||
| ...(recovery === undefined ? {} : { recovery }), | ||
| }), | ||
| }], | ||
| isError: true, | ||
| }; | ||
| } | ||
| if (error instanceof ClervoProblemError) { | ||
| return { | ||
| content: [{ | ||
| type: 'text', | ||
| text: JSON.stringify({ | ||
| error: 'clervo_problem', | ||
| status: error.status, | ||
| problem: error.problem, | ||
| ...(recovery === undefined ? {} : { recovery }), | ||
| }), | ||
| }], | ||
| isError: true, | ||
| }; | ||
| } | ||
| return { | ||
| content: [{ type: 'text', text: JSON.stringify({ error: 'clervo_call_failed' }) }], | ||
| isError: true, | ||
| }; | ||
| } | ||
| export function createToolHandlers(client) { | ||
| const execute = async (productId, input) => { | ||
| try { | ||
| const request = { | ||
| query: input.query, | ||
| ...(input.maxResults === undefined ? {} : { maxResults: input.maxResults }), | ||
| ...(input.language === undefined ? {} : { language: input.language }), | ||
| ...(input.region === undefined ? {} : { region: input.region }), | ||
| }; | ||
| const options = { | ||
| ...(input.idempotencyKey === undefined ? {} : { idempotencyKey: input.idempotencyKey }), | ||
| ...(input.mode === undefined ? {} : { mode: input.mode }), | ||
| }; | ||
| const value = productId === 'search.web' | ||
| ? await client.search.web(request, options) | ||
| : await client.search.answer(request, options); | ||
| return text(value); | ||
| } | ||
| catch (error) { | ||
| return failure(error); | ||
| } | ||
| }; | ||
| return Object.freeze({ | ||
| search_web: (input) => execute('search.web', input), | ||
| search_answer: (input) => execute('search.answer', input), | ||
| }); | ||
| } | ||
| const inputSchema = { | ||
| query: z.string().trim().min(1).max(2_000).describe('The evidence query.'), | ||
| maxResults: z.number().int().min(1).max(10).optional(), | ||
| language: z.string().regex(/^[a-z]{2,3}$/u).optional(), | ||
| region: z.string().regex(/^[A-Z]{2}$/u).optional(), | ||
| idempotencyKey: z.string().min(8).max(128).optional(), | ||
| mode: z.enum(['preview', 'challenge']).default('preview').describe('Preview executes the local sample route. Challenge returns a non-payable 402 and never pays.'), | ||
| }; | ||
| export function createClervoMcpServer(options = {}) { | ||
| const baseUrl = options.baseUrl ?? process.env.CLERVO_BASE_URL; | ||
| const client = options.client ?? (baseUrl === undefined ? undefined : new ClervoClient({ baseUrl })); | ||
| const server = new McpServer({ name: 'clervo', version: '0.3.0' }); | ||
| const handlers = client === undefined ? undefined : createToolHandlers(client); | ||
| server.registerTool('search_web', { | ||
| title: 'Clervo web evidence preview', | ||
| description: 'Runs the repository-local search.web preview. Public availability and payment are not claimed.', | ||
| inputSchema, | ||
| annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, | ||
| }, async (input) => handlers === undefined | ||
| ? { content: [{ type: 'text', text: JSON.stringify({ error: 'clervo_base_url_required' }) }], isError: true } | ||
| : handlers.search_web(input)); | ||
| server.registerTool('search_answer', { | ||
| title: 'Clervo cited answer preview', | ||
| description: 'Runs the repository-local search.answer preview with synthesis forced on. Public availability and payment are not claimed.', | ||
| inputSchema, | ||
| annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true }, | ||
| }, async (input) => handlers === undefined | ||
| ? { content: [{ type: 'text', text: JSON.stringify({ error: 'clervo_base_url_required' }) }], isError: true } | ||
| : handlers.search_answer(input)); | ||
| return server; | ||
| } | ||
| //# sourceMappingURL=server.js.map |
| {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"} |
+47
-8
| { | ||
| "name": "@clervo/mcp", | ||
| "version": "0.2.0", | ||
| "description": "Clervo x402 Gateway MCP server — 23 AI models, 8 free. One wallet, pay per call in USDC.", | ||
| "version": "0.3.0", | ||
| "description": "Clervo MCP server generated from the frozen two-operation distribution candidate.", | ||
| "license": "UNLICENSED", | ||
| "type": "module", | ||
| "bin": { "clervo-mcp": "./bin/serve.js" }, | ||
| "main": "./src/index.js", | ||
| "keywords": ["mcp", "clervo", "x402", "ai", "claude", "gpt", "usdc", "solana", "agent", "llm"], | ||
| "license": "MIT", | ||
| "engines": { "node": ">=18" }, | ||
| "files": ["bin/", "src/", "README.md"] | ||
| "keywords": [ | ||
| "clervo", | ||
| "mcp", | ||
| "model-context-protocol", | ||
| "search" | ||
| ], | ||
| "homepage": "https://clervo.dev/docs/mcp", | ||
| "bugs": { | ||
| "url": "https://github.com/clervo/clervo/issues" | ||
| }, | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "git+https://github.com/clervo/clervo.git", | ||
| "directory": "packages/mcp" | ||
| }, | ||
| "engines": { | ||
| "node": ">=20" | ||
| }, | ||
| "files": [ | ||
| "dist", | ||
| "README.md" | ||
| ], | ||
| "bin": { | ||
| "clervo-mcp": "./dist/run.js" | ||
| }, | ||
| "exports": { | ||
| ".": { | ||
| "types": "./dist/server.d.ts", | ||
| "import": "./dist/server.js" | ||
| } | ||
| }, | ||
| "scripts": { | ||
| "build": "npm run build --workspace @clervo/sdk && tsc --project tsconfig.json", | ||
| "prepack": "npm run build" | ||
| }, | ||
| "dependencies": { | ||
| "@clervo/sdk": "0.3.0", | ||
| "@modelcontextprotocol/sdk": "1.30.0", | ||
| "zod": "4.4.3" | ||
| }, | ||
| "publishConfig": { | ||
| "access": "public", | ||
| "provenance": true | ||
| } | ||
| } |
+27
-54
@@ -1,61 +0,34 @@ | ||
| # @clervo/mcp | ||
| # `@clervo/mcp` | ||
| MCP server for the [Clervo x402 Gateway](https://api.clervo.dev) — 23 AI models, 8 free. Pay per call in USDC on Solana. | ||
| Local stdio MCP server for Clervo's frozen distribution candidate. | ||
| ## Install in Claude Code | ||
| It exposes exactly two tools: | ||
| ```bash | ||
| claude mcp add clervo -s user -- npx -y @clervo/mcp@latest | ||
| ``` | ||
| - `search_web` → `search.web` | ||
| - `search_answer` → `search.answer` | ||
| Restart Claude Code. Done. | ||
| Set `CLERVO_BASE_URL` to an explicitly selected Clervo preview endpoint. No | ||
| public deployment is assumed. The tools never sign, pay, retry payment, or | ||
| convert a non-payable `402` challenge into success. | ||
| ## What you get | ||
| ```json | ||
| { | ||
| "mcpServers": { | ||
| "clervo": { | ||
| "command": "npx", | ||
| "args": ["-y", "@clervo/mcp"], | ||
| "env": { | ||
| "CLERVO_BASE_URL": "http://127.0.0.1:8080" | ||
| } | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
| | Tool | What it does | | ||
| |------|-------------| | ||
| | `clervo_chat` | Call any AI model — 8 free (no wallet), 11 paid (USDC) | | ||
| | `clervo_models` | List all models with pricing | | ||
| | `clervo_status` | Look up operation receipts | | ||
| The package writes protocol messages to stdout and operational failures to | ||
| stderr only. | ||
| ## Free models (no payment needed) | ||
| Just call them: | ||
| - `groq/llama-3.1-8b-instant` — 170ms, fastest | ||
| - `groq/llama-3.3-70b` — large, fast | ||
| - `sambanova/deepseek-v3.2` — strong reasoning | ||
| - `sambanova/llama-3.3-70b` — large general | ||
| - `hcn/qwen3.6-35b` — fast small | ||
| - `hcn/step-3.7-flash` — reasoning | ||
| - `hcn/deepseek-v4-pro` — strongest open model | ||
| - `hcn/auto` — auto-routed | ||
| ## Paid models (10-20% cheaper than BlockRun) | ||
| - Claude Haiku 4.5 — $0.002/req | ||
| - Claude Sonnet 4.6 / 5 — $0.015/req | ||
| - Claude Opus 4.7 / 5 — $0.084/req | ||
| - GPT-5.4 Mini — $0.005/req | ||
| - GPT-5.5 / 5.6 Sol — $0.035/req | ||
| ## Example | ||
| In Claude Code, just say: | ||
| > "Use clervo_chat with groq/llama-3.1-8b-instant to explain quantum computing in 3 sentences" | ||
| Or for Claude: | ||
| > "Use clervo_chat with tongkhokr/claude-opus-5 to review this code" | ||
| ## Configuration | ||
| Set `CLERVO_API_URL` to override the default (`https://api.clervo.dev`). | ||
| ## Links | ||
| - API: https://api.clervo.dev | ||
| - Models: https://api.clervo.dev/v1/models | ||
| - Quickstart: https://api.clervo.dev/quickstart.md | ||
| - OpenAPI: https://api.clervo.dev/openapi.json | ||
| Known future payment failures include the same single recovery action as both | ||
| SDKs. The server never performs that action, signs, pays, or retries on the | ||
| agent's behalf. Unknown settlement and payment timeouts remain blocked until | ||
| the original idempotency key is reconciled. |
| #!/usr/bin/env node | ||
| import { serve } from '../src/index.js'; | ||
| serve(); |
-212
| /** | ||
| * @clervo/mcp — MCP server for Clervo x402 Gateway | ||
| * | ||
| * Install: claude mcp add clervo -s user -- npx -y @clervo/mcp@latest | ||
| * | ||
| * Tools exposed: | ||
| * 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 | ||
| */ | ||
| import { createInterface } from 'node:readline'; | ||
| const API = process.env.CLERVO_API_URL || 'https://api.clervo.dev'; | ||
| // MCP protocol handler | ||
| const tools = [ | ||
| { | ||
| name: 'clervo_chat', | ||
| 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: { | ||
| type: 'object', | ||
| required: ['model', 'message'], | ||
| properties: { | ||
| model: { | ||
| type: 'string', | ||
| 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.', | ||
| }, | ||
| message: { type: 'string', description: 'The user message to send.' }, | ||
| system: { type: 'string', description: 'Optional system prompt.' }, | ||
| max_tokens: { type: 'number', description: 'Max output tokens (default 1024).' }, | ||
| }, | ||
| }, | ||
| }, | ||
| { | ||
| 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 on Base). 26 models across Groq, SambaNova, Nvidia, Claude, and GPT families.', | ||
| inputSchema: { type: 'object', properties: {} }, | ||
| }, | ||
| { | ||
| name: 'clervo_status', | ||
| description: 'Look up an operation by ID to get status, receipt, and cost information.', | ||
| inputSchema: { | ||
| type: 'object', | ||
| required: ['operation_id'], | ||
| properties: { | ||
| operation_id: { type: 'string', description: 'The operation ID from x-clervo-operation-id header.' }, | ||
| }, | ||
| }, | ||
| }, | ||
| ]; | ||
| async function handleChat({ model, message, system, max_tokens }) { | ||
| const crypto = await import('node:crypto'); | ||
| const messages = []; | ||
| if (system) messages.push({ role: 'system', content: system }); | ||
| messages.push({ role: 'user', content: message }); | ||
| const r = await fetch(`${API}/v1/chat/completions`, { | ||
| method: 'POST', | ||
| headers: { 'content-type': 'application/json', 'idempotency-key': crypto.randomUUID() }, | ||
| body: JSON.stringify({ model, messages, max_completion_tokens: max_tokens || 1024 }), | ||
| }); | ||
| if (r.status === 402) { | ||
| 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)` }] }; | ||
| } | ||
| const j = await r.json(); | ||
| if (r.status !== 200) { | ||
| return { content: [{ type: 'text', text: `Error (${r.status}): ${j.error?.message || JSON.stringify(j)}` }], isError: true }; | ||
| } | ||
| const content = j.choices?.[0]?.message?.content || ''; | ||
| const opId = r.headers.get('x-clervo-operation-id') || ''; | ||
| return { | ||
| content: [{ type: 'text', text: content }], | ||
| ...(opId ? { _meta: { operationId: opId, model: j.model, usage: j.usage } } : {}), | ||
| }; | ||
| } | ||
| 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() { | ||
| const r = await fetch(`${API}/v1/models`); | ||
| const j = await r.json(); | ||
| const free = j.data.filter(m => m.lifecycle === 'free_beta'); | ||
| const paid = j.data.filter(m => m.lifecycle === 'paid_beta'); | ||
| 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 on Base, 20% cheaper than BlockRun):\n`; | ||
| paid.forEach(m => { | ||
| const price = m.paid_pricing?.amount || m.pricing?.amount || '?'; | ||
| text += ` ${m.id} — $${price}/req — ${m.description || m.name}\n`; | ||
| }); | ||
| text += `\nServices: search (POST /v1/search), scrape (POST /v1/scrape) — both FREE`; | ||
| text += `\nQuickstart: ${API}/quickstart.md`; | ||
| return { content: [{ type: 'text', text }] }; | ||
| } | ||
| async function handleStatus({ operation_id }) { | ||
| const r = await fetch(`${API}/v1/operations/${operation_id}`); | ||
| if (r.status === 404) return { content: [{ type: 'text', text: 'Operation not found.' }], isError: true }; | ||
| const j = await r.json(); | ||
| return { content: [{ type: 'text', text: JSON.stringify(j, null, 2) }] }; | ||
| } | ||
| // MCP stdio transport | ||
| export function serve() { | ||
| const rl = createInterface({ input: process.stdin }); | ||
| function send(msg) { | ||
| process.stdout.write(JSON.stringify(msg) + '\n'); | ||
| } | ||
| rl.on('line', async (line) => { | ||
| let msg; | ||
| try { msg = JSON.parse(line); } catch { return; } | ||
| if (msg.method === 'initialize') { | ||
| send({ jsonrpc: '2.0', id: msg.id, result: { | ||
| protocolVersion: '2024-11-05', | ||
| capabilities: { tools: {} }, | ||
| serverInfo: { name: 'clervo', version: '0.2.0' }, | ||
| }}); | ||
| } else if (msg.method === 'notifications/initialized') { | ||
| // no response needed | ||
| } else if (msg.method === 'tools/list') { | ||
| send({ jsonrpc: '2.0', id: msg.id, result: { tools } }); | ||
| } else if (msg.method === 'tools/call') { | ||
| const { name, arguments: args } = msg.params; | ||
| let result; | ||
| try { | ||
| 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(); | ||
| else if (name === 'clervo_status') result = await handleStatus(args); | ||
| else result = { content: [{ type: 'text', text: `Unknown tool: ${name}` }], isError: true }; | ||
| } catch (e) { | ||
| result = { content: [{ type: 'text', text: `Error: ${e.message}` }], isError: true }; | ||
| } | ||
| send({ jsonrpc: '2.0', id: msg.id, result }); | ||
| } else if (msg.id) { | ||
| send({ jsonrpc: '2.0', id: msg.id, error: { code: -32601, message: 'Method not found' } }); | ||
| } | ||
| }); | ||
| rl.on('close', () => { | ||
| setTimeout(() => process.exit(0), 100); | ||
| }); | ||
| } |
Explicitly Unlicensed Item
LicenseSomething was found which is explicitly marked as unlicensed.
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Misc. License Issues
LicenseA package's licensing information has fine-grained problems.
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Network access
Supply chain riskThis module accesses the network.
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
No website
QualityPackage does not have a website.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
14375
35.78%8
100%1
-50%0
-100%2
-33.33%1
-66.67%1
-80%3
Infinity%1
Infinity%1
Infinity%0
-100%163
-15.54%35
-43.55%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
+ Added