Connects Claude directly to Perforce version control through Python bindings and FastMCP. You get read/write tools for changelists, shelves, workspaces, jobs, and P4's code review system, including voting, commenting, and participant management. Runs in read-only mode by default with ownership checks and interactive confirmations for destructive operations like obliterate. Configure which tool categories to expose (files, streams, server metadata) based on your workflow. Ships as pre-built binaries for offline environments or runs via uvx without installation. Useful when you're managing code reviews, tracking shelved changes, or automating workspace operations without leaving your AI conversation.
Perforce P4 MCP Server is a Model Context Protocol (MCP) server that integrates with the Perforce P4 version control system. It is built on FastMCP with direct P4 Python bindings to expose safe, structured read/write tools for changelists, files, shelves, workspaces, jobs, reviews, and server metadata.
Features · Prerequisites · System Requirements · Install · Deployment · Client Configurations · P4 Configurations · Tools
Logging · Troubleshoot · Support · Contributions · License
logs/ directory.| Component | Supported Versions |
|---|---|
| Operating Systems | Windows 10+ macOS 12+ Linux (glibc 2.34+, e.g. Ubuntu 22.04+, Rocky Linux 9+) |
| Perforce P4 Server | 2025.2 (earlier versions untested) |
| Python | 3.11+ (required only for building from source) |
If you have uv installed, you can run P4 MCP Server directly without any manual installation:
# Run the server
uvx p4mcp-server
# Check version
uvx p4mcp-server --version
# Run with arguments
uvx p4mcp-server --readonly --allow-usage
This automatically fetches and runs the latest version from PyPI. No Python virtual environment setup or dependency management needed.
Requirements:
Download the appropriate binary for your operating system:
Extract and use the executable directly. No Python installation is required.
# macOS / Linux
unzip p4-mcp-server-mac.zip # or p4-mcp-server-linux.zip
./p4-mcp-server --help
# Windows
Expand-Archive p4-mcp-server-win.zip -DestinationPath .
.\p4-mcp-server.exe --help
Requirements:
Build:
chmod +x build.sh && ./build.sh packagechmod +x build.sh && ./build.sh packagebuild.bat packageOutput:
p4-mcp-server-<version>.tgzp4-mcp-server-<version>.zipRun the P4 MCP Server directly on your machine using the default STDIO transport.
Add the following to your mcp.json:
{
"mcpServers": {
"perforce-p4-mcp": {
"command": "/absolute/path/to/p4-mcp-server",
"env": {
"P4PORT": "ssl:perforce.example.com:1666",
"P4USER": "your_username",
"P4CLIENT": "your_workspace"
},
"args": [
"--readonly", "--allow-usage"
]
}
}
}
Note: This example shows explicit
envvalues. IfP4CONFIGis set, you can omit them and use the generic configuration example in theMCP client configurationsection instead.
Run the P4 MCP Server from a Docker container with STDIO transport, allowing MCP clients to manage the container lifecycle.
Note: Docker-based execution is currently supported on macOS and Linux only.
Prerequisites
Pull the Docker image
docker pull ghcr.io/perforce/p4mcp-server:latest
cd /path/to/p4mcp-server
docker build -t ghcr.io/perforce/p4mcp-server .
Configure MCP Client
Add the following to your mcp.json:
{
"servers": {
"perforce-p4mcp-docker": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"--hostname", "your-hostname",
"-e", "P4PORT=ssl:perforce.example.com:1666",
"-e", "P4USER=your_username",
"-e", "P4CLIENT=your_workspace",
"-v", "/Users/your_username/.p4tickets:/home/mcpuser/.p4tickets:ro",
"ghcr.io/perforce/p4mcp-server:latest"
]
}
}
}
Configuration Options
| Flag | Description |
|---|---|
-i | Interactive mode (required for STDIO) |
--rm | Remove container when stopped |
--hostname | Match workspace host restriction |
-e P4PORT | P4 server address |
-e P4USER | P4 username |
-e P4CLIENT | Workspace name |
-v | Mount P4 tickets file |
Authentication
Using P4 tickets:
# macOS/Linux
-v /Users/your_username/.p4tickets:/home/mcpuser/.p4tickets:ro
Note: Use the full path to your tickets file (not
~). After runningp4 login, restart the MCP server to pick up the new ticket.
Using a password:
-e P4PASSWD="your_password"
Workspace Host Restrictions
⚠️ Important: Docker containers have their own hostname, which differs from your local machine. If your P4 workspace is restricted to a specific host, operations like
syncwill fail.
To resolve this, set the container hostname to match your workspace's host restriction:
--hostname your-hostname
To find your workspace host name:
# macOS/Linux
p4 client -o your_workspace | grep "^Host:"
Mounting Client Root for Write Operations
⚠️ Important: By default, the Docker container cannot access your local workspace files. For write operations like
sync,submit, orreconcile, you must mount your client root directory into the container at the same path.
Add a volume mount for your client root:
-v /path/to/your/client/root:/path/to/your/client/root
Example configuration with client root mounted:
{
"servers": {
"perforce-p4mcp-docker": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"--hostname", "your-hostname",
"-e", "P4PORT=ssl:perforce.example.com:1666",
"-e", "P4USER=your_username",
"-e", "P4CLIENT=your_workspace",
"-v", "/Users/your_username/.p4tickets:/home/mcpuser/.p4tickets",
"-v", "/path/to/client/root:/path/to/client/root",
"ghcr.io/perforce/p4mcp-server:latest"
]
}
}
}
To find your client root:
p4 client -o your_workspace | grep "^Root:"
Note: The mount path inside the container must match the client root path exactly, as P4 tracks files by their absolute paths.
Run the MCP server on a VM using the HTTP transport, allowing clients to connect over the network.
Start the server on the VM:
P4PORT=ssl:perforce.example.com:1666 P4USER=your_username P4PASSWD=YOUR_TICKET ./p4-mcp-server --readonly --transport http --port 8000
Configure the MCP client:
Add the following to your mcp.json:
{
"servers": {
"perforce-p4-mcp": {
"type": "http",
"url": "http://<ip-or-hostname>:8000/mcp"
}
}
}
Note: Ensure the VM's firewall allows inbound connections on the chosen port. For production use, consider placing the server behind a reverse proxy with TLS.
Run the MCP server in a Docker container using HTTP transport and expose the MCP endpoint over a host port.
Start the container:
docker run --rm -p 8000:8000 \
-e P4PORT=ssl:perforce.example.com:1666 \
-e P4USER=your_username \
-e P4PASSWD=YOUR_TICKET \
ghcr.io/perforce/p4mcp-server:latest \
python3 -m p4mcp.main --readonly --transport http --port 8000
Configure the MCP client:
Add the following to your mcp.json:
{
"servers": {
"perforce-p4-mcp": {
"type": "http",
"url": "http://<ip-or-hostname>:8000/mcp"
}
}
}
Note: Docker supports HTTP-based deployment as well. The container image defaults to STDIO transport, so the HTTP startup command must explicitly override the default command. If you need write operations, also mount the client root and ticket file paths into the container.
Note: In all configuration examples below, if
P4CONFIGis set, you do not need to set any environment variables in theenvblock. The server will use the configuration from the specified P4CONFIG file instead.
Tip: If you have uv installed, you can use
uvx p4mcp-serverinstead of/absolute/path/to/p4-mcp-serverin thecommandfield. This eliminates the need to download or build binaries manually.Server configuration example using uvx
{ "mcpServers": { "perforce-p4-mcp": { "command": "uvx", "args": [ "p4mcp-server", "--readonly", "--allow-usage" ], "env": { "P4PORT": "ssl:perforce.example.com:1666", "P4USER": "your_username", "P4CLIENT": "your_workspace" } } } }Server configuration example using binary path
{ "mcpServers": { "perforce-p4-mcp": { "command": "/absolute/path/to/p4-mcp-server", "env": { }, "args": [ "--readonly", "--allow-usage" ] } } }
See the JetBrains AI Assistant VCS Integration documentation for detailed configuration steps.
See the Claude Code MCP docs for more information.
Using uvx (no installation required):
{
"mcpServers": {
"perforce-p4-mcp": {
"command": "uvx",
"args": [
"p4mcp-server",
"--readonly", "--allow-usage"
],
"env": {
"P4PORT": "ssl:perforce.example.com:1666",
"P4USER": "your_username",
"P4CLIENT": "your_workspace"
}
}
}
}
Using pre-built binary:
{
"mcpServers": {
"perforce-p4-mcp": {
"command": "/absolute/path/to/p4-mcp-server",
"env": {
"P4PORT": "ssl:perforce.example.com:1666",
"P4USER": "your_username",
"P4CLIENT": "your_workspace"
},
"args": [
"--readonly", "--allow-usage"
]
}
}
}
See the Cursor MCP documentation for more information.
{
"mcpServers": {
"perforce-p4-mcp": {
"command": "/absolute/path/to/p4-mcp-server",
"env": {
"P4PORT": "ssl:perforce.example.com:1666",
"P4USER": "your_username",
"P4CLIENT": "your_workspace"
},
"args": [
"--readonly", "--allow-usage"
]
}
}
}
See the Eclipse MCP documentation for more information.
{
"servers": {
"perforce-p4-mcp": {
"command": "/absolute/path/to/p4-mcp-server",
"env": {
"P4PORT": "ssl:perforce.example.com:1666",
"P4USER": "your_username",
"P4CLIENT": "your_workspace"
},
"args": [
"--readonly", "--allow-usage"
]
}
}
}
See the Kiro MCP documentation for more information.
{
"mcpServers": {
"perforce-p4-mcp": {
"command": "/absolute/path/to/p4-mcp-server",
"env": {
"P4PORT": "ssl:perforce.example.com:1666",
"P4USER": "your_username",
"P4CLIENT": "your_workspace"
},
"args": [
"--readonly", "--allow-usage"
]
}
}
}
See the VS Code documentation for more information.
{
"servers": {
"perforce-p4-mcp": {
"command": "/absolute/path/to/p4-mcp-server",
"env": {
"P4PORT": "ssl:perforce.example.com:1666",
"P4USER": "your_username",
"P4CLIENT": "your_workspace"
},
"args": [
"--readonly", "--allow-usage"
]
}
}
}
See the Windsurf MCP documentation for more information.
{
"mcpServers": {
"perforce-p4-mcp": {
"command": "/absolute/path/to/p4-mcp-server",
"env": {
"P4PORT": "ssl:perforce.example.com:1666",
"P4USER": "your_username",
"P4CLIENT": "your_workspace"
},
"args": [
"--readonly", "--allow-usage"
]
}
}
}
P4PORT - P4 Server address. Examples: ssl:perforce.example.com:1666, localhost:1666P4USER - Your P4 usernameP4CLIENT - Your current P4 workspace. Optional, but recommendedP4MCP_LOG_DIR - Directory for log files. Default: logs/ in the server executable's directory. Can be overridden by the --log-dir CLI argument.P4MCP_TLS_CA_MODE - TLS certificate source mode.
system (default): use OS trust store via truststore. Note: In this mode, truststore overrides the verify= parameter — custom CA bundles set via P4MCP_CA_BUNDLE or --ca-bundle are ignored. To use a custom CA bundle, set P4MCP_TLS_CA_MODE=certifi.certifi: disable truststore injection and use default Python TLS certificate behavior. Custom CA bundles (P4MCP_CA_BUNDLE / --ca-bundle) take effect only in this mode.P4MCP_SSL_VERIFY - Set to false to disable SSL verification for P4 Code Review API requests. Default: true. Works in both TLS modes.P4MCP_CA_BUNDLE - Path to a custom CA certificate bundle (PEM) for P4 Code Review API requests. Takes priority over P4MCP_SSL_VERIFY. Requires P4MCP_TLS_CA_MODE=certifi to take effect.--readonly - Control write operations.
--allow-usage - Allow usage statistics.
--toolsets - Specify which tool categories to enable.
files, changelists, shelves, workspaces, jobs, reviews, streamsquery_server is always available regardless of the --toolsets setting.--search-transform - Enable search-based tool discovery to reduce token overhead.
regex — Expose a regex pattern-matching search tool. Best for targeted lookups.bm25 — Expose a natural-language relevance-ranked search tool. Best for exploratory queries.both — Expose both search tools with distinct names (regex_search_tools/regex_call_tool and semantic_search_tools/semantic_call_tool).query_server is always directly visible to the client.CheckPermissionMiddleware) and --readonly filtering remain fully enforced. Search transforms query the real tool catalog internally, so tools blocked by middleware or excluded by read-only mode are never discoverable or callable through the search interface.--ssl-no-verify - Disable SSL certificate verification for P4 Code Review API requests.
system and certifi TLS modes.http://, they have no effect.--ca-bundle <path> - Path to a custom CA certificate bundle (PEM) for P4 Code Review API requests.
P4MCP_TLS_CA_MODE=certifi to take effect. In the default system mode, truststore uses the OS trust store and ignores this setting.--ca-bundle and --ssl-no-verify are provided, --ca-bundle takes priority (verification is performed using the specified bundle).Priority order:
--ca-bundle>--ssl-no-verify>P4MCP_CA_BUNDLE>P4MCP_SSL_VERIFY> default (true). CLI args take priority over environment variables.
--log-dir <path> - Directory for log files.
logs/ in the server executable's directory.P4MCP_LOG_DIR environment variable.Priority order:
--log-dir>P4MCP_LOG_DIR> default (logs/in the server executable's directory).
command field in all configurations.Example setup
# Windows (PowerShell)
$env:P4PORT = "ssl:perforce.example.com:1666"
$env:P4USER = "your_username"
$env:P4CLIENT = "your_workspace"
# macOS/Linux (Bash)
export P4PORT="ssl:perforce.example.com:1666"
export P4USER="your_username"
export P4CLIENT="your_workspace"
Manage access through group-level and user-level server properties. P4 resolves each property to a single value using two rules, applied in order:
-s flag is the primary sort key. It applies across all scopes — a group property at -s5 beats a user property at -s1 or default.P4 does not compare values semantically. It does not know that false is more restrictive than true. The winning property's value is returned as-is and checked by the MCP server.
If no property applies, MCP remains enabled unless explicitly disabled.
To disable MCP for all users:
p4 property -a -n mcp.enabled -v false
To re-enable group/user-based control, delete the global property first:
p4 property -d -n mcp.enabled
To prevent access for all members of a specific group:
p4 property -a -n mcp.enabled -v false -g noaccessgroup
You can set multiple group restrictions the same way.
When a user belongs to multiple groups with conflicting settings, P4's property resolution determines which value wins.
The highest sequence number (-s) wins. At equal sequence numbers, the alphabetically-first group name wins.
Example:
p4 property -a -n mcp.enabled -v false -s1 -g noaccessgroup
p4 property -a -n mcp.enabled -v true -s2 -g accessgroup
In this example, accessgroup wins because -s2 is higher than -s1.
To block a specific user regardless of group membership:
p4 property -a -n mcp.enabled -v false -u noaccessuser
At the same sequence number, user-level properties override group-level and global settings (P4's scope tiebreaker).
Example: Even if noaccessuser is in accessgroup (where MCP is enabled), the user property at the same sequence takes precedence and MCP is disabled.
Note: A group property at a higher
-svalue can override a user property at a lower sequence number. To ensure a user-level property always wins, give it a high-svalue or ensure no group properties use a higher sequence.
Restrict which toolsets are available server-wide using mcp.toolsets.allowed. Only listed toolsets will be enabled; all others are blocked.
Available toolsets: server, changelists, files, jobs, reviews, shelves, workspaces, streams
Allow only changelists and files:
p4 property -a -n mcp.toolsets.allowed -v changelists,files
Remove the allowlist to restore all toolsets:
p4 property -d -n mcp.toolsets.allowed
Disable all write operations (modify tools) while keeping read operations (query tools) available:
p4 property -a -n mcp.toolsets.write -v false
Re-enable writes:
p4 property -a -n mcp.toolsets.write -v true
When write=false, all modify_* tools are blocked but all query_* tools continue to work.
Enable or disable individual toolsets for a specific group.
Disable a toolset for a specific group:
p4 property -a -n mcp.toolset.changelists.enabled -v false -g reviewers
Users in reviewers are blocked from changelists. Users in other groups (with no explicit setting) retain default access.
To restrict a toolset to only one group, disable it for every other group that should not have access:
p4 property -a -n mcp.toolset.files.enabled -v false -g reviewers
p4 property -a -n mcp.toolset.files.enabled -v false -g interns
# Only groups without an explicit "false" retain default access to files
Note: All toolsets are enabled by default. Setting
enabled=truefor a group is redundant unless you are explicitly overriding a previousfalsesetting. At the same sequence number, a group property overrides a global property (P4's scope tiebreaker), so a groupenabled=truecan override a globalenabled=false. To ensure a global setting cannot be overridden, give it a high-svalue. To isolate a toolset to specific groups, disable it for the groups you want to block.
Control write access for each toolset at the group level.
Disable writes for a specific toolset per group:
p4 property -a -n mcp.toolset.workspaces.write -v false -g reviewers
This blocks modify_workspaces for the group while query_workspaces remains accessible.
Restrict a group to specific tools within a toolset using mcp.toolset.<name>.tools.
Allow only query_files (block modify_files) for developers:
p4 property -a -n mcp.toolset.files.tools -v query_files -g developers
Allow both query and modify for leads:
p4 property -a -n mcp.toolset.reviews.tools -v query_reviews,modify_reviews -g leads
Tool-specific overrides can restrict access even when writes are enabled:
p4 property -a -n mcp.toolsets.write -v true
p4 property -a -n mcp.toolset.files.tools -v query_files -g developers
# Result: modify_files is BLOCKED — tool list restricts
Note: Tool-specific overrides cannot bypass write restrictions. The server checks write permissions before evaluating tool lists. If
write=falseis set at any level, write tools are blocked regardless of the tool list.
When a user belongs to multiple groups with conflicting settings, P4 resolves each property to a single value. The MCP server does not perform its own multi-group logic — it uses whichever value P4 returns.
P4's resolution rules for a given property name:
-s (sequence number) wins. This is the primary sort key.P4 does not compare values. It picks the winning entry by position, not by content.
Example — groups at the same sequence (default):
p4 property -a -n mcp.toolset.files.enabled -v true -g developers
p4 property -a -n mcp.toolset.files.enabled -v false -g leads
# User in both groups → resolved value is "true"
# Reason: "developers" < "leads" alphabetically, so developers wins
Swapping the values would give false — developers still wins regardless of the value.
Example — only one group has a setting:
p4 property -a -n mcp.toolset.files.enabled -v false -g leads
# developers has no setting
# User in developers + leads → resolved value is "false"
# Reason: leads is the only group with a value, so it wins
Example — write access:
p4 property -a -n mcp.toolset.files.write -v false -g developers
p4 property -a -n mcp.toolset.files.write -v true -g leads
# User in both groups → resolved value is "false"
# Reason: "developers" < "leads" alphabetically, not because false is "more restrictive"
Example — tool lists (no union):
p4 property -a -n mcp.toolset.reviews.tools -v query_reviews -g developers
p4 property -a -n mcp.toolset.reviews.tools -v query_reviews,modify_reviews -g leads
# User in both groups → resolved value is "query_reviews"
# Reason: "developers" wins alphabetically. P4 returns one value, not a union.
Example — using -s to control which group wins:
p4 property -a -n mcp.enabled -v false -s1 -g noaccessgroup
p4 property -a -n mcp.enabled -v true -s2 -g accessgroup
# accessgroup wins because -s2 > -s1 (highest sequence wins)
Tip: To get predictable results with multiple groups, always use explicit
-svalues rather than relying on alphabetical group name ordering.
Disable a single toolset for all users without affecting others:
p4 property -a -n mcp.toolset.reviews.enabled -v false
This blocks both query_reviews and modify_reviews for all users. Other toolsets remain unaffected.
Restrict a specific group to read-only without affecting other groups:
p4 property -a -n mcp.toolsets.write -v false -g problematic_group
Users in other groups retain full write access. If a user belongs to both the restricted group and an unrestricted group, P4's property resolution determines the outcome — typically the alphabetically-first group name wins at equal sequence numbers. Use explicit -s values for predictable results.
The MCP server checks properties in this order. Each property is resolved independently by P4 using the standard resolution rules (highest -s wins, then user > group > global at equal sequence, then alphabetically-first group name).
| Check order | Property | MCP server behavior |
|---|---|---|
| 1 | mcp.enabled | If resolved value is false, block all access |
| 2 | mcp.toolsets.write | If resolved value is false and tool is a write operation, block |
| 3 | mcp.toolsets.allowed | If set, only listed toolsets are available |
| 4 | mcp.toolset.<name>.enabled | If resolved value is false, block the toolset |
| 5 | mcp.toolset.<name>.write | If resolved value is false and tool is a write operation, block |
| 6 | mcp.toolset.<name>.tools | If set, only listed tools within the toolset are available |
Important notes
Each property is resolved to a single value by P4 before the MCP server sees it. P4 uses: highest sequence number (-s) first, then scope (user > group > global) as a tiebreaker, then alphabetical group name. The MCP server does not perform its own multi-group or multi-scope resolution.
mcp.enabled acts as the main switch. When its resolved value is false, all access is blocked.
At the same sequence number, a group or user property overrides a global property. To ensure a global false cannot be overridden, assign it a high -s value.
Scope hierarchy (user > group > global) only applies as a tiebreaker at equal sequence numbers. A group property at -s5 will beat a user property at default sequence or -s1.
When a user belongs to multiple groups, the alphabetically-first group name wins (at equal -s). The winning value is used as-is — P4 does not compare true vs false or pick the "most restrictive" value. Use explicit -s values to control which group takes priority.
Tool-specific overrides (mcp.toolset.<name>.tools) can further restrict access but cannot bypass write restrictions. Write checks are evaluated before tool lists.
Property changes take effect within 60 seconds due to server-side caching, or immediately on a new MCP server connection.
Only the value false (case-insensitive) disables or blocks access. Any other value (including true, 1, yes, or invalid strings) is treated as not blocking.
query_server - Get server information and current user detailsserver_info - Get P4 version, uptime, and configurationcurrent_user - Get current user information and permissionsquery_workspaces - Workspace information and managementlist - List all workspaces (optionally filtered by user)get - Get a detailed workspace specificationtype - Check workspace type and configurationstatus - Check workspace sync statusworkspace_name, user, max_resultsquery_changelists - Access changelist information and historyget - Get detailed changelist information (files, description, jobs)list - List changelists with filters (status, user, workspace)changelist_id, status (pending/submitted), workspace_name, max_resultsquery_files - File operations and informationcontent - Get file content at a specific revisionhistory - Get file revision history and integration recordsinfo - Get file basic details (type, size, permissions)metadata - Get file metadata (attributes, filesize, etc.)diff - Compare file versions (depot-to-depot or mixed)annotations - Get file annotations with blame informationsearch - Search for files by name pattern (wildcard matching)grep - Search for files by content pattern (text search)file_path, file2 (for diff), pattern (for search/grep), case_insensitive (for grep), max_results, diff2 (boolean)query_shelves - Shelved changelist operations and inspectionlist - List shelved changes by user or globallydiff - Show differences in shelved filesfiles - List files in a specific shelfchangelist_id, user, max_resultsquery_jobs - Job tracking and defect managementlist_jobs - List jobs associated with a changelistget_job - Get detailed job information and statuschangelist_id, job_id, max_resultsquery_reviews - Review discovery, details, and activitylist - List all reviews with optional filteringdashboard - Get current user's review dashboard (my reviews, needs attention)get - Get detailed review informationtransitions - Get available state transitions for a reviewfiles_readby - Get files read status by usersfiles - Get files in a review (with optional version range)activity - Get review activity historycomments - Get comments on a reviewreview_id - Review ID (required for get, transitions, files_readby, files, comments, activity)review_fields - Comma-separated fields to return (e.g., "id,description,author,state")comments_fields - Fields for comments (default: "id,body,user,time")up_voters - List of up voters for transitionsfrom_version, to_version - Version range for files actionmax_results - Maximum results (default: 10)query_streams - Stream hierarchy, integration status, and workspace validationlist - List streams with optional filters (path pattern, owner, type)get - Get a detailed stream specificationchildren - Get child streams of a given streamparent - Get the parent streamgraph - Get the full stream graph (parent + children)integration_status - Get integration status between stream and parent (p4 istat)get_workspace - Get a workspace spec bound to a streamlist_workspaces - List workspaces bound to a streamvalidate_file - Validate file paths against a stream's viewvalidate_submit - Validate opened files for submit in a stream workspacecheck_resolve - Check for pending stream spec conflictsinterchanges - List changelists awaiting integration between streamsstream_name - Stream depot path (required for get, children, parent, graph, check_resolve, interchanges)stream_path - Path pattern(s) for list (e.g., ["//depot/..."])filter - Filter expression for list (e.g., "Owner=alice&Type=development")fields - Fields to return for list (e.g., ["Stream", "Owner", "Type"])workspace - Workspace name for get_workspace, validate_file, validate_submitfile_paths - File paths for validate_fileview_without_edit - View locked stream spec without opening for editat_change - Retrieve historical stream spec at a changelist numberboth_directions - Show integration status in both directionsforce_refresh - Force istat cache refreshreverse, long_output, limit - Options for interchangesunloaded, all_streams, viewmatch - Filters for listmax_results - Maximum resultsmodify_workspaces - Workspace creation and managementcreate, update, delete, switchname, specs (WorkspaceSpec object with View, Root, Options, etc.)modify_changelists - Changelist lifecycle managementcreate, update, submit, delete, move_fileschangelist_id, description, file_pathsmodify_files - File system operations and version controladd, edit, delete, move, revert, reconcile, resolve, syncfile_paths, changelist, force, mode (for resolve operations)auto, safe, force, preview, theirs, yoursmodify_shelves - Shelving operations for work in progressshelve, unshelve, update, delete, unshelve_to_changelistchangelist_id, file_paths, target_changelist, forcemodify_jobs - Job and changelist integrationlink_job, unlink_jobchangelist_id, job_idmodify_reviews - Review creation, transitions, participants, and commentscreate - Create a new review from a changelistrefresh_projects - Refresh project associationsvote - Vote on a review (up, down, clear)transition - Change review state (needsRevision, needsReview, approved, committed, rejected, archived)append_participants - Add reviewers/groups to a reviewreplace_participants - Replace all participantsdelete_participants - Remove participants from a reviewadd_comment - Add a comment to a reviewreply_comment - Reply to an existing commentappend_change - Add a changelist to an existing reviewreplace_with_change - Replace review content with a changelistjoin - Join a review as a participantleave - Leave a reviewarchive_inactive - Archive inactive reviewsmark_comment_read / mark_comment_unread - Mark individual comment read statusmark_all_comments_read / mark_all_comments_unread - Mark all comments read statusupdate_author - Change the review authorupdate_description - Update review descriptionobliterate - Permanently delete a reviewreview_id - Review ID (required for most actions)change_id - Changelist ID (required for create, append_change, replace_with_change)description - Review descriptionreviewers, required_reviewers - Lists of reviewer usernamesreviewer_groups - Reviewer groups with requirementsvote_value - Vote value: up, down, clearversion - Review version for votingtransition - Target state: needsRevision, needsReview, approved, committed, approved:commit, rejected, archivedjobs, fix_status, cleanup - Job linking and cleanup options for transitionsusers, groups - Structured participant data for append/replace/deletebody - Comment body texttask_state - Comment task state: open, commentnotify - Notification mode: immediate, delayedcomment_id - Comment ID for replies or marking read/unreadcontext - Comment context (file, line numbers, content, version)not_updated_since, max_reviews - Filters for archive_inactivenew_author, new_description - Values for update actionsmodify_streams - Stream lifecycle, spec editing, propagation, and workspace managementcreate - Create a new stream (mainline, development, release, task, virtual, etc.)update - Update stream properties (name, description, options, paths, parent_view)delete - Delete a streamedit_spec - Open stream spec for editing (p4 stream edit)resolve_spec - Resolve stream spec conflictsrevert_spec - Revert stream spec editsshelve_spec - Shelve stream spec edits to a numbered changelistunshelve_spec - Unshelve stream spec editscopy - Copy changes between parent and child streamsmerge - Merge changes between parent and child streamsintegrate - Integrate changes with advanced optionspopulate - Populate a new stream with files (branch)switch - Switch a workspace to a different streamcreate_workspace - Create a new workspace bound to a streamstream_name - Stream depot path (required for create, update, delete, edit_spec, resolve_spec, revert_spec, switch)stream_type - Stream type for create: mainline, development, sparsedev, release, sparserel, task, virtualparent - Parent stream for non-mainline createname, description - Stream display name and descriptionoptions - Stream options: allsubmit/ownersubmit, unlocked/locked, toparent/notoparent, fromparent/nofromparent, mergedown/mergeanyparent_view - Parent view treatment: inherit or noinheritpaths, remapped, ignored - Stream view mappingschangelist - Changelist for spec editing or propagation operationsresolve_mode - Resolve mode for resolve_spec: auto, accept_theirs, accept_yoursparent_stream - Override parent for propagation (-P flag)branch - Branch spec for integrate/populate (-b flag)file_paths - File paths for propagationpreview - Preview only, no changes (-n flag)force - Force operation (-f flag)reverse - Reverse direction (-r flag)max_files - Limit files processed (-m flag)quiet - Suppress informational messages (-q flag)output_base - Show base revision with scheduled resolve (-Ob flag for merge/integrate) or list files created (-o flag for populate)virtual - Copy using virtual stream (-v flag, copy only)schedule_branch_resolve - Schedule branch resolves instead of automatic branching (-Rb flag, integrate only)integrate_around_deleted - Integrate around deleted revisions (-Di flag, integrate only)skip_cherry_picked - Skip cherry-picked revisions already integrated (-Rs flag, integrate only)source_path, target_path - Source and target paths for populateworkspace - Workspace name for switchworkspace_name, root, host, alt_roots - Workspace creation parametersLog locations:
logs/p4mcp.log - Main server operations and errorslogs/sessions/*.log - Individual session activities are recorded only when the --allow-usage flag is specified in the server's startup arguments.Privacy-first approach:
Data collected (if consented):
Data not collected:
Control:
--allow-usage argument is provided at startup.Symptoms: OS cannot find or execute the binary; error includes ENOENT or "No such file or directory".
Solutions:
command field uses the correct absolute path for your OS:
/absolute/path/to/p4-mcp-serverC:\absolute\path\to\p4-mcp-server.exels -l /absolute/path/to/p4-mcp-server && chmod +x /absolute/path/to/p4-mcp-server
dir C:\absolute\path\to\p4-mcp-server.exe
.exe file, select Properties, and if present, click Unblock.Symptoms: Cannot connect to P4 Server
Solutions:
P4PORT environment variable: echo $P4PORT (macOS) or echo $env:P4PORT (Windows)p4 infoping perforce.example.comssl: prefix for SSL connections).Symptoms: SSL trust errors when connecting to the P4 server Solutions:
p4 trust -f -yp4 trust -lSymptoms: CERTIFICATE_VERIFY_FAILED errors when using review tools
Solutions:
truststore. Ensure your corporate CA is installed in the OS certificate store.P4MCP_TLS_CA_MODE=certifi (to disable truststore), then provide the CA path via --ca-bundle /path/to/ca.pem or P4MCP_CA_BUNDLE. In the default system mode, truststore overrides custom CA bundles and they are silently ignored.--ssl-no-verify or set P4MCP_SSL_VERIFY=false (not recommended for production). This works in both TLS modes.Note: These SSL settings only apply when the Swarm URL uses HTTPS. If Swarm is configured with an
http://URL, SSL verification is not performed and these settings have no effect.
Symptoms: Authentication failures
Solutions:
p4 login -ap4 login -sp4 users -m 1 your_usernameSymptoms: Login failures
Solutions:
p4 login -ap4 infoSymptoms: Workspace not found errors
Solutions:
p4 clientsP4CLIENT environment variable.p4 client workspace_namep4 client -o workspace_nameSymptoms: Files are outside the workspace mapping
Solutions:
p4 client -o workspace_namep4 where file_path to check the mapping.Symptoms: Insufficient permissions for operations
Solutions:
p4 opened file_pathp4 protects file_pathSymptoms: Exclusive lock conflicts
Solutions:
p4 opened file_pathSymptoms: Long response times
Solutions:
max_results parameter to limit the query size.Symptoms: High memory usage
Solutions:
max_results for large queries.Symptoms: Conflict with built-in or other MCP tools
Solutions:
Symptoms: Invalid context or outdated session history
Solutions:
logs/p4mcp.log first.p4 info works before troubleshooting MCP.Perforce P4 MCP Server is a community supported project and is not officially supported by Perforce. Pull requests and issues are the responsibility of the project's moderator(s); this may be a vetted individual or team with members outside of the Perforce organization. All issues should be reported and managed via GitHub (not via Perforce's standard support process).
We welcome contributions to the P4 MCP Server project.
This project is licensed under the MIT License. See LICENSE for details.
This project includes third-party components. Their licenses and attributions are listed in THIRD-PARTY-NOTICES.
P4PORTPerforce server address (e.g. ssl:perforce.example.com:1666)
P4USERPerforce username
P4CLIENTPerforce workspace/client name
P4PASSWDPerforce password or ticket