@simular-ai/sai-mcp 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -103
- package/dist/server.js +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,37 +1,44 @@
|
|
|
1
1
|
# @simular-ai/sai-mcp
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
client
|
|
5
|
-
computer-use agent. Sai
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
Give your coding agent a computer. This MCP server lets Claude Code, Codex,
|
|
4
|
+
Cursor or any MCP client hand tasks to [Sai](https://www.simular.ai), Simular's
|
|
5
|
+
computer-use agent. Sai does the work on a real desktop (a browser, native
|
|
6
|
+
apps, files) and reports back. Sai runs on a cloud computer we host; the free
|
|
7
|
+
plan includes one.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
(
|
|
9
|
+
You need Node.js 22.12 or newer and a Sai API key (`sapi_…`). Sign in at
|
|
10
|
+
[platform.simular.ai](https://platform.simular.ai) and create one under
|
|
11
|
+
[API Keys](https://platform.simular.ai/api-keys). It is shown once.
|
|
12
|
+
|
|
13
|
+
Docs: [docs.simular.ai/sai-api](https://docs.simular.ai/sai-api/introduction)
|
|
11
14
|
|
|
12
15
|
## Install
|
|
13
16
|
|
|
17
|
+
Replace `sapi_YOUR_KEY` with your key.
|
|
18
|
+
|
|
14
19
|
### Claude Code
|
|
15
20
|
|
|
16
21
|
```bash
|
|
17
|
-
claude mcp add sai -e SAI_API_KEY=
|
|
22
|
+
claude mcp add sai -e SAI_API_KEY=sapi_YOUR_KEY -- npx -y @simular-ai/sai-mcp
|
|
18
23
|
```
|
|
19
24
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
falling back to plain HTTP:
|
|
25
|
+
Optional: install the `sai` skill, which teaches Claude Code how to run a task
|
|
26
|
+
from start to finish, including when the MCP server isn't loaded:
|
|
23
27
|
|
|
24
28
|
```bash
|
|
25
29
|
npx -y @simular-ai/sai-mcp init-claude # ~/.claude/skills/sai
|
|
26
30
|
npx -y @simular-ai/sai-mcp init-claude --project # ./.claude/skills/sai
|
|
27
|
-
npx -y @simular-ai/sai-mcp init-claude --check # exit 1 when missing or stale
|
|
28
31
|
```
|
|
29
32
|
|
|
30
33
|
It never overwrites a `SKILL.md` you edited; `--force` does.
|
|
31
34
|
|
|
32
35
|
### Codex
|
|
33
36
|
|
|
34
|
-
|
|
37
|
+
```bash
|
|
38
|
+
codex mcp add sai --env SAI_API_KEY=sapi_YOUR_KEY -- npx -y @simular-ai/sai-mcp
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Or in `~/.codex/config.toml`:
|
|
35
42
|
|
|
36
43
|
```toml
|
|
37
44
|
[mcp_servers.sai]
|
|
@@ -39,12 +46,12 @@ command = "npx"
|
|
|
39
46
|
args = ["-y", "@simular-ai/sai-mcp"]
|
|
40
47
|
|
|
41
48
|
[mcp_servers.sai.env]
|
|
42
|
-
SAI_API_KEY = "
|
|
49
|
+
SAI_API_KEY = "sapi_YOUR_KEY"
|
|
43
50
|
```
|
|
44
51
|
|
|
45
52
|
### Cursor
|
|
46
53
|
|
|
47
|
-
|
|
54
|
+
In `~/.cursor/mcp.json` (or `.cursor/mcp.json` in a project), then restart Cursor:
|
|
48
55
|
|
|
49
56
|
```json
|
|
50
57
|
{
|
|
@@ -52,113 +59,62 @@ SAI_API_KEY = "sapi_..."
|
|
|
52
59
|
"sai": {
|
|
53
60
|
"command": "npx",
|
|
54
61
|
"args": ["-y", "@simular-ai/sai-mcp"],
|
|
55
|
-
"env": { "SAI_API_KEY": "
|
|
62
|
+
"env": { "SAI_API_KEY": "sapi_YOUR_KEY" }
|
|
56
63
|
}
|
|
57
64
|
}
|
|
58
65
|
}
|
|
59
66
|
```
|
|
60
67
|
|
|
61
|
-
The same
|
|
62
|
-
|
|
63
|
-
## Environment
|
|
64
|
-
|
|
65
|
-
| Variable | Required | Meaning |
|
|
66
|
-
| ---------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
67
|
-
| `SAI_API_KEY` | yes | A Sai API key (`sapi_…`) or a Firebase ID token. Sent as `Authorization: Bearer`. |
|
|
68
|
-
| `SAI_API_URL` | no | Cloud API base URL. Default: production (`https://simular-cloud-api-149671192594.us-central1.run.app`). |
|
|
69
|
-
| `SAI_PUSH` | no | `1` enables channel push (see below). Only with `--dangerously-load-development-channels server:sai`; otherwise results are dropped. |
|
|
70
|
-
| `SAI_EVENTS_API` | no | `1` switches to the `wait:false` + `GET /v1/agents/events` transport once cloud-api ships it. Default off: the SSE stream is collected in-process. |
|
|
71
|
-
|
|
72
|
-
## Tools
|
|
68
|
+
The same block works for any client that runs stdio MCP servers.
|
|
73
69
|
|
|
74
|
-
|
|
75
|
-
| ------------------ | --------------------------------------------------- | -------------------------------------------------------------------------------------------- |
|
|
76
|
-
| `sai_machines` | — | `{ machines: [{ machineId, name, kind?, online? }], default? }` — `default` when exactly one |
|
|
77
|
-
| `sai_task_start` | `{ task, machine_id?, file_ids?, new_session? }` | `{ session_id, machine_id, queued, push }` |
|
|
78
|
-
| `sai_task_wait` | `{ session_id, timeout_s? (90, max 110), cursor? }` | `{ status, events, text, approval?, cursor, error? }` |
|
|
79
|
-
| `sai_task_approve` | `{ approval_id, decision, selections? }` | `{ ok: true }` or `{ ok: false, reason: 'link_only', approval_url }` |
|
|
80
|
-
| `sai_task_abort` | `{ session_id }` | `{ ok, aborted, reason? }` |
|
|
81
|
-
| `sai_upload` | `{ path }` | `{ file_id, name, mime, size }` |
|
|
70
|
+
### Try it
|
|
82
71
|
|
|
83
|
-
|
|
84
|
-
requests for the rest of the task) or `deny`. `status` is `running`,
|
|
85
|
-
`needs_approval`, `idle` or `error`.
|
|
72
|
+
Ask your agent something like:
|
|
86
73
|
|
|
87
|
-
|
|
88
|
-
text.
|
|
74
|
+
> Use Sai to open Notepad on my cloud computer, type "Hello from Sai", and tell me the window title.
|
|
89
75
|
|
|
90
|
-
##
|
|
91
|
-
|
|
92
|
-
The server's `instructions` teach the model this loop; it is what you will see
|
|
93
|
-
it do:
|
|
94
|
-
|
|
95
|
-
1. `sai_machines` once — skip when the machine id is already known.
|
|
96
|
-
2. `sai_task_start { task }` → `session_id`. The task keeps running on the
|
|
97
|
-
machine.
|
|
98
|
-
3. `sai_task_wait { session_id }` and repeat while `status` is `running`,
|
|
99
|
-
passing back the `cursor` each time (each call blocks up to `timeout_s`,
|
|
100
|
-
under Claude Code's two-minute tool limit).
|
|
101
|
-
- `needs_approval`: read `approval`. If `isLinkOnly` is false, decide with
|
|
102
|
-
`sai_task_approve`. If it is true (OAuth consent, credentials, phone
|
|
103
|
-
verification) the model hands `approval.approvalUrl` to you and keeps
|
|
104
|
-
waiting.
|
|
105
|
-
- `idle`: `text` is Sai's answer.
|
|
106
|
-
- `error`: `error` says what went wrong.
|
|
107
|
-
4. `sai_task_abort` to stop a task you no longer want.
|
|
108
|
-
|
|
109
|
-
One conversation per machine persists on Sai's `api` channel across calls, so
|
|
110
|
-
follow-up tasks can refer to earlier ones. `new_session: true` starts clean.
|
|
111
|
-
|
|
112
|
-
Files: `sai_upload` a local file first, then pass its `file_id` in
|
|
113
|
-
`sai_task_start.file_ids` (uploads are remembered for the lifetime of the
|
|
114
|
-
server process).
|
|
115
|
-
|
|
116
|
-
## Channels (Claude Code, research preview)
|
|
117
|
-
|
|
118
|
-
Claude Code [channels](https://code.claude.com/docs/en/channels) let a server
|
|
119
|
-
push events into the session instead of being polled. This server always
|
|
120
|
-
declares the `claude/channel` capability; with `SAI_PUSH=1` it also acts on it:
|
|
121
|
-
`sai_task_start` returns `push: true`, the model stops calling
|
|
122
|
-
`sai_task_wait`, and the server delivers `needs_approval`, `idle` and `error`
|
|
123
|
-
as `<channel source="sai" session_id=… event=… approval_id=… approval_url=…>`
|
|
124
|
-
notifications while Claude carries on with other work.
|
|
125
|
-
|
|
126
|
-
Constraints of the preview:
|
|
76
|
+
## Tools
|
|
127
77
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
78
|
+
| Tool | What it does |
|
|
79
|
+
| ------------------ | -------------------------------------------------------------------------- |
|
|
80
|
+
| `sai_machines` | Lists your computers. Skip it when you have one. |
|
|
81
|
+
| `sai_models` | Lists the models Sai can use on your plan. |
|
|
82
|
+
| `sai_task_start` | Hands Sai a task in plain English. Returns a `session_id` right away. |
|
|
83
|
+
| `sai_task_wait` | Waits for progress: `running`, `needs_approval`, `idle` (done) or `error`. |
|
|
84
|
+
| `sai_task_approve` | Answers a permission request: `approve`, `approve_for_task` or `deny`. |
|
|
85
|
+
| `sai_task_abort` | Stops a task. |
|
|
86
|
+
| `sai_upload` | Uploads a local file so a task can use it. |
|
|
132
87
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
88
|
+
A task keeps running on the computer between calls. When Sai asks for
|
|
89
|
+
something only you can do, such as signing in to an account, your agent gives
|
|
90
|
+
you a link to finish it and keeps waiting. Sai remembers earlier tasks on the
|
|
91
|
+
same computer; `new_session: true` starts fresh.
|
|
137
92
|
|
|
138
|
-
|
|
139
|
-
|
|
93
|
+
There is no screenshot tool: Sai sees the screen itself and reports in text.
|
|
94
|
+
Watch it work live in the [Playground](https://platform.simular.ai/playground).
|
|
140
95
|
|
|
141
|
-
|
|
96
|
+
## Environment
|
|
142
97
|
|
|
143
|
-
|
|
144
|
-
|
|
98
|
+
| Variable | Required | Meaning |
|
|
99
|
+
| ------------- | -------- | -------------------------------------------------------------------- |
|
|
100
|
+
| `SAI_API_KEY` | yes | Your Sai API key (`sapi_…`). |
|
|
101
|
+
| `SAI_PUSH` | no | `1` turns on Claude Code channels (below). Leave it unset otherwise. |
|
|
145
102
|
|
|
146
|
-
##
|
|
103
|
+
## Claude Code channels (research preview)
|
|
147
104
|
|
|
148
|
-
|
|
105
|
+
With [channels](https://code.claude.com/docs/en/channels), results are pushed
|
|
106
|
+
into your Claude Code session instead of your agent polling for them, so it can
|
|
107
|
+
carry on with other work during a long task. Only Claude Code supports this;
|
|
108
|
+
Codex and Cursor poll, which works everywhere.
|
|
149
109
|
|
|
150
110
|
```bash
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
npm run build -w @simular-ai/sai-mcp # dist/server.js (esbuild bundle)
|
|
154
|
-
SAI_API_KEY=... node packages/sai-mcp/dist/server.js # run over stdio
|
|
111
|
+
claude mcp add sai -e SAI_API_KEY=sapi_YOUR_KEY -e SAI_PUSH=1 -- npx -y @simular-ai/sai-mcp
|
|
112
|
+
claude --dangerously-load-development-channels server:sai
|
|
155
113
|
```
|
|
156
114
|
|
|
157
|
-
|
|
115
|
+
Only set `SAI_PUSH=1` together with that flag. Without it, pushed results are
|
|
116
|
+
dropped and your agent is told not to poll.
|
|
158
117
|
|
|
159
|
-
##
|
|
118
|
+
## Support
|
|
160
119
|
|
|
161
|
-
|
|
162
|
-
in `package.json` and `SERVER_VERSION` in `src/server.ts`, merge, then
|
|
163
|
-
`git tag sai-mcp-vX.Y.Z && git push origin sai-mcp-vX.Y.Z`. CI publishes to npm
|
|
164
|
-
with trusted publishing (OIDC) and creates a GitHub release.
|
|
120
|
+
[support@simular.ai](mailto:support@simular.ai)
|
package/dist/server.js
CHANGED
|
@@ -27319,7 +27319,7 @@ var SaiApi = class {
|
|
|
27319
27319
|
};
|
|
27320
27320
|
|
|
27321
27321
|
// src/config.ts
|
|
27322
|
-
var DEFAULT_API_URL = "https://
|
|
27322
|
+
var DEFAULT_API_URL = "https://api.simular.ai";
|
|
27323
27323
|
var APPROVAL_URL_BASE = "https://sai.simular.ai/approval";
|
|
27324
27324
|
function flag(value) {
|
|
27325
27325
|
return value === "1" || value === "true";
|
|
@@ -27328,7 +27328,7 @@ function readConfig(env = process.env) {
|
|
|
27328
27328
|
const apiKey = env.SAI_API_KEY?.trim();
|
|
27329
27329
|
if (!apiKey) {
|
|
27330
27330
|
throw new Error(
|
|
27331
|
-
"SAI_API_KEY is not set. Create an API key at https://
|
|
27331
|
+
"SAI_API_KEY is not set. Create an API key at https://platform.simular.ai/api-keys and export it as SAI_API_KEY."
|
|
27332
27332
|
);
|
|
27333
27333
|
}
|
|
27334
27334
|
const apiUrl = (env.SAI_API_URL?.trim() || DEFAULT_API_URL).replace(/\/+$/, "");
|
|
@@ -28064,7 +28064,7 @@ function runInitClaude(options, env) {
|
|
|
28064
28064
|
|
|
28065
28065
|
// src/server.ts
|
|
28066
28066
|
var SERVER_NAME = "sai";
|
|
28067
|
-
var SERVER_VERSION = "0.1.
|
|
28067
|
+
var SERVER_VERSION = "0.1.2";
|
|
28068
28068
|
var log = (line) => {
|
|
28069
28069
|
process.stderr.write(`[sai-mcp] ${line}
|
|
28070
28070
|
`);
|