granttap-mcp 0.6.7 → 0.7.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/README.md +141 -246
- package/SECURITY.md +63 -69
- package/apps/bridge/src/approval-state.ts +7 -5
- package/apps/bridge/src/approval.ts +4 -67
- package/apps/bridge/src/bin/claude-hook.ts +8 -0
- package/apps/bridge/src/bin/codex-hook.ts +3 -0
- package/apps/bridge/src/bin/codex-policy-hook.ts +2 -1
- package/apps/bridge/src/bin/connect.ts +27 -6
- package/apps/bridge/src/bin/cursor-after-shell.ts +5 -1
- package/apps/bridge/src/bin/cursor-hook.ts +5 -0
- package/apps/bridge/src/bin/cursor-mcp-hook.ts +5 -0
- package/apps/bridge/src/bin/mesh-connect.ts +27 -0
- package/apps/bridge/src/bin/reset.ts +53 -0
- package/apps/bridge/src/bin/setup.ts +88 -17
- package/apps/bridge/src/capabilities/README.md +3 -0
- package/apps/bridge/src/capabilities/descriptors.ts +91 -0
- package/apps/bridge/src/capabilities/metadata.ts +220 -0
- package/apps/bridge/src/capabilities/skills.ts +68 -0
- package/apps/bridge/src/capabilities/types.ts +34 -0
- package/apps/bridge/src/capabilities.ts +8 -440
- package/apps/bridge/src/config/README.md +7 -0
- package/apps/bridge/src/config/capability-policy.ts +160 -0
- package/apps/bridge/src/config/pairing.ts +143 -0
- package/apps/bridge/src/config/paths.ts +31 -0
- package/apps/bridge/src/config/runtime.ts +175 -0
- package/apps/bridge/src/config.ts +8 -524
- package/apps/bridge/src/install.ts +15 -3
- package/apps/bridge/src/mesh/README.md +25 -0
- package/apps/bridge/src/mesh/attention.ts +19 -0
- package/apps/bridge/src/mesh/capsule.ts +86 -0
- package/apps/bridge/src/mesh/catalog.ts +105 -0
- package/apps/bridge/src/mesh/endpoint.ts +179 -0
- package/apps/bridge/src/mesh/handoff.ts +37 -0
- package/apps/bridge/src/mesh/identity.ts +39 -0
- package/apps/bridge/src/mesh/local.ts +18 -0
- package/apps/bridge/src/mesh/runtime.ts +278 -0
- package/apps/bridge/src/mesh/store-support.ts +23 -0
- package/apps/bridge/src/mesh/store.ts +297 -0
- package/apps/bridge/src/mesh/worktree.ts +38 -0
- package/apps/bridge/src/monitor-heartbeat.ts +27 -0
- package/apps/bridge/src/monitor-publish-loop.ts +29 -0
- package/apps/bridge/src/monitor-session-activity.ts +60 -0
- package/apps/bridge/src/monitor-single-flight.ts +32 -0
- package/apps/bridge/src/monitor.ts +124 -79
- package/apps/bridge/src/pairing.ts +26 -0
- package/apps/bridge/src/reply/README.md +7 -0
- package/apps/bridge/src/reply/attachments.ts +50 -0
- package/apps/bridge/src/reply/process.ts +55 -0
- package/apps/bridge/src/reply/provider-headless.ts +96 -0
- package/apps/bridge/src/reply/routing.ts +18 -0
- package/apps/bridge/src/reply/types.ts +8 -0
- package/apps/bridge/src/reply.ts +33 -209
- package/apps/bridge/src/session-keys.ts +23 -1
- package/apps/bridge/src/sessions/claude.ts +4 -1
- package/apps/bridge/src/sessions/codex.ts +3 -0
- package/apps/bridge/src/sessions/common.ts +3 -5
- package/apps/bridge/src/sessions/cursor/README.md +6 -0
- package/apps/bridge/src/sessions/cursor/activity.ts +97 -0
- package/apps/bridge/src/sessions/cursor/catalog.ts +187 -0
- package/apps/bridge/src/sessions/cursor/scan.ts +162 -0
- package/apps/bridge/src/sessions/cursor/transcripts.ts +257 -0
- package/apps/bridge/src/sessions/cursor.ts +9 -868
- package/apps/bridge/src/sessions/grok.ts +179 -0
- package/apps/bridge/src/sessions/telemetry/README.md +6 -0
- package/apps/bridge/src/sessions/telemetry/command-preview.ts +105 -0
- package/apps/bridge/src/sessions/telemetry/estimation.ts +117 -0
- package/apps/bridge/src/sessions/telemetry/identity.ts +53 -0
- package/apps/bridge/src/sessions/telemetry.ts +43 -348
- package/apps/bridge/src/sessions.ts +11 -13
- package/apps/mcp/src/bin/status.ts +13 -9
- package/apps/mcp/src/create-server.ts +10 -333
- package/apps/mcp/src/cursor-config.ts +3 -3
- package/apps/mcp/src/http-service/README.md +3 -0
- package/apps/mcp/src/http-service/common.ts +48 -0
- package/apps/mcp/src/http-service/health.ts +56 -0
- package/apps/mcp/src/http-service/installer.ts +130 -0
- package/apps/mcp/src/http-service/snapshot.ts +125 -0
- package/apps/mcp/src/http-service.ts +15 -396
- package/apps/mcp/src/mcp-tools/README.md +17 -0
- package/apps/mcp/src/mcp-tools/connect.ts +75 -0
- package/apps/mcp/src/mcp-tools/interaction.ts +155 -0
- package/apps/mcp/src/mcp-tools/mesh-actions.ts +224 -0
- package/apps/mcp/src/mcp-tools/mesh-relay.ts +66 -0
- package/apps/mcp/src/mcp-tools/mesh-resource.ts +31 -0
- package/apps/mcp/src/mcp-tools/mesh-tools.ts +103 -0
- package/apps/mcp/src/mcp-tools/relay.ts +161 -0
- package/apps/mcp/src/mesh-server.ts +13 -0
- package/apps/mcp/src/mesh-stdio.ts +5 -0
- package/apps/mcp/src/oauth/README.md +3 -0
- package/apps/mcp/src/oauth/consent-page.ts +61 -0
- package/apps/mcp/src/oauth/store.ts +66 -0
- package/apps/mcp/src/oauth-provider.ts +9 -242
- package/apps/mcp/src/provider-status.ts +22 -69
- package/apps/mcp/src/server.ts +1 -1
- package/bin/granttap-mcp.mjs +32 -24
- package/cursor-plugin/README.md +4 -4
- package/cursor-plugin/commands/connect.md +1 -1
- package/cursor-plugin/skills/connect/SKILL.md +4 -4
- package/docs/cursor-authorize.md +16 -59
- package/docs/images/apple-watch-approval.png +0 -0
- package/docs/images/apple-watch-inbox.png +0 -0
- package/docs/images/apple-watch-task.png +0 -0
- package/docs/images/iphone-chat.png +0 -0
- package/docs/images/iphone-claude-tasks.png +0 -0
- package/docs/images/iphone-command-center.png +0 -0
- package/docs/images/iphone-mcp-usage.png +0 -0
- package/docs/images/iphone-photo-preview.png +0 -0
- package/docs/images/iphone-task-detail.png +0 -0
- package/package.json +12 -6
- package/packages/core/relay-client-types.ts +38 -0
- package/packages/core/relay-client.ts +10 -46
- package/packages/core/relay-envelope.ts +37 -0
- package/packages/protocol/messages/README.md +13 -0
- package/packages/protocol/messages/approvals.ts +87 -0
- package/packages/protocol/messages/capabilities.ts +104 -0
- package/packages/protocol/messages/interaction.ts +69 -0
- package/packages/protocol/messages/mesh-endpoint.ts +68 -0
- package/packages/protocol/messages/mesh.ts +247 -0
- package/packages/protocol/messages/primitives.ts +27 -0
- package/packages/protocol/messages/sessions.ts +196 -0
- package/packages/protocol/schema.ts +76 -615
- package/apps/bridge/src/bin/web.ts +0 -33
- package/apps/bridge/src/cloud-approvals.ts +0 -324
- package/apps/bridge/src/scheduler.ts +0 -298
- package/apps/bridge/src/sessions/copilot.ts +0 -411
- package/docs/images/phone-activity.png +0 -0
- package/docs/images/watch-approval.png +0 -0
package/README.md
CHANGED
|
@@ -2,303 +2,198 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/granttap-mcp)
|
|
4
4
|
[](https://github.com/sergii-ziborov/granttap-mcp/actions/workflows/ci.yml)
|
|
5
|
-
[](package.json)
|
|
6
5
|
[](LICENSE)
|
|
7
6
|
|
|
8
|
-
|
|
7
|
+
GrantTap is a Personal live control center for local coding agents.
|
|
9
8
|
|
|
10
|
-
|
|
11
|
-
run local schedules without exposing agent traffic to the relay. GrantTap MCP is
|
|
12
|
-
the open-source machine-side bridge: the agents stay on your Mac, and Cloudflare
|
|
13
|
-
only routes authenticated ciphertext it cannot decrypt.
|
|
9
|
+
> See what your coding agents are doing. Step in when they need you.
|
|
14
10
|
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
This repository is the canonical machine runtime: CLI, MCP server, provider
|
|
12
|
+
hooks, local adapters, and TypeScript wire schemas. Agents and provider
|
|
13
|
+
credentials stay on your computer. Native iPhone and Apple Watch traffic is
|
|
14
|
+
end-to-end encrypted.
|
|
15
|
+
|
|
16
|
+
[Website](https://granttap.com) · [npm](https://www.npmjs.com/package/granttap-mcp) ·
|
|
17
17
|
[Security model](SECURITY.md) ·
|
|
18
|
-
[
|
|
18
|
+
[Relay source](https://github.com/sergii-ziborov/granttap-relay)
|
|
19
|
+
|
|
20
|
+
## iPhone and Apple Watch
|
|
19
21
|
|
|
20
22
|
<p align="center">
|
|
21
|
-
<img src="
|
|
22
|
-
|
|
23
|
-
<img src="
|
|
23
|
+
<img src="docs/images/iphone-command-center.png" width="230" alt="GrantTap Now with Needs You and at-risk tasks">
|
|
24
|
+
<img src="docs/images/iphone-chat.png" width="230" alt="GrantTap live task timeline and composer">
|
|
25
|
+
<img src="docs/images/iphone-mcp-usage.png" width="230" alt="GrantTap actionable usage overview">
|
|
24
26
|
</p>
|
|
25
27
|
|
|
26
|
-
<p align="center"
|
|
28
|
+
<p align="center">
|
|
29
|
+
<img src="docs/images/apple-watch-inbox.png" width="180" alt="GrantTap Needs You on Apple Watch">
|
|
30
|
+
<img src="docs/images/apple-watch-approval.png" width="180" alt="GrantTap approval on Apple Watch">
|
|
31
|
+
</p>
|
|
27
32
|
|
|
28
|
-
|
|
29
|
-
status is published at [granttap.com](https://granttap.com).
|
|
33
|
+
## Supported providers
|
|
30
34
|
|
|
31
|
-
|
|
35
|
+
- Primary: Claude Code and Codex.
|
|
36
|
+
- Beta: Cursor.
|
|
37
|
+
- Experimental where available: Grok Build.
|
|
32
38
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
- **One task view for both agents.** See recent Codex and Claude Code tasks,
|
|
36
|
-
human-readable activity, delivery state, usage, and context data the agent
|
|
37
|
-
actually exposes.
|
|
38
|
-
- **Continue work from the phone.** Reply to an existing task or create a new
|
|
39
|
-
one for the selected agent and advertised workspace. Send up to five photos,
|
|
40
|
-
camera images, or documents in one message.
|
|
41
|
-
- **A useful Watch app, not an approval-only notification.** Browse tasks, open
|
|
42
|
-
recent activity, approve a command, or reply by voice or text.
|
|
43
|
-
- **Per-task controls that are enforced locally.** Inspect MCP servers and
|
|
44
|
-
repository skills, disable MCP servers for later GrantTap-delivered turns,
|
|
45
|
-
choose a relevant MCP or skill, and select Codex sandbox access.
|
|
46
|
-
- **A local scheduler, not a pretend provider API.** Create recurring Codex or
|
|
47
|
-
Claude Code runs manually or through a conversational planner, then inspect
|
|
48
|
-
the run history from the phone.
|
|
49
|
-
- **Receipts instead of optimistic UI.** Messages have stable IDs, encrypted
|
|
50
|
-
accepted/rejected receipts, bounded retries, and queued/sending/delivered/
|
|
51
|
-
failed state.
|
|
39
|
+
GrantTap reports the depth each provider actually exposes. Visibility does not
|
|
40
|
+
imply deterministic remote blocking or full mobile continuation.
|
|
52
41
|
|
|
53
|
-
##
|
|
42
|
+
## Project Mesh and task handoff
|
|
54
43
|
|
|
55
|
-
|
|
44
|
+
Project Mesh adds stable Project and Task identity above provider-native
|
|
45
|
+
sessions. A Task can retain its `taskId` across multiple executions, agents,
|
|
46
|
+
and computers while each native session remains intact.
|
|
56
47
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
48
|
+
Agents can read the compact `granttap://mesh/current` MCP resource and publish
|
|
49
|
+
bounded progress, dependency, question, answer, claim, conflict, and completion
|
|
50
|
+
events through the existing `notify` tool. Full transcripts and hidden
|
|
51
|
+
reasoning are never mesh payloads. Claims have TTLs; a colliding claim is
|
|
52
|
+
rejected before it is recorded so agents can choose different work or contact
|
|
53
|
+
the owner before escalating to Needs You.
|
|
60
54
|
|
|
61
|
-
The
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
55
|
+
The first executable handoff path is Claude Code ↔ Codex across linked
|
|
56
|
+
computers. GrantTap builds a bounded Task Capsule from explicit task/git facts,
|
|
57
|
+
requires local phone authorization, creates a separate target branch/worktree,
|
|
58
|
+
starts the target execution, and returns a receipt bound to the exact capsule.
|
|
59
|
+
Cursor and Grok Build use the same provider-neutral schema and discovery model;
|
|
60
|
+
unsupported remote-start paths fail closed instead of claiming parity.
|
|
66
61
|
|
|
67
|
-
###
|
|
62
|
+
### Grok Bot as a scoped Mesh participant
|
|
68
63
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
64
|
+
Grok Bot is a persistent agent, not a coding-agent integration. The iPhone
|
|
65
|
+
issues a one-time encrypted Mesh Invite scoped to the Projects you select, and
|
|
66
|
+
the invite is redeemed on the trusted CLI:
|
|
72
67
|
|
|
73
|
-
|
|
68
|
+
```bash
|
|
69
|
+
granttap mesh connect <one-time-invite>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Grok Bot then runs `granttap internal mesh-mcp`, a separate scoped MCP server
|
|
73
|
+
that exposes only the twelve task-scoped Mesh operations. It cannot create
|
|
74
|
+
invites, change the relay, expand Project scope, or reach `setup`; revoking the
|
|
75
|
+
endpoint from the iPhone stops new Mesh operations immediately while local Task
|
|
76
|
+
history stays on the device.
|
|
74
77
|
|
|
75
|
-
|
|
78
|
+
## Install
|
|
76
79
|
|
|
77
80
|
```bash
|
|
78
|
-
npm install
|
|
79
|
-
|
|
80
|
-
codex mcp add granttap -- granttap
|
|
81
|
-
claude mcp add granttap -- granttap
|
|
81
|
+
npm install -g granttap-mcp
|
|
82
|
+
granttap setup
|
|
82
83
|
```
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
`granttap setup` detects supported local agents, installs or repairs their
|
|
86
|
+
hooks, installs the background helper, configures Cursor's persistent local
|
|
87
|
+
OAuth service when Cursor is present, and starts phone pairing when run in an
|
|
88
|
+
interactive terminal. It ends with one exact next action.
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
2. returns a scannable one-time QR directly in the agent chat.
|
|
90
|
+
The normal CLI surface is intentionally small:
|
|
91
91
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
92
|
+
```text
|
|
93
|
+
granttap setup
|
|
94
|
+
granttap status [--json]
|
|
95
|
+
granttap connect [--relay <wss-url>]
|
|
96
|
+
granttap reset [--yes]
|
|
97
|
+
granttap mesh connect <one-time-invite>
|
|
98
|
+
```
|
|
95
99
|
|
|
96
|
-
|
|
97
|
-
|
|
100
|
+
`connect` reuses a valid pairing. If none exists, it creates a one-time QR.
|
|
101
|
+
Custom relays are CLI-only and explicit. `reset` moves active pairing files to
|
|
102
|
+
recoverable local backups before a new pairing can be created.
|
|
98
103
|
|
|
99
|
-
|
|
104
|
+
Cursor setup is automatic in the normal flow. The advanced repair command is:
|
|
100
105
|
|
|
101
106
|
```bash
|
|
102
|
-
|
|
103
|
-
granttap connect
|
|
104
|
-
granttap setup
|
|
105
|
-
granttap status
|
|
107
|
+
granttap cursor repair
|
|
106
108
|
```
|
|
107
109
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
Existing beta state under `~/.nodvox/` is migrated automatically.
|
|
110
|
+
After Codex hooks are installed, open `/hooks`, review and trust both exact
|
|
111
|
+
GrantTap hooks, then restart Codex. GrantTap never treats installation as user
|
|
112
|
+
trust.
|
|
112
113
|
|
|
113
|
-
|
|
114
|
-
then restart Codex. Installation alone is not reported as trusted or connected.
|
|
114
|
+
## MCP contract
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
`tools/list` returns exactly four public tools:
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
118
|
+
| Tool | Contract |
|
|
119
|
+
| --- | --- |
|
|
120
|
+
| `connect` | Reuse the existing production pairing or return a one-time QR |
|
|
121
|
+
| `notify` | Send a non-blocking status update of at most 2,000 characters |
|
|
122
|
+
| `ask_yes_no` | Ask a yes/no question and wait for the explicit answer |
|
|
123
|
+
| `ask` | Ask an open question and wait for typed or spoken text |
|
|
122
124
|
|
|
123
|
-
|
|
125
|
+
MCP `connect` accepts no custom routing, replacement, or key-rotation input.
|
|
126
|
+
Setup is CLI-only because it changes provider configuration and must not be
|
|
127
|
+
available to a model through prompt injection.
|
|
124
128
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
granttap authorize
|
|
128
|
-
```
|
|
129
|
+
`notify` may alternatively carry one bounded task-scoped Mesh event. This does
|
|
130
|
+
not add a fifth MCP tool or grant any global setup capability.
|
|
129
131
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
**Cursor Settings → MCP → GrantTap → Authorize**. The local consent page shows
|
|
134
|
-
the pairing QR plus a manual-token fallback when the Mac is not paired yet.
|
|
135
|
-
`granttap authorize` installs a loopback-only per-user LaunchAgent, verifies its
|
|
136
|
-
exact `/healthz` identity, writes Cursor config only after that check succeeds,
|
|
137
|
-
and exits. The service uses RunAtLoad + KeepAlive, so closing the terminal or
|
|
138
|
-
restarting the Mac does not leave Cursor pointing at a dead URL.
|
|
132
|
+
Provider-native approvals and mobile continuation require the matching local
|
|
133
|
+
adapter. MCP registration alone is never reported as proof that an integration
|
|
134
|
+
is ready.
|
|
139
135
|
|
|
140
|
-
|
|
136
|
+
## What the runtime publishes
|
|
141
137
|
|
|
142
|
-
|
|
138
|
+
The bounded encrypted protocol preserves:
|
|
143
139
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
140
|
+
- provider, task, computer, model, workspace, branch, state, and summary;
|
|
141
|
+
- visible activity, delivery state, context and token counters;
|
|
142
|
+
- MCP, Skill, and CLI observations;
|
|
143
|
+
- child-agent relationships;
|
|
144
|
+
- per-capability outcome: `success`, `error`, `cancelled`, or `unknown`.
|
|
148
145
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
```json
|
|
153
|
-
{
|
|
154
|
-
"mcpServers": {
|
|
155
|
-
"granttap": {
|
|
156
|
-
"url": "http://127.0.0.1:17342/mcp"
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
```
|
|
146
|
+
An optional bounded `errorClass` may describe an error category. Full tool
|
|
147
|
+
error payloads are not copied into usage telemetry by default.
|
|
161
148
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
`granttap setup` is the policy-hook entry point: it installs Cursor
|
|
173
|
-
`beforeShellExecution`, `afterShellExecution`, and `beforeMCPExecution` hooks,
|
|
174
|
-
plus Claude/Codex hooks and background task sync. It does not opt a new user
|
|
175
|
-
into OAuth; when an exact Cursor HTTP entry already exists, it also repairs the
|
|
176
|
-
persistent OAuth service. Per-chat blocks are checked before phone routing,
|
|
177
|
-
and ambiguous/unscoped Cursor calls fall back to Cursor's native permission UI.
|
|
178
|
-
|
|
179
|
-
## Codex and Claude Code: honest capability matrix
|
|
180
|
-
|
|
181
|
-
| Capability | Codex | Claude Code |
|
|
182
|
-
| --- | --- | --- |
|
|
183
|
-
| Approval hook | `PermissionRequest` when Codex hooks are enabled | `PreToolUse` |
|
|
184
|
-
| Resume an existing task | Yes, through the local Codex CLI | Yes, through the local Claude CLI |
|
|
185
|
-
| Start a new persistent task | Yes | Yes |
|
|
186
|
-
| Up to five attachments within one encrypted-frame budget | Images through Codex image inputs; documents as local paths | Local image/document paths in the turn |
|
|
187
|
-
| Change filesystem access from iPhone | Read-only, workspace, or full for the next GrantTap turn | Not exposed; the existing Claude policy remains authoritative |
|
|
188
|
-
| Disable MCP per task | Enforced for later GrantTap-delivered turns | Enforced for later GrantTap-delivered turns |
|
|
189
|
-
| Usage and context | Reported when present in local task logs | Reported when present in local task logs |
|
|
190
|
-
| Trigger real context compaction | Yes, for an idle task through Codex app-server | No supported remote API; GrantTap reports this honestly |
|
|
191
|
-
| Conversational schedule planner | Ephemeral read-only run | Ephemeral plan-mode run |
|
|
192
|
-
|
|
193
|
-
GrantTap controls local Codex and Claude Code tasks. It does **not** claim to
|
|
194
|
-
create ordinary ChatGPT chats, private ChatGPT Scheduled Tasks, Codex
|
|
195
|
-
Automations, or Claude Routines through unpublished provider APIs.
|
|
196
|
-
|
|
197
|
-
Globally disabled MCP servers stay disabled. A phone choice only narrows later
|
|
198
|
-
turns sent through GrantTap; it cannot broaden the agent's global configuration.
|
|
199
|
-
Repository skills are discovered only in the selected task workspace under
|
|
200
|
-
`.agents/skills` or `.claude/skills`.
|
|
201
|
-
|
|
202
|
-
## MCP tools
|
|
203
|
-
|
|
204
|
-
| Tool | Result |
|
|
205
|
-
| --- | --- |
|
|
206
|
-
| `connect` | Creates a pairing and returns a secure one-time QR in chat |
|
|
207
|
-
| `ask` | Sends an open question and waits for a spoken or typed reply |
|
|
208
|
-
| `ask_yes_no` | Sends a yes/no question and waits for a tap |
|
|
209
|
-
| `notify` | Sends a non-blocking status update |
|
|
210
|
-
| `setup` | Registers Cursor/Claude/Codex policy hooks and the terminal-free helper |
|
|
211
|
-
|
|
212
|
-
The default answer timeout is three minutes. Override it with
|
|
213
|
-
`GRANTTAP_ASK_TIMEOUT_MS`.
|
|
214
|
-
|
|
215
|
-
## Why the relay cannot read a session
|
|
216
|
-
|
|
217
|
-
- Endpoint keys are generated locally. The relay never receives a device's
|
|
218
|
-
secret encryption key.
|
|
219
|
-
- Pairing hand-off uses an opaque mailbox ID plus an independent 256-bit
|
|
220
|
-
transfer key. Only the mailbox ID reaches Cloudflare; the key stays in the QR
|
|
221
|
-
or manual token.
|
|
222
|
-
- Every attached Codex or Claude Code task receives its own random 256-bit task
|
|
223
|
-
key. Disclosure of one task key cannot decrypt another task.
|
|
224
|
-
- Questions, commands, replies, attachments, approvals, scheduler drafts, and
|
|
225
|
-
task activity remain authenticated ciphertext across the network, relay,
|
|
226
|
-
Durable Objects, and APNs path.
|
|
227
|
-
- APNs carries only a content-neutral wake. It contains no title, prompt,
|
|
228
|
-
command, path, task kind, or response.
|
|
229
|
-
- Cloudflare accepts at most a 32 MiB WebSocket frame. Because task messages are
|
|
230
|
-
sealed and base64-encoded twice, attachments share a 16,000,000-character
|
|
231
|
-
base64 budget (about 12 MB raw total); five small files fit, five 6 MB files do not.
|
|
232
|
-
|
|
233
|
-
The in-chat QR is marked user-only for MCP hosts, but that annotation is not a
|
|
234
|
-
cryptographic separation from the model provider. Use CLI `connect` when the
|
|
235
|
-
model provider itself is part of your threat model; Cloudflare still receives
|
|
236
|
-
only the mailbox id and ciphertext in either flow.
|
|
237
|
-
|
|
238
|
-
The relay can still observe operational metadata: opaque room/mailbox IDs, IP
|
|
239
|
-
addresses, timing, ciphertext sizes, and APNs device token/environment. A
|
|
240
|
-
compromised authorized endpoint can read the tasks explicitly granted to that
|
|
241
|
-
endpoint; cryptography cannot hide plaintext from a device authorized to show
|
|
242
|
-
it. The exact boundary and threat-model limits are documented in
|
|
243
|
-
[SECURITY.md](SECURITY.md).
|
|
244
|
-
|
|
245
|
-
## Task sync and scheduling
|
|
246
|
-
|
|
247
|
-
The background helper publishes a bounded window of recent local Codex and
|
|
248
|
-
Claude Code task metadata. Older chat metadata is available separately for up
|
|
249
|
-
to 90 days and 160 chats; full activity for a task is sent only after the phone
|
|
250
|
-
subscribes to it. Hidden reasoning is never converted into visible activity.
|
|
251
|
-
|
|
252
|
-
New phone-created tasks default to an isolated per-agent GrantTap workspace.
|
|
253
|
-
The phone can instead select a same-agent folder already advertised by a recent
|
|
254
|
-
local task. The helper rejects arbitrary unadvertised paths.
|
|
255
|
-
|
|
256
|
-
Schedules use standard five-field cron in the Mac's timezone. The app supports
|
|
257
|
-
hourly, daily, weekday, selected-weekday, and monthly series, plus enable,
|
|
258
|
-
disable, edit, delete, and run-now actions. Every run records local start/end
|
|
259
|
-
time, agent, status, result, and created task ID.
|
|
260
|
-
|
|
261
|
-
## CLI commands
|
|
262
|
-
|
|
263
|
-
| Command | Purpose |
|
|
149
|
+
## Local enforcement
|
|
150
|
+
|
|
151
|
+
GrantTap can narrow later actions for an exact task only where a provider
|
|
152
|
+
offers a deterministic local hook. Global provider configuration always wins.
|
|
153
|
+
Read-only integrations stay read-only in the app instead of presenting a fake
|
|
154
|
+
toggle.
|
|
155
|
+
|
|
156
|
+
The user-facing approval modes map to the existing runtime policy:
|
|
157
|
+
|
|
158
|
+
| Personal UI | Runtime |
|
|
264
159
|
| --- | --- |
|
|
265
|
-
|
|
|
266
|
-
|
|
|
267
|
-
|
|
|
268
|
-
| `connect [relayUrl]` | Creates an E2EE pairing; optionally targets a self-hosted `wss://` relay |
|
|
269
|
-
| `setup` | Registers Cursor/Claude/Codex hooks, background sync, and repairs configured OAuth |
|
|
270
|
-
| `status [--json]` | Reads local readiness; JSON uses `granttap.provider-status.v1` and contains no keys |
|
|
271
|
-
|
|
272
|
-
The installed public command is `granttap`; `granttap-mcp` remains an alias for
|
|
273
|
-
existing scripts. `status` only reads configuration and runtime state—it does
|
|
274
|
-
not install hooks, pair a device, start OAuth, or reload the background helper.
|
|
275
|
-
If Cursor has an HTTP GrantTap entry, status requires both an owned persistent
|
|
276
|
-
service and a live identity-checked health response; a dead URL is never shown
|
|
277
|
-
as connected. Without an HTTP entry, OAuth remains optional and Cursor policy
|
|
278
|
-
readiness is based on the full hook set, pairing, and background sync.
|
|
160
|
+
| Ask for risky actions | `except_push` |
|
|
161
|
+
| Ask for every action | `ask` |
|
|
162
|
+
| Use agent defaults | no GrantTap gate for that task |
|
|
279
163
|
|
|
280
|
-
|
|
164
|
+
Legacy custom levels remain compatible but are not part of the primary flow.
|
|
165
|
+
|
|
166
|
+
## Relay boundary
|
|
167
|
+
|
|
168
|
+
Pairing and task keys are generated locally. The relay receives opaque routing
|
|
169
|
+
metadata and ciphertext, not provider credentials or task plaintext. Pairing
|
|
170
|
+
handoff uses a relay-visible random mailbox ID plus an independent transfer key
|
|
171
|
+
that stays in the QR.
|
|
172
|
+
|
|
173
|
+
APNs carries a content-neutral wake only. It contains no prompt, task title,
|
|
174
|
+
command, path, request ID, or ciphertext. See [SECURITY.md](SECURITY.md) for the
|
|
175
|
+
complete boundary and reporting instructions.
|
|
281
176
|
|
|
282
|
-
|
|
177
|
+
## Development
|
|
283
178
|
|
|
284
179
|
```bash
|
|
285
|
-
git clone https://github.com/sergii-ziborov/granttap-mcp.git
|
|
286
|
-
cd granttap-mcp
|
|
287
180
|
npm install
|
|
288
|
-
npm test
|
|
289
181
|
npm run typecheck
|
|
182
|
+
npm test
|
|
183
|
+
npm run package:allowlist
|
|
184
|
+
npm run test:coverage # macOS only — see below
|
|
290
185
|
```
|
|
291
186
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
187
|
+
`npm test` runs everywhere. Both suites run with an isolated `HOME`, so a
|
|
188
|
+
developer's own Claude/Codex/Cursor data can never inflate a local result: the
|
|
189
|
+
numbers on this machine and in CI are the same. The coverage contract is
|
|
190
|
+
measured on macOS because the background helper, the Cursor OAuth service, and
|
|
191
|
+
the installer only execute there, so a Linux percentage understates real
|
|
192
|
+
runtime coverage. CI runs the cross-platform suite on Linux and the coverage
|
|
193
|
+
gate on macOS, and `npm publish` enforces the same gate through
|
|
194
|
+
`prepublishOnly`.
|
|
296
195
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
- [Public relay source](https://github.com/sergii-ziborov/granttap-relay)
|
|
300
|
-
- [Privacy](https://granttap.com/privacy)
|
|
301
|
-
- [Support](https://granttap.com/support)
|
|
302
|
-
- [Security policy](SECURITY.md)
|
|
196
|
+
Do not publish from a dirty checkout or before the package allowlist, tests,
|
|
197
|
+
typecheck, and release checks pass.
|
|
303
198
|
|
|
304
|
-
GrantTap is not affiliated with Anthropic or
|
|
199
|
+
GrantTap is not affiliated with Anthropic, OpenAI, Apple, Anysphere, or xAI.
|
package/SECURITY.md
CHANGED
|
@@ -6,82 +6,76 @@ Use GitHub's private
|
|
|
6
6
|
[security advisory form](https://github.com/sergii-ziborov/granttap-mcp/security/advisories/new).
|
|
7
7
|
For urgent coordination, contact `sergii.ziborov@gmail.com`.
|
|
8
8
|
|
|
9
|
-
Do not open a public issue containing pairing tokens, device keys, room
|
|
10
|
-
|
|
11
|
-
exploit.
|
|
12
|
-
a minimal reproduction using synthetic data.
|
|
9
|
+
Do not open a public issue containing pairing tokens, device keys, room IDs,
|
|
10
|
+
real prompts, command payloads, APNs tokens, local configuration, or a working
|
|
11
|
+
exploit. Use synthetic data and include the affected package version or commit.
|
|
13
12
|
|
|
14
13
|
## Local secrets
|
|
15
14
|
|
|
16
|
-
Pairing state belongs in `~/.granttap
|
|
17
|
-
to an issue, or
|
|
18
|
-
keys
|
|
15
|
+
Pairing state belongs in `~/.granttap/`. It must never be committed, attached
|
|
16
|
+
to an issue, or printed in logs. The active secret classes are endpoint NaCl
|
|
17
|
+
keys, per-task keys, the one-time pairing transfer key, and the random room
|
|
18
|
+
credential used for authenticated WebSocket and APNs registration.
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
the room WebSocket and APNs device-token registration at the relay. None may be logged.
|
|
23
|
-
The relay receives only a hash of `pushAuth` and never receives an endpoint's
|
|
24
|
-
secret encryption key.
|
|
20
|
+
Provider credentials remain in each provider's own local authentication flow.
|
|
21
|
+
GrantTap does not send them to the relay.
|
|
25
22
|
|
|
26
23
|
## Cryptographic boundary
|
|
27
24
|
|
|
28
|
-
- Every
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
metadata and visible activity, and places it inside the existing device or
|
|
83
|
-
independent per-task NaCl box. Structured MCP/skill fields describe observed
|
|
84
|
-
tool calls; hidden reasoning is never turned into activity or usage records.
|
|
25
|
+
- Every computer pairing is generated locally with unique Curve25519 keys.
|
|
26
|
+
- Pairing handoff uses an opaque 128-bit mailbox ID and an independent 256-bit
|
|
27
|
+
transfer key. The relay receives the mailbox ID and ciphertext, not the key.
|
|
28
|
+
- Each attached task has an independent 256-bit task key. One task key cannot
|
|
29
|
+
decrypt another task.
|
|
30
|
+
- Project Mesh snapshots have independent project keys. Cross-computer events
|
|
31
|
+
remain under their Task key, and a linked destination receives either key
|
|
32
|
+
only through an explicit phone-mediated route.
|
|
33
|
+
- Task keys travel only inside the authenticated device channel and are stored
|
|
34
|
+
in device-protected storage.
|
|
35
|
+
- Native phone/watch payloads remain authenticated ciphertext across the
|
|
36
|
+
network, Cloudflare, Durable Objects, and the offline queue.
|
|
37
|
+
- APNs is a neutral wake. It contains no prompt, task title, command, path,
|
|
38
|
+
task/request/delivery ID, or task ciphertext.
|
|
39
|
+
- MCP audience annotations are not a cryptographic model-provider boundary.
|
|
40
|
+
Use CLI `granttap connect` when the model provider itself is in the threat
|
|
41
|
+
model.
|
|
42
|
+
|
|
43
|
+
Cloudflare can observe operational metadata required to run the relay: opaque
|
|
44
|
+
room/mailbox IDs, routing role, IP address, timing, expiry, ciphertext size, and
|
|
45
|
+
APNs token/environment. It cannot decrypt task content from those fields.
|
|
46
|
+
|
|
47
|
+
The honest endpoint limit remains: a compromised device can read the tasks
|
|
48
|
+
whose independent keys were granted to it. The protection is against relay,
|
|
49
|
+
database/network compromise, other pairings, and disclosure of a different
|
|
50
|
+
task key—not against an endpoint already authorized for that task.
|
|
51
|
+
|
|
52
|
+
Task Capsules are strict, bounded schemas containing goal, explicit status,
|
|
53
|
+
repository/commit facts, changed-file names, tests, dependencies, claims,
|
|
54
|
+
remaining work, and explicit decisions. Unknown fields are rejected; hidden
|
|
55
|
+
reasoning and transcript replication are outside the contract. Handoff
|
|
56
|
+
acceptance includes a SHA-256 receipt over a canonical capsule and the source,
|
|
57
|
+
target, Task identity, and acceptance time. Stale claims expire, replayed event
|
|
58
|
+
IDs are ignored, and destination routing is explicit.
|
|
59
|
+
|
|
60
|
+
## Runtime controls
|
|
61
|
+
|
|
62
|
+
Provider hooks enforce policy on the computer. Global provider deny always
|
|
63
|
+
wins. If a provider cannot deterministically block a capability, GrantTap must
|
|
64
|
+
report the observation as read-only instead of implying enforcement.
|
|
65
|
+
|
|
66
|
+
`setup` is CLI-only because it writes local provider configuration and installs
|
|
67
|
+
background services. The public MCP server can only connect an existing or new
|
|
68
|
+
phone pairing, notify, and ask bounded questions; it cannot reconfigure the
|
|
69
|
+
machine or select a custom relay.
|
|
70
|
+
|
|
71
|
+
A Grok Bot endpoint is a separate scoped identity. Its one-time invite is
|
|
72
|
+
created only on the iPhone, stored on the relay as ciphertext, redeemed only by
|
|
73
|
+
the trusted `granttap mesh connect` CLI, and written to disk with `0600`
|
|
74
|
+
permissions. Its MCP server exposes only task-scoped Mesh operations bound to
|
|
75
|
+
one credential: every call re-checks endpoint, credential, policy revision,
|
|
76
|
+
expiry, actor, Project scope, and operation, and a revoked or disabled endpoint
|
|
77
|
+
fails closed. Invite creation, actor enablement, Project scope, and revocation
|
|
78
|
+
stay in the iPhone UI and the trusted CLI, never in a model-callable tool.
|
|
85
79
|
|
|
86
80
|
Relay vulnerabilities should be reported through the
|
|
87
81
|
[GrantTap relay advisory form](https://github.com/sergii-ziborov/granttap-relay/security/advisories/new).
|