charles-mcp: a MCP server that puts Charles Proxy traffic in front of an AI agent
Charles Proxy MCP server for AI agents with live capture, structured traffic analysis, and agent-friendly tool contracts
At a glance
- What is it?
- charles-mcp wraps the Charles Proxy web interface in an MCP server so agents read structured, summary-first traffic instead of raw capture dictionaries. It is a narrow bridge between two existing tools, and it only works while Charles is running.
- Who is it for?
- Adopt charles-mcp if you already run Charles Proxy for manual network debugging and want an agent to do the first pass over live or recorded sessions.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 84 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The gap charles-mcp fills between Charles Proxy and an agent
Charles Proxy already records everything you need. The problem is the shape of that data. A capture session is a large collection of request and response objects, and handing that to a language model burns context on fields nobody asked about. The README frames the project around three problems: reading incremental traffic while recording is still in progress, running live and history through the same structured analysis instead of letting the agent consume raw capture dictionaries, and defaulting to summary-first output so the agent sees hot spots before it drills into a single request.
That last point is the design decision worth noticing. The tool surface is built so that the cheap call comes first. According to the README, read_live_capture and peek_live_capture now return only route-level summary fields such as host, method, path and status. An agent that wants headers or bodies has to ask for a specific entry. This is a deliberate tax on the agent in exchange for a smaller context window, and it is the right trade for exploratory debugging where you do not yet know which request matters.
The audience is narrow and specific: developers who already keep Charles open while debugging mobile or desktop clients, and who want an agent to triage the resulting traffic. If you do not run Charles, nothing here applies to you.
How the server talks to Charles and what the agent actually receives
charles-mcp is a Python MCP server. It speaks the MCP protocol over stdio to a client such as Claude Code, Claude Desktop, Cursor, Windsurf or Codex CLI, and on the other side it talks HTTP to the Charles Web Interface. There is no packet capture inside this project: Charles does the proxying, and the MCP server queries it.
That is why the setup instructions start in Charles rather than in Python. You enable the web interface under Proxy, then Web Interface Settings, with the username admin and the password 123456. The server reaches the proxy control plane at 127.0.0.1:8888 by default, which is exposed as CHARLES_PROXY_HOST and CHARLES_PROXY_PORT. Credentials go in CHARLES_USER and CHARLES_PASS.
The recommended live path in the README is a five-step sequence: start_live_capture, group_capture_analysis, query_live_capture_entries, get_traffic_entry_detail, stop_live_capture. The history path is list_recordings, analyze_recorded_traffic, group_capture_analysis with source="history", then get_traffic_entry_detail. Both paths share the same shape: aggregate first, then expand one entry. That consistency is the part of the design that holds up, because an agent that has learned the live path can follow the history path without relearning the contract.
The v3.0 line also added a reverse-analysis tool chain covering import, query, decode, replay, signature candidate analysis and live reverse sessions. The README describes the goal as letting the agent work around authentication, signing, parameter mutation and replayability rather than only viewing traffic. Treat that as a direction the project is moving in, not a finished surface.
Installing charles-mcp and running a first live capture
The README states you do not need to clone the repository or create a virtual environment by hand. You need uv installed first, then the package is run through uvx. Python 3.10 or newer is required, and Charles Proxy must be running locally with the web interface enabled.
For Claude Code, the README gives a single registration command that writes the server entry with the credentials and lifecycle flag in one step:
claude mcp add-json charles '{
"type": "stdio",
"command": "uvx",
"args": ["charles-mcp"],
"env": {
"CHARLES_USER": "admin",
"CHARLES_PASS": "123456",
"CHARLES_MANAGE_LIFECYCLE": "false"
}
}'For Claude Desktop, Cursor and other clients that read a JSON config, the same entry goes under mcpServers:
{
"mcpServers": {
"charles": {
"command": "uvx",
"args": ["charles-mcp"],
"env": {
"CHARLES_USER": "admin",
"CHARLES_PASS": "123456",
"CHARLES_MANAGE_LIFECYCLE": "false"
}
}
}
}Codex CLI uses TOML instead, with the same command and environment keys:
[mcp_servers.charles]
command = "uvx"
args = ["charles-mcp"]
[mcp_servers.charles.env]
CHARLES_USER = "admin"
CHARLES_PASS = "123456"
CHARLES_MANAGE_LIFECYCLE = "false"After restarting the client, the first real use is to start a bounded recording and let the agent summarize it. The README's live path begins with start_live_capture; CHARLES_MAX_STOPTIME defaults to 3600, which caps how long a bounded recording can run. Then call group_capture_analysis to get the aggregate view, query_live_capture_entries to narrow it, and get_traffic_entry_detail on one entry. What you should see is a short list of routes with host, method, path and status before any body content appears. If the server starts but every call fails, the credentials or the web interface setting is the first thing to check, not the MCP wiring.
Charles must be running, and the web interface is the whole dependency
The sharpest limitation is structural. charles-mcp does not capture anything on its own. If Charles is not running with the web interface enabled and reachable at the configured host and port, the server has nothing to read. This is not a bug to work around; it is what the project is. Anyone hoping for a headless capture stack should look elsewhere, because the architecture assumes a GUI proxy process on the same machine.
The second constraint is the tool contract itself. In v3.0.3 the default public surface was tightened to 31 canonical tools, and the legacy aliases filter_func, proxy_by_time and list_sessions are no longer exposed by default. They come back only through create_server(expose_legacy_tools=True) or the environment variable CHARLES_EXPOSE_LEGACY_TOOLS=true. If you have prompts or agent instructions written against the old names, they will fail silently in the sense that the tool simply is not there. The repository points to docs/migrations/legacy-tools.md as the authoritative migration note, and that is the file to read before upgrading.
Third, the project ships as 3.1.0rc1, a release candidate, and pyproject.toml classifies it as Development Status 4 - Beta. The README also carries a maintenance notice dated 2026-04-21 stating that the public Git history was reorganized on that date, and that anyone who cloned before it should re-clone rather than merge from an old local copy. That is a real operational detail: stale clones can reintroduce outdated history. The last push to the repository was on 2026-06-23, so this is not a project with a long quiet period behind it, but the release candidate status means the tool surface can still move.
Where charles-mcp fits next to mitmproxy and browser DevTools
The obvious alternative for scripted traffic work is mitmproxy. The difference in approach is where the control lives. mitmproxy is itself the proxy, and its addon API and command line let you intercept, rewrite and replay flows programmatically from the start. charles-mcp is a query layer over a proxy you already run, and its job is to translate that proxy's state into something an agent can consume in a few calls. If your goal is automated interception with no human in the loop, mitmproxy is the shorter path. If your goal is an agent reading the session you are already inspecting by hand in Charles, charles-mcp is the only one of the two that does that.
Browser DevTools is the other comparison, and it is a weaker one. DevTools shows you one browser tab's traffic and nothing else. It cannot see a mobile app on the same network, and there is no MCP surface to query. For desktop or mobile client debugging, DevTools is not in the same category.
The honest framing is that charles-mcp inherits every limitation of Charles and adds a context-efficiency layer on top. It does not make Charles headless, scriptable in the mitmproxy sense, or usable on a machine without the GUI. It makes the data Charles already collected legible to an agent.
Maintenance, licence and what an upgrade costs you
The licence is MIT, declared in pyproject.toml with license-files pointing at LICENSE. That is permissive and imposes no copyleft obligation on your own code, but the usual caveat applies: this is a description of what the repository declares, not legal advice, and if the licence matters to your organisation, read the LICENSE file and your own policy.
The upgrade cost is mostly about the tool surface. The move from the pre-v3.0 names to the 31 canonical tools is a breaking change for anything that hardcoded filter_func, proxy_by_time or list_sessions. The escape hatch exists, but leaving CHARLES_EXPOSE_LEGACY_TOOLS=true on indefinitely means you are running a compatibility layer the project has already decided to stop exposing by default. The migration document is the place to work from.
The other cost is state. Reverse-analysis keeps a SQLite database and artifacts under CHARLES_REVERSE_STATE_DIR, which defaults to ${CHARLES_STATE_DIR}/reverse. The README notes that the older CHARLES_VNEXT_STATE_DIR variable is migrated automatically on first start of the main charles-mcp process. If you are scripting around that directory, plan for the new variable name rather than the old one.
Dependencies are ordinary Python packages: mcp, httpx, pydantic, jmespath, defusedxml, brotli, zstandard and protobuf. Nothing exotic, and uvx resolves them at launch, so there is no virtual environment to maintain on your side.
Editorial conclusion
Adopt charles-mcp if you already run Charles Proxy for manual network debugging and want an agent to do the first pass over live or recorded sessions. Skip it if you do not use Charles, if you need a proxy with no GUI behind it, or if you want a stable tool surface: the project is at 3.1.0rc1, the v3.0 line cut the default tool count to 31 and moved legacy aliases behind CHARLES_EXPOSE_LEGACY_TOOLS, so anything written against the older names needs the migration note in docs/migrations/legacy-tools.md. Before wiring it into a workflow, confirm that your Charles Web Interface answers on 127.0.0.1:8888 with the credentials you put in CHARLES_USER and CHARLES_PASS, and leave CHARLES_MANAGE_LIFECYCLE at false unless you want the server to shut down your Charles process.
Frequently asked questions
What is the charles-mcp server used for?
It connects Charles Proxy to an MCP client so an AI agent can read live capture and recorded sessions as structured, summary-first traffic. The README describes three goals: incremental reads during an active recording, one analysis path for live and history, and drill-down into a single request only when needed.
Do I need to clone the charles-mcp repository to install it?
No. The README states you install uv and then run the package through uvx, registering it with your MCP client through a JSON or TOML config entry. Python 3.10 or newer is required.
Why does charles-mcp fail to return any traffic?
The most likely cause is that Charles Proxy is not running, or the web interface is not enabled under Proxy then Web Interface Settings. The server queries Charles over HTTP at CHARLES_PROXY_HOST and CHARLES_PROXY_PORT, which default to 127.0.0.1 and 8888, and it has no capture capability of its own.
What changed in charles-mcp v3.0.3 about legacy tools?
The default public tool surface was tightened to 31 canonical tools, and the legacy aliases filter_func, proxy_by_time and list_sessions are no longer exposed by default. They can be re-enabled with create_server(expose_legacy_tools=True) or the CHARLES_EXPOSE_LEGACY_TOOLS=true environment variable, and docs/migrations/legacy-tools.md is the migration reference.
Should I set CHARLES_MANAGE_LIFECYCLE to true in charles-mcp?
The README recommends keeping it false unless you explicitly want the MCP server to manage Charles startup and shutdown. With the default, the server will not close your Charles process when it exits.
Community notes