@skyelight/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/README.md +3 -3
- package/package.json +1 -1
- package/src/install.js +44 -7
- package/src/tools.js +12 -0
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ An MCP server that lets a coding agent read the feedback people left on your
|
|
|
4
4
|
running app — the thread, the page, and the element they were pointing at —
|
|
5
5
|
and report back on it when the work is done.
|
|
6
6
|
|
|
7
|
-
Works with anything that speaks MCP over stdio: Claude Code, Cursor, Codex.
|
|
7
|
+
Works with anything that speaks MCP over stdio: Claude Code, Cursor, Grok, Codex.
|
|
8
8
|
|
|
9
9
|
## Setup
|
|
10
10
|
|
|
@@ -22,8 +22,8 @@ Finds your coding agent, registers the remote server with it, and leaves the
|
|
|
22
22
|
sign-in to OAuth — nothing is pasted and no key is stored on disk. It shows
|
|
23
23
|
what it will change and waits; `--yes` skips that once you have read it.
|
|
24
24
|
|
|
25
|
-
It knows Claude Code, Cursor,
|
|
26
|
-
cursor` when more than one is installed, and point at another deployment with
|
|
25
|
+
It knows Claude Code, Cursor, Grok, Codex and Windsurf. Name one with
|
|
26
|
+
`--client cursor` when more than one is installed, and point at another deployment with
|
|
27
27
|
`SKYELIGHT_URL=https://…`. The deployment tells the installer its own MCP URL
|
|
28
28
|
and OAuth client over `/mcp/install-config`, so this package holds no
|
|
29
29
|
environment-specific constants.
|
package/package.json
CHANGED
package/src/install.js
CHANGED
|
@@ -30,7 +30,8 @@ const home = () => homedir();
|
|
|
30
30
|
*
|
|
31
31
|
* Ordered by how likely a given machine is to have one, because the first
|
|
32
32
|
* match wins when nothing is named. That is a guess, and `--client` exists
|
|
33
|
-
* for when it guesses wrong.
|
|
33
|
+
* for when it guesses wrong. The same order the settings card lists them in,
|
|
34
|
+
* so the two never disagree about which agent is the obvious one.
|
|
34
35
|
*/
|
|
35
36
|
export const CLIENTS = [
|
|
36
37
|
{
|
|
@@ -67,12 +68,40 @@ export const CLIENTS = [
|
|
|
67
68
|
detect: () => existsSync(join(home(), ".cursor")),
|
|
68
69
|
},
|
|
69
70
|
{
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Grok's own entry, which it needs despite appearing to work without one.
|
|
73
|
+
*
|
|
74
|
+
* It reads `~/.claude.json` as a compatibility source, so on a machine
|
|
75
|
+
* that also has Claude Code it inherits that registration — client id,
|
|
76
|
+
* callback port and all — and looks configured when nothing here ran.
|
|
77
|
+
* On a machine without Claude Code there is nothing to inherit.
|
|
78
|
+
*
|
|
79
|
+
* Two differences from Codex, both from Grok's own config reference:
|
|
80
|
+
* `oauth_client_id` is a flat key rather than a nested table, and there
|
|
81
|
+
* is no callback setting at all — Grok picks the loopback address, which
|
|
82
|
+
* is why both spellings of it are registered with Clerk.
|
|
83
|
+
*
|
|
84
|
+
* `oauth_scopes` is spelled out because Grok sends no `scope` parameter
|
|
85
|
+
* otherwise, and a token minted without `offline_access` carries no
|
|
86
|
+
* refresh: the session works, then quietly stops.
|
|
87
|
+
*/
|
|
88
|
+
id: "grok",
|
|
89
|
+
label: "Grok",
|
|
90
|
+
file: () => join(home(), ".grok", "config.toml"),
|
|
91
|
+
format: "toml",
|
|
92
|
+
entry: (url, clientId) =>
|
|
93
|
+
[
|
|
94
|
+
`[mcp_servers.${SERVER_NAME}]`,
|
|
95
|
+
`url = "${url}"`,
|
|
96
|
+
"enabled = true",
|
|
97
|
+
...(clientId
|
|
98
|
+
? [
|
|
99
|
+
`oauth_client_id = "${clientId}"`,
|
|
100
|
+
'oauth_scopes = ["profile", "email", "offline_access"]',
|
|
101
|
+
]
|
|
102
|
+
: []),
|
|
103
|
+
].join("\n"),
|
|
104
|
+
detect: () => existsSync(join(home(), ".grok")),
|
|
76
105
|
},
|
|
77
106
|
{
|
|
78
107
|
id: "codex",
|
|
@@ -96,6 +125,14 @@ export const CLIENTS = [
|
|
|
96
125
|
].join("\n"),
|
|
97
126
|
detect: () => existsSync(join(home(), ".codex")),
|
|
98
127
|
},
|
|
128
|
+
{
|
|
129
|
+
id: "windsurf",
|
|
130
|
+
label: "Windsurf",
|
|
131
|
+
file: () => join(home(), ".codeium", "windsurf", "mcp_config.json"),
|
|
132
|
+
format: "json",
|
|
133
|
+
entry: (url) => ({ serverUrl: url }),
|
|
134
|
+
detect: () => existsSync(join(home(), ".codeium", "windsurf")),
|
|
135
|
+
},
|
|
99
136
|
];
|
|
100
137
|
|
|
101
138
|
/** On PATH, without running the thing. */
|
package/src/tools.js
CHANGED
|
@@ -393,6 +393,18 @@ export function renderItem(item) {
|
|
|
393
393
|
if (item.anchor.selectedText) {
|
|
394
394
|
lines.push(` with "${item.anchor.selectedText}" selected`);
|
|
395
395
|
}
|
|
396
|
+
// Which row, when the element is one of many the same component rendered.
|
|
397
|
+
// The author's own React key, so it reads as something from their codebase
|
|
398
|
+
// — "the row with key plan:pro" locates a record, which is a different and
|
|
399
|
+
// better question than where on the page it was drawn.
|
|
400
|
+
//
|
|
401
|
+
// `skyId` is deliberately not here. It is an opaque hash: it anchors the
|
|
402
|
+
// pin and tells a reader nothing they can act on, and `source` below
|
|
403
|
+
// already names the file. It stays in the structured response for anything
|
|
404
|
+
// resolving anchors, out of the prose for anything reading one.
|
|
405
|
+
if (item.anchor.skyKey) {
|
|
406
|
+
lines.push(` the item with key ${item.anchor.skyKey}`);
|
|
407
|
+
}
|
|
396
408
|
lines.push(` selector: ${item.anchor.selector}`);
|
|
397
409
|
lines.push(
|
|
398
410
|
` seen at ${item.anchor.viewport.width}x${item.anchor.viewport.height}`,
|