> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentx.wft/llms.txt
> Use this file to discover all available pages before exploring further.

# agentx scan

> See every agent configuration with the skills, MCP servers and plugins each one has.

`agentx scan` reads your agent clients' directories, their MCP configuration files and the library and prints what it finds. It writes nothing and never starts a server unless you ask for a handshake.

## Scan the machine

```sh theme={null}
agentx scan
```

```text theme={null}
3 configurations, 4 skills, 2 servers, 4 plugins detected

Claude Code (claude-code)  /home/me/.claude  enabled  3 skills, 1 plugin
  skills:
    commit  symlink    user  /home/me/.claude/skills/commit -> /home/me/.agents/skills/commit
    format  directory  user  /home/me/.claude/plugins/cache/acme-tools/formatter/1.2.0/skills/format  (plugin formatter)
    review  directory  user  /home/me/.claude/skills/review
  plugins:
    formatter  1.2.0  1 skill

Codex (codex)  /home/me/.codex  enabled  2 skills, 2 plugins
  skills:
    commit  directory  user  /home/me/.agents/skills/commit
    sales   directory  user  /home/me/.codex/plugins/cache/acme-tools/sales/1.0.8/skills/sales  (plugin sales)
  plugins:
    notes  local  (disabled)
    sales  1.0.8  1 skill

Cursor (cursor)  /home/me/.cursor  enabled  2 skills, 2 servers, 1 plugin
  skills:
    commit  symlink    user  /home/me/.claude/skills/commit -> /home/me/.agents/skills/commit
    review  directory  user  /home/me/.claude/skills/review
  servers:
    context7  stdio            npx -y @upstash/context7-mcp
    stripe    streamable-http  https://mcp.stripe.com
  plugins:
    thermos  9f86d081884c7d659a2feaa0c55ad015a3bf4f1b
```

The first line counts the machine: configurations, skills, servers and plugins, each once however many configurations share it. Then one section per agent configuration, headed by the client name, its id, its configuration directory, whether it is enabled and how many skills, servers and plugins it has. A `skills:` block lists every skill the configuration can see, one per line: the skill name, the kind of placement, the scope and the path the client reads. A skill that comes from a plugin ends with the plugin's name.

Then, when the configuration declares MCP servers, a `servers:` block with one line per server: its name, its transport (`stdio`, `sse` or `streamable-http`) and its command line or URL. Then, when the configuration has plugins, a `plugins:` block with one line per plugin: its name, its version, how many skills and servers the plugin provides in this configuration, and `(disabled)` when the client has turned it off.

In a terminal the names are bold, the block labels cyan, the kind and scope dim, `enabled` green, `(disabled)` yellow and a plugin marker magenta, so the names and states stand out from the paths.

A skill's name and a server's command line come from files agentx did not write, so they are printed with control characters replaced by spaces, and a path holding one is printed in quotes with escapes. See [Output and exit codes](/cli/output). Read the values as they are on disk with `--json`.

A configuration is detected when its configuration directory exists, such as `~/.claude` for Claude Code or `~/.cursor` for Cursor.

## Read the kind

| Kind | Meaning |
| - | - |
| `symlink` | The path is a symlink. The arrow shows where it resolves to. A skill symlinked into several clients is one skill with one source of truth. |
| `copy` | The path is a real directory that agentx placed as a copy for this configuration. |
| `directory` | The path is a real directory. |

## See who reads what

A client can read other clients' directories. Cursor reads `~/.claude/skills` and `~/.codex/skills` next to its own `~/.cursor/skills`, so a skill you put in the Claude Code directory appears under Cursor too. Some clients, such as Codex and Gemini CLI, read the library at `~/.agents/skills` directly, so every library skill appears under them without any link in their own directories.

## Read the servers

agentx reads the user-scope MCP configuration of Claude Code (`~/.claude.json`), Codex (`~/.codex/config.toml`), Cursor (`~/.cursor/mcp.json`), Gemini CLI (`~/.gemini/settings.json`), Windsurf (`~/.codeium/windsurf/mcp_config.json`) and GitHub Copilot (`~/.copilot/mcp-config.json`). Other clients contribute skills only.

The inventory shows the command and arguments of a local server and the URL of a remote one. It never shows the values of environment variables or headers, in any output mode: a scan does not print your secrets. In JSON output only their names appear, as `env_keys` and `header_keys`.

The same server declared in two clients is one server with two occurrences: agentx recognises a remote server by its address and a local `npx`, `uvx`, `pipx` or `docker` server by its package or image, whatever the version. A server that cannot be identified that way is unique to this machine.

A configuration file that cannot be parsed is reported as a warning and the scan continues.

## Handshake the servers

```sh theme={null}
agentx scan --handshake
```

```text theme={null}
  servers:
    context7  stdio            npx -y @upstash/context7-mcp  12 tools
    stripe    streamable-http  https://mcp.stripe.com        9 tools
```

Starts or connects to every MCP server and records the tools, prompts and resources it exposes. Each server gets ten seconds. agentx runs each server the way the client that declares it does:

* A local server starts in its declared `cwd`, with the environment variables its declaration sets. A relative `cwd` resolves against the plugin's directory for a plugin's server, else against the directory you run agentx in.
* Placeholders such as `${API_KEY}` are filled in from your environment, in the syntax of the client that declares the server: `${VAR}` for Claude Code, `${env:VAR}` for Cursor and Windsurf, `$VAR` or `${VAR}` for Gemini CLI and Copilot CLI. The inventory shows the declaration as written. Credentials Claude Code never sends to a remote server, such as `AWS_SECRET_ACCESS_KEY`, agentx doesn't send either, nor any `ANTHROPIC_*` or `CLAUDE_*` variable. Run with `--verbose` to see which variables were withheld.
* A remote server receives its declared headers at its declared URL. agentx never tries another URL. For Codex, `env_http_headers` and `bearer_token_env_var` are read from your environment.
* A server on the legacy `sse` transport is handshaken over SSE. A streamable HTTP server that refuses the opening request with 400, 404 or 405, and no MCP error, is tried once more over SSE at the same URL.
* A server you turned off in its client, shown with `(disabled)`, is never started. agentx reads this from Codex (`enabled = false`), Gemini CLI (`mcp.excluded`, `mcp.allowed` and `gemini mcp disable`) and Copilot CLI (`/mcp disable`). Claude Code, Cursor and Windsurf keep it outside the files agentx reads.

No environment value or header is ever printed.

What a server exposed becomes its signature. Two servers with the same command or address but different tools get different signatures, so the inventory tells them apart; the same server declared in two clients with the same tools stays one server. In JSON output the node carries the `signature`, when it was taken as `signature_at`, and the `tools` list.

The signatures are kept in `handshakes.json` in agentx home. A later scan without `--handshake` shows them until the next handshake replaces them; each occurrence's `handshake` field says whether that scan handshook the server itself.

### Fix a failed handshake

A server that fails its handshake shows no tool count. Its row says why, a warning names its file, and a hint says what to do. The server keeps its previous signature and the scan still succeeds.

```text theme={null}
  servers:
    notion   streamable-http  https://mcp.notion.com/mcp  needs sign-in
    browser  streamable-http  http://127.0.0.1:9010/mcp   unreachable
```

| Row says | What to do |
| - | - |
| `needs sign-in` | The server answered 401 or 403. agentx sends only the headers the declaration sets. It cannot use the sign-in your agent client holds, so a server you sign in to through the browser always lands here. Declare a header with an API key to list its tools, or renew the key if one is declared. For Codex's `bearer_token_env_var`, set that variable in the shell you run agentx from. |
| `unreachable` | Start the server, or check the URL and your proxy settings. |
| `command not found` | Check the command in the declaration. A bare name is looked up on your `PATH`. A relative path resolves against the declared `cwd`, else against the directory you run agentx in. |
| `timed out` | Raise the budget, for example `AGENTX_HANDSHAKE_TIMEOUT=30s agentx scan --handshake`. |
| `handshake failed` | The server exited or answered badly. Run its command or request its URL by hand. |

In JSON output the occurrence carries `handshake_error` with `reason`, `message` and `hint`.

## Read the plugins

Plugins are listed under the configuration they are installed in, with their version. The skills and MCP servers a plugin provides appear in the configuration's list like any other, marked with the plugin's name. A skill that is installed both standalone and through a plugin is one skill with two placements.

| Client | What agentx reads |
| - | - |
| Claude Code | The install records in `~/.claude/plugins/installed_plugins.json` and each plugin's directory. |
| Codex | The `[plugins."<name>@<marketplace>"]` tables in `~/.codex/config.toml` and the plugin copies under `~/.codex/plugins/cache`. A plugin with `enabled = false` is listed with `(disabled)`, and so is a server the plugin's table turns off with `[plugins."<name>@<marketplace>".mcp_servers.<server>]` and `enabled = false`. A plugin that has a copy but no table, such as one installed through your account, is listed without an enabled state. |
| Cursor | Your local plugins under `~/.cursor/plugins/local` and the marketplace plugins Cursor has cached under `~/.cursor/plugins/cache`. Cursor keeps the list of enabled plugins in your account, not on disk, so a cached plugin is installed but not necessarily enabled. A cached copy that Cursor did not finish writing is reported as a warning naming its directory and is not listed. A plugin's skills and MCP servers are read from where its manifest points, with or without a leading `./`, else from `skills` and `mcp.json`. A manifest path that leaves the plugin is reported as a warning and skipped. The Claude Code plugins Cursor also loads are listed under Claude Code only. |
| Gemini CLI | The extensions under `~/.gemini/extensions`. |

A plugin's version is what its manifest or install record says. For a Codex or Cursor plugin without one, the cache directory name stands in: `local`, a commit id or a release tag. A plugin manifest that cannot be read is reported as a warning naming the file, and the plugin is still listed by its directory name.

## Include a project

```sh theme={null}
agentx scan --project ~/code/my-app
```

Adds the skills found in the project's own skills directories, such as `.claude/skills`, `.cursor/skills` and `.agents/skills`, with scope `project`. The project is only read. Without the flag, only user scope is scanned.

## Rescan after a change

```sh theme={null}
agentx scan --configuration cursor
```

Names the configuration that changed. The whole machine is scanned either way, so the output is always complete. An id that is not detected exits with code 5 and lists the detected ids.

## Warnings

The `---` block at the top of a `SKILL.md` is read as YAML, so `name` and `description` are picked up however they are written: on one line, quoted, as a `|` or `>-` block, or continued on the indented lines under the key. A `metadata:` block or any other nested key is ignored.

A frontmatter block far larger or more deeply nested than any real skill is refused unread, so a repository cannot make a scan run out of memory.

A broken symlink, a `SKILL.md` whose block is not valid YAML or a symlink that points outside its skill does not stop the scan. Each one is reported on stderr as `warning: ...` and the skill is skipped or named after its directory. Several broken symlinks in one skills directory are reported as one warning that names the directory and lists the links:

```
warning: /home/me/.qwen/skills: 3 broken symlinks (audit, polish, shape), skipped
```

Delete the listed links to clear the warning.

## Script it

Add `--json` to get one `snapshot` event with the machine, every configuration, every skill, MCP server and plugin with its occurrences, the edges between them and the warnings. It also lists the skills of your library under `library`, each as [`agentx skill list`](/cli/skill) reports it: what agentx knows it as, where it came from, whether it was edited since, whether a client's placement was replaced or is missing (`displaced`, `missing`), whether its source is still added (`source removed` when it is not), whether its source still holds it (`upstream removed` when the last update check found it gone), the newer version the last update check found (`candidate`), whether an update left a merge of your edits pending (`pending_merge`), its placements and the universal clients that see it whatever its placements.

```sh theme={null}
agentx --json scan
```

If agentx cannot read its account repo, the scan still lists everything else, but `library` is empty and a warning names the repo and gives git's error. Read that error, run `agentx doctor`, and check the account repo the warning names: doctor does not catch every way a repo can break.

Every node carries a stable identity, and two scans of an unchanged machine are byte-identical apart from `instance_id`. Set `AGENTX_INSTANCE_ID` to fix that too.


## Related topics

- [agentx serve](/cli/serve.md)
- [agentx doctor](/cli/doctor.md)
- [agentx config](/cli/config.md)
- [agentx](/index.md)
