@pharaoh-so/mcp 0.1.3 → 0.1.5
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/auth.js.map +1 -0
- package/dist/credentials.js.map +1 -0
- package/dist/index.js +138 -60
- package/dist/index.js.map +1 -0
- package/dist/proxy.d.ts +0 -4
- package/dist/proxy.js +17 -14
- package/dist/proxy.js.map +1 -0
- package/inspect-tools.json +856 -0
- package/package.json +32 -31
- package/dist/helpers.d.ts +0 -36
- package/dist/helpers.js +0 -124
package/package.json
CHANGED
|
@@ -1,32 +1,33 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
2
|
+
"name": "@pharaoh-so/mcp",
|
|
3
|
+
"version": "0.1.5",
|
|
4
|
+
"description": "Stdio-to-SSE proxy for Pharaoh MCP — enables headless environments (VPS, SSH, CI) via device flow auth",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"pharaoh-mcp": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc && node -e \"const fs=require('fs'),f='dist/index.js',c=fs.readFileSync(f,'utf8');if(!c.startsWith('#!'))fs.writeFileSync(f,'#!/usr/bin/env node\\n'+c);fs.chmodSync(f,0o755)\"",
|
|
12
|
+
"typecheck": "tsc --noEmit",
|
|
13
|
+
"test": "vitest run",
|
|
14
|
+
"lint": "biome check src/"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"inspect-tools.json",
|
|
19
|
+
"README.md"
|
|
20
|
+
],
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@modelcontextprotocol/sdk": "^1.26.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@biomejs/biome": "^2.3.15",
|
|
30
|
+
"typescript": "^5.9.3",
|
|
31
|
+
"vitest": "^4.0.18"
|
|
32
|
+
}
|
|
33
|
+
}
|
package/dist/helpers.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure helper functions for the mcp-proxy CLI — no side effects on import.
|
|
3
|
-
* Separated from index.ts so tests can import without triggering main().
|
|
4
|
-
*/
|
|
5
|
-
import type { TokenResponse } from "./auth.js";
|
|
6
|
-
import type { Credentials } from "./credentials.js";
|
|
7
|
-
/** Write one or more lines to stderr. */
|
|
8
|
-
export declare function printLines(...lines: string[]): void;
|
|
9
|
-
/** Parse CLI arguments. */
|
|
10
|
-
export declare function parseArgs(argv?: string[]): {
|
|
11
|
-
server: string;
|
|
12
|
-
logout: boolean;
|
|
13
|
-
};
|
|
14
|
-
export declare function printUsage(): void;
|
|
15
|
-
/**
|
|
16
|
-
* Validate that a server-supplied SSE URL shares the same origin as the configured server.
|
|
17
|
-
* Prevents a compromised auth response from redirecting the Bearer token to an attacker's host.
|
|
18
|
-
* Falls back to `${server}/sse` if the URL is missing, malformed, or cross-origin.
|
|
19
|
-
*/
|
|
20
|
-
export declare function resolveSseUrl(tokenSseUrl: string | undefined, server: string): string;
|
|
21
|
-
/** Convert a token response to storable credentials. */
|
|
22
|
-
export declare function tokenToCredentials(token: TokenResponse, sseUrl: string): Credentials;
|
|
23
|
-
/** Format remaining TTL as human-readable string (e.g. "5d 12h"). */
|
|
24
|
-
export declare function formatTtl(expiresAt: string): string;
|
|
25
|
-
/**
|
|
26
|
-
* Print setup instructions for Claude Code. Called in interactive mode
|
|
27
|
-
* after auth completes (or when credentials already exist).
|
|
28
|
-
*/
|
|
29
|
-
export declare function printSetupInstructions(): void;
|
|
30
|
-
/** Format a credential identity string (e.g. "alice (my-org)"). */
|
|
31
|
-
export declare function formatIdentity(creds: Credentials): string;
|
|
32
|
-
/**
|
|
33
|
-
* Determine if credentials are valid for proxy use.
|
|
34
|
-
* Returns a diagnostic message if not, null if valid.
|
|
35
|
-
*/
|
|
36
|
-
export declare function validateCredentials(creds: Credentials | null): string | null;
|
package/dist/helpers.js
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
import { isExpired } from "./credentials.js";
|
|
2
|
-
const DEFAULT_SERVER = "https://mcp.pharaoh.so";
|
|
3
|
-
/** Write one or more lines to stderr. */
|
|
4
|
-
export function printLines(...lines) {
|
|
5
|
-
process.stderr.write(lines.join("\n") + "\n");
|
|
6
|
-
}
|
|
7
|
-
/** Parse CLI arguments. */
|
|
8
|
-
export function parseArgs(argv = process.argv.slice(2)) {
|
|
9
|
-
let server = DEFAULT_SERVER;
|
|
10
|
-
let logout = false;
|
|
11
|
-
for (let i = 0; i < argv.length; i++) {
|
|
12
|
-
if (argv[i] === "--server" && argv[i + 1]) {
|
|
13
|
-
server = argv[i + 1];
|
|
14
|
-
i++;
|
|
15
|
-
}
|
|
16
|
-
else if (argv[i] === "--logout") {
|
|
17
|
-
logout = true;
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
// Strip trailing slash
|
|
21
|
-
server = server.replace(/\/+$/, "");
|
|
22
|
-
// Reject non-HTTPS servers (allow loopback addresses for local dev)
|
|
23
|
-
try {
|
|
24
|
-
const parsed = new URL(server);
|
|
25
|
-
const isLoopback = parsed.hostname === "localhost" ||
|
|
26
|
-
parsed.hostname === "127.0.0.1" ||
|
|
27
|
-
parsed.hostname === "[::1]";
|
|
28
|
-
if (parsed.protocol !== "https:" && !isLoopback) {
|
|
29
|
-
printLines(`Pharaoh: --server must use HTTPS (got ${parsed.protocol}//…). Use https:// or http://localhost for local dev.`);
|
|
30
|
-
process.exit(1);
|
|
31
|
-
}
|
|
32
|
-
if (parsed.protocol !== "https:" && isLoopback) {
|
|
33
|
-
printLines("⚠ Warning: using insecure HTTP over loopback — do not use in production.");
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
printLines(`Pharaoh: --server is not a valid URL: ${server}`);
|
|
38
|
-
process.exit(1);
|
|
39
|
-
}
|
|
40
|
-
return { server, logout };
|
|
41
|
-
}
|
|
42
|
-
export function printUsage() {
|
|
43
|
-
printLines("Usage: pharaoh-mcp [options]", "", "Options:", " --server <url> Pharaoh server URL (default: https://mcp.pharaoh.so)", " --logout Clear stored credentials and exit", " --help, -h Show this help", "", "Add to Claude Code:", " claude mcp add pharaoh -- npx @pharaoh-so/mcp", "");
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Validate that a server-supplied SSE URL shares the same origin as the configured server.
|
|
47
|
-
* Prevents a compromised auth response from redirecting the Bearer token to an attacker's host.
|
|
48
|
-
* Falls back to `${server}/sse` if the URL is missing, malformed, or cross-origin.
|
|
49
|
-
*/
|
|
50
|
-
export function resolveSseUrl(tokenSseUrl, server) {
|
|
51
|
-
const fallback = `${server}/sse`;
|
|
52
|
-
if (!tokenSseUrl)
|
|
53
|
-
return fallback;
|
|
54
|
-
try {
|
|
55
|
-
const sseOrigin = new URL(tokenSseUrl).origin;
|
|
56
|
-
const serverOrigin = new URL(server).origin;
|
|
57
|
-
if (sseOrigin !== serverOrigin) {
|
|
58
|
-
printLines(`Pharaoh: ignoring cross-origin sse_url (${sseOrigin} ≠ ${serverOrigin})`);
|
|
59
|
-
return fallback;
|
|
60
|
-
}
|
|
61
|
-
return tokenSseUrl;
|
|
62
|
-
}
|
|
63
|
-
catch {
|
|
64
|
-
return fallback;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
/** Convert a token response to storable credentials. */
|
|
68
|
-
export function tokenToCredentials(token, sseUrl) {
|
|
69
|
-
return {
|
|
70
|
-
version: 1,
|
|
71
|
-
access_token: token.access_token,
|
|
72
|
-
expires_at: new Date(Date.now() + token.expires_in * 1000).toISOString(),
|
|
73
|
-
expires_in: token.expires_in,
|
|
74
|
-
sse_url: sseUrl,
|
|
75
|
-
github_login: token.github_login ?? null,
|
|
76
|
-
tenant_name: token.tenant_name ?? null,
|
|
77
|
-
repos: token.repos ?? [],
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
/** Format remaining TTL as human-readable string (e.g. "5d 12h"). */
|
|
81
|
-
export function formatTtl(expiresAt) {
|
|
82
|
-
const remainingMs = new Date(expiresAt).getTime() - Date.now();
|
|
83
|
-
if (remainingMs <= 0)
|
|
84
|
-
return "expired";
|
|
85
|
-
const hours = Math.floor(remainingMs / 3_600_000);
|
|
86
|
-
const days = Math.floor(hours / 24);
|
|
87
|
-
const remHours = hours % 24;
|
|
88
|
-
if (days > 0)
|
|
89
|
-
return `${days}d ${remHours}h`;
|
|
90
|
-
if (hours > 0)
|
|
91
|
-
return `${hours}h`;
|
|
92
|
-
return `${Math.floor(remainingMs / 60_000)}m`;
|
|
93
|
-
}
|
|
94
|
-
/**
|
|
95
|
-
* Print setup instructions for Claude Code. Called in interactive mode
|
|
96
|
-
* after auth completes (or when credentials already exist).
|
|
97
|
-
*/
|
|
98
|
-
export function printSetupInstructions() {
|
|
99
|
-
printLines("", "┌───────────────────────────────────────────────────────┐", "│ Next step: add Pharaoh to Claude Code │", "│ │", "│ If pharaoh is already registered (e.g. as SSE): │", "│ claude mcp remove pharaoh │", "│ │", "│ Then add as stdio proxy: │", "│ claude mcp add pharaoh -- npx @pharaoh-so/mcp │", "│ │", "│ Verify with: │", "│ claude mcp list │", "└───────────────────────────────────────────────────────┘", "");
|
|
100
|
-
}
|
|
101
|
-
/** Format a credential identity string (e.g. "alice (my-org)"). */
|
|
102
|
-
export function formatIdentity(creds) {
|
|
103
|
-
return [
|
|
104
|
-
creds.github_login ?? "unknown",
|
|
105
|
-
creds.tenant_name ? `(${creds.tenant_name})` : null,
|
|
106
|
-
]
|
|
107
|
-
.filter(Boolean)
|
|
108
|
-
.join(" ");
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Determine if credentials are valid for proxy use.
|
|
112
|
-
* Returns a diagnostic message if not, null if valid.
|
|
113
|
-
*/
|
|
114
|
-
export function validateCredentials(creds) {
|
|
115
|
-
if (!creds || isExpired(creds)) {
|
|
116
|
-
return [
|
|
117
|
-
"Pharaoh: no valid credentials — cannot start proxy.",
|
|
118
|
-
"Run this command first to authenticate:",
|
|
119
|
-
" npx @pharaoh-so/mcp",
|
|
120
|
-
"",
|
|
121
|
-
].join("\n");
|
|
122
|
-
}
|
|
123
|
-
return null;
|
|
124
|
-
}
|