milady

This commit is contained in:
nirholas
2026-03-31 10:38:23 +00:00
parent 8ba939ba68
commit cf9b405372
35 changed files with 7380 additions and 793 deletions

View File

@@ -24,386 +24,6 @@ main().catch((err) => {
});
/** Recursively collect all file paths under `root` (relative to root). */
async function walkFiles(root: string, rel = ""): Promise<string[]> {
const results: string[] = [];
let entries;
try {
entries = await fs.readdir(path.join(root, rel), { withFileTypes: true });
} catch {
return results;
}
for (const e of entries) {
const child = rel ? `${rel}/${e.name}` : e.name;
if (e.isDirectory()) {
results.push(...(await walkFiles(root, child)));
} else {
results.push(child);
}
}
return results;
}
/** Safely resolve a user-supplied relative path under SRC_ROOT. */
function safePath(relPath: string): string | null {
const resolved = path.resolve(SRC_ROOT, relPath);
if (!resolved.startsWith(SRC_ROOT)) return null; // path traversal blocked
return resolved;
}
// ---------------------------------------------------------------------------
// Tool & Command Metadata
// ---------------------------------------------------------------------------
interface ToolInfo {
name: string;
directory: string;
files: string[];
}
interface CommandInfo {
name: string;
path: string;
isDirectory: boolean;
files?: string[];
}
async function getToolList(): Promise<ToolInfo[]> {
const toolsDir = path.join(SRC_ROOT, "tools");
const entries = await fs.readdir(toolsDir, { withFileTypes: true });
const tools: ToolInfo[] = [];
for (const e of entries) {
if (!e.isDirectory() || e.name === "shared" || e.name === "testing")
continue;
const files = await listDir(path.join(toolsDir, e.name));
tools.push({ name: e.name, directory: `tools/${e.name}`, files });
}
return tools.sort((a, b) => a.name.localeCompare(b.name));
}
async function getCommandList(): Promise<CommandInfo[]> {
const cmdsDir = path.join(SRC_ROOT, "commands");
const entries = await fs.readdir(cmdsDir, { withFileTypes: true });
const commands: CommandInfo[] = [];
for (const e of entries) {
if (e.isDirectory()) {
const files = await listDir(path.join(cmdsDir, e.name));
commands.push({
name: e.name,
path: `commands/${e.name}`,
isDirectory: true,
files,
});
} else {
commands.push({
name: e.name.replace(/\.(ts|tsx)$/, ""),
path: `commands/${e.name}`,
isDirectory: false,
});
}
}
return commands.sort((a, b) => a.name.localeCompare(b.name));
}
// ---------------------------------------------------------------------------
// Server
// ---------------------------------------------------------------------------
const server = new Server(
{ name: "claude-code-explorer", version: "1.0.0" },
{
capabilities: {
tools: {},
resources: {},
prompts: {},
},
}
);
// ---- Resources -----------------------------------------------------------
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
resources: [
{
uri: "claude-code://architecture",
name: "Architecture Overview",
description: "High-level overview of the Claude Code source architecture",
mimeType: "text/markdown",
},
{
uri: "claude-code://tools",
name: "Tool Registry",
description: "List of all agent tools with their files",
mimeType: "application/json",
},
{
uri: "claude-code://commands",
name: "Command Registry",
description: "List of all slash commands",
mimeType: "application/json",
},
],
}));
server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => ({
resourceTemplates: [
{
uriTemplate: "claude-code://source/{path}",
name: "Source file",
description: "Read a source file from the Claude Code src/ directory",
mimeType: "text/plain",
},
],
}));
server.setRequestHandler(ReadResourceRequestSchema, async (request: { params: { uri: string } }) => {
const { uri } = request.params;
if (uri === "claude-code://architecture") {
const readmePath = path.resolve(SRC_ROOT, "..", "README.md");
let text: string;
try {
text = await fs.readFile(readmePath, "utf-8");
} catch {
text = "README.md not found.";
}
return { contents: [{ uri, mimeType: "text/markdown", text }] };
}
if (uri === "claude-code://tools") {
const tools = await getToolList();
return {
contents: [
{
uri,
mimeType: "application/json",
text: JSON.stringify(tools, null, 2),
},
],
};
}
if (uri === "claude-code://commands") {
const commands = await getCommandList();
return {
contents: [
{
uri,
mimeType: "application/json",
text: JSON.stringify(commands, null, 2),
},
],
};
}
// Source file template
if (uri.startsWith("claude-code://source/")) {
const relPath = uri.slice("claude-code://source/".length);
const abs = safePath(relPath);
if (!abs) throw new Error("Invalid path");
const text = await fs.readFile(abs, "utf-8");
return { contents: [{ uri, mimeType: "text/plain", text }] };
}
throw new Error(`Unknown resource: ${uri}`);
});
// ---- Tools ---------------------------------------------------------------
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "list_tools",
description:
"List all Claude Code agent tools (BashTool, FileReadTool, etc.) with their source files.",
inputSchema: { type: "object" as const, properties: {} },
},
{
name: "list_commands",
description:
"List all Claude Code slash commands (/commit, /review, /mcp, etc.) with their source files.",
inputSchema: { type: "object" as const, properties: {} },
},
{
name: "get_tool_source",
description:
"Read the full source code of a specific Claude Code tool implementation. Provide the tool directory name (e.g. 'BashTool', 'FileEditTool').",
inputSchema: {
type: "object" as const,
properties: {
toolName: {
type: "string",
description:
"Tool directory name, e.g. 'BashTool', 'FileReadTool'",
},
fileName: {
type: "string",
description:
"Optional: specific file within the tool directory. If omitted, returns the main implementation file.",
},
},
required: ["toolName"],
},
},
{
name: "get_command_source",
description:
"Read the source code of a specific Claude Code slash command. Provide the command name (e.g. 'commit', 'review', 'mcp').",
inputSchema: {
type: "object" as const,
properties: {
commandName: {
type: "string",
description: "Command name, e.g. 'commit', 'review', 'mcp'",
},
fileName: {
type: "string",
description:
"Optional: specific file within the command directory.",
},
},
required: ["commandName"],
},
},
{
name: "read_source_file",
description:
"Read any source file from the Claude Code src/ directory by relative path.",
inputSchema: {
type: "object" as const,
properties: {
path: {
type: "string",
description:
"Relative path from src/, e.g. 'QueryEngine.ts', 'services/mcp/types.ts'",
},
startLine: {
type: "number",
description: "Optional 1-based start line to read from.",
},
endLine: {
type: "number",
description: "Optional 1-based end line to read to.",
},
},
required: ["path"],
},
},
{
name: "search_source",
description:
"Search for a pattern (regex or plain text) across the Claude Code source code. Returns matching lines with file paths and line numbers.",
inputSchema: {
type: "object" as const,
properties: {
pattern: {
type: "string",
description: "Search pattern (regex supported).",
},
filePattern: {
type: "string",
description:
"Optional glob-like filter for file extensions, e.g. '.ts', '.tsx'.",
},
maxResults: {
type: "number",
description: "Maximum number of matches to return (default: 50).",
},
},
required: ["pattern"],
},
},
{
name: "list_directory",
description:
"List files and subdirectories within a directory under src/.",
inputSchema: {
type: "object" as const,
properties: {
path: {
type: "string",
description:
"Relative path from src/, e.g. 'services', 'tools/BashTool'. Use '' for the root.",
},
},
required: ["path"],
},
},
{
name: "get_architecture",
description:
"Get a high-level architecture overview of Claude Code including directory structure, core systems, and key files.",
inputSchema: { type: "object" as const, properties: {} },
},
],
}));
server.setRequestHandler(CallToolRequestSchema, async (request: { params: { name: string; arguments?: Record<string, unknown> } }) => {
const { name, arguments: args } = request.params;
switch (name) {
// ---- list_tools ----
case "list_tools": {
const tools = await getToolList();
return {
content: [{ type: "text" as const, text: JSON.stringify(tools, null, 2) }],
};
}
// ---- list_commands ----
case "list_commands": {
const commands = await getCommandList();
return {
content: [
{ type: "text" as const, text: JSON.stringify(commands, null, 2) },
],
};
}
// ---- get_tool_source ----
case "get_tool_source": {
const toolName = (args as Record<string, unknown>)?.toolName as string;
if (!toolName) throw new Error("toolName is required");
const toolDir = safePath(`tools/${toolName}`);
if (!toolDir || !(await dirExists(toolDir)))
throw new Error(`Tool not found: ${toolName}`);
let fileName = (args as Record<string, unknown>)?.fileName as
| string
| undefined;
if (!fileName) {
// Find the main implementation file
const files = await listDir(toolDir);
const main =
files.find(
(f) => f === `${toolName}.ts` || f === `${toolName}.tsx`
) ?? files.find((f) => f.endsWith(".ts") || f.endsWith(".tsx"));
if (!main) throw new Error(`No source files in ${toolName}`);
fileName = main;
}
const filePath = safePath(`tools/${toolName}/${fileName}`);
if (!filePath || !(await fileExists(filePath)))
throw new Error(`File not found: tools/${toolName}/${fileName}`);
const content = await fs.readFile(filePath, "utf-8");
return {
content: [
{
type: "text" as const,
text: `// tools/${toolName}/${fileName}\n// ${content.split("\n").length} lines\n\n${content}`,
},
],
};
}
// ---- get_command_source ----
case "get_command_source": {
const commandName = (args as Record<string, unknown>)
?.commandName as string;
if (!commandName) throw new Error("commandName is required");
// Try directory first, then .ts / .tsx
const candidates = [
`commands/${commandName}`,

View File

@@ -0,0 +1,24 @@
#!/usr/bin/env node
/**
* STDIO entrypoint — for local use with Claude Desktop, Claude Code, etc.
*
* Usage:
* node dist/index.js
* CLAUDE_CODE_SRC_ROOT=/path/to/src node dist/index.js
*/
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { createServer, validateSrcRoot, SRC_ROOT } from "./server.js";
async function main() {
await validateSrcRoot();
const server = createServer();
const transport = new StdioServerTransport();
await server.connect(transport);
console.error(`Claude Code Explorer MCP (stdio) started — src: ${SRC_ROOT}`);
}
main().catch((err) => {
console.error("Fatal error:", err);
process.exit(1);
});