
Verified the scope of what AI can and cannot handle when operating from Claude Code via Perforce P4 MCP
This page has been translated by machine translation. View original
Introduction
Git has become naturally usable from AI agents like Claude Code. It can explain diffs, generate commit messages, and even help resolve conflicts. On the other hand, you don't hear much about similar AI integration for Perforce, which is used in game development and other fields.
In this article, I connect the Perforce P4 MCP server p4mcp-server to Claude Code and empirically determine what AI can and cannot handle for both querying and writing. To state the conclusion upfront: text-related tasks such as querying change history and generating changelist descriptions worked well with AI, while binary file contents could not be handled by AI.
This article also includes the steps from setup to connection so you can reproduce everything locally.
What is Perforce?
Perforce is a centralized version control system widely used in development environments that handle large-volume binaries with many contributors. It sees heavy adoption in game development, and is characterized by exclusive locking where files are edited by one person at a time, and partial sync where only the needed files are retrieved. The server process is called p4d, and the client is called p4.
Verification Environment
- macOS
- Helix Core p4d 2025.2
- p4mcp-server 2026.3
- Claude Code
- uv and Python 3.14
Target Audience
- Those who operate Perforce and want to know how far AI can be leveraged
- Those who handle large-volume binaries and find tracking change history and reviews tedious
- Those who want to connect an MCP server to actual business tools
References
- P4 MCP Product Page
- P4 MCP Server Documentation
- perforce/p4mcp-server (GitHub)
- Model Context Protocol
Background and Problem Statement
In Perforce operations, you manage things like who introduced a change, what a changelist was intended for, how a file has changed recently, and how newcomers can trace past history. With Git, you can simply ask Claude Code, but whether the same approach was available for Perforce had not been clearly established until now.
There is a structural reason behind this. The core of Perforce is managing large-volume binaries that cannot be merged. In this domain, large language models (LLMs) cannot read the contents, making it hard to see the benefits of AI. This is in contrast to Git, whose core—text diffs—aligns well with what LLMs excel at.
However, upon investigation, Perforce was providing a Community Supported MCP server on its official GitHub. The first release in the repository was in September 2025. In this article, I identify what this MCP actually solves and what it does not. I verify through testing whether AI can handle text-related research such as change history and reviews, and whether AI can ease the management of binary assets themselves.
Verification Method
I set up Perforce locally, created a change history containing both text and binaries, then connected p4mcp-server to Claude Code. I first tested read-only queries, then also tested writes.
Starting p4d
Perforce's p4d and p4 can be obtained from the official download page.
mkdir -p p4root
p4d -r "$PWD/p4root" -p 1666 -L "$PWD/p4d.log" -J "$PWD/p4root/journal" -d
# Disable authentication for verification. Do not use this in production.
p4 -p 1666 configure set security=0
Creating Change History with Two Users
To make queries meaningful, I create history involving two users, tester_a and tester_b, including text files, exclusively locked binaries, and non-exclusively locked binaries.
2-sample-history.sh
export P4PORT=1666
# Create workspace for tester_a
P4USER=tester_a P4CLIENT=ws_a p4 client -i <<EOF
Client: ws_a
Owner: tester_a
Root: $PWD/ws_a
View:
//depot/... //ws_a/...
EOF
mkdir -p ws_a && cd ws_a
# CL1: Text and exclusively locked binary
printf 'baseline notes\n' > notes.txt
head -c 1048576 /dev/urandom > assetX.bin
p4 -u tester_a -c ws_a add -t text notes.txt
p4 -u tester_a -c ws_a add -t binary+l assetX.bin
p4 -u tester_a -c ws_a submit -d "baseline: notes.txt and assetX.bin"
# CL2: Add non-exclusively locked binary
head -c 524288 /dev/urandom > assetW.bin
p4 -u tester_a -c ws_a add -t binary+w assetW.bin
p4 -u tester_a -c ws_a submit -d "add assetW.bin (binary+w)"
# CL3: tester_a edits assetW
p4 -u tester_a -c ws_a edit assetW.bin
head -c 524288 /dev/urandom > assetW.bin
p4 -u tester_a -c ws_a submit -d "A edits assetW"
cd ..
# Create workspace for tester_b and edit assetW (CL4)
P4USER=tester_b P4CLIENT=ws_b p4 client -i <<EOF
Client: ws_b
Owner: tester_b
Root: $PWD/ws_b
View:
//depot/... //ws_b/...
EOF
mkdir -p ws_b && cd ws_b
p4 -u tester_b -c ws_b sync
p4 -u tester_b -c ws_b edit assetW.bin
head -c 524288 /dev/urandom > assetW.bin
p4 -u tester_b -c ws_b submit -d "B edits assetW"
cd ..
Connecting the MCP Server to Claude Code
p4mcp-server can be obtained via uvx. Since I test both querying and writing in this article, I connect two instances under different names: one read-only and one writable.
# For querying: read-only. Write tools are not exposed.
claude mcp add p4lab \
--env P4PORT=localhost:1666 --env P4USER=tester_a --env P4CLIENT=ws_a \
-- uvx p4mcp-server --readonly
# For writing: without --readonly
claude mcp add p4lab-rw \
--env P4PORT=localhost:1666 --env P4USER=tester_a --env P4CLIENT=ws_a \
-- uvx p4mcp-server
After connecting, confirm that both show as connected in Claude Code's /mcp. With read-only p4lab, only the 8 query tools are exposed and write tools do not appear. Use p4lab-rw for write testing.
Verification Results
Querying (read-only)
First, when I asked for information about the connected server, it returned the server version, address, and authenticated user in a table.
[Prompt]
Tell me about the connected Perforce server
[Response (excerpt)]
Here is the information about the connected Perforce server.
## Server
| Item | Value |
|---|---|
| Server Address | `localhost:1666` |
| Server Version | P4D/MACOSX12ARM64/2025.2/2907753 (2026/03/09) |
| Service Type | standard |
| License | none (not set) |
## Authenticated User
| Item | Value |
|---|---|
| User | `tester_a` |
| Type | standard |
| Authentication Method | perforce |
This is a verification P4D server running locally (`localhost:1666`).
Next, I asked it to list the change history in reverse chronological order and provide a summary. It compiled who changed what into a table with bullet points, and even picked up on the differences in file types.
[Prompt]
List the changelists in reverse chronological order. Summarize who changed what.
[Response (supplementary notes omitted)]
Here are the changelists listed in reverse chronological order. All 6 are submitted to `//depot`, with 2 users: `tester_a` and `tester_b`.
## Changelists in Reverse Chronological Order
| CL | Date/Time (JST) | User | Summary |
|---|---|---|---|
| 6 | 07/18 20:30 | tester_a | Branch creation to branch1 (lazy copy) |
| 5 | 07/18 20:08 | tester_a | Added model.uasset |
| 4 | 07/18 20:05 | tester_b | Edited assetW.bin |
| 3 | 07/18 20:05 | tester_a | Edited assetW.bin |
| 2 | 07/18 20:04 | tester_a | Added assetW.bin |
| 1 | 07/18 20:02 | tester_a | Baseline creation |
## Who Changed What (Details)
- CL4 — tester_b "B edits assetW": edited assetW.bin (rev.3). Type is binary+w (non-exclusive). Following tester_a's edit in CL3, a different user was able to update the same file.
- CL1 — tester_a "baseline: notes.txt (text), assetX/Y.bin (binary+l)": added notes.txt (text), assetX.bin and assetY.bin with exclusive lock (binary+l).
The output varies depending on the depot history, but this shows that understanding change history and reading file types can be delegated to natural language. Text file contents are also readable without issue. When I asked about notes.txt, it was displayed as-is.
[Prompt]
Show me the contents of //depot/notes.txt
[Response]
Here are the contents of `//depot/notes.txt` (rev.1, text, 21 bytes).
```
baseline notes
line2
```
There have been no changes since it was added in the CL1 baseline (still at rev.1).
Up to this point, the experience is on par with Git.
Binaries, however, are handled differently. When I asked to see the contents of //depot/assetX.bin, Claude recognized it as a 1 MB binary and determined there was no point in displaying it as-is. Rather than proceeding to dump the contents, it showed metadata such as type, size, and digest, and asked how I wanted to view it—through change history, a diff against another revision, or checking the actual local file. Claude itself noted that dumping binary contents to the terminal would consume an enormous number of tokens and was not practical.
[Prompt]
Show me the contents of //depot/assetX.bin
[Response]
`//depot/assetX.bin` is a **binary file** (type: `binary+l`, size 1,048,576 bytes = 1MB). Since it is not text, displaying the raw contents would not produce meaningful information and would not fit in the terminal.
The metadata is as follows:
| Item | Value |
|------|-----|
| head Rev | #2 (CL2) |
| Type | binary+l (binary with exclusive lock) |
| Size | 1,048,576 bytes (1MB) |
| digest | 05DE508D48FD6E6CB0D6236D77FC0BB4 |
This digest matches `//depot/branch1/assetX.bin` #1 branched in CL6, confirming that branch1 is a lazy copy of this content.
Note: Directly dumping binary+l binary contents to the terminal consumes an enormous number of tokens and is not practical, so I am avoiding displaying it as-is.
I also checked what would happen if I forced retrieval of the contents. When the query tool's content was applied directly to a binary, the return value ballooned to 1,575,604 characters, exceeded the token limit, and could not fit in Claude Code's context, being offloaded to an external file. This confirms that feeding binary contents to AI produces no meaningful information even if you force it.
Writing
First, I had AI generate a changelist description and create the changelist. This is equivalent to generating a commit message in Git.
[Prompt]
Please create a pending changelist with the description "Update baseline notes in notes.txt"
[Response]
A pending changelist has been created.
| Item | Value |
|------|-----|
| Changelist | 9 |
| Status | pending |
| Description | Update baseline notes in notes.txt |
| User / Client | tester_a / ws_a |
No files have been added yet (empty pending).
The creation succeeded without issue. Since the description is text, writing is also within AI's domain of strength.
Next, I tried opening a file for editing. This is equivalent to a p4 edit operation.
[Prompt]
Please open //depot/notes.txt for editing
[Response]
`//depot/notes.txt` has been opened for editing.
| Item | Value |
|------|-----|
| Changelist | 9 (pending) |
| Depot File | `//depot/notes.txt` |
| Target Revision | #1 → editing |
| action | edit |
| Type | text+D |
The local notes.txt is now writable and has been added to CL9.
It was opened for editing. The file was placed in the CL9 that was created earlier.
I then asked to move this edit into a new changelist and shelve it (i.e., stash it for later).
[Prompt]
Please put the open //depot/notes.txt into a new pending changelist and shelve it
[Response]
Done.
## Actions Taken
| Step | Result |
|---------|------|
| Created new pending changelist | CL10 (description: "Changelist for shelving notes.txt edits") |
| Moved file | Moved `//depot/notes.txt` from CL9 → CL10 |
| Shelve | Shelved `//depot/notes.txt` #1 (edit) in CL10 |
## Current State
- CL10 (pending): `//depot/notes.txt` is open for edit and shelved.
- CL9 (pending): The file has been removed, leaving it empty.
Creating the changelist, moving the file, and shelving were all accomplished with a single natural language instruction. All of these are non-destructive operations, so they proceed smoothly.
Next, I asked to delete the created changelists as a destructive operation. Claude cleaned up the shelved files and open files before proceeding with the deletion.
[Prompt]
Please delete the created changelists
[Response (excerpt)]
I will delete both (CL9 and CL10). I will proceed in this order: delete CL10's shelve → revert files → delete changelists.
## Actions Taken
| Step | Result |
|---|---|
| Delete CL10 shelve | Deleted shelve of `//depot/notes.txt` |
| Revert file | Reverted `//depot/notes.txt` (no effect since unchanged) |
| Delete CL10 | Change 10 deleted |
| Delete CL9 | Change 9 deleted |
No open files or pending changelists remain. Returned to a clean state.
However, this deletion did not execute immediately. For destructive operations like deleting a shelve or changelist, the MCP server requests confirmation and a dialog appears in Claude Code. The deletion will not execute unless you approve it by selecting PROCEED.
Discussion
These results clearly illustrate the boundary of what AI can handle.
Binary contents produce no meaningful information when passed to AI as-is. It is nothing more than an endless stream of escaped characters byte by byte, and forcing retrieval can even exceed the token limit. That is precisely why capable AI avoids dumping the raw contents and instead makes judgments using metadata and digest. In fact, Claude demonstrated this by using the digest to verify that the original file and its branched copy were identical in content.
Text, on the other hand, is within AI's domain of strength not just for reading but also for writing. Generating changelist descriptions can be delegated to natural language, and confirmation is required for destructive operations like deletion.
In other words, what MCP can handle is text-related work such as understanding change history and summarizing or creating changelists. The concerns raised by the target readers at the beginning fall within this scope. Meanwhile, the core purpose of Perforce—managing large-volume binaries—is not something AI can make easier. The boundary of what AI can and cannot handle maps directly onto the boundary between text and binary in Perforce.
Summary
Perforce can be operated from AI through MCP, and text-related tasks ranging from querying change history to generating changelist descriptions can be delegated to natural language. Confirmation is required for destructive operations like deletion. However, binary file contents cannot be passed to AI, and the scope of what is handleable is limited to text and metadata. I hope this article serves as a useful reference for deciding how to combine Perforce with AI.
