Grok Build · 55 min

MCP servers, plugins, and hooks

Specialist rung. If you do not write software or run agents, you can stop after C4 and still have reached repo level.

Open Grok Build docs
  • Add a project-scoped MCP server and name its tools as server__tool
  • Tell plugins apart from MCP and from hooks, including install, enable, and trust
  • Write a PreToolUse hook that denies on purpose, and know that hooks fail open
  • Use /mcps, /plugins, /hooks, and grok inspect instead of guessing what loaded

Why this matters

Built-in tools stop at the repo and the web. The next layer is other systems: a tracker, a database, a filesystem jail, a formatter that runs after every edit. Grok Build does that with three different objects that people mash into one word.

Specialist rung. If you do not write software or run agents, you can stop after C4 and still have reached repo level.

MCP servers add tools. Plugins install a bundle (skills, agents, hooks, MCP, LSP). Hooks run your script at a lifecycle event. If you treat them as the same switch, you will enable a plugin you do not trust, commit a token, or believe a hook is blocking commands when it crashed and failed open.

This module is how those three attach, how they are named, and what you have to trust before any of them run. The artifact is not a screenshot of a marketplace. It is a project config you can read, a hook that denied a command you asked for, and grok inspect output that matches what you think is loaded.

Teach

Three layers, three jobs

LayerWhat it addsWhen it runsTrust
MCP serverTools the model can call (linear__save_issue, filesystem__read_file)When the model uses search_tool / use_toolProject MCP rides the same folder-trust gate as project hooks
PluginA directory of skills, slash commands, agents, hooks, MCP, LSPAfter install and enable; hooks/MCP stay dark until trustedgrok plugin install … --trust, or a path under ~/.grok/plugins/
HookA command or HTTP POST on PreToolUse, Stop, SessionStart, and the restOn the event. Only PreToolUse (and Stop / SubagentStop) can change control flowGlobal ~/.grok/hooks/ always trusted; project .grok/hooks/ needs /hooks-trust

Do not install a plugin to “add MCP.” You can add an MCP server with no plugin. Do not write a hook to “add a Linear tool.” That is an MCP server. Do not expect a skill from C6 to block rm. That is a hook or a deny rule (C10).

MCP servers

An MCP server is a process that speaks the Model Context Protocol. Grok starts it (stdio) or connects to it (HTTP / SSE). Configure in ~/.grok/config.toml (every project) or .grok/config.toml (this repo). Same name: the project entry replaces the user one; fields do not merge.

# .grok/config.toml — team-shareable. Hosted servers use url = "https://…"
[mcp_servers.practice-fs]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "."]
enabled = true
# After -- belongs to the server, so -y reaches npx
grok mcp add --scope project practice-fs -- npx -y @modelcontextprotocol/server-filesystem .
grok mcp list
grok mcp doctor practice-fs

--scope user (default) writes ~/.grok/config.toml. --scope project writes .grok/config.toml here. Store secrets as ${INTERNAL_MCP_TOKEN}, not a bearer in git. On Windows, command = "npx" is enough — Grok resolves the .cmd shim.

Names. Server practice-fs plus tool read_file is practice-fs__read_file. The model finds tools with search_tool, then calls them with use_tool. If a C8 subagent gets an empty catalog, the parent never connected the server, or mcpInheritance filtered it. Plugin agents cannot declare their own mcpServers.

OAuth tokens land in ~/.grok/mcp_credentials.json (owner-only plaintext). Never paste that file. After a config edit, r in /mcps or grok mcp doctor. grok inspect shows each server and its source. On a name clash: config.toml > Claude > Cursor > .mcp.json.

Plugins

A plugin is a folder (skills/, commands/, agents/, hooks/hooks.json, .mcp.json). A marketplace is a git repo with .grok-plugin/marketplace.json. Adding a marketplace installs nothing. An installed plugin stays off until you enable it. Trust is a third switch: hooks and MCP stay dark until trusted.

grok plugin marketplace add owner/repo
grok plugin install deploy-tools --trust
grok plugin details deploy-tools

Without --trust, install warns and stops. That is correct. Plugins run as you. /plugins opens the extensions modal (Ctrl+L outside the VS Code family). Space enables. Collision: /plugin-name:skill. [plugins] enabled = ["deploy-tools"] in config is the durable on-switch.

~/.grok/plugins/ is auto-trusted. .grok/plugins/ is not. Plugin agent frontmatter cannot set mcpServers, hooks, or permissionMode: bypassPermissions. You do not publish a marketplace today. You do need to know a team plugin is how a shop ships skill + hook + MCP as one unit.

Hooks

A hook is a command or an HTTP POST. Grok fires it on a lifecycle event. Input is JSON on stdin. The useful gate is PreToolUse: write {"decision":"deny","reason":"…"} to stdout and exit 2, and that tool call does not run.

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          { "type": "command", "command": "node bin/deny-demo.js", "timeout": 5 }
        ]
      }
    ]
  }
}

matcher is a regex on the tool name. Bash also matches Grok’s run_terminal_command. MCP calls match the qualified server__tool name, not use_tool. Empty matcher matches everything.

Fail-open. Timeout, crash, missing script, malformed JSON: the failure is recorded in scrollback, and the tool runs. Only an explicit deny blocks. A hook you cannot see succeed is not a security boundary. C10 will put deny rules and (on Linux/macOS) the sandbox under that same sentence.

Stop / SubagentStop can keep the agent working ({"decision":"block","reason":"tests failed"}). UserPromptSubmit is observe-only here. SessionStart does not fire for a subagent’s own session.

~/.grok/hooks/*.json is always trusted. Project .grok/hooks/ is silently skipped until /hooks-trust (or --trust). That grant (~/.grok/trusted_folders.toml) covers MCP, LSP, and hooks together. /hooks-untrust revokes it. /hooks lists what loaded; r reloads.

Inspect, then talk to the model

grok inspect
grok mcp list
grok plugin list

Inside the TUI: /mcps, /plugins, /hooks. If inspect and the modal disagree with the story in your head, the files win. Fix the files. Do not prompt the model to “enable Linear” and hope.

Worked example

Same practice desk as C1 (%USERPROFILE%\grok-build-practice). Not this LMS. Not a client repo.

  1. cd into the practice repo. Confirm git status is clean enough that you can see new files.
  2. Add a project filesystem MCP rooted on . — the command in Teach. Run grok mcp list. You should see practice-fs marked (project).
  3. Create .grok/hooks/deny-demo.json with the PreToolUse / Bash block above. Create bin/deny-demo.js so that any command containing GROK_HOOK_DENY_DEMO writes a deny JSON and exits 2. Otherwise allow.
  4. Launch grok in that directory. Run /hooks-trust when asked, or because the hook is not listed. Open /mcps and /hooks. Press r if you edited files after launch.
  5. Send: Run the shell command echo GROK_HOOK_DENY_DEMO and then echo ok. Do not find another way to print those strings.
  6. Scrollback should show the hook deny, reason visible, echo ok never reached. If the command ran, the hook failed open — node missing, path wrong, folder untrusted, or matcher missed. Fix that before you continue.
  7. Send: Using search_tool, find tools from practice-fs. Name one qualified tool. Do not write files.
  8. /quit. Run grok inspect and save the MCP + hook lines.

What you did not do: paste an API key into config.toml, install a marketplace plugin from a name you Googled, or flip always-approve so the deny would “just work.” The deny is the hook. Always-approve is C9 and C10, and it does not override a hook deny.

Your turn

Do c7-l01-e1 in Grok Build, in a git repo you own. The exercise makes Grok Build add the MCP server, write the hook, trust the folder, and produce the deny plus grok inspect. If you type the JSON by hand and never open the TUI, you did not take the module.

Common failure

Project hooks that “do nothing.” The folder is untrusted. /hooks will not show them as live. /hooks-trust. The same grant is what lets project MCP start.

A hook you treat as a lock. The script threw, node was not on PATH, or you matched use_tool instead of practice-fs__read_file. Fail-open means the dangerous command ran. Read the scrollback annotation. Until you have seen a deny you caused, you do not have a hook.

Secrets in git. Authorization = "Bearer xai-…" in a committed .grok/config.toml. Use ${VAR}. Rotate anything that already landed in history.

Install without reading. grok plugin install some-stranger/cool-tools --trust because a blog said to. Plugins run as you. Marketplace add, then grok plugin details, then a source you recognize, then --trust.

What’s next

C8 is the other kind of extra process: subagents with their own context window, and git worktrees so a child can edit without stepping on your tree. MCP inheritance rides along. Do not skip the isolation part.

Your turn

Grok Build

Stand up a project MCP server and a deny hook

Copy-ready prompt
I am on Grok Mastery Pathway C, module C7.

Do all of this in this repo. Do not leave this working tree. Do not enable always-approve.

1) Add a project-scoped MCP server named practice-fs that runs:
   npx -y @modelcontextprotocol/server-filesystem
   with the allowed directory set to this repo root.
   Prefer `grok mcp add --scope project` if the CLI is the cleanest path.
   Do not put tokens or API keys anywhere.

2) Add a project PreToolUse hook (matcher Bash) whose command is
   `node bin/c7-deny-demo.js`. The script must read the hook JSON from stdin.
   If toolInput.command contains the exact substring GROK_HOOK_DENY_DEMO,
   write {"decision":"deny","reason":"C7 demo deny"} to stdout and exit 2.
   Otherwise write {"decision":"allow"} and exit 0.
   Do not block any other command.

3) Tell me if this folder still needs /hooks-trust. Do not invent a trust grant
   if the UI already shows the hook as live.

4) After I confirm the hook is trusted and listed in /hooks, run exactly:
   echo GROK_HOOK_DENY_DEMO
   Then stop. Do not work around the hook.

5) Use search_tool to find tools from practice-fs. Name one fully qualified
   tool (server__tool). Do not write files through MCP.

6) Run `grok inspect` (or show me how and wait). Summarize only:
   - MCP servers loaded (name, scope, source)
   - hooks loaded (event, command, trusted or skipped)
Artifact

1. The practice-fs block from `.grok/config.toml` or `grok mcp list` (no secrets). 2. The project hook JSON and `bin/c7-deny-demo.js` (full files). 3. Scrollback proof the hook denied `echo GROK_HOOK_DENY_DEMO`. 4. One qualified MCP tool name from `search_tool` (shape: `practice-fs__read_file`). 5. MCP and hook lines from `grok inspect`, or Grok’s faithful summary of them.

Read the lesson if you want. Submitting an artifact and marking complete needs a seat.