sipgate-mcp 0.1.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +125 -34
  3. package/SKILL.md +87 -0
  4. package/dist/backend/access-controlled-backend.d.ts +57 -0
  5. package/dist/backend/access-controlled-backend.d.ts.map +1 -0
  6. package/dist/backend/access-controlled-backend.js +227 -0
  7. package/dist/backend/access-controlled-backend.js.map +1 -0
  8. package/dist/backend/sipgate-backend.d.ts +13 -1
  9. package/dist/backend/sipgate-backend.d.ts.map +1 -1
  10. package/dist/backend/sipgate-backend.js +101 -10
  11. package/dist/backend/sipgate-backend.js.map +1 -1
  12. package/dist/backend/telephony-backend.d.ts +16 -0
  13. package/dist/backend/telephony-backend.d.ts.map +1 -1
  14. package/dist/config.d.ts +4 -1
  15. package/dist/config.d.ts.map +1 -1
  16. package/dist/config.js +19 -5
  17. package/dist/config.js.map +1 -1
  18. package/dist/credentials.d.ts +13 -0
  19. package/dist/credentials.d.ts.map +1 -0
  20. package/dist/credentials.js +57 -0
  21. package/dist/credentials.js.map +1 -0
  22. package/dist/index.d.ts +6 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +38 -4
  25. package/dist/index.js.map +1 -1
  26. package/dist/server.d.ts +2 -2
  27. package/dist/server.d.ts.map +1 -1
  28. package/dist/server.js +8 -3
  29. package/dist/server.js.map +1 -1
  30. package/dist/setup.d.ts +17 -0
  31. package/dist/setup.d.ts.map +1 -0
  32. package/dist/setup.js +152 -0
  33. package/dist/setup.js.map +1 -0
  34. package/dist/tools/definitions.d.ts +2 -2
  35. package/dist/tools/definitions.d.ts.map +1 -1
  36. package/dist/tools/definitions.js +53 -18
  37. package/dist/tools/definitions.js.map +1 -1
  38. package/dist/version.d.ts +2 -0
  39. package/dist/version.d.ts.map +1 -0
  40. package/dist/version.js +2 -0
  41. package/dist/version.js.map +1 -0
  42. package/package.json +3 -1
package/CHANGELOG.md ADDED
@@ -0,0 +1,29 @@
1
+ # Changelog
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
+
15
+ ## 0.2.0 - 2026-08-30
16
+
17
+ - Default to MCP-level user scope resolved from sipgate's authenticated user.
18
+ - Restrict user-scoped users, numbers, devices, phonelines, settings, and call
19
+ history to the authenticated user's resources.
20
+ - Validate user-scoped write targets and outbound caller identities before
21
+ sending changes or chargeable actions to sipgate.
22
+ - Avoid account-wide number and active-call snapshots in user-scoped actions.
23
+ - Add explicit account scope that requires a verified sipgate administrator.
24
+ - Advertise active scope and read-only behavior through MCP server instructions.
25
+
26
+ ## 0.1.0 - 2026-08-30
27
+
28
+ - Initial local stdio MCP server with focused sipgate read and write tools.
29
+ - Personal Access Token authentication and optional read-only mode.
package/README.md CHANGED
@@ -2,18 +2,32 @@
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 and later default to user-scoped access: tools are constrained to the
6
+ authenticated sipgate user's resources. Account-wide access is an explicit
7
+ administrator-only mode.
8
+
5
9
  The server uses stdio only. It does not start an HTTP server or route credentials
6
10
  through a third-party service. It sends authentication only from the local MCP
7
11
  process directly to `https://api.sipgate.com/v2`.
8
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
+
9
24
  ## Requirements
10
25
 
11
26
  - Node.js 22 or newer
12
27
  - A sipgate account with a Personal Access Token (PAT)
13
28
  - An MCP client with stdio support
14
29
 
15
- After the first npm release, install the command globally with any of the
16
- supported package managers:
30
+ Install the command globally with any of the supported package managers:
17
31
 
18
32
  ```bash
19
33
  npm install --global sipgate-mcp
@@ -21,54 +35,114 @@ pnpm add --global sipgate-mcp
21
35
  vp install --global sipgate-mcp
22
36
  ```
23
37
 
24
- Then start it with:
38
+ On macOS, run the interactive setup once:
25
39
 
26
40
  ```bash
27
- export SIPGATE_TOKEN_ID="your-token-id"
28
- export SIPGATE_TOKEN="your-token"
29
- sipgate-mcp
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
67
+ export SIPGATE_MCP_SCOPE="user"
68
+ export SIPGATE_MCP_READONLY="1"
30
69
  ```
31
70
 
32
71
  For clients that manage MCP commands on demand, `npx -y sipgate-mcp` remains
33
- supported without a global installation. The package name was available when
34
- checked on 2026-08-30; this repository is configured for `sipgate-mcp`, but the
35
- initial npm publish still needs to be completed.
72
+ supported without a global installation.
36
73
 
37
74
  ## Create a Personal Access Token
38
75
 
39
76
  1. Open [sipgate Personal Access Tokens](https://app.sipgate.com/personal-access-token).
40
77
  2. Select **Add token**, give the token a recognizable name, and select the scopes needed for the tools you intend to use.
41
78
  3. Copy both the token ID and token. sipgate displays the token itself only once.
42
- 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.
43
80
 
44
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).
45
82
 
46
- 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).
93
+
94
+ ## MCP access scopes
95
+
96
+ `SIPGATE_MCP_SCOPE` controls the resource boundary enforced by the MCP in
97
+ addition to sipgate's own user role and PAT scopes:
98
+
99
+ | Value | Behavior |
100
+ | --- | --- |
101
+ | `user` (default) | Resolves the authenticated user through `/authorization/userinfo`; returns only that user and their assigned numbers; forces user-specific device, routing, and settings reads; constrains call history to owned connection IDs; and validates every write target against owned numbers, phonelines, or devices. |
102
+ | `account` | Enables account-wide reads and writes. Startup fails unless `/users/{authenticatedUserId}` reports `admin: true`. Requires `users:read` for the administrator check. |
103
+
104
+ Token scopes are permission ceilings, not role elevation. For example,
105
+ `numbers:write` does not turn a regular sipgate user into an administrator.
106
+ The effective permission is the intersection of the sipgate user role, PAT
107
+ scopes, MCP access scope, and read-only mode.
108
+
109
+ Use account scope only when account-wide administration is intended:
110
+
111
+ ```bash
112
+ export SIPGATE_MCP_SCOPE="account"
113
+ npx -y sipgate-mcp
114
+ ```
47
115
 
48
116
  ## Tools and PAT scopes
49
117
 
50
- The table lists the non-`all` scopes named by sipgate's live Swagger document, plus scopes required by this server's pre/post state reads. sipgate also exposes broader parent scopes such as `sessions:write`; select the listed specific and parent scopes offered by the PAT UI when in doubt.
118
+ Every mode identifies the authenticated user with `GET /authorization/userinfo`.
119
+ The table lists the non-`all` scopes named by sipgate's live Swagger document,
120
+ including ownership checks performed in user scope and pre/post state reads.
121
+ sipgate also exposes broader parent scopes such as `sessions:write`; select the
122
+ listed specific and parent scopes offered by the PAT UI when in doubt.
51
123
 
52
124
  | Tool | Access | sipgate API calls | PAT scopes |
53
125
  | --- | --- | --- | --- |
54
- | `account_info` | Read | `GET /account`, `GET /authorization/userinfo` | `account:read` (`userinfo` has no scope declaration in Swagger) |
55
- | `list_users` | Read | `GET /users` | `users:read` |
56
- | `list_numbers` | Read | `GET /numbers` | `numbers:read` |
57
- | `list_devices` | Read | `GET /users`, `GET /{userId}/devices` | `devices:read`; `users:read` when `user_id` is omitted |
58
- | `get_routing` | Read | `GET /numbers`, `GET /users`, `GET /{userId}/phonelines`, `GET /{userId}/phonelines/{phonelineId}/numbers`, `GET /{userId}/phonelines/{phonelineId}/forwardings` | `numbers:read`, `phonelines:read`, `phonelines:numbers:read`, `phonelines:forwardings:read`; `users:read` when `user_id` is omitted |
59
- | `call_history` | Read | `GET /history` | `history:read` |
126
+ | `account_info` | Read | User: cached `/authorization/userinfo`; account: plus `GET /account` | Account: `account:read` (`userinfo` has no scope declaration in Swagger) |
127
+ | `list_users` | Read | User: `GET /users/{self}`; account: `GET /users` | `users:read` |
128
+ | `list_numbers` | Read | User: `GET /{self}/phonelines` and each phoneline's `/numbers`; account: `GET /numbers` | User: `phonelines:read`, `phonelines:numbers:read`; account: `numbers:read` |
129
+ | `list_devices` | Read | User: `GET /{self}/devices`; account: `GET /users`, `GET /{userId}/devices` | `devices:read`; account also needs `users:read` when `user_id` is omitted |
130
+ | `get_routing` | Read | User: own phonelines, numbers, and forwardings; account: also `GET /numbers` and `GET /users` | `phonelines:read`, `phonelines:numbers:read`, `phonelines:forwardings:read`; account also needs `numbers:read` and, when `user_id` is omitted, `users:read` |
131
+ | `call_history` | Read | User: ownership reads for own phonelines/devices, then filtered `GET /history`; account: `GET /history` | `history:read`; user also needs `phonelines:read`, `devices:read` |
60
132
  | `get_settings` | Read | `GET /users[/userId]`, `GET /{userId}/devices`, `GET /{userId}/phonelines[/phonelineId]` | `users:read`, `devices:read`, `phonelines:read` |
61
- | `set_number_routing` | Write | pre/post `GET /numbers`, `PUT /numbers/{numberId}` | `numbers:read`, `numbers:write` |
62
- | `set_forwarding` | Write | pre/post `GET /{userId}/phonelines/{phonelineId}/forwardings`, `PUT` to the same path | `phonelines:read`, `phonelines:write`, `phonelines:forwardings:read`, `phonelines:forwardings:write` |
63
- | `set_dnd` | Write | pre/post `GET /devices/{deviceId}`, `PUT /devices/{deviceId}` | `devices:read`, `devices:write` |
133
+ | `set_number_routing` | Write | User: pre/post reads through own phonelines; account: pre/post `GET /numbers`; all modes: `PUT /numbers/{numberId}` | `numbers:write`; user also needs `phonelines:read`, `phonelines:numbers:read`; account needs `numbers:read` |
134
+ | `set_forwarding` | Write | User: phoneline ownership read; then pre/post forwarding reads and `PUT` | `phonelines:read`, `phonelines:write`, `phonelines:forwardings:read`, `phonelines:forwardings:write` |
135
+ | `set_dnd` | Write | User: device ownership read; then pre/post `GET /devices/{deviceId}` and `PUT` | `devices:read`, `devices:write` |
64
136
  | `send_sms` | Write/action | `GET /{userId}/sms`, pre/post `GET /history`, `POST /sessions/sms` | `sms:read`, `history:read`, `sessions:write`, `sessions:sms:write` |
65
- | `initiate_call` | Write/action | pre/post `GET /calls`, `POST /sessions/calls` | `rtcm:read`, `sessions:write`, `sessions:calls:write` |
137
+ | `initiate_call` | Write/action | User: device/number ownership reads, then `POST /sessions/calls`; account: pre/post `GET /calls` plus `POST` | `sessions:write`, `sessions:calls:write`; user also needs `devices:read`, `phonelines:read`, `phonelines:numbers:read`; account needs `rtcm:read` |
66
138
 
67
139
  Every write tool reads current state first and returns a JSON object with `before` and `after`. SMS history can update asynchronously, and `/calls` only contains established calls, so those action snapshots also include an acceptance/session marker.
68
140
 
69
141
  ### Tool notes
70
142
 
71
143
  - `list_devices` resolves devices through users because the documented account-wide route is `GET /{userId}/devices`; the live v2 Swagger document does not define `GET /devices`.
144
+ - User scope resolves assigned numbers through the authenticated user's phonelines and never calls account-wide `GET /users` or `GET /numbers` for read tools.
145
+ - User-scoped number-routing snapshots are also resolved through owned phonelines, and user-scoped Click2Dial deliberately omits account-wide `/calls` snapshots.
72
146
  - Number routing uses sipgate's documented `endpointId`. Obtain existing IDs from the read tools; a phoneline ID such as `p0` is the documented example.
73
147
  - `set_forwarding` replaces the complete phoneline forwarding list. Pass `forwardings: []` to remove all forwardings. A `timeout` of `0` represents immediate forwarding.
74
148
  - `send_sms` refuses to post unless `GET /{userId}/sms` returns the requested (or first available) SMS extension.
@@ -80,12 +154,16 @@ Set `SIPGATE_MCP_READONLY=1` to register only the seven read tools. Write tools
80
154
 
81
155
  ```bash
82
156
  export SIPGATE_MCP_READONLY=1
157
+ export SIPGATE_MCP_SCOPE=user
83
158
  npx -y sipgate-mcp
84
159
  ```
85
160
 
86
161
  ## MCP client configuration
87
162
 
88
- 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.
89
167
 
90
168
  ### Claude Code
91
169
 
@@ -95,12 +173,13 @@ Claude Code expands `${VAR}` references in MCP environment entries. Single quote
95
173
  claude mcp add \
96
174
  --env 'SIPGATE_TOKEN_ID=${SIPGATE_TOKEN_ID}' \
97
175
  --env 'SIPGATE_TOKEN=${SIPGATE_TOKEN}' \
176
+ --env SIPGATE_MCP_SCOPE=user \
98
177
  --transport stdio \
99
178
  --scope user \
100
179
  sipgate -- npx -y sipgate-mcp
101
180
  ```
102
181
 
103
- Add `--env SIPGATE_MCP_READONLY=1` before `--transport` for read-only mode. Verify the connection with `claude mcp get sipgate`. See the official [Claude Code MCP documentation](https://code.claude.com/docs/en/mcp).
182
+ Add `--env SIPGATE_MCP_READONLY=1` before `--transport` for read-only mode. Replace the scope with `account` only for deliberate administrator access. Verify the connection with `claude mcp get sipgate`. See the official [Claude Code MCP documentation](https://code.claude.com/docs/en/mcp).
104
183
 
105
184
  ### Claude Desktop
106
185
 
@@ -127,18 +206,22 @@ Codex can forward named variables from its local environment without storing the
127
206
  [mcp_servers.sipgate]
128
207
  command = "npx"
129
208
  args = ["-y", "sipgate-mcp"]
130
- env_vars = ["SIPGATE_TOKEN_ID", "SIPGATE_TOKEN", "SIPGATE_MCP_READONLY"]
209
+ env_vars = ["SIPGATE_TOKEN_ID", "SIPGATE_TOKEN", "SIPGATE_MCP_SCOPE", "SIPGATE_MCP_READONLY"]
131
210
  ```
132
211
 
133
212
  Export the variables before starting Codex, then use `/mcp` or `codex mcp list` to confirm the server. The `env_vars` forwarding form is documented in the [official OpenAI MCP documentation](https://developers.openai.com/codex/mcp/).
134
213
 
135
214
  ## Manual smoke test with MCP Inspector
136
215
 
137
- This test makes real sipgate API calls. Start with a PAT containing only `account:read` and `numbers:read`, plus the required environment variables:
216
+ This test makes real sipgate API calls. Start in user/read-only mode with a PAT
217
+ containing `phonelines:read` and `phonelines:numbers:read`, plus the required
218
+ environment variables:
138
219
 
139
220
  ```bash
140
221
  export SIPGATE_TOKEN_ID="your-token-id"
141
222
  export SIPGATE_TOKEN="your-token"
223
+ export SIPGATE_MCP_SCOPE="user"
224
+ export SIPGATE_MCP_READONLY=1
142
225
  npx @modelcontextprotocol/inspector npx -y sipgate-mcp
143
226
  ```
144
227
 
@@ -158,17 +241,24 @@ The MCP layer depends only on the backend interface:
158
241
  ```text
159
242
  MCP stdio server
160
243
  -> validated tool definitions (Zod)
161
- -> TelephonyBackend
162
- -> SipgateBackend (v1 implementation)
163
- -> SipgateClient
164
- -> native fetch -> https://api.sipgate.com/v2
244
+ -> user/account access policy
245
+ -> TelephonyBackend
246
+ -> SipgateBackend
247
+ -> SipgateClient
248
+ -> native fetch -> https://api.sipgate.com/v2
165
249
  ```
166
250
 
167
251
  `TelephonyBackend` contains the stable, provider-neutral operations. `SipgateBackend` is the only v1 implementation, so a future second telephony provider can reuse the same MCP tool surface.
168
252
 
169
253
  ## Security
170
254
 
171
- - 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.
260
+ - User scope is the default and validates user IDs plus number, phoneline, device, call, and history ownership before delegation.
261
+ - Account scope fails startup unless the authenticated sipgate user reports `admin: true`.
172
262
  - The Basic Auth header exists only in memory and is sent only to the fixed sipgate API base URL.
173
263
  - API error bodies are discarded. User-facing errors never include request headers, response bodies, or credentials.
174
264
  - Potentially sensitive response properties such as `credentials`, `password`, `token`, and `secret` are redacted before tool output.
@@ -184,7 +274,7 @@ npm run build
184
274
  npm test
185
275
  ```
186
276
 
187
- Tests use `node:test` and mocked `fetch`; they never call the real sipgate API. The suite includes client authentication/error behavior, exact critical write payloads, credential redaction, one test per MCP tool, and read-only registration.
277
+ Tests use `node:test` and mocked `fetch`; they never call the real sipgate API. The suite includes client authentication/error behavior, user/account access-policy enforcement, exact critical write payloads, credential redaction, one test per MCP tool, and read-only registration.
188
278
 
189
279
  ## Releases
190
280
 
@@ -203,8 +293,9 @@ The endpoint paths, query parameters, request bodies, response models, and scope
203
293
 
204
294
  ## Roadmap
205
295
 
206
- - v1: local self-hosted stdio server (this release)
207
- - v2: optional remote deployment, including a Cloudflare Workers backend, without changing the MCP tool surface
296
+ - v0.1: local self-hosted stdio server and sipgate REST API tools
297
+ - v0.2: user-scoped access by default plus explicit administrator-only account scope
298
+ - Future: optional remote deployment, including a Cloudflare Workers backend, without changing the MCP tool surface
208
299
  - Additional `TelephonyBackend` implementation(s)
209
300
  - Product-aware Click2Dial behavior for classic and Neo PBX accounts
210
301
 
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.
@@ -0,0 +1,57 @@
1
+ import type { AccessScope, AuthenticatedUserContext, DeviceType, ForwardingRule, HistoryQuery, JsonValue, MutationResult, PaginationInput, TelephonyBackend } from "./telephony-backend.js";
2
+ export declare class AccessPolicyError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ /**
6
+ * Enforces MCP-level resource boundaries in addition to sipgate's own role and
7
+ * token-scope checks. Account scope is rejected unless sipgate identifies the
8
+ * authenticated user as an administrator.
9
+ */
10
+ export declare class AccessControlledBackend implements TelephonyBackend {
11
+ private readonly delegate;
12
+ private readonly scope;
13
+ private readonly context;
14
+ constructor(delegate: TelephonyBackend, scope: AccessScope, context: AuthenticatedUserContext);
15
+ getAuthenticatedUser(): Promise<AuthenticatedUserContext>;
16
+ getUser(userId: string): Promise<JsonValue>;
17
+ getAccountInfo(): Promise<JsonValue>;
18
+ listUsers(): Promise<JsonValue>;
19
+ listNumbers({ offset, limit }: PaginationInput): Promise<JsonValue>;
20
+ listUserNumbers(userId: string, pagination: PaginationInput): Promise<JsonValue>;
21
+ listPhonelines(userId: string): Promise<JsonValue>;
22
+ listDevices(userId?: string, types?: DeviceType[]): Promise<JsonValue>;
23
+ getRouting(userId?: string): Promise<JsonValue>;
24
+ getCallHistory(query: HistoryQuery): Promise<JsonValue>;
25
+ getSettings(userId?: string): Promise<JsonValue>;
26
+ setNumberRouting(numberId: string, endpointId: string): Promise<MutationResult>;
27
+ setUserNumberRouting(userId: string, numberId: string, endpointId: string): Promise<MutationResult>;
28
+ setForwarding(userId: string, phonelineId: string, forwardings: ForwardingRule[]): Promise<MutationResult>;
29
+ setDnd(deviceId: string, enabled: boolean): Promise<MutationResult>;
30
+ sendSms(input: {
31
+ userId: string;
32
+ smsId?: string;
33
+ recipient: string;
34
+ message: string;
35
+ sendAt?: number;
36
+ }): Promise<MutationResult>;
37
+ initiateCall(input: {
38
+ caller: string;
39
+ callee: string;
40
+ callerId?: string;
41
+ deviceId?: string;
42
+ }): Promise<MutationResult>;
43
+ initiateUserCall(input: {
44
+ caller: string;
45
+ callee: string;
46
+ callerId?: string;
47
+ deviceId?: string;
48
+ }): Promise<MutationResult>;
49
+ private assertUser;
50
+ private assertOwned;
51
+ private ownedConnectionIds;
52
+ private ownedPhonelineIds;
53
+ private ownedDeviceIds;
54
+ private ownedNumbers;
55
+ }
56
+ export declare function createAccessControlledBackend(delegate: TelephonyBackend, scope: AccessScope): Promise<AccessControlledBackend>;
57
+ //# sourceMappingURL=access-controlled-backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"access-controlled-backend.d.ts","sourceRoot":"","sources":["../../src/backend/access-controlled-backend.ts"],"names":[],"mappings":"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"}