@pharaoh-so/mcp 0.3.38 → 0.3.40

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/dist/backend.d.ts CHANGED
@@ -3,9 +3,9 @@
3
3
  *
4
4
  * Two concrete implementations:
5
5
  *
6
- * 1. AuthRequiredBackend — advertises a single tool (`get_codebase_map`) that
7
- * turns every invocation into a device-flow state step. Used while the
8
- * proxy is waiting for the user to authorize.
6
+ * 1. AuthRequiredBackend — advertises the real tool catalog (bundled at build
7
+ * time, see catalog.ts) and turns every invocation into a device-flow state
8
+ * step. Used while the proxy is waiting for the user to authorize.
9
9
  *
10
10
  * 2. SseProxyBackend (returned by createSseBackend) — wraps an MCP Client
11
11
  * connected to the remote Pharaoh SSE server. Forwards list/call requests
@@ -33,17 +33,6 @@ export interface Backend {
33
33
  */
34
34
  waitForExit?(): Promise<void>;
35
35
  }
36
- /**
37
- * Minimal pre-auth catalog. Single tool — matches Pharaoh's "call this first"
38
- * protocol (CLAUDE.md, skills), so the pre-auth surface mirrors the first
39
- * tool most agents try. Keeping this at 1 means the swap to the real catalog
40
- * fires a clean visible sendToolListChanged delta.
41
- *
42
- * If you add tools here, sync with src/mcp/tool-registry.ts in the main
43
- * package — descriptions should match so agents get consistent behavior
44
- * across the pre-auth / authorized transition.
45
- */
46
- export declare const AUTH_REQUIRED_TOOLS: Tool[];
47
36
  /**
48
37
  * Pre-auth backend. Every tool call triggers a device-flow state step via the
49
38
  * gateway; returns a structured auth-required response. Once the gateway
@@ -57,6 +46,11 @@ export declare class AuthRequiredBackend implements Backend {
57
46
  private readonly onAuthorized?;
58
47
  readonly name: "auth-required";
59
48
  constructor(gateway: DeviceFlowGateway, onAuthorized?: (() => Promise<void>) | undefined);
49
+ /**
50
+ * The real catalog (bundled at build time), so the agent learns every tool
51
+ * — and Claude Code loads the always-load ones — before sign-in. Each call
52
+ * returns the sign-in steps until the user authorizes.
53
+ */
60
54
  listTools(): Promise<Tool[]>;
61
55
  callTool(_name: string, _args: Record<string, unknown>): Promise<CallToolResult>;
62
56
  }
package/dist/backend.js CHANGED
@@ -3,9 +3,9 @@
3
3
  *
4
4
  * Two concrete implementations:
5
5
  *
6
- * 1. AuthRequiredBackend — advertises a single tool (`get_codebase_map`) that
7
- * turns every invocation into a device-flow state step. Used while the
8
- * proxy is waiting for the user to authorize.
6
+ * 1. AuthRequiredBackend — advertises the real tool catalog (bundled at build
7
+ * time, see catalog.ts) and turns every invocation into a device-flow state
8
+ * step. Used while the proxy is waiting for the user to authorize.
9
9
  *
10
10
  * 2. SseProxyBackend (returned by createSseBackend) — wraps an MCP Client
11
11
  * connected to the remote Pharaoh SSE server. Forwards list/call requests
@@ -17,34 +17,9 @@
17
17
  */
18
18
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
19
19
  import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
20
+ import { loadBundledCatalog } from "./catalog.js";
20
21
  import { classifySSEError, TenantSuspendedError, TokenExpiredError } from "./proxy.js";
21
22
  import { getPackageVersion } from "./version.js";
22
- /**
23
- * Minimal pre-auth catalog. Single tool — matches Pharaoh's "call this first"
24
- * protocol (CLAUDE.md, skills), so the pre-auth surface mirrors the first
25
- * tool most agents try. Keeping this at 1 means the swap to the real catalog
26
- * fires a clean visible sendToolListChanged delta.
27
- *
28
- * If you add tools here, sync with src/mcp/tool-registry.ts in the main
29
- * package — descriptions should match so agents get consistent behavior
30
- * across the pre-auth / authorized transition.
31
- */
32
- export const AUTH_REQUIRED_TOOLS = [
33
- {
34
- name: "get_codebase_map",
35
- description: "Pharaoh — call this FIRST to understand the codebase structure. " +
36
- "Requires authentication; calling this tool will surface the auth URL.",
37
- inputSchema: {
38
- type: "object",
39
- properties: {
40
- repo: {
41
- type: "string",
42
- description: "Optional repo slug (owner/name) to map.",
43
- },
44
- },
45
- },
46
- },
47
- ];
48
23
  /**
49
24
  * Pre-auth backend. Every tool call triggers a device-flow state step via the
50
25
  * gateway; returns a structured auth-required response. Once the gateway
@@ -61,8 +36,13 @@ export class AuthRequiredBackend {
61
36
  this.gateway = gateway;
62
37
  this.onAuthorized = onAuthorized;
63
38
  }
39
+ /**
40
+ * The real catalog (bundled at build time), so the agent learns every tool
41
+ * — and Claude Code loads the always-load ones — before sign-in. Each call
42
+ * returns the sign-in steps until the user authorizes.
43
+ */
64
44
  async listTools() {
65
- return AUTH_REQUIRED_TOOLS;
45
+ return loadBundledCatalog().tools;
66
46
  }
67
47
  async callTool(_name, _args) {
68
48
  const response = await this.gateway.handleToolCall();
@@ -106,7 +86,9 @@ export class AuthRequiredBackend {
106
86
  content: [
107
87
  {
108
88
  type: "text",
109
- text: "Pharaoh: authenticated. Call this tool again to get the codebase map.",
89
+ // ProxyServer re-runs the call on the new backend; this text
90
+ // only reaches the agent if no backend swap happened.
91
+ text: "Pharaoh: authenticated. Call the tool again.",
110
92
  },
111
93
  ],
112
94
  isError: false,
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Pharaoh's agent-facing surface as bundled into this package at build time:
3
+ * the server instructions and the tool catalog in inspect-tools.json, written by
4
+ * the main repo's scripts/generate-inspect-schemas.ts from the same code the
5
+ * production server runs.
6
+ *
7
+ * The proxy answers Claude Code's `initialize` and first `tools/list` before it
8
+ * has reached (or signed in to) mcp.pharaoh.so, and the client reads instructions
9
+ * only once, at connect. So it serves this copy rather than a stub. See VISION.md
10
+ * § Every connection path delivers the same instructions and tool metadata.
11
+ */
12
+ import type { Tool } from "@modelcontextprotocol/sdk/types.js";
13
+ /** Instructions and tools exactly as the Pharaoh server sends them. */
14
+ export interface BundledCatalog {
15
+ /** Server instructions (getInstructions() in the main repo). */
16
+ instructions: string;
17
+ /** Every tool the server lists, with descriptions, schemas and `_meta`. */
18
+ tools: Tool[];
19
+ }
20
+ /**
21
+ * Load the bundled instructions and tool catalog (read once per process).
22
+ *
23
+ * @returns The catalog shipped in this package's inspect-tools.json.
24
+ * @throws If the file is missing or lacks instructions or tools — a packaging bug.
25
+ */
26
+ export declare function loadBundledCatalog(): BundledCatalog;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Pharaoh's agent-facing surface as bundled into this package at build time:
3
+ * the server instructions and the tool catalog in inspect-tools.json, written by
4
+ * the main repo's scripts/generate-inspect-schemas.ts from the same code the
5
+ * production server runs.
6
+ *
7
+ * The proxy answers Claude Code's `initialize` and first `tools/list` before it
8
+ * has reached (or signed in to) mcp.pharaoh.so, and the client reads instructions
9
+ * only once, at connect. So it serves this copy rather than a stub. See VISION.md
10
+ * § Every connection path delivers the same instructions and tool metadata.
11
+ */
12
+ import { readFileSync } from "node:fs";
13
+ import { dirname, join } from "node:path";
14
+ import { fileURLToPath } from "node:url";
15
+ let cached = null;
16
+ /**
17
+ * Load the bundled instructions and tool catalog (read once per process).
18
+ *
19
+ * @returns The catalog shipped in this package's inspect-tools.json.
20
+ * @throws If the file is missing or lacks instructions or tools — a packaging bug.
21
+ */
22
+ export function loadBundledCatalog() {
23
+ if (cached)
24
+ return cached;
25
+ // Resolved from the module URL: the package supports Node 18, before the dirname shortcut.
26
+ const path = join(dirname(fileURLToPath(import.meta.url)), "..", "inspect-tools.json");
27
+ const parsed = JSON.parse(readFileSync(path, "utf-8"));
28
+ if (typeof parsed.instructions !== "string" || !Array.isArray(parsed.tools)) {
29
+ throw new Error(`${path} has no instructions or tools — rebuild the package`);
30
+ }
31
+ cached = { instructions: parsed.instructions, tools: parsed.tools };
32
+ return cached;
33
+ }
@@ -22,6 +22,8 @@ export interface Credentials {
22
22
  tenant_name: string | null;
23
23
  repos: string[];
24
24
  }
25
+ /** Default credential file path (route-grep-hook.ts checks the same file to know Pharaoh is signed in). */
26
+ export declare const CREDENTIALS_PATH: string;
25
27
  /**
26
28
  * Read and parse stored credentials. Returns null if missing, unreadable,
27
29
  * malformed, or wrong schema version (v1 credentials will return null here,
@@ -26,8 +26,8 @@ const LOCK_POLL_MS = 50;
26
26
  * token to upgrade from.
27
27
  */
28
28
  const SCHEMA_VERSION = 2;
29
- /** Default credential file path. */
30
- const CREDENTIALS_PATH = join(homedir(), ".pharaoh", "credentials.json");
29
+ /** Default credential file path (route-grep-hook.ts checks the same file to know Pharaoh is signed in). */
30
+ export const CREDENTIALS_PATH = join(homedir(), ".pharaoh", "credentials.json");
31
31
  /**
32
32
  * Read and parse stored credentials. Returns null if missing, unreadable,
33
33
  * malformed, or wrong schema version (v1 credentials will return null here,
package/dist/helpers.js CHANGED
@@ -42,7 +42,7 @@ export function parseArgs(argv = process.argv.slice(2)) {
42
42
  return { server, logout };
43
43
  }
44
44
  export function printUsage() {
45
- printLines("Usage: pharaoh-mcp [options]", "", "Options:", " --server <url> Pharaoh server URL (default: https://mcp.pharaoh.so)", " --logout Clear credentials and MCP config, then exit", " --clean Remove all Pharaoh MCP entries from Claude Code config", " --install-skills Force reinstall Pharaoh skills (Claude Code + OpenClaw)", " --help, -h Show this help", "", "Get started:", ` ${NPX_COMMAND}`, "");
45
+ printLines("Usage: pharaoh-mcp [options]", "", "Options:", " --server <url> Pharaoh server URL (default: https://mcp.pharaoh.so)", " --logout Clear credentials, MCP config and the Claude Code plugin, then exit", " --clean Remove Pharaoh's MCP entries and plugin from Claude Code config", " --install-skills Reinstall the Claude Code plugin and OpenClaw skills", " --help, -h Show this help", "", "Get started:", ` ${NPX_COMMAND}`, "");
46
46
  }
47
47
  /**
48
48
  * Validate that a server-supplied SSE URL shares the same origin as the configured server.
package/dist/index.js CHANGED
@@ -52,16 +52,20 @@ async function main() {
52
52
  // disabled states, project-scoped configs). Useful for resetting broken installs.
53
53
  if (args.includes("--clean")) {
54
54
  const { cleanSlate } = await import("./setup.js");
55
+ const { uninstallClaudePlugin } = await import("./install-skills.js");
55
56
  cleanSlate();
56
- printLines("Pharaoh: cleaned all MCP entries from Claude Code config");
57
+ uninstallClaudePlugin();
58
+ printLines("Pharaoh: cleaned all MCP entries and the plugin from Claude Code config");
57
59
  process.exit(0);
58
60
  }
59
61
  const { server, logout } = parseArgs(args);
60
62
  if (logout) {
61
63
  const { cleanSlate } = await import("./setup.js");
64
+ const { uninstallClaudePlugin } = await import("./install-skills.js");
62
65
  cleanSlate();
66
+ uninstallClaudePlugin();
63
67
  deleteCredentials();
64
- printLines("Pharaoh: credentials and MCP config cleared");
68
+ printLines("Pharaoh: credentials, MCP config and the Claude Code plugin cleared");
65
69
  process.exit(0);
66
70
  }
67
71
  const isInteractive = Boolean(process.stdin.isTTY);
package/dist/inspect.d.ts CHANGED
@@ -1,11 +1,11 @@
1
1
  /**
2
- * Inspect mode — serves Pharaoh's tool schemas over stdio for Glama inspection.
2
+ * Inspect mode — serves Pharaoh's instructions and tool schemas over stdio for
3
+ * Glama inspection.
3
4
  *
4
- * Reads pre-generated tool schemas from inspect-tools.json (generated at build
5
- * time by the main repo's `generate-inspect-schemas.ts`). Registers each tool
6
- * on an MCP server that returns a "connect to mcp.pharaoh.so" message if invoked.
7
- *
8
- * Zero-drift: schemas are extracted from the same registerXxx() code that the
9
- * production server uses, serialized to JSON during build, and shipped in the npm package.
5
+ * Serves the bundled catalog (catalog.ts — inspect-tools.json, generated at build
6
+ * time by the main repo's `generate-inspect-schemas.ts`) verbatim: the same
7
+ * instructions, descriptions, schemas, annotations and `_meta` the production
8
+ * server sends. Any tool call returns a "connect to mcp.pharaoh.so" message.
10
9
  */
10
+ /** Run the inspect server on stdio until the client disconnects. */
11
11
  export declare function runInspect(): Promise<void>;
package/dist/inspect.js CHANGED
@@ -1,46 +1,33 @@
1
1
  /**
2
- * Inspect mode — serves Pharaoh's tool schemas over stdio for Glama inspection.
2
+ * Inspect mode — serves Pharaoh's instructions and tool schemas over stdio for
3
+ * Glama inspection.
3
4
  *
4
- * Reads pre-generated tool schemas from inspect-tools.json (generated at build
5
- * time by the main repo's `generate-inspect-schemas.ts`). Registers each tool
6
- * on an MCP server that returns a "connect to mcp.pharaoh.so" message if invoked.
7
- *
8
- * Zero-drift: schemas are extracted from the same registerXxx() code that the
9
- * production server uses, serialized to JSON during build, and shipped in the npm package.
5
+ * Serves the bundled catalog (catalog.ts — inspect-tools.json, generated at build
6
+ * time by the main repo's `generate-inspect-schemas.ts`) verbatim: the same
7
+ * instructions, descriptions, schemas, annotations and `_meta` the production
8
+ * server sends. Any tool call returns a "connect to mcp.pharaoh.so" message.
10
9
  */
11
- import { readFileSync } from "node:fs";
12
- import { join } from "node:path";
13
- import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
10
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
14
11
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
12
+ import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
13
+ import { loadBundledCatalog } from "./catalog.js";
15
14
  import { getPackageVersion } from "./version.js";
16
15
  const INSPECT_MSG = "This is Pharaoh's inspection server for directory listings. " +
17
16
  "Connect to https://mcp.pharaoh.so for actual usage.";
17
+ /** Run the inspect server on stdio until the client disconnects. */
18
18
  export async function runInspect() {
19
- // Load pre-generated schemas (shipped in the npm package)
20
- const schemasPath = join(import.meta.dirname, "..", "inspect-tools.json");
21
- let schemas;
19
+ let catalog;
22
20
  try {
23
- schemas = JSON.parse(readFileSync(schemasPath, "utf-8"));
21
+ catalog = loadBundledCatalog();
24
22
  }
25
- catch {
26
- process.stderr.write("Pharaoh: inspect-tools.json not found — rebuild the package.\n");
23
+ catch (err) {
24
+ process.stderr.write(`Pharaoh: ${err instanceof Error ? err.message : String(err)}\n`);
27
25
  process.exit(1);
28
26
  }
29
- const server = new McpServer({ name: "pharaoh", version: getPackageVersion() }, {
30
- instructions: "Pharaoh turns codebases into knowledge graphs that AI agents can think with. " +
31
- "Connect at https://mcp.pharaoh.so for full functionality.",
32
- });
33
- // Register each tool with pre-serialized JSON Schema.
34
- // Cast inputSchema to satisfy TypeScript — at runtime registerTool passes it through as-is.
35
- for (const tool of schemas.tools) {
36
- // biome-ignore lint/suspicious/noExplicitAny: JSON Schema from inspect-tools.json, not Zod
37
- const schema = tool.inputSchema;
38
- server.registerTool(tool.name, {
39
- description: tool.description,
40
- inputSchema: schema,
41
- annotations: tool.annotations,
42
- }, async () => ({ content: [{ type: "text", text: INSPECT_MSG }] }));
43
- }
44
- const transport = new StdioServerTransport();
45
- await server.connect(transport);
27
+ const server = new Server({ name: "pharaoh", version: getPackageVersion() }, { capabilities: { tools: {} }, instructions: catalog.instructions });
28
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: catalog.tools }));
29
+ server.setRequestHandler(CallToolRequestSchema, async () => ({
30
+ content: [{ type: "text", text: INSPECT_MSG }],
31
+ }));
32
+ await server.connect(new StdioServerTransport());
46
33
  }
@@ -5,6 +5,16 @@
5
5
  * @returns True if ~/.openclaw/ exists.
6
6
  */
7
7
  export declare function detectOpenClaw(home?: string): boolean;
8
+ /** Runs one `claude` CLI command; true on success. */
9
+ type ClaudeCli = (args: string[]) => boolean;
10
+ /**
11
+ * Uninstall Pharaoh's Claude Code plugin: through the CLI, then the local
12
+ * marketplace directory and any pre-marketplace install.
13
+ *
14
+ * @param home - Home directory override (defaults to os.homedir()).
15
+ * @param claude - `claude` CLI runner (defaults to the real CLI for `home`).
16
+ */
17
+ export declare function uninstallClaudePlugin(home?: string, claude?: ClaudeCli): void;
8
18
  /**
9
19
  * Install bundled skills to `~/.openclaw/skills/` with the same `pharaoh-`
10
20
  * prefix that Claude Code installs use. Keeps naming consistent across both
@@ -33,7 +43,11 @@ export declare function mergeOpenClawConfig(home?: string): boolean;
33
43
  * Installs to all detected platforms (a user may use both).
34
44
  *
35
45
  * @param home - Home directory override (defaults to os.homedir()).
46
+ * @param options.silent - Print nothing (the interactive setup prints its own summary).
47
+ * @param options.claude - `claude` CLI runner (defaults to the real CLI for `home`).
36
48
  */
37
49
  export declare function runInstallSkills(home?: string, options?: {
38
50
  silent?: boolean;
51
+ claude?: ClaudeCli;
39
52
  }): void;
53
+ export {};