agentafk
Guides

MCP Servers & Plugins

Configure MCP servers with layered mcp.json, use mcp__<server>__<tool> naming, and manage plugins with afk plugin.

Agent AFK supports MCP for connecting external tools and data sources. Plugins add skills, commands, and agents.

MCP servers

Configuration layers

MCP server configuration is loaded from four sources, merged in priority order (highest wins per server name):

PrioritySourceNotes
4 (highest)--mcp-config <path> flagPer-run override
3<cwd>/.mcp.jsonProject-local config — not loaded by default (opt-in); set AFK_ALLOW_PROJECT_MCP=1 to load
2~/.afk/config/mcp.jsonUser-global config
1 (lowest)Plugin-contributed <plugin>/.claude-plugin/mcp.jsonPer-plugin servers

Source: docs/architecture.md (MCP client section).

If two config files define a server with the same name, the higher-priority one wins. The other is logged as a warning — nothing is silently dropped.

Project-local .mcp.json is not loaded by default — it is opt-in. A project-local config can spawn arbitrary commands on session start, so entering an untrusted repository must never auto-spawn its servers. When a .mcp.json is present but the opt-in is absent, AFK skips it and prints a warning listing the skipped server names, their commands, and the exact opt-in instruction. Set AFK_ALLOW_PROJECT_MCP=1 (or true/yes/on) to load this layer for a directory you trust. A .mcp.json whose real path resolves outside the working directory (via a symlink or ..) is refused outright.

mcp.json schema

The schema matches Claude Code's mcpServers block for portability.

Field reference

Source: src/agent/mcp/types.ts (McpServerConfig).

FieldTypeDescription
type"stdio" | "streamable-http" | "sse"Transport to use. Inferred when omitted: command present → stdio; url present → streamable-http. Set explicitly to override.
commandstringExecutable to spawn. Required for stdio servers.
argsstring[]Arguments passed to the executable.
envobjectEnvironment variables for the spawned process. Values may contain ${VAR} placeholders expanded from the host environment at connect time (never via shell eval). Unset variables are passed as the empty string and logged as a warning.
urlstringEndpoint URL. Required for streamable-http and sse servers.
headersobjectExtra HTTP headers sent with every request. Values support the same ${VAR} expansion as env — use for static bearer tokens: { "Authorization": "Bearer ${TOKEN}" }.
oauthbooleanWhen true, runs the SDK's OAuth consent flow against the endpoint. The authorization URL is surfaced in the REPL or pushed via Telegram when running headless. Tokens are persisted in the macOS keychain. Run /mcp auth in the REPL to surface any pending consent URLs.
disabledbooleanSkip this server entirely without removing its config block.
alwaysLoadbooleanWhen true, a connect failure aborts session startup rather than being logged and skipped.
timeoutnumberRequest timeout in milliseconds for tools/list and tools/call (default 30000).

stdio example

{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
    },
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
      }
    }
  }
}

HTTP/SSE example

{
  "mcpServers": {
    "remote-tools": {
      "type": "streamable-http",
      "url": "https://mcp.example.com/sse",
      "headers": {
        "Authorization": "Bearer ${REMOTE_TOOLS_TOKEN}"
      }
    },
    "oauth-server": {
      "type": "streamable-http",
      "url": "https://mcp.example.com/oauth",
      "oauth": true
    }
  }
}

${VAR} placeholders in env and headers are expanded from the host environment at connect time (not via shell eval). Run /mcp auth in the REPL to view and complete any pending OAuth consent flows (the URL is also pushed via Telegram when running headless).

Tool naming

Every MCP tool is exposed to the agent as mcp__<server>__<tool>. For example, a server named filesystem with a read_file tool becomes:

mcp__filesystem__read_file

Tools are read fresh per query. When an MCP server sends a notifications/tools/list_changed notification, the tool list updates in-place — no session restart needed.

Surface coverage

MCP servers load on all surfaces — REPL, afk chat, daemon, and Telegram. Each surface constructs McpManager from the resolved config before the AgentSession is created, so MCP tools are available regardless of how AFK is invoked.

Viewing server status

In the REPL, use the /mcp slash commands:

/mcp          # list connected servers and tool counts
/mcp auth     # surface pending OAuth URLs

/mcp auth reads pending OAuth consent URLs from ~/.afk/state/mcp/server-status.json. When an MCP server requests OAuth consent (e.g., Supabase re-auth), the REPL prints the server name, message, and URL, then prompts Continue? [y/N].

Interactive server prompts

Some MCP servers request input mid-session through an elicitation form. On the REPL these render inline, and fields with a fixed set of values — enum fields and booleans — appear as an arrow-key selector rather than a free-text prompt (optional fields include a "skip" choice). On non-TTY surfaces (daemon, piped input) AFK falls back to a typed prompt. Type :decline or :cancel at any prompt to exit the form.

Server failures

Non-fatal by default: a server that fails to connect is reported as a warning and skipped. Mark a server alwaysLoad: true in the config to make its failure abort session startup:

{
  "mcpServers": {
    "critical-db": {
      "command": "...",
      "alwaysLoad": true
    }
  }
}

Source: docs/architecture.md (MCP client section).

Plugins

Plugins extend AFK with skills, user-defined subagents, and MCP server contributions. All plugin state lives under ~/.afk/plugins/ — separate from Claude Code's ~/.claude/plugins/.

Installing plugins

# GitHub shorthand (expands to https://github.com/<owner>/<repo>.git)
afk plugin install anthropics/claude-plugins-official

# Explicit git URL
afk plugin install https://github.com/example/my-plugin.git

# Local checkout (symlinked)
afk plugin install ~/Projects/my-plugin

# Pin to a tag, branch, or SHA
afk plugin install owner/repo --ref v1.2.3

By default, install picks the highest semver git tag, falling back to the default branch when no tags parse as semver.

Source: docs/reference.md (Plugins section).

Managing plugins

afk plugin list                           # installed plugins with enabled state
afk plugin update                         # update all plugins
afk plugin update <name>                  # update one plugin
afk plugin disable <name>                 # disable without removing
afk plugin enable <name>                  # re-enable
afk plugin remove <name>                  # uninstall

Plugin state is tracked in ~/.afk/plugins/.index.json. Entries with enabled: false are skipped at session startup.

Plugin discovery

The scanner walks ~/.afk/plugins/<name>/ at session construction, looking for .claude-plugin/plugin.json up to 5 directory levels deep. This means Claude Code's marketplace cache layout (cache/<marketplace>/<plugin>/<version>/) is also discovered automatically when dropped into ~/.afk/plugins/.

What plugins can contribute

A plugin directory can contain:

PathWhat it provides
skills/<skill>/SKILL.mdSlash command skill
agents/<agent>/Subagent definition
commands/<cmd>/Slash command
.claude-plugin/mcp.jsonMCP server config (lowest priority layer)
main field in plugin.jsonJS entrypoint — a module path loaded via dynamic import() before AgentSession is constructed. Use it to call registerSkill() or other side-effecting setup that must run synchronously before the session's skill manifest is assembled. Non-fatal: a failing entrypoint is caught and reported as a warning, never aborting boot. Idempotent per resolved path across plugin reloads.

Skills from plugins are auto-registered at session start and appear in /skills (alias /builtin-skills). Use /reload-plugins in the REPL to pick up changes after editing a plugin without restarting.

Marketplaces

afk marketplace install <url>    # add a marketplace source
afk marketplace list              # installed marketplaces
afk marketplace remove <name>     # remove a source

Marketplace state lives under ~/.afk/plugins/cache/.

User-scope skills (no plugin required)

Skills and subagents don't have to live in a plugin. Drop them directly:

~/.afk/skills/<name>/SKILL.md         # user-scope skill
~/.afk/agents/<name>/                  # user-scope subagent
~/.afk/commands/<name>/                # user-scope slash command

These are discovered alongside plugin contributions at session start.

Checking what's loaded

/skills       # all loaded skills (built-in + plugin + user-scope)
/agents       # all loaded subagent definitions
/mcp          # connected MCP servers
/tools        # full tool list including mcp__*

The afk config command dumps the resolved configuration including which MCP config files were found.

On this page