Skip to main content
Glama

scan_ai

Detect AI-generated content using Originality.ai to verify originality before publishing. Provides overall AI percentage and sentence-by-sentence breakdown with confidence scores.

Instructions

Detect AI-generated content using Originality.ai. Returns an overall AI vs. Original percentage and a sentence-by-sentence breakdown with confidence scores. Use this after writing content to check AI detection scores before publishing. Costs ~1 credit per 100 words.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
contentYesPlain text content to scan. Strip HTML/markdown for best accuracy. Minimum ~50 words for reliable results.
titleNoLabel for the scan (for reference in stored results).AI Detection Scan

Implementation Reference

  • The handle_scan_ai function is the main handler that executes the scan_ai tool logic. It strips markdown from input content, validates minimum content length (~50 words), calls the OriginalityClient.scan() API with check_ai=True, and returns formatted AI detection results as TextContent.
    async def handle_scan_ai(
        arguments: dict[str, Any],
        client: OriginalityClient,
    ) -> list[TextContent]:
        """AI detection scan only."""
        content = _strip_markdown(arguments.get("content", ""))
        if not content or len(content.split()) < 20:
            return [TextContent(type="text", text="Content too short — need at least ~50 words for reliable AI detection.")]
    
        result = await client.scan(
            content=content,
            title=arguments.get("title", "AI Detection Scan"),
            check_ai=True,
            ai_model_version=arguments.get("ai_model", "lite-102"),
        )
        return [TextContent(type="text", text=_format_ai_result(result))]
  • Defines the scan_ai Tool with name, description, and inputSchema. The schema specifies 'content' (required string) and 'title' (optional string with default 'AI Detection Scan') as parameters for the AI detection scan.
    Tool(
        name="scan_ai",
        description=(
            "Detect AI-generated content using Originality.ai. Returns an overall "
            "AI vs. Original percentage and a sentence-by-sentence breakdown with "
            "confidence scores. Use this after writing content to check AI detection "
            "scores before publishing. Costs ~1 credit per 100 words."
        ),
        inputSchema={
            "type": "object",
            "properties": {
                "content": {
                    "type": "string",
                    "description": "Plain text content to scan. Strip HTML/markdown for best accuracy. Minimum ~50 words for reliable results.",
                },
                "title": {
                    "type": "string",
                    "default": "AI Detection Scan",
                    "description": "Label for the scan (for reference in stored results).",
                },
            },
            "required": ["content"],
        },
    ),
  • Registers the scan_ai tool by mapping the tool name 'scan_ai' to its handler function handle_scan_ai in the TOOL_HANDLERS dictionary. This routing enables the MCP server to dispatch tool calls to the correct handler.
    TOOL_HANDLERS = {
        "scan_ai": handle_scan_ai,
  • The _strip_markdown helper function strips markdown formatting (bold, italic, headings, links, code blocks, lists, etc.) from input text to provide clean plaintext to the Originality.ai API for more accurate AI detection scoring.
    def _strip_markdown(text: str) -> str:
        """Strip markdown formatting to send clean plaintext to the API.
    
        Originality.ai docs: 'For the most accurate scoring provide plain text.'
        """
        # Remove bold/italic markers
        text = re.sub(r'\*{1,3}(.+?)\*{1,3}', r'\1', text)
        text = re.sub(r'_{1,3}(.+?)_{1,3}', r'\1', text)
        # Remove headings (## Heading -> Heading)
        text = re.sub(r'^#{1,6}\s+', '', text, flags=re.MULTILINE)
        # Remove markdown links [text](url) -> text
        text = re.sub(r'\[([^\]]+)\]\([^)]+\)', r'\1', text)
        # Remove inline code backticks
        text = re.sub(r'`([^`]+)`', r'\1', text)
        # Remove blockquote markers
        text = re.sub(r'^>\s+', '', text, flags=re.MULTILINE)
        # Remove horizontal rules
        text = re.sub(r'^---+$', '', text, flags=re.MULTILINE)
        # Remove list markers (- item, * item, 1. item)
        text = re.sub(r'^[\-\*]\s+', '', text, flags=re.MULTILINE)
        text = re.sub(r'^\d+\.\s+', '', text, flags=re.MULTILINE)
        # Remove image syntax ![alt](url)
        text = re.sub(r'!\[([^\]]*)\]\([^)]+\)', r'\1', text)
        # Collapse multiple blank lines
        text = re.sub(r'\n{3,}', '\n\n', text)
        return text.strip()
  • The _format_ai_result helper function formats AI detection results into a human-readable markdown table with AI/Original percentages, model used, credits consumed, a verdict (high AI/mixed/mostly original), and flagged sentence breakdown.
    def _format_ai_result(data: dict) -> str:
        """Format AI detection results."""
        results = data.get("results", data)
        ai = results.get("ai", {})
        credits_used = _safe_get(results, "credits", "used", default="?")
        ai_pct, original_pct = _extract_ai_probs(results)
        model = ai.get("aiModel", "unknown")
    
        lines = [
            "## AI Detection Results",
            "",
            f"| Metric | Score |",
            f"|--------|-------|",
            f"| AI Content | **{ai_pct:.0%}** |",
            f"| Original Content | **{original_pct:.0%}** |",
            f"| Model Used | {model} |",
            f"| Credits Used | {credits_used} |",
            "",
        ]
    
        # Verdict
        if ai_pct >= 0.75:
            lines.append("**Verdict:** High AI probability — significant revision recommended before publishing.")
        elif ai_pct >= 0.5:
            lines.append("**Verdict:** Mixed signals — some sections flagged as AI. Review flagged sentences below.")
        elif ai_pct >= 0.25:
            lines.append("**Verdict:** Mostly original with minor AI signals. Light revision may help.")
        else:
            lines.append("**Verdict:** Content reads as original.")
    
        # Sentence-level breakdown (top flagged sentences)
        blocks = ai.get("blocks", [])
        flagged = [b for b in blocks if b.get("result", {}).get("fake", 0) > 0.5]
    
        if flagged:
            lines.append("")
            lines.append(f"### Flagged Sentences ({len(flagged)} of {len(blocks)} total)")
            lines.append("")
            for block in flagged:
                text = block.get("text", "")[:120]
                fake_score = block.get("result", {}).get("fake", 0)
                lines.append(f"- **{fake_score:.0%} AI** — \"{text}{'...' if len(block.get('text', '')) > 120 else ''}\"")
    
    
        # Scan ID for retrieval
        scan_id = results.get("id", "")
        if scan_id:
            lines.extend(["", f"*Scan ID: {scan_id}*"])
    
        return "\n".join(lines)

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/EfrainTorres/armavita-originality-ai-mcp'

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