local-code-mcp
Provides read-only Git repository access, enabling status, diff, and log inspection for configured projects.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@local-code-mcpCan you list the files in project-a?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
local-code-mcp
A security-first Model Context Protocol (MCP) server for inspecting and editing multiple local repositories over STDIO. Repository roots are configured on the server and exposed to clients only through explicit project aliases.
Tiếng Việt · WSL + ChatGPT Secure MCP Tunnel runbook
Design goals
No arbitrary shell tool.
No client-supplied repository roots.
No mutable “current project” state.
Independent path sandboxing for every configured project.
Read-only Git access.
Atomic text-file writes with secret and path protections.
Project-specific, allowlisted test commands executed with
spawn()andshell: false.
Related MCP server: local-code-mcp
Requirements
Node.js 18 or newer
npm
Git for the Git tools
Optional: ripgrep for faster
search_code; the server has a built-in literal-search fallback whenrgis unavailable
End-to-end flow
From a clean checkout to a client that can call tools:
Step | Command | Result |
1. Install and verify |
|
|
2. Configure roots | copy | aliases mapped to absolute roots |
3. Smoke-test locally |
|
|
4a. Use from Codex CLI |
| tools available in Codex |
4b. Use from ChatGPT |
| tools available in a developer-mode app — full setup in the Secure MCP Tunnel runbook |
5. Verify from the client |
| reads and writes reach the right repository |
6. After changing this server |
| clients pick up the new build |
Step 6 matters: tunnel-client and Codex spawn dist/index.js once and keep that process, so a rebuild alone changes nothing until the parent is restarted.
For ChatGPT specifically, the runbook covers the parts this README does not: installing tunnel-client, creating the tunnel and runtime key, initializing and running the profile, the developer-mode app, verification, and troubleshooting.
Install and verify
npm install
npm run typecheck
npm test
npm run buildThe build output is dist/. The server entry point is dist/index.js.
Configure projects
Set PROJECTS_CONFIG to a non-empty JSON object whose keys are aliases and whose values are absolute repository paths:
export PROJECTS_CONFIG='{
"project-a": "/home/example/projects/project-a",
"project-b": "/home/example/projects/project-b",
"project-c": "/home/example/projects/project-c"
}'At startup, the server:
accepts aliases matching
[a-zA-Z0-9_-]+;requires every root to be an existing absolute directory;
canonicalizes every root with
realpath;rejects duplicate canonical roots; and
exits before accepting requests if the configuration is missing or invalid.
Only aliases are logged or returned to clients. Clients cannot submit raw repository roots.
Run
node dist/index.jsThis is a STDIO server. It normally waits silently for JSON-RPC input; operational logs go to stderr, while stdout is reserved for MCP traffic.
For Codex CLI, copy start-mcp.example.sh to an untracked start-mcp.sh, replace the example paths, make it executable, and register it:
chmod 0755 /absolute/path/to/local-code-mcp/start-mcp.sh
codex mcp add local-code -- /absolute/path/to/local-code-mcp/start-mcp.sh
codex mcp listTo connect this private STDIO server to ChatGPT, follow the Secure MCP Tunnel runbook. In short: tunnel-client init --profile <profile> …, tunnel-client doctor --profile <profile> --explain, then keep tunnel-client run --profile <profile> in the foreground while ChatGPT discovers and calls tools.
After changing server code
npm run typecheck && npm test && npm run buildThen restart the process that spawns dist/index.js — tunnel-client run (Ctrl+C, start it again) or the Codex session. Until that restart, clients keep talking to the previously loaded build.
Tool reference
Except for list_projects, every tool requires a project alias.
Tool | Inputs | Behavior and limits |
| none | Returns configured aliases only. |
|
| Lists from |
|
| Reads UTF-8 text with numbered lines. Rejects binary files and files larger than 2,000,000 bytes. Response text is capped at 500,000 characters. |
|
| Performs a literal search from |
|
| Creates or replaces one UTF-8 text file, up to 2,000,000 bytes, using a same-directory temporary file and atomic rename. Replaced files keep their previous mode and ownership; new files are created |
|
| Runs |
|
| Runs |
|
| Runs |
|
| Runs only a server-defined command for the selected alias. Timeout: 120 seconds. Combined stdout/stderr capture is capped independently at 500,000 characters. |
Test allowlist
The allowlist is the TEST_COMMANDS map in src/git-tools.ts. Each entry is a fixed argv, never a shell string, and deployments edit the map for their own aliases:
Project alias | Test name | Command |
|
| deployment-defined argv |
|
| deployment-defined argv |
|
| deployment-defined argv |
Other aliases can use repository and Git tools, but run_tests returns COMMAND_NOT_ALLOWED until a command is explicitly added for that alias. Test arguments are passed as an argv array, limited to 20 strings, and reject shell metacharacters, newlines, absolute paths, and .. path components.
Security model
Path containment
Every repository path is resolved relative to the selected canonical root. Lexical traversal, absolute paths outside the root, and symlink escapes are rejected with PATH_OUTSIDE_PROJECT_ROOT. Directory listings do not follow symlinks.
Blocked content
Direct paths passed to read_file and write_file reject these names anywhere in the relative path:
directories:
.git,.ssh,.aws,.gnupg,node_modules, andvendor;files:
.env,.env.*,*.pem,*.key,*.p12,*.pfx,id_rsa,id_ed25519, andauthorized_keys.
.git is blocked in full rather than only .git/objects: git executes the values of core.fsmonitor, core.pager, and aliases from .git/config, and runs .git/hooks/*, so a writable .git would turn this server's own Git tools into arbitrary command execution.
The denylist is applied by read_file, write_file, list_files, and both search_code implementations, so blocked files are neither read, written, listed, nor matched. It is still a last line of defense, not a substitute for choosing narrow project roots and running the process with least privilege.
Commands and Git
All child processes use spawn(command, args, { shell: false }) with a fixed command and argument structure. There is no generic command-execution tool. Git exposure is intentionally limited to status, diff, and log; the server does not expose commit, push, reset, clean, checkout, merge, or rebase operations.
Child processes do not inherit the server environment. They receive only PATH, HOME, LANG, LC_ALL, TZ, TERM, USER, and LOGNAME, so PROJECTS_CONFIG and any tunnel credentials stay in the server process. A deployment that needs another variable (for example COMPOSER_HOME) lists its name in MCP_CHILD_ENV_ALLOWLIST, which can never re-add PROJECTS_CONFIG.
Writes
write_file validates the destination before writing, refuses blocked paths and symlink escapes, writes a mode-0600 temporary file in the destination directory, and atomically renames it into place. Because rename replaces the inode, the mode and ownership of the file being replaced are restored explicitly before the rename; otherwise an edit would narrow an existing 0644 repository file to 0600 and break the runtime user that serves it. New files are created 0644. The file and its directory are synced so the replacement survives power loss, not only a process crash. It does not create parent directories. Filesystem errors are mapped to safe error codes without returning stack traces.
Logging
Each tool call writes one JSON record to stderr containing timestamp, alias, tool, the requested path (or .), success status, and duration; failures also carry the returned code and an operator-only detail field. File contents, configured roots, and environment values are not included. Because rejected client input is still logged, operators must protect stderr logs appropriately.
Error codes
Expected failures include:
PROJECT_CONFIG_INVALID,PROJECT_ALIAS_INVALID,PROJECT_ROOT_INVALIDPROJECT_NOT_FOUND,INVALID_ARGUMENT,UNKNOWN_TOOLPATH_OUTSIDE_PROJECT_ROOT,BLOCKED_FILEFILE_TOO_LARGE,BINARY_FILECOMMAND_NOT_ALLOWED,COMMAND_FAILED,COMMAND_TIMEOUTWRITE_PERMISSION_DENIED,WRITE_FAILEDINTERNAL_ERRORfor anything unmapped
MCP tool failures are returned with isError: true and a text payload in the form CODE: message. Only the codes above are ever returned: an unmapped failure becomes INTERNAL_ERROR: Tool execution failed, because a raw errno such as EACCES carries a Node message containing server-side absolute paths, and reporting an internal fault as INVALID_ARGUMENT sends the client into retrying arguments that were never wrong. Messages are redacted of configured roots and truncated to 2,000 characters; the full cause is written to stderr only.
Development
npm run typecheck
npm test
npm run buildnpm run typecheck checks src/ and tests/ against tsconfig.json; npm run build emits dist/ from tsconfig.build.json.
Add or update tests whenever path handling, blocked content, command execution, writes, or project isolation changes. Keep Git access read-only and never add a generic shell interface.
Files
src/index.ts— MCP tool registration, dispatch, and client-safe error mappingsrc/config.ts— project-alias configurationsrc/security.ts— root containment, blocked-path policy, root redactionsrc/fs-tools.ts—list_files,read_file,search_codesrc/git-tools.ts— read-only Git tools and theTEST_COMMANDSallowlistsrc/write-file.ts— validated atomic writessrc/command.ts— boundedspawn()wrapper and child-environment allowlistsrc/errors.ts— error-code allowlist and redactionsrc/tool-input.ts,src/limits.ts— argument validation and shared boundssrc/logger.ts— structuredstderraudit recordstests/— security, write, filesystem-tool, error-mapping, command, and isolation testsstart-mcp.example.sh— local launcher template
Handling secrets
Never commit API keys, .env files, tunnel credentials, local tunnel profiles, private certificates, or a machine-specific start-mcp.sh. Review repository changes before committing.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Alicense-qualityCmaintenanceA secure, git-aware MCP server for working with local repositories, enabling file management, shell commands, and full git operations within allowed directories.1951GPL 3.0
- Flicense-qualityBmaintenanceProfile-driven MCP server for safely inspecting and changing local Git repositories via a Streamable HTTP endpoint with deny-by-default security.1
- AlicenseAqualityBmaintenanceA local MCP server that provides a safe, explicit set of Git operations for version control tasks like status, diff, branching, staging, committing, fetching, merging, and pushing.1345MIT
- Alicense-qualityAmaintenanceA local MCP server that lets Claude Code and Codex delegate repository exploration and test proposals to a remote LM Studio model, while enforcing security boundaries by keeping all repository access read-only and never applying patches or running commands remotely.8531MIT
Related MCP Connectors
A MCP server built for developers enabling Git based project management with project and personal…
An MCP server for deep research or task groups
An MCP server that gives your AI access to the source code and docs of all public github repos
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/jutlyne/codex-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server