@pharaoh-so/mcp 0.3.2 → 0.3.3
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/README.md +3 -3
- package/dist/helpers.d.ts +2 -6
- package/dist/helpers.js +4 -13
- package/dist/index.js +14 -47
- package/dist/install-skills.js +1 -1
- package/dist/setup.js +4 -4
- package/package.json +1 -1
- package/skills/pharaoh/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ This displays a device code and a URL. Open the URL on **any device** (phone, la
|
|
|
26
26
|
### Step 2 — Add to Claude Code
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
|
-
npx @pharaoh-so/mcp
|
|
29
|
+
npx @pharaoh-so/mcp
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
Verify the connection:
|
|
@@ -43,7 +43,7 @@ If you previously added Pharaoh as an SSE server, remove it first:
|
|
|
43
43
|
|
|
44
44
|
```bash
|
|
45
45
|
claude mcp remove pharaoh
|
|
46
|
-
npx @pharaoh-so/mcp
|
|
46
|
+
npx @pharaoh-so/mcp
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
## How It Works
|
|
@@ -203,7 +203,7 @@ npx @pharaoh-so/mcp
|
|
|
203
203
|
Make sure you added it with the correct command:
|
|
204
204
|
|
|
205
205
|
```bash
|
|
206
|
-
npx @pharaoh-so/mcp
|
|
206
|
+
npx @pharaoh-so/mcp
|
|
207
207
|
```
|
|
208
208
|
|
|
209
209
|
Note the `--` separator between `pharaoh` and `npx`.
|
package/dist/helpers.d.ts
CHANGED
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { TokenResponse } from "./auth.js";
|
|
6
6
|
import type { Credentials } from "./credentials.js";
|
|
7
|
+
/** The npx command users run to set up Pharaoh. Single source of truth for all output. */
|
|
8
|
+
export declare const NPX_COMMAND = "npx @pharaoh-so/mcp";
|
|
7
9
|
/** Write one or more lines to stderr. */
|
|
8
10
|
export declare function printLines(...lines: string[]): void;
|
|
9
11
|
/** Parse CLI arguments. */
|
|
10
12
|
export declare function parseArgs(argv?: string[]): {
|
|
11
13
|
server: string;
|
|
12
14
|
logout: boolean;
|
|
13
|
-
setup: boolean;
|
|
14
15
|
};
|
|
15
16
|
export declare function printUsage(): void;
|
|
16
17
|
/**
|
|
@@ -23,11 +24,6 @@ export declare function resolveSseUrl(tokenSseUrl: string | undefined, server: s
|
|
|
23
24
|
export declare function tokenToCredentials(token: TokenResponse, sseUrl: string): Credentials;
|
|
24
25
|
/** Format remaining TTL as human-readable string (e.g. "5d 12h"). */
|
|
25
26
|
export declare function formatTtl(expiresAt: string): string;
|
|
26
|
-
/**
|
|
27
|
-
* Print setup instructions for Claude Code. Called in interactive mode
|
|
28
|
-
* after auth completes (or when credentials already exist).
|
|
29
|
-
*/
|
|
30
|
-
export declare function printSetupInstructions(): void;
|
|
31
27
|
/** Format a credential identity string (e.g. "alice (my-org)"). */
|
|
32
28
|
export declare function formatIdentity(creds: Credentials): string;
|
|
33
29
|
/**
|
package/dist/helpers.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { isExpired } from "./credentials.js";
|
|
2
2
|
const DEFAULT_SERVER = "https://mcp.pharaoh.so";
|
|
3
|
+
/** The npx command users run to set up Pharaoh. Single source of truth for all output. */
|
|
4
|
+
export const NPX_COMMAND = "npx @pharaoh-so/mcp";
|
|
3
5
|
/** Write one or more lines to stderr. */
|
|
4
6
|
export function printLines(...lines) {
|
|
5
7
|
process.stderr.write(lines.join("\n") + "\n");
|
|
@@ -8,7 +10,6 @@ export function printLines(...lines) {
|
|
|
8
10
|
export function parseArgs(argv = process.argv.slice(2)) {
|
|
9
11
|
let server = DEFAULT_SERVER;
|
|
10
12
|
let logout = false;
|
|
11
|
-
let setup = false;
|
|
12
13
|
for (let i = 0; i < argv.length; i++) {
|
|
13
14
|
if (argv[i] === "--server" && argv[i + 1]) {
|
|
14
15
|
server = argv[i + 1];
|
|
@@ -17,9 +18,6 @@ export function parseArgs(argv = process.argv.slice(2)) {
|
|
|
17
18
|
else if (argv[i] === "--logout") {
|
|
18
19
|
logout = true;
|
|
19
20
|
}
|
|
20
|
-
else if (argv[i] === "--setup") {
|
|
21
|
-
setup = true;
|
|
22
|
-
}
|
|
23
21
|
}
|
|
24
22
|
// Strip trailing slash
|
|
25
23
|
server = server.replace(/\/+$/, "");
|
|
@@ -41,10 +39,10 @@ export function parseArgs(argv = process.argv.slice(2)) {
|
|
|
41
39
|
printLines(`Pharaoh: --server is not a valid URL: ${server}`);
|
|
42
40
|
process.exit(1);
|
|
43
41
|
}
|
|
44
|
-
return { server, logout
|
|
42
|
+
return { server, logout };
|
|
45
43
|
}
|
|
46
44
|
export function printUsage() {
|
|
47
|
-
printLines("Usage: pharaoh-mcp [options]", "", "Options:", " --
|
|
45
|
+
printLines("Usage: pharaoh-mcp [options]", "", "Options:", " --server <url> Pharaoh server URL (default: https://mcp.pharaoh.so)", " --logout Clear stored credentials and exit", " --install-skills Force reinstall Pharaoh skills (Claude Code + OpenClaw)", " --help, -h Show this help", "", "Get started:", ` ${NPX_COMMAND}`, "");
|
|
48
46
|
}
|
|
49
47
|
/**
|
|
50
48
|
* Validate that a server-supplied SSE URL shares the same origin as the configured server.
|
|
@@ -95,13 +93,6 @@ export function formatTtl(expiresAt) {
|
|
|
95
93
|
return `${hours}h`;
|
|
96
94
|
return `${Math.floor(remainingMs / 60_000)}m`;
|
|
97
95
|
}
|
|
98
|
-
/**
|
|
99
|
-
* Print setup instructions for Claude Code. Called in interactive mode
|
|
100
|
-
* after auth completes (or when credentials already exist).
|
|
101
|
-
*/
|
|
102
|
-
export function printSetupInstructions() {
|
|
103
|
-
printLines("", "┌───────────────────────────────────────────────────────┐", "│ To register Pharaoh in Claude Code, run: │", "│ npx @pharaoh-so/mcp --setup │", "│ │", "│ This removes stale entries, registers the MCP │", "│ server globally, and installs all skills. │", "└───────────────────────────────────────────────────────┘", "");
|
|
104
|
-
}
|
|
105
96
|
/** Format a credential identity string (e.g. "alice (my-org)"). */
|
|
106
97
|
export function formatIdentity(creds) {
|
|
107
98
|
return [
|
package/dist/index.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { pollForToken, printActivationPrompt, printAuthSuccess, requestDeviceCode, } from "./auth.js";
|
|
14
14
|
import { deleteCredentials, isExpired, readCredentials, writeCredentials } from "./credentials.js";
|
|
15
|
-
import {
|
|
15
|
+
import { NPX_COMMAND, formatTtl, parseArgs, printLines, printUsage, resolveSseUrl, tokenToCredentials, } from "./helpers.js";
|
|
16
16
|
import { runInstallSkills } from "./install-skills.js";
|
|
17
17
|
import { startProxy, TenantSuspendedError, TokenExpiredError } from "./proxy.js";
|
|
18
18
|
async function main() {
|
|
@@ -33,7 +33,7 @@ async function main() {
|
|
|
33
33
|
runInstallSkills();
|
|
34
34
|
return;
|
|
35
35
|
}
|
|
36
|
-
const { server, logout
|
|
36
|
+
const { server, logout } = parseArgs(args);
|
|
37
37
|
if (logout) {
|
|
38
38
|
deleteCredentials();
|
|
39
39
|
printLines("Pharaoh: credentials cleared");
|
|
@@ -41,49 +41,13 @@ async function main() {
|
|
|
41
41
|
}
|
|
42
42
|
const creds = readCredentials();
|
|
43
43
|
const isInteractive = Boolean(process.stdin.isTTY);
|
|
44
|
-
// ── Setup mode (--setup): full automated install ──
|
|
45
|
-
// Auth → remove stale → register MCP → install skills → done.
|
|
46
|
-
if (setup) {
|
|
47
|
-
// Authenticate if needed
|
|
48
|
-
let activeCreds = creds && !isExpired(creds) ? creds : null;
|
|
49
|
-
if (activeCreds) {
|
|
50
|
-
printLines(`Pharaoh: authenticated as ${formatIdentity(activeCreds)} — token valid for ${formatTtl(activeCreds.expires_at)}`);
|
|
51
|
-
}
|
|
52
|
-
else {
|
|
53
|
-
printLines("Pharaoh: starting device authorization...");
|
|
54
|
-
const deviceCode = await requestDeviceCode(server);
|
|
55
|
-
printActivationPrompt(deviceCode.user_code, deviceCode.verification_uri);
|
|
56
|
-
const token = await pollForToken(server, deviceCode.device_code, deviceCode.interval);
|
|
57
|
-
if (token.provisional) {
|
|
58
|
-
printLines(`Pharaoh: provisional access — install the GitHub App to map your repos: ${token.install_url ?? ""}`);
|
|
59
|
-
}
|
|
60
|
-
const sseUrl = resolveSseUrl(token.sse_url, server);
|
|
61
|
-
const newCreds = tokenToCredentials(token, sseUrl);
|
|
62
|
-
writeCredentials(newCreds);
|
|
63
|
-
activeCreds = newCreds;
|
|
64
|
-
printAuthSuccess(token.github_login ?? null, token.tenant_name ?? null, token.repos?.length ?? 0);
|
|
65
|
-
}
|
|
66
|
-
// Register MCP server in Claude Code
|
|
67
|
-
const { runSetup } = await import("./setup.js");
|
|
68
|
-
runSetup();
|
|
69
|
-
// Install skills
|
|
70
|
-
runInstallSkills();
|
|
71
|
-
printLines("", "Pharaoh is ready. Start a new Claude Code conversation and ask:", ' "What modules does this codebase have?"', "");
|
|
72
|
-
process.exit(0);
|
|
73
|
-
}
|
|
74
44
|
// ── Interactive mode (user running in a terminal) ──
|
|
75
|
-
//
|
|
76
|
-
//
|
|
45
|
+
// Full setup every time: fresh auth → register MCP → install skills → done.
|
|
46
|
+
// Running `npx @pharaoh-so/mcp` is the only command a user needs.
|
|
77
47
|
if (isInteractive) {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
runInstallSkills();
|
|
82
|
-
printSetupInstructions();
|
|
83
|
-
process.exit(0);
|
|
84
|
-
}
|
|
85
|
-
// No valid credentials — run device flow
|
|
86
|
-
printLines("Pharaoh: no valid credentials — starting device authorization");
|
|
48
|
+
// Always re-authenticate for a fresh session
|
|
49
|
+
printLines("Pharaoh: starting device authorization...");
|
|
50
|
+
deleteCredentials();
|
|
87
51
|
const deviceCode = await requestDeviceCode(server);
|
|
88
52
|
printActivationPrompt(deviceCode.user_code, deviceCode.verification_uri);
|
|
89
53
|
const token = await pollForToken(server, deviceCode.device_code, deviceCode.interval);
|
|
@@ -94,15 +58,18 @@ async function main() {
|
|
|
94
58
|
const newCreds = tokenToCredentials(token, sseUrl);
|
|
95
59
|
writeCredentials(newCreds);
|
|
96
60
|
printAuthSuccess(token.github_login ?? null, token.tenant_name ?? null, token.repos?.length ?? 0);
|
|
97
|
-
//
|
|
61
|
+
// Register MCP server in Claude Code (remove stale + add fresh)
|
|
62
|
+
const { runSetup } = await import("./setup.js");
|
|
63
|
+
runSetup();
|
|
64
|
+
// Install skills to all detected platforms
|
|
98
65
|
runInstallSkills();
|
|
99
|
-
|
|
66
|
+
printLines("", "Pharaoh is ready. Start a new Claude Code conversation and ask:", ' "What modules does this codebase have?"', "");
|
|
100
67
|
process.exit(0);
|
|
101
68
|
}
|
|
102
69
|
// ── Proxy mode (Claude Code spawned us as a stdio MCP server) ──
|
|
103
70
|
// If no credentials, we can't run the device flow (no TTY for user interaction).
|
|
104
71
|
if (!creds || isExpired(creds)) {
|
|
105
|
-
printLines("Pharaoh: no valid credentials — cannot start proxy.", "Run this command first to authenticate:",
|
|
72
|
+
printLines("Pharaoh: no valid credentials — cannot start proxy.", "Run this command first to authenticate:", ` ${NPX_COMMAND}`, "");
|
|
106
73
|
process.exit(1);
|
|
107
74
|
}
|
|
108
75
|
// Valid credentials — ensure skills are installed before starting proxy
|
|
@@ -119,7 +86,7 @@ async function main() {
|
|
|
119
86
|
}
|
|
120
87
|
catch (err) {
|
|
121
88
|
if (err instanceof TokenExpiredError) {
|
|
122
|
-
printLines("Pharaoh: token expired or revoked.", "Run this command to re-authenticate:",
|
|
89
|
+
printLines("Pharaoh: token expired or revoked.", "Run this command to re-authenticate:", ` ${NPX_COMMAND}`, "");
|
|
123
90
|
deleteCredentials();
|
|
124
91
|
process.exit(1);
|
|
125
92
|
}
|
package/dist/install-skills.js
CHANGED
|
@@ -258,7 +258,7 @@ export function runInstallSkills(home = homedir()) {
|
|
|
258
258
|
" • Claude Code — install from https://claude.ai/download",
|
|
259
259
|
" • OpenClaw — install from https://openclaw.dev/install",
|
|
260
260
|
"",
|
|
261
|
-
"Once installed, re-run: npx @pharaoh-so/mcp
|
|
261
|
+
"Once installed, re-run: npx @pharaoh-so/mcp",
|
|
262
262
|
"",
|
|
263
263
|
].join("\n"));
|
|
264
264
|
}
|
package/dist/setup.js
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Full automated install: authenticates via device flow, removes stale MCP
|
|
5
5
|
* entries, registers Pharaoh as a global stdio MCP server, and installs skills.
|
|
6
|
-
* One command does everything: `npx @pharaoh-so/mcp
|
|
6
|
+
* One command does everything: `npx @pharaoh-so/mcp`
|
|
7
7
|
*/
|
|
8
8
|
import { execFileSync } from "node:child_process";
|
|
9
|
-
import { printLines } from "./helpers.js";
|
|
9
|
+
import { NPX_COMMAND, printLines } from "./helpers.js";
|
|
10
10
|
/** Check if `claude` CLI is available in PATH. */
|
|
11
11
|
function hasClaude() {
|
|
12
12
|
try {
|
|
@@ -48,7 +48,7 @@ function runClaude(args) {
|
|
|
48
48
|
*/
|
|
49
49
|
export function runSetup() {
|
|
50
50
|
if (!hasClaude()) {
|
|
51
|
-
printLines("Pharaoh: Claude Code CLI not found.", "", "Install Claude Code first: https://claude.ai/download",
|
|
51
|
+
printLines("Pharaoh: Claude Code CLI not found.", "", "Install Claude Code first: https://claude.ai/download", `Then re-run: ${NPX_COMMAND}`, "");
|
|
52
52
|
return false;
|
|
53
53
|
}
|
|
54
54
|
printLines("Pharaoh: setting up...");
|
|
@@ -66,7 +66,7 @@ export function runSetup() {
|
|
|
66
66
|
"@pharaoh-so/mcp",
|
|
67
67
|
]);
|
|
68
68
|
if (!added) {
|
|
69
|
-
printLines("Pharaoh: failed to register MCP server.",
|
|
69
|
+
printLines("Pharaoh: failed to register MCP server.", `Try manually: ${NPX_COMMAND}`, "");
|
|
70
70
|
return false;
|
|
71
71
|
}
|
|
72
72
|
printLines("Pharaoh: registered as global MCP server (scope: user)");
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pharaoh-so/mcp",
|
|
3
3
|
"mcpName": "so.pharaoh/pharaoh",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.3",
|
|
5
5
|
"description": "MCP proxy for Pharaoh — maps codebases into queryable knowledge graphs for AI agents. Enables Claude Code in headless environments (VPS, SSH, CI) via device flow auth.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "dist/index.js",
|
package/skills/pharaoh/SKILL.md
CHANGED