Skip to content

Razi Tools

by razikallayi · remote · local (npm) · no sign-in to list tools · v2.1.2 · published by GitHub user razikallayi

PDF, image, video, OCR, screenshot, SQL, QR and text tools for agents. No API key, no signup.

Final · 2Changes · 22

28 tools: 2 do something that can't be undone, 22 change things and 4 only read.

Scanned Oct 21, 2026

2 checks matched something in the tool definitions. No finding is not a safety guarantee. How the checks work.

claude mcp add --transport http razi-tools https://www.razi.pro/api/mcp

Findings

Matches of fixed checks, with the text they matched.

2 info
  • The description mentions "credentials".

    Matched text

    description: "...s in a fresh browser with no cookies or credentials, so anything behind a login is unreacha..."

    What this check looks for
  • The description is 2,025 characters long, over the 2,000 this check looks for.

    Matched text

    description ends: "...or 24 hours and replayed with cached: true; 20 calls per minute per IP, then 429."

    What this check looks for

Tools

Open a tool for its reasons and full description. Descriptions are the publisher's own words, shown as they are.

28 tools

Can't be undone 2Claude Code: ask
  • merge_pdfConcatenate two or more PDFs into a single PDF, in the order supplied, and return the merged file.No findings

    Why it is in this group

    • The name "merge_pdf" says "merge": a word for a change that another call does not undo.
    Description, as the server wrote it
    Concatenate two or more PDFs into a single PDF, in the order supplied, and return the merged file. Over MCP the PDF is never inlined: it comes back as a stored URL that stays retrievable for about 24 hours. Page content is copied unchanged — it does not compress (use compress_pdf) or select pages (use split_pdf). Fewer than two files is rejected. Every input must already be a PDF; a photo handed to this tool is rejected rather than converted. Use images_to_pdf when any input is a picture — it takes PDFs alongside them and splices both in one pass. There is no upload channel over MCP: pass `fileUrls`, an array of URLs in razi.pro's own storage; third-party URLs are rejected. Obtain such a URL by uploading the file over the REST API first (POST /api/v1/tools/execute with the file attached). Over the REST API the files may instead be attached as multipart/form-data. Limited to 20 merges per hour per IP.
  • screenshot_urlCapture a screenshot of any public web page, rendered in a real headless browser so JavaScript, web fonts and lazy-loaded images all appear.1 finding

    Why it is in this group

    • The name "screenshot_url" says "screenshot": a word for reading.
    • The description's first verb is "capture": a word that usually means money moves, which cannot be taken back.

    Findings

    • Info

      The description mentions "credentials".

      Matched text

      description: "...s in a fresh browser with no cookies or credentials, so anything behind a login is unreacha..."

      What this check looks for
    Description, as the server wrote it
    Capture a screenshot of any public web page, rendered in a real headless browser so JavaScript, web fonts and lazy-loaded images all appear. Returns JSON with a hosted image URL — not image bytes: { url, screenshotUrl (the same value under the older key), width, height, format, bytes, cached, source }. When source is "vps" the image is on razi.pro's CDN and every field is populated, except that height is null for a fullPage capture. If source is "thumbio" the renderer was unavailable and a third-party fallback produced the image: the URL points at image.thum.io rather than razi.pro, only width accompanies it (height, format and bytes are absent), and the fullPage, format, darkMode and delayMs options were ignored. Public pages only: every capture runs in a fresh browser with no cookies or credentials, so anything behind a login is unreachable, and a URL that is not http(s) or that resolves to a loopback, private or link-local address is refused with 400. Identical requests are cached for 7 days and return the same image (cached: true), so this cannot be used to poll a page for changes. Out-of-range numeric options are clamped to their stated range rather than rejected. Other failures: 429 over either rate limit, 403 when screenshots are switched off platform-wide, 502 when the render fails and no fallback is available. This is the most expensive call on the platform: it holds a whole browser worker for up to 50 seconds. Limited to 10 captures per minute and 100 per day per IP.
Changes things 22Claude Code: ask
  • calculate_percentageRun one of four percentage calculations on two numbers.No findings

    Why it is in this group

    • The description's first verb is "run": a word for a change.
    Description, as the server wrote it
    Run one of four percentage calculations on two numbers. Returns JSON { operation, result } (plus unit: 'percent' for the 'change' operation). The meaning of value1 and value2 depends on the operation, so read their descriptions before calling. Exact arithmetic, no model involved, no rounding applied. Ratios and general expressions are not supported.
  • compress_imageRe-encode a single raster image to webp, jpeg, png or avif, optionally resizing it and/or converting it to grayscale.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    Re-encode a single raster image to webp, jpeg, png or avif, optionally resizing it and/or converting it to grayscale. HEIC/HEIF input is converted to JPEG first, and SVG input is rasterised at 300 DPI, fitted inside 800x800 unless width or height is given. Lossy for webp, jpeg and avif at any quality below 1.0. Raster images only: a PDF or a video is rejected, and neither can be re-encoded anywhere on this server. Output shape depends on size: an input under 5MB is processed in-app and the encoded image bytes are returned, while anything larger is sent to razi.pro's worker and the reply is JSON { url, size, metadata } pointing at a hosted copy instead of bytes. Paid compute; 30 calls per hour per IP. There is no upload channel over MCP: pass `fileUrl`, a URL in razi.pro's own storage; third-party URLs are rejected. Obtain one by uploading the image over the REST API first (POST /api/v1/tools/execute with the file attached).
  • compress_pdfShrink a PDF's byte size while keeping it a PDF, for email limits or slow connections.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    Shrink a PDF's byte size while keeping it a PDF, for email limits or slow connections. Returns the compressed PDF; over MCP it is never inlined, arriving as a stored URL that stays retrievable for about 24 hours. Ghostscript on razi.pro's worker downsamples embedded images at a fixed 'ebook' preset — lossy, with no quality knob. Compression is not guaranteed: if the worker is unavailable the fallback only rewrites the file with object streams, which typically saves almost nothing, and when nothing can be saved the original bytes are returned unchanged. PDFs only: an image or a video is rejected, and neither can be re-encoded anywhere on this server. Paid compute; 20 calls per hour per IP; a large file can take minutes. There is no upload channel over MCP: pass `fileUrl`, a URL in razi.pro's own storage; third-party URLs are rejected. Obtain one by uploading the PDF over the REST API first (POST /api/v1/tools/execute with the file attached).
  • decode_base64Decode a Base64 string back to UTF-8 text.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    Decode a Base64 string back to UTF-8 text. Returns JSON { decoded }. Input is verified by re-encoding, so anything that is not genuine Base64 is rejected with an error instead of returning plausible garbage; binary payloads that are not valid UTF-8 will also fail. It handles Base64 and nothing else: a string of %20-style percent escapes is not Base64 and will be rejected rather than unescaped. For a JWT use decode_jwt, which splits the three segments and handles their base64url padding for you.
  • decode_jwtDecode a JWT's header and payload for inspection.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    Decode a JWT's header and payload for inspection. Returns JSON { header, payload, signatureVerified, note, expiresAt, isExpired } — structured objects, not a rendered table. The signature is NEVER verified: that needs the issuer's key, which this service does not have, so signatureVerified is always false and the claims must be treated as untrusted, attacker-controllable input. Expiry is computed from the `exp` claim and is null when the token has none. Use decode_base64 for a bare Base64 string; this tool additionally splits the three segments and handles base64url padding.
  • decode_urlReverse percent-encoding with decodeURIComponent, turning %20-style escapes back into the characters they stand for.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    Reverse percent-encoding with decodeURIComponent, turning %20-style escapes back into the characters they stand for. Returns JSON { decoded }. A malformed or truncated escape sequence is rejected with an error rather than passed through. Note that '+' is left as a literal plus, not converted to a space. It understands percent-escapes and nothing else: Base64 text and JWTs pass through unchanged or fail, rather than being decoded. It is the exact inverse of encode_url.
  • draft_emailWrite a business email body from a short brief.No findings

    Why it is in this group

    • The description's first verb is "write": a word for a change.
    Description, as the server wrote it
    Write a business email body from a short brief. Returns JSON { email, cached } containing the body only — no subject line, no recipient, and nothing is sent anywhere. Choose this over generate_text when the output should be a whole email; use humanize_text to rewrite an email you already drafted. Paid model call. Anonymous callers get 3 per hour per IP and are then refused with 401; signed-in callers get 15 per minute per IP. Length is capped at roughly 400 tokens. Identical briefs may return a cached draft.
  • encode_base64Encode UTF-8 text as standard Base64 (padded, A-Z a-z 0-9 + /), for embedding binary-unsafe content in JSON, data URIs, HTTP headers or Basic auth.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    Encode UTF-8 text as standard Base64 (padded, A-Z a-z 0-9 + /), for embedding binary-unsafe content in JSON, data URIs, HTTP headers or Basic auth. Returns JSON { encoded }. The output uses the standard alphabet, so it is NOT URL-safe: '+' and '/' must still be percent-escaped before they go in a query string or path segment, and this tool does not do that. It is an encoding, not encryption — anyone can reverse it with decode_base64. Runs locally, no size limit beyond the request body.
  • encode_urlPercent-encode a string with encodeURIComponent so reserved characters survive transport inside a URL.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    Percent-encode a string with encodeURIComponent so reserved characters survive transport inside a URL. Returns JSON { encoded }. It escapes the structural characters too — : / ? # & = all become %XX — so it is for a single query-string value or path segment, NOT for a whole address you still want to be clickable. This is escaping for URLs only. It is the wrong transform for making binary-unsafe content fit in JSON, an HTTP header or a data URI, which call for Base64 rather than percent-encoding. Reverse it with decode_url.
  • extract_text_ocrUse this ONLY when the text exists as PIXELS and nothing else — a photo, a screenshot, a scan.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    Use this ONLY when the text exists as PIXELS and nothing else — a photo, a screenshot, a scan. It runs optical character recognition on an image and GUESSES the characters, so it is a best-effort transcription that misreads under blur, skew or low contrast. Returns JSON { text, language, confidence? }. If the file already stores real characters, this is the wrong tool and will be less accurate: parse_document reads them exactly. The deciding question is what the bytes contain, never the file extension — a .png of a letter needs this tool, a .txt never does. Layout is not preserved — no tables, columns or coordinates, just a flat string. Paid compute; 20 calls per hour per IP. There is no upload channel over MCP: pass `fileUrl`, a URL in razi.pro's own storage; third-party URLs are rejected. Obtain one by uploading the image over the REST API first (POST /api/v1/tools/execute with the file attached).
  • generate_blog_outlineProduce a markdown heading structure for a blog post — title, introduction, numbered sections with subsections, conclusion and an FAQ block.No findings

    Why it is in this group

    • The name "generate_blog_outline" says "generate": a word for a change.
    Description, as the server wrote it
    Produce a markdown heading structure for a blog post — title, introduction, numbered sections with subsections, conclusion and an FAQ block. Returns JSON { outline } holding the markdown. It writes the skeleton only, not the article: use generate_text for body prose and humanize_text to rework text that already exists. Paid model call, capped at roughly 1,000 tokens, so a large section count yields thinner sections. 10 calls per minute per IP; identical requests may return a cached outline.
  • generate_fake_dataProduce placeholder person records for testing and fixtures.No findings

    Why it is in this group

    • The name "generate_fake_data" says "generate": a word for a change.
    Description, as the server wrote it
    Produce placeholder person records for testing and fixtures. Returns JSON { type, count, records } where records is an array of strings, or of objects when type is 'user'. The values are drawn from a fixed word list by index, so they are DETERMINISTIC: the same arguments always return the same records, and asking twice does not give you fresh data. Emails all use example.com and phone numbers all use the +1-555 reserved range. It fabricates people only — for lorem-style prose use generate_text.
  • generate_imageGenerate a new image from a text description with a diffusion model.No findings

    Why it is in this group

    • The name "generate_image" says "generate": a word for a change.
    Description, as the server wrote it
    Generate a new image from a text description with a diffusion model. Returns a single PNG; over MCP it arrives inline when under 1MB and otherwise as a stored URL that stays retrievable for about 24 hours. This invents an image from scratch — it cannot edit, upscale or restyle a picture you already have. Use compress_image to re-encode or resize an existing file. Requires a signed-in razi.pro account; an anonymous call is rejected with 401. Paid compute, 20 images per hour per account, and generation can take tens of seconds. Providers are tried in turn (Fireworks FLUX.1-schnell, Hugging Face FLUX.1-schnell, SDXL, Cloudflare SDXL, Replicate), so the model that actually ran varies with availability and there is no seed or size control. No two calls give identical output, and the image is not automatically hosted anywhere permanent.
  • generate_qr_codeRender text or a URL as a QR code image.No findings

    Why it is in this group

    • The name "generate_qr_code" says "generate": a word for a change.
    Description, as the server wrote it
    Render text or a URL as a QR code image. Returns JSON { dataUrl, text, size } where dataUrl is a base64 PNG data URI embedded in the response — not a hosted link, so nothing is stored and the image cannot be fetched later. Runs locally and costs nothing. Writing only — it cannot read or decode an existing QR code. A long payload makes a denser, less scannable code, so shorten the address by other means before encoding it if you can.
  • generate_sqlTranslate a natural-language request into a SQL statement.No findings

    Why it is in this group

    • The name "generate_sql" says "generate": a word for a change.
    Description, as the server wrote it
    Translate a natural-language request into a SQL statement. Returns JSON { sql } containing the query text and nothing else — no validation report, no complexity score, and the query is never executed or checked against a real database. It has no knowledge of your schema beyond what the request states, so table and column names are guesses unless you supply them. Review before running, especially anything that writes. Paid model call. Anonymous callers get 3 per hour per IP and are then refused with 401; signed-in callers get 15 per minute per IP. Capped at roughly 500 tokens. Answers are cached, so the same request returns the same query.
  • generate_textGenerate filler prose — lorem ipsum, random copy or sentences — for mockups and placeholder content.No findings

    Why it is in this group

    • The name "generate_text" says "generate": a word for a change.
    Description, as the server wrote it
    Generate filler prose — lorem ipsum, random copy or sentences — for mockups and placeholder content. Returns JSON { text, provider, cached } with the blocks separated by newlines. A language model writes it, so it is a paid call and the output is approximate: type, length and count are phrased into the prompt rather than enforced, and the result will not match a requested character count exactly. For placeholder people (names, emails, addresses) use generate_fake_data, which is exact, free and deterministic. For a real email use draft_email, and to rework existing text use humanize_text. 15 calls per minute per IP; capped at roughly 1,500 tokens; identical requests may return a cached result.
  • humanize_textRewrite text you already have so it reads less like model output — fewer stock phrases, more contractions, varied sentence rhythm.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    Rewrite text you already have so it reads less like model output — fewer stock phrases, more contractions, varied sentence rhythm. Returns JSON { humanizedText }. Meaning is meant to be preserved but wording is not: never use it on text that must stay verbatim, such as quotes, legal copy or code. Use generate_text to produce new prose from a prompt and draft_email for a whole email; this one only transforms text it is given. Requires a signed-in razi.pro account — an anonymous call is rejected with 401. Paid model call; input capped at 10,000 characters and output at roughly 2,000 tokens, so long passages come back truncated. 30 calls per hour per account, and identical inputs may return a cached result.
  • images_to_pdfAssemble pictures into one PDF, a page per picture, in the order supplied.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    Assemble pictures into one PDF, a page per picture, in the order supplied. PNG and JPEG bytes are embedded untouched; WebP, GIF, TIFF and AVIF are re-encoded to PNG on the way in, which loses no detail but does rewrite the file. A PDF sitting among the pictures is spliced in whole at its position, so a photo/contract/photo sequence takes one call. Each page defaults to the pixel dimensions of its picture, so nothing is scaled, cropped or letterboxed; choose 'a4' or 'letter' instead to centre every picture on a fixed portrait sheet, optionally inside a `margin` of blank points. Ceilings per call: 100 files, and 50MB summed across all of them, at 20 calls an hour per IP. Bytes that cannot be decoded as a picture — a spreadsheet, a video, a corrupt upload — earn an HTTP 400 naming the offending file; a blank page is never substituted to hide one. Output is the finished PDF: raw bytes over REST, and over MCP a link to the stored document that keeps working for roughly a day. MCP carries no attachments, so name the pictures with `fileUrls` — an ordered array of links inside razi.pro's own storage. Links elsewhere on the internet are refused. Mint them by POSTing the pictures to /api/v1/tools/execute first, where they may simply be attached.
  • parse_documentUse this when the file ALREADY stores its text as characters: it decodes them and returns JSON { text, metadata } verbatim, with no guessing involved.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    Use this when the file ALREADY stores its text as characters: it decodes them and returns JSON { text, metadata } verbatim, with no guessing involved. That exactness is the whole difference from extract_text_ocr, which recovers text from pixels by guessing at glyph shapes and should only ever be pointed at a photo, screenshot or scan. Supported: .txt, decoded as UTF-8 and returned in full with metadata { format: "txt", words }; and .pdf, where the text layer is read page by page and joined with a `--- Page N ---` separator, returning metadata { format: "pdf", pages, words } — pages and words are counted from the document itself, never estimated. .docx and every other extension are rejected with 400. A scanned or photographed PDF has no text layer, so nothing can be extracted from it here; that case returns 422 with a metadata.imageOnly flag rather than an empty success, and extract_text_ocr is the tool for it. Limits: 50MB and 300 pages, over which the call returns 413; an unreadable or encrypted PDF returns 400. Layout is not preserved — no tables, columns or coordinates, just a flat string per page. The file type is decided by the filename extension, not by inspecting the bytes. 10 calls per minute per caller. There is no upload channel over MCP: pass `fileUrl`, a URL in razi.pro's own storage; third-party URLs are rejected. Obtain one by uploading the file over the REST API first (POST /api/v1/tools/execute with the file attached).
  • shorten_urlCreate a permanent razi.pro short link that redirects to a long URL.No findings

    Why it is in this group

    • The description's first verb is "create": a word for a change.
    Description, as the server wrote it
    Create a permanent razi.pro short link that redirects to a long URL. Returns JSON { code, shortUrl } and nothing else. Visits through the link are counted, but no tool here reads that count back, and the link cannot be edited, retargeted or deleted through this API. It never expires. The destination is stored, never fetched or checked for reachability, so a dead or mistyped URL still yields a working short link. Only http and https targets are accepted. This shortens an existing address; it does not host anything, so a file needs a public URL of its own before there is something to shorten. No sign-in is required; an anonymous call creates the link unowned, so it will not appear in any account's list. 30 links per hour per IP, then 429.
  • split_imageCut one storyboard, collage or grid image into its separate panels and return them as a ZIP, one file per panel in reading order.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    Cut one storyboard, collage or grid image into its separate panels and return them as a ZIP, one file per panel in reading order. Over MCP the ZIP is not inlined: it comes back as a stored URL that stays retrievable for about 24 hours. Two modes. Give both rows and cols for an exact equal division, which is free of model cost and predictable. Omit them and a vision model locates the panels, excluding borders, gaps and captions — better on uneven layouts, but it is a paid inference whose panel count and crops can vary between runs, and it fails with 400 if it finds nothing. Panels are cropped, never resized; a lossy re-encode at quality 90 is applied for jpeg and webp. This divides one image into several — it does not shrink a file (use compress_image), and it cannot take a PDF apart. Paid compute; 20 calls per hour per IP. There is no upload channel over MCP: pass `fileUrl`, a URL in razi.pro's own storage; third-party URLs are rejected. Obtain one by uploading the image over the REST API first (POST /api/v1/tools/execute with the file attached).
  • split_pdfExtract page ranges from one PDF into new PDFs.No findings

    Why it is in this group

    • Nothing in its name or description says what it does, so it is counted as a write.
    Description, as the server wrote it
    Extract page ranges from one PDF into new PDFs. One output file is produced per range: a single range returns that PDF directly, several ranges return a ZIP containing one PDF each. Over MCP you receive a link to the stored output rather than its bytes, and that link keeps working for roughly a day. Pages are copied verbatim — this does not reduce file size (use compress_pdf) and it cannot rasterise pages into images, which is a browser-only feature of razi.pro. Every output stays a PDF. There is no upload channel over MCP: pass `fileUrl`, a URL in razi.pro's own storage; third-party URLs are rejected. Obtain one by uploading the PDF over the REST API first, where it may instead be attached as multipart/form-data. Limited to 20 splits per hour per IP.
Only reads 4Claude Code: allow
  • compare_textCompare two blocks of text line by line.No findings

    Why it is in this group

    • The name "compare_text" says "compare": a word for reading.
    Description, as the server wrote it
    Compare two blocks of text line by line. Returns JSON { identical, linesCompared, changeCount, changes[] }, where each change carries a 1-based line number, a change of 'added' | 'removed' | 'modified', and the before/after text. Lines are matched by POSITION, not by content: this is not an LCS diff, so inserting one line near the top reports every following line as modified. There is no character-level or word-level detail, and no unified-diff patch output. Whitespace and case are significant; \r\n and \n line endings are treated the same. Runs locally and costs nothing.
  • fetch_page_metadataRead a web page's metadata without downloading any images.No findings

    Why it is in this group

    • The name "fetch_page_metadata" says "fetch": a word for reading.
    Description, as the server wrote it
    Read a web page's metadata without downloading any images. Returns JSON { url, finalUrl, title, description, siteName, canonical, lang, themeColor, author, generator, feeds, openGraph, twitter, icons, cached }, where `feeds` is an array of RSS/Atom URLs, `openGraph` and `twitter` are the complete tag sets as string maps, and any tag the page does not declare is simply omitted. `icons` is always an empty array here because icon resolution is switched off — call fetch_site_logo when the caller wants a logo, favicon or icon. `finalUrl` is the address after redirects (up to 3 hops are followed), which is how you resolve where a domain actually points. This is the fast, cheap counterpart to fetch_site_logo: one page fetch and no image work. It reads the served HTML only — it runs no JavaScript, so a client-rendered page may expose little, and it does not capture how the page looks (use screenshot_url for that). The crawler identifies itself as RaziMetadataBot, and HTTP status is not checked, so a 404 or bot-challenge page that serves HTML is parsed as though it were the page you asked for. Errors: 400 for a URL that is refused as unsafe, redirects too many times, does not return HTML, or exceeds the 5MB page cap; 504 if the page does not answer within 10 seconds; 502 otherwise. Results are cached for 24 hours and replayed with cached: true; 20 calls per minute per IP, then 429.
  • format_jsonValidate and re-print a JSON string.No findings

    Why it is in this group

    • The description's first verb is "validate": a word for reading.
    Description, as the server wrote it
    Validate and re-print a JSON string. Returns JSON { valid, formatted, minified } — the indented form and the whitespace-free form as plain strings, with no syntax highlighting or colour. Invalid JSON is rejected with the parser's own error message rather than returned as valid:false, so a successful call is proof the input parses. Round-tripping through the parser normalises the document: key order is kept but comments, trailing commas and duplicate keys are lost, and large integers lose precision.

This is not a safety rating, and no finding is not a safety guarantee. The groups and findings come from fixed checks of the tool definitions the server returned on the date shown, not from its code or what it does when called. How the checks work.

Install

Pinned to version 2.1.2. Values in angle brackets are yours to fill in.

claude mcp add --transport http razi-tools https://www.razi.pro/api/mcp

Run in a terminal.

Claude Code permissions

Allow the reads, ask before a change, deny the deletes. Paste into .claude/settings.json.

.claude/settings.json
{
  "permissions": {
    "allow": [
      "mcp__razi-tools__fetch_site_logo",
      "mcp__razi-tools__fetch_page_metadata",
      "mcp__razi-tools__format_json",
      "mcp__razi-tools__compare_text"
    ],
    "ask": [
      "mcp__razi-tools__merge_pdf",
      "mcp__razi-tools__split_pdf",
      "mcp__razi-tools__compress_pdf",
      "mcp__razi-tools__images_to_pdf",
      "mcp__razi-tools__compress_image",
      "mcp__razi-tools__shorten_url",
      "mcp__razi-tools__screenshot_url",
      "mcp__razi-tools__humanize_text",
      "mcp__razi-tools__draft_email",
      "mcp__razi-tools__generate_blog_outline",
      "mcp__razi-tools__generate_sql",
      "mcp__razi-tools__encode_base64",
      "mcp__razi-tools__decode_base64",
      "mcp__razi-tools__encode_url",
      "mcp__razi-tools__decode_url",
      "mcp__razi-tools__decode_jwt",
      "mcp__razi-tools__generate_qr_code",
      "mcp__razi-tools__calculate_percentage",
      "mcp__razi-tools__generate_fake_data",
      "mcp__razi-tools__generate_text",
      "mcp__razi-tools__extract_text_ocr",
      "mcp__razi-tools__generate_image",
      "mcp__razi-tools__parse_document",
      "mcp__razi-tools__split_image"
    ],
    "deny": []
  }
}

Tools that only read are allowed, tools that change things ask first, tools that delete or cancel are denied. It assumes the server is installed as razi-tools. Review it before you use it.