psephos-mcp 0.0.1 → 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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hamit Çevik
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,11 +1,90 @@
1
1
  # psephos-mcp
2
2
 
3
- MCP server for Psephos — coming soon.
3
+ MCP server for **Psephos** — let your AI agents ask for your approval on your
4
+ phone before they do something risky, and wait for your answer.
4
5
 
5
- This release only reserves the package name and does nothing yet. Running it
6
- prints a notice and exits.
6
+ The agent calls `ask_approval`; your iPhone gets a notification with
7
+ **Approve** and **Reject** buttons; your tap goes straight back to the agent.
8
+
9
+ ## Setup
10
+
11
+ 1. Install the Psephos app on your iPhone and open it once. It creates your
12
+ identity and shows your **API key** (`ak_...`).
13
+ 2. Add the server to your MCP client with that key.
14
+
15
+ **Claude Code**
16
+
17
+ ```sh
18
+ claude mcp add psephos -e PSEPHOS_API_KEY=ak_your_key -- npx -y psephos-mcp
19
+ ```
20
+
21
+ **Any MCP client** (JSON config)
22
+
23
+ ```json
24
+ {
25
+ "mcpServers": {
26
+ "psephos": {
27
+ "command": "npx",
28
+ "args": ["-y", "psephos-mcp"],
29
+ "env": { "PSEPHOS_API_KEY": "ak_your_key" }
30
+ }
31
+ }
32
+ }
33
+ ```
34
+
35
+ Requires Node.js 18 or newer.
36
+
37
+ ## Tools
38
+
39
+ ### `ask_approval`
40
+
41
+ Sends an approval request to your phone and waits for the answer.
42
+
43
+ | Parameter | Type | Description |
44
+ |---|---|---|
45
+ | `title` | string, required | Short, clear question |
46
+ | `body` | string | Details: what is being approved |
47
+ | `wait_seconds` | integer 0–600 | How long to wait (default 55) |
48
+
49
+ Returns `status`: `approved`, `rejected`, or `pending` if the wait ran out
50
+ before you answered. On `pending`, the agent keeps waiting with
51
+ `check_approval`.
52
+
53
+ ### `check_approval`
54
+
55
+ Returns the current state of an earlier request, optionally waiting for it.
56
+
57
+ | Parameter | Type | Description |
58
+ |---|---|---|
59
+ | `request_id` | UUID, required | From `ask_approval` |
60
+ | `wait_seconds` | integer 0–600 | How long to wait (default 0 = check now) |
61
+
62
+ `status` can also be `expired`: the request timed out and no longer accepts
63
+ an answer.
64
+
65
+ ## Environment
66
+
67
+ | Variable | Required | Description |
68
+ |---|---|---|
69
+ | `PSEPHOS_API_KEY` | yes | Your API key from the Psephos app |
70
+ | `PSEPHOS_SERVER_URL` | no | Override the server address |
71
+
72
+ ## Good to know
73
+
74
+ - **The buttons appear when you press and hold the notification.** You can
75
+ answer without opening the app.
76
+ - Your key only ever reaches your own devices, and it can send requests but
77
+ cannot answer them — only your phone can.
78
+ - Limits per key: 30 requests per minute and 1000 per day; status checks up
79
+ to 120 per minute.
80
+
81
+ ## License
82
+
83
+ MIT
7
84
 
8
85
  ---
9
86
 
10
- Psephos için MCP sunucusu — yakında. Bu sürüm yalnızca paket adını ayırmak
11
- için yayınlandı ve henüz bir işlevi yok.
87
+ **Türkçe:** Psephos, yapay zekâ ajanlarının riskli bir işlemden önce
88
+ telefonundan onay istemesini sağlar. Uygulamayı açınca görünen API anahtarını
89
+ `PSEPHOS_API_KEY` olarak yukarıdaki yapılandırmaya ekle. Onayla/Reddet
90
+ butonları bildirime basılı tutunca açılır.
package/dist/server.js ADDED
@@ -0,0 +1,117 @@
1
+ #!/usr/bin/env node
2
+ // Psephos MCP sunucusu (npm: psephos-mcp). Kaynak bu dosya; npm paketi bunun
3
+ // derlenmiş hâlini (dist/) taşır, çünkü Node node_modules içindeki .ts
4
+ // dosyalarını çalıştırmaz. Sahip ise repodan doğrudan çalıştırır
5
+ // (.mcp.json: node --env-file-if-exists=.env mcp/server.ts).
6
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
7
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
8
+ import { z } from 'zod';
9
+ // package.json'daki sürümle aynı tutulmalı
10
+ const VERSION = '0.1.0';
11
+ // PSEPHOS_* herkes için; diğer adlar sahibin repodaki kurulumu çalışsın diye
12
+ // (kök .env'i --env-file ile paylaşıyor).
13
+ const SERVER_URL = process.env.PSEPHOS_SERVER_URL ??
14
+ process.env.EXPO_PUBLIC_SERVER_URL ??
15
+ process.env.SERVER_URL ??
16
+ 'https://173-212-253-154.sslip.io';
17
+ const API_KEY = process.env.PSEPHOS_API_KEY ?? process.env.EXPO_PUBLIC_API_KEY ?? process.env.API_KEY ?? '';
18
+ const POLL_INTERVAL_MS = 2000;
19
+ const DEFAULT_WAIT_SECONDS = 55;
20
+ // DİKKAT: stdio taşımasında stdout protokole aittir — log SADECE console.error ile.
21
+ if (!API_KEY) {
22
+ console.error('[psephos] PSEPHOS_API_KEY tanımlı değil. Psephos uygulamasındaki API anahtarını ' +
23
+ 'MCP yapılandırmasına "env": { "PSEPHOS_API_KEY": "ak_..." } olarak ekle.\n' +
24
+ '[psephos] PSEPHOS_API_KEY is not set. Add the API key from the Psephos app to your ' +
25
+ 'MCP config as "env": { "PSEPHOS_API_KEY": "ak_..." }.');
26
+ process.exit(1);
27
+ }
28
+ async function api(path, init) {
29
+ const res = await fetch(`${SERVER_URL}${path}`, {
30
+ ...init,
31
+ headers: { 'Content-Type': 'application/json', 'x-api-key': API_KEY },
32
+ });
33
+ const json = (await res.json().catch(() => ({})));
34
+ if (!res.ok) {
35
+ throw new Error(`Onay sunucusu ${res.status} döndü: ${JSON.stringify(json)}`);
36
+ }
37
+ return json;
38
+ }
39
+ function sleep(ms) {
40
+ return new Promise((resolve) => setTimeout(resolve, ms));
41
+ }
42
+ function toolResult(payload) {
43
+ return { content: [{ type: 'text', text: JSON.stringify(payload) }] };
44
+ }
45
+ async function waitForAnswer(id, deadlineMs) {
46
+ let last;
47
+ do {
48
+ last = await api(`/requests/${id}`);
49
+ if (last.status !== 'pending')
50
+ return last;
51
+ if (Date.now() >= deadlineMs)
52
+ return last;
53
+ await sleep(Math.min(POLL_INTERVAL_MS, Math.max(0, deadlineMs - Date.now())));
54
+ } while (true);
55
+ }
56
+ const server = new McpServer({ name: 'psephos', version: VERSION });
57
+ server.registerTool('ask_approval', {
58
+ title: 'Kullanıcıdan onay iste',
59
+ description: "Kullanıcının telefonuna Onayla/Reddet butonlu push bildirimi gönderir ve cevabı bekler. " +
60
+ "Dönen status: 'approved' (onaylandı), 'rejected' (reddedildi) ya da 'pending' (süre doldu, " +
61
+ "henüz cevap yok). 'pending' dönerse aynı request_id ile check_approval çağırarak beklemeye devam et; " +
62
+ "kullanıcı reddetmedikçe işlemi iptal etme.",
63
+ inputSchema: {
64
+ title: z.string().min(1).describe('Bildirim başlığı — kısa, net bir soru/özet'),
65
+ body: z.string().optional().describe('Detay metni (ne onaylanıyor, kapsamı ne)'),
66
+ wait_seconds: z
67
+ .number()
68
+ .int()
69
+ .min(0)
70
+ .max(600)
71
+ .optional()
72
+ .describe(`Cevap için beklenecek süre, saniye (varsayılan ${DEFAULT_WAIT_SECONDS})`),
73
+ },
74
+ }, async ({ title, body, wait_seconds }) => {
75
+ const created = await api('/requests', {
76
+ method: 'POST',
77
+ body: JSON.stringify({ title, body: body ?? '' }),
78
+ });
79
+ console.error(`[psephos] Onay isteği açıldı: ${created.id} "${title}"`);
80
+ const waitMs = (wait_seconds ?? DEFAULT_WAIT_SECONDS) * 1000;
81
+ const finalState = await waitForAnswer(created.id, Date.now() + waitMs);
82
+ console.error(`[psephos] Sonuç: ${created.id} → ${finalState.status}`);
83
+ return toolResult({
84
+ request_id: finalState.id,
85
+ status: finalState.status,
86
+ responded_at: finalState.respondedAt,
87
+ ...(finalState.status === 'pending'
88
+ ? { note: 'Süre doldu, kullanıcı henüz cevaplamadı. check_approval ile tekrar sorgula.' }
89
+ : {}),
90
+ });
91
+ });
92
+ server.registerTool('check_approval', {
93
+ title: 'Onay durumunu sorgula',
94
+ description: "Daha önce açılmış bir onay isteğinin durumunu döndürür (approved/rejected/pending/expired). " +
95
+ "ask_approval 'pending' döndüyse bununla beklemeye devam edebilirsin. " +
96
+ "'expired': isteğin süresi doldu ve artık cevap kabul etmiyor; gerekiyorsa ask_approval ile yeniden sor.",
97
+ inputSchema: {
98
+ request_id: z.string().uuid().describe('ask_approval çıktısındaki request_id'),
99
+ wait_seconds: z
100
+ .number()
101
+ .int()
102
+ .min(0)
103
+ .max(600)
104
+ .optional()
105
+ .describe('Cevap bekleme süresi; 0 = anlık durum (varsayılan 0)'),
106
+ },
107
+ }, async ({ request_id, wait_seconds }) => {
108
+ const finalState = await waitForAnswer(request_id, Date.now() + (wait_seconds ?? 0) * 1000);
109
+ return toolResult({
110
+ request_id: finalState.id,
111
+ title: finalState.title,
112
+ status: finalState.status,
113
+ responded_at: finalState.respondedAt,
114
+ });
115
+ });
116
+ await server.connect(new StdioServerTransport());
117
+ console.error(`[psephos] MCP sunucusu hazır (stdio) — API: ${SERVER_URL}`);
package/package.json CHANGED
@@ -1,17 +1,38 @@
1
1
  {
2
2
  "name": "psephos-mcp",
3
- "version": "0.0.1",
4
- "description": "MCP server for Psephos (coming soon). This release only reserves the name.",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for Psephos: agents ask for your approval on your phone and wait for the answer.",
5
+ "license": "MIT",
6
+ "type": "module",
5
7
  "bin": {
6
- "psephos-mcp": "bin.js"
8
+ "psephos-mcp": "dist/server.js"
7
9
  },
8
10
  "files": [
9
- "bin.js",
10
- "README.md"
11
+ "dist",
12
+ "README.md",
13
+ "LICENSE"
11
14
  ],
15
+ "engines": {
16
+ "node": ">=18"
17
+ },
12
18
  "keywords": [
13
19
  "mcp",
20
+ "model-context-protocol",
21
+ "approval",
22
+ "human-in-the-loop",
23
+ "notifications",
14
24
  "psephos"
15
25
  ],
16
- "license": "UNLICENSED"
26
+ "scripts": {
27
+ "build": "tsc -p tsconfig.build.json",
28
+ "prepublishOnly": "npm run build"
29
+ },
30
+ "dependencies": {
31
+ "@modelcontextprotocol/sdk": "^1.29.0",
32
+ "zod": "^3.25.76"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^26.1.1",
36
+ "typescript": "~6.0.3"
37
+ }
17
38
  }
package/bin.js DELETED
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env node
2
- console.error('psephos-mcp is not released yet: the Psephos MCP server will be published here soon.');
3
- console.error('psephos-mcp henüz yayında değil: Psephos MCP sunucusu yakında burada olacak.');
4
- process.exit(1);