Blog • AI / Agent
Why Does Claude Code Look More Like a Real AI Agent? Tool Use, MCP, Session, Permission, and the JSON Workflow
Claude Code looks like an agent because one session binds three JSON documents: a resumable conversation, the permission check on every tool use, and the MCP config read at startup. Resume with --resume, permissions live in settings.json, and tools come from .mcp.json. Drop any one of them and the resumed run is not the same piece of work.
The tool loop itself is already in How coding agents work. How harnesses differ is in the harness race. This article only splits Claude Code: what a session restores, when the permission mode changes, when MCP is read again, and which workflow JSON you should keep yourself.
This article covers:
- What a resumed session brings back, and what it does not
- Permission mode is session state. Rules live in settings
- MCP is read when the session starts. A command-line config does not return on its own
- A workflow JSON you own, so the next resume uses the same arguments
- The order in which one tool use updates those three documents
Hold this first: resuming a session is not the same as restoring launch flags. The conversation and some permission modes come back. --mcp-config does not. The sections below split session, permission, MCP, and your workflow JSON.
What a session restores, and what it does not
A session is a conversation tied to a project directory. See Manage sessions. The transcript is written locally as you work, so you can come back after you exit.
| Entry | What comes back | Permission mode |
|---|---|---|
claude --continue |
The full latest interactive conversation in this directory, including tool calls and results | From a terminal without -p, the official table applies. bypassPermissions and plan do not return unchanged |
claude --resume <name> |
Resume that session directly by name | A unique name opens it. A duplicate name opens the picker, and the picker does not restore the stored mode |
claude -p --resume |
Non-interactive resume, for scripts | The mode is whatever a new claude -p run would use. Plan mode returns only when the session ended in plan and the four official conditions hold |
Resume also brings back the model in use, an active goal, and scheduled tasks that have not expired. Background Bash does not return.
- Comes back: conversation history, the model (unless it was retired or blocked by availableModels), and an agent started with --agent. If that agent is missing from both directories, the session falls back to the default tools and shows a warning.
- Does not come back on its own:
--mcp-config,--settings,--add-dir, and directories added mid-session with /add-dir. Pass those again on the resume command. - Config in
settings.jsonand settings.local.json is re-read at launch. You do not pass it again.
The transcript is JSONL by default, under ~/.claude/projects/ in a folder derived from the working directory. Official docs say the format changes. Do not treat it as your stable contract. Keep the stable fields in a separate JSON document.
Permission mode travels with the session
The mode is not a sentence in the prompt. During a session, Shift+Tab cycles default, acceptEdits, and plan. At startup, use --permission-mode. The lasting default is permission modes field permissions.defaultMode. Asking the model in chat to change the mode does not change the gate.
{
"permissions": {
"defaultMode": "default",
"allow": ["Bash(npm test *)"],
"ask": ["Bash(git push *)"],
"deny": ["Read(./.env)", "Read(./.env.*)"]
}
}
Rule order is in Claude Code permissions. A more specific allow does not override a deny that already matched.
| How you resume | Permission mode |
|---|---|
| Terminal --continue, or --resume of a unique name, without -p | Restores the mode the session ended in, except bypassPermissions and plan start as a new session would. auto returns only if the account still qualifies. |
| The picker at launch, or a name that matches more than one session | Does not restore the stored mode. Starts in the mode a new session would use for this launch. |
/resume |
Does not restore the target session's stored mode. Continues in the mode of the session you are already in. |
How rules become an approval queue and a denial write-back is in how to attach permission control. This article only treats the mode as session state. The rules file is re-read on resume.
MCP is read when the session starts
A project server lives in .mcp.json at the repo root and is read when the session starts. After you edit the file, exit and start again. See Connect to MCP. The first time Claude Code sees a project server, it asks you to approve it. A cloned repo cannot start a process on your machine without that consent.
{
"mcpServers": {
"docs": {
"type": "http",
"url": "https://code.claude.com/docs/mcp"
}
}
}
- Project scope:
.mcp.json, shared with everyone who clones the repo. Approve it first. - Local scope:
~/.claude.json. local is only you, only this project. user is only you, every project. - The flag
--mcp-configapplies only to this launch. Resume does not bring it back. Pass it again.
The full tool name uses a prefix such as mcp__docs__. Permission rules match that full name. Do not write only the short name from the server.
The workflow JSON you keep
The JSONL transcript is not a stable contract. The document below is yours. It records what to pass next time you resume. It is not a Claude Code request body, and the CLI does not read it.
{
"name": "auth-refactor",
"cwd": "/repo/app",
"permission_mode": "default",
"settings": ".claude/settings.json",
"mcp_config": ".mcp.json",
"resume": ["--resume", "auth-refactor"],
"last_tool": {
"name": "mcp__docs__search",
"decision": "allow"
}
}
name is the name you set with claude -n or /rename, so --resume can find it. cwd must be the project directory from that session. Sessions are stored per directory.
-
1
Match the session first
nameis what you pass to --resume.cwddecides which project directory holds the transcript. The wrong directory means the same name is not found. -
2
Then align the permission mode
Copy
permission_modeonto--permission-modein the resume command. The picker and /resume will not restore the old mode for you. -
3
Then attach MCP
If
mcp_configpoints at a file in the repo, startup reads it again. If the original run depended on a command-line file, put that path in--mcp-config.
How one tool use updates the three documents
A turn is not another paragraph of prompt. The order is fixed.
-
1
Load
The session loads the existing conversation and re-reads settings.json and .mcp.json. Command-line MCP is present only if you passed it this time.
-
2
Propose the call
The model emits a tool_use: the full tool name and input. An MCP tool carries the server prefix.
-
3
Pass permissions
Evaluate deny, then ask, then allow. Deny does not run. Ask waits for a person. Allow is what calls the tool.
-
4
Write back
The result is appended to the session transcript. Your workflow JSON updates only
last_tool. Do not copy the whole transcript into it.
On the next resume you know which tool you stopped on, which mode was in effect, and which file supplied MCP. Claude Code still stores the transcript.
How this differs from the other two articles
| How coding agents work | The harness race | This article | |
|---|---|---|---|
| Question answered | How a tool loop turns in general | How the shells differ | What each of the three JSON documents does when a Claude Code session resumes |
| Do not look here for | Another survey of tool calling | Another product comparison table | Parsing the JSONL transcript as a stable API |
Check the workflow JSON in JSONNote
-
1
Format
Open settings.json and the workflow record in JSON format. A comment or a trailing comma makes Claude Code report a Settings Error on the next start.
-
2
Validate the workflow record
Paste the Schema below into JSON Schema. A missing name or cwd, or a permission_mode outside the enum, should be fixed before you resume.
-
3
Diff the permission rules
Before and after a deny / allow edit, use JSON Diff to see whether a
denyrule moved intoallow. That change matters more than the session name.
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"additionalProperties": false,
"required": ["name", "cwd", "permission_mode", "settings", "mcp_config"],
"properties": {
"name": { "type": "string", "minLength": 1 },
"cwd": { "type": "string", "minLength": 1 },
"permission_mode": {
"enum": ["default", "acceptEdits", "plan", "auto", "dontAsk", "bypassPermissions"]
},
"settings": { "type": "string", "minLength": 1 },
"mcp_config": { "type": "string", "minLength": 1 },
"resume": { "type": "array", "items": { "type": "string" } },
"last_tool": {
"type": "object",
"required": ["name", "decision"],
"properties": {
"name": { "type": "string" },
"decision": { "enum": ["allow", "deny", "ask"] }
}
}
}
}
FAQ
Are MCP servers still there after resume?
Servers in .mcp.json or ~/.claude.json are read again at startup. A server passed only through --mcp-config does not come back. Pass it again when you resume.
Does the permission mode resume with the conversation?
Not always. A terminal --continue, or --resume of a unique name, without -p, follows the official table. bypassPermissions and plan do not come back as they were. The picker and /resume use the mode of this launch.
Can you parse the JSONL under ~/.claude/projects as the workflow?
Do not. Official docs treat the transcript format as an internal file that changes. Keep the workflow JSON in this article: name, directory, mode, config paths, and the last tool decision.
Does asking the model in chat to switch permission mode work?
No. The mode is set by Shift+Tab, --permission-mode, or defaultMode in settings. A prompt does not change the gate.
Is this the same thing as the approval queue?
No. permission_mode here is the gate for this session. The queue, the denial write-back, and tool_use_id are in the permission-control article. You need both: the mode decides whether to ask, the queue decides how the answer is stored.
Conclusion
Claude Code looks like an agent because a session binds the conversation, the permission mode, and the MCP tools into one resumable piece of work. Restoring the conversation is not the same as restoring launch flags. Leave the JSONL transcript to the CLI. Keep your own workflow JSON.
Direct conclusion: locate the session by name and directory. Pass the permission mode again for the picker and /resume. Pass --mcp-config again on every resume.
Next: validate the workflow record, then open the session with the resume arguments inside it.