MCP server for nudity detection
Give Claude, Cursor, VS Code or Codex a tool that tells them how much nudity is in an image, GIF or video. Your agent gets a level from 0 to 3 and a blocked or allowed verdict, and never has to look at the image itself.
Set it up in one step
Put your key in SFWAPI_API_KEY, pick your client and copy. Hosted needs no install; local adds the file tool.
One command. It reads the key from SFWAPI_API_KEY in your shell.
claude mcp add --transport http sfwapi https://api.sfwapi.dev/mcp --header "Authorization: Bearer $SFWAPI_API_KEY"claude mcp add sfwapi -e SFWAPI_API_KEY=$SFWAPI_API_KEY -- npx -y @sfwapi/mcpAdd --scope user to have it in every project. Check with /mcp inside a session.
Save as .cursor/mcp.json in the project, or ~/.cursor/mcp.json for every project. Cursor fills in the key from your environment.
{
"mcpServers": {
"sfwapi": {
"url": "https://api.sfwapi.dev/mcp",
"headers": {
"Authorization": "Bearer ${env:SFWAPI_API_KEY}"
}
}
}
}{
"mcpServers": {
"sfwapi": {
"command": "npx",
"args": [
"-y",
"@sfwapi/mcp"
],
"env": {
"SFWAPI_API_KEY": "${env:SFWAPI_API_KEY}"
}
}
}
}Save as .vscode/mcp.json. VS Code asks for the key once and keeps it in its secret storage.
{
"inputs": [
{
"type": "promptString",
"id": "sfwapi-key",
"description": "SFW API key",
"password": true
}
],
"servers": {
"sfwapi": {
"type": "http",
"url": "https://api.sfwapi.dev/mcp",
"headers": {
"Authorization": "Bearer ${input:sfwapi-key}"
}
}
}
}{
"inputs": [
{
"type": "promptString",
"id": "sfwapi-key",
"description": "SFW API key",
"password": true
}
],
"servers": {
"sfwapi": {
"type": "stdio",
"command": "npx",
"args": [
"-y",
"@sfwapi/mcp"
],
"env": {
"SFWAPI_API_KEY": "${input:sfwapi-key}"
}
}
}
}Add a table to ~/.codex/config.toml. The hosted form reads the key from SFWAPI_API_KEY in your environment.
[mcp_servers.sfwapi]
url = "https://api.sfwapi.dev/mcp"
bearer_token_env_var = "SFWAPI_API_KEY"[mcp_servers.sfwapi]
command = "npx"
args = ["-y", "@sfwapi/mcp"]
env = { SFWAPI_API_KEY = "sk_live_..." }Open Settings, Developer, Edit Config and add the server to claude_desktop_config.json, then restart the app. Needs Node.js 20 or newer.
{
"mcpServers": {
"sfwapi": {
"command": "npx",
"args": [
"-y",
"@sfwapi/mcp"
],
"env": {
"SFWAPI_API_KEY": "sk_live_..."
}
}
}
}Claude Desktop starts local servers only, so it uses the package. The hosted endpoint needs a client that can send a header.
Another client? The endpoint is https://api.sfwapi.dev/mcp (Streamable HTTP, Authorization: Bearer with your key) and the local command is npx -y @sfwapi/mcp.
What your agent can do
Three tools, each returning a line a person can read and the full result as structured data.
analyze_url
Analyse an image, GIF or video at a public URL.
Hosted and local
analyze_file
Analyse a file on your machine. It is uploaded to the API, analysed in memory and discarded.
Local only
get_account
Credit balance, plan limits and this month's usage. Free.
Hosted and local
Check https://example.com/upload.jpg before it goes on the public feed. Block from level 2.
Level 2 (Implied Nudity). Scores 0-100: revealing 96.2, implied nudity 71.5, explicit 8.1. Blocked by the policy (level). 1 credit used, 499 left.
Levels: 0 Everyday, 1 Revealing, 2 Implied Nudity, 3 Explicit. Pass block_level and the answer says blocked or allowed, so the agent does not compare scores itself. What each level means
Hosted or local
Both use the same key, the same credits and the same tool definitions.
Cost and privacy
One credit per analysis
One credit per image, or one per analysed frame of a GIF or video. Connecting, listing tools, get_account and failed calls cost nothing. Every account starts with 500 free credits a month.
Media is not stored
Media is analysed in memory on our servers in Germany and discarded. No bytes, URLs, file names or hashes are stored or logged, and the tool result carries numbers only.
Questions
- What is the SFW API MCP server?
- A Model Context Protocol server that gives an AI agent tools for nudity detection. The agent passes a URL or a file and gets back a content level (0 Everyday, 1 Revealing, 2 Implied Nudity, 3 Explicit), a score per level and flags for drawn content and adult objects.
- Which clients does it work with?
- The hosted endpoint works with every client that can send an Authorization header, such as Claude Code, Cursor, VS Code and Codex. The local package works with every client that can start a local server, including Claude Desktop.
- What does it cost?
- The same credits as the API: one per image, or one per analysed frame of a GIF or video. Listing the tools and get_account are free, and so is every call that fails. Each account gets 500 free credits a month without a card.
- Is the image stored, and does the model see it?
- No to both. The API analyses the media in memory in Germany and discards it; no bytes, URLs, file names or hashes are kept. The tool result holds the level and the scores, never the image, so nothing explicit enters the conversation.
- Hosted or local: which one should I use?
- Start with the hosted endpoint; it is one line and has nothing to install. Use the local package when the agent has to check files on your machine, or when your client can only start local servers.
- Can I add it as a custom connector on claude.ai?
- Not yet. Connectors on claude.ai sign in with OAuth, and the hosted endpoint takes an API key in a header. In Claude Desktop, use the local package instead.
- Where does the API key go?
- Into the SFWAPI_API_KEY environment variable, or into your client's secret prompt where it has one. Keep it out of files you commit. A key can be rotated or revoked in the console at any time.
- Does it work for GIFs and videos?
- Yes. Frames are sampled evenly (5 for a GIF, 10 for a video, up to 32 with max_frames) and the level is the highest over the frames. Video needs a paid account.
Want the agent to write the integration into your own app instead? Use the skill for Claude Code, Codex or Cursor.
Get a key and send a first request
The free key takes a sign-in and no card. Media is processed in memory on our servers in Germany and discarded when the answer is sent, and failed requests cost nothing.