Skip to content
Malwagon
Sign up

MCP server

Endpoint
https://malwagon.com/mcp
A callPOST /mcp
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "lookup_hash",
    "arguments": {
      "sha256": "9c1f0b6d2ae74318bd50c7a9e6f34182"
                "bb0d5e7c94a2f61038de7b5c0a91f2d4"
    },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28"
    }
  }
}
The digest is the target. No bytes cross this boundary, in either direction.
The answer200, one response
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "content": [{ "type": "text", "text": "..." }],
    "structuredContent": {
      "sha256": "9c1f0b6d...0a91f2d4",
      "known": true,
      "scans": [
        { "scan_id": 4127,
          "verdict": "malicious",
          "score": 88 }
      ]
    }
  }
}
A refused call is still a 200 with an error inside it, so a client can tell a spent budget from a broken connection.

What it is for

An analyst working with an AI client should not have to be the wire between the two. The MCP server exposes this platform's analysis as tools the client can call itself: it looks a hash up, searches an indicator across the corpus, queues a scan and reads the finished report, and it does that with the same identity, the same plan limits and the same privacy rules a person would have.

It is a second surface over the work the REST API already does, not a second platform. A scan submitted through a tool call is the same scan, in the same queue, on the same machines, and it produces the same report.

It is included with Team and Enterprise plans, and it authenticates with a bearer token like the REST API does. See pricing.

The tools

Five, each carrying the scope it costs. A token issued read can call the four that read; only a submit token can queue an analysis, and a client is told which it holds before it tries.

Tool Scope What it answers
lookup_hash read Find analyses of a known SHA-256 digest.
get_report read The derived analysis report for one scan: verdict, capabilities, behaviour summary, observed operations and defanged indicators.
search_indicator read Find scans where an indicator was observed: an IP, a domain, a URL, a mutex, a registry key, a hash or a JA3/JA4 fingerprint.
poll_scan read The current status of one scan, for polling after submit_scan.
submit_scan submit Queue a new analysis of a target that can be named as text: a SHA-256 to look up, a URL to visit, a command to run, or a package to install.

Connect a client

Two values do all the work: the endpoint and a bearer token. Where a client keeps them differs; what it sends does not.

Check your client's revision firstread this first
This endpoint speaks revision 2026-07-28 and no earlier one. That revision has no handshake and puts the protocol version and the client's capabilities in every request, so a client built for an earlier revision is refused on its first call with -32602 rather than connecting and behaving oddly. If your client has not adopted it yet, run the small stdio bridge below: it speaks your client's revision on one side and this one on the other, and it holds no policy of its own. The token, the plan and the scope are still decided here.
AI client holds the token MCP endpoint token, plan, scope, budget Analysis the same queue and machines tool call target as text No sample bytes cross either arrow, in either direction.
Clauderemote MCP server
{
  "mcpServers": {
    "malwagon": {
      "url": "https://malwagon.com/mcp",
      "headers": {
        "Authorization": "Bearer mwg_a1b2c3d4_kZq7Xn2R9tLpWv0sYcB4hJdF6gMaE3uNbT1xQfV5rDo"
      }
    }
  }
}
This is the shape a client uses once it speaks revision 2026-07-28: Claude Desktop keeps a block like it in its own configuration file, and Claude Code registers the same server from the command line. Where the setting lives is the client's business and its documentation is the authority on that; the URL and the header are ours. Until the client adopts the revision, point it at the bridge instead and keep the same two values there.
ChatGPTconnector fields
Server URL      https://malwagon.com/mcp
Authorization   Bearer mwg_a1b2c3d4_kZq7Xn2R9tLpWv0sYcB4hJdF6gMaE3uNbT1xQfV5rDo
Its connector form asks for a server address and the header to send with it, which are the same two values. Two things are outside our control: whether that form is available to you depends on your ChatGPT plan and workspace settings, and a hosted connector reaches this endpoint directly, so it works once the connector speaks revision 2026-07-28, and a local bridge cannot stand in for it the way it can for a desktop client.
Bridgefor a client on an earlier revision
{
  "mcpServers": {
    "malwagon": {
      "command": "python3",
      "args": ["/path/to/mcp_bridge.py"],
      "env": {
        "MWG_MCP_URL": "https://malwagon.com/mcp",
        "MWG_MCP_TOKEN": "mwg_a1b2c3d4_kZq7Xn2R9tLpWv0sYcB4hJdF6gMaE3uNbT1xQfV5rDo"
      }
    }
  }
}
Put the file wherever the client can reach it and give that path here; the example is a placeholder, not a location on this host. A single file with no dependencies beyond the standard library. It answers the handshake locally, because there is nothing here to forward one to, and adds the revision block and the mirrored headers to every call it passes on. The token is read from the environment rather than from the command line, so it does not appear in a process list.
Any MCP clientprove it first
curl -sS -X POST "https://malwagon.com/mcp" \
  -H "Authorization: Bearer $MWG_TOKEN" \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: tools/list" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list",
       "params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28"}}}'
Worth running before wiring anything: it answers with the tools your token's scope can reach, so a plan problem or a wrong scope shows up here rather than as a client that connects and then does nothing.

What a client sends

Revision 2026-07-28 has no handshake. Every request states its own protocol version and client capabilities, and the server answers each one on its own terms, so a dropped connection costs nothing to resume.

In params._meta

  • io.modelcontextprotocol/protocolVersion
  • io.modelcontextprotocol/clientInfo
  • io.modelcontextprotocol/clientCapabilities

The prefix is reserved by the specification, so these exact strings are the contract rather than a convention.

Mirrored into headers

  • MCP-Protocol-Version
  • Mcp-Method
  • Mcp-Name

They must agree with the body. A header that contradicts what it mirrors is refused rather than reconciled, because a proxy that rewrote one of them is a thing the server cannot see.

What a call passes through

Four gates, in this order, and each one is answered before the next is asked. A call that fails any of them never reaches the analysis pipeline.

  1. 01 Envelope One JSON-RPC request, the declared revision, and every mirrored header agreeing with the body it mirrors.
  2. 02 Token Resolved to an account on every call, never cached between them, so a revoked token stops at the next one.
  3. 03 Plan and scope The plan has to include this surface and the token's scope has to cover this tool. Both are read live.
  4. 04 Budget Reads and submissions carry separate allowances; a submission also spends a credit, and one that cannot be charged is refused rather than queued.

Error codes

Standard JSON-RPC codes, plus the two ranges the specification reserves. Nothing outside these is emitted, and each carries one meaning.

Code Meaning
-32700 The body is not JSON.
-32600 Valid JSON, but not a JSON-RPC request.
-32601 No such method on this server.
-32602 The params are wrong for the method named.
-32603 The server failed while handling a valid call.
-32020 A mirrored header disagrees with the body it mirrors.
-32021 The call needs a client capability this client did not declare.
-32022 The declared revision is not one this server speaks.
-31001 No usable token, or a plan that does not include this surface.
-31002 The token is valid and its scope does not cover this tool.

What it will not do

It never carries a sample. No tool accepts file bytes and none returns them. A submission names its target as text, a digest, a URL, a command line or a package, and a report comes back as derived findings. The bytes stay on the hardware that ran them.

A read token cannot be talked into writing. Scope is checked per tool call against the token, not against the session, so a client that has been persuaded to try submit_scan with a read token is refused rather than asked to confirm.

It has no privileges of its own. The token belongs to an account, and every call is answered with that account's plan, its credits and its visibility. A tool call cannot read a scan the person holding the token could not open in the console.

It is rate limited like everything else. Reads and submissions carry their own budgets, and a spent budget comes back as a tool error inside a successful response rather than as a transport failure, because a client that cannot read the difference will retry the wrong one.

Sign in

Sign in

The analyst console and your scan history. Private scans and the API come with a paid plan.

or
Continue with Google

New team? Create a free account

Sign up

Create your account

Free tier: 20 scans a month, three sandbox images, reports public. No card required.

12 characters minimum

or
Continue with Google

By creating an account you accept the terms and privacy policy.

Already provisioned? Sign in