mcp-pachca 0.2.0 → 0.3.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/.mcp.json +11 -0
- package/README.md +47 -25
- package/dist/auth.js +28 -11
- package/dist/auth.js.map +1 -1
- package/dist/client.js +17 -3
- package/dist/client.js.map +1 -1
- package/dist/index.js +9 -3
- package/dist/index.js.map +1 -1
- package/dist/server.js +2 -2
- package/dist/server.js.map +1 -1
- package/dist/setup.js +38 -26
- package/dist/setup.js.map +1 -1
- package/dist/tools/handlers.js +37 -23
- package/dist/tools/handlers.js.map +1 -1
- package/package.json +1 -1
- package/src/auth.ts +41 -17
- package/src/client.ts +18 -3
- package/src/index.ts +13 -3
- package/src/server.ts +2 -2
- package/src/setup.ts +36 -28
- package/src/tools/handlers.ts +38 -23
package/.mcp.json
ADDED
package/README.md
CHANGED
|
@@ -1,50 +1,72 @@
|
|
|
1
1
|
# mcp-pachca
|
|
2
2
|
|
|
3
|
-
MCP
|
|
3
|
+
MCP-сервер для корпоративного мессенджера [Pachca](https://pachca.com). Позволяет Claude Code, Cursor и другим MCP-клиентам читать чаты, искать сообщения, просматривать пользователей и отправлять сообщения.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Установка
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
```bash
|
|
8
|
+
npx mcp-pachca --setup
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Мастер настройки:
|
|
12
|
+
1. Выберите MCP-клиент (Claude Code / Cursor)
|
|
13
|
+
2. Выберите область конфигурации (проект / глобально)
|
|
14
|
+
3. Введите email от Pachca
|
|
15
|
+
4. Введите 6-значный код из письма
|
|
16
|
+
|
|
17
|
+
Сессия сохраняется в `~/.config/mcp-pachca/session.json`, конфигурация MCP записывается автоматически.
|
|
18
|
+
|
|
19
|
+
### Ручная конфигурация
|
|
20
|
+
|
|
21
|
+
Если мастер уже пройден, можно добавить сервер вручную в `.mcp.json`:
|
|
8
22
|
|
|
9
23
|
```json
|
|
10
24
|
{
|
|
11
25
|
"mcpServers": {
|
|
12
26
|
"pachca": {
|
|
27
|
+
"type": "stdio",
|
|
13
28
|
"command": "npx",
|
|
14
|
-
"args": ["-y", "
|
|
15
|
-
"env": {
|
|
16
|
-
"PACHCA_ACCESS_TOKEN": "your_token_here"
|
|
17
|
-
}
|
|
29
|
+
"args": ["-y", "mcp-pachca@latest"]
|
|
18
30
|
}
|
|
19
31
|
}
|
|
20
32
|
}
|
|
21
33
|
```
|
|
22
34
|
|
|
23
|
-
|
|
35
|
+
## Инструменты
|
|
24
36
|
|
|
25
|
-
|
|
37
|
+
| Инструмент | Описание |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `pachca_search_users` | Поиск пользователей по имени или email |
|
|
40
|
+
| `pachca_get_user` | Получить пользователя по ID |
|
|
41
|
+
| `pachca_list_chats` | Список чатов по папкам (pinned / team / personal) |
|
|
42
|
+
| `pachca_get_chat` | Получить чат по ID |
|
|
43
|
+
| `pachca_get_chat_members` | Участники чата |
|
|
44
|
+
| `pachca_list_messages` | Сообщения в чате (anchor-based пагинация) |
|
|
45
|
+
| `pachca_get_message` | Получить сообщение по ID |
|
|
46
|
+
| `pachca_send_message` | Отправить сообщение в чат |
|
|
47
|
+
| `pachca_search` | Полнотекстовый поиск по сообщениям |
|
|
48
|
+
| `pachca_get_profile` | Текущий пользователь ("кто я") |
|
|
49
|
+
| `pachca_get_unread` | Чаты с непрочитанными сообщениями |
|
|
50
|
+
| `pachca_get_presence` | Онлайн-статус пользователей |
|
|
51
|
+
| `pachca_get_personal_chat` | Найти личный чат с пользователем по его ID |
|
|
26
52
|
|
|
27
|
-
|
|
28
|
-
|------|-------------|
|
|
29
|
-
| `pachca_list_users` | List workspace users (search, pagination) |
|
|
30
|
-
| `pachca_get_user` | Get user by ID |
|
|
31
|
-
| `pachca_list_chats` | List chats/channels (filter, sort, pagination) |
|
|
32
|
-
| `pachca_get_chat` | Get chat by ID |
|
|
33
|
-
| `pachca_get_chat_members` | Get chat members (role filter, pagination) |
|
|
34
|
-
| `pachca_list_messages` | List messages in a chat (pagination) |
|
|
35
|
-
| `pachca_get_message` | Get message by ID |
|
|
36
|
-
| `pachca_list_tags` | List group tags (pagination) |
|
|
37
|
-
| `pachca_get_thread` | Get thread details |
|
|
38
|
-
| `pachca_send_message` | Send message to chat/user/thread |
|
|
39
|
-
|
|
40
|
-
## Development
|
|
53
|
+
## Разработка
|
|
41
54
|
|
|
42
55
|
```bash
|
|
56
|
+
git clone https://github.com/r-ms/mcp-pachca.git
|
|
57
|
+
cd mcp-pachca
|
|
43
58
|
npm install
|
|
44
59
|
npm run build
|
|
45
|
-
|
|
60
|
+
node dist/index.js --setup # авторизация
|
|
61
|
+
node dist/index.js # запуск сервера
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Для отладки запросов к API:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
DEBUG=1 node dist/index.js
|
|
46
68
|
```
|
|
47
69
|
|
|
48
|
-
##
|
|
70
|
+
## Лицензия
|
|
49
71
|
|
|
50
72
|
MIT
|
package/dist/auth.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import * as os from "node:os";
|
|
4
|
+
import { logger } from "./logger.js";
|
|
4
5
|
const BASE_URL = "https://app.pachca.com/api/v3";
|
|
5
6
|
export function getSessionPath() {
|
|
6
7
|
return path.join(os.homedir(), ".config", "mcp-pachca", "session.json");
|
|
@@ -9,16 +10,29 @@ export function loadSession() {
|
|
|
9
10
|
const p = getSessionPath();
|
|
10
11
|
try {
|
|
11
12
|
const raw = fs.readFileSync(p, "utf8");
|
|
12
|
-
|
|
13
|
+
const data = JSON.parse(raw);
|
|
14
|
+
if (typeof data.email !== "string" ||
|
|
15
|
+
typeof data.jwt !== "string" ||
|
|
16
|
+
typeof data.workspaceJwt !== "string" ||
|
|
17
|
+
typeof data.profileId !== "number" ||
|
|
18
|
+
typeof data.companyId !== "number" ||
|
|
19
|
+
!Array.isArray(data.cookies) ||
|
|
20
|
+
!data.cookies.every((c) => typeof c === "string")) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return data;
|
|
13
24
|
}
|
|
14
|
-
catch {
|
|
25
|
+
catch (err) {
|
|
26
|
+
if (err instanceof Error && (!("code" in err) || err.code !== "ENOENT")) {
|
|
27
|
+
logger.error("Failed to load session", { error: String(err) });
|
|
28
|
+
}
|
|
15
29
|
return null;
|
|
16
30
|
}
|
|
17
31
|
}
|
|
18
32
|
export function saveSession(session) {
|
|
19
33
|
const p = getSessionPath();
|
|
20
|
-
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
21
|
-
fs.writeFileSync(p, JSON.stringify(session, null, 2) + "\n", "utf8");
|
|
34
|
+
fs.mkdirSync(path.dirname(p), { recursive: true, mode: 0o700 });
|
|
35
|
+
fs.writeFileSync(p, JSON.stringify(session, null, 2) + "\n", { encoding: "utf8", mode: 0o600 });
|
|
22
36
|
}
|
|
23
37
|
export async function requestOTP(email) {
|
|
24
38
|
const res = await fetch(`${BASE_URL}/account/code`, {
|
|
@@ -53,17 +67,20 @@ export async function performLogin(email, code) {
|
|
|
53
67
|
const body = await wsRes.text();
|
|
54
68
|
throw new Error(`Failed to fetch workspaces (HTTP ${wsRes.status}): ${body}`);
|
|
55
69
|
}
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
70
|
+
// Response shape: { data: [{ workspaces: [{ actual_profile: { id, jwt, company_id, ... } }] }] }
|
|
71
|
+
const wsBody = (await wsRes.json());
|
|
72
|
+
const account = wsBody.data?.[0];
|
|
73
|
+
const workspace = account?.workspaces?.[0];
|
|
74
|
+
const profile = workspace?.actual_profile;
|
|
75
|
+
if (!profile?.jwt) {
|
|
76
|
+
throw new Error("No workspace found for this account");
|
|
59
77
|
}
|
|
60
|
-
const ws = wsData[0];
|
|
61
78
|
return {
|
|
62
79
|
email,
|
|
63
80
|
jwt,
|
|
64
|
-
workspaceJwt:
|
|
65
|
-
profileId:
|
|
66
|
-
companyId:
|
|
81
|
+
workspaceJwt: profile.jwt,
|
|
82
|
+
profileId: profile.id,
|
|
83
|
+
companyId: profile.company_id,
|
|
67
84
|
cookies,
|
|
68
85
|
createdAt: new Date().toISOString(),
|
|
69
86
|
};
|
package/dist/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/client.js
CHANGED
|
@@ -43,6 +43,7 @@ export class PachcaClient {
|
|
|
43
43
|
const headers = {
|
|
44
44
|
Authorization: `Bearer ${this.session.workspaceJwt}`,
|
|
45
45
|
Accept: "application/json",
|
|
46
|
+
"user-id": String(this.session.profileId),
|
|
46
47
|
};
|
|
47
48
|
if (this.session.cookies.length > 0) {
|
|
48
49
|
headers["Cookie"] = this.session.cookies.join("; ");
|
|
@@ -60,15 +61,17 @@ export class PachcaClient {
|
|
|
60
61
|
return undefined;
|
|
61
62
|
}
|
|
62
63
|
if (response.status === 401) {
|
|
64
|
+
await response.text();
|
|
63
65
|
throw new Error("Session expired. Run: npx mcp-pachca --setup");
|
|
64
66
|
}
|
|
65
67
|
if (!response.ok) {
|
|
68
|
+
const rawBody = await response.text();
|
|
66
69
|
let errorBody;
|
|
67
70
|
try {
|
|
68
|
-
errorBody =
|
|
71
|
+
errorBody = JSON.parse(rawBody);
|
|
69
72
|
}
|
|
70
73
|
catch {
|
|
71
|
-
errorBody =
|
|
74
|
+
errorBody = rawBody;
|
|
72
75
|
}
|
|
73
76
|
logger.error("Pachca API error", {
|
|
74
77
|
status: response.status,
|
|
@@ -76,7 +79,18 @@ export class PachcaClient {
|
|
|
76
79
|
});
|
|
77
80
|
throw new Error(`Pachca API error (HTTP ${response.status}): ${JSON.stringify(errorBody)}`);
|
|
78
81
|
}
|
|
79
|
-
|
|
82
|
+
const rawText = await response.text();
|
|
83
|
+
let data;
|
|
84
|
+
try {
|
|
85
|
+
data = JSON.parse(rawText);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
throw new Error(`Pachca API returned non-JSON response (HTTP ${response.status}): ${rawText.slice(0, 200)}`);
|
|
89
|
+
}
|
|
90
|
+
if (process.env["DEBUG"]) {
|
|
91
|
+
logger.debug("Pachca API response", { method, url, body: data });
|
|
92
|
+
}
|
|
93
|
+
return data;
|
|
80
94
|
}
|
|
81
95
|
catch (err) {
|
|
82
96
|
if (err instanceof Error && err.name === "AbortError") {
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,MAAM,OAAO,YAAY;IACN,OAAO,GAAG,+BAA+B,CAAC;IAC1C,OAAO,CAAU;IAElC,YAAY,OAAgB;QAC1B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,GAAG,CAAI,IAAY,EAAE,MAA+B;QACxD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC,CAAC;QAC9C,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;oBACxC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;gBACnC,CAAC;YACH,CAAC;QACH,CAAC;QACD,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAI,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAM,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,kBAAkB,CACtB,IAAY,EACZ,WAAgD,EAChD,MAA+B;QAE/B,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,CAAC,CAAC;QAC9C,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAClD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;oBACxC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;gBACnC,CAAC;YACH,CAAC;QACH,CAAC;QACD,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;YACxD,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;gBACvB,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,GAAG,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;YACjD,CAAC;QACH,CAAC;QACD,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,CAAI,KAAK,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAM,CAAC;IAC7D,CAAC;IAED,KAAK,CAAC,IAAI,CAAI,IAAY,EAAE,IAAa;QACvC,OAAO,IAAI,CAAC,OAAO,CAAI,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;IACjE,CAAC;IAEO,KAAK,CAAC,OAAO,CACnB,MAAc,EACd,GAAW,EACX,IAAc;QAEd,MAAM,CAAC,KAAK,CAAC,oBAAoB,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAEpD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC;QAE7D,IAAI,CAAC;YACH,MAAM,OAAO,GAA2B;gBACtC,aAAa,EAAE,UAAU,IAAI,CAAC,OAAO,CAAC,YAAY,EAAE;gBACpD,MAAM,EAAE,kBAAkB;
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { loadSession } from "./auth.js";
|
|
|
5
5
|
import { logger } from "./logger.js";
|
|
6
6
|
import { runSetup } from "./setup.js";
|
|
7
7
|
async function main() {
|
|
8
|
-
if (process.argv
|
|
8
|
+
if (process.argv[2] === "--setup") {
|
|
9
9
|
await runSetup();
|
|
10
10
|
process.exit(0);
|
|
11
11
|
}
|
|
@@ -21,8 +21,14 @@ async function main() {
|
|
|
21
21
|
await server.close();
|
|
22
22
|
process.exit(0);
|
|
23
23
|
};
|
|
24
|
-
process.on("SIGINT", () =>
|
|
25
|
-
|
|
24
|
+
process.on("SIGINT", () => shutdown("SIGINT").catch((err) => {
|
|
25
|
+
logger.error("Error during shutdown", { error: String(err) });
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}));
|
|
28
|
+
process.on("SIGTERM", () => shutdown("SIGTERM").catch((err) => {
|
|
29
|
+
logger.error("Error during shutdown", { error: String(err) });
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}));
|
|
26
32
|
await server.connect(transport);
|
|
27
33
|
logger.info("MCP Pachca server started");
|
|
28
34
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,KAAK,UAAU,IAAI;IACjB,IAAI,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,KAAK,UAAU,IAAI;IACjB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;QAClC,MAAM,QAAQ,EAAE,CAAC;QACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;IAC9B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,+CAA+C,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAE7C,MAAM,QAAQ,GAAG,KAAK,EAAE,MAAc,EAAiB,EAAE;QACvD,MAAM,CAAC,IAAI,CAAC,YAAY,MAAM,iBAAiB,CAAC,CAAC;QACjD,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;QACrB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC;IAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CACxB,QAAQ,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QAC/B,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CACH,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CACzB,QAAQ,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QAChC,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CACH,CAAC;IAEF,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,MAAM,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;AAC3C,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;IAC5B,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,GAAG,CAAC,CAAC;IACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/dist/server.js
CHANGED
|
@@ -6,7 +6,7 @@ import { handlerRegistry } from "./tools/handlers.js";
|
|
|
6
6
|
import { logger } from "./logger.js";
|
|
7
7
|
export function createServer(session) {
|
|
8
8
|
const client = new PachcaClient(session);
|
|
9
|
-
const server = new Server({ name: "mcp-pachca", version: "0.
|
|
9
|
+
const server = new Server({ name: "mcp-pachca", version: "0.3.0" }, { capabilities: { tools: {} } });
|
|
10
10
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
11
11
|
tools: toolDefinitions,
|
|
12
12
|
}));
|
|
@@ -21,7 +21,7 @@ export function createServer(session) {
|
|
|
21
21
|
}
|
|
22
22
|
try {
|
|
23
23
|
const result = await handler(client, (args ?? {}));
|
|
24
|
-
const text = JSON.stringify(result, null, 2);
|
|
24
|
+
const text = JSON.stringify(result, null, 2) ?? "null";
|
|
25
25
|
return { content: [{ type: "text", text }] };
|
|
26
26
|
}
|
|
27
27
|
catch (err) {
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC;IAEzC,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,EACxC,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAChC,CAAC;IAEF,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,EAAE,eAAe;KACvB,CAAC,CAAC,CAAC;IAEJ,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAChE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QACjD,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QAEtC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,iBAAiB,IAAI,EAAE,EAAE,CAAC;gBACnE,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,EAAE,CAA4B,CAAC,CAAC;YAC9E,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EACL,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,oCAAoC,CAAC;AAE5C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,MAAM,MAAM,GAAG,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC;IAEzC,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,EACxC,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAChC,CAAC;IAEF,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,EAAE,eAAe;KACvB,CAAC,CAAC,CAAC;IAEJ,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE;QAChE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QACjD,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;QAEtC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,iBAAiB,IAAI,EAAE,EAAE,CAAC;gBACnE,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,EAAE,CAA4B,CAAC,CAAC;YAC9E,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC;YACvD,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC;QACxD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,KAAK,CAAC,kBAAkB,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACrE,MAAM,OAAO,GACX,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,gCAAgC,CAAC;YACxE,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;gBACnD,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/setup.js
CHANGED
|
@@ -14,11 +14,15 @@ function stderrln(msg = "") {
|
|
|
14
14
|
// --- Prompt helpers ---
|
|
15
15
|
/** Collect all lines from a non-TTY stdin upfront (avoids readline buffering issues). */
|
|
16
16
|
function readAllLines() {
|
|
17
|
-
return new Promise((resolve) => {
|
|
17
|
+
return new Promise((resolve, reject) => {
|
|
18
18
|
const lines = [];
|
|
19
19
|
const iface = rl.createInterface({ input: process.stdin });
|
|
20
20
|
iface.on("line", (line) => lines.push(line));
|
|
21
21
|
iface.on("close", () => resolve(lines));
|
|
22
|
+
iface.on("error", (err) => {
|
|
23
|
+
iface.close();
|
|
24
|
+
reject(err);
|
|
25
|
+
});
|
|
22
26
|
});
|
|
23
27
|
}
|
|
24
28
|
/** Simple line-based prompter backed by a pre-read array (non-TTY). */
|
|
@@ -51,7 +55,7 @@ function makeTTYPrompter() {
|
|
|
51
55
|
};
|
|
52
56
|
}
|
|
53
57
|
// --- Choice helper ---
|
|
54
|
-
async function askChoice(ask, question, choices) {
|
|
58
|
+
async function askChoice(ask, question, choices, retry = true) {
|
|
55
59
|
stderrln(question);
|
|
56
60
|
for (let i = 0; i < choices.length; i++) {
|
|
57
61
|
stderrln(` ${i + 1}) ${choices[i]}`);
|
|
@@ -62,6 +66,10 @@ async function askChoice(ask, question, choices) {
|
|
|
62
66
|
if (n >= 1 && n <= choices.length) {
|
|
63
67
|
return choices[n - 1];
|
|
64
68
|
}
|
|
69
|
+
if (!retry) {
|
|
70
|
+
stderrln(`Error: invalid choice "${raw}". Expected a number between 1 and ${choices.length}.`);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
65
73
|
stderrln(`Please enter a number between 1 and ${choices.length}.`);
|
|
66
74
|
}
|
|
67
75
|
}
|
|
@@ -78,11 +86,15 @@ function resolveConfigPath(client, scope) {
|
|
|
78
86
|
: path.join(os.homedir(), ".cursor", "mcp.json");
|
|
79
87
|
}
|
|
80
88
|
function buildEntry() {
|
|
81
|
-
|
|
89
|
+
const entry = {
|
|
82
90
|
type: "stdio",
|
|
83
91
|
command: "npx",
|
|
84
92
|
args: ["-y", "mcp-pachca@latest"],
|
|
85
93
|
};
|
|
94
|
+
if (process.env["DEBUG"]) {
|
|
95
|
+
entry["env"] = { DEBUG: "1" };
|
|
96
|
+
}
|
|
97
|
+
return entry;
|
|
86
98
|
}
|
|
87
99
|
// --- Main ---
|
|
88
100
|
export async function runSetup() {
|
|
@@ -91,42 +103,41 @@ export async function runSetup() {
|
|
|
91
103
|
let scope;
|
|
92
104
|
let email;
|
|
93
105
|
let code;
|
|
94
|
-
if (process.stdin.isTTY) {
|
|
95
|
-
|
|
106
|
+
if (!process.stdin.isTTY) {
|
|
107
|
+
stderrln("Error: --setup requires an interactive terminal (OTP code is sent via email).");
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
const prompter = makeTTYPrompter();
|
|
111
|
+
try {
|
|
96
112
|
client = await askChoice(prompter.ask, "Select your MCP client:", CLIENTS);
|
|
97
113
|
scope = await askChoice(prompter.ask, "Select config scope:", SCOPES);
|
|
98
114
|
email = await prompter.ask("Enter your Pachca email: ");
|
|
99
|
-
if (!email) {
|
|
100
|
-
stderrln("Error: email
|
|
115
|
+
if (!email || !email.includes("@")) {
|
|
116
|
+
stderrln("Error: invalid email address.");
|
|
101
117
|
process.exit(1);
|
|
102
118
|
}
|
|
103
119
|
stderrln("\nRequesting login code...");
|
|
104
120
|
await requestOTP(email);
|
|
105
121
|
stderrln("Check your email for the 6-digit code.");
|
|
106
122
|
code = await prompter.ask("Enter the code: ");
|
|
107
|
-
prompter.close();
|
|
108
123
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const prompter = makePipePrompter(lines);
|
|
112
|
-
client = await askChoice(prompter.ask, "Select your MCP client:", CLIENTS);
|
|
113
|
-
scope = await askChoice(prompter.ask, "Select config scope:", SCOPES);
|
|
114
|
-
email = prompter.ask("Enter your Pachca email: ");
|
|
115
|
-
if (!email) {
|
|
116
|
-
stderrln("Error: email cannot be empty.");
|
|
117
|
-
process.exit(1);
|
|
118
|
-
}
|
|
119
|
-
stderrln("\nRequesting login code...");
|
|
120
|
-
await requestOTP(email);
|
|
121
|
-
stderrln("Check your email for the 6-digit code.");
|
|
122
|
-
code = prompter.ask("Enter the code: ");
|
|
124
|
+
finally {
|
|
125
|
+
prompter.close();
|
|
123
126
|
}
|
|
124
|
-
if (!code) {
|
|
125
|
-
stderrln("Error: code
|
|
127
|
+
if (!code || !/^\d{6}$/.test(code)) {
|
|
128
|
+
stderrln("Error: code must be exactly 6 digits.");
|
|
126
129
|
process.exit(1);
|
|
127
130
|
}
|
|
128
131
|
stderrln("Logging in...");
|
|
129
|
-
|
|
132
|
+
let session;
|
|
133
|
+
try {
|
|
134
|
+
session = await performLogin(email, code);
|
|
135
|
+
}
|
|
136
|
+
catch (err) {
|
|
137
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
138
|
+
stderrln(`\nLogin failed: ${msg}`);
|
|
139
|
+
process.exit(1);
|
|
140
|
+
}
|
|
130
141
|
saveSession(session);
|
|
131
142
|
stderrln(`Session saved to ~/.config/mcp-pachca/session.json`);
|
|
132
143
|
// Write MCP config
|
|
@@ -147,7 +158,8 @@ export async function runSetup() {
|
|
|
147
158
|
else {
|
|
148
159
|
config = {};
|
|
149
160
|
}
|
|
150
|
-
const
|
|
161
|
+
const raw = config["mcpServers"];
|
|
162
|
+
const servers = (raw !== null && typeof raw === "object" && !Array.isArray(raw) ? raw : {});
|
|
151
163
|
servers["pachca"] = buildEntry();
|
|
152
164
|
config["mcpServers"] = servers;
|
|
153
165
|
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf8");
|
package/dist/setup.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAElE,MAAM,OAAO,GAAG,CAAC,aAAa,EAAE,QAAQ,CAAU,CAAC;AAGnD,MAAM,MAAM,GAAG,CAAC,SAAS,EAAE,QAAQ,CAAU,CAAC;AAG9C,SAAS,MAAM,CAAC,GAAW;IACzB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,QAAQ,CAAC,MAAc,EAAE;IAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,CAAC,CAAC;AACnC,CAAC;AAED,yBAAyB;AAEzB,yFAAyF;AACzF,SAAS,YAAY;IACnB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/handlers.js
CHANGED
|
@@ -4,7 +4,7 @@ async function handleSearchUsers(client, args) {
|
|
|
4
4
|
type: "user",
|
|
5
5
|
query: String(args["query"]),
|
|
6
6
|
};
|
|
7
|
-
if (args["cursor"])
|
|
7
|
+
if (args["cursor"] !== undefined)
|
|
8
8
|
params["cursor"] = String(args["cursor"]);
|
|
9
9
|
return client.get("/search", params);
|
|
10
10
|
}
|
|
@@ -15,26 +15,24 @@ async function handleGetUser(client, args) {
|
|
|
15
15
|
return data.data[0];
|
|
16
16
|
}
|
|
17
17
|
async function handleListChats(client, args) {
|
|
18
|
-
const
|
|
18
|
+
const res = await client.get("/menu/folders");
|
|
19
|
+
const folders = res?.data ?? [];
|
|
19
20
|
const folderKind = args["folder"];
|
|
20
21
|
if (!folderKind) {
|
|
21
22
|
return {
|
|
22
|
-
folders: folders
|
|
23
|
+
folders: folders.map((f) => ({
|
|
23
24
|
id: f.id,
|
|
24
25
|
title: f.title,
|
|
25
26
|
kind: f.kind,
|
|
26
27
|
})),
|
|
27
28
|
};
|
|
28
29
|
}
|
|
29
|
-
const folder = folders
|
|
30
|
+
const folder = folders.find((f) => f.kind === folderKind);
|
|
30
31
|
if (!folder) {
|
|
31
|
-
|
|
32
|
-
error: `Folder "${folderKind}" not found`,
|
|
33
|
-
available: folders?.map((f) => f.kind),
|
|
34
|
-
};
|
|
32
|
+
throw new Error(`Folder "${folderKind}" not found. Available: ${folders.map((f) => f.kind).join(", ")}`);
|
|
35
33
|
}
|
|
36
34
|
const params = {};
|
|
37
|
-
if (args["cursor"])
|
|
35
|
+
if (args["cursor"] !== undefined)
|
|
38
36
|
params["cursor"] = String(args["cursor"]);
|
|
39
37
|
return client.get(`/menu/folders/${folder.id}/chats`, params);
|
|
40
38
|
}
|
|
@@ -45,23 +43,28 @@ async function handleGetChat(client, args) {
|
|
|
45
43
|
return data.records[0];
|
|
46
44
|
}
|
|
47
45
|
async function handleGetChatMembers(client, args) {
|
|
46
|
+
const chatId = Number(args["id"]);
|
|
48
47
|
const params = {};
|
|
49
|
-
if (args["limit"])
|
|
48
|
+
if (args["limit"] !== undefined)
|
|
50
49
|
params["limit"] = String(args["limit"]);
|
|
51
|
-
if (args["cursor"])
|
|
50
|
+
if (args["cursor"] !== undefined)
|
|
52
51
|
params["cursor"] = String(args["cursor"]);
|
|
53
|
-
return client.get(`/chats/${
|
|
52
|
+
return client.get(`/chats/${chatId}/users`, params);
|
|
54
53
|
}
|
|
55
54
|
async function handleListMessages(client, args) {
|
|
56
55
|
const params = {
|
|
57
56
|
chat_id: String(args["chat_id"]),
|
|
58
57
|
};
|
|
59
|
-
if (args["per"])
|
|
58
|
+
if (args["per"] !== undefined)
|
|
60
59
|
params["per"] = String(args["per"]);
|
|
61
|
-
if (args["message_id"])
|
|
60
|
+
if (args["message_id"] !== undefined)
|
|
62
61
|
params["message_id"] = String(args["message_id"]);
|
|
63
|
-
if (args["direction"])
|
|
62
|
+
if (args["direction"] !== undefined) {
|
|
63
|
+
if (args["message_id"] === undefined) {
|
|
64
|
+
throw new Error("direction requires message_id to be set");
|
|
65
|
+
}
|
|
64
66
|
params["direction"] = String(args["direction"]);
|
|
67
|
+
}
|
|
65
68
|
return client.get("/messages", params);
|
|
66
69
|
}
|
|
67
70
|
async function handleGetMessage(client, args) {
|
|
@@ -73,23 +76,30 @@ async function handleGetMessage(client, args) {
|
|
|
73
76
|
return data[0];
|
|
74
77
|
}
|
|
75
78
|
async function handleSendMessage(client, args) {
|
|
76
|
-
const
|
|
77
|
-
chat_id: Number(args["chat_id"]),
|
|
78
|
-
text: String(args["text"]),
|
|
79
|
+
const message = {
|
|
79
80
|
uuid: randomUUID(),
|
|
81
|
+
content: String(args["text"]),
|
|
82
|
+
markup: [],
|
|
83
|
+
kind: 0,
|
|
84
|
+
files: [],
|
|
85
|
+
skip_invite_mentions: false,
|
|
80
86
|
};
|
|
81
|
-
if (args["parent_message_id"]) {
|
|
82
|
-
|
|
87
|
+
if (args["parent_message_id"] !== undefined) {
|
|
88
|
+
message["parent_message_id"] = Number(args["parent_message_id"]);
|
|
83
89
|
}
|
|
90
|
+
const body = {
|
|
91
|
+
chat_id: Number(args["chat_id"]),
|
|
92
|
+
message,
|
|
93
|
+
};
|
|
84
94
|
const result = await client.post("/messages", body);
|
|
85
|
-
return result ?? { success: true };
|
|
95
|
+
return result ?? { success: true, uuid: message.uuid, chat_id: body.chat_id };
|
|
86
96
|
}
|
|
87
97
|
async function handleSearch(client, args) {
|
|
88
98
|
const params = {
|
|
89
99
|
type: "message",
|
|
90
100
|
query: String(args["query"]),
|
|
91
101
|
};
|
|
92
|
-
if (args["cursor"])
|
|
102
|
+
if (args["cursor"] !== undefined)
|
|
93
103
|
params["cursor"] = String(args["cursor"]);
|
|
94
104
|
return client.get("/search", params);
|
|
95
105
|
}
|
|
@@ -100,7 +110,11 @@ async function handleGetUnread(client) {
|
|
|
100
110
|
return client.get("/chats/unread_ids");
|
|
101
111
|
}
|
|
102
112
|
async function handleGetPresence(client, args) {
|
|
103
|
-
const
|
|
113
|
+
const rawIds = args["ids"];
|
|
114
|
+
if (!Array.isArray(rawIds) || rawIds.length === 0) {
|
|
115
|
+
throw new Error("ids must be a non-empty array of numbers");
|
|
116
|
+
}
|
|
117
|
+
const ids = rawIds.map((id) => Number(id));
|
|
104
118
|
return client.getWithArrayParams("/friends/presence", {
|
|
105
119
|
ids,
|
|
106
120
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/tools/handlers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAkBzC,KAAK,UAAU,iBAAiB,CAC9B,MAAoB,EACpB,IAA6B;IAE7B,MAAM,MAAM,GAA2B;QACrC,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;KAC7B,CAAC;IACF,IAAI,IAAI,CAAC,QAAQ,CAAC;QAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/tools/handlers.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/auth.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import * as os from "node:os";
|
|
4
|
+
import { logger } from "./logger.js";
|
|
4
5
|
|
|
5
6
|
export interface Session {
|
|
6
7
|
email: string;
|
|
@@ -22,16 +23,31 @@ export function loadSession(): Session | null {
|
|
|
22
23
|
const p = getSessionPath();
|
|
23
24
|
try {
|
|
24
25
|
const raw = fs.readFileSync(p, "utf8");
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
const data = JSON.parse(raw) as Record<string, unknown>;
|
|
27
|
+
if (
|
|
28
|
+
typeof data.email !== "string" ||
|
|
29
|
+
typeof data.jwt !== "string" ||
|
|
30
|
+
typeof data.workspaceJwt !== "string" ||
|
|
31
|
+
typeof data.profileId !== "number" ||
|
|
32
|
+
typeof data.companyId !== "number" ||
|
|
33
|
+
!Array.isArray(data.cookies) ||
|
|
34
|
+
!data.cookies.every((c: unknown) => typeof c === "string")
|
|
35
|
+
) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
return data as unknown as Session;
|
|
39
|
+
} catch (err: unknown) {
|
|
40
|
+
if (err instanceof Error && (!("code" in err) || (err as NodeJS.ErrnoException).code !== "ENOENT")) {
|
|
41
|
+
logger.error("Failed to load session", { error: String(err) });
|
|
42
|
+
}
|
|
27
43
|
return null;
|
|
28
44
|
}
|
|
29
45
|
}
|
|
30
46
|
|
|
31
47
|
export function saveSession(session: Session): void {
|
|
32
48
|
const p = getSessionPath();
|
|
33
|
-
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
34
|
-
fs.writeFileSync(p, JSON.stringify(session, null, 2) + "\n", "utf8");
|
|
49
|
+
fs.mkdirSync(path.dirname(p), { recursive: true, mode: 0o700 });
|
|
50
|
+
fs.writeFileSync(p, JSON.stringify(session, null, 2) + "\n", { encoding: "utf8", mode: 0o600 });
|
|
35
51
|
}
|
|
36
52
|
|
|
37
53
|
export async function requestOTP(email: string): Promise<void> {
|
|
@@ -79,25 +95,33 @@ export async function performLogin(
|
|
|
79
95
|
);
|
|
80
96
|
}
|
|
81
97
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
98
|
+
// Response shape: { data: [{ workspaces: [{ actual_profile: { id, jwt, company_id, ... } }] }] }
|
|
99
|
+
const wsBody = (await wsRes.json()) as {
|
|
100
|
+
data: Array<{
|
|
101
|
+
workspaces: Array<{
|
|
102
|
+
actual_profile: {
|
|
103
|
+
id: number;
|
|
104
|
+
jwt: string;
|
|
105
|
+
company_id: number;
|
|
106
|
+
};
|
|
107
|
+
}>;
|
|
108
|
+
}>;
|
|
109
|
+
};
|
|
88
110
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
111
|
+
const account = wsBody.data?.[0];
|
|
112
|
+
const workspace = account?.workspaces?.[0];
|
|
113
|
+
const profile = workspace?.actual_profile;
|
|
92
114
|
|
|
93
|
-
|
|
115
|
+
if (!profile?.jwt) {
|
|
116
|
+
throw new Error("No workspace found for this account");
|
|
117
|
+
}
|
|
94
118
|
|
|
95
119
|
return {
|
|
96
120
|
email,
|
|
97
121
|
jwt,
|
|
98
|
-
workspaceJwt:
|
|
99
|
-
profileId:
|
|
100
|
-
companyId:
|
|
122
|
+
workspaceJwt: profile.jwt,
|
|
123
|
+
profileId: profile.id,
|
|
124
|
+
companyId: profile.company_id,
|
|
101
125
|
cookies,
|
|
102
126
|
createdAt: new Date().toISOString(),
|
|
103
127
|
};
|
package/src/client.ts
CHANGED
|
@@ -60,6 +60,7 @@ export class PachcaClient {
|
|
|
60
60
|
const headers: Record<string, string> = {
|
|
61
61
|
Authorization: `Bearer ${this.session.workspaceJwt}`,
|
|
62
62
|
Accept: "application/json",
|
|
63
|
+
"user-id": String(this.session.profileId),
|
|
63
64
|
};
|
|
64
65
|
|
|
65
66
|
if (this.session.cookies.length > 0) {
|
|
@@ -82,15 +83,17 @@ export class PachcaClient {
|
|
|
82
83
|
}
|
|
83
84
|
|
|
84
85
|
if (response.status === 401) {
|
|
86
|
+
await response.text();
|
|
85
87
|
throw new Error("Session expired. Run: npx mcp-pachca --setup");
|
|
86
88
|
}
|
|
87
89
|
|
|
88
90
|
if (!response.ok) {
|
|
91
|
+
const rawBody = await response.text();
|
|
89
92
|
let errorBody: unknown;
|
|
90
93
|
try {
|
|
91
|
-
errorBody =
|
|
94
|
+
errorBody = JSON.parse(rawBody);
|
|
92
95
|
} catch {
|
|
93
|
-
errorBody =
|
|
96
|
+
errorBody = rawBody;
|
|
94
97
|
}
|
|
95
98
|
logger.error("Pachca API error", {
|
|
96
99
|
status: response.status,
|
|
@@ -101,7 +104,19 @@ export class PachcaClient {
|
|
|
101
104
|
);
|
|
102
105
|
}
|
|
103
106
|
|
|
104
|
-
|
|
107
|
+
const rawText = await response.text();
|
|
108
|
+
let data: T;
|
|
109
|
+
try {
|
|
110
|
+
data = JSON.parse(rawText) as T;
|
|
111
|
+
} catch {
|
|
112
|
+
throw new Error(
|
|
113
|
+
`Pachca API returned non-JSON response (HTTP ${response.status}): ${rawText.slice(0, 200)}`,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
if (process.env["DEBUG"]) {
|
|
117
|
+
logger.debug("Pachca API response", { method, url, body: data });
|
|
118
|
+
}
|
|
119
|
+
return data;
|
|
105
120
|
} catch (err) {
|
|
106
121
|
if (err instanceof Error && err.name === "AbortError") {
|
|
107
122
|
logger.error("Pachca API request timeout", { url });
|
package/src/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { logger } from "./logger.js";
|
|
|
7
7
|
import { runSetup } from "./setup.js";
|
|
8
8
|
|
|
9
9
|
async function main(): Promise<void> {
|
|
10
|
-
if (process.argv
|
|
10
|
+
if (process.argv[2] === "--setup") {
|
|
11
11
|
await runSetup();
|
|
12
12
|
process.exit(0);
|
|
13
13
|
}
|
|
@@ -27,8 +27,18 @@ async function main(): Promise<void> {
|
|
|
27
27
|
process.exit(0);
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
-
process.on("SIGINT", () =>
|
|
31
|
-
|
|
30
|
+
process.on("SIGINT", () =>
|
|
31
|
+
shutdown("SIGINT").catch((err) => {
|
|
32
|
+
logger.error("Error during shutdown", { error: String(err) });
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}),
|
|
35
|
+
);
|
|
36
|
+
process.on("SIGTERM", () =>
|
|
37
|
+
shutdown("SIGTERM").catch((err) => {
|
|
38
|
+
logger.error("Error during shutdown", { error: String(err) });
|
|
39
|
+
process.exit(1);
|
|
40
|
+
}),
|
|
41
|
+
);
|
|
32
42
|
|
|
33
43
|
await server.connect(transport);
|
|
34
44
|
logger.info("MCP Pachca server started");
|
package/src/server.ts
CHANGED
|
@@ -13,7 +13,7 @@ export function createServer(session: Session): Server {
|
|
|
13
13
|
const client = new PachcaClient(session);
|
|
14
14
|
|
|
15
15
|
const server = new Server(
|
|
16
|
-
{ name: "mcp-pachca", version: "0.
|
|
16
|
+
{ name: "mcp-pachca", version: "0.3.0" },
|
|
17
17
|
{ capabilities: { tools: {} } },
|
|
18
18
|
);
|
|
19
19
|
|
|
@@ -34,7 +34,7 @@ export function createServer(session: Session): Server {
|
|
|
34
34
|
|
|
35
35
|
try {
|
|
36
36
|
const result = await handler(client, (args ?? {}) as Record<string, unknown>);
|
|
37
|
-
const text = JSON.stringify(result, null, 2);
|
|
37
|
+
const text = JSON.stringify(result, null, 2) ?? "null";
|
|
38
38
|
return { content: [{ type: "text" as const, text }] };
|
|
39
39
|
} catch (err) {
|
|
40
40
|
logger.error("Tool call failed", { tool: name, error: String(err) });
|
package/src/setup.ts
CHANGED
|
@@ -22,11 +22,15 @@ function stderrln(msg: string = ""): void {
|
|
|
22
22
|
|
|
23
23
|
/** Collect all lines from a non-TTY stdin upfront (avoids readline buffering issues). */
|
|
24
24
|
function readAllLines(): Promise<string[]> {
|
|
25
|
-
return new Promise((resolve) => {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
26
|
const lines: string[] = [];
|
|
27
27
|
const iface = rl.createInterface({ input: process.stdin });
|
|
28
28
|
iface.on("line", (line) => lines.push(line));
|
|
29
29
|
iface.on("close", () => resolve(lines));
|
|
30
|
+
iface.on("error", (err) => {
|
|
31
|
+
iface.close();
|
|
32
|
+
reject(err);
|
|
33
|
+
});
|
|
30
34
|
});
|
|
31
35
|
}
|
|
32
36
|
|
|
@@ -67,6 +71,7 @@ async function askChoice<T extends string>(
|
|
|
67
71
|
ask: (q: string) => string | Promise<string>,
|
|
68
72
|
question: string,
|
|
69
73
|
choices: readonly T[],
|
|
74
|
+
retry = true,
|
|
70
75
|
): Promise<T> {
|
|
71
76
|
stderrln(question);
|
|
72
77
|
for (let i = 0; i < choices.length; i++) {
|
|
@@ -78,6 +83,10 @@ async function askChoice<T extends string>(
|
|
|
78
83
|
if (n >= 1 && n <= choices.length) {
|
|
79
84
|
return choices[n - 1]!;
|
|
80
85
|
}
|
|
86
|
+
if (!retry) {
|
|
87
|
+
stderrln(`Error: invalid choice "${raw}". Expected a number between 1 and ${choices.length}.`);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
81
90
|
stderrln(`Please enter a number between 1 and ${choices.length}.`);
|
|
82
91
|
}
|
|
83
92
|
}
|
|
@@ -97,11 +106,15 @@ function resolveConfigPath(client: Client, scope: Scope): string {
|
|
|
97
106
|
}
|
|
98
107
|
|
|
99
108
|
function buildEntry(): Record<string, unknown> {
|
|
100
|
-
|
|
109
|
+
const entry: Record<string, unknown> = {
|
|
101
110
|
type: "stdio",
|
|
102
111
|
command: "npx",
|
|
103
112
|
args: ["-y", "mcp-pachca@latest"],
|
|
104
113
|
};
|
|
114
|
+
if (process.env["DEBUG"]) {
|
|
115
|
+
entry["env"] = { DEBUG: "1" };
|
|
116
|
+
}
|
|
117
|
+
return entry;
|
|
105
118
|
}
|
|
106
119
|
|
|
107
120
|
// --- Main ---
|
|
@@ -114,15 +127,19 @@ export async function runSetup(): Promise<void> {
|
|
|
114
127
|
let email: string;
|
|
115
128
|
let code: string;
|
|
116
129
|
|
|
117
|
-
if (process.stdin.isTTY) {
|
|
118
|
-
|
|
130
|
+
if (!process.stdin.isTTY) {
|
|
131
|
+
stderrln("Error: --setup requires an interactive terminal (OTP code is sent via email).");
|
|
132
|
+
process.exit(1);
|
|
133
|
+
}
|
|
119
134
|
|
|
135
|
+
const prompter = makeTTYPrompter();
|
|
136
|
+
try {
|
|
120
137
|
client = await askChoice(prompter.ask, "Select your MCP client:", CLIENTS);
|
|
121
138
|
scope = await askChoice(prompter.ask, "Select config scope:", SCOPES);
|
|
122
139
|
|
|
123
140
|
email = await prompter.ask("Enter your Pachca email: ");
|
|
124
|
-
if (!email) {
|
|
125
|
-
stderrln("Error: email
|
|
141
|
+
if (!email || !email.includes("@")) {
|
|
142
|
+
stderrln("Error: invalid email address.");
|
|
126
143
|
process.exit(1);
|
|
127
144
|
}
|
|
128
145
|
|
|
@@ -131,34 +148,24 @@ export async function runSetup(): Promise<void> {
|
|
|
131
148
|
stderrln("Check your email for the 6-digit code.");
|
|
132
149
|
|
|
133
150
|
code = await prompter.ask("Enter the code: ");
|
|
151
|
+
} finally {
|
|
134
152
|
prompter.close();
|
|
135
|
-
} else {
|
|
136
|
-
const lines = await readAllLines();
|
|
137
|
-
const prompter = makePipePrompter(lines);
|
|
138
|
-
|
|
139
|
-
client = await askChoice(prompter.ask, "Select your MCP client:", CLIENTS);
|
|
140
|
-
scope = await askChoice(prompter.ask, "Select config scope:", SCOPES);
|
|
141
|
-
|
|
142
|
-
email = prompter.ask("Enter your Pachca email: ");
|
|
143
|
-
if (!email) {
|
|
144
|
-
stderrln("Error: email cannot be empty.");
|
|
145
|
-
process.exit(1);
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
stderrln("\nRequesting login code...");
|
|
149
|
-
await requestOTP(email);
|
|
150
|
-
stderrln("Check your email for the 6-digit code.");
|
|
151
|
-
|
|
152
|
-
code = prompter.ask("Enter the code: ");
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
if (!code) {
|
|
156
|
-
stderrln("Error: code
|
|
155
|
+
if (!code || !/^\d{6}$/.test(code)) {
|
|
156
|
+
stderrln("Error: code must be exactly 6 digits.");
|
|
157
157
|
process.exit(1);
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
stderrln("Logging in...");
|
|
161
|
-
|
|
161
|
+
let session;
|
|
162
|
+
try {
|
|
163
|
+
session = await performLogin(email, code);
|
|
164
|
+
} catch (err) {
|
|
165
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
166
|
+
stderrln(`\nLogin failed: ${msg}`);
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
162
169
|
saveSession(session);
|
|
163
170
|
stderrln(`Session saved to ~/.config/mcp-pachca/session.json`);
|
|
164
171
|
|
|
@@ -182,7 +189,8 @@ export async function runSetup(): Promise<void> {
|
|
|
182
189
|
config = {};
|
|
183
190
|
}
|
|
184
191
|
|
|
185
|
-
const
|
|
192
|
+
const raw = config["mcpServers"];
|
|
193
|
+
const servers = (raw !== null && typeof raw === "object" && !Array.isArray(raw) ? raw : {}) as Record<string, unknown>;
|
|
186
194
|
servers["pachca"] = buildEntry();
|
|
187
195
|
config["mcpServers"] = servers;
|
|
188
196
|
|
package/src/tools/handlers.ts
CHANGED
|
@@ -24,7 +24,7 @@ async function handleSearchUsers(
|
|
|
24
24
|
type: "user",
|
|
25
25
|
query: String(args["query"]),
|
|
26
26
|
};
|
|
27
|
-
if (args["cursor"]) params["cursor"] = String(args["cursor"]);
|
|
27
|
+
if (args["cursor"] !== undefined) params["cursor"] = String(args["cursor"]);
|
|
28
28
|
return client.get<PachcaSearchResult<PachcaUser>>("/search", params);
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -44,12 +44,13 @@ async function handleListChats(
|
|
|
44
44
|
client: PachcaClient,
|
|
45
45
|
args: Record<string, unknown>,
|
|
46
46
|
): Promise<unknown> {
|
|
47
|
-
const
|
|
47
|
+
const res = await client.get<{ data: PachcaFolder[] }>("/menu/folders");
|
|
48
|
+
const folders = res?.data ?? [];
|
|
48
49
|
|
|
49
50
|
const folderKind = args["folder"] as string | undefined;
|
|
50
51
|
if (!folderKind) {
|
|
51
52
|
return {
|
|
52
|
-
folders: folders
|
|
53
|
+
folders: folders.map((f) => ({
|
|
53
54
|
id: f.id,
|
|
54
55
|
title: f.title,
|
|
55
56
|
kind: f.kind,
|
|
@@ -57,16 +58,13 @@ async function handleListChats(
|
|
|
57
58
|
};
|
|
58
59
|
}
|
|
59
60
|
|
|
60
|
-
const folder = folders
|
|
61
|
+
const folder = folders.find((f) => f.kind === folderKind);
|
|
61
62
|
if (!folder) {
|
|
62
|
-
|
|
63
|
-
error: `Folder "${folderKind}" not found`,
|
|
64
|
-
available: folders?.map((f) => f.kind),
|
|
65
|
-
};
|
|
63
|
+
throw new Error(`Folder "${folderKind}" not found. Available: ${folders.map((f) => f.kind).join(", ")}`);
|
|
66
64
|
}
|
|
67
65
|
|
|
68
66
|
const params: Record<string, string> = {};
|
|
69
|
-
if (args["cursor"]) params["cursor"] = String(args["cursor"]);
|
|
67
|
+
if (args["cursor"] !== undefined) params["cursor"] = String(args["cursor"]);
|
|
70
68
|
|
|
71
69
|
return client.get<{ records: PachcaChat[]; paginate: PachcaPaginate }>(
|
|
72
70
|
`/menu/folders/${folder.id}/chats`,
|
|
@@ -90,14 +88,15 @@ async function handleGetChatMembers(
|
|
|
90
88
|
client: PachcaClient,
|
|
91
89
|
args: Record<string, unknown>,
|
|
92
90
|
): Promise<unknown> {
|
|
91
|
+
const chatId = Number(args["id"]);
|
|
93
92
|
const params: Record<string, string> = {};
|
|
94
|
-
if (args["limit"]) params["limit"] = String(args["limit"]);
|
|
95
|
-
if (args["cursor"]) params["cursor"] = String(args["cursor"]);
|
|
93
|
+
if (args["limit"] !== undefined) params["limit"] = String(args["limit"]);
|
|
94
|
+
if (args["cursor"] !== undefined) params["cursor"] = String(args["cursor"]);
|
|
96
95
|
return client.get<{
|
|
97
96
|
users: PachcaUser[];
|
|
98
97
|
total_users: number;
|
|
99
98
|
paginate: PachcaPaginate;
|
|
100
|
-
}>(`/chats/${
|
|
99
|
+
}>(`/chats/${chatId}/users`, params);
|
|
101
100
|
}
|
|
102
101
|
|
|
103
102
|
async function handleListMessages(
|
|
@@ -107,9 +106,14 @@ async function handleListMessages(
|
|
|
107
106
|
const params: Record<string, string> = {
|
|
108
107
|
chat_id: String(args["chat_id"]),
|
|
109
108
|
};
|
|
110
|
-
if (args["per"]) params["per"] = String(args["per"]);
|
|
111
|
-
if (args["message_id"]) params["message_id"] = String(args["message_id"]);
|
|
112
|
-
if (args["direction"]
|
|
109
|
+
if (args["per"] !== undefined) params["per"] = String(args["per"]);
|
|
110
|
+
if (args["message_id"] !== undefined) params["message_id"] = String(args["message_id"]);
|
|
111
|
+
if (args["direction"] !== undefined) {
|
|
112
|
+
if (args["message_id"] === undefined) {
|
|
113
|
+
throw new Error("direction requires message_id to be set");
|
|
114
|
+
}
|
|
115
|
+
params["direction"] = String(args["direction"]);
|
|
116
|
+
}
|
|
113
117
|
return client.get<PachcaMessage[]>("/messages", params);
|
|
114
118
|
}
|
|
115
119
|
|
|
@@ -128,16 +132,23 @@ async function handleSendMessage(
|
|
|
128
132
|
client: PachcaClient,
|
|
129
133
|
args: Record<string, unknown>,
|
|
130
134
|
): Promise<unknown> {
|
|
131
|
-
const
|
|
132
|
-
chat_id: Number(args["chat_id"]),
|
|
133
|
-
text: String(args["text"]),
|
|
135
|
+
const message: Record<string, unknown> = {
|
|
134
136
|
uuid: randomUUID(),
|
|
137
|
+
content: String(args["text"]),
|
|
138
|
+
markup: [],
|
|
139
|
+
kind: 0,
|
|
140
|
+
files: [],
|
|
141
|
+
skip_invite_mentions: false,
|
|
135
142
|
};
|
|
136
|
-
if (args["parent_message_id"]) {
|
|
137
|
-
|
|
143
|
+
if (args["parent_message_id"] !== undefined) {
|
|
144
|
+
message["parent_message_id"] = Number(args["parent_message_id"]);
|
|
138
145
|
}
|
|
146
|
+
const body = {
|
|
147
|
+
chat_id: Number(args["chat_id"]),
|
|
148
|
+
message,
|
|
149
|
+
};
|
|
139
150
|
const result = await client.post<PachcaMessage>("/messages", body);
|
|
140
|
-
return result ?? { success: true };
|
|
151
|
+
return result ?? { success: true, uuid: message.uuid, chat_id: body.chat_id };
|
|
141
152
|
}
|
|
142
153
|
|
|
143
154
|
async function handleSearch(
|
|
@@ -148,7 +159,7 @@ async function handleSearch(
|
|
|
148
159
|
type: "message",
|
|
149
160
|
query: String(args["query"]),
|
|
150
161
|
};
|
|
151
|
-
if (args["cursor"]) params["cursor"] = String(args["cursor"]);
|
|
162
|
+
if (args["cursor"] !== undefined) params["cursor"] = String(args["cursor"]);
|
|
152
163
|
return client.get<PachcaSearchResult<PachcaMessage>>("/search", params);
|
|
153
164
|
}
|
|
154
165
|
|
|
@@ -164,7 +175,11 @@ async function handleGetPresence(
|
|
|
164
175
|
client: PachcaClient,
|
|
165
176
|
args: Record<string, unknown>,
|
|
166
177
|
): Promise<unknown> {
|
|
167
|
-
const
|
|
178
|
+
const rawIds = args["ids"];
|
|
179
|
+
if (!Array.isArray(rawIds) || rawIds.length === 0) {
|
|
180
|
+
throw new Error("ids must be a non-empty array of numbers");
|
|
181
|
+
}
|
|
182
|
+
const ids = rawIds.map((id) => Number(id));
|
|
168
183
|
return client.getWithArrayParams<PachcaPresence[]>("/friends/presence", {
|
|
169
184
|
ids,
|
|
170
185
|
});
|