@socketsecurity/mcp 0.0.20 → 0.2.1

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.
package/README.md CHANGED
@@ -1,17 +1,14 @@
1
1
  # Socket MCP Server
2
2
 
3
- [![Socket Badge](https://socket.dev/api/badge/npm/package/@socketsecurity/mcp)](https://socket.dev/npm/package/@socketsecurity/mcp)
4
- [![CI](https://github.com/SocketDev/socket-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/SocketDev/socket-mcp/actions/workflows/ci.yml)
5
- ![Coverage](https://img.shields.io/badge/coverage-80%25-green)
3
+ <a href="https://socket.dev/npm/package/@socketsecurity/mcp"><img src="https://socket.dev/api/badge/npm/package/@socketsecurity/mcp" alt="Socket Badge" height="20"></a>
4
+ <picture><img src="https://raw.githubusercontent.com/SocketDev/socket-mcp/v0.2.1/assets/repo/coverage.svg?v=66258ab9f3b4" height="20" alt="Coverage" /></picture>
6
5
 
7
6
  [![Follow @SocketSecurity](https://img.shields.io/twitter/follow/SocketSecurity?style=social)](https://twitter.com/SocketSecurity)
8
7
  [![Follow @socket.dev on Bluesky](https://img.shields.io/badge/Follow-@socket.dev-1DA1F2?style=social&logo=bluesky)](https://bsky.app/profile/socket.dev)
9
8
 
10
- A Model Context Protocol (MCP) server for Socket integration — lets AI assistants query dependency vulnerability scores and security metadata.
11
-
12
- ## Why this repo exists
13
-
14
- Socket MCP exposes Socket.dev's package-scoring API through the Model Context Protocol, so any MCP-aware AI assistant (Claude, VS Code Copilot, Cursor, Windsurf) can score a package, audit a `package.json`, or flag risky dependencies as part of a conversation. It ships as both a hosted public server (`https://mcp.socket.dev/`, no setup) and a self-hostable npm package, so you can choose between zero-friction and full data isolation.
9
+ Socket MCP lets AI assistants query Socket's dependency security scores and metadata through the Model Context Protocol (MCP).
10
+ Use it to score a package, audit a `package.json`, or identify risky dependencies in a conversation.
11
+ Connect your MCP client to the hosted server at `https://mcp.socket.dev/`, or run the npm package yourself.
15
12
 
16
13
  ## ✨ Features
17
14
 
@@ -28,34 +25,21 @@ Socket MCP exposes Socket.dev's package-scoring API through the Model Context Pr
28
25
 
29
26
  ### Option 1: Use the public Socket MCP server (recommended)
30
27
 
31
- The easiest way to get started. The public server uses OAuth — your MCP client opens a browser to sign in to Socket on first connect; no API key to copy or manage. Click a button below to install in your favorite AI assistant.
28
+ The public server uses OAuth. Your MCP client opens a browser to sign in to Socket on first connection. You do not need an API key.
32
29
 
33
- [![Install in VS Code](https://img.shields.io/badge/VS_Code-Socket_MCP-0098FF?style=flat-square&logo=visualstudiocode&logoColor=white)](https://vscode.dev/redirect/mcp/install?name=socket-mcp&config={"url":"https://mcp.socket.dev/","type":"http"})
34
- [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=socket-mcp&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Imh0dHBzOi8vbWNwLnNvY2tldC5kZXYvIn0%3D)
30
+ - [Install in VS Code](https://vscode.dev/redirect/mcp/install?name=socket-mcp&config=%7B%22url%22%3A%22https%3A%2F%2Fmcp.socket.dev%2F%22%2C%22type%22%3A%22http%22%7D).
31
+ - [Install in Cursor](https://cursor.com/en/install-mcp?name=socket-mcp&config=eyJ0eXBlIjoiaHR0cCIsInVybCI6Imh0dHBzOi8vbWNwLnNvY2tldC5kZXYvIn0%3D).
35
32
 
36
- <details><summary><b>Manual install — Claude Desktop / Claude Code</b></summary>
33
+ <details><summary><b>Manual install - Claude Desktop / Claude Code</b></summary>
37
34
 
38
- > [!NOTE]
39
- > Custom integrations are not available to all paid versions of Claude. Check [here](https://support.anthropic.com/en/articles/11175166-about-custom-integrations-using-remote-mcp) for more information.
35
+ Add the hosted server through Claude's [custom connector settings](https://support.claude.com/en/articles/11175166-get-started-with-custom-connectors-using-remote-mcp). The Developer configuration file is for local servers.
40
36
 
41
- 1. In Claude Desktop, go to Settings > Developer > Edit Config.
42
- 2. Add the Socket MCP server configuration:
43
-
44
- ```json
45
- {
46
- "mcpServers": {
47
- "socket-mcp": {
48
- "type": "http",
49
- "url": "https://mcp.socket.dev/"
50
- }
51
- }
52
- }
53
- ```
37
+ 1. Open Customize > Connectors in Claude.
38
+ 2. Select **Add custom connector** and enter `https://mcp.socket.dev/` as the server URL. On Team and Enterprise plans, an organization owner adds the connector through Organization settings > Connectors first.
39
+ 3. Select **Connect** and complete the Socket authorization flow when prompted.
40
+ 4. Enable the connector for your conversation, then ask Claude "Check the security score for express version 4.18.2".
54
41
 
55
- 3. Save the configuration and restart Claude Desktop.
56
- 4. Now you can ask Claude "Check the security score for express version 4.18.2".
57
-
58
- For Claude Code:
42
+ For Claude Code, one command does all of it:
59
43
 
60
44
  ```sh
61
45
  claude mcp add --transport http socket-mcp https://mcp.socket.dev/
@@ -63,7 +47,7 @@ claude mcp add --transport http socket-mcp https://mcp.socket.dev/
63
47
 
64
48
  </details>
65
49
 
66
- <details><summary><b>Manual install — VS Code</b></summary>
50
+ <details><summary><b>Manual install - VS Code</b></summary>
67
51
 
68
52
  ```sh
69
53
  # For VS Code with GitHub Copilot
@@ -85,7 +69,7 @@ Or add to `.vscode/mcp.json`:
85
69
 
86
70
  </details>
87
71
 
88
- <details><summary><b>Manual install — Cursor</b></summary>
72
+ <details><summary><b>Manual install - Cursor</b></summary>
89
73
 
90
74
  `Cursor Settings` → `MCP` → `Add new MCP Server`. Name `socket-mcp`, `http` type, URL `https://mcp.socket.dev/`.
91
75
 
@@ -102,10 +86,9 @@ Or add to `.vscode/mcp.json`:
102
86
 
103
87
  </details>
104
88
 
105
- <details><summary><b>Manual install — Windsurf</b></summary>
89
+ <details><summary><b>Manual install - Windsurf</b></summary>
106
90
 
107
- > [!WARNING]
108
- > Windsurf does not support `http` type MCP servers yet. Use the stdio configuration in Option 2 below.
91
+ Windsurf does not support `http` type MCP servers. Use the stdio configuration in Option 2 below, or the `serverUrl` form:
109
92
 
110
93
  ```json
111
94
  {
@@ -119,7 +102,7 @@ Or add to `.vscode/mcp.json`:
119
102
 
120
103
  </details>
121
104
 
122
- <details><summary><b>Manual install — Factory</b></summary>
105
+ <details><summary><b>Manual install - Factory</b></summary>
123
106
 
124
107
  [Factory](https://factory.ai) is an AI-powered software engineering platform. Install the Socket MCP server with the Factory CLI:
125
108
 
@@ -133,16 +116,60 @@ Alternatively, type `/mcp` within the Factory droid to manage MCP servers from a
133
116
 
134
117
  </details>
135
118
 
119
+ ### Clients that need a local bridge
120
+
121
+ Prefer your client's native remote HTTP connection to `https://mcp.socket.dev/` when available. For clients that only launch local stdio servers, install `mcp-remote` 0.8.3:
122
+
123
+ ```bash
124
+ pnpm add --global mcp-remote@0.8.3
125
+ ```
126
+
127
+ Add this local server configuration to your MCP client:
128
+
129
+ ```json
130
+ {
131
+ "mcpServers": {
132
+ "socket": {
133
+ "command": "mcp-remote",
134
+ "args": ["https://mcp.socket.dev/"]
135
+ }
136
+ }
137
+ }
138
+ ```
139
+
140
+ The bridge runs on your computer and receives OAuth redirects at `http://localhost:<port>/oauth/callback`. Keep it running while you authorize. Version 0.3.3 introduced the [mid-session authorization fix](https://github.com/punkpeye/mcp-remote/pull/340); the forwarding and reauthorization retry paths were verified against the published 0.8.3 package. This verification does not cover a complete browser sign-in.
141
+
142
+ Reuse saved authorization while it remains valid. If a browser reports connection refused at the localhost callback, check the bridge's version and process. The callback listener belongs to the bridge; changing the hosted MCP URL does not start it.
143
+
136
144
  ### Option 2: Self-host the Socket MCP server
137
145
 
138
- To run your own instance, create an API key first (only the `packages:list` permission scope is needed; see [creating-and-managing-api-tokens](https://docs.socket.dev/reference/creating-and-managing-api-tokens)).
146
+ Self-hosting keeps every request inside your own infrastructure. It needs a Socket API token and Node.js 24 or later.
147
+
148
+ **Get a token first.** Sign in at [socket.dev](https://socket.dev/), open the API tokens page, and create a token with the `packages:list` scope. That single scope covers `depscore`; the org-scoped tools need whatever scopes your organization requires for the endpoints they call. Full walkthrough: [creating and managing API tokens](https://docs.socket.dev/reference/creating-and-managing-api-tokens).
149
+
150
+ **Then pick a transport.** The server speaks the same MCP protocol either way; the difference is who launches it.
151
+
152
+ | | Stdio (Option 2a) | HTTP (Option 2b) |
153
+ | ---------------------- | --------------------------------------------- | -------------------------------------------------------------------- |
154
+ | Who starts the process | Your MCP client, on demand | You, as a long-running service |
155
+ | Who it serves | One local user | Any client that can reach the port |
156
+ | Where the token lives | The client's config, as an env var | The server env, or per-request `Authorization` headers |
157
+ | Reach for it when | You are a developer wiring up your own editor | You are deploying one instance for a team, or fronting it with OAuth |
158
+
159
+ Stdio is the default and the right answer for a single developer. Choose HTTP when more than one person, or something that is not a local process, needs to reach the server.
160
+
161
+ Install it once, globally, before either option:
162
+
163
+ ```sh
164
+ pnpm add -g @socketsecurity/mcp
165
+ ```
139
166
 
140
- <details><summary><b>Option 2a — Stdio mode (default)</b></summary>
167
+ <details><summary><b>Option 2a - Stdio mode (default)</b></summary>
141
168
 
142
169
  Claude Code:
143
170
 
144
171
  ```sh
145
- claude mcp add socket-mcp -e SOCKET_API_TOKEN="your-api-token-here" -- npx -y @socketsecurity/mcp@latest # socket-hook: allow npx
172
+ claude mcp add socket-mcp -e SOCKET_API_TOKEN="your-api-token-here" -- socket-mcp
146
173
  ```
147
174
 
148
175
  Most other MCP clients:
@@ -151,8 +178,7 @@ Most other MCP clients:
151
178
  {
152
179
  "mcpServers": {
153
180
  "socket-mcp": {
154
- "command": "npx", // socket-hook: allow npx
155
- "args": ["@socketsecurity/mcp@latest"],
181
+ "command": "socket-mcp",
156
182
  "env": {
157
183
  "SOCKET_API_TOKEN": "your-api-token-here"
158
184
  }
@@ -163,40 +189,93 @@ Most other MCP clients:
163
189
 
164
190
  </details>
165
191
 
166
- <details><summary><b>Option 2b — HTTP mode</b></summary>
192
+ <details><summary><b>Option 2b - HTTP mode</b></summary>
167
193
 
168
- Run the server in HTTP mode using npx:
194
+ Run the server in HTTP mode:
169
195
 
170
196
  ```sh
171
- MCP_HTTP_MODE=true SOCKET_API_TOKEN=your-api-token npx @socketsecurity/mcp@latest --http # socket-hook: allow npx
197
+ MCP_HTTP_MODE=true SOCKET_API_TOKEN=your-api-token socket-mcp --http
172
198
  ```
173
199
 
200
+ The server listens on `http://localhost:3000/`. The MCP endpoint is `/` and the health endpoint is `/health`; every other path answers `404`.
201
+
202
+ The transport is stateless. Each `POST /` is self-contained, with no session to open, no `Mcp-Session-Id` header, and nothing to expire, so you can put several instances behind a load balancer without session affinity. `GET` and `DELETE` on the MCP endpoint answer `405`. Clients written against the 2025 protocol, which open with an `initialize` handshake, are still served.
203
+
174
204
  Environment variables for HTTP mode:
175
205
 
176
- | Variable | Required | Default | Description |
177
- | ------------------------------------------ | ------------------------------------------------------------ | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
178
- | `SOCKET_API_TOKEN` | Required unless OAuth is enabled | None | Socket API token used for outbound API calls. Legacy aliases (`SOCKET_API_KEY`, `SOCKET_CLI_API_TOKEN`, `SOCKET_CLI_API_KEY`, `SOCKET_SECURITY_API_TOKEN`, `SOCKET_SECURITY_API_KEY`) are accepted via the fleet's `getSocketApiToken()` helper. If unset in OAuth-enabled HTTP mode, the validated incoming bearer token is forwarded upstream instead. |
179
- | `SOCKET_OAUTH_ISSUER` | Set together with the two introspection vars to enable OAuth | None | OAuth issuer URL used for metadata discovery and incoming bearer-token validation. |
180
- | `SOCKET_OAUTH_INTROSPECTION_CLIENT_ID` | With OAuth | None | Client ID used for token introspection. |
181
- | `SOCKET_OAUTH_INTROSPECTION_CLIENT_SECRET` | With OAuth | None | Client secret used for token introspection. |
182
- | `SOCKET_OAUTH_REQUIRED_SCOPES` | No | _(none)_ | Space-delimited scopes required on incoming access tokens. When unset, no scope is enforced — any active token passes. |
183
- | `SOCKET_API_URL` | No | Production Socket API URL, or localhost when `SOCKET_DEBUG=true` | Override the upstream Socket API endpoint. Useful for local development and testing. |
184
- | `SOCKET_DEBUG` | No | `false` | Switches the default upstream Socket API endpoint to localhost when `SOCKET_API_URL` is unset. |
185
- | `TRUST_PROXY` | No | `false` | When `true`, trust `X-Forwarded-Host` and `X-Forwarded-Proto` when building OAuth metadata URLs. Enable only behind a trusted reverse proxy that rewrites these headers. |
186
- | `MCP_PORT` | HTTP mode only | `3000` | Port to bind the HTTP server to. |
206
+ | Variable | Required | Default | Description |
207
+ | ------------------------------------------ | -------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
208
+ | `MCP_HTTP_MODE` | Yes, unless you pass `--http` | `false` | Set to `true` to serve HTTP instead of stdio. The `--http` CLI flag does the same thing. |
209
+ | `MCP_PORT` | No | `3000` | Port to bind the HTTP server to. |
210
+ | `SOCKET_API_TOKEN` | Required unless OAuth is enabled | None | Socket API token for outbound API calls. See the alias list below. |
211
+ | `SOCKET_OAUTH_ISSUER` | With OAuth | None | OAuth issuer URL. Must be `https` on a public host. See "Enabling OAuth" below. |
212
+ | `SOCKET_OAUTH_INTROSPECTION_CLIENT_ID` | With OAuth | None | Client ID used for RFC 7662 token introspection. |
213
+ | `SOCKET_OAUTH_INTROSPECTION_CLIENT_SECRET` | With OAuth | None | Client secret used for RFC 7662 token introspection. |
214
+ | `SOCKET_OAUTH_REQUIRED_SCOPES` | No | None | Scopes required on incoming access tokens, separated by spaces or commas. When unset, any active token passes. |
215
+ | `SOCKET_OAUTH_REQUIRE_AUDIENCE` | No | `false` | When `true`, reject an access token whose introspection response carries no `aud` claim. Read the audience note below first. |
216
+ | `SOCKET_API_BASE_URL` | No | None | Override the upstream Socket API endpoint. Falls back to `https://api.socket.dev` when unset. |
217
+ | `SOCKET_DEBUG` | No | `false` | Turns on verbose request and cache tracing on stderr, points `depscore` at `http://localhost:8866`, and permits a local OAuth issuer. |
218
+ | `TRUST_PROXY` | No | `false` | Trust `X-Forwarded-Host` and `X-Forwarded-Proto` when building OAuth metadata URLs. Enable only behind a reverse proxy that rewrites them. |
219
+
220
+ The three OAuth variables are a set: configure all three or none. Setting only some of them makes the server print `Incomplete OAuth configuration for HTTP mode` and exit `1`, rather than quietly start unauthenticated.
221
+
222
+ `SOCKET_API_TOKEN` is canonical. These aliases are read in order, first non-empty wins: `SOCKET_API_TOKEN`, `SOCKET_API_KEY`, `SOCKET_CLI_API_TOKEN`, `SOCKET_CLI_API_KEY`, `SOCKET_SECURITY_API_TOKEN`, `SOCKET_SECURITY_API_KEY`.
223
+
224
+ `SOCKET_API_TOKEN`, `SOCKET_API_BASE_URL`, and `SOCKET_DEBUG` also apply in stdio mode. Everything else in the table is HTTP-only.
225
+
226
+ <details>
227
+
228
+ <summary>Tuning the package-file blob cache and its fetches</summary>
229
+
230
+ `package_files`, `package_file_contents`, and `package_file_grep` fetch blobs from `socketusercontent.com` and hold them in a process-wide LRU cache. These knobs exist for operators running the server at volume; the defaults are fine otherwise.
187
231
 
188
- `SOCKET_API_URL` and `SOCKET_DEBUG` also apply in stdio mode.
232
+ | Variable | Default | Description |
233
+ | ---------------------------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------- |
234
+ | `SOCKET_BLOB_CACHE_BYTES` | `67108864` (64 MB) | Bytes the blob cache holds before evicting. A non-positive or unparseable value falls back to the default. |
235
+ | `SOCKET_BLOB_URL` | `https://socketusercontent.com` | Base URL blobs are fetched from. |
236
+ | `SOCKET_BROWSER_USER_AGENT` | A Chrome UA string | `User-Agent` sent on blob fetches. |
237
+ | `SOCKET_BYPASS_HEADER_NAME` | None | Name of an extra header sent on every blob fetch. Both name and value must be set for it to apply. |
238
+ | `SOCKET_BYPASS_HEADER_VALUE` | None | Value for that header. |
239
+ | `SOCKET_INTERNAL_USER_AGENT` | `socket-internal-tool/1.0` | `User-Agent` sent on the authenticated file-list call. |
189
240
 
190
- To enable OAuth-backed auth for incoming MCP requests:
241
+ </details>
242
+
243
+ **Enabling OAuth.** Set all three OAuth variables to require an OAuth access token on every MCP request:
191
244
 
192
245
  ```sh
193
246
  MCP_HTTP_MODE=true \
194
247
  SOCKET_OAUTH_ISSUER=https://issuer.example.com \
195
248
  SOCKET_OAUTH_INTROSPECTION_CLIENT_ID=your-client-id \
196
249
  SOCKET_OAUTH_INTROSPECTION_CLIENT_SECRET=your-client-secret \
197
- npx @socketsecurity/mcp@latest --http # socket-hook: allow npx
250
+ socket-mcp --http
198
251
  ```
199
252
 
253
+ With OAuth enabled, every request to the MCP endpoint goes through RFC 7662 token introspection. A raw Socket API token is rejected with a `401`, whatever its prefix; a `sktsec_` token is no more privileged than any other string here. Callers send an OAuth access token, and the server uses that token for the Socket API calls it makes on their behalf. Run without the OAuth variables to accept raw Socket API tokens instead.
254
+
255
+ At startup the server discovers the issuer's RFC 8414 metadata. An issuer that carries a path (`https://auth.example.com/tenant1`) is probed at the path-inserted well-known URL first (`https://auth.example.com/.well-known/oauth-authorization-server/tenant1`), and the metadata document's own `issuer` must match `SOCKET_OAUTH_ISSUER` byte for byte. The issuer must be `https` on a public host; a loopback or private-network issuer is refused outright unless `SOCKET_DEBUG=true` is set for local-stack work. The same rule applies to the `introspection_endpoint` the metadata advertises.
256
+
257
+ Clients discover how to authenticate from `GET /.well-known/oauth-protected-resource` (RFC 9728), which the server publishes once OAuth is on:
258
+
259
+ ```json
260
+ {
261
+ "resource": "https://mcp.example.com/",
262
+ "authorization_servers": ["https://issuer.example.com"],
263
+ "scopes_supported": ["packages:list"],
264
+ "bearer_methods_supported": ["header"],
265
+ "resource_name": "Socket MCP Server"
266
+ }
267
+ ```
268
+
269
+ A rejected request answers `401` with a `WWW-Authenticate` header naming that metadata URL and the scopes this resource requires:
270
+
271
+ ```text
272
+ WWW-Authenticate: Bearer error="invalid_token", error_description="Invalid or expired token",
273
+ resource_metadata="https://mcp.example.com/.well-known/oauth-protected-resource", scope="packages:list"
274
+ ```
275
+
276
+ > [!IMPORTANT]
277
+ > **Audience validation.** When an introspection response includes an `aud` claim, the server requires it to name this resource and rejects the token otherwise. That check is always on and has no opt-out. When the response includes no `aud` at all, the token is accepted by default, because an authorization server that never emits the claim would otherwise fail every request. Audience validation therefore protects you exactly as far as your authorization server populates `aud`; if it does not, no audience is being checked. Set `SOCKET_OAUTH_REQUIRE_AUDIENCE=true` to additionally require the claim's presence, but only once you have confirmed your authorization server returns `aud` on introspection. Enabling it against a server that omits the claim rejects all traffic.
278
+
200
279
  Add `TRUST_PROXY=true` only when the server is deployed behind a trusted reverse proxy or load balancer that normalizes the forwarded host and protocol headers.
201
280
 
202
281
  Configure your MCP client to connect to the HTTP server:
@@ -224,18 +303,21 @@ Once installed, ask your AI assistant questions like:
224
303
 
225
304
  ### Tools exposed
226
305
 
306
+ <details><summary>The full tool roster - names, arguments, and what each returns</summary>
307
+
227
308
  #### depscore
228
309
 
229
310
  Query the Socket API for dependency scoring information. Returns supply chain, quality, maintenance, vulnerability, and license scores per package.
230
311
 
231
- | Parameter | Type | Required | Default | Description |
232
- | ---------------------- | ------ | -------- | ----------- | -------------------------------------------------- |
233
- | `packages` | Array | ✅ Yes | - | Array of package objects to analyze |
234
- | `packages[].ecosystem` | String | No | `"npm"` | Package ecosystem. See Supported ecosystems below. |
235
- | `packages[].depname` | String | ✅ Yes | - | Name of the dependency/package |
236
- | `packages[].version` | String | No | `"unknown"` | Version of the dependency |
312
+ | Parameter | Type | Required | Default | Description |
313
+ | ---------------------- | ------ | -------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
314
+ | `packages` | Array | ✅ Yes | - | Array of package objects to analyze |
315
+ | `packages[].ecosystem` | String | No | `"npm"` | Package ecosystem. See Supported ecosystems below. |
316
+ | `packages[].depname` | String | ✅ Yes | - | Name of the dependency/package |
317
+ | `packages[].version` | String | No | `"unknown"` | Version of the dependency |
318
+ | `platform` | String | No | - | OS-architecture hint (`linux-x64`, `darwin-arm64`, `win32-x64`) applied to every package in the request. Picks the most relevant artifact when a package ships platform-specific builds. |
237
319
 
238
- **Supported ecosystems**
320
+ ##### Supported ecosystems
239
321
 
240
322
  Based on [Socket's language support](https://docs.socket.dev/docs/language-support). The `ecosystem` parameter maps to PURL types:
241
323
 
@@ -251,6 +333,8 @@ Based on [Socket's language support](https://docs.socket.dev/docs/language-suppo
251
333
  | PHP | `composer` | Composer | Experimental |
252
334
  | GitHub Actions | `actions` | GitHub Actions workflows | Experimental (workflow scanning, not package-level) |
253
335
 
336
+ `packagist` is accepted as an alias for `composer`, and `openvsx` for the `vscode` PURL type.
337
+
254
338
  Example request:
255
339
 
256
340
  ```json
@@ -262,21 +346,39 @@ Example request:
262
346
  }
263
347
  ```
264
348
 
265
- Sample response:
349
+ Response, as a single block of text. Every score is an integer from 0 to 100, higher is better:
266
350
 
267
- ```
268
- pkg:npm/express@4.18.2: supply_chain: 1.0, quality: 0.9, maintenance: 1.0, vulnerability: 1.0, license: 1.0
351
+ ```text
352
+ Dependency scores:
353
+ pkg:npm/express@4.18.2: license: 100, maintenance: 87, quality: 100, supplyChain: 97, vulnerability: 98
269
354
  Report: https://socket.dev/npm/package/express
270
- pkg:pypi/fastapi@0.100.0: supply_chain: 1.0, quality: 0.95, maintenance: 0.98, vulnerability: 1.0, license: 1.0
355
+ pkg:pypi/fastapi@0.100.0: license: 100, maintenance: 100, quality: 100, supplyChain: 100, vulnerability: 100
271
356
  Report: https://socket.dev/pypi/package/fastapi
272
357
  ```
273
358
 
359
+ Packages come back in the order the API returns them, not the order you asked for. A package Socket has no record of is left out of the list rather than reported as an error, so compare the response against your request when a name is missing.
360
+
274
361
  #### organizations
275
362
 
276
363
  List the Socket organizations the authenticated user belongs to. Takes no parameters. Use it to discover the `org_slug` value that the org-scoped tools (`alerts`, `threat_feed`) require.
277
364
 
278
365
  This tool needs a Socket API token. See [Authentication for organization-scoped tools](#authentication-for-organization-scoped-tools) below.
279
366
 
367
+ The response is the Socket API's JSON, keyed by organization id. The `slug` is what the other tools want:
368
+
369
+ ```json
370
+ {
371
+ "organizations": {
372
+ "1234": {
373
+ "id": "1234",
374
+ "name": "Acme Robotics",
375
+ "plan": "enterprise",
376
+ "slug": "acme-robotics"
377
+ }
378
+ }
379
+ }
380
+ ```
381
+
280
382
  #### alerts
281
383
 
282
384
  List the latest security alerts for one Socket organization: supply-chain, vulnerability, quality, license, and maintenance issues across the org's monitored packages. Backed by `GET /v0/orgs/{org_slug}/alerts`. Results are paginated; pass the previous response's `endCursor` as `cursor` to fetch the next page.
@@ -292,30 +394,30 @@ List the latest security alerts for one Socket organization: supply-chain, vulne
292
394
  | `alert_type` | String | No | - | Comma-separated Socket alert types (e.g. `usesEval,unmaintained`) |
293
395
  | `repo_slug` | String | No | - | Comma-separated repository slugs |
294
396
  | `per_page` | Integer | No | `100` | Results per page (1–5000) |
295
- | `cursor` | String | No | - | Pagination cursor — the `endCursor` from a previous response |
397
+ | `cursor` | String | No | - | Pagination cursor - the `endCursor` from a previous response |
296
398
 
297
399
  #### threat_feed
298
400
 
299
401
  Look up items in a Socket organization's threat feed: packages recently flagged as malware, typosquats, obfuscated code, and similar. Backed by `GET /v0/orgs/{org_slug}/threat-feed`. The response carries a `nextPageCursor`; pass it as `cursor` to page forward.
300
402
 
301
- | Parameter | Type | Required | Default | Description |
302
- | ------------------- | ------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------- |
303
- | `org_slug` | String | ✅ Yes | - | Organization slug (get it from the `organizations` tool) |
304
- | `filter` | String | No | `mal` | Threat category: `mal` (malware), `vuln`, `typ` (typosquat), `obf` (obfuscated), `mjo`, `kes`, `spy`, etc. |
305
- | `ecosystem` | String | No | - | Ecosystem: `npm`, `pypi`, `gem`, `maven`, `golang`, `nuget`, `cargo`, `chrome`, `openvsx`, `huggingface` |
306
- | `name` | String | No | - | Filter by package name |
307
- | `version` | String | No | - | Filter by package version |
308
- | `is_human_reviewed` | Boolean | No | `false` | Only return human-reviewed items |
309
- | `sort` | String | No | `updated_at` | Sort field: `id`, `created_at`, `updated_at` |
310
- | `direction` | String | No | `desc` | Sort direction: `asc`, `desc` |
311
- | `updated_after` | String | No | - | ISO timestamp; only items updated after this |
312
- | `created_after` | String | No | - | ISO timestamp; only items created after this |
313
- | `per_page` | Integer | No | `30` | Results per page (1–100) |
314
- | `cursor` | String | No | - | Pagination cursor — the `nextPageCursor` from a previous response |
403
+ | Parameter | Type | Required | Default | Description |
404
+ | ------------------- | ------- | -------- | ------------ | ------------------------------------------------------------------------------------------------------------------ |
405
+ | `org_slug` | String | ✅ Yes | - | Organization slug (get it from the `organizations` tool) |
406
+ | `filter` | String | No | `mal` | Threat category: `mal` (malware), `vuln`, `typ` (typosquat), `obf` (obfuscated), `mjo`, `kes`, `spy`, etc. |
407
+ | `ecosystem` | String | No | - | Ecosystem: `npm`, `pypi`, `gem`, `maven`, `golang`, `nuget`, `cargo`, `chrome`, `openvsx`, `vscode`, `huggingface` |
408
+ | `name` | String | No | - | Filter by package name |
409
+ | `version` | String | No | - | Filter by package version |
410
+ | `is_human_reviewed` | Boolean | No | `false` | Only return human-reviewed items |
411
+ | `sort` | String | No | `updated_at` | Sort field: `id`, `created_at`, `updated_at` |
412
+ | `direction` | String | No | `desc` | Sort direction: `asc`, `desc` |
413
+ | `updated_after` | String | No | - | ISO timestamp; only items updated after this |
414
+ | `created_after` | String | No | - | ISO timestamp; only items created after this |
415
+ | `per_page` | Integer | No | `30` | Results per page (1–100) |
416
+ | `cursor` | String | No | - | Pagination cursor - the `nextPageCursor` from a previous response |
315
417
 
316
418
  #### package_files
317
419
 
318
- List the files published in a package: a tree of paths and sizes for any package on a supported ecosystem. Use it to inspect what a dependency ships before installing it. Each entry prints a blob `hash` that `package_file_contents` and `package_file_grep` consume.
420
+ List the files published in a package: a tree of file paths, each with its size and blob hash, for any package on a supported ecosystem. Use it to inspect what a dependency ships before installing it. Pass a file's `hash` to `package_file_contents` or `package_file_grep`.
319
421
 
320
422
  | Parameter | Type | Required | Default | Description |
321
423
  | ------------ | ------ | -------- | ------- | --------------------------------------------------------------------------------------- |
@@ -325,6 +427,16 @@ List the files published in a package: a tree of paths and sizes for any package
325
427
  | `artifactId` | String | No | - | Per-version disambiguator (PyPI filename, Maven artifact id, NuGet asset) |
326
428
  | `platform` | String | No | - | Platform qualifier for per-OS/arch artifacts (e.g. openvsx `linux-x64`, `darwin-arm64`) |
327
429
 
430
+ Output is a header line and a tree. The token after each size is the blob `hash`:
431
+
432
+ ```text
433
+ pkg:npm/lodash@4.17.21 — 1054 files, 1379.3 KB
434
+ └── package/
435
+ ├── fp/
436
+ │ ├── __.js 43B QlKUJ6782LHNEISw-t4uX1hyH1TCZye4ShYOMIAghheg
437
+ │ ├── _baseConvert.js 16.0K QpGkoQltpQn5ZeTFxYQOnk8FWp-7yyeUQtyzdZXl48nA
438
+ ```
439
+
328
440
  #### package_file_contents
329
441
 
330
442
  Read a single file from a package. Pass the `hash` printed next to an entry in `package_files` output. Returns up to 1 MB of UTF-8 text; binary files return metadata only.
@@ -336,7 +448,7 @@ Read a single file from a package. Pass the `hash` printed next to an entry in `
336
448
 
337
449
  #### package_file_grep
338
450
 
339
- Search a single file from a package for lines matching a JavaScript regular expression, returning matches with line numbers (grep -n style). The file is fetched once per session and cached, so repeated greps on the same hash skip the network.
451
+ Search a single file from a package for lines matching a JavaScript regular expression, returning matches with line numbers (grep -n style). Each blob is fetched once and held in a process-wide cache, so repeated reads and greps of the same hash skip the network.
340
452
 
341
453
  | Parameter | Type | Required | Default | Description |
342
454
  | ----------------- | ------- | -------- | ------- | ------------------------------------------------------- |
@@ -347,6 +459,8 @@ Search a single file from a package for lines matching a JavaScript regular expr
347
459
  | `maxMatches` | Integer | No | `100` | Cap on matching lines returned (1–500) |
348
460
  | `path` | String | No | - | File path, for display only; does not affect the lookup |
349
461
 
462
+ </details>
463
+
350
464
  ### Authentication for organization-scoped tools
351
465
 
352
466
  `depscore` works without credentials on the public server. The `organizations`, `alerts`, `threat_feed`, and `package_files` tools call Socket's authenticated REST API, so they need a Socket API token.
@@ -354,7 +468,14 @@ Search a single file from a package for lines matching a JavaScript regular expr
354
468
  How the server resolves a token depends on the transport:
355
469
 
356
470
  - **stdio mode** reads one token at startup from the environment and uses it for every request. Set `SOCKET_API_TOKEN`. The server also accepts these aliases, in priority order: `SOCKET_API_TOKEN` → `SOCKET_API_KEY` → `SOCKET_CLI_API_TOKEN` → `SOCKET_CLI_API_KEY` → `SOCKET_SECURITY_API_TOKEN` → `SOCKET_SECURITY_API_KEY`. `SOCKET_API_TOKEN` is canonical; `SOCKET_API_KEY` is the alias most local setups already export. Because the process belongs to one user, this token is yours and scopes every tool to your account.
357
- - **HTTP mode** scopes the organization tools to the caller, never to the server's own token. Send your credential as an `Authorization: Bearer <token>` header on each request: a raw Socket API token (recognized by its `sktsec_` prefix) is used directly and works whether or not the server runs OAuth, while any other token is treated as an OAuth access token and validated through introspection when the server runs OAuth. The server uses that per-request token for the Socket API calls it makes on your behalf. A shared deployment never answers `organizations`, `alerts`, `threat_feed`, or `package_files` with the operator's data: when a request carries no token, those tools return the auth-required error. `depscore` alone may fall back to the server's startup token, since package scores are the same for every caller.
471
+ - **HTTP mode** scopes the organization tools to the caller, never to the server's own token. Send your credential as an `Authorization: Bearer <token>` header on each request. Which credential to send depends on whether the deployment runs OAuth. On an OAuth-enabled server, send an OAuth access token: every bearer token is validated through introspection, and a raw Socket API token is rejected with a `401` challenge no matter what it starts with. On a server without OAuth, send your raw Socket API token and it is used directly. Either way the server uses that per-request token for the Socket API calls it makes on your behalf. A shared deployment never answers `organizations`, `alerts`, `threat_feed`, or `package_files` with the operator's data: when a request carries no token, those tools return the auth-required error. `depscore` alone may fall back to the server's startup token, since package scores are the same for every caller.
472
+
473
+ When a token is missing, every affected tool returns the same message:
474
+
475
+ ```text
476
+ Authentication is required. Set SOCKET_API_TOKEN for stdio mode, or send your Socket API
477
+ token as an `Authorization: Bearer <token>` header (or connect through OAuth) in HTTP mode.
478
+ ```
358
479
 
359
480
  Generate a token from the [Socket dashboard](https://socket.dev/) under API tokens, then export it before launching the server:
360
481
 
@@ -362,25 +483,23 @@ Generate a token from the [Socket dashboard](https://socket.dev/) under API toke
362
483
  export SOCKET_API_TOKEN="your-socket-api-token"
363
484
  ```
364
485
 
365
- When no token is available, these tools return an authentication-required error explaining how to supply one for each transport.
366
-
367
486
  ### Worked example: organization details and alerts
368
487
 
369
488
  With `SOCKET_API_TOKEN` set, ask your assistant something like "show me the open critical alerts for my Socket org". Under the hood the assistant chains two tools:
370
489
 
371
- 1. **Discover the org slug.** Call `organizations` (no arguments). The server reads your token, calls `GET /v0/organizations`, and returns the organizations your token can see. Pick the `slug` you want, e.g. `my-org`.
490
+ 1. **Discover the org slug.** Call `organizations` (no arguments). The server reads your token, calls `GET /v0/organizations`, and returns the organizations your token can see. Pick the `slug` you want, e.g. `acme-robotics`.
372
491
 
373
492
  2. **Fetch alerts for that org.** Call `alerts` with the slug and any filters:
374
493
 
375
494
  ```json
376
495
  {
377
- "org_slug": "my-org",
496
+ "org_slug": "acme-robotics",
378
497
  "severity": "high,critical",
379
498
  "status": "open"
380
499
  }
381
500
  ```
382
501
 
383
- The server calls `GET /v0/orgs/my-org/alerts` with the same token and returns the matching alerts plus pagination metadata. To page forward, pass the response's `endCursor` back as `cursor`.
502
+ The server calls `GET /v0/orgs/acme-robotics/alerts` with the same token and returns the matching alerts plus pagination metadata. To page forward, pass the response's `endCursor` back as `cursor`.
384
503
 
385
504
  The same token scopes every org-scoped tool, so `threat_feed` and `package_files` work the moment `organizations` confirms which slug the token belongs to.
386
505
 
@@ -402,7 +521,7 @@ Always check dependency scores with the depscore tool when you add a new depende
402
521
 
403
522
  ## Claude Code Hook (Optional)
404
523
 
405
- The repo ships an optional [Claude Code hook](https://code.claude.com/docs/en/hooks) that blocks high-risk packages before installation. When Claude Code runs an install command, the hook queries the public Socket MCP server at `https://mcp.socket.dev/` and denies the install when the package's supply chain score is below `20` (known malware, typosquats, high-risk supply chain signals). No CLI to install — copy the file and wire it up; the public server signs in via OAuth on first use.
524
+ The repo ships an optional [Claude Code hook](https://code.claude.com/docs/en/hooks) that blocks high-risk packages before installation. When Claude Code runs an install command, the hook queries the public Socket MCP server at `https://mcp.socket.dev/` and denies the install when the package's supply chain score is below `20` (known malware, typosquats, high-risk supply chain signals). No CLI to install - copy the file and wire it up; the public server signs in via OAuth on first use.
406
525
 
407
526
  Supported ecosystems and package managers:
408
527
 
@@ -417,17 +536,28 @@ Supported ecosystems and package managers:
417
536
 
418
537
  ### Setup
419
538
 
420
- **Prerequisites:** Node.js 22+.
539
+ <details><summary>Per-client setup steps - Claude Desktop, Claude Code, Cursor, and VS Code</summary>
421
540
 
422
- 1. Copy the whole `socket-gate` directory into your hooks folder. The bundled
423
- `socket-gate.cjs` is self-contained, so it runs without any dependencies
424
- beside it. From a checkout, run `pnpm run build` first to produce it; from a
425
- published install, copy from `node_modules/@socketsecurity/mcp/`:
541
+ **Prerequisites:** Node.js 24+.
426
542
 
427
- ```bash
428
- mkdir -p ~/.claude/hooks
429
- cp -R hooks/socket-gate ~/.claude/hooks/
430
- ```
543
+ 1. Copy the whole `dist/socket-gate` directory into your hooks folder. The
544
+ bundled `socket-gate.cjs` is self-contained, so it runs without any
545
+ dependencies beside it.
546
+
547
+ From a published install:
548
+
549
+ ```bash
550
+ mkdir -p ~/.claude/hooks
551
+ cp -R node_modules/@socketsecurity/mcp/dist/socket-gate ~/.claude/hooks/
552
+ ```
553
+
554
+ From a checkout, build it first:
555
+
556
+ ```bash
557
+ pnpm run build
558
+ mkdir -p ~/.claude/hooks
559
+ cp -R dist/socket-gate ~/.claude/hooks/
560
+ ```
431
561
 
432
562
  2. Add to `~/.claude/settings.json`:
433
563
 
@@ -452,9 +582,11 @@ cp -R hooks/socket-gate ~/.claude/hooks/
452
582
  See [`hooks/socket-gate/README.md`](hooks/socket-gate/README.md) for the full
453
583
  reference.
454
584
 
585
+ </details>
586
+
455
587
  ### How it works
456
588
 
457
- The hook denies installation when `supplyChain < 20`, allows it otherwise — e.g. `express`/`lodash`/`react` (75–97) allow, `browserlist` (typosquat of `browserslist`, 15) and confirmed malware (0) block. Network, timeout, or parse errors all fail open, so a Socket outage will not block legitimate work.
589
+ The hook denies installation when `supplyChain < 20`, allows it otherwise - e.g. `express`/`lodash`/`react` (75–97) allow, `browserlist` (typosquat of `browserslist`, 15) and confirmed malware (0) block. Network, timeout, or parse errors all fail open, so a Socket outage will not block legitimate work.
458
590
 
459
591
  ### Limitations
460
592
 
@@ -471,36 +603,53 @@ Inspired by [Jimmy Vo's dependency hook](https://blog.jimmyvo.com/posts/claudes-
471
603
  <details>
472
604
  <summary>Contributor commands</summary>
473
605
 
606
+ This repo uses pnpm, and every command runs from the repo root. Node.js 24+ is required.
607
+
474
608
  ```sh
475
609
  git clone https://github.com/SocketDev/socket-mcp.git
476
610
  cd socket-mcp
477
- npm install
478
- npm run build
611
+ pnpm install
479
612
  ```
480
613
 
481
- Run from source (stdio mode):
614
+ Run from source. No build step is needed, because Node 24 strips the TypeScript itself:
482
615
 
483
616
  ```sh
484
617
  export SOCKET_API_TOKEN=your_api_token_here
485
- node --experimental-strip-types index.ts
618
+ pnpm run server-stdio
486
619
  ```
487
620
 
488
621
  Or in HTTP mode:
489
622
 
490
623
  ```sh
491
- MCP_HTTP_MODE=true SOCKET_API_TOKEN=your_api_token_here node --experimental-strip-types index.ts --http
624
+ pnpm run server-http
492
625
  ```
493
626
 
627
+ Both scripts read `SOCKET_API_TOKEN` (falling back to `SOCKET_API_KEY`) from your environment. Append `:debug` to either one (`pnpm run server-http:debug`) to set `SOCKET_DEBUG=1` and get per-request tracing on stderr.
628
+
629
+ | Task | Command |
630
+ | ------------------------- | ----------------------------------- |
631
+ | Test | `pnpm test` |
632
+ | Test one file | `pnpm test test/unit/purl.test.mts` |
633
+ | Live-API end-to-end tests | `pnpm run test:e2e` |
634
+ | Type check | `pnpm run type` |
635
+ | Lint and format | `pnpm run fix --all` |
636
+ | Full check suite | `pnpm run check --all` |
637
+ | Bundle to `dist/` | `pnpm run build` |
638
+
639
+ Never put `--` before a test path; that widens the run to the whole suite. Write `pnpm test test/unit/purl.test.mts`.
640
+
641
+ To drive a running server by hand, see [mock-client debugging](docs/mock-client-debugging.md).
642
+
494
643
  ### Health check endpoint
495
644
 
496
- When running in HTTP mode, `GET /health` returns:
645
+ When running in HTTP mode, `GET /health` returns the running server's version and skips origin validation, which makes it safe to call from a probe that sends no `Origin` header:
497
646
 
498
647
  ```json
499
648
  {
500
649
  "status": "healthy",
501
650
  "service": "socket-mcp",
502
- "version": "0.0.18",
503
- "timestamp": "2025-06-17T20:45:22.059Z"
651
+ "version": "0.0.20",
652
+ "timestamp": "2026-07-29T01:50:30.394Z"
504
653
  }
505
654
  ```
506
655
 
@@ -508,13 +657,17 @@ Suitable for Kubernetes liveness/readiness probes, Docker health checks, load ba
508
657
 
509
658
  ### Troubleshooting
510
659
 
511
- **Q: The public server isn't responding** — Check the URL `https://mcp.socket.dev/`, verify your MCP client configuration, restart your MCP client.
660
+ **Q: The public server isn't responding** - Check the URL `https://mcp.socket.dev/`, verify your MCP client configuration, restart your MCP client.
661
+
662
+ **Q: Getting a `403 Forbidden: Invalid origin` error, or the connector never opens an OAuth screen** - The server accepts client `Origin` headers when the request's `Host` matches the hosted deployment. Confirm that your client uses `https://mcp.socket.dev/` and follows its setup steps above. A persistent `Invalid origin` response requires checking that the hosted deployment includes the fix.
663
+
664
+ **Q: Local server fails to start** - Ensure Node.js 24+ is installed, check `SOCKET_API_TOKEN` is set, verify the API token has `packages:list` permission. In stdio mode a missing token is fatal: the server prints `SOCKET_API_TOKEN environment variable is required in stdio mode` and exits `1`.
512
665
 
513
- **Q: Local server fails to start** — Ensure Node.js 22+ is installed, check `SOCKET_API_TOKEN` is set, verify the API token has `packages:list` permission.
666
+ **Q: The server exits with `Incomplete OAuth configuration for HTTP mode`** - `SOCKET_OAUTH_ISSUER`, `SOCKET_OAUTH_INTROSPECTION_CLIENT_ID`, and `SOCKET_OAUTH_INTROSPECTION_CLIENT_SECRET` must all be set or all be unset.
514
667
 
515
- **Q: Getting authentication errors with local server** — Double-check your API key is valid, ensure `packages:list` scope, regenerate if needed.
668
+ **Q: Getting authentication errors with local server** - Double-check your API key is valid, ensure `packages:list` scope, regenerate if needed. If the tool that failed was `organizations`, `alerts`, `threat_feed`, or `package_files` on an HTTP deployment, the server is refusing to answer with the operator's token by design; send your own in an `Authorization: Bearer` header.
516
669
 
517
- **Q: AI assistant can't find the depscore tool** — Restart your MCP client after configuration changes, verify config is saved, check the server is running.
670
+ **Q: AI assistant can't find the depscore tool** - Restart your MCP client after configuration changes, verify config is saved, check the server is running. `tools/list` advertises a one-hour public cache, so a client that caches the tool list may need a restart to pick up a newly added tool.
518
671
 
519
672
  ### Getting help
520
673
 
@@ -528,11 +681,10 @@ Suitable for Kubernetes liveness/readiness probes, Docker health checks, load ba
528
681
 
529
682
  MIT
530
683
 
531
- <br/>
532
684
  <div align="center">
533
685
  <picture>
534
- <source media="(prefers-color-scheme: dark)" srcset="logo-white.png">
535
- <source media="(prefers-color-scheme: light)" srcset="logo-black.png">
536
- <img width="324" height="108" alt="Socket Logo" src="logo-black.png">
686
+ <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/SocketDev/socket-mcp/v0.2.1/assets/fleet/socket-combomark-dark.svg">
687
+ <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/SocketDev/socket-mcp/v0.2.1/assets/fleet/socket-combomark-light.svg">
688
+ <img width="320" height="91" alt="Socket" src="https://raw.githubusercontent.com/SocketDev/socket-mcp/v0.2.1/assets/fleet/socket-combomark-light.svg">
537
689
  </picture>
538
690
  </div>