Skyelight MCP Server
by plastrlab
README.md
# @skyelight/mcp
<!-- A full URL, not a relative path, so the npm page shows it too. The
image lives in the public repo (assets/), not in the npm package. -->

[npm](https://www.npmjs.com/package/@skyelight/mcp) ·
[source](https://github.com/plastrlab/skyelight-mcp) ·
[docs](https://skyelight.ai/docs/mcp)
An MCP server that lets a coding agent read the feedback people left on your
running app — the thread, the page, and the element they were pointing at —
and report back on it when the work is done.
Full guide: [skyelight.ai/docs/mcp](https://skyelight.ai/docs/mcp). The REST
API behind the local server is documented at
[skyelight.ai/docs/api](https://skyelight.ai/docs/api).
Two ways to connect, with the same eighteen tools either way:
- **Remote, with OAuth** — the default. Your agent talks to Skyelight over
HTTP and you sign in once in the browser. Nothing is pasted and no key is
stored on disk.
- **Local, with a token** — this package runs as a stdio server on your
machine and carries a personal token. For clients or machines where the
browser sign-in is not an option.
Every plan includes every tool, Free included, for owners, admins and
collaborators. On Free, your agent gets 25 agent threads a month; Pro and
above have no limit. A reviewer reads and comments in the web app but does
not get agent tools.
## The short way
```bash
npx @skyelight/mcp init
```
Finds your coding agents, registers Skyelight's remote server with them, and
leaves the sign-in to OAuth — the first time the agent connects it opens a
browser and you approve it there. It shows what it will change and waits;
`--yes` skips that once you have read it.
It knows Claude Code, Cursor, Grok, Codex and Windsurf. With several
installed it asks which; `--client cursor` or `--client all` answers in
advance. `npx @skyelight/mcp remove` takes the entry out again. Point at
another deployment with `SKYELIGHT_URL=https://…`; the deployment tells the
installer its own MCP URL and OAuth client over `/mcp/install-config`, so this
package holds no environment-specific constants.
The same setup, with a snippet per client, is in the Skyelight web app under
account settings → **Coding Agents**.
## As a Claude Code plugin
```
/plugin marketplace add plastrlab/skyelight-mcp
/plugin install skyelight@skyelight
```
The plugin connects Claude Code to Skyelight's remote server (sign-in is
OAuth, as above) and adds a skill for working through feedback and two
commands: `/skyelight:whats-new` and `/skyelight:fix-feedback`. Its files are
`.claude-plugin/marketplace.json` and `plugin/` in this repository.
## With a token
**Get a personal access token.** In the Skyelight web app, go to account
settings → **API Keys** → create one. It is shown once, belongs to the
organization you create it in, and can be given an expiry.
Then add the server to your client:
```json
{
"mcpServers": {
"skyelight": {
"command": "npx",
"args": ["-y", "@skyelight/mcp"],
"env": {
"SKYELIGHT_API_URL": "https://app.skyelight.ai",
"SKYELIGHT_API_TOKEN": "sky_..."
}
}
}
}
```
Claude Code users can skip the file:
```bash
claude mcp add skyelight \
--env SKYELIGHT_API_URL=https://app.skyelight.ai \
--env SKYELIGHT_API_TOKEN=sky_... \
-- npx -y @skyelight/mcp
```
`SKYELIGHT_API_URL` is `https://app.skyelight.ai`, the same host as the MCP
URL on the **Coding Agents** page (`https://app.skyelight.ai/mcp`), without
`/mcp`. A deployment's `.convex.site` host also works.
### Credentials
Checked in order, so an existing setup keeps working:
1. `SKYELIGHT_API_TOKEN` / `SKYELIGHT_API_URL` in the environment
2. `.env.local`, then `.env`, in the working directory
3. `~/.skyelight/credentials` — `{"apiUrl": "...", "token": "sky_..."}`
### Binding a repo to a project
With the local server, if you can reach several projects, drop a
`.skyelight.json` at the repo root:
```json
{ "projectId": "j57abc...", "projectName": "Checkout rebuild" }
```
Tools then default to that project and nobody has to pass an id. Without it
(and always on the remote server), `list_items` asks for a project and the
agent calls `list_projects` first rather than guess.
## Tools
| Tool | What it is for |
| --------------------- | ------------------------------------------------------------------------------------ |
| `list_workspaces` | Which workspaces this credential can reach, and who you are. |
| `list_projects` | The projects inside them, with the ids the other tools take. |
| `list_items` | What is outstanding. Filter by page, type, status, assignee, hand-off. |
| `search_items` | Find items whose thread mentions some text, replies included. |
| `get_item` | Everything needed to work one item: thread, page, anchor, code, images. |
| `post_update` | Report back on the thread the feedback came from. |
| `create_item` | Raise a new item — an audit finding, something you noticed. |
| `set_status` | Move an item to open, deferred or resolved. |
| `list_members` | Who is in the workspace, so you can name an assignee or a mention. |
| `assign` | Hand an item to a person, or unassign it. |
| `whats_new` | What changed since you last looked, from your own bookmark. |
| `project_review` | Where a project landed, for a wrap-up or hand-off document. |
| `decision_log` | What the team decided in its threads, quoted, and its current rules. |
| `save_rule` | Keep an agreed rule in the project context (owners and admins). |
| `find_by_source` | Feedback on a file or component before you edit it, or the hot spots. |
| `find_similar` | Check for an existing report before creating one. |
| `merge_items` | Fold duplicate items into one. |
| `publish_review_link` | Share something for review: code for Skyelight to host, or a deployed app's address. |
**Which tools change things.** `list_workspaces`, `list_projects`,
`list_items`, `search_items`, `get_item`, `list_members`, `project_review`,
`find_by_source`, `find_similar` and `decision_log` only read. `post_update`,
`create_item`, `set_status`, `assign`, `save_rule`, `merge_items`,
`publish_review_link` and `whats_new` (which moves your "last looked"
bookmark) make changes. Every tool carries MCP annotations saying which it
is, with `merge_items` marked destructive, so your client can ask before a
write runs.
**Publishing for review.** `publish_review_link` takes one of two things:
- `code`: one HTML page, or one React component with an export default (a
Claude prototype, a v0 snippet). Skyelight hosts it at its own link on
`skyelight.page` with the review badge on it, in a project you name or a new
one. Publishing again makes a new version at the same link.
- `url`: an app already deployed, such as a Lovable, v0 or Bolt project on
`*.lovable.app` or `*.vercel.app`. The address goes on the project's Review
Links, and the answer carries a script tag for the app's `<head>` and the
review link to share (the address with `?skyelight=1`).
Code that imports the rest of its app is not hosted; the answer says to send
the app's `url` instead. It answers to `publish_prototype` too, its name
before 0.7.0.
`list_items` leads with a summary — totals, breakdown by type and by page — so
an agent can tell you the shape of the work before pulling any of it. Rows are
stubs; `get_item` is where the thread and the anchor live.
**"What is assigned to me."** `list_workspaces` returns your own user id, and
`list_items` takes `assignee: "me"`, so the most ordinary question anyone asks
an agent needs no id looked up by hand.
**"What was I asked to fix."** A person can hand a thread to an agent in the
app (Hand off: Investigate, Plan or Fix). `list_items` takes `task` with one of
those, or `"none"`, and each row names its hand-off. With `assignee: "me"` it
is your own queue of fixes.
**Merged duplicates do not appear twice.** When somebody merges five reports of
one problem in the web app, the duplicates leave the list and the item they were
merged into says `5 reports`. A list that shows all five reads as five bugs.
## What the agent sees
```
Alpha: 21 items total — 15 open, 3 deferred, 3 resolved, 19 unassigned.
By type: bug (7), idea (4), feedback (10).
Busiest pages: /checkout (8), /settings (4).
2 matches:
- The pay button does nothing on the second click
bug · open · /checkout · unassigned · 2 replies · 5 reports — id i1
```
Deliberately prose rather than JSON. A tool that returns a bare array invites a
model to read the array out; this one invites it to summarise.
A row's line is the one-sentence summary Skyelight's classifier wrote, where
there is one, rather than the first 140 characters of whatever somebody typed —
four truncated paragraphs are not something you can choose between.
One call reads the 2,000 most recent items in a project. Past that the result
says so, in words, rather than presenting a slice as the total.
### The pictures
`get_item` returns the screenshot taken when the pin was left, and any images
people attached to the thread, as **image content blocks** — things a model can
actually look at, not links it cannot open.
```
Screenshot of the page when this was pinned: attached below.
2 images attached to this thread: also below.
```
Capped at four per call. Anything too large to inline comes back as its link
with the reason, so a picture never disappears silently.
### What somebody else already did
`get_item` also names the Linear issue a thread was handed to, and who it was
delegated to, so an agent does not start work a Linear-hosted agent is
finishing. Reactions come back counted by emoji — a thread with one comment and
nine thumbs up is not a thread with one comment.
### Where the code is
If the app was built with [`@skyelight/build`](https://www.npmjs.com/package/@skyelight/build),
`get_item` ends with the line that changes what an agent does next:
```
Written by components/Card.tsx, line 88, in build a1b2c3d on branch feat/checkout.
```
The file saves a grep. The commit and branch are how an agent tells "still
broken" from "already fixed, this pin is stale" — and, on a preview
deployment, which branch the code it wants is actually on.
## Who a write belongs to
Every write is **a person's**. Your sign-in or token carries your access, so a
reply the agent posts is yours. Over the remote server, the editor it came
through is shown as a mark beside the timestamp rather than as the author.
There is no service-account mode, and workspace API keys (`sk_live_...`) no
longer work. The API accepts two credentials, both of which are you: an OAuth
sign-in and a personal token (`sky_...`).
## Permissions
The server enforces nothing; the API does. The agent can do what your account
can do in that workspace, and nothing more:
- Agent tools work on **every plan, Free included**, for owners, admins and
collaborators. A reviewer is refused with the reason — the workspace is listed
and marked rather than hidden, so you are told which gate closed instead of
being told it does not exist.
- **On Free**, your agent gets **25 agent threads a month**. Two things
count: each conversation, once, on its first call of any tool, listing
included; and each thread the first time in the month `get_item`,
`post_update`, `set_status`, `assign` or `merge_items` touches it. So
"what feedback do I have?" then "fix that one" is 2. Nothing counted is
given back. `list_workspaces` says how many are left, and at the limit
anything new is refused with the reset date. Free hosts one prototype.
- Adding a deployed app's address to Review Links is for owners and admins.
- Owners, admins and collaborators read, reply, raise items and change any
thread's status.
- A token only reaches workspaces in the organization it was created in.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues