telique-mcp 1.0.0 → 1.0.2
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/index.js +7 -2
- package/dist/setup.js +141 -12
- package/package.json +4 -2
- package/postinstall.js +16 -0
package/dist/index.js
CHANGED
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { stdin } from "node:process";
|
|
3
3
|
const subcommand = process.argv[2];
|
|
4
|
-
|
|
4
|
+
// If run with "setup" arg, or directly in a terminal (not piped by an MCP client),
|
|
5
|
+
// launch the interactive setup flow.
|
|
6
|
+
const isInteractiveTerminal = subcommand !== "serve" && stdin.isTTY === true;
|
|
7
|
+
if (subcommand === "setup" || isInteractiveTerminal) {
|
|
5
8
|
const { runSetup } = await import("./setup.js");
|
|
6
9
|
await runSetup();
|
|
7
10
|
}
|
|
8
11
|
else {
|
|
12
|
+
// MCP server mode — stdin is piped JSON-RPC from the MCP client
|
|
9
13
|
const { McpServer } = await import("@modelcontextprotocol/sdk/server/mcp.js");
|
|
10
14
|
const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
|
|
11
15
|
const { TeliqueClient } = await import("./client.js");
|
|
16
|
+
const { loadConfig } = await import("./config.js");
|
|
12
17
|
const { setAnonymousMode } = await import("./utils/formatting.js");
|
|
13
18
|
const { registerRoutelinkTools } = await import("./tools/routelink.js");
|
|
14
19
|
const { registerLrnTools } = await import("./tools/lrn.js");
|
package/dist/setup.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createInterface } from "node:readline/promises";
|
|
2
2
|
import { mkdirSync, writeFileSync, existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import { execSync, execFileSync } from "node:child_process";
|
|
3
4
|
import { stdin, stdout } from "node:process";
|
|
4
5
|
import { CONFIG_DIR, CONFIG_FILE } from "./config.js";
|
|
5
6
|
const REGISTER_URL = "https://telique.ringer.tel/register";
|
|
@@ -13,8 +14,8 @@ export async function runSetup() {
|
|
|
13
14
|
console.log(` Found existing API key: ${maskToken(existing)}`);
|
|
14
15
|
const keep = await rl.question(" Keep this key? (Y/n): ");
|
|
15
16
|
if (keep.toLowerCase() !== "n") {
|
|
16
|
-
console.log("\n ✓ Keeping existing configuration
|
|
17
|
-
|
|
17
|
+
console.log("\n ✓ Keeping existing configuration.");
|
|
18
|
+
await registerWithClients(rl, existing);
|
|
18
19
|
rl.close();
|
|
19
20
|
return;
|
|
20
21
|
}
|
|
@@ -44,26 +45,154 @@ export async function runSetup() {
|
|
|
44
45
|
}
|
|
45
46
|
saveToken(trimmed);
|
|
46
47
|
console.log(` ✓ Token validated`);
|
|
47
|
-
console.log(` ✓ Saved to ${CONFIG_FILE}
|
|
48
|
-
|
|
48
|
+
console.log(` ✓ Saved to ${CONFIG_FILE}`);
|
|
49
|
+
await registerWithClients(rl, trimmed);
|
|
49
50
|
break;
|
|
50
51
|
}
|
|
51
52
|
case "2": {
|
|
52
53
|
console.log(`\n Opening ${REGISTER_URL} ...\n`);
|
|
53
54
|
await openBrowser(REGISTER_URL);
|
|
54
|
-
console.log(" After creating your account, run
|
|
55
|
+
console.log(" After creating your account, run `telique-mcp setup` again.\n");
|
|
55
56
|
break;
|
|
56
57
|
}
|
|
57
58
|
case "3":
|
|
58
59
|
default: {
|
|
59
60
|
console.log("\n ✓ Skipped. Running in anonymous mode (10 ops/min).");
|
|
60
|
-
console.log(` Get an API key anytime at ${REGISTER_URL}
|
|
61
|
-
|
|
61
|
+
console.log(` Get an API key anytime at ${REGISTER_URL}`);
|
|
62
|
+
await registerWithClients(rl, null);
|
|
62
63
|
break;
|
|
63
64
|
}
|
|
64
65
|
}
|
|
65
66
|
rl.close();
|
|
66
67
|
}
|
|
68
|
+
async function registerWithClients(rl, token) {
|
|
69
|
+
const clients = detectMcpClients();
|
|
70
|
+
if (clients.length === 0) {
|
|
71
|
+
console.log("\n No supported MCP clients detected.\n");
|
|
72
|
+
printManualConfig(token);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
console.log("\n Detected MCP clients:\n");
|
|
76
|
+
clients.forEach((c, i) => console.log(` [${i + 1}] ${c.name}`));
|
|
77
|
+
console.log(` [A] All of the above`);
|
|
78
|
+
console.log(` [S] Skip — I'll configure manually`);
|
|
79
|
+
console.log();
|
|
80
|
+
const answer = await rl.question(" Register with which client? > ");
|
|
81
|
+
const trimmed = answer.trim().toUpperCase();
|
|
82
|
+
if (trimmed === "S") {
|
|
83
|
+
printManualConfig(token);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const selected = trimmed === "A"
|
|
87
|
+
? clients
|
|
88
|
+
: clients.filter((_, i) => trimmed === String(i + 1));
|
|
89
|
+
if (selected.length === 0) {
|
|
90
|
+
printManualConfig(token);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
for (const client of selected) {
|
|
94
|
+
const success = client.register(token);
|
|
95
|
+
if (success) {
|
|
96
|
+
console.log(` ✓ Registered with ${client.name}`);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
console.log(` ✗ Failed to register with ${client.name}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
console.log("\n Done! Restart your MCP client to load the Telique tools.\n");
|
|
103
|
+
}
|
|
104
|
+
function detectMcpClients() {
|
|
105
|
+
const clients = [];
|
|
106
|
+
// Claude Code
|
|
107
|
+
if (commandExists("claude")) {
|
|
108
|
+
clients.push({
|
|
109
|
+
name: "Claude Code",
|
|
110
|
+
register: (token) => registerClaudeCode(token),
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
// Claude Desktop
|
|
114
|
+
const claudeDesktopConfig = getClaudeDesktopConfigPath();
|
|
115
|
+
if (claudeDesktopConfig && existsSync(claudeDesktopConfig)) {
|
|
116
|
+
clients.push({
|
|
117
|
+
name: "Claude Desktop",
|
|
118
|
+
register: (token) => registerJsonConfig(claudeDesktopConfig, token),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return clients;
|
|
122
|
+
}
|
|
123
|
+
function registerClaudeCode(token) {
|
|
124
|
+
try {
|
|
125
|
+
// Remove existing entry first (ignore errors if not found)
|
|
126
|
+
try {
|
|
127
|
+
execSync("claude mcp remove -s user telique 2>/dev/null", {
|
|
128
|
+
stdio: "ignore",
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
// ignore
|
|
133
|
+
}
|
|
134
|
+
const args = ["mcp", "add", "-s", "user", "telique"];
|
|
135
|
+
if (token) {
|
|
136
|
+
args.push("-e", `TELIQUE_API_TOKEN=${token}`);
|
|
137
|
+
}
|
|
138
|
+
args.push("--", "npx", "-y", "telique-mcp");
|
|
139
|
+
execFileSync("claude", args, { stdio: "ignore" });
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return false;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function registerJsonConfig(configPath, token) {
|
|
147
|
+
try {
|
|
148
|
+
let config = {};
|
|
149
|
+
try {
|
|
150
|
+
config = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// start fresh
|
|
154
|
+
}
|
|
155
|
+
if (!config.mcpServers || typeof config.mcpServers !== "object") {
|
|
156
|
+
config.mcpServers = {};
|
|
157
|
+
}
|
|
158
|
+
const servers = config.mcpServers;
|
|
159
|
+
const entry = {
|
|
160
|
+
command: "npx",
|
|
161
|
+
args: ["-y", "telique-mcp"],
|
|
162
|
+
};
|
|
163
|
+
if (token) {
|
|
164
|
+
entry.env = { TELIQUE_API_TOKEN: token };
|
|
165
|
+
}
|
|
166
|
+
servers.telique = entry;
|
|
167
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
function getClaudeDesktopConfigPath() {
|
|
175
|
+
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
176
|
+
switch (process.platform) {
|
|
177
|
+
case "darwin":
|
|
178
|
+
return `${home}/Library/Application Support/Claude/claude_desktop_config.json`;
|
|
179
|
+
case "win32":
|
|
180
|
+
return `${process.env.APPDATA}/Claude/claude_desktop_config.json`;
|
|
181
|
+
case "linux":
|
|
182
|
+
return `${home}/.config/Claude/claude_desktop_config.json`;
|
|
183
|
+
default:
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
function commandExists(cmd) {
|
|
188
|
+
try {
|
|
189
|
+
execSync(`which ${cmd} 2>/dev/null`, { stdio: "ignore" });
|
|
190
|
+
return true;
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
return false;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
67
196
|
function loadExistingToken() {
|
|
68
197
|
try {
|
|
69
198
|
const raw = readFileSync(CONFIG_FILE, "utf-8");
|
|
@@ -76,11 +205,11 @@ function loadExistingToken() {
|
|
|
76
205
|
}
|
|
77
206
|
function saveToken(token) {
|
|
78
207
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
79
|
-
const
|
|
208
|
+
const existing = existsSync(CONFIG_FILE)
|
|
80
209
|
? JSON.parse(readFileSync(CONFIG_FILE, "utf-8"))
|
|
81
210
|
: {};
|
|
82
|
-
|
|
83
|
-
writeFileSync(CONFIG_FILE, JSON.stringify(
|
|
211
|
+
existing.apiToken = token;
|
|
212
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(existing, null, 2) + "\n");
|
|
84
213
|
}
|
|
85
214
|
async function validateToken(token) {
|
|
86
215
|
try {
|
|
@@ -108,7 +237,7 @@ async function openBrowser(url) {
|
|
|
108
237
|
: "xdg-open";
|
|
109
238
|
exec(`${cmd} ${url}`);
|
|
110
239
|
}
|
|
111
|
-
function
|
|
240
|
+
function printManualConfig(token) {
|
|
112
241
|
const env = {};
|
|
113
242
|
if (token) {
|
|
114
243
|
env.TELIQUE_API_TOKEN = token;
|
|
@@ -122,7 +251,7 @@ function printMcpConfig(token) {
|
|
|
122
251
|
},
|
|
123
252
|
},
|
|
124
253
|
};
|
|
125
|
-
console.log(" Add this to your MCP client configuration:\n");
|
|
254
|
+
console.log("\n Add this to your MCP client configuration:\n");
|
|
126
255
|
console.log(JSON.stringify(config, null, 2)
|
|
127
256
|
.split("\n")
|
|
128
257
|
.map((line) => " " + line)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "telique-mcp",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "MCP server for Telique telecom APIs (RouteLink, LRN, CNAM, LERG)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -8,12 +8,14 @@
|
|
|
8
8
|
"telique-mcp": "dist/index.js"
|
|
9
9
|
},
|
|
10
10
|
"files": [
|
|
11
|
-
"dist"
|
|
11
|
+
"dist",
|
|
12
|
+
"postinstall.js"
|
|
12
13
|
],
|
|
13
14
|
"scripts": {
|
|
14
15
|
"build": "tsc",
|
|
15
16
|
"start": "node dist/index.js",
|
|
16
17
|
"dev": "tsx src/index.ts",
|
|
18
|
+
"postinstall": "node postinstall.js",
|
|
17
19
|
"prepublishOnly": "npm run build"
|
|
18
20
|
},
|
|
19
21
|
"keywords": [
|
package/postinstall.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
console.log(`
|
|
3
|
+
┌─────────────────────────────────────────────────┐
|
|
4
|
+
│ │
|
|
5
|
+
│ telique-mcp installed successfully! │
|
|
6
|
+
│ │
|
|
7
|
+
│ Get started: │
|
|
8
|
+
│ telique-mcp setup │
|
|
9
|
+
│ │
|
|
10
|
+
│ Or use immediately in anonymous mode │
|
|
11
|
+
│ (10 ops/min) — no API key required. │
|
|
12
|
+
│ │
|
|
13
|
+
│ Docs: https://github.com/Ringer/telique-mcp │
|
|
14
|
+
│ │
|
|
15
|
+
└─────────────────────────────────────────────────┘
|
|
16
|
+
`);
|