@leo000001/claude-code-mcp 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -0
- package/LICENSE +21 -0
- package/README.md +192 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +651 -0
- package/dist/index.js.map +1 -0
- package/package.json +68 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.1.0 (2026-02-11)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
- New tool: `claude_code_configure` for runtime bypass mode management (enable/disable without restart)
|
|
7
|
+
- New parameters for `claude_code`: `additionalDirectories`, `outputFormat`, `thinking`
|
|
8
|
+
- Effort level now supports `"max"` in addition to low/medium/high
|
|
9
|
+
|
|
10
|
+
### Improvements
|
|
11
|
+
- README: Added Prerequisites section clarifying Claude Code CLI dependency
|
|
12
|
+
- README: Removed ANTHROPIC_API_KEY from environment variables (handled by CLI)
|
|
13
|
+
- DESIGN.md: Updated to reflect 4-tool architecture
|
|
14
|
+
|
|
15
|
+
## 1.0.0 (2026-02-11)
|
|
16
|
+
|
|
17
|
+
### Features
|
|
18
|
+
- Initial release
|
|
19
|
+
- 3 MCP tools: `claude_code`, `claude_code_reply`, `claude_code_session`
|
|
20
|
+
- Session management with resume and fork support
|
|
21
|
+
- Fine-grained permission control (default, acceptEdits, bypassPermissions, plan, delegate, dontAsk)
|
|
22
|
+
- Custom subagent definitions
|
|
23
|
+
- Effort level control (low, medium, high)
|
|
24
|
+
- Beta features support (e.g., 1M context window)
|
|
25
|
+
- Cost and turn tracking per session
|
|
26
|
+
- Session cancellation via AbortController
|
|
27
|
+
- Auto-cleanup for idle (30min) and stuck running (4h) sessions
|
|
28
|
+
- Security: bypassPermissions disabled by default (CLAUDE_CODE_MCP_ALLOW_BYPASS env var)
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 claude-code-mcp contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# claude-code-mcp
|
|
2
|
+
|
|
3
|
+
MCP server that wraps [Claude Code (Claude Agent SDK)](https://docs.anthropic.com/en/docs/claude-code/overview) as tools, enabling any MCP client to invoke Claude Code for autonomous coding tasks.
|
|
4
|
+
|
|
5
|
+
Inspired by the [Codex MCP](https://developers.openai.com/codex/guides/agents-sdk/) design philosophy — minimum tools, maximum capability.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **4 tools** covering the full agent lifecycle: start, continue, manage, configure
|
|
10
|
+
- **Session management** with resume and fork support
|
|
11
|
+
- **Fine-grained permissions** — tool whitelist/blacklist, permission modes
|
|
12
|
+
- **Custom subagents** — define specialized agents per session
|
|
13
|
+
- **Cost tracking** — per-session turn and cost accounting
|
|
14
|
+
- **Session cancellation** via AbortController
|
|
15
|
+
- **Auto-cleanup** — 30-minute idle timeout for expired sessions
|
|
16
|
+
- **Security** — `bypassPermissions` disabled by default
|
|
17
|
+
|
|
18
|
+
## Prerequisites
|
|
19
|
+
|
|
20
|
+
This MCP server invokes the **Claude Code CLI** installed on your local machine. You must have Claude Code CLI installed and configured (including API key setup) before using this MCP server.
|
|
21
|
+
|
|
22
|
+
- Install Claude Code CLI: see [Claude Code documentation](https://docs.anthropic.com/en/docs/claude-code/overview)
|
|
23
|
+
- Configure your API key in the CLI (e.g. `claude config set apiKey sk-ant-...`)
|
|
24
|
+
|
|
25
|
+
> **Note:** This MCP server does **not** handle API key configuration — it delegates all API calls to the locally installed Claude Code CLI.
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
### As an MCP server (recommended)
|
|
30
|
+
|
|
31
|
+
Add to your MCP client configuration (Claude Desktop, Cursor, etc.):
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"mcpServers": {
|
|
36
|
+
"claude-code": {
|
|
37
|
+
"command": "npx",
|
|
38
|
+
"args": ["claude-code-mcp"]
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### OpenAI Codex CLI
|
|
45
|
+
|
|
46
|
+
Add to your Codex configuration file (`~/.codex/config.toml`):
|
|
47
|
+
|
|
48
|
+
```toml
|
|
49
|
+
[mcp_servers.claude-code]
|
|
50
|
+
command = "npx"
|
|
51
|
+
args = ["claude-code-mcp"]
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Or with custom options:
|
|
55
|
+
|
|
56
|
+
```toml
|
|
57
|
+
[mcp_servers.claude-code]
|
|
58
|
+
command = "npx"
|
|
59
|
+
args = ["claude-code-mcp"]
|
|
60
|
+
enabled = true
|
|
61
|
+
# tool_timeout_sec = 120
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### From source
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
git clone https://github.com/anthropics/claude-code-mcp.git
|
|
68
|
+
cd claude-code-mcp
|
|
69
|
+
npm install
|
|
70
|
+
npm run build
|
|
71
|
+
npm start
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Tools
|
|
75
|
+
|
|
76
|
+
### `claude_code` — Start a new session
|
|
77
|
+
|
|
78
|
+
Start a Claude Code agent that can read/write files, run commands, and more.
|
|
79
|
+
|
|
80
|
+
| Parameter | Type | Required | Description |
|
|
81
|
+
| ----------------------- | -------- | -------- | -------------------------------------------------------------------------------------------------------- |
|
|
82
|
+
| `prompt` | string | Yes | Task or question for Claude Code |
|
|
83
|
+
| `cwd` | string | No | Working directory (defaults to server cwd) |
|
|
84
|
+
| `allowedTools` | string[] | No | Tool whitelist (e.g. `["Read","Edit","Bash"]`) |
|
|
85
|
+
| `disallowedTools` | string[] | No | Tool blacklist |
|
|
86
|
+
| `permissionMode` | string | No | `"default"`, `"acceptEdits"`, `"bypassPermissions"`, `"plan"`, `"delegate"`, `"dontAsk"` |
|
|
87
|
+
| `maxTurns` | number | No | Maximum agentic turns |
|
|
88
|
+
| `model` | string | No | Model to use (e.g. `"claude-sonnet-4-5-20250929"`) |
|
|
89
|
+
| `systemPrompt` | string | No | Custom system prompt |
|
|
90
|
+
| `agents` | object | No | Custom subagent definitions |
|
|
91
|
+
| `maxBudgetUsd` | number | No | Maximum budget in USD |
|
|
92
|
+
| `effort` | string | No | Effort level: `"low"`, `"medium"`, `"high"`, `"max"` |
|
|
93
|
+
| `betas` | string[] | No | Beta features (e.g. `["context-1m-2025-08-07"]`) |
|
|
94
|
+
| `additionalDirectories` | string[] | No | Additional directories the agent can access beyond cwd |
|
|
95
|
+
| `outputFormat` | object | No | Output format: `{ type: "text" }` or `{ type: "json", schema: {...} }` |
|
|
96
|
+
| `thinking` | object | No | Thinking mode: `{ type: "adaptive" }`, `{ type: "enabled", budgetTokens: N }`, or `{ type: "disabled" }` |
|
|
97
|
+
|
|
98
|
+
**Returns:** `{ sessionId, result, isError, durationMs, numTurns, totalCostUsd }`
|
|
99
|
+
|
|
100
|
+
### `claude_code_reply` — Continue a session
|
|
101
|
+
|
|
102
|
+
Continue an existing session with full context preserved.
|
|
103
|
+
|
|
104
|
+
| Parameter | Type | Required | Description |
|
|
105
|
+
| ------------- | ------- | -------- | --------------------------------------------- |
|
|
106
|
+
| `sessionId` | string | Yes | Session ID from a previous `claude_code` call |
|
|
107
|
+
| `prompt` | string | Yes | Follow-up prompt |
|
|
108
|
+
| `forkSession` | boolean | No | Fork to a new session (preserves original) |
|
|
109
|
+
|
|
110
|
+
### `claude_code_session` — Manage sessions
|
|
111
|
+
|
|
112
|
+
List, inspect, or cancel sessions.
|
|
113
|
+
|
|
114
|
+
| Parameter | Type | Required | Description |
|
|
115
|
+
| ----------- | ------ | -------------- | -------------------------------- |
|
|
116
|
+
| `action` | string | Yes | `"list"`, `"get"`, or `"cancel"` |
|
|
117
|
+
| `sessionId` | string | For get/cancel | Target session ID |
|
|
118
|
+
|
|
119
|
+
### `claude_code_configure` — Runtime configuration
|
|
120
|
+
|
|
121
|
+
Enable or disable `bypassPermissions` mode at runtime without restarting the server.
|
|
122
|
+
|
|
123
|
+
| Parameter | Type | Required | Description |
|
|
124
|
+
| --------- | ------ | -------- | -------------------------------------------------------- |
|
|
125
|
+
| `action` | string | Yes | `"enable_bypass"`, `"disable_bypass"`, or `"get_config"` |
|
|
126
|
+
|
|
127
|
+
**Returns:** `{ allowBypass, message }`
|
|
128
|
+
|
|
129
|
+
## Usage Example
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
# 1. Start a new session
|
|
133
|
+
result = await mcp.call_tool("claude_code", {
|
|
134
|
+
"prompt": "Fix the authentication bug in src/auth.ts",
|
|
135
|
+
"cwd": "/path/to/project",
|
|
136
|
+
"allowedTools": ["Read", "Edit", "Bash", "Glob", "Grep"],
|
|
137
|
+
"permissionMode": "acceptEdits"
|
|
138
|
+
})
|
|
139
|
+
session_id = json.loads(result)["sessionId"]
|
|
140
|
+
|
|
141
|
+
# 2. Continue the session
|
|
142
|
+
result = await mcp.call_tool("claude_code_reply", {
|
|
143
|
+
"sessionId": session_id,
|
|
144
|
+
"prompt": "Now add unit tests for the fix"
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
# 3. List all sessions
|
|
148
|
+
result = await mcp.call_tool("claude_code_session", {
|
|
149
|
+
"action": "list"
|
|
150
|
+
})
|
|
151
|
+
|
|
152
|
+
# 4. Cancel a running session
|
|
153
|
+
result = await mcp.call_tool("claude_code_session", {
|
|
154
|
+
"action": "cancel",
|
|
155
|
+
"sessionId": session_id
|
|
156
|
+
})
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Security
|
|
160
|
+
|
|
161
|
+
- **`bypassPermissions` is disabled by default.** Set `CLAUDE_CODE_MCP_ALLOW_BYPASS=1` to enable.
|
|
162
|
+
- Use `allowedTools` / `disallowedTools` to restrict agent capabilities.
|
|
163
|
+
- `maxTurns` and `maxBudgetUsd` prevent runaway execution.
|
|
164
|
+
- Sessions auto-expire after 30 minutes of inactivity.
|
|
165
|
+
|
|
166
|
+
## Environment Variables
|
|
167
|
+
|
|
168
|
+
| Variable | Description |
|
|
169
|
+
| ------------------------------ | ------------------------------------------------------ |
|
|
170
|
+
| `CLAUDE_CODE_MCP_ALLOW_BYPASS` | Set to `1` or `true` to allow `bypassPermissions` mode |
|
|
171
|
+
|
|
172
|
+
## Development
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
npm install # Install dependencies
|
|
176
|
+
npm run build # Build with tsup
|
|
177
|
+
npm run typecheck # Type check with tsc
|
|
178
|
+
npm test # Run tests with vitest
|
|
179
|
+
npm run dev # Watch mode build
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Architecture
|
|
183
|
+
|
|
184
|
+
```
|
|
185
|
+
MCP Client ←→ (stdio/JSON-RPC) ←→ MCP Server
|
|
186
|
+
├── Session Manager (Map<id, state>)
|
|
187
|
+
└── Claude Agent SDK (query())
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
MIT
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,651 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
|
|
6
|
+
// src/server.ts
|
|
7
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
|
|
10
|
+
// src/session/manager.ts
|
|
11
|
+
var SESSION_TTL_MS = 30 * 60 * 1e3;
|
|
12
|
+
var RUNNING_SESSION_MAX_MS = 4 * 60 * 60 * 1e3;
|
|
13
|
+
var SessionManager = class {
|
|
14
|
+
sessions = /* @__PURE__ */ new Map();
|
|
15
|
+
cleanupTimer;
|
|
16
|
+
constructor() {
|
|
17
|
+
this.cleanupTimer = setInterval(() => this.cleanup(), 6e4);
|
|
18
|
+
}
|
|
19
|
+
create(params) {
|
|
20
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
21
|
+
const info = {
|
|
22
|
+
sessionId: params.sessionId,
|
|
23
|
+
status: "running",
|
|
24
|
+
createdAt: now,
|
|
25
|
+
lastActiveAt: now,
|
|
26
|
+
totalTurns: 0,
|
|
27
|
+
totalCostUsd: 0,
|
|
28
|
+
cwd: params.cwd,
|
|
29
|
+
model: params.model,
|
|
30
|
+
permissionMode: params.permissionMode ?? "default",
|
|
31
|
+
abortController: params.abortController
|
|
32
|
+
};
|
|
33
|
+
this.sessions.set(params.sessionId, info);
|
|
34
|
+
return info;
|
|
35
|
+
}
|
|
36
|
+
get(sessionId) {
|
|
37
|
+
return this.sessions.get(sessionId);
|
|
38
|
+
}
|
|
39
|
+
list() {
|
|
40
|
+
return Array.from(this.sessions.values());
|
|
41
|
+
}
|
|
42
|
+
update(sessionId, patch) {
|
|
43
|
+
const info = this.sessions.get(sessionId);
|
|
44
|
+
if (!info) return void 0;
|
|
45
|
+
Object.assign(info, patch, { lastActiveAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
46
|
+
return info;
|
|
47
|
+
}
|
|
48
|
+
cancel(sessionId) {
|
|
49
|
+
const info = this.sessions.get(sessionId);
|
|
50
|
+
if (!info) return false;
|
|
51
|
+
if (info.abortController) {
|
|
52
|
+
info.abortController.abort();
|
|
53
|
+
}
|
|
54
|
+
info.status = "cancelled";
|
|
55
|
+
info.lastActiveAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
delete(sessionId) {
|
|
59
|
+
return this.sessions.delete(sessionId);
|
|
60
|
+
}
|
|
61
|
+
/** Remove sessions that have been idle for too long, or stuck running too long */
|
|
62
|
+
cleanup() {
|
|
63
|
+
const now = Date.now();
|
|
64
|
+
for (const [id, info] of this.sessions) {
|
|
65
|
+
const lastActive = new Date(info.lastActiveAt).getTime();
|
|
66
|
+
if (Number.isNaN(lastActive)) {
|
|
67
|
+
this.sessions.delete(id);
|
|
68
|
+
} else if (info.status === "running" && now - lastActive > RUNNING_SESSION_MAX_MS) {
|
|
69
|
+
if (info.abortController) info.abortController.abort();
|
|
70
|
+
info.status = "error";
|
|
71
|
+
} else if (info.status !== "running" && now - lastActive > SESSION_TTL_MS) {
|
|
72
|
+
this.sessions.delete(id);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/** Serialize session info for external consumption (strip internal fields) */
|
|
77
|
+
toJSON(info) {
|
|
78
|
+
const { abortController: _, ...rest } = info;
|
|
79
|
+
return rest;
|
|
80
|
+
}
|
|
81
|
+
destroy() {
|
|
82
|
+
clearInterval(this.cleanupTimer);
|
|
83
|
+
for (const info of this.sessions.values()) {
|
|
84
|
+
if (info.status === "running" && info.abortController) {
|
|
85
|
+
info.abortController.abort();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
this.sessions.clear();
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// src/tools/claude-code.ts
|
|
93
|
+
import { query } from "@anthropic-ai/claude-agent-sdk";
|
|
94
|
+
|
|
95
|
+
// src/types.ts
|
|
96
|
+
var PERMISSION_MODES = [
|
|
97
|
+
"default",
|
|
98
|
+
"acceptEdits",
|
|
99
|
+
"bypassPermissions",
|
|
100
|
+
"plan",
|
|
101
|
+
"delegate",
|
|
102
|
+
"dontAsk"
|
|
103
|
+
];
|
|
104
|
+
var EFFORT_LEVELS = ["low", "medium", "high", "max"];
|
|
105
|
+
var AGENT_MODELS = ["sonnet", "opus", "haiku", "inherit"];
|
|
106
|
+
var CONFIGURE_ACTIONS = ["enable_bypass", "disable_bypass", "get_config"];
|
|
107
|
+
var SESSION_ACTIONS = ["list", "get", "cancel"];
|
|
108
|
+
|
|
109
|
+
// src/tools/claude-code.ts
|
|
110
|
+
async function executeClaudeCode(input, sessionManager, serverCwd, allowBypass = false) {
|
|
111
|
+
const cwd = input.cwd || serverCwd;
|
|
112
|
+
const abortController = new AbortController();
|
|
113
|
+
let sessionId = "";
|
|
114
|
+
let resultText = "";
|
|
115
|
+
let isError = false;
|
|
116
|
+
let durationMs = 0;
|
|
117
|
+
let numTurns = 0;
|
|
118
|
+
let totalCostUsd = 0;
|
|
119
|
+
if (input.permissionMode === "bypassPermissions" && !allowBypass) {
|
|
120
|
+
return {
|
|
121
|
+
sessionId: "",
|
|
122
|
+
result: `Error [${"PERMISSION_DENIED" /* PERMISSION_DENIED */}]: bypassPermissions is disabled on this server. Use the claude_code_configure tool with action 'enable_bypass', or set CLAUDE_CODE_MCP_ALLOW_BYPASS=1.`,
|
|
123
|
+
isError: true,
|
|
124
|
+
durationMs: 0,
|
|
125
|
+
numTurns: 0,
|
|
126
|
+
totalCostUsd: 0
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
const options = {
|
|
130
|
+
cwd,
|
|
131
|
+
abortController
|
|
132
|
+
};
|
|
133
|
+
if (input.allowedTools) options.allowedTools = input.allowedTools;
|
|
134
|
+
if (input.disallowedTools) options.disallowedTools = input.disallowedTools;
|
|
135
|
+
if (input.maxTurns) options.maxTurns = input.maxTurns;
|
|
136
|
+
if (input.model) options.model = input.model;
|
|
137
|
+
if (input.maxBudgetUsd) options.maxBudgetUsd = input.maxBudgetUsd;
|
|
138
|
+
if (input.agents) options.agents = input.agents;
|
|
139
|
+
if (input.effort) options.effort = input.effort;
|
|
140
|
+
if (input.betas) options.betas = input.betas;
|
|
141
|
+
if (input.additionalDirectories) options.additionalDirectories = input.additionalDirectories;
|
|
142
|
+
if (input.outputFormat) options.outputFormat = input.outputFormat;
|
|
143
|
+
if (input.thinking) options.thinking = input.thinking;
|
|
144
|
+
if (input.permissionMode) {
|
|
145
|
+
options.permissionMode = input.permissionMode;
|
|
146
|
+
if (input.permissionMode === "bypassPermissions") {
|
|
147
|
+
options.allowDangerouslySkipPermissions = true;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (input.systemPrompt) {
|
|
151
|
+
options.systemPrompt = input.systemPrompt;
|
|
152
|
+
}
|
|
153
|
+
try {
|
|
154
|
+
for await (const message of query({
|
|
155
|
+
prompt: input.prompt,
|
|
156
|
+
options
|
|
157
|
+
})) {
|
|
158
|
+
if (message.type === "system" && message.subtype === "init") {
|
|
159
|
+
sessionId = message.session_id;
|
|
160
|
+
sessionManager.create({
|
|
161
|
+
sessionId,
|
|
162
|
+
cwd,
|
|
163
|
+
model: input.model,
|
|
164
|
+
permissionMode: input.permissionMode,
|
|
165
|
+
abortController
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
if (message.type === "result") {
|
|
169
|
+
const result = message;
|
|
170
|
+
durationMs = result.duration_ms ?? 0;
|
|
171
|
+
numTurns = result.num_turns ?? 0;
|
|
172
|
+
totalCostUsd = result.total_cost_usd ?? 0;
|
|
173
|
+
isError = result.is_error ?? false;
|
|
174
|
+
if (result.subtype === "success") {
|
|
175
|
+
resultText = result.result ?? "";
|
|
176
|
+
} else {
|
|
177
|
+
isError = true;
|
|
178
|
+
resultText = (result.errors ?? []).join("\n") || "Unknown error";
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
} catch (err) {
|
|
183
|
+
isError = true;
|
|
184
|
+
resultText = err instanceof Error ? err.message : String(err);
|
|
185
|
+
if (sessionId) {
|
|
186
|
+
const current = sessionManager.get(sessionId);
|
|
187
|
+
if (current && current.status !== "cancelled") {
|
|
188
|
+
sessionManager.update(sessionId, { status: "error" });
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
if (sessionId) {
|
|
193
|
+
const current = sessionManager.get(sessionId);
|
|
194
|
+
if (current && current.status !== "cancelled") {
|
|
195
|
+
sessionManager.update(sessionId, {
|
|
196
|
+
status: isError ? "error" : "idle",
|
|
197
|
+
totalTurns: numTurns,
|
|
198
|
+
totalCostUsd,
|
|
199
|
+
abortController: void 0
|
|
200
|
+
});
|
|
201
|
+
} else if (current) {
|
|
202
|
+
sessionManager.update(sessionId, {
|
|
203
|
+
totalTurns: numTurns,
|
|
204
|
+
totalCostUsd,
|
|
205
|
+
abortController: void 0
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
} else {
|
|
209
|
+
isError = true;
|
|
210
|
+
const noInitMsg = `Error [${"INTERNAL" /* INTERNAL */}]: No session ID received from agent.`;
|
|
211
|
+
resultText = resultText ? `${noInitMsg} Original: ${resultText}` : noInitMsg;
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
sessionId,
|
|
215
|
+
result: resultText,
|
|
216
|
+
isError,
|
|
217
|
+
durationMs,
|
|
218
|
+
numTurns,
|
|
219
|
+
totalCostUsd
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// src/tools/claude-code-reply.ts
|
|
224
|
+
import { query as query2 } from "@anthropic-ai/claude-agent-sdk";
|
|
225
|
+
async function executeClaudeCodeReply(input, sessionManager, allowBypass = false) {
|
|
226
|
+
const session = sessionManager.get(input.sessionId);
|
|
227
|
+
if (!session) {
|
|
228
|
+
return {
|
|
229
|
+
sessionId: input.sessionId,
|
|
230
|
+
result: `Error [${"SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */}]: Session '${input.sessionId}' not found or expired.`,
|
|
231
|
+
isError: true,
|
|
232
|
+
durationMs: 0,
|
|
233
|
+
numTurns: 0,
|
|
234
|
+
totalCostUsd: 0
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
if (session.status === "running") {
|
|
238
|
+
return {
|
|
239
|
+
sessionId: input.sessionId,
|
|
240
|
+
result: `Error [${"SESSION_BUSY" /* SESSION_BUSY */}]: Session is currently running. Wait for it to complete or cancel it.`,
|
|
241
|
+
isError: true,
|
|
242
|
+
durationMs: 0,
|
|
243
|
+
numTurns: 0,
|
|
244
|
+
totalCostUsd: 0
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
if (session.status === "cancelled") {
|
|
248
|
+
return {
|
|
249
|
+
sessionId: input.sessionId,
|
|
250
|
+
result: `Error [${"CANCELLED" /* CANCELLED */}]: Session '${input.sessionId}' has been cancelled and cannot be resumed.`,
|
|
251
|
+
isError: true,
|
|
252
|
+
durationMs: 0,
|
|
253
|
+
numTurns: 0,
|
|
254
|
+
totalCostUsd: 0
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
if (session.permissionMode === "bypassPermissions" && !allowBypass) {
|
|
258
|
+
return {
|
|
259
|
+
sessionId: input.sessionId,
|
|
260
|
+
result: `Error [${"PERMISSION_DENIED" /* PERMISSION_DENIED */}]: Cannot resume a bypassPermissions session while bypass is disabled. Use the claude_code_configure tool with action 'enable_bypass' first.`,
|
|
261
|
+
isError: true,
|
|
262
|
+
durationMs: 0,
|
|
263
|
+
numTurns: 0,
|
|
264
|
+
totalCostUsd: 0
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
const abortController = new AbortController();
|
|
268
|
+
sessionManager.update(input.sessionId, {
|
|
269
|
+
status: "running",
|
|
270
|
+
abortController
|
|
271
|
+
});
|
|
272
|
+
let resultText = "";
|
|
273
|
+
let isError = false;
|
|
274
|
+
let durationMs = 0;
|
|
275
|
+
let numTurns = 0;
|
|
276
|
+
let totalCostUsd = 0;
|
|
277
|
+
let newSessionId = input.sessionId;
|
|
278
|
+
try {
|
|
279
|
+
const options = {
|
|
280
|
+
resume: input.sessionId,
|
|
281
|
+
abortController
|
|
282
|
+
};
|
|
283
|
+
if (input.forkSession) {
|
|
284
|
+
options.forkSession = true;
|
|
285
|
+
}
|
|
286
|
+
for await (const message of query2({
|
|
287
|
+
prompt: input.prompt,
|
|
288
|
+
options
|
|
289
|
+
})) {
|
|
290
|
+
if (input.forkSession && message.type === "system" && message.subtype === "init") {
|
|
291
|
+
newSessionId = message.session_id;
|
|
292
|
+
sessionManager.create({
|
|
293
|
+
sessionId: newSessionId,
|
|
294
|
+
cwd: session.cwd,
|
|
295
|
+
model: session.model,
|
|
296
|
+
permissionMode: session.permissionMode,
|
|
297
|
+
abortController
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
if (message.type === "result") {
|
|
301
|
+
const result = message;
|
|
302
|
+
durationMs = result.duration_ms ?? 0;
|
|
303
|
+
numTurns = result.num_turns ?? 0;
|
|
304
|
+
totalCostUsd = result.total_cost_usd ?? 0;
|
|
305
|
+
isError = result.is_error ?? false;
|
|
306
|
+
if (result.subtype === "success") {
|
|
307
|
+
resultText = result.result ?? "";
|
|
308
|
+
} else {
|
|
309
|
+
isError = true;
|
|
310
|
+
resultText = (result.errors ?? []).join("\n") || "Unknown error";
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
} catch (err) {
|
|
315
|
+
isError = true;
|
|
316
|
+
resultText = err instanceof Error ? err.message : String(err);
|
|
317
|
+
}
|
|
318
|
+
if (input.forkSession && newSessionId !== input.sessionId) {
|
|
319
|
+
const forkedCurrent = sessionManager.get(newSessionId);
|
|
320
|
+
if (forkedCurrent && forkedCurrent.status !== "cancelled") {
|
|
321
|
+
sessionManager.update(newSessionId, {
|
|
322
|
+
status: isError ? "error" : "idle",
|
|
323
|
+
totalTurns: numTurns,
|
|
324
|
+
totalCostUsd,
|
|
325
|
+
abortController: void 0
|
|
326
|
+
});
|
|
327
|
+
} else if (forkedCurrent) {
|
|
328
|
+
sessionManager.update(newSessionId, {
|
|
329
|
+
totalTurns: numTurns,
|
|
330
|
+
totalCostUsd,
|
|
331
|
+
abortController: void 0
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
const origCurrent = sessionManager.get(input.sessionId);
|
|
335
|
+
if (origCurrent && origCurrent.status !== "cancelled") {
|
|
336
|
+
sessionManager.update(input.sessionId, {
|
|
337
|
+
status: "idle",
|
|
338
|
+
abortController: void 0
|
|
339
|
+
});
|
|
340
|
+
} else if (origCurrent) {
|
|
341
|
+
sessionManager.update(input.sessionId, {
|
|
342
|
+
abortController: void 0
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
const current = sessionManager.get(input.sessionId);
|
|
347
|
+
if (current && current.status !== "cancelled") {
|
|
348
|
+
sessionManager.update(input.sessionId, {
|
|
349
|
+
status: isError ? "error" : "idle",
|
|
350
|
+
totalTurns: (session.totalTurns ?? 0) + numTurns,
|
|
351
|
+
totalCostUsd: (session.totalCostUsd ?? 0) + totalCostUsd,
|
|
352
|
+
abortController: void 0
|
|
353
|
+
});
|
|
354
|
+
} else if (current) {
|
|
355
|
+
sessionManager.update(input.sessionId, {
|
|
356
|
+
totalTurns: (session.totalTurns ?? 0) + numTurns,
|
|
357
|
+
totalCostUsd: (session.totalCostUsd ?? 0) + totalCostUsd,
|
|
358
|
+
abortController: void 0
|
|
359
|
+
});
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
const targetSessionId = input.forkSession ? newSessionId : input.sessionId;
|
|
363
|
+
return {
|
|
364
|
+
sessionId: targetSessionId,
|
|
365
|
+
result: resultText,
|
|
366
|
+
isError,
|
|
367
|
+
durationMs,
|
|
368
|
+
numTurns,
|
|
369
|
+
totalCostUsd
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// src/tools/claude-code-session.ts
|
|
374
|
+
function executeClaudeCodeSession(input, sessionManager) {
|
|
375
|
+
switch (input.action) {
|
|
376
|
+
case "list": {
|
|
377
|
+
const sessions = sessionManager.list().map((s) => sessionManager.toJSON(s));
|
|
378
|
+
return { sessions };
|
|
379
|
+
}
|
|
380
|
+
case "get": {
|
|
381
|
+
if (!input.sessionId) {
|
|
382
|
+
return {
|
|
383
|
+
sessions: [],
|
|
384
|
+
message: `Error [${"INVALID_ARGUMENT" /* INVALID_ARGUMENT */}]: sessionId is required for 'get' action.`,
|
|
385
|
+
isError: true
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
const session = sessionManager.get(input.sessionId);
|
|
389
|
+
if (!session) {
|
|
390
|
+
return {
|
|
391
|
+
sessions: [],
|
|
392
|
+
message: `Error [${"SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */}]: Session '${input.sessionId}' not found.`,
|
|
393
|
+
isError: true
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
return { sessions: [sessionManager.toJSON(session)] };
|
|
397
|
+
}
|
|
398
|
+
case "cancel": {
|
|
399
|
+
if (!input.sessionId) {
|
|
400
|
+
return {
|
|
401
|
+
sessions: [],
|
|
402
|
+
message: `Error [${"INVALID_ARGUMENT" /* INVALID_ARGUMENT */}]: sessionId is required for 'cancel' action.`,
|
|
403
|
+
isError: true
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
const cancelled = sessionManager.cancel(input.sessionId);
|
|
407
|
+
if (!cancelled) {
|
|
408
|
+
return {
|
|
409
|
+
sessions: [],
|
|
410
|
+
message: `Error [${"SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */}]: Session '${input.sessionId}' not found.`,
|
|
411
|
+
isError: true
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
const updated = sessionManager.get(input.sessionId);
|
|
415
|
+
return {
|
|
416
|
+
sessions: updated ? [sessionManager.toJSON(updated)] : [],
|
|
417
|
+
message: `Session '${input.sessionId}' cancelled.`
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
default:
|
|
421
|
+
return {
|
|
422
|
+
sessions: [],
|
|
423
|
+
message: `Error [${"INVALID_ARGUMENT" /* INVALID_ARGUMENT */}]: Unknown action '${input.action}'. Use 'list', 'get', or 'cancel'.`,
|
|
424
|
+
isError: true
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// src/tools/claude-code-configure.ts
|
|
430
|
+
function executeClaudeCodeConfigure(input, config) {
|
|
431
|
+
switch (input.action) {
|
|
432
|
+
case "enable_bypass":
|
|
433
|
+
config.setAllowBypass(true);
|
|
434
|
+
return {
|
|
435
|
+
allowBypass: true,
|
|
436
|
+
message: "bypassPermissions mode is now enabled for this server session. Use with caution."
|
|
437
|
+
};
|
|
438
|
+
case "disable_bypass":
|
|
439
|
+
config.setAllowBypass(false);
|
|
440
|
+
return {
|
|
441
|
+
allowBypass: false,
|
|
442
|
+
message: "bypassPermissions mode is now disabled."
|
|
443
|
+
};
|
|
444
|
+
case "get_config":
|
|
445
|
+
return {
|
|
446
|
+
allowBypass: config.getAllowBypass(),
|
|
447
|
+
message: `Current config: bypassPermissions ${config.getAllowBypass() ? "enabled" : "disabled"}.`
|
|
448
|
+
};
|
|
449
|
+
default:
|
|
450
|
+
return {
|
|
451
|
+
allowBypass: config.getAllowBypass(),
|
|
452
|
+
message: `Error [${"INVALID_ARGUMENT" /* INVALID_ARGUMENT */}]: Unknown action '${input.action}'. Use 'enable_bypass', 'disable_bypass', or 'get_config'.`,
|
|
453
|
+
isError: true
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
// src/server.ts
|
|
459
|
+
var SERVER_VERSION = true ? "1.1.0" : "0.0.0-dev";
|
|
460
|
+
function createServer(serverCwd, opts) {
|
|
461
|
+
const sessionManager = new SessionManager();
|
|
462
|
+
let allowBypass = opts?.allowBypass ?? ["1", "true"].includes(process.env.CLAUDE_CODE_MCP_ALLOW_BYPASS ?? "");
|
|
463
|
+
const config = {
|
|
464
|
+
getAllowBypass: () => allowBypass,
|
|
465
|
+
setAllowBypass: (v) => {
|
|
466
|
+
allowBypass = v;
|
|
467
|
+
}
|
|
468
|
+
};
|
|
469
|
+
const server = new McpServer({
|
|
470
|
+
name: "claude-code-mcp",
|
|
471
|
+
version: SERVER_VERSION
|
|
472
|
+
});
|
|
473
|
+
server.tool(
|
|
474
|
+
"claude_code",
|
|
475
|
+
`Start a new Claude Code agent session to perform coding tasks autonomously.
|
|
476
|
+
The agent can read/write files, run commands, search code, and more.
|
|
477
|
+
Returns a sessionId for continuing the conversation later.`,
|
|
478
|
+
{
|
|
479
|
+
prompt: z.string().describe("The task or question for Claude Code"),
|
|
480
|
+
cwd: z.string().optional().describe("Working directory (defaults to server cwd)"),
|
|
481
|
+
allowedTools: z.array(z.string()).optional().describe("Tool whitelist, e.g. ['Read','Edit','Bash','Glob','Grep']"),
|
|
482
|
+
disallowedTools: z.array(z.string()).optional().describe("Tool blacklist"),
|
|
483
|
+
permissionMode: z.enum(PERMISSION_MODES).optional().describe("Permission mode for the session"),
|
|
484
|
+
maxTurns: z.number().int().positive().optional().describe("Maximum agentic turns"),
|
|
485
|
+
model: z.string().optional().describe("Model to use, e.g. 'claude-sonnet-4-5-20250929'"),
|
|
486
|
+
systemPrompt: z.string().optional().describe("Custom system prompt for the agent"),
|
|
487
|
+
agents: z.record(
|
|
488
|
+
z.string(),
|
|
489
|
+
z.object({
|
|
490
|
+
description: z.string(),
|
|
491
|
+
prompt: z.string(),
|
|
492
|
+
tools: z.array(z.string()).optional(),
|
|
493
|
+
model: z.enum(AGENT_MODELS).optional()
|
|
494
|
+
})
|
|
495
|
+
).optional().describe("Custom subagent definitions"),
|
|
496
|
+
maxBudgetUsd: z.number().positive().optional().describe("Maximum budget in USD for this session"),
|
|
497
|
+
effort: z.enum(EFFORT_LEVELS).optional().describe(
|
|
498
|
+
"Effort level: 'low' (fast), 'medium' (balanced), 'high' (thorough), 'max' (maximum)"
|
|
499
|
+
),
|
|
500
|
+
betas: z.array(z.string()).optional().describe("Beta features to enable (e.g. ['context-1m-2025-08-07'])"),
|
|
501
|
+
additionalDirectories: z.array(z.string()).optional().describe("Additional directories the agent can access beyond cwd"),
|
|
502
|
+
outputFormat: z.union([
|
|
503
|
+
z.object({
|
|
504
|
+
type: z.literal("json"),
|
|
505
|
+
schema: z.record(z.string(), z.unknown()).describe("JSON Schema for structured output")
|
|
506
|
+
}),
|
|
507
|
+
z.object({ type: z.literal("text") })
|
|
508
|
+
]).optional().describe("Output format: 'text' (default) or 'json' with schema"),
|
|
509
|
+
thinking: z.union([
|
|
510
|
+
z.object({ type: z.literal("adaptive") }),
|
|
511
|
+
z.object({
|
|
512
|
+
type: z.literal("enabled"),
|
|
513
|
+
budgetTokens: z.number().int().positive().describe("Token budget for thinking")
|
|
514
|
+
}),
|
|
515
|
+
z.object({ type: z.literal("disabled") })
|
|
516
|
+
]).optional().describe("Thinking mode: 'adaptive' (auto), 'enabled' (with budget), or 'disabled'")
|
|
517
|
+
},
|
|
518
|
+
async (args) => {
|
|
519
|
+
try {
|
|
520
|
+
const result = await executeClaudeCode(args, sessionManager, serverCwd, allowBypass);
|
|
521
|
+
return {
|
|
522
|
+
content: [
|
|
523
|
+
{
|
|
524
|
+
type: "text",
|
|
525
|
+
text: JSON.stringify(result, null, 2)
|
|
526
|
+
}
|
|
527
|
+
],
|
|
528
|
+
isError: result.isError
|
|
529
|
+
};
|
|
530
|
+
} catch (err) {
|
|
531
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
532
|
+
return {
|
|
533
|
+
content: [
|
|
534
|
+
{
|
|
535
|
+
type: "text",
|
|
536
|
+
text: `Error: ${message}`
|
|
537
|
+
}
|
|
538
|
+
],
|
|
539
|
+
isError: true
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
);
|
|
544
|
+
server.tool(
|
|
545
|
+
"claude_code_reply",
|
|
546
|
+
`Continue an existing Claude Code session with full context preserved.
|
|
547
|
+
Claude remembers all files read, analysis done, and conversation history.`,
|
|
548
|
+
{
|
|
549
|
+
sessionId: z.string().describe("The session ID to continue (from a previous claude_code call)"),
|
|
550
|
+
prompt: z.string().describe("Follow-up prompt or instruction"),
|
|
551
|
+
forkSession: z.boolean().optional().describe("Fork to a new session (preserves original session state)")
|
|
552
|
+
},
|
|
553
|
+
async (args) => {
|
|
554
|
+
try {
|
|
555
|
+
const result = await executeClaudeCodeReply(args, sessionManager, allowBypass);
|
|
556
|
+
return {
|
|
557
|
+
content: [
|
|
558
|
+
{
|
|
559
|
+
type: "text",
|
|
560
|
+
text: JSON.stringify(result, null, 2)
|
|
561
|
+
}
|
|
562
|
+
],
|
|
563
|
+
isError: result.isError
|
|
564
|
+
};
|
|
565
|
+
} catch (err) {
|
|
566
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
567
|
+
return {
|
|
568
|
+
content: [
|
|
569
|
+
{
|
|
570
|
+
type: "text",
|
|
571
|
+
text: `Error: ${message}`
|
|
572
|
+
}
|
|
573
|
+
],
|
|
574
|
+
isError: true
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
);
|
|
579
|
+
server.tool(
|
|
580
|
+
"claude_code_session",
|
|
581
|
+
`Manage Claude Code sessions: list all sessions, get status of a specific session, or cancel a running session.`,
|
|
582
|
+
{
|
|
583
|
+
action: z.enum(SESSION_ACTIONS).describe("Action to perform: 'list', 'get', or 'cancel'"),
|
|
584
|
+
sessionId: z.string().optional().describe("Session ID (required for 'get' and 'cancel')")
|
|
585
|
+
},
|
|
586
|
+
async (args) => {
|
|
587
|
+
const result = executeClaudeCodeSession(args, sessionManager);
|
|
588
|
+
return {
|
|
589
|
+
content: [
|
|
590
|
+
{
|
|
591
|
+
type: "text",
|
|
592
|
+
text: JSON.stringify(result, null, 2)
|
|
593
|
+
}
|
|
594
|
+
],
|
|
595
|
+
isError: result.isError ?? false
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
);
|
|
599
|
+
server.tool(
|
|
600
|
+
"claude_code_configure",
|
|
601
|
+
`Configure the Claude Code MCP server at runtime.
|
|
602
|
+
Actions: enable_bypass (allow bypassPermissions mode), disable_bypass, get_config.`,
|
|
603
|
+
{
|
|
604
|
+
action: z.enum(CONFIGURE_ACTIONS).describe("Configuration action to perform")
|
|
605
|
+
},
|
|
606
|
+
async (args) => {
|
|
607
|
+
const result = executeClaudeCodeConfigure(args, config);
|
|
608
|
+
return {
|
|
609
|
+
content: [
|
|
610
|
+
{
|
|
611
|
+
type: "text",
|
|
612
|
+
text: JSON.stringify(result, null, 2)
|
|
613
|
+
}
|
|
614
|
+
],
|
|
615
|
+
isError: result.isError ?? false
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
);
|
|
619
|
+
const originalClose = server.close?.bind(server);
|
|
620
|
+
server.close = async () => {
|
|
621
|
+
sessionManager.destroy();
|
|
622
|
+
if (originalClose) await originalClose();
|
|
623
|
+
};
|
|
624
|
+
return server;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// src/index.ts
|
|
628
|
+
async function main() {
|
|
629
|
+
const serverCwd = process.cwd();
|
|
630
|
+
const server = createServer(serverCwd);
|
|
631
|
+
const transport = new StdioServerTransport();
|
|
632
|
+
let closing = false;
|
|
633
|
+
const shutdown = async () => {
|
|
634
|
+
if (closing) return;
|
|
635
|
+
closing = true;
|
|
636
|
+
try {
|
|
637
|
+
await server.close();
|
|
638
|
+
} catch {
|
|
639
|
+
}
|
|
640
|
+
process.exit(0);
|
|
641
|
+
};
|
|
642
|
+
process.on("SIGINT", shutdown);
|
|
643
|
+
process.on("SIGTERM", shutdown);
|
|
644
|
+
await server.connect(transport);
|
|
645
|
+
console.error(`claude-code-mcp server started (cwd: ${serverCwd})`);
|
|
646
|
+
}
|
|
647
|
+
main().catch((err) => {
|
|
648
|
+
console.error("Fatal error:", err);
|
|
649
|
+
process.exit(1);
|
|
650
|
+
});
|
|
651
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/server.ts","../src/session/manager.ts","../src/tools/claude-code.ts","../src/types.ts","../src/tools/claude-code-reply.ts","../src/tools/claude-code-session.ts","../src/tools/claude-code-configure.ts"],"sourcesContent":["/**\n * claude-code-mcp - MCP server entry point\n *\n * Starts the MCP server with stdio transport.\n * Usage: npx claude-code-mcp\n */\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { createServer } from \"./server.js\";\n\nasync function main(): Promise<void> {\n const serverCwd = process.cwd();\n const server = createServer(serverCwd);\n const transport = new StdioServerTransport();\n\n // Handle graceful shutdown (idempotent)\n let closing = false;\n const shutdown = async () => {\n if (closing) return;\n closing = true;\n try {\n await server.close();\n } catch {\n // Ignore close errors during shutdown\n }\n process.exit(0);\n };\n process.on(\"SIGINT\", shutdown);\n process.on(\"SIGTERM\", shutdown);\n\n await server.connect(transport);\n\n // Log to stderr (stdout is used for MCP communication)\n console.error(`claude-code-mcp server started (cwd: ${serverCwd})`);\n}\n\nmain().catch((err) => {\n console.error(\"Fatal error:\", err);\n process.exit(1);\n});\n","/**\n * MCP Server definition - registers tools and handles requests\n */\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport { SessionManager } from \"./session/manager.js\";\nimport { executeClaudeCode } from \"./tools/claude-code.js\";\nimport { executeClaudeCodeReply } from \"./tools/claude-code-reply.js\";\nimport { executeClaudeCodeSession } from \"./tools/claude-code-session.js\";\nimport { executeClaudeCodeConfigure } from \"./tools/claude-code-configure.js\";\nimport {\n PERMISSION_MODES,\n EFFORT_LEVELS,\n AGENT_MODELS,\n CONFIGURE_ACTIONS,\n SESSION_ACTIONS,\n} from \"./types.js\";\n\ndeclare const __PKG_VERSION__: string;\nconst SERVER_VERSION = typeof __PKG_VERSION__ !== \"undefined\" ? __PKG_VERSION__ : \"0.0.0-dev\";\n\nexport interface ServerOptions {\n /** Allow bypassPermissions mode (default: false, set via CLAUDE_CODE_MCP_ALLOW_BYPASS=1) */\n allowBypass?: boolean;\n}\n\nexport function createServer(serverCwd: string, opts?: ServerOptions): McpServer {\n const sessionManager = new SessionManager();\n let allowBypass =\n opts?.allowBypass ?? [\"1\", \"true\"].includes(process.env.CLAUDE_CODE_MCP_ALLOW_BYPASS ?? \"\");\n\n const config = {\n getAllowBypass: () => allowBypass,\n setAllowBypass: (v: boolean) => {\n allowBypass = v;\n },\n };\n\n const server = new McpServer({\n name: \"claude-code-mcp\",\n version: SERVER_VERSION,\n });\n\n // Tool 1: claude_code - Start a new agent session\n server.tool(\n \"claude_code\",\n `Start a new Claude Code agent session to perform coding tasks autonomously.\nThe agent can read/write files, run commands, search code, and more.\nReturns a sessionId for continuing the conversation later.`,\n {\n prompt: z.string().describe(\"The task or question for Claude Code\"),\n cwd: z.string().optional().describe(\"Working directory (defaults to server cwd)\"),\n allowedTools: z\n .array(z.string())\n .optional()\n .describe(\"Tool whitelist, e.g. ['Read','Edit','Bash','Glob','Grep']\"),\n disallowedTools: z.array(z.string()).optional().describe(\"Tool blacklist\"),\n permissionMode: z\n .enum(PERMISSION_MODES)\n .optional()\n .describe(\"Permission mode for the session\"),\n maxTurns: z.number().int().positive().optional().describe(\"Maximum agentic turns\"),\n model: z.string().optional().describe(\"Model to use, e.g. 'claude-sonnet-4-5-20250929'\"),\n systemPrompt: z.string().optional().describe(\"Custom system prompt for the agent\"),\n agents: z\n .record(\n z.string(),\n z.object({\n description: z.string(),\n prompt: z.string(),\n tools: z.array(z.string()).optional(),\n model: z.enum(AGENT_MODELS).optional(),\n })\n )\n .optional()\n .describe(\"Custom subagent definitions\"),\n maxBudgetUsd: z\n .number()\n .positive()\n .optional()\n .describe(\"Maximum budget in USD for this session\"),\n effort: z\n .enum(EFFORT_LEVELS)\n .optional()\n .describe(\n \"Effort level: 'low' (fast), 'medium' (balanced), 'high' (thorough), 'max' (maximum)\"\n ),\n betas: z\n .array(z.string())\n .optional()\n .describe(\"Beta features to enable (e.g. ['context-1m-2025-08-07'])\"),\n additionalDirectories: z\n .array(z.string())\n .optional()\n .describe(\"Additional directories the agent can access beyond cwd\"),\n outputFormat: z\n .union([\n z.object({\n type: z.literal(\"json\"),\n schema: z.record(z.string(), z.unknown()).describe(\"JSON Schema for structured output\"),\n }),\n z.object({ type: z.literal(\"text\") }),\n ])\n .optional()\n .describe(\"Output format: 'text' (default) or 'json' with schema\"),\n thinking: z\n .union([\n z.object({ type: z.literal(\"adaptive\") }),\n z.object({\n type: z.literal(\"enabled\"),\n budgetTokens: z.number().int().positive().describe(\"Token budget for thinking\"),\n }),\n z.object({ type: z.literal(\"disabled\") }),\n ])\n .optional()\n .describe(\"Thinking mode: 'adaptive' (auto), 'enabled' (with budget), or 'disabled'\"),\n },\n async (args) => {\n try {\n const result = await executeClaudeCode(args, sessionManager, serverCwd, allowBypass);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n isError: result.isError,\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Error: ${message}`,\n },\n ],\n isError: true,\n };\n }\n }\n );\n\n // Tool 2: claude_code_reply - Continue an existing session\n server.tool(\n \"claude_code_reply\",\n `Continue an existing Claude Code session with full context preserved.\nClaude remembers all files read, analysis done, and conversation history.`,\n {\n sessionId: z\n .string()\n .describe(\"The session ID to continue (from a previous claude_code call)\"),\n prompt: z.string().describe(\"Follow-up prompt or instruction\"),\n forkSession: z\n .boolean()\n .optional()\n .describe(\"Fork to a new session (preserves original session state)\"),\n },\n async (args) => {\n try {\n const result = await executeClaudeCodeReply(args, sessionManager, allowBypass);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n isError: result.isError,\n };\n } catch (err: unknown) {\n const message = err instanceof Error ? err.message : String(err);\n return {\n content: [\n {\n type: \"text\" as const,\n text: `Error: ${message}`,\n },\n ],\n isError: true,\n };\n }\n }\n );\n\n // Tool 3: claude_code_session - Manage sessions\n server.tool(\n \"claude_code_session\",\n `Manage Claude Code sessions: list all sessions, get status of a specific session, or cancel a running session.`,\n {\n action: z\n .enum(SESSION_ACTIONS)\n .describe(\"Action to perform: 'list', 'get', or 'cancel'\"),\n sessionId: z.string().optional().describe(\"Session ID (required for 'get' and 'cancel')\"),\n },\n async (args) => {\n const result = executeClaudeCodeSession(args, sessionManager);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n isError: result.isError ?? false,\n };\n }\n );\n\n // Tool 4: claude_code_configure - Runtime configuration\n server.tool(\n \"claude_code_configure\",\n `Configure the Claude Code MCP server at runtime.\nActions: enable_bypass (allow bypassPermissions mode), disable_bypass, get_config.`,\n {\n action: z\n .enum(CONFIGURE_ACTIONS)\n .describe(\"Configuration action to perform\"),\n },\n async (args) => {\n const result = executeClaudeCodeConfigure(args, config);\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify(result, null, 2),\n },\n ],\n isError: result.isError ?? false,\n };\n }\n );\n\n // Cleanup on server close\n const originalClose = server.close?.bind(server);\n server.close = async () => {\n sessionManager.destroy();\n if (originalClose) await originalClose();\n };\n\n return server;\n}\n","/**\n * Session Manager - tracks and manages Claude Code agent sessions\n */\nimport type { SessionInfo, PermissionMode } from \"../types.js\";\n\nconst SESSION_TTL_MS = 30 * 60 * 1000; // 30 minutes idle timeout\nconst RUNNING_SESSION_MAX_MS = 4 * 60 * 60 * 1000; // 4 hours max for running sessions\n\nexport class SessionManager {\n private sessions = new Map<string, SessionInfo>();\n private cleanupTimer: ReturnType<typeof setInterval>;\n\n constructor() {\n // Periodically clean up expired sessions\n this.cleanupTimer = setInterval(() => this.cleanup(), 60_000);\n }\n\n create(params: {\n sessionId: string;\n cwd: string;\n model?: string;\n permissionMode?: PermissionMode;\n abortController?: AbortController;\n }): SessionInfo {\n const now = new Date().toISOString();\n const info: SessionInfo = {\n sessionId: params.sessionId,\n status: \"running\",\n createdAt: now,\n lastActiveAt: now,\n totalTurns: 0,\n totalCostUsd: 0,\n cwd: params.cwd,\n model: params.model,\n permissionMode: params.permissionMode ?? \"default\",\n abortController: params.abortController,\n };\n this.sessions.set(params.sessionId, info);\n return info;\n }\n\n get(sessionId: string): SessionInfo | undefined {\n return this.sessions.get(sessionId);\n }\n\n list(): SessionInfo[] {\n return Array.from(this.sessions.values());\n }\n\n update(\n sessionId: string,\n patch: Partial<Pick<SessionInfo, \"status\" | \"totalTurns\" | \"totalCostUsd\" | \"abortController\">>\n ): SessionInfo | undefined {\n const info = this.sessions.get(sessionId);\n if (!info) return undefined;\n Object.assign(info, patch, { lastActiveAt: new Date().toISOString() });\n return info;\n }\n\n cancel(sessionId: string): boolean {\n const info = this.sessions.get(sessionId);\n if (!info) return false;\n if (info.abortController) {\n info.abortController.abort();\n }\n info.status = \"cancelled\";\n info.lastActiveAt = new Date().toISOString();\n return true;\n }\n\n delete(sessionId: string): boolean {\n return this.sessions.delete(sessionId);\n }\n\n /** Remove sessions that have been idle for too long, or stuck running too long */\n private cleanup(): void {\n const now = Date.now();\n for (const [id, info] of this.sessions) {\n const lastActive = new Date(info.lastActiveAt).getTime();\n if (Number.isNaN(lastActive)) {\n // Invalid timestamp — remove the session\n this.sessions.delete(id);\n } else if (info.status === \"running\" && now - lastActive > RUNNING_SESSION_MAX_MS) {\n // Stuck running session — abort and remove\n if (info.abortController) info.abortController.abort();\n info.status = \"error\";\n } else if (info.status !== \"running\" && now - lastActive > SESSION_TTL_MS) {\n this.sessions.delete(id);\n }\n }\n }\n\n /** Serialize session info for external consumption (strip internal fields) */\n toJSON(info: SessionInfo): Omit<SessionInfo, \"abortController\"> {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { abortController: _, ...rest } = info;\n return rest;\n }\n\n destroy(): void {\n clearInterval(this.cleanupTimer);\n // Cancel all running sessions\n for (const info of this.sessions.values()) {\n if (info.status === \"running\" && info.abortController) {\n info.abortController.abort();\n }\n }\n this.sessions.clear();\n }\n}\n","/**\n * claude_code tool - Start a new Claude Code agent session\n */\nimport { query } from \"@anthropic-ai/claude-agent-sdk\";\nimport type { SessionManager } from \"../session/manager.js\";\nimport type { AgentResult, AgentDefinition, PermissionMode, EffortLevel } from \"../types.js\";\nimport { ErrorCode } from \"../types.js\";\n\nexport interface ClaudeCodeInput {\n prompt: string;\n cwd?: string;\n allowedTools?: string[];\n disallowedTools?: string[];\n permissionMode?: PermissionMode;\n maxTurns?: number;\n model?: string;\n systemPrompt?: string;\n agents?: Record<string, AgentDefinition>;\n maxBudgetUsd?: number;\n effort?: EffortLevel;\n betas?: string[];\n additionalDirectories?: string[];\n outputFormat?: { type: \"json\"; schema: Record<string, unknown> } | { type: \"text\" };\n thinking?:\n | { type: \"adaptive\" }\n | { type: \"enabled\"; budgetTokens: number }\n | { type: \"disabled\" };\n}\n\nexport async function executeClaudeCode(\n input: ClaudeCodeInput,\n sessionManager: SessionManager,\n serverCwd: string,\n allowBypass = false\n): Promise<AgentResult> {\n const cwd = input.cwd || serverCwd;\n const abortController = new AbortController();\n\n let sessionId = \"\";\n let resultText = \"\";\n let isError = false;\n let durationMs = 0;\n let numTurns = 0;\n let totalCostUsd = 0;\n\n // Security: block bypassPermissions unless explicitly allowed\n if (input.permissionMode === \"bypassPermissions\" && !allowBypass) {\n return {\n sessionId: \"\",\n result: `Error [${ErrorCode.PERMISSION_DENIED}]: bypassPermissions is disabled on this server. Use the claude_code_configure tool with action 'enable_bypass', or set CLAUDE_CODE_MCP_ALLOW_BYPASS=1.`,\n isError: true,\n durationMs: 0,\n numTurns: 0,\n totalCostUsd: 0,\n };\n }\n\n // Build options for the Agent SDK query()\n const options: Record<string, unknown> = {\n cwd,\n abortController,\n };\n\n if (input.allowedTools) options.allowedTools = input.allowedTools;\n if (input.disallowedTools) options.disallowedTools = input.disallowedTools;\n if (input.maxTurns) options.maxTurns = input.maxTurns;\n if (input.model) options.model = input.model;\n if (input.maxBudgetUsd) options.maxBudgetUsd = input.maxBudgetUsd;\n if (input.agents) options.agents = input.agents;\n if (input.effort) options.effort = input.effort;\n if (input.betas) options.betas = input.betas;\n if (input.additionalDirectories) options.additionalDirectories = input.additionalDirectories;\n if (input.outputFormat) options.outputFormat = input.outputFormat;\n if (input.thinking) options.thinking = input.thinking;\n\n if (input.permissionMode) {\n options.permissionMode = input.permissionMode;\n if (input.permissionMode === \"bypassPermissions\") {\n options.allowDangerouslySkipPermissions = true;\n }\n }\n\n if (input.systemPrompt) {\n options.systemPrompt = input.systemPrompt;\n }\n\n // No placeholder session - we create the session only after receiving the init message\n try {\n for await (const message of query({\n prompt: input.prompt,\n options: options as any,\n })) {\n if (message.type === \"system\" && message.subtype === \"init\") {\n sessionId = message.session_id;\n sessionManager.create({\n sessionId,\n cwd,\n model: input.model,\n permissionMode: input.permissionMode,\n abortController,\n });\n }\n\n if (message.type === \"result\") {\n const result = message as any;\n durationMs = result.duration_ms ?? 0;\n numTurns = result.num_turns ?? 0;\n totalCostUsd = result.total_cost_usd ?? 0;\n isError = result.is_error ?? false;\n\n if (result.subtype === \"success\") {\n resultText = result.result ?? \"\";\n } else {\n isError = true;\n resultText = (result.errors ?? []).join(\"\\n\") || \"Unknown error\";\n }\n }\n }\n } catch (err: unknown) {\n isError = true;\n resultText = err instanceof Error ? err.message : String(err);\n if (sessionId) {\n // Don't overwrite \"cancelled\" status in catch block\n const current = sessionManager.get(sessionId);\n if (current && current.status !== \"cancelled\") {\n sessionManager.update(sessionId, { status: \"error\" });\n }\n }\n }\n\n // Update session to idle (or error), clear abortController\n // Preserve \"cancelled\" status if session was cancelled during execution\n if (sessionId) {\n const current = sessionManager.get(sessionId);\n if (current && current.status !== \"cancelled\") {\n sessionManager.update(sessionId, {\n status: isError ? \"error\" : \"idle\",\n totalTurns: numTurns,\n totalCostUsd,\n abortController: undefined,\n });\n } else if (current) {\n // Session was cancelled — just clear the abortController and update totals\n sessionManager.update(sessionId, {\n totalTurns: numTurns,\n totalCostUsd,\n abortController: undefined,\n });\n }\n } else {\n // No session ID means something went wrong regardless of result content\n isError = true;\n const noInitMsg = `Error [${ErrorCode.INTERNAL}]: No session ID received from agent.`;\n resultText = resultText ? `${noInitMsg} Original: ${resultText}` : noInitMsg;\n }\n\n return {\n sessionId,\n result: resultText,\n isError,\n durationMs,\n numTurns,\n totalCostUsd,\n };\n}\n","/**\n * Type definitions for claude-code-mcp\n *\n * Shared constants are defined as tuples so both Zod schemas and\n * TypeScript types can derive from the same source of truth.\n */\n\n/** Permission modes supported by Claude Agent SDK */\nexport const PERMISSION_MODES = [\n \"default\",\n \"acceptEdits\",\n \"bypassPermissions\",\n \"plan\",\n \"delegate\",\n \"dontAsk\",\n] as const;\nexport type PermissionMode = (typeof PERMISSION_MODES)[number];\n\n/** Effort levels */\nexport const EFFORT_LEVELS = [\"low\", \"medium\", \"high\", \"max\"] as const;\nexport type EffortLevel = (typeof EFFORT_LEVELS)[number];\n\n/** Subagent model options */\nexport const AGENT_MODELS = [\"sonnet\", \"opus\", \"haiku\", \"inherit\"] as const;\nexport type AgentModel = (typeof AGENT_MODELS)[number];\n\n/** Configure tool actions */\nexport const CONFIGURE_ACTIONS = [\"enable_bypass\", \"disable_bypass\", \"get_config\"] as const;\nexport type ConfigureAction = (typeof CONFIGURE_ACTIONS)[number];\n\n/** Session management actions */\nexport const SESSION_ACTIONS = [\"list\", \"get\", \"cancel\"] as const;\nexport type SessionAction = (typeof SESSION_ACTIONS)[number];\n\n/** Session status */\nexport type SessionStatus = \"idle\" | \"running\" | \"cancelled\" | \"error\";\n\n/** Subagent definition */\nexport interface AgentDefinition {\n description: string;\n prompt: string;\n tools?: string[];\n model?: AgentModel;\n}\n\n/** Session metadata stored by the session manager */\nexport interface SessionInfo {\n sessionId: string;\n status: SessionStatus;\n createdAt: string;\n lastActiveAt: string;\n totalTurns: number;\n totalCostUsd: number;\n cwd: string;\n model?: string;\n permissionMode: PermissionMode;\n abortController?: AbortController;\n}\n\n/** Result returned from a claude_code or claude_code_reply call */\nexport interface AgentResult {\n sessionId: string;\n result: string;\n isError: boolean;\n durationMs: number;\n numTurns: number;\n totalCostUsd: number;\n}\n\n/** Error codes for structured error responses */\nexport enum ErrorCode {\n INVALID_ARGUMENT = \"INVALID_ARGUMENT\",\n SESSION_NOT_FOUND = \"SESSION_NOT_FOUND\",\n SESSION_BUSY = \"SESSION_BUSY\",\n PERMISSION_DENIED = \"PERMISSION_DENIED\",\n TIMEOUT = \"TIMEOUT\",\n CANCELLED = \"CANCELLED\",\n INTERNAL = \"INTERNAL\",\n}\n","/**\n * claude_code_reply tool - Continue an existing Claude Code session\n */\nimport { query } from \"@anthropic-ai/claude-agent-sdk\";\nimport type { SessionManager } from \"../session/manager.js\";\nimport type { AgentResult } from \"../types.js\";\nimport { ErrorCode } from \"../types.js\";\n\nexport interface ClaudeCodeReplyInput {\n sessionId: string;\n prompt: string;\n forkSession?: boolean;\n}\n\nexport async function executeClaudeCodeReply(\n input: ClaudeCodeReplyInput,\n sessionManager: SessionManager,\n allowBypass = false\n): Promise<AgentResult> {\n const session = sessionManager.get(input.sessionId);\n if (!session) {\n return {\n sessionId: input.sessionId,\n result: `Error [${ErrorCode.SESSION_NOT_FOUND}]: Session '${input.sessionId}' not found or expired.`,\n isError: true,\n durationMs: 0,\n numTurns: 0,\n totalCostUsd: 0,\n };\n }\n\n if (session.status === \"running\") {\n return {\n sessionId: input.sessionId,\n result: `Error [${ErrorCode.SESSION_BUSY}]: Session is currently running. Wait for it to complete or cancel it.`,\n isError: true,\n durationMs: 0,\n numTurns: 0,\n totalCostUsd: 0,\n };\n }\n\n if (session.status === \"cancelled\") {\n return {\n sessionId: input.sessionId,\n result: `Error [${ErrorCode.CANCELLED}]: Session '${input.sessionId}' has been cancelled and cannot be resumed.`,\n isError: true,\n durationMs: 0,\n numTurns: 0,\n totalCostUsd: 0,\n };\n }\n\n // Security: block resume/fork of bypassPermissions sessions when bypass is disabled\n if (session.permissionMode === \"bypassPermissions\" && !allowBypass) {\n return {\n sessionId: input.sessionId,\n result: `Error [${ErrorCode.PERMISSION_DENIED}]: Cannot resume a bypassPermissions session while bypass is disabled. Use the claude_code_configure tool with action 'enable_bypass' first.`,\n isError: true,\n durationMs: 0,\n numTurns: 0,\n totalCostUsd: 0,\n };\n }\n\n const abortController = new AbortController();\n sessionManager.update(input.sessionId, {\n status: \"running\",\n abortController,\n });\n\n let resultText = \"\";\n let isError = false;\n let durationMs = 0;\n let numTurns = 0;\n let totalCostUsd = 0;\n let newSessionId = input.sessionId;\n\n try {\n const options: Record<string, unknown> = {\n resume: input.sessionId,\n abortController,\n };\n\n if (input.forkSession) {\n options.forkSession = true;\n }\n\n for await (const message of query({\n prompt: input.prompt,\n options: options as any,\n })) {\n // If forked, capture the new session ID\n if (input.forkSession && message.type === \"system\" && message.subtype === \"init\") {\n newSessionId = message.session_id;\n sessionManager.create({\n sessionId: newSessionId,\n cwd: session.cwd,\n model: session.model,\n permissionMode: session.permissionMode,\n abortController,\n });\n }\n\n if (message.type === \"result\") {\n const result = message as any;\n durationMs = result.duration_ms ?? 0;\n numTurns = result.num_turns ?? 0;\n totalCostUsd = result.total_cost_usd ?? 0;\n isError = result.is_error ?? false;\n\n if (result.subtype === \"success\") {\n resultText = result.result ?? \"\";\n } else {\n isError = true;\n resultText = (result.errors ?? []).join(\"\\n\") || \"Unknown error\";\n }\n }\n }\n } catch (err: unknown) {\n isError = true;\n resultText = err instanceof Error ? err.message : String(err);\n }\n\n // Update session state, clear abortController\n // Preserve \"cancelled\" status if session was cancelled during execution\n if (input.forkSession && newSessionId !== input.sessionId) {\n const forkedCurrent = sessionManager.get(newSessionId);\n if (forkedCurrent && forkedCurrent.status !== \"cancelled\") {\n sessionManager.update(newSessionId, {\n status: isError ? \"error\" : \"idle\",\n totalTurns: numTurns,\n totalCostUsd,\n abortController: undefined,\n });\n } else if (forkedCurrent) {\n sessionManager.update(newSessionId, {\n totalTurns: numTurns,\n totalCostUsd,\n abortController: undefined,\n });\n }\n // Restore original session — but preserve \"cancelled\" if it was cancelled during fork\n const origCurrent = sessionManager.get(input.sessionId);\n if (origCurrent && origCurrent.status !== \"cancelled\") {\n sessionManager.update(input.sessionId, {\n status: \"idle\",\n abortController: undefined,\n });\n } else if (origCurrent) {\n sessionManager.update(input.sessionId, {\n abortController: undefined,\n });\n }\n } else {\n const current = sessionManager.get(input.sessionId);\n if (current && current.status !== \"cancelled\") {\n sessionManager.update(input.sessionId, {\n status: isError ? \"error\" : \"idle\",\n totalTurns: (session.totalTurns ?? 0) + numTurns,\n totalCostUsd: (session.totalCostUsd ?? 0) + totalCostUsd,\n abortController: undefined,\n });\n } else if (current) {\n sessionManager.update(input.sessionId, {\n totalTurns: (session.totalTurns ?? 0) + numTurns,\n totalCostUsd: (session.totalCostUsd ?? 0) + totalCostUsd,\n abortController: undefined,\n });\n }\n }\n\n const targetSessionId = input.forkSession ? newSessionId : input.sessionId;\n\n return {\n sessionId: targetSessionId,\n result: resultText,\n isError,\n durationMs,\n numTurns,\n totalCostUsd,\n };\n}\n","/**\n * claude_code_session tool - Manage sessions (list, get, cancel)\n */\nimport type { SessionManager } from \"../session/manager.js\";\nimport type { SessionInfo, SessionAction } from \"../types.js\";\nimport { ErrorCode } from \"../types.js\";\n\nexport interface ClaudeCodeSessionInput {\n action: SessionAction;\n sessionId?: string;\n}\n\nexport interface SessionResult {\n sessions: Array<Omit<SessionInfo, \"abortController\">>;\n message?: string;\n isError?: boolean;\n}\n\nexport function executeClaudeCodeSession(\n input: ClaudeCodeSessionInput,\n sessionManager: SessionManager\n): SessionResult {\n switch (input.action) {\n case \"list\": {\n const sessions = sessionManager.list().map((s) => sessionManager.toJSON(s));\n return { sessions };\n }\n\n case \"get\": {\n if (!input.sessionId) {\n return {\n sessions: [],\n message: `Error [${ErrorCode.INVALID_ARGUMENT}]: sessionId is required for 'get' action.`,\n isError: true,\n };\n }\n const session = sessionManager.get(input.sessionId);\n if (!session) {\n return {\n sessions: [],\n message: `Error [${ErrorCode.SESSION_NOT_FOUND}]: Session '${input.sessionId}' not found.`,\n isError: true,\n };\n }\n return { sessions: [sessionManager.toJSON(session)] };\n }\n\n case \"cancel\": {\n if (!input.sessionId) {\n return {\n sessions: [],\n message: `Error [${ErrorCode.INVALID_ARGUMENT}]: sessionId is required for 'cancel' action.`,\n isError: true,\n };\n }\n const cancelled = sessionManager.cancel(input.sessionId);\n if (!cancelled) {\n return {\n sessions: [],\n message: `Error [${ErrorCode.SESSION_NOT_FOUND}]: Session '${input.sessionId}' not found.`,\n isError: true,\n };\n }\n const updated = sessionManager.get(input.sessionId);\n return {\n sessions: updated ? [sessionManager.toJSON(updated)] : [],\n message: `Session '${input.sessionId}' cancelled.`,\n };\n }\n\n default:\n return {\n sessions: [],\n message: `Error [${ErrorCode.INVALID_ARGUMENT}]: Unknown action '${input.action}'. Use 'list', 'get', or 'cancel'.`,\n isError: true,\n };\n }\n}\n","/**\n * claude_code_configure tool - Runtime configuration management\n */\nimport { ErrorCode } from \"../types.js\";\nimport type { ConfigureAction } from \"../types.js\";\n\nexport interface ClaudeCodeConfigureInput {\n action: ConfigureAction;\n}\n\nexport interface ConfigureResult {\n allowBypass: boolean;\n message: string;\n isError?: boolean;\n}\n\nexport function executeClaudeCodeConfigure(\n input: ClaudeCodeConfigureInput,\n config: { getAllowBypass: () => boolean; setAllowBypass: (v: boolean) => void }\n): ConfigureResult {\n switch (input.action) {\n case \"enable_bypass\":\n config.setAllowBypass(true);\n return {\n allowBypass: true,\n message: \"bypassPermissions mode is now enabled for this server session. Use with caution.\",\n };\n\n case \"disable_bypass\":\n config.setAllowBypass(false);\n return {\n allowBypass: false,\n message: \"bypassPermissions mode is now disabled.\",\n };\n\n case \"get_config\":\n return {\n allowBypass: config.getAllowBypass(),\n message: `Current config: bypassPermissions ${config.getAllowBypass() ? \"enabled\" : \"disabled\"}.`,\n };\n\n default:\n return {\n allowBypass: config.getAllowBypass(),\n message: `Error [${ErrorCode.INVALID_ARGUMENT}]: Unknown action '${input.action}'. Use 'enable_bypass', 'disable_bypass', or 'get_config'.`,\n isError: true,\n };\n }\n}\n"],"mappings":"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","names":["query","query"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@leo000001/claude-code-mcp",
|
|
3
|
+
"version": "1.1.0",
|
|
4
|
+
"description": "MCP server that wraps Claude Code (Claude Agent SDK) as tools for any MCP client",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"claude-code-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsup",
|
|
12
|
+
"dev": "tsup --watch",
|
|
13
|
+
"start": "node dist/index.js",
|
|
14
|
+
"typecheck": "tsc --noEmit",
|
|
15
|
+
"test": "vitest run",
|
|
16
|
+
"test:watch": "vitest",
|
|
17
|
+
"prepublishOnly": "npm run build",
|
|
18
|
+
"lint": "eslint src/",
|
|
19
|
+
"format": "prettier --write \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
20
|
+
"format:check": "prettier --check \"src/**/*.ts\" \"tests/**/*.ts\"",
|
|
21
|
+
"prepare": "husky"
|
|
22
|
+
},
|
|
23
|
+
"lint-staged": {
|
|
24
|
+
"*.ts": [
|
|
25
|
+
"prettier --write",
|
|
26
|
+
"eslint --fix"
|
|
27
|
+
]
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"mcp",
|
|
31
|
+
"claude-code",
|
|
32
|
+
"claude",
|
|
33
|
+
"agent",
|
|
34
|
+
"ai"
|
|
35
|
+
],
|
|
36
|
+
"author": "anthropics",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"repository": {
|
|
39
|
+
"type": "git",
|
|
40
|
+
"url": "https://github.com/anthropics/claude-code-mcp.git"
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"dist",
|
|
44
|
+
"LICENSE",
|
|
45
|
+
"README.md",
|
|
46
|
+
"CHANGELOG.md"
|
|
47
|
+
],
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@anthropic-ai/claude-agent-sdk": "^0.2.38",
|
|
50
|
+
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
51
|
+
"zod": "^4.3.6"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@eslint/js": "^9.39.2",
|
|
55
|
+
"@types/node": "^25.2.3",
|
|
56
|
+
"eslint": "^9.39.2",
|
|
57
|
+
"husky": "^9.1.7",
|
|
58
|
+
"lint-staged": "^16.2.7",
|
|
59
|
+
"prettier": "^3.8.1",
|
|
60
|
+
"tsup": "^8.5.1",
|
|
61
|
+
"typescript": "^5.9.3",
|
|
62
|
+
"typescript-eslint": "^8.55.0",
|
|
63
|
+
"vitest": "^4.0.18"
|
|
64
|
+
},
|
|
65
|
+
"engines": {
|
|
66
|
+
"node": ">=18.0.0"
|
|
67
|
+
}
|
|
68
|
+
}
|