ping-mcp-server 0.1.0

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/src/init.ts ADDED
@@ -0,0 +1,300 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * PING INIT SCRIPT
4
+ * ================
5
+ *
6
+ * Sets up Ping for first-time users:
7
+ * - Shows welcome banner
8
+ * - Checks API connectivity
9
+ * - Creates config directory
10
+ * - Offers to add Ping to Claude Code config
11
+ */
12
+
13
+ import * as fs from 'fs';
14
+ import * as path from 'path';
15
+ import * as os from 'os';
16
+ import * as readline from 'readline';
17
+
18
+ // ============================================================
19
+ // CONFIGURATION
20
+ // ============================================================
21
+
22
+ const API_BASE_URL = process.env.PING_API_URL || 'https://api.ping-money.com';
23
+ const CONFIG_DIR = path.join(os.homedir(), '.ping');
24
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
25
+
26
+ // Possible Claude Code config locations
27
+ const CLAUDE_CONFIG_PATHS = [
28
+ path.join(os.homedir(), '.config', 'claude-code', 'config.json'),
29
+ path.join(os.homedir(), '.claude', 'config.json'),
30
+ path.join(os.homedir(), 'Library', 'Application Support', 'Claude', 'config.json'),
31
+ path.join(os.homedir(), '.config', 'claude', 'config.json'),
32
+ ];
33
+
34
+ // ============================================================
35
+ // BANNER
36
+ // ============================================================
37
+
38
+ const BANNER = `
39
+ +------------------------------------------+
40
+ | |
41
+ | ____ _ |
42
+ | | _ \\(_)_ __ __ _ |
43
+ | | |_) | | '_ \\ / _\` | |
44
+ | | __/| | | | | (_| | |
45
+ | |_| |_|_| |_|\\__, | |
46
+ | |___/ |
47
+ | |
48
+ | Answer questions. Earn crypto. |
49
+ | |
50
+ +------------------------------------------+
51
+ `;
52
+
53
+ // ============================================================
54
+ // HELPERS
55
+ // ============================================================
56
+
57
+ function print(message: string) {
58
+ console.log(message);
59
+ }
60
+
61
+ function printSuccess(message: string) {
62
+ console.log(`[OK] ${message}`);
63
+ }
64
+
65
+ function printError(message: string) {
66
+ console.log(`[ERROR] ${message}`);
67
+ }
68
+
69
+ function printInfo(message: string) {
70
+ console.log(`[INFO] ${message}`);
71
+ }
72
+
73
+ async function prompt(question: string): Promise<string> {
74
+ const rl = readline.createInterface({
75
+ input: process.stdin,
76
+ output: process.stdout,
77
+ });
78
+
79
+ return new Promise((resolve) => {
80
+ rl.question(question, (answer) => {
81
+ rl.close();
82
+ resolve(answer.trim().toLowerCase());
83
+ });
84
+ });
85
+ }
86
+
87
+ // ============================================================
88
+ // API CHECK
89
+ // ============================================================
90
+
91
+ async function checkApiConnectivity(): Promise<boolean> {
92
+ try {
93
+ const response = await fetch(`${API_BASE_URL}/health`);
94
+ return response.ok;
95
+ } catch {
96
+ return false;
97
+ }
98
+ }
99
+
100
+ // ============================================================
101
+ // CONFIG SETUP
102
+ // ============================================================
103
+
104
+ function createConfigDirectory(): boolean {
105
+ try {
106
+ if (!fs.existsSync(CONFIG_DIR)) {
107
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
108
+ printSuccess(`Created config directory: ${CONFIG_DIR}`);
109
+ } else {
110
+ printInfo(`Config directory already exists: ${CONFIG_DIR}`);
111
+ }
112
+ return true;
113
+ } catch (error) {
114
+ printError(`Failed to create config directory: ${error}`);
115
+ return false;
116
+ }
117
+ }
118
+
119
+ function initializeConfig(): boolean {
120
+ try {
121
+ if (!fs.existsSync(CONFIG_FILE)) {
122
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify({}, null, 2));
123
+ printSuccess(`Created config file: ${CONFIG_FILE}`);
124
+ } else {
125
+ printInfo(`Config file already exists: ${CONFIG_FILE}`);
126
+ }
127
+ return true;
128
+ } catch (error) {
129
+ printError(`Failed to create config file: ${error}`);
130
+ return false;
131
+ }
132
+ }
133
+
134
+ // ============================================================
135
+ // CLAUDE CODE INTEGRATION
136
+ // ============================================================
137
+
138
+ function findClaudeCodeConfig(): string | null {
139
+ for (const configPath of CLAUDE_CONFIG_PATHS) {
140
+ if (fs.existsSync(configPath)) {
141
+ return configPath;
142
+ }
143
+ }
144
+ return null;
145
+ }
146
+
147
+ function findClaudeCodeConfigDir(): string | null {
148
+ // Find an existing config, or default to the most common location
149
+ const existingConfig = findClaudeCodeConfig();
150
+ if (existingConfig) {
151
+ return path.dirname(existingConfig);
152
+ }
153
+
154
+ // Default location for Claude Code config
155
+ const defaultDir = path.join(os.homedir(), '.config', 'claude-code');
156
+ return defaultDir;
157
+ }
158
+
159
+ interface ClaudeCodeConfig {
160
+ mcpServers?: {
161
+ [key: string]: {
162
+ command: string;
163
+ args?: string[];
164
+ env?: Record<string, string>;
165
+ };
166
+ };
167
+ }
168
+
169
+ function addToClaudeCodeConfig(configPath: string): boolean {
170
+ try {
171
+ const configDir = path.dirname(configPath);
172
+
173
+ // Ensure config directory exists
174
+ if (!fs.existsSync(configDir)) {
175
+ fs.mkdirSync(configDir, { recursive: true });
176
+ }
177
+
178
+ // Load existing config or create empty one
179
+ let config: ClaudeCodeConfig = {};
180
+ if (fs.existsSync(configPath)) {
181
+ const content = fs.readFileSync(configPath, 'utf-8');
182
+ config = JSON.parse(content);
183
+ }
184
+
185
+ // Initialize mcpServers if it doesn't exist
186
+ if (!config.mcpServers) {
187
+ config.mcpServers = {};
188
+ }
189
+
190
+ // Check if Ping is already configured
191
+ if (config.mcpServers.ping) {
192
+ printInfo('Ping MCP server is already configured in Claude Code');
193
+ return true;
194
+ }
195
+
196
+ // Add Ping MCP server
197
+ config.mcpServers.ping = {
198
+ command: 'npx',
199
+ args: ['-y', '@ping/mcp-server'],
200
+ };
201
+
202
+ // Write updated config
203
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2));
204
+ printSuccess(`Added Ping MCP server to: ${configPath}`);
205
+ return true;
206
+ } catch (error) {
207
+ printError(`Failed to update Claude Code config: ${error}`);
208
+ return false;
209
+ }
210
+ }
211
+
212
+ // ============================================================
213
+ // MAIN
214
+ // ============================================================
215
+
216
+ async function main() {
217
+ print(BANNER);
218
+ print('Welcome to Ping! Let\'s get you set up.\n');
219
+
220
+ // Step 1: Check API connectivity
221
+ print('Checking API connectivity...');
222
+ const apiOk = await checkApiConnectivity();
223
+ if (apiOk) {
224
+ printSuccess(`Connected to ${API_BASE_URL}`);
225
+ } else {
226
+ printError(`Could not reach ${API_BASE_URL}`);
227
+ printInfo('The API may be temporarily unavailable. You can continue setup.');
228
+ }
229
+ print('');
230
+
231
+ // Step 2: Create config directory
232
+ print('Setting up local configuration...');
233
+ const dirOk = createConfigDirectory();
234
+ if (!dirOk) {
235
+ printError('Setup failed. Please check permissions and try again.');
236
+ process.exit(1);
237
+ }
238
+
239
+ // Step 3: Initialize config file
240
+ const configOk = initializeConfig();
241
+ if (!configOk) {
242
+ printError('Setup failed. Please check permissions and try again.');
243
+ process.exit(1);
244
+ }
245
+ print('');
246
+
247
+ // Step 4: Claude Code integration
248
+ print('Looking for Claude Code configuration...');
249
+ const claudeConfigPath = findClaudeCodeConfig();
250
+ const claudeConfigDir = findClaudeCodeConfigDir();
251
+
252
+ if (claudeConfigPath) {
253
+ printInfo(`Found Claude Code config: ${claudeConfigPath}`);
254
+ } else if (claudeConfigDir) {
255
+ printInfo(`Will create Claude Code config at: ${path.join(claudeConfigDir, 'config.json')}`);
256
+ }
257
+
258
+ const targetConfigPath = claudeConfigPath || path.join(claudeConfigDir!, 'config.json');
259
+
260
+ print('');
261
+ const answer = await prompt('Add Ping MCP server to Claude Code? (y/n): ');
262
+
263
+ if (answer === 'y' || answer === 'yes') {
264
+ const added = addToClaudeCodeConfig(targetConfigPath);
265
+ if (!added) {
266
+ printInfo('You can manually add Ping to your Claude Code config later.');
267
+ }
268
+ } else {
269
+ printInfo('Skipped Claude Code integration.');
270
+ printInfo('You can manually add this to your Claude Code config:');
271
+ print('');
272
+ print(' {');
273
+ print(' "mcpServers": {');
274
+ print(' "ping": {');
275
+ print(' "command": "npx",');
276
+ print(' "args": ["-y", "@ping/mcp-server"]');
277
+ print(' }');
278
+ print(' }');
279
+ print(' }');
280
+ }
281
+
282
+ // Step 5: Success message
283
+ print('');
284
+ print('+------------------------------------------+');
285
+ print('| |');
286
+ print('| Setup complete! |');
287
+ print('| |');
288
+ print('| Next steps: |');
289
+ print('| 1. Restart Claude Code |');
290
+ print('| 2. Say "ping_login" to connect GitHub |');
291
+ print('| 3. Start earning! |');
292
+ print('| |');
293
+ print('+------------------------------------------+');
294
+ print('');
295
+ }
296
+
297
+ main().catch((error) => {
298
+ printError(`Unexpected error: ${error}`);
299
+ process.exit(1);
300
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src"
6
+ },
7
+ "include": ["src/**/*"]
8
+ }