# Phase 2: Per-Agent MCP Server Support — Specification

**Priority:** P1 · **Effort:** 2–3 days · **Dependencies:** None  
**Reference:** `claude-code-main/src/tools/AgentTool/runAgent.ts` (`initializeAgentMcpServers`)

---

## 1. Problem Statement

Claude Code agents can declare their own MCP servers in frontmatter (`mcpServers`). These are connected when the agent starts and cleaned up when it finishes. They are **additive** to the parent session's MCP clients — an agent can have database access, Slack integration, browser automation, or any other MCP-powered capability without burdening the parent.

pi-subagents has no per-agent MCP support. All agents inherit the parent's MCP context. This limits agent autonomy — an Explore agent that needs to query a database, or a Plan agent that needs to check issue trackers, can't do so unless the parent already has those MCP servers.

---

## 2. Design

### 2.1. MCP Server Specification

Agent frontmatter supports an `mcpServers` array. Each entry is either:

**Named reference** (string): refers to an MCP server configured in the parent session.

```yaml
# .pi/agents/data-explorer.md
name: data-explorer
description: Database exploration agent
mcpServers:
  - postgres
  - slack
```

**Inline definition** (object): defines a new MCP server inline (agent-specific, cleaned up with agent).

```yaml
mcpServers:
  - my-db:
      command: npx
      args: ["@modelcontextprotocol/server-postgres", "postgresql://..."]
```

### 2.2. Merge Strategy

1. Start with the **parent's MCP clients** (cloned or shared)
2. For each `mcpServers` entry:
   - **String reference**: look up in parent's MCP config, use memoized connection
   - **Inline definition**: create a new connection, mark as "agent-owned"
3. Fetch tools from each connected server
4. Deduplicate tools by name (parent tools take precedence)
5. Pass merged clients + tools to the agent session

### 2.3. Cleanup Strategy

- **Named references** point to shared/memoized connections — do NOT clean up
- **Inline definitions** are agent-owned — disconnect on agent completion (success, error, or abort)
- Cleanup runs in a `finally` block after the agent execution loop

### 2.4. Plugin-Only Policy

If the pi ecosystem has a plugin-only policy for MCP, respect it:
- Plugin agents and built-in agents: always allow frontmatter MCP
- User-controlled agents: skip frontmatter MCP when locked to plugin-only

---

## 3. API Changes

### 3.1. `AgentConfig` Interface — New Field

```typescript
export interface AgentConfig {
  // ...existing fields...

  /** MCP servers for this agent. String = reference to parent config.
   *  Object = inline definition { name: config }. Additive to parent clients. */
  mcpServers?: Array<string | Record<string, McpServerConfig>>;
}
```

### 3.2. `AgentDefinition` Frontmatter — New Schema Field

```yaml
---
name: my-agent
description: Description
mcpServers:
  - some-existing-server
  - my-inline-db:
      command: npx
      args: ["-y", "@modelcontextprotocol/server-db"]
---
```

### 3.3. `agent-runner.ts` — New Initialization Step

In `runAgent()` or equivalent, before creating the session:

```typescript
const { clients: mergedClients, tools: mcpTools, cleanup } =
  await initializeAgentMcpServers(agentConfig, parentMcpClients);
```

### 3.4. Option: McpServerConfig Type

If pi doesn't have an existing MCP server config schema, define a minimal one:

```typescript
interface McpServerConfig {
  command: string;
  args?: string[];
  env?: Record<string, string>;
  /** Whether stdio transport uses shell (default: false) */
  shell?: boolean;
}
```

---

## 4. Integration Points

| File | Change |
|---|---|
| `src/types.ts` | Add `mcpServers` to `AgentConfig` |
| `src/agent-runner.ts` | Initialize agent MCP servers before session creation |
| `src/custom-agents.ts` | Parse `mcpServers` from frontmatter YAML |
| `src/index.ts` | Pass parent MCP clients to agent spawn |

---

## 5. Edge Cases

| Case | Behavior |
|---|---|
| Named server doesn't exist in config | Log warning, skip (don't fail agent) |
| Inline server fails to connect | Log warning, skip (don't fail agent) |
| Plugin-only policy restricts agents | Skip MCP init for non-admin agents |
| Duplicate tool names across servers | Deduplicate, parent tools win |
| Agent creates the same inline server twice | Clean up only the first (or deduplicate by name) |

---

## 6. Testing Plan

| Test | What it verifies |
|---|---|
| Empty mcpServers | Returns parent clients as-is |
| Named reference only | Looks up in config, merges |
| Inline definition | Creates new connection, cleans up on completion |
| Mixed references + inline | Both paths work together |
| Tool deduplication | Duplicate tool names resolved correctly |
| Cleanup on error | Inline servers cleaned up even on agent error |
| Policy restricted | MCP init skipped for non-admin agents |
