sipgate-mcp 0.2.0 → 0.3.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,26 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.1 - 2026-08-30
4
+
5
+ - Fix Claude Code registration by using its unambiguous `mcp add-json` command
6
+ instead of the variadic `--env` parser.
7
+ - Clearly map macOS Keychain's generic `password data` prompts to sipgate's
8
+ PAT-ID and PAT labels.
9
+ - Reuse existing Keychain credentials on repeated setup runs and add
10
+ `--replace-credentials` for deliberate rotation.
11
+
12
+ ## 0.3.0 - 2026-08-30
13
+
14
+ - Add `sipgate-mcp setup` for interactive PAT storage in macOS Keychain.
15
+ - Register installed Codex and Claude Code clients with a secret-free launch
16
+ command, user scope, and read-only mode by default.
17
+ - Load Keychain credentials automatically when environment credentials are
18
+ absent, while keeping environment variables as an explicit override.
19
+ - Add setup dry-run and opt-in write-mode flags.
20
+ - Add a versioned agent skill and README bootstrap link for guided setup.
21
+ - Add `sipgate-mcp --version` and verify that CLI, package, and skill versions
22
+ remain synchronized.
23
+
3
24
  ## 0.2.0 - 2026-08-30
4
25
 
5
26
  - Default to MCP-level user scope resolved from sipgate's authenticated user.
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  `sipgate-mcp` is an open-source, self-hosted Model Context Protocol server for inspecting and configuring a sipgate account. It exposes the sipgate REST API v2 as focused tools for agents such as Claude Code, Claude Desktop, and Codex.
4
4
 
5
- Version 0.2 defaults to user-scoped access: tools are constrained to the
5
+ Version 0.2 and later default to user-scoped access: tools are constrained to the
6
6
  authenticated sipgate user's resources. Account-wide access is an explicit
7
7
  administrator-only mode.
8
8
 
@@ -10,6 +10,17 @@ The server uses stdio only. It does not start an HTTP server or route credential
10
10
  through a third-party service. It sends authentication only from the local MCP
11
11
  process directly to `https://api.sipgate.com/v2`.
12
12
 
13
+ ## Agent-assisted setup
14
+
15
+ Tell Codex or Claude:
16
+
17
+ > Set up sipgate MCP by following
18
+ > https://raw.githubusercontent.com/wiesson/sipgate-mcp/main/SKILL.md
19
+
20
+ The linked, versioned [`SKILL.md`](SKILL.md) tells the agent how to install and
21
+ verify the matching package without asking for credentials in chat. Secret
22
+ entry remains an interactive local Keychain step controlled by the user.
23
+
13
24
  ## Requirements
14
25
 
15
26
  - Node.js 22 or newer
@@ -24,13 +35,43 @@ pnpm add --global sipgate-mcp
24
35
  vp install --global sipgate-mcp
25
36
  ```
26
37
 
27
- Then start it with:
38
+ On macOS, run the interactive setup once:
28
39
 
29
40
  ```bash
30
- export SIPGATE_TOKEN_ID="your-token-id"
31
- export SIPGATE_TOKEN="your-token"
41
+ sipgate-mcp setup
42
+ ```
43
+
44
+ The setup stores the PAT token ID and token in macOS Keychain without placing
45
+ either value in shell history or an MCP configuration file. It registers every
46
+ installed supported client (Codex and Claude Code) in user/read-only mode.
47
+ Those clients start and stop the stdio server automatically; `sipgate-mcp` does
48
+ not run as a daemon and does not need to be started manually.
49
+
50
+ Use `sipgate-mcp setup --client codex` or `--client claude` to configure only
51
+ one client. Add `--allow-writes` only when agent-initiated account changes are
52
+ deliberately wanted. `--dry-run` prints the secret-free registration commands
53
+ without changing the Keychain or client configuration. Repeated setup runs
54
+ reuse existing Keychain credentials; use `--replace-credentials` only to rotate
55
+ the stored PAT-ID and PAT.
56
+
57
+ During first setup, macOS calls both secure inputs `password data`. The setup
58
+ labels the steps explicitly: enter the sipgate **PAT-ID** twice in step 1, then
59
+ the sipgate **PAT** twice in step 2. Input remains hidden while typing.
60
+
61
+ Secure interactive storage currently supports macOS. Environment variables
62
+ remain available for Linux, Windows, containers, CI, and password-manager
63
+ wrappers. To avoid putting literal credentials in shell history, read them
64
+ interactively:
65
+
66
+ ```bash
67
+ printf "sipgate PAT token ID: "
68
+ IFS= read -r SIPGATE_TOKEN_ID
69
+ printf "sipgate PAT token: "
70
+ IFS= read -rs SIPGATE_TOKEN
71
+ printf "\n"
72
+ export SIPGATE_TOKEN_ID SIPGATE_TOKEN
32
73
  export SIPGATE_MCP_SCOPE="user"
33
- sipgate-mcp
74
+ export SIPGATE_MCP_READONLY="1"
34
75
  ```
35
76
 
36
77
  For clients that manage MCP commands on demand, `npx -y sipgate-mcp` remains
@@ -41,11 +82,20 @@ supported without a global installation.
41
82
  1. Open [sipgate Personal Access Tokens](https://app.sipgate.com/personal-access-token).
42
83
  2. Select **Add token**, give the token a recognizable name, and select the scopes needed for the tools you intend to use.
43
84
  3. Copy both the token ID and token. sipgate displays the token itself only once.
44
- 4. Put them in the environment as `SIPGATE_TOKEN_ID` and `SIPGATE_TOKEN` before starting your MCP client.
85
+ 4. Run `sipgate-mcp setup` on macOS, or provide them as `SIPGATE_TOKEN_ID` and `SIPGATE_TOKEN` in the MCP process environment.
45
86
 
46
87
  sipgate PAT authentication uses HTTP Basic Auth with `token-id:token` as the credential pair. `sipgate-mcp` constructs that header in memory. See sipgate's [authentication guide](https://en.sipgate.io/rest-api/authentication).
47
88
 
48
- Do not put either value in this repository, an MCP config committed to source control, command output, or an issue report.
89
+ Do not put either value in this repository, an MCP config committed to source control, shell command arguments, command output, or an issue report.
90
+
91
+ The separate **API Clients** screen in the sipgate account creates OAuth 2.0
92
+ client credentials for an application that redirects users through sipgate's
93
+ authorization flow. Those client credentials are not PAT replacements and are
94
+ not used by the local stdio setup. They are relevant to a future hosted/remote
95
+ MCP, which would need a registered redirect URI, user consent, access-token
96
+ refresh, and secure per-user token storage. See sipgate's [OAuth authentication
97
+ flow](https://en.sipgate.io/rest-api/authentication#oauth2) and [API client
98
+ management](https://en.sipgate.io/rest-api/managing-third-party-clients).
49
99
 
50
100
  ## MCP access scopes
51
101
 
@@ -116,7 +166,10 @@ npx -y sipgate-mcp
116
166
 
117
167
  ## MCP client configuration
118
168
 
119
- Set `SIPGATE_TOKEN_ID` and `SIPGATE_TOKEN` in the environment that launches the MCP client. The examples keep secret values out of configuration files.
169
+ The recommended macOS path is `sipgate-mcp setup`. The following manual
170
+ examples are useful for other platforms and custom launchers. Set
171
+ `SIPGATE_TOKEN_ID` and `SIPGATE_TOKEN` in the environment that launches the MCP
172
+ client; the examples keep secret values out of configuration files.
120
173
 
121
174
  ### Claude Code
122
175
 
@@ -205,7 +258,11 @@ MCP stdio server
205
258
 
206
259
  ## Security
207
260
 
208
- - PAT values are read only from `SIPGATE_TOKEN_ID` and `SIPGATE_TOKEN`.
261
+ - PAT values are read from `SIPGATE_TOKEN_ID` and `SIPGATE_TOKEN`, or from the
262
+ current user's macOS Keychain when both variables are absent.
263
+ - `sipgate-mcp setup` delegates secret entry directly to the macOS Keychain
264
+ prompt. Secret values are never passed as command-line arguments and are not
265
+ written to Codex or Claude configuration.
209
266
  - User scope is the default and validates user IDs plus number, phoneline, device, call, and history ownership before delegation.
210
267
  - Account scope fails startup unless the authenticated sipgate user reports `admin: true`.
211
268
  - The Basic Auth header exists only in memory and is sent only to the fixed sipgate API base URL.
package/SKILL.md ADDED
@@ -0,0 +1,91 @@
1
+ ---
2
+ name: sipgate-mcp
3
+ description: Install and securely configure the sipgate MCP server when a user asks to set up or connect a sipgate account to Codex or Claude. Do not use for ordinary sipgate product questions.
4
+ metadata:
5
+ version: "0.3.1"
6
+ ---
7
+
8
+ # Set up sipgate MCP
9
+
10
+ Install the matching CLI version with one available package manager:
11
+
12
+ ```bash
13
+ vp install -g sipgate-mcp@0.3.1
14
+ ```
15
+
16
+ ```bash
17
+ npm install -g sipgate-mcp@0.3.1
18
+ ```
19
+
20
+ ```bash
21
+ pnpm add -g sipgate-mcp@0.3.1
22
+ ```
23
+
24
+ Run only one install command. Confirm that `sipgate-mcp --version` reports
25
+ `0.3.1` before continuing.
26
+
27
+ ## Security boundary
28
+
29
+ - Never ask the user to paste a sipgate PAT, token, client secret, or other
30
+ credential into chat.
31
+ - Never place credentials in command arguments, MCP configuration, repository
32
+ files, logs, or issue reports.
33
+ - The local server uses a sipgate Personal Access Token. A sipgate OAuth API
34
+ client ID and secret are not substitutes for this local setup.
35
+ - Keep the first setup user-scoped and read-only. Do not enable write tools or
36
+ account-wide administrator access without an explicit user request.
37
+ - Do not remove or replace an existing MCP configuration without the user's
38
+ approval.
39
+
40
+ ## Configure
41
+
42
+ On macOS, run the interactive setup for the MCP client the user is currently
43
+ using:
44
+
45
+ ```bash
46
+ sipgate-mcp setup --client codex
47
+ ```
48
+
49
+ or:
50
+
51
+ ```bash
52
+ sipgate-mcp setup --client claude
53
+ ```
54
+
55
+ Omit `--client` only when both installed clients should be configured. The
56
+ setup delegates PAT entry directly to macOS Keychain and registers a
57
+ user-scoped, read-only stdio server. The client starts and stops that process;
58
+ do not launch `sipgate-mcp` as a daemon.
59
+
60
+ When credentials already exist in Keychain, setup reuses them without another
61
+ prompt. Use `--replace-credentials` only when the user explicitly wants to
62
+ rotate or replace the stored PAT-ID and PAT.
63
+
64
+ If the Keychain prompt cannot be presented in the current environment, ask the
65
+ user to run the setup command in their local interactive terminal. Do not ask
66
+ them to provide the credential to the agent instead. On Linux or Windows,
67
+ follow the secret-free environment or password-manager launcher guidance in
68
+ the project README rather than inventing a plaintext credential file.
69
+
70
+ If setup reports that an MCP server named `sipgate` already exists, inspect it
71
+ with `codex mcp get sipgate` or `claude mcp get sipgate`. Explain the conflict
72
+ and request approval before removing or replacing that configuration.
73
+
74
+ ## Verify
75
+
76
+ Use the applicable client command:
77
+
78
+ ```bash
79
+ codex mcp get sipgate
80
+ ```
81
+
82
+ ```bash
83
+ claude mcp get sipgate
84
+ ```
85
+
86
+ Ask the user to restart the client when required, open `/mcp`, and test with:
87
+
88
+ > Use sipgate read-only. Check the connection and list my phone numbers.
89
+
90
+ Do not enable `--allow-writes` merely to make a failed read test pass. Diagnose
91
+ installation, credentials, client registration, and PAT read scopes first.
package/dist/config.d.ts CHANGED
@@ -1,9 +1,10 @@
1
1
  import type { AccessScope } from "./backend/telephony-backend.js";
2
+ import { type SipgateCredentials } from "./credentials.js";
2
3
  export interface ServerConfig {
3
4
  accessScope: AccessScope;
4
5
  tokenId: string;
5
6
  token: string;
6
7
  readonly: boolean;
7
8
  }
8
- export declare function loadConfig(env?: NodeJS.ProcessEnv): ServerConfig;
9
+ export declare function loadConfig(env?: NodeJS.ProcessEnv, storedCredentialLoader?: () => SipgateCredentials | undefined): ServerConfig;
9
10
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAElE,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,UAAU,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,YAAY,CAgB7E"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,WAAW,CAAC;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,UAAU,CACxB,GAAG,GAAE,MAAM,CAAC,UAAwB,EACpC,sBAAsB,GAAE,MAAM,kBAAkB,GAAG,SAAiC,GACnF,YAAY,CAwBd"}
package/dist/config.js CHANGED
@@ -1,8 +1,13 @@
1
- export function loadConfig(env = process.env) {
2
- const tokenId = env.SIPGATE_TOKEN_ID;
3
- const token = env.SIPGATE_TOKEN;
1
+ import { loadStoredCredentials, } from "./credentials.js";
2
+ export function loadConfig(env = process.env, storedCredentialLoader = loadStoredCredentials) {
3
+ const hasEnvironmentCredential = Boolean(env.SIPGATE_TOKEN_ID || env.SIPGATE_TOKEN);
4
+ const storedCredentials = hasEnvironmentCredential
5
+ ? undefined
6
+ : storedCredentialLoader();
7
+ const tokenId = env.SIPGATE_TOKEN_ID ?? storedCredentials?.tokenId;
8
+ const token = env.SIPGATE_TOKEN ?? storedCredentials?.token;
4
9
  if (!tokenId || !token) {
5
- throw new Error("Both SIPGATE_TOKEN_ID and SIPGATE_TOKEN must be set.");
10
+ throw new Error("Credentials are missing. Run 'sipgate-mcp setup' or set both SIPGATE_TOKEN_ID and SIPGATE_TOKEN.");
6
11
  }
7
12
  const accessScope = env.SIPGATE_MCP_SCOPE ?? "user";
8
13
  if (accessScope !== "user" && accessScope !== "account") {
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AASA,MAAM,UAAU,UAAU,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG;IAC7D,MAAM,OAAO,GAAG,GAAG,CAAC,gBAAgB,CAAC;IACrC,MAAM,KAAK,GAAG,GAAG,CAAC,aAAa,CAAC;IAChC,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IACD,MAAM,WAAW,GAAG,GAAG,CAAC,iBAAiB,IAAI,MAAM,CAAC;IACpD,IAAI,WAAW,KAAK,MAAM,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO;QACL,WAAW;QACX,OAAO;QACP,KAAK;QACL,QAAQ,EAAE,GAAG,CAAC,oBAAoB,KAAK,GAAG;KAC3C,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,EACL,qBAAqB,GAEtB,MAAM,kBAAkB,CAAC;AAS1B,MAAM,UAAU,UAAU,CACxB,GAAG,GAAsB,OAAO,CAAC,GAAG,EACpC,sBAAsB,GAAyC,qBAAqB;IAEpF,MAAM,wBAAwB,GAAG,OAAO,CACtC,GAAG,CAAC,gBAAgB,IAAI,GAAG,CAAC,aAAa,CAC1C,CAAC;IACF,MAAM,iBAAiB,GAAG,wBAAwB;QAChD,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,sBAAsB,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,GAAG,CAAC,gBAAgB,IAAI,iBAAiB,EAAE,OAAO,CAAC;IACnE,MAAM,KAAK,GAAG,GAAG,CAAC,aAAa,IAAI,iBAAiB,EAAE,KAAK,CAAC;IAC5D,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,kGAAkG,CACnG,CAAC;IACJ,CAAC;IACD,MAAM,WAAW,GAAG,GAAG,CAAC,iBAAiB,IAAI,MAAM,CAAC;IACpD,IAAI,WAAW,KAAK,MAAM,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QACxD,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO;QACL,WAAW;QACX,OAAO;QACP,KAAK;QACL,QAAQ,EAAE,GAAG,CAAC,oBAAoB,KAAK,GAAG;KAC3C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ export interface SipgateCredentials {
2
+ tokenId: string;
3
+ token: string;
4
+ }
5
+ export declare const MACOS_KEYCHAIN_SERVICE = "sipgate-mcp";
6
+ export declare const MACOS_KEYCHAIN_TOKEN_ID_ACCOUNT = "pat-token-id";
7
+ export declare const MACOS_KEYCHAIN_TOKEN_ACCOUNT = "pat-token";
8
+ type KeychainReader = (account: string) => string;
9
+ type KeychainWriter = (account: string, label: string) => void;
10
+ export declare function loadStoredCredentials(platform?: NodeJS.Platform, readKeychain?: KeychainReader): SipgateCredentials | undefined;
11
+ export declare function storeCredentialsInteractively(platform?: NodeJS.Platform, writeKeychain?: KeychainWriter, output?: Pick<NodeJS.WriteStream, "write">): void;
12
+ export {};
13
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,sBAAsB,gBAAgB,CAAC;AACpD,eAAO,MAAM,+BAA+B,iBAAiB,CAAC;AAC9D,eAAO,MAAM,4BAA4B,cAAc,CAAC;AAExD,KAAK,cAAc,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,CAAC;AAClD,KAAK,cAAc,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;AA0C/D,wBAAgB,qBAAqB,CACnC,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,YAAY,GAAE,cAAsC,GACnD,kBAAkB,GAAG,SAAS,CAehC;AAED,wBAAgB,6BAA6B,CAC3C,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,aAAa,GAAE,cAAsC,EACrD,MAAM,GAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAkB,GACzD,IAAI,CAmBN"}
@@ -0,0 +1,63 @@
1
+ import { execFileSync, spawnSync } from "node:child_process";
2
+ export const MACOS_KEYCHAIN_SERVICE = "sipgate-mcp";
3
+ export const MACOS_KEYCHAIN_TOKEN_ID_ACCOUNT = "pat-token-id";
4
+ export const MACOS_KEYCHAIN_TOKEN_ACCOUNT = "pat-token";
5
+ function defaultKeychainReader(account) {
6
+ return execFileSync("/usr/bin/security", [
7
+ "find-generic-password",
8
+ "-s",
9
+ MACOS_KEYCHAIN_SERVICE,
10
+ "-a",
11
+ account,
12
+ "-w",
13
+ ], {
14
+ encoding: "utf8",
15
+ stdio: ["ignore", "pipe", "ignore"],
16
+ }).trim();
17
+ }
18
+ function defaultKeychainWriter(account, label) {
19
+ const result = spawnSync("/usr/bin/security", [
20
+ "add-generic-password",
21
+ "-a",
22
+ account,
23
+ "-s",
24
+ MACOS_KEYCHAIN_SERVICE,
25
+ "-l",
26
+ label,
27
+ "-U",
28
+ "-w",
29
+ ], { stdio: "inherit" });
30
+ if (result.error || result.status !== 0) {
31
+ throw new Error("macOS Keychain did not store the credential.");
32
+ }
33
+ }
34
+ export function loadStoredCredentials(platform = process.platform, readKeychain = defaultKeychainReader) {
35
+ if (platform !== "darwin") {
36
+ return undefined;
37
+ }
38
+ try {
39
+ const tokenId = readKeychain(MACOS_KEYCHAIN_TOKEN_ID_ACCOUNT).trim();
40
+ const token = readKeychain(MACOS_KEYCHAIN_TOKEN_ACCOUNT).trim();
41
+ if (!tokenId || !token) {
42
+ return undefined;
43
+ }
44
+ return { tokenId, token };
45
+ }
46
+ catch {
47
+ return undefined;
48
+ }
49
+ }
50
+ export function storeCredentialsInteractively(platform = process.platform, writeKeychain = defaultKeychainWriter, output = process.stderr) {
51
+ if (platform !== "darwin") {
52
+ throw new Error("Secure interactive setup currently supports macOS Keychain only. Use SIPGATE_TOKEN_ID and SIPGATE_TOKEN on this platform.");
53
+ }
54
+ output.write("\n[1/2] sipgate PAT-ID\n" +
55
+ "The following macOS Keychain prompt calls this value 'password data'.\n" +
56
+ "Enter the PAT-ID twice. Input is hidden while typing.\n");
57
+ writeKeychain(MACOS_KEYCHAIN_TOKEN_ID_ACCOUNT, "sipgate PAT-ID");
58
+ output.write("\n[2/2] sipgate PAT\n" +
59
+ "The following macOS Keychain prompt again calls this value 'password data'.\n" +
60
+ "Enter the PAT twice. Input is hidden while typing.\n");
61
+ writeKeychain(MACOS_KEYCHAIN_TOKEN_ACCOUNT, "sipgate PAT");
62
+ }
63
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAO7D,MAAM,CAAC,MAAM,sBAAsB,GAAG,aAAa,CAAC;AACpD,MAAM,CAAC,MAAM,+BAA+B,GAAG,cAAc,CAAC;AAC9D,MAAM,CAAC,MAAM,4BAA4B,GAAG,WAAW,CAAC;AAKxD,SAAS,qBAAqB,CAAC,OAAe;IAC5C,OAAO,YAAY,CACjB,mBAAmB,EACnB;QACE,uBAAuB;QACvB,IAAI;QACJ,sBAAsB;QACtB,IAAI;QACJ,OAAO;QACP,IAAI;KACL,EACD;QACE,QAAQ,EAAE,MAAM;QAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;KACpC,CACF,CAAC,IAAI,EAAE,CAAC;AACX,CAAC;AAED,SAAS,qBAAqB,CAAC,OAAe,EAAE,KAAa;IAC3D,MAAM,MAAM,GAAG,SAAS,CACtB,mBAAmB,EACnB;QACE,sBAAsB;QACtB,IAAI;QACJ,OAAO;QACP,IAAI;QACJ,sBAAsB;QACtB,IAAI;QACJ,KAAK;QACL,IAAI;QACJ,IAAI;KACL,EACD,EAAE,KAAK,EAAE,SAAS,EAAE,CACrB,CAAC;IAEF,IAAI,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,QAAQ,GAAoB,OAAO,CAAC,QAAQ,EAC5C,YAAY,GAAmB,qBAAqB;IAEpD,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,YAAY,CAAC,+BAA+B,CAAC,CAAC,IAAI,EAAE,CAAC;QACrE,MAAM,KAAK,GAAG,YAAY,CAAC,4BAA4B,CAAC,CAAC,IAAI,EAAE,CAAC;QAChE,IAAI,CAAC,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;YACvB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,QAAQ,GAAoB,OAAO,CAAC,QAAQ,EAC5C,aAAa,GAAmB,qBAAqB,EACrD,MAAM,GAAsC,OAAO,CAAC,MAAM;IAE1D,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CACb,2HAA2H,CAC5H,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,KAAK,CACV,0BAA0B;QAC1B,yEAAyE;QACzE,yDAAyD,CAC1D,CAAC;IACF,aAAa,CAAC,+BAA+B,EAAE,gBAAgB,CAAC,CAAC;IACjE,MAAM,CAAC,KAAK,CACV,uBAAuB;QACvB,+EAA+E;QAC/E,sDAAsD,CACvD,CAAC;IACF,aAAa,CAAC,4BAA4B,EAAE,aAAa,CAAC,CAAC;AAC7D,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,10 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  export declare function main(): Promise<void>;
3
+ export declare function runCli(args?: string[]): Promise<void>;
3
4
  export declare function isMainModule(moduleUrl: string, entrypoint: string | undefined): boolean;
4
5
  export { SipgateBackend } from "./backend/sipgate-backend.js";
5
6
  export { AccessPolicyError, createAccessControlledBackend, } from "./backend/access-controlled-backend.js";
6
7
  export { SipgateApiError, SipgateClient } from "./backend/sipgate-client.js";
7
8
  export type { AccessScope, AuthenticatedUserContext, TelephonyBackend, } from "./backend/telephony-backend.js";
8
9
  export { createServer } from "./server.js";
10
+ export { loadStoredCredentials, storeCredentialsInteractively, } from "./credentials.js";
11
+ export { buildRegistrationCommand, parseSetupArgs, runSetup } from "./setup.js";
9
12
  export { createToolDefinitions } from "./tools/definitions.js";
13
+ export { VERSION } from "./version.js";
10
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAaA,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAO1C;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAUvF;AAUD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EACL,iBAAiB,EACjB,6BAA6B,GAC9B,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC7E,YAAY,EACV,WAAW,EACX,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAeA,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAO1C;AAED,wBAAsB,MAAM,CAAC,IAAI,GAAE,MAAM,EAA0B,GAAG,OAAO,CAAC,IAAI,CAAC,CAsBlF;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAUvF;AAaD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EACL,iBAAiB,EACjB,6BAA6B,GAC9B,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC7E,YAAY,EACV,WAAW,EACX,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EACL,qBAAqB,EACrB,6BAA6B,GAC9B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,wBAAwB,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js CHANGED
@@ -7,6 +7,8 @@ import { SipgateBackend } from "./backend/sipgate-backend.js";
7
7
  import { SipgateClient } from "./backend/sipgate-client.js";
8
8
  import { loadConfig } from "./config.js";
9
9
  import { createServer } from "./server.js";
10
+ import { runSetup, SETUP_HELP, SetupError } from "./setup.js";
11
+ import { VERSION } from "./version.js";
10
12
  export async function main() {
11
13
  const config = loadConfig();
12
14
  const client = new SipgateClient({ tokenId: config.tokenId, token: config.token });
@@ -15,6 +17,29 @@ export async function main() {
15
17
  const server = createServer(backend, config.readonly, config.accessScope);
16
18
  await server.connect(new StdioServerTransport());
17
19
  }
20
+ export async function runCli(args = process.argv.slice(2)) {
21
+ const command = args[0];
22
+ if (command === "setup") {
23
+ if (args[1] === "--help" || args[1] === "-h") {
24
+ process.stdout.write(SETUP_HELP);
25
+ return;
26
+ }
27
+ runSetup(args.slice(1));
28
+ return;
29
+ }
30
+ if (command === "--help" || command === "-h" || command === "help") {
31
+ process.stdout.write(SETUP_HELP);
32
+ return;
33
+ }
34
+ if (command === "--version" || command === "-V" || command === "version") {
35
+ process.stdout.write(`${VERSION}\n`);
36
+ return;
37
+ }
38
+ if (command) {
39
+ throw new SetupError(`Unknown command: ${command}`);
40
+ }
41
+ await main();
42
+ }
18
43
  export function isMainModule(moduleUrl, entrypoint) {
19
44
  if (!entrypoint) {
20
45
  return false;
@@ -27,9 +52,11 @@ export function isMainModule(moduleUrl, entrypoint) {
27
52
  }
28
53
  }
29
54
  if (isMainModule(import.meta.url, process.argv[1])) {
30
- main().catch((error) => {
31
- const detail = error instanceof AccessPolicyError ? ` ${error.message}` : "";
32
- console.error(`sipgate-mcp failed to start.${detail} Check the required environment variables and MCP client configuration.`);
55
+ runCli().catch((error) => {
56
+ const detail = error instanceof AccessPolicyError || error instanceof SetupError
57
+ ? ` ${error.message}`
58
+ : "";
59
+ console.error(`sipgate-mcp failed.${detail} Check credentials and MCP client configuration.`);
33
60
  process.exitCode = 1;
34
61
  });
35
62
  }
@@ -37,5 +64,8 @@ export { SipgateBackend } from "./backend/sipgate-backend.js";
37
64
  export { AccessPolicyError, createAccessControlledBackend, } from "./backend/access-controlled-backend.js";
38
65
  export { SipgateApiError, SipgateClient } from "./backend/sipgate-client.js";
39
66
  export { createServer } from "./server.js";
67
+ export { loadStoredCredentials, storeCredentialsInteractively, } from "./credentials.js";
68
+ export { buildRegistrationCommand, parseSetupArgs, runSetup } from "./setup.js";
40
69
  export { createToolDefinitions } from "./tools/definitions.js";
70
+ export { VERSION } from "./version.js";
41
71
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EACL,iBAAiB,EACjB,6BAA6B,GAC9B,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,CAAC,KAAK,UAAU,IAAI;IACxB,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,IAAI,aAAa,CAAC,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IACnF,MAAM,cAAc,GAAG,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;IAClD,MAAM,OAAO,GAAG,MAAM,6BAA6B,CAAC,cAAc,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;IACxF,MAAM,MAAM,GAAG,YAAY,CAAC,OAAO,EAAE,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;IAC1E,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;AACnD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,SAAiB,EAAE,UAA8B;IAC5E,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,KAAK,YAAY,CAAC,UAAU,CAAC,CAAC;IAC7E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,IAAI,YAAY,CAAC,OAAO,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACnD,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;QAC9B,MAAM,MAAM,GAAG,KAAK,YAAY,iBAAiB,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7E,OAAO,CAAC,KAAK,CAAC,+BAA+B,MAAM,yEAAyE,CAAC,CAAC;QAC9H,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EACL,iBAAiB,EACjB,6BAA6B,GAC9B,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAM7E,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ import { type SipgateCredentials } from "./credentials.js";
2
+ export type SetupClient = "codex" | "claude";
3
+ export interface SetupOptions {
4
+ allowWrites: boolean;
5
+ clients: SetupClient[];
6
+ dryRun: boolean;
7
+ replaceCredentials: boolean;
8
+ }
9
+ export interface ClientCommand {
10
+ command: string;
11
+ args: string[];
12
+ }
13
+ export declare class SetupError extends Error {
14
+ }
15
+ export declare function parseSetupArgs(args: string[]): SetupOptions;
16
+ export declare function buildRegistrationCommand(client: SetupClient, nodeExecutable: string, entrypoint: string, allowWrites: boolean): ClientCommand;
17
+ export declare function ensureStoredCredentials(replaceCredentials: boolean, loadCredentials?: () => SipgateCredentials | undefined, storeCredentials?: () => void, output?: Pick<NodeJS.WriteStream, "write">): void;
18
+ export declare function runSetup(args: string[], entrypointArgument?: string | undefined): void;
19
+ export declare const SETUP_HELP = "Usage:\n sipgate-mcp Start the MCP stdio server\n sipgate-mcp setup [options] Store credentials and register MCP clients\n sipgate-mcp --version Print the installed version\n\nSetup options:\n --client codex|claude Register only this client (repeatable)\n --allow-writes Register write tools; default is read-only\n --replace-credentials Replace an existing PAT-ID and PAT in Keychain\n --dry-run Print registration commands without changing anything\n";
20
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE7C,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,OAAO,CAAC;IACrB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,MAAM,EAAE,OAAO,CAAC;IAChB,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,qBAAa,UAAW,SAAQ,KAAK;CAAG;AAExC,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,YAAY,CAwC3D;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,WAAW,EACnB,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,OAAO,GACnB,aAAa,CA4Cf;AAED,wBAAgB,uBAAuB,CACrC,kBAAkB,EAAE,OAAO,EAC3B,eAAe,GAAE,MAAM,kBAAkB,GAAG,SAAiC,EAC7E,gBAAgB,GAAE,MAAM,IAAoC,EAC5D,MAAM,GAAE,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,OAAO,CAAkB,GACzD,IAAI,CAQN;AAoBD,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EAAE,EACd,kBAAkB,GAAE,MAAM,GAAG,SAA2B,GACvD,IAAI,CA+DN;AAED,eAAO,MAAM,UAAU,siBAUtB,CAAC"}
package/dist/setup.js ADDED
@@ -0,0 +1,167 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { resolve } from "node:path";
3
+ import { loadStoredCredentials, storeCredentialsInteractively, } from "./credentials.js";
4
+ export class SetupError extends Error {
5
+ }
6
+ export function parseSetupArgs(args) {
7
+ const clients = [];
8
+ let allowWrites = false;
9
+ let dryRun = false;
10
+ let replaceCredentials = false;
11
+ for (let index = 0; index < args.length; index += 1) {
12
+ const argument = args[index];
13
+ if (argument === "--allow-writes") {
14
+ allowWrites = true;
15
+ continue;
16
+ }
17
+ if (argument === "--dry-run") {
18
+ dryRun = true;
19
+ continue;
20
+ }
21
+ if (argument === "--replace-credentials") {
22
+ replaceCredentials = true;
23
+ continue;
24
+ }
25
+ if (argument === "--client") {
26
+ const client = args[index + 1];
27
+ if (client !== "codex" && client !== "claude") {
28
+ throw new SetupError("--client must be either 'codex' or 'claude'.");
29
+ }
30
+ if (!clients.includes(client)) {
31
+ clients.push(client);
32
+ }
33
+ index += 1;
34
+ continue;
35
+ }
36
+ throw new SetupError(`Unknown setup option: ${argument ?? ""}`);
37
+ }
38
+ return {
39
+ allowWrites,
40
+ clients: clients.length > 0 ? clients : ["codex", "claude"],
41
+ dryRun,
42
+ replaceCredentials,
43
+ };
44
+ }
45
+ export function buildRegistrationCommand(client, nodeExecutable, entrypoint, allowWrites) {
46
+ const modeEnvironment = [
47
+ "SIPGATE_MCP_SCOPE=user",
48
+ `SIPGATE_MCP_READONLY=${allowWrites ? "0" : "1"}`,
49
+ ];
50
+ if (client === "codex") {
51
+ return {
52
+ command: "codex",
53
+ args: [
54
+ "mcp",
55
+ "add",
56
+ "sipgate",
57
+ "--env",
58
+ modeEnvironment[0],
59
+ "--env",
60
+ modeEnvironment[1],
61
+ "--",
62
+ nodeExecutable,
63
+ entrypoint,
64
+ ],
65
+ };
66
+ }
67
+ const configuration = {
68
+ type: "stdio",
69
+ command: nodeExecutable,
70
+ args: [entrypoint],
71
+ env: {
72
+ SIPGATE_MCP_SCOPE: "user",
73
+ SIPGATE_MCP_READONLY: allowWrites ? "0" : "1",
74
+ },
75
+ };
76
+ return {
77
+ command: "claude",
78
+ args: [
79
+ "mcp",
80
+ "add-json",
81
+ "--scope",
82
+ "user",
83
+ "sipgate",
84
+ JSON.stringify(configuration),
85
+ ],
86
+ };
87
+ }
88
+ export function ensureStoredCredentials(replaceCredentials, loadCredentials = loadStoredCredentials, storeCredentials = storeCredentialsInteractively, output = process.stderr) {
89
+ if (!replaceCredentials && loadCredentials()) {
90
+ output.write("Using the existing sipgate PAT-ID and PAT from macOS Keychain.\n");
91
+ return;
92
+ }
93
+ storeCredentials();
94
+ }
95
+ function isCommandAvailable(command) {
96
+ const result = spawnSync(command, ["--version"], { stdio: "ignore" });
97
+ return !result.error && result.status === 0;
98
+ }
99
+ function isAlreadyConfigured(client) {
100
+ const result = spawnSync(client, ["mcp", "get", "sipgate"], {
101
+ stdio: "ignore",
102
+ });
103
+ return !result.error && result.status === 0;
104
+ }
105
+ function shellDisplay(command) {
106
+ return [command.command, ...command.args]
107
+ .map((part) => (/^[A-Za-z0-9_./:=+-]+$/.test(part) ? part : JSON.stringify(part)))
108
+ .join(" ");
109
+ }
110
+ export function runSetup(args, entrypointArgument = process.argv[1]) {
111
+ const options = parseSetupArgs(args);
112
+ if (!entrypointArgument) {
113
+ throw new SetupError("Could not determine the sipgate-mcp entrypoint.");
114
+ }
115
+ const entrypoint = resolve(entrypointArgument);
116
+ const commands = options.clients.map((client) => ({
117
+ client,
118
+ registration: buildRegistrationCommand(client, process.execPath, entrypoint, options.allowWrites),
119
+ }));
120
+ if (options.dryRun) {
121
+ process.stdout.write("Dry run: no credentials or MCP configurations were changed.\n");
122
+ for (const { registration } of commands) {
123
+ process.stdout.write(`${shellDisplay(registration)}\n`);
124
+ }
125
+ return;
126
+ }
127
+ process.stderr.write("sipgate-mcp stores the PAT-ID and PAT in macOS Keychain. Secret values are not written to MCP configuration or shell history.\n");
128
+ try {
129
+ ensureStoredCredentials(options.replaceCredentials);
130
+ }
131
+ catch (error) {
132
+ const message = error instanceof Error
133
+ ? error.message
134
+ : "Secure credential storage failed.";
135
+ throw new SetupError(message);
136
+ }
137
+ for (const { client, registration } of commands) {
138
+ if (!isCommandAvailable(client)) {
139
+ process.stderr.write(`Skipping ${client}: command not found.\n`);
140
+ continue;
141
+ }
142
+ if (isAlreadyConfigured(client)) {
143
+ process.stderr.write(`Skipping ${client}: an MCP server named 'sipgate' is already configured. Remove it first to replace its launch command.\n`);
144
+ continue;
145
+ }
146
+ const result = spawnSync(registration.command, registration.args, {
147
+ stdio: "inherit",
148
+ });
149
+ if (result.error || result.status !== 0) {
150
+ throw new SetupError(`Could not register sipgate-mcp with ${client}.`);
151
+ }
152
+ process.stderr.write(`Registered sipgate-mcp with ${client} in user scope (${options.allowWrites ? "writes enabled" : "read-only"}).\n`);
153
+ }
154
+ process.stderr.write("Setup complete. Restart Codex or Claude, open /mcp, and ask it to list your sipgate numbers.\n");
155
+ }
156
+ export const SETUP_HELP = `Usage:
157
+ sipgate-mcp Start the MCP stdio server
158
+ sipgate-mcp setup [options] Store credentials and register MCP clients
159
+ sipgate-mcp --version Print the installed version
160
+
161
+ Setup options:
162
+ --client codex|claude Register only this client (repeatable)
163
+ --allow-writes Register write tools; default is read-only
164
+ --replace-credentials Replace an existing PAT-ID and PAT in Keychain
165
+ --dry-run Print registration commands without changing anything
166
+ `;
167
+ //# sourceMappingURL=setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.js","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare const VERSION = "0.3.1";
2
+ //# sourceMappingURL=version.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,OAAO,UAAU,CAAC"}
@@ -0,0 +1,2 @@
1
+ export const VERSION = "0.3.1";
2
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sipgate-mcp",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "description": "A self-hosted MCP server for configuring sipgate accounts through the sipgate REST API v2",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,6 +16,7 @@
16
16
  },
17
17
  "files": [
18
18
  "dist",
19
+ "SKILL.md",
19
20
  "README.md",
20
21
  "CHANGELOG.md",
21
22
  "LICENSE"