sipgate-mcp 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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.0 - 2026-08-30
4
+
5
+ - Add `sipgate-mcp setup` for interactive PAT storage in macOS Keychain.
6
+ - Register installed Codex and Claude Code clients with a secret-free launch
7
+ command, user scope, and read-only mode by default.
8
+ - Load Keychain credentials automatically when environment credentials are
9
+ absent, while keeping environment variables as an explicit override.
10
+ - Add setup dry-run and opt-in write-mode flags.
11
+ - Add a versioned agent skill and README bootstrap link for guided setup.
12
+ - Add `sipgate-mcp --version` and verify that CLI, package, and skill versions
13
+ remain synchronized.
14
+
3
15
  ## 0.2.0 - 2026-08-30
4
16
 
5
17
  - 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,37 @@ 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.
54
+
55
+ Secure interactive storage currently supports macOS. Environment variables
56
+ remain available for Linux, Windows, containers, CI, and password-manager
57
+ wrappers. To avoid putting literal credentials in shell history, read them
58
+ interactively:
59
+
60
+ ```bash
61
+ printf "sipgate PAT token ID: "
62
+ IFS= read -r SIPGATE_TOKEN_ID
63
+ printf "sipgate PAT token: "
64
+ IFS= read -rs SIPGATE_TOKEN
65
+ printf "\n"
66
+ export SIPGATE_TOKEN_ID SIPGATE_TOKEN
32
67
  export SIPGATE_MCP_SCOPE="user"
33
- sipgate-mcp
68
+ export SIPGATE_MCP_READONLY="1"
34
69
  ```
35
70
 
36
71
  For clients that manage MCP commands on demand, `npx -y sipgate-mcp` remains
@@ -41,11 +76,20 @@ supported without a global installation.
41
76
  1. Open [sipgate Personal Access Tokens](https://app.sipgate.com/personal-access-token).
42
77
  2. Select **Add token**, give the token a recognizable name, and select the scopes needed for the tools you intend to use.
43
78
  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.
79
+ 4. Run `sipgate-mcp setup` on macOS, or provide them as `SIPGATE_TOKEN_ID` and `SIPGATE_TOKEN` in the MCP process environment.
45
80
 
46
81
  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
82
 
48
- Do not put either value in this repository, an MCP config committed to source control, command output, or an issue report.
83
+ Do not put either value in this repository, an MCP config committed to source control, shell command arguments, command output, or an issue report.
84
+
85
+ The separate **API Clients** screen in the sipgate account creates OAuth 2.0
86
+ client credentials for an application that redirects users through sipgate's
87
+ authorization flow. Those client credentials are not PAT replacements and are
88
+ not used by the local stdio setup. They are relevant to a future hosted/remote
89
+ MCP, which would need a registered redirect URI, user consent, access-token
90
+ refresh, and secure per-user token storage. See sipgate's [OAuth authentication
91
+ flow](https://en.sipgate.io/rest-api/authentication#oauth2) and [API client
92
+ management](https://en.sipgate.io/rest-api/managing-third-party-clients).
49
93
 
50
94
  ## MCP access scopes
51
95
 
@@ -116,7 +160,10 @@ npx -y sipgate-mcp
116
160
 
117
161
  ## MCP client configuration
118
162
 
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.
163
+ The recommended macOS path is `sipgate-mcp setup`. The following manual
164
+ examples are useful for other platforms and custom launchers. Set
165
+ `SIPGATE_TOKEN_ID` and `SIPGATE_TOKEN` in the environment that launches the MCP
166
+ client; the examples keep secret values out of configuration files.
120
167
 
121
168
  ### Claude Code
122
169
 
@@ -205,7 +252,11 @@ MCP stdio server
205
252
 
206
253
  ## Security
207
254
 
208
- - PAT values are read only from `SIPGATE_TOKEN_ID` and `SIPGATE_TOKEN`.
255
+ - PAT values are read from `SIPGATE_TOKEN_ID` and `SIPGATE_TOKEN`, or from the
256
+ current user's macOS Keychain when both variables are absent.
257
+ - `sipgate-mcp setup` delegates secret entry directly to the macOS Keychain
258
+ prompt. Secret values are never passed as command-line arguments and are not
259
+ written to Codex or Claude configuration.
209
260
  - User scope is the default and validates user IDs plus number, phoneline, device, call, and history ownership before delegation.
210
261
  - Account scope fails startup unless the authenticated sipgate user reports `admin: true`.
211
262
  - 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,87 @@
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.0"
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.0
14
+ ```
15
+
16
+ ```bash
17
+ npm install -g sipgate-mcp@0.3.0
18
+ ```
19
+
20
+ ```bash
21
+ pnpm add -g sipgate-mcp@0.3.0
22
+ ```
23
+
24
+ Run only one install command. Confirm that `sipgate-mcp --version` reports
25
+ `0.3.0` 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
+ If the Keychain prompt cannot be presented in the current environment, ask the
61
+ user to run the setup command in their local interactive terminal. Do not ask
62
+ them to provide the credential to the agent instead. On Linux or Windows,
63
+ follow the secret-free environment or password-manager launcher guidance in
64
+ the project README rather than inventing a plaintext credential file.
65
+
66
+ If setup reports that an MCP server named `sipgate` already exists, inspect it
67
+ with `codex mcp get sipgate` or `claude mcp get sipgate`. Explain the conflict
68
+ and request approval before removing or replacing that configuration.
69
+
70
+ ## Verify
71
+
72
+ Use the applicable client command:
73
+
74
+ ```bash
75
+ codex mcp get sipgate
76
+ ```
77
+
78
+ ```bash
79
+ claude mcp get sipgate
80
+ ```
81
+
82
+ Ask the user to restart the client when required, open `/mcp`, and test with:
83
+
84
+ > Use sipgate read-only. Check the connection and list my phone numbers.
85
+
86
+ Do not enable `--allow-writes` merely to make a failed read test pass. Diagnose
87
+ 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) => 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,KAAK,IAAI,CAAC;AAwChD,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,CAWN"}
@@ -0,0 +1,57 @@
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) {
19
+ const result = spawnSync("/usr/bin/security", [
20
+ "add-generic-password",
21
+ "-a",
22
+ account,
23
+ "-s",
24
+ MACOS_KEYCHAIN_SERVICE,
25
+ "-U",
26
+ "-w",
27
+ ], { stdio: "inherit" });
28
+ if (result.error || result.status !== 0) {
29
+ throw new Error("macOS Keychain did not store the credential.");
30
+ }
31
+ }
32
+ export function loadStoredCredentials(platform = process.platform, readKeychain = defaultKeychainReader) {
33
+ if (platform !== "darwin") {
34
+ return undefined;
35
+ }
36
+ try {
37
+ const tokenId = readKeychain(MACOS_KEYCHAIN_TOKEN_ID_ACCOUNT).trim();
38
+ const token = readKeychain(MACOS_KEYCHAIN_TOKEN_ACCOUNT).trim();
39
+ if (!tokenId || !token) {
40
+ return undefined;
41
+ }
42
+ return { tokenId, token };
43
+ }
44
+ catch {
45
+ return undefined;
46
+ }
47
+ }
48
+ export function storeCredentialsInteractively(platform = process.platform, writeKeychain = defaultKeychainWriter, output = process.stderr) {
49
+ if (platform !== "darwin") {
50
+ throw new Error("Secure interactive setup currently supports macOS Keychain only. Use SIPGATE_TOKEN_ID and SIPGATE_TOKEN on this platform.");
51
+ }
52
+ output.write("Enter the sipgate PAT token ID in the macOS Keychain prompt.\n");
53
+ writeKeychain(MACOS_KEYCHAIN_TOKEN_ID_ACCOUNT);
54
+ output.write("Enter the sipgate PAT token in the macOS Keychain prompt.\n");
55
+ writeKeychain(MACOS_KEYCHAIN_TOKEN_ACCOUNT);
56
+ }
57
+ //# 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;IAC5C,MAAM,MAAM,GAAG,SAAS,CACtB,mBAAmB,EACnB;QACE,sBAAsB;QACtB,IAAI;QACJ,OAAO;QACP,IAAI;QACJ,sBAAsB;QACtB,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,CAAC,gEAAgE,CAAC,CAAC;IAC/E,aAAa,CAAC,+BAA+B,CAAC,CAAC;IAC/C,MAAM,CAAC,KAAK,CAAC,6DAA6D,CAAC,CAAC;IAC5E,aAAa,CAAC,4BAA4B,CAAC,CAAC;AAC9C,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,17 @@
1
+ export type SetupClient = "codex" | "claude";
2
+ export interface SetupOptions {
3
+ allowWrites: boolean;
4
+ clients: SetupClient[];
5
+ dryRun: boolean;
6
+ }
7
+ export interface ClientCommand {
8
+ command: string;
9
+ args: string[];
10
+ }
11
+ export declare class SetupError extends Error {
12
+ }
13
+ export declare function parseSetupArgs(args: string[]): SetupOptions;
14
+ export declare function buildRegistrationCommand(client: SetupClient, nodeExecutable: string, entrypoint: string, allowWrites: boolean): ClientCommand;
15
+ export declare function runSetup(args: string[], entrypointArgument?: string | undefined): void;
16
+ 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 --dry-run Print registration commands without changing anything\n";
17
+ //# sourceMappingURL=setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAIA,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;CACjB;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,CAkC3D;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,WAAW,EACnB,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,OAAO,GACnB,aAAa,CA2Cf;AAoBD,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EAAE,EACd,kBAAkB,GAAE,MAAM,GAAG,SAA2B,GACvD,IAAI,CA+DN;AAED,eAAO,MAAM,UAAU,qdAStB,CAAC"}
package/dist/setup.js ADDED
@@ -0,0 +1,152 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { resolve } from "node:path";
3
+ import { 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
+ for (let index = 0; index < args.length; index += 1) {
11
+ const argument = args[index];
12
+ if (argument === "--allow-writes") {
13
+ allowWrites = true;
14
+ continue;
15
+ }
16
+ if (argument === "--dry-run") {
17
+ dryRun = true;
18
+ continue;
19
+ }
20
+ if (argument === "--client") {
21
+ const client = args[index + 1];
22
+ if (client !== "codex" && client !== "claude") {
23
+ throw new SetupError("--client must be either 'codex' or 'claude'.");
24
+ }
25
+ if (!clients.includes(client)) {
26
+ clients.push(client);
27
+ }
28
+ index += 1;
29
+ continue;
30
+ }
31
+ throw new SetupError(`Unknown setup option: ${argument ?? ""}`);
32
+ }
33
+ return {
34
+ allowWrites,
35
+ clients: clients.length > 0 ? clients : ["codex", "claude"],
36
+ dryRun,
37
+ };
38
+ }
39
+ export function buildRegistrationCommand(client, nodeExecutable, entrypoint, allowWrites) {
40
+ const modeEnvironment = [
41
+ "SIPGATE_MCP_SCOPE=user",
42
+ `SIPGATE_MCP_READONLY=${allowWrites ? "0" : "1"}`,
43
+ ];
44
+ if (client === "codex") {
45
+ return {
46
+ command: "codex",
47
+ args: [
48
+ "mcp",
49
+ "add",
50
+ "sipgate",
51
+ "--env",
52
+ modeEnvironment[0],
53
+ "--env",
54
+ modeEnvironment[1],
55
+ "--",
56
+ nodeExecutable,
57
+ entrypoint,
58
+ ],
59
+ };
60
+ }
61
+ return {
62
+ command: "claude",
63
+ args: [
64
+ "mcp",
65
+ "add",
66
+ "--transport",
67
+ "stdio",
68
+ "--scope",
69
+ "user",
70
+ "--env",
71
+ modeEnvironment[0],
72
+ "--env",
73
+ modeEnvironment[1],
74
+ "sipgate",
75
+ "--",
76
+ nodeExecutable,
77
+ entrypoint,
78
+ ],
79
+ };
80
+ }
81
+ function isCommandAvailable(command) {
82
+ const result = spawnSync(command, ["--version"], { stdio: "ignore" });
83
+ return !result.error && result.status === 0;
84
+ }
85
+ function isAlreadyConfigured(client) {
86
+ const result = spawnSync(client, ["mcp", "get", "sipgate"], {
87
+ stdio: "ignore",
88
+ });
89
+ return !result.error && result.status === 0;
90
+ }
91
+ function shellDisplay(command) {
92
+ return [command.command, ...command.args]
93
+ .map((part) => (/^[A-Za-z0-9_./:=+-]+$/.test(part) ? part : JSON.stringify(part)))
94
+ .join(" ");
95
+ }
96
+ export function runSetup(args, entrypointArgument = process.argv[1]) {
97
+ const options = parseSetupArgs(args);
98
+ if (!entrypointArgument) {
99
+ throw new SetupError("Could not determine the sipgate-mcp entrypoint.");
100
+ }
101
+ const entrypoint = resolve(entrypointArgument);
102
+ const commands = options.clients.map((client) => ({
103
+ client,
104
+ registration: buildRegistrationCommand(client, process.execPath, entrypoint, options.allowWrites),
105
+ }));
106
+ if (options.dryRun) {
107
+ process.stdout.write("Dry run: no credentials or MCP configurations were changed.\n");
108
+ for (const { registration } of commands) {
109
+ process.stdout.write(`${shellDisplay(registration)}\n`);
110
+ }
111
+ return;
112
+ }
113
+ process.stderr.write("sipgate-mcp will store the PAT in macOS Keychain. Secret values are not written to MCP configuration or shell history.\n");
114
+ try {
115
+ storeCredentialsInteractively();
116
+ }
117
+ catch (error) {
118
+ const message = error instanceof Error
119
+ ? error.message
120
+ : "Secure credential storage failed.";
121
+ throw new SetupError(message);
122
+ }
123
+ for (const { client, registration } of commands) {
124
+ if (!isCommandAvailable(client)) {
125
+ process.stderr.write(`Skipping ${client}: command not found.\n`);
126
+ continue;
127
+ }
128
+ if (isAlreadyConfigured(client)) {
129
+ process.stderr.write(`Skipping ${client}: an MCP server named 'sipgate' is already configured. Remove it first to replace its launch command.\n`);
130
+ continue;
131
+ }
132
+ const result = spawnSync(registration.command, registration.args, {
133
+ stdio: "inherit",
134
+ });
135
+ if (result.error || result.status !== 0) {
136
+ throw new SetupError(`Could not register sipgate-mcp with ${client}.`);
137
+ }
138
+ process.stderr.write(`Registered sipgate-mcp with ${client} in user scope (${options.allowWrites ? "writes enabled" : "read-only"}).\n`);
139
+ }
140
+ process.stderr.write("Setup complete. Restart Codex or Claude, open /mcp, and ask it to list your sipgate numbers.\n");
141
+ }
142
+ export const SETUP_HELP = `Usage:
143
+ sipgate-mcp Start the MCP stdio server
144
+ sipgate-mcp setup [options] Store credentials and register MCP clients
145
+ sipgate-mcp --version Print the installed version
146
+
147
+ Setup options:
148
+ --client codex|claude Register only this client (repeatable)
149
+ --allow-writes Register write tools; default is read-only
150
+ --dry-run Print registration commands without changing anything
151
+ `;
152
+ //# 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.0";
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.0";
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.0",
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"