vt-mcp 0.8.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. vt_mcp-0.8.3/LICENSE +202 -0
  2. vt_mcp-0.8.3/LICENSES/MIT.txt +21 -0
  3. vt_mcp-0.8.3/NOTICE +11 -0
  4. vt_mcp-0.8.3/PKG-INFO +134 -0
  5. vt_mcp-0.8.3/README.md +114 -0
  6. vt_mcp-0.8.3/docs/access.md +141 -0
  7. vt_mcp-0.8.3/docs/analysis.md +367 -0
  8. vt_mcp-0.8.3/docs/ci-pilot.md +212 -0
  9. vt_mcp-0.8.3/docs/client-validation-2026-09-07.md +81 -0
  10. vt_mcp-0.8.3/docs/clients.md +682 -0
  11. vt_mcp-0.8.3/docs/control.md +274 -0
  12. vt_mcp-0.8.3/docs/discovery.md +130 -0
  13. vt_mcp-0.8.3/docs/embedding.md +82 -0
  14. vt_mcp-0.8.3/docs/hosted-clients.md +91 -0
  15. vt_mcp-0.8.3/docs/publishing.md +133 -0
  16. vt_mcp-0.8.3/docs/releases/v0.1.0.md +15 -0
  17. vt_mcp-0.8.3/docs/releases/v0.2.0.md +20 -0
  18. vt_mcp-0.8.3/docs/releases/v0.3.0.md +31 -0
  19. vt_mcp-0.8.3/docs/releases/v0.4.0.md +24 -0
  20. vt_mcp-0.8.3/docs/releases/v0.5.0.md +9 -0
  21. vt_mcp-0.8.3/docs/releases/v0.6.0.md +26 -0
  22. vt_mcp-0.8.3/docs/releases/v0.7.0.md +30 -0
  23. vt_mcp-0.8.3/docs/releases/v0.8.0.md +48 -0
  24. vt_mcp-0.8.3/docs/releases/v0.8.1.md +36 -0
  25. vt_mcp-0.8.3/docs/releases/v0.8.2.md +31 -0
  26. vt_mcp-0.8.3/docs/releases/v0.8.3.md +18 -0
  27. vt_mcp-0.8.3/examples/README.md +14 -0
  28. vt_mcp-0.8.3/examples/client-configs/README.md +64 -0
  29. vt_mcp-0.8.3/examples/client-configs/agy-permissions.json +14 -0
  30. vt_mcp-0.8.3/examples/client-configs/cascade-http.json +10 -0
  31. vt_mcp-0.8.3/examples/client-configs/claude-http.json +11 -0
  32. vt_mcp-0.8.3/examples/client-configs/codex-http.toml +6 -0
  33. vt_mcp-0.8.3/examples/client-configs/codex-stdio.toml +6 -0
  34. vt_mcp-0.8.3/examples/client-configs/copilot-cli-stdio.json +14 -0
  35. vt_mcp-0.8.3/examples/client-configs/cursor-http.json +10 -0
  36. vt_mcp-0.8.3/examples/client-configs/gemini-qwen-http.json +10 -0
  37. vt_mcp-0.8.3/examples/client-configs/opencode-v1-http.json +12 -0
  38. vt_mcp-0.8.3/examples/client-configs/opencode-v1-stdio.json +11 -0
  39. vt_mcp-0.8.3/examples/client-configs/stdio.json +10 -0
  40. vt_mcp-0.8.3/examples/client-configs/vscode-http.json +19 -0
  41. vt_mcp-0.8.3/examples/hooks/codex-pretool.toml +13 -0
  42. vt_mcp-0.8.3/examples/lookup.py +39 -0
  43. vt_mcp-0.8.3/glama.json +4 -0
  44. vt_mcp-0.8.3/pyproject.toml +77 -0
  45. vt_mcp-0.8.3/pyproject.toml.orig +65 -0
  46. vt_mcp-0.8.3/server.json +58 -0
  47. vt_mcp-0.8.3/src/vt_mcp/__init__.py +6 -0
  48. vt_mcp-0.8.3/src/vt_mcp/__main__.py +35 -0
  49. vt_mcp-0.8.3/src/vt_mcp/analyses.py +408 -0
  50. vt_mcp-0.8.3/src/vt_mcp/client.py +145 -0
  51. vt_mcp-0.8.3/src/vt_mcp/guard.py +550 -0
  52. vt_mcp-0.8.3/src/vt_mcp/reports.py +302 -0
  53. vt_mcp-0.8.3/src/vt_mcp/server.py +381 -0
  54. vt_mcp-0.8.3/src/vt_mcp/submission_cli.py +397 -0
  55. vt_mcp-0.8.3/src/vt_mcp/submissions.py +122 -0
  56. vt_mcp-0.8.3/src/vt_mcp/vtai_client.py +206 -0
vt_mcp-0.8.3/LICENSE ADDED
@@ -0,0 +1,202 @@
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 vt-mcp contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
vt_mcp-0.8.3/NOTICE ADDED
@@ -0,0 +1,11 @@
1
+ vt-mcp
2
+ Copyright (c) 2026 vt-mcp contributors
3
+
4
+ This release is licensed under the Apache License, Version 2.0.
5
+
6
+ Versions up to and including 0.8.0 were released under the MIT License.
7
+ LICENSES/MIT.txt preserves the original copyright and permission notice for
8
+ pre-existing material carried forward from those versions. It does not offer
9
+ new contributions under an alternative MIT license.
10
+
11
+ Dependencies are distributed separately under their respective licenses.
vt_mcp-0.8.3/PKG-INFO ADDED
@@ -0,0 +1,134 @@
1
+ Metadata-Version: 2.4
2
+ Name: vt-mcp
3
+ Version: 0.8.3
4
+ Summary: VirusTotal intelligence for MCP clients, powered by VTAI
5
+ Author: VirusTotal
6
+ License-Expression: Apache-2.0
7
+ License-File: LICENSE
8
+ License-File: LICENSES/MIT.txt
9
+ License-File: NOTICE
10
+ Requires-Dist: anyio>=4.15.1,<5
11
+ Requires-Dist: httpx>=0.28.1,<0.29
12
+ Requires-Dist: mcp==2.1.1
13
+ Requires-Dist: pydantic>=2.13.5,<3
14
+ Requires-Python: >=3.12
15
+ Project-URL: Homepage, https://ai.virustotal.com
16
+ Project-URL: Documentation, https://ai.virustotal.com/install.md
17
+ Project-URL: Repository, https://github.com/VirusTotal/virustotal-mcp
18
+ Project-URL: Issues, https://github.com/VirusTotal/virustotal-mcp/issues
19
+ Description-Content-Type: text/markdown
20
+
21
+ # VirusTotal MCP
22
+
23
+ <!-- mcp-name: io.github.VirusTotal/virustotal-mcp -->
24
+
25
+ Give your agent VirusTotal intelligence before it opens a link, runs a downloaded file or investigates suspicious infrastructure. **vt-mcp** connects MCP clients to [VTAI](https://ai.virustotal.com), with reports for files, URLs, domains and IP addresses, file submission and analysis recovery.
26
+
27
+ Use the free VTAI service with its current access limits. You need a **VTAI token**, available from [connection setup](https://ai.virustotal.com/connect/mcp); you do not need your own VirusTotal API key. Both local and remote connections use the same account rights and quotas.
28
+
29
+ ## Install for local stdio
30
+
31
+ For local stdio, install [uv](https://docs.astral.sh/uv/getting-started/installation/) and run:
32
+
33
+ ```bash
34
+ uv tool install --python 3.12 --default-index https://pypi.org/simple 'vt-mcp==0.8.3'
35
+ vt-mcp --version
36
+ ```
37
+
38
+ The command installs the package from the official PyPI index in an isolated tool environment. Python 3.12 or newer is required. Keep `vt-mcp` on the MCP client's PATH, or use its absolute executable path. The package does not modify client configuration.
39
+
40
+ For a connection without a local Python process, use **`https://ai.virustotal.com/mcp`** with a supported HTTP client. Supply the VTAI token through either `Authorization: Bearer` or `x-apikey`, using the client's protected credential settings. Send only one authentication header. This is static token authentication; clients that require OAuth need a separate integration.
41
+
42
+ ## Connect your client
43
+
44
+ 1. Reuse your existing VTAI access or [create a token](https://ai.virustotal.com/connect/mcp).
45
+ 2. For stdio, save the token in a file readable only by your user, such as `~/.config/vt-mcp/token`. Set the MCP server's environment variable `VTAI_TOKEN_FILE` to that path and its command to `vt-mcp`. The file contains only the token; never put the token itself in chat, command arguments or project files.
46
+ 3. Follow the client-specific setup, restart or reconnect the client, and inspect its available tools.
47
+
48
+ | Client | Setup |
49
+ |---|---|
50
+ | Antigravity CLI (`agy`) | [Local stdio](https://ai.virustotal.com/connect/mcp?client=agy&transport=stdio) |
51
+ | Claude Code | [HTTP](https://ai.virustotal.com/connect/mcp?client=claude&transport=http) or [local stdio](https://ai.virustotal.com/connect/mcp?client=claude&transport=stdio) |
52
+ | Codex | [HTTP](https://ai.virustotal.com/connect/mcp?client=codex&transport=http) or [local stdio](https://ai.virustotal.com/connect/mcp?client=codex&transport=stdio) |
53
+ | Cursor | [HTTP recipe](https://ai.virustotal.com/connect/mcp?client=cursor&transport=http) |
54
+ | VS Code with GitHub Copilot | [HTTP recipe](https://ai.virustotal.com/connect/mcp?client=vscode&transport=http) |
55
+ | GitHub Copilot CLI | [Local stdio recipe](https://ai.virustotal.com/connect/mcp?client=copilot&transport=stdio) |
56
+ | Devin Local | [Local stdio recipe](https://ai.virustotal.com/connect/mcp?client=devin&transport=stdio) |
57
+ | Windsurf / Devin Desktop | [Cascade HTTP recipe](https://ai.virustotal.com/connect/mcp?client=cascade&transport=http) |
58
+ | Antigravity IDE | [Local stdio configuration](#antigravity-ide) |
59
+
60
+ The [client guide](https://ai.virustotal.com/install.md) distinguishes documented configuration, local transport checks and workflows exercised with a model. A recipe is not a claim of full validation in every client. Other agents can use the same MCP endpoint or the [VTAI API directly](https://ai.virustotal.com/skills/BASIC.md).
61
+
62
+ For a first query, ask your agent:
63
+
64
+ > Use VirusTotal to look up the SHA-256 hash e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855. Explain the source, analysis date, coverage and limitations.
65
+
66
+ This is the empty-file hash. A report lookup does not read or upload local files. A missing report remains unknown, and zero detections do not establish safety.
67
+
68
+ ## Antigravity IDE
69
+
70
+ In the agent panel, open **MCP Servers → Manage MCP Servers → View raw config** and merge this entry with your existing configuration:
71
+
72
+ ```json
73
+ {
74
+ "mcpServers": {
75
+ "virustotal": {
76
+ "command": "vt-mcp",
77
+ "args": [],
78
+ "env": {
79
+ "VTAI_TOKEN_FILE": "~/.config/vt-mcp/token"
80
+ }
81
+ }
82
+ }
83
+ }
84
+ ```
85
+
86
+ Use an absolute executable path if the IDE cannot find `vt-mcp`, then reload and inspect the tools. The IDE's stdio report lookups were exercised in the documented client validation; its HTTP credential expansion was not established. See [Antigravity MCP configuration](https://antigravity.google/docs/mcp).
87
+
88
+ The source archive also includes recipes for Qwen Code, Kimi Code and OpenCode. Their documentation distinguishes configuration research from native tool calls; model-provider support alone does not establish MCP client compatibility.
89
+
90
+ ## Tools
91
+
92
+ | Tool | Purpose |
93
+ |---|---|
94
+ | `get_file_report(hash)` | Retrieve an existing report by MD5, SHA-1 or SHA-256. |
95
+ | `get_url_report(url)` | Retrieve an existing report for an HTTP(S) URL. |
96
+ | `get_domain_report(domain)` | Retrieve domain intelligence; no scheme, path or port. |
97
+ | `get_ip_report(ip)` | Retrieve intelligence for one IPv4 or IPv6 address. |
98
+ | `submit_file(sha256, content_base64)` | Submit authorized bytes for standard analysis, up to 24,000,000 decoded bytes. |
99
+ | `get_submission(sha256)` | Recover this account's submission receipt without sending the file again. |
100
+ | `get_analysis(analysis_id)` | Read the selected analysis registered to this VTAI account. |
101
+ | `submit_local_file(path, expected_sha256=None)` | **Local stdio only:** submit a copy of a regular file, up to 32,000,000 bytes. An expected digest must match that copy. |
102
+
103
+ The seven common tools are available through HTTP and stdio. The remote server cannot read paths on your device. Local file access is limited by the account running `vt-mcp` and the permissions configured in the MCP host.
104
+
105
+ For a file workflow, look up its hash, submit the file when analysis is needed and authorized, then use `get_submission` to recover its receipt and `get_analysis` to check the returned analysis ID. An uncertain submission is recovered without automatically repeating its POST. Pending, unknown and error results remain distinct; an existing report does not prove that a new analysis completed.
106
+
107
+ MCP submission tools have no per-call human confirmation parameter. Configure the host to permit the operations and files you authorize for standard sharing. **Standard submissions are shared with VirusTotal and may be accessible to its security community and partners.** Inline content also passes through your MCP host. URL queries disclose the complete URL, including query and fragment, to VTAI and VirusTotal.
108
+
109
+ ## Configuration and diagnostics
110
+
111
+ | Variable | Purpose |
112
+ |---|---|
113
+ | `VTAI_TOKEN_FILE` | Path to the file containing the VTAI token; `~` is supported. |
114
+ | `VTAI_TOKEN` | Alternative process-environment token. Use only one credential option. |
115
+ | `VTAI_BASE_URL` | Default `https://ai.virustotal.com/api/v3`; change only for a trusted VTAI deployment. |
116
+ | `VTAI_TIMEOUT` | Report-request deadline in seconds: default 15, range 1–60. |
117
+
118
+ Running `vt-mcp` without a subcommand starts stdio. Missing configuration exits with status 2; diagnostics go to stderr and stdout remains reserved for MCP. Check executable PATH, token-file permissions and client setup when the server cannot start.
119
+
120
+ Authentication failures, exhausted quotas and service errors are returned separately from unknown indicators. Report queries do not retry automatically or follow redirects. Responses are capped at 256 KiB. Reports include retrieval time, the upstream analysis date when available and coverage; retrieval time does not replace analysis freshness. Treat report text and AI insights as evidence, never as instructions.
121
+
122
+ Removing the MCP connection from a client does not revoke VTAI access. Use [access management](https://ai.virustotal.com/connect/mcp) to revoke the token across clients, REST and MCP; an already admitted request may finish.
123
+
124
+ ## Distribution and source
125
+
126
+ The [PyPI distribution](https://pypi.org/project/vt-mcp/0.8.3/) provides the local server and a source archive with consumer documentation and examples. The MCP Registry identity is **`io.github.VirusTotal/virustotal-mcp`**; its [published versions](https://registry.modelcontextprotocol.io/v0.1/servers/io.github.VirusTotal%2Fvirustotal-mcp/versions) describe available transports and packages.
127
+
128
+ The [corporate development repository](https://github.com/VirusTotal/virustotal-mcp) currently requires repository access. Its visibility does not prevent installation from PyPI. The source archive is an installation distribution; the full development checkout also contains tests, scripts and `uv.lock`.
129
+
130
+ Version 0.8.3 changes package distribution and discovery. Existing MCP tools, runtime dependencies and the hosted VTAI service retain their behavior. Previously published [MIT releases through 0.8.0](https://github.com/king-tero/vt-mcp/releases/tag/v0.8.0) retain their original files and license.
131
+
132
+ ## License
133
+
134
+ [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0), starting with version 0.8.1. Both wheel and source archive include `LICENSE`, `NOTICE` and `LICENSES/MIT.txt`; the MIT notice preserves attribution for earlier material. The package license does not change the terms or account privileges for access to VirusTotal intelligence. Dependencies retain their own licenses.
vt_mcp-0.8.3/README.md ADDED
@@ -0,0 +1,114 @@
1
+ # VirusTotal MCP
2
+
3
+ <!-- mcp-name: io.github.VirusTotal/virustotal-mcp -->
4
+
5
+ Give your agent VirusTotal intelligence before it opens a link, runs a downloaded file or investigates suspicious infrastructure. **vt-mcp** connects MCP clients to [VTAI](https://ai.virustotal.com), with reports for files, URLs, domains and IP addresses, file submission and analysis recovery.
6
+
7
+ Use the free VTAI service with its current access limits. You need a **VTAI token**, available from [connection setup](https://ai.virustotal.com/connect/mcp); you do not need your own VirusTotal API key. Both local and remote connections use the same account rights and quotas.
8
+
9
+ ## Install for local stdio
10
+
11
+ For local stdio, install [uv](https://docs.astral.sh/uv/getting-started/installation/) and run:
12
+
13
+ ```bash
14
+ uv tool install --python 3.12 --default-index https://pypi.org/simple 'vt-mcp==0.8.3'
15
+ vt-mcp --version
16
+ ```
17
+
18
+ The command installs the package from the official PyPI index in an isolated tool environment. Python 3.12 or newer is required. Keep `vt-mcp` on the MCP client's PATH, or use its absolute executable path. The package does not modify client configuration.
19
+
20
+ For a connection without a local Python process, use **`https://ai.virustotal.com/mcp`** with a supported HTTP client. Supply the VTAI token through either `Authorization: Bearer` or `x-apikey`, using the client's protected credential settings. Send only one authentication header. This is static token authentication; clients that require OAuth need a separate integration.
21
+
22
+ ## Connect your client
23
+
24
+ 1. Reuse your existing VTAI access or [create a token](https://ai.virustotal.com/connect/mcp).
25
+ 2. For stdio, save the token in a file readable only by your user, such as `~/.config/vt-mcp/token`. Set the MCP server's environment variable `VTAI_TOKEN_FILE` to that path and its command to `vt-mcp`. The file contains only the token; never put the token itself in chat, command arguments or project files.
26
+ 3. Follow the client-specific setup, restart or reconnect the client, and inspect its available tools.
27
+
28
+ | Client | Setup |
29
+ |---|---|
30
+ | Antigravity CLI (`agy`) | [Local stdio](https://ai.virustotal.com/connect/mcp?client=agy&transport=stdio) |
31
+ | Claude Code | [HTTP](https://ai.virustotal.com/connect/mcp?client=claude&transport=http) or [local stdio](https://ai.virustotal.com/connect/mcp?client=claude&transport=stdio) |
32
+ | Codex | [HTTP](https://ai.virustotal.com/connect/mcp?client=codex&transport=http) or [local stdio](https://ai.virustotal.com/connect/mcp?client=codex&transport=stdio) |
33
+ | Cursor | [HTTP recipe](https://ai.virustotal.com/connect/mcp?client=cursor&transport=http) |
34
+ | VS Code with GitHub Copilot | [HTTP recipe](https://ai.virustotal.com/connect/mcp?client=vscode&transport=http) |
35
+ | GitHub Copilot CLI | [Local stdio recipe](https://ai.virustotal.com/connect/mcp?client=copilot&transport=stdio) |
36
+ | Devin Local | [Local stdio recipe](https://ai.virustotal.com/connect/mcp?client=devin&transport=stdio) |
37
+ | Windsurf / Devin Desktop | [Cascade HTTP recipe](https://ai.virustotal.com/connect/mcp?client=cascade&transport=http) |
38
+ | Antigravity IDE | [Local stdio configuration](#antigravity-ide) |
39
+
40
+ The [client guide](https://ai.virustotal.com/install.md) distinguishes documented configuration, local transport checks and workflows exercised with a model. A recipe is not a claim of full validation in every client. Other agents can use the same MCP endpoint or the [VTAI API directly](https://ai.virustotal.com/skills/BASIC.md).
41
+
42
+ For a first query, ask your agent:
43
+
44
+ > Use VirusTotal to look up the SHA-256 hash e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855. Explain the source, analysis date, coverage and limitations.
45
+
46
+ This is the empty-file hash. A report lookup does not read or upload local files. A missing report remains unknown, and zero detections do not establish safety.
47
+
48
+ ## Antigravity IDE
49
+
50
+ In the agent panel, open **MCP Servers → Manage MCP Servers → View raw config** and merge this entry with your existing configuration:
51
+
52
+ ```json
53
+ {
54
+ "mcpServers": {
55
+ "virustotal": {
56
+ "command": "vt-mcp",
57
+ "args": [],
58
+ "env": {
59
+ "VTAI_TOKEN_FILE": "~/.config/vt-mcp/token"
60
+ }
61
+ }
62
+ }
63
+ }
64
+ ```
65
+
66
+ Use an absolute executable path if the IDE cannot find `vt-mcp`, then reload and inspect the tools. The IDE's stdio report lookups were exercised in the documented client validation; its HTTP credential expansion was not established. See [Antigravity MCP configuration](https://antigravity.google/docs/mcp).
67
+
68
+ The source archive also includes recipes for Qwen Code, Kimi Code and OpenCode. Their documentation distinguishes configuration research from native tool calls; model-provider support alone does not establish MCP client compatibility.
69
+
70
+ ## Tools
71
+
72
+ | Tool | Purpose |
73
+ |---|---|
74
+ | `get_file_report(hash)` | Retrieve an existing report by MD5, SHA-1 or SHA-256. |
75
+ | `get_url_report(url)` | Retrieve an existing report for an HTTP(S) URL. |
76
+ | `get_domain_report(domain)` | Retrieve domain intelligence; no scheme, path or port. |
77
+ | `get_ip_report(ip)` | Retrieve intelligence for one IPv4 or IPv6 address. |
78
+ | `submit_file(sha256, content_base64)` | Submit authorized bytes for standard analysis, up to 24,000,000 decoded bytes. |
79
+ | `get_submission(sha256)` | Recover this account's submission receipt without sending the file again. |
80
+ | `get_analysis(analysis_id)` | Read the selected analysis registered to this VTAI account. |
81
+ | `submit_local_file(path, expected_sha256=None)` | **Local stdio only:** submit a copy of a regular file, up to 32,000,000 bytes. An expected digest must match that copy. |
82
+
83
+ The seven common tools are available through HTTP and stdio. The remote server cannot read paths on your device. Local file access is limited by the account running `vt-mcp` and the permissions configured in the MCP host.
84
+
85
+ For a file workflow, look up its hash, submit the file when analysis is needed and authorized, then use `get_submission` to recover its receipt and `get_analysis` to check the returned analysis ID. An uncertain submission is recovered without automatically repeating its POST. Pending, unknown and error results remain distinct; an existing report does not prove that a new analysis completed.
86
+
87
+ MCP submission tools have no per-call human confirmation parameter. Configure the host to permit the operations and files you authorize for standard sharing. **Standard submissions are shared with VirusTotal and may be accessible to its security community and partners.** Inline content also passes through your MCP host. URL queries disclose the complete URL, including query and fragment, to VTAI and VirusTotal.
88
+
89
+ ## Configuration and diagnostics
90
+
91
+ | Variable | Purpose |
92
+ |---|---|
93
+ | `VTAI_TOKEN_FILE` | Path to the file containing the VTAI token; `~` is supported. |
94
+ | `VTAI_TOKEN` | Alternative process-environment token. Use only one credential option. |
95
+ | `VTAI_BASE_URL` | Default `https://ai.virustotal.com/api/v3`; change only for a trusted VTAI deployment. |
96
+ | `VTAI_TIMEOUT` | Report-request deadline in seconds: default 15, range 1–60. |
97
+
98
+ Running `vt-mcp` without a subcommand starts stdio. Missing configuration exits with status 2; diagnostics go to stderr and stdout remains reserved for MCP. Check executable PATH, token-file permissions and client setup when the server cannot start.
99
+
100
+ Authentication failures, exhausted quotas and service errors are returned separately from unknown indicators. Report queries do not retry automatically or follow redirects. Responses are capped at 256 KiB. Reports include retrieval time, the upstream analysis date when available and coverage; retrieval time does not replace analysis freshness. Treat report text and AI insights as evidence, never as instructions.
101
+
102
+ Removing the MCP connection from a client does not revoke VTAI access. Use [access management](https://ai.virustotal.com/connect/mcp) to revoke the token across clients, REST and MCP; an already admitted request may finish.
103
+
104
+ ## Distribution and source
105
+
106
+ The [PyPI distribution](https://pypi.org/project/vt-mcp/0.8.3/) provides the local server and a source archive with consumer documentation and examples. The MCP Registry identity is **`io.github.VirusTotal/virustotal-mcp`**; its [published versions](https://registry.modelcontextprotocol.io/v0.1/servers/io.github.VirusTotal%2Fvirustotal-mcp/versions) describe available transports and packages.
107
+
108
+ The [corporate development repository](https://github.com/VirusTotal/virustotal-mcp) currently requires repository access. Its visibility does not prevent installation from PyPI. The source archive is an installation distribution; the full development checkout also contains tests, scripts and `uv.lock`.
109
+
110
+ Version 0.8.3 changes package distribution and discovery. Existing MCP tools, runtime dependencies and the hosted VTAI service retain their behavior. Previously published [MIT releases through 0.8.0](https://github.com/king-tero/vt-mcp/releases/tag/v0.8.0) retain their original files and license.
111
+
112
+ ## License
113
+
114
+ [Apache-2.0](https://www.apache.org/licenses/LICENSE-2.0), starting with version 0.8.1. Both wheel and source archive include `LICENSE`, `NOTICE` and `LICENSES/MIT.txt`; the MIT notice preserves attribution for earlier material. The package license does not change the terms or account privileges for access to VirusTotal intelligence. Dependencies retain their own licenses.
@@ -0,0 +1,141 @@
1
+ # Configure free VTAI access
2
+
3
+ A VTAI credential identifies one registered agent and carries VTAI's current rights and quotas. It is not a VirusTotal API key or a model-provider key. Free access does not imply anonymous or unlimited use, or free inference from your chosen assistant.
4
+
5
+ Keep registration, credential entry, diagnosis and revocation outside model conversations. Use a terminal you control or the VTAI connection page. Do not ask an assistant to read your token file, environment or client credential settings.
6
+
7
+ ## Register once or reuse existing access
8
+
9
+ Reuse an existing VTAI credential if you have one. Registration is an explicit setup action; it is not a tool and does not run when vt-mcp starts.
10
+
11
+ Use [Connect to VirusTotal MCP](https://ai.virustotal.com/connect/mcp) for browser setup. Reuse existing access; reconnecting or changing transport does not register another agent. Its flow lets you register explicitly, request a token-file download, check access and revoke a credential. A download request does not prove the file was saved; confirm protected storage yourself. Checking access consumes query quota and tests the report endpoint, not your model's use of MCP. Registration may have succeeded if the connection fails; do not register again automatically.
12
+
13
+ The [browser acceptance table](clients.md#distribution-and-browser-acceptance) records the real flow through a route pinned to the production candidate, separately from ordinary public navigation and package release acceptance. If the page is unavailable, check the exact endpoint/prefix and [service validation](clients.md#service-and-workflow-validation). For a terminal setup, the explicit API example below is an alternative; opening the API URL alone does not register an agent.
14
+
15
+ For local setup, this terminal script calls the existing registration API and writes the credential without printing it. It refuses an existing path and uses owner-only permissions on POSIX. Run it only once; if the request times out after registration, registration may have succeeded. Diagnose that uncertainty before creating another agent.
16
+
17
+ ```bash
18
+ python3 - <<'PY'
19
+ import json
20
+ import os
21
+ from pathlib import Path
22
+ from urllib.error import HTTPError, URLError
23
+ from urllib.request import HTTPRedirectHandler, Request, build_opener
24
+
25
+ class NoRedirect(HTTPRedirectHandler):
26
+ def redirect_request(self, req, fp, code, msg, headers, newurl):
27
+ return None
28
+
29
+ path = Path.home() / ".config" / "vt-mcp" / "token"
30
+ path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
31
+ path.parent.chmod(0o700)
32
+ if path.exists() or path.is_symlink():
33
+ raise SystemExit("An existing credential path is already configured.")
34
+ request = Request(
35
+ "https://ai.virustotal.com/api/v3/agents/register",
36
+ data=json.dumps({"agent_family": "vt-mcp", "agent_version": "0.8.3"}).encode(),
37
+ headers={"Content-Type": "application/json"},
38
+ method="POST",
39
+ )
40
+ try:
41
+ with build_opener(NoRedirect).open(request, timeout=20) as response:
42
+ raw = response.read(65537)
43
+ if len(raw) > 65536:
44
+ raise ValueError("response limit")
45
+ token = json.loads(raw)["agent_token"]
46
+ if not isinstance(token, str) or not token.startswith("vtai_"):
47
+ raise ValueError("credential format")
48
+ if not 6 <= len(token) <= 256 or any(not 33 <= ord(c) <= 126 for c in token):
49
+ raise ValueError("credential format")
50
+ except (HTTPError, URLError, TimeoutError, ValueError, KeyError, TypeError):
51
+ raise SystemExit("Registration was not confirmed. No credential was saved.") from None
52
+ try:
53
+ with os.fdopen(os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600), "w") as output:
54
+ output.write(token)
55
+ except OSError:
56
+ raise SystemExit("Registration returned access, but saving failed. Resolve local storage before retrying.") from None
57
+ print("VTAI credential saved. Registration is not needed at each startup.")
58
+ PY
59
+ ```
60
+
61
+ An existing credential can instead be saved using a trusted editor or password manager to `~/.config/vt-mcp/token`, as a single value. Do not put it in a shell command or a project file. On POSIX, protect the directory with mode `0700` and the file with mode `0600`. If you downloaded a token, a browser does not guarantee those permissions: move it to protected storage and remove the extra download after verifying storage. Windows needs equivalent user-only file access; the POSIX instructions are not Windows validation.
62
+
63
+ ## Local stdio
64
+
65
+ Install the wheel using the [README](../README.md), then add your client using [client setup](clients.md). Configure only the file path:
66
+
67
+ ```text
68
+ VTAI_TOKEN_FILE=~/.config/vt-mcp/token
69
+ ```
70
+
71
+ vt-mcp reads the file at startup and uses `x-apikey` for its VTAI requests. Restart its client process after replacing the file. `VTAI_TOKEN` is an alternative for direct process configuration; setting both credential options is an error.
72
+
73
+ ## Remote client environment
74
+
75
+ Remote MCP uses `https://ai.virustotal.com/mcp`, not the REST URL ending `/api/v3`. Existing clients can keep using **`x-apikey`**. VTAI 0.8.1 additionally accepts the same VTAI credential in **`Authorization: Bearer`** on protected REST routes and MCP. This backend option does not require a vt-mcp 0.8.0 package upgrade.
76
+
77
+ Use the host's supported environment-header reference from the [configuration fragments](../examples/client-configs/README.md). `VTAI_MCP_TOKEN` is an arbitrary host-side variable name, chosen to avoid conflict with a stdio server's `VTAI_TOKEN_FILE`.
78
+
79
+ For Antigravity CLI (`agy`) 1.1.27, use the [stdio token-file setup](clients.md#antigravity-cli-agy); tested HTTP header variables were sent literally. Claude Code and Codex support the remote configurations described here.
80
+
81
+ ### Choose one authentication header
82
+
83
+ Configure **one** credential method per connection: `x-apikey` or `Authorization: Bearer`. Both identify the same VTAI agent and share its rights, quotas and revocation. Sending both is rejected, even if their values match; an invalid Bearer does not fall back to `x-apikey`. Tokens in URLs, query parameters or request bodies do not authenticate a request.
84
+
85
+ For the Bearer alternative, use the host's protected environment reference: [Claude Code](clients.md#claude-code) expands `Bearer ${VTAI_MCP_TOKEN}` in its Authorization header, and [Codex](clients.md#codex-cli--remote-http) supports `bearer_token_env_var = "VTAI_MCP_TOKEN"`. Remove any `x-apikey` mapping from that server entry when selecting Bearer. The examples contain a variable name, never a credential value. See the [scoped native Bearer checks and deployment status](clients.md#bearer-authentication-validation); earlier HTTP workflow evidence used `x-apikey`.
86
+
87
+ This is a static VTAI Agent Token, not a VirusTotal API key, Google access token or model-provider login. VTAI does not implement OAuth login, refresh or OAuth discovery. A `WWW-Authenticate: Bearer` challenge does not establish an OAuth authorization server or hosted-connector compatibility. Do not run `codex mcp login` to obtain this token; reuse or explicitly register VTAI access as described above.
88
+
89
+ The Bearer scheme is case insensitive and the token is case sensitive. The configured header must use spaces between the scheme and token, without quotes, surrounding whitespace, tabs or comma-separated credentials. The examples below load the token for either supported header mapping.
90
+
91
+ In a human-controlled Bash terminal, load the file without printing its value, then launch the client:
92
+
93
+ ```bash
94
+ (
95
+ set +x
96
+ unset VTAI_MCP_TOKEN
97
+ IFS= read -r VTAI_MCP_TOKEN < "$HOME/.config/vt-mcp/token" || test -n "$VTAI_MCP_TOKEN" || exit 1
98
+ test -n "$VTAI_MCP_TOKEN" || exit 1
99
+ export VTAI_MCP_TOKEN
100
+ exec claude
101
+ )
102
+ ```
103
+
104
+ Use `exec codex` instead for Codex, with its matching header configuration. A nonempty first line works with or without a trailing newline; a missing file or empty first line prevents launch. The subshell does not leave a new export in the parent shell. The variable lasts for that client process, and a previously opened GUI will not inherit it. Do not use a header flag containing an expanded credential: it can put the secret in process arguments and saved configuration. File and environment storage avoid normal disclosure in prompts; they do not isolate credentials from software with permission to read them.
105
+
106
+ ## Diagnose the right layer
107
+
108
+ 1. Check the installed client version and `vt-mcp --version` for stdio. Confirm the executable PATH and file access without displaying the credential.
109
+ 2. Inspect the client's MCP status. A configuration parser or `tools/list` result proves only that layer. In stdio, discovery does not authenticate a VTAI request.
110
+ 3. Make one explicit report query through the client. Use the empty-file SHA-256 `e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855`, or `example.com`. This consumes an admitted query and does not upload or start a scan. Check source, analysis date, coverage and report link.
111
+ 4. Confirm that the assistant actually called a tool and used its result. A generic SDK test or successful connection does not establish a model workflow in another client.
112
+
113
+ | Observation | Meaning / action |
114
+ |---|---|
115
+ | 400 / Bearer `invalid_request` | Malformed or repeated Bearer authentication, or both credential methods sent together. Keep exactly one valid header mapping. |
116
+ | 401 | No supported credential, or an invalid, unknown, expired or revoked Bearer token. Check the mapping and environment source without displaying the value. |
117
+ | 403 / `access_denied` | Legacy `x-apikey` was rejected, or the operation was denied after authentication. Check the structured error and current access. |
118
+ | 429 / `rate_limited` | Wait for a supplied retry delay; repeated retries consume resources. |
119
+ | Tool result `not_found` | No report was found; this is not a safety verdict. |
120
+ | HTTP 404 for `/mcp` or `/connect/mcp` | Check endpoint, prefix and deployment flags; this is not an unknown indicator result. |
121
+ | Timeout / service error | A failed lookup is not a clean report. Check service status; do not silently submit a sample. |
122
+
123
+ REST and MCP share VTAI admission and quotas. Unknown reports and upstream failures still consume an admitted query. The stdio wrapper defaults to a 15-second total request deadline; the backend lookup has its own 35-second limit. A client timeout can happen first, and an already admitted request may complete later. Show only sanitized errors to the model; never paste raw auth headers or debug logs into chat.
124
+
125
+ VTAI 0.8.1 authentication failures use `Cache-Control: no-store`. Missing credentials receive a plain `Bearer realm="VTAI"` challenge; rejected Bearer tokens add `error="invalid_token"`, and malformed Bearer requests add `error="invalid_request"`. Legacy `x-apikey` rejections retain 403 without a challenge. Access-storage unavailability remains 503. Permission, quota and tool errors after authentication keep their existing contracts.
126
+
127
+ ## Disconnect and reconnect
128
+
129
+ Remove or disable the `virustotal` entry in the client and restart/reload it. [Client setup](clients.md) lists removal commands. Verify that its tools disappear. This removes that connection; it does not revoke VTAI access or delete VTAI history.
130
+
131
+ Do not remove a credential file shared by other clients unless you intend to remove their local access too. After a local disconnect, a still-valid credential can be used to reconnect without registering again.
132
+
133
+ ## Revoke access
134
+
135
+ Use the revocation form at [the VTAI connection page](https://ai.virustotal.com/connect/mcp) when its deployment enables revocation. Enter the credential in that human-facing form and confirm the action. Its API is `DELETE /api/v3/agents/me/token`, authenticated with `x-apikey` or, on VTAI 0.8.1, the alternative Bearer header; this is an advanced setup operation, not an MCP tool.
136
+
137
+ A confirmed revocation returns 204. A timeout or service error does not confirm success; retain protected access to the credential so you can diagnose or retry. A 401/403 means it was not accepted, not proof that this particular action revoked it.
138
+
139
+ VTAI currently has one credential per agent. Revocation disables that agent across clients, REST and MCP; records remain, and a lookup admitted before revocation may finish. Remove the connection from every affected client afterward. To obtain access after revocation, explicitly register a new agent. This is not rotation of the old agent's credential.
140
+
141
+ A subsequent request using the revoked token receives 401 with Bearer or 403 with legacy `x-apikey`; the two headers do not create separate credentials.