@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 +8 -14
- package/dist/backend.js +13 -31
- package/dist/catalog.d.ts +26 -0
- package/dist/catalog.js +33 -0
- package/dist/credentials.d.ts +2 -0
- package/dist/credentials.js +2 -2
- package/dist/helpers.js +1 -1
- package/dist/index.js +6 -2
- package/dist/inspect.d.ts +7 -7
- package/dist/inspect.js +20 -33
- package/dist/install-skills.d.ts +14 -0
- package/dist/install-skills.js +164 -150
- package/dist/proxy-server.js +13 -1
- package/dist/setup.d.ts +8 -0
- package/dist/setup.js +13 -1
- package/hooks/hooks.json +16 -0
- package/hooks/route-grep.mjs +139 -0
- package/inspect-tools.json +40 -23
- package/package.json +2 -1
- package/skills/pharaoh/SKILL.md +18 -22
package/dist/backend.d.ts
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Two concrete implementations:
|
|
5
5
|
*
|
|
6
|
-
* 1. AuthRequiredBackend — advertises
|
|
7
|
-
* turns every invocation into a device-flow state
|
|
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
|
|
7
|
-
* turns every invocation into a device-flow state
|
|
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
|
|
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
|
-
|
|
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;
|
package/dist/catalog.js
ADDED
|
@@ -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
|
+
}
|
package/dist/credentials.d.ts
CHANGED
|
@@ -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,
|
package/dist/credentials.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
|
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
|
|
2
|
+
* Inspect mode — serves Pharaoh's instructions and tool schemas over stdio for
|
|
3
|
+
* Glama inspection.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
* time by the main repo's `generate-inspect-schemas.ts`)
|
|
6
|
-
*
|
|
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
|
|
2
|
+
* Inspect mode — serves Pharaoh's instructions and tool schemas over stdio for
|
|
3
|
+
* Glama inspection.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
* time by the main repo's `generate-inspect-schemas.ts`)
|
|
6
|
-
*
|
|
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 {
|
|
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
|
-
|
|
20
|
-
const schemasPath = join(import.meta.dirname, "..", "inspect-tools.json");
|
|
21
|
-
let schemas;
|
|
19
|
+
let catalog;
|
|
22
20
|
try {
|
|
23
|
-
|
|
21
|
+
catalog = loadBundledCatalog();
|
|
24
22
|
}
|
|
25
|
-
catch {
|
|
26
|
-
process.stderr.write(
|
|
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
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
}
|
package/dist/install-skills.d.ts
CHANGED
|
@@ -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 {};
|