Skip to main content
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

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. 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

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

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.
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. 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

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

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:
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 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.
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.