Skip to main content
Glama

skvil_scan

Submit security scan results for AI agent skills to the Skvil reputation network. Contributes to community reputation scores by providing accurate security findings and assessments.

Instructions

Submit security scan results for an AI agent skill to the Skvil reputation network. Contributes to the community reputation score (EMA). Requires an API key (use skvil_register first). The server recomputes the score from findings — always provide accurate findings.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
nameYesSkill name
composite_hashYesSHA-256 composite hash of the skill (e.g. "sha256:4a2f8b...c81e")
file_countYesNumber of files in the skill
file_hashesYesMap of relative file paths to their SHA-256 hex hashes
scoreYesComputed security score (0-100)
risk_levelYesOverall risk assessment
findingsNoSecurity findings detected in the skill
frontmatterNoSKILL.md frontmatter metadata (optional)
skill_urlYesSource URL of the skill (e.g. "https://github.com/user/repo")
providerYesPlatform hosting the skill
agentYesAgent platform submitting the scan (e.g. "claude", "codex", "openclaw")

Implementation Reference

  • Main handler implementation for skvil_scan tool. Registers the tool with input schema (Zod validation) including name, composite_hash, file_count, file_hashes, score, risk_level, findings, frontmatter, skill_url, provider, and agent. The handler calls api.scan() and formats the response with scan_id, reputation_score, total_scans, and certification status.
    server.tool(
      'skvil_scan',
      'Submit security scan results for an AI agent skill to the Skvil reputation ' +
        'network. Contributes to the community reputation score (EMA). Requires an ' +
        'API key (use skvil_register first). The server recomputes the score from ' +
        'findings — always provide accurate findings.',
      {
        name: z.string().max(256).describe('Skill name'),
        composite_hash: hashSchema,
        file_count: z.number().int().min(0).max(10000).describe('Number of files in the skill'),
        file_hashes: z
          .record(
            z
              .string()
              .max(500)
              .regex(/^[a-zA-Z0-9_\-./]+$/, 'Invalid file path'),
            z.string().regex(/^[a-f0-9]{64}$/, 'Must be 64 hex characters'),
          )
          .describe('Map of relative file paths to their SHA-256 hex hashes'),
        score: z.number().int().min(0).max(100).describe('Computed security score (0-100)'),
        risk_level: z.enum(['safe', 'caution', 'danger']).describe('Overall risk assessment'),
        findings: z
          .array(
            z.object({
              severity: z.enum(['critical', 'high', 'medium', 'low']),
              category: z.string().max(100),
              description: z.string().max(1000),
              file: z.string().max(500),
              line: z.number().int().optional(),
            }),
          )
          .max(500)
          .default([])
          .describe('Security findings detected in the skill'),
        frontmatter: z
          .record(z.union([z.string(), z.number(), z.boolean(), z.null()]))
          .optional()
          .describe('SKILL.md frontmatter metadata (optional)'),
        skill_url: z
          .string()
          .max(512)
          .regex(
            /^https:\/\/(github\.com|gitlab\.com|clawhub\.ai)\/[^/]+\/[^/].*$/,
            'Must be a GitHub, GitLab, or ClawHub HTTPS URL',
          )
          .describe('Source URL of the skill (e.g. "https://github.com/user/repo")'),
        provider: z
          .enum(['github', 'gitlab', 'clawhub'])
          .describe('Platform hosting the skill'),
        agent: z
          .string()
          .max(50)
          .describe('Agent platform submitting the scan (e.g. "claude", "codex", "openclaw")'),
      },
      async (params) => {
        try {
          const result = await api.scan(params);
          const lines = [
            '**Scan submitted successfully**\n',
            `- **Scan ID:** ${result.scan_id}`,
            `- **Updated reputation:** ${formatScore(result.reputation_score)}`,
            `- **Total community scans:** ${result.total_scans}`,
          ];
    
          if (result.certification) {
            lines.push(`- **Certification:** ${result.certification}`);
          }
    
          lines.push(
            '\nYour scan contributes to the community reputation via exponential ' +
              'moving average (EMA). Thank you for helping secure the AI skill ecosystem.',
          );
    
          return { content: [{ type: 'text', text: lines.join('\n') }] };
        } catch (error) {
          return { content: [{ type: 'text', text: formatError('scan', error) }], isError: true };
        }
      },
    );
  • Type definitions for skvil_scan input/output. ScanPayload (lines 81-93) defines the expected input structure with name, composite_hash, file_count, file_hashes, score, risk_level, findings array, optional frontmatter, skill_url, provider, and agent. ScanResponse (lines 95-100) defines the output with scan_id, reputation_score, total_scans, and certification.
    export interface ScanFinding {
      severity: 'critical' | 'high' | 'medium' | 'low';
      category: string;
      description: string;
      file: string;
      line?: number;
    }
    
    export interface ScanPayload {
      name: string;
      composite_hash: string;
      file_count: number;
      file_hashes: Record<string, string>;
      score: number;
      risk_level: 'safe' | 'caution' | 'danger';
      findings: ScanFinding[];
      frontmatter?: Record<string, unknown>;
      skill_url: string;
      provider: 'github' | 'gitlab' | 'clawhub';
      agent: string;
    }
    
    export interface ScanResponse {
      scan_id: number;
      reputation_score: number;
      total_scans: number;
      certification: string | null;
    }
  • API helper function that performs the actual HTTP POST request to the Skvil /scan endpoint. Takes a ScanPayload, authenticates with API key, and returns a ScanResponse. Uses the shared request() function with retry logic and error handling.
    /** Submit scan results for a skill. */
    export async function scan(payload: ScanPayload): Promise<ScanResponse> {
      return request<ScanResponse>('POST', '/scan', { body: payload, auth: true });
    }
  • Shared hashSchema definition used by skvil_scan and other tools. Validates SHA-256 composite hash format: 'sha256:' prefix followed by 64 hexadecimal characters. This schema is reused in the composite_hash parameter of skvil_scan.
    const HASH_PATTERN = /^sha256:[a-f0-9]{64}$/;
    
    const hashSchema = z
      .string()
      .regex(HASH_PATTERN, 'Must be "sha256:" followed by 64 hex characters')
      .describe('SHA-256 composite hash of the skill (e.g. "sha256:4a2f8b...c81e")');
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries full burden and discloses several behavioral traits: it's a write operation ('Submit'), has a prerequisite (API key from skvil_register), contributes to community reputation, and the server recomputes scores. It doesn't mention rate limits, authentication details beyond the API key, or error handling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three sentences with zero waste: first states purpose, second provides prerequisite and community impact, third gives critical behavioral guidance. Each sentence earns its place and information is front-loaded appropriately.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a complex 11-parameter write tool with no annotations and no output schema, the description provides good context about purpose, prerequisites, and behavioral expectations. However, it doesn't explain what happens after submission (success response, error cases) or how the reputation score is computed from findings.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the baseline is 3. The description doesn't add specific parameter meaning beyond what the schema provides, though it implies that 'findings' should be 'accurate' and that the tool processes security scan results which relate to the parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('Submit security scan results'), target resource ('AI agent skill'), and destination ('Skvil reputation network'). It distinguishes from siblings by focusing on submitting scan results rather than cataloging, certifying, registering, reporting, or verifying.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to use ('Requires an API key (use skvil_register first)'), providing a clear prerequisite and alternative tool. The instruction to 'always provide accurate findings' offers behavioral guidance for proper usage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Skvil-IA/skvil-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server