@glie/mcp-polaris 0.8.0 → 0.10.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/dist/index.js +97 -15
- package/package.json +3 -14
package/dist/index.js
CHANGED
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
|
|
4
4
|
// ../../src/mcp/index.ts
|
|
5
5
|
import { createInterface } from "readline";
|
|
6
|
+
|
|
7
|
+
// ../../src/lib/media-types.ts
|
|
8
|
+
var MEDIA_TYPES = [
|
|
9
|
+
{ mime: "image/png", kind: "image", ext: ".png", aliases: [] },
|
|
10
|
+
{ mime: "image/jpeg", kind: "image", ext: ".jpg", aliases: [".jpeg"] },
|
|
11
|
+
{ mime: "image/webp", kind: "image", ext: ".webp", aliases: [] },
|
|
12
|
+
{ mime: "video/mp4", kind: "video", ext: ".mp4", aliases: [] },
|
|
13
|
+
{ mime: "video/quicktime", kind: "video", ext: ".mov", aliases: [] },
|
|
14
|
+
{ mime: "video/webm", kind: "video", ext: ".webm", aliases: [] }
|
|
15
|
+
];
|
|
16
|
+
function allMimes() {
|
|
17
|
+
return MEDIA_TYPES.map((t) => t.mime);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// ../../src/mcp/index.ts
|
|
6
21
|
var BASE = process.env.POLARIS_URL ?? "http://127.0.0.1:7843";
|
|
7
22
|
var TOKEN = process.env.POLARIS_TOKEN ?? "";
|
|
8
23
|
var PROJECT = process.env.POLARIS_PROJECT ?? "";
|
|
@@ -123,12 +138,27 @@ var TOOLS = [
|
|
|
123
138
|
},
|
|
124
139
|
{
|
|
125
140
|
name: "polaris.project.create",
|
|
126
|
-
description: "Create a project (human-only).",
|
|
127
|
-
inputSchema: objSchema({
|
|
128
|
-
|
|
141
|
+
description: "Create a project (human-only). With GitHub connected a repository is required \u2014 pick one from polaris.github.repositories. One repository holds one project.",
|
|
142
|
+
inputSchema: objSchema({
|
|
143
|
+
key: strSchema(),
|
|
144
|
+
name: strSchema(),
|
|
145
|
+
repo_url: strSchema("https://github.com/owner/repo \u2014 required when GitHub is connected")
|
|
146
|
+
}, ["key", "name"]),
|
|
147
|
+
call: async (args) => (await apiCall("POST", "/api/projects", args)).body
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: "polaris.github.repositories",
|
|
151
|
+
description: "Repositories a project may live in (human-only): whether GitHub is connected, and every repository the GitHub App reaches \u2014 available, or why not (already another project's, or archived).",
|
|
152
|
+
inputSchema: objSchema({}),
|
|
153
|
+
call: async () => (await apiCall("GET", "/api/github/repositories")).body
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
name: "polaris.github.repository.create",
|
|
157
|
+
description: "Create a repository ready for Polaris (human-only): private, initialised, Issues on, with a dev branch. Needs the GitHub App's Administration: write permission \u2014 the answer says where to grant it when missing. Then create the project with its URL.",
|
|
158
|
+
inputSchema: objSchema({ name: strSchema("the repository name \u2014 usually the project key") }, [
|
|
129
159
|
"name"
|
|
130
160
|
]),
|
|
131
|
-
call: async (args) => (await apiCall("POST", "/api/
|
|
161
|
+
call: async (args) => (await apiCall("POST", "/api/github/repositories", args)).body
|
|
132
162
|
},
|
|
133
163
|
{
|
|
134
164
|
name: "polaris.project.arm",
|
|
@@ -213,7 +243,7 @@ var TOOLS = [
|
|
|
213
243
|
description: "Step 1 of attaching an image to a milestone: reserve an upload key. Returns file_key + upload_url \u2014 PUT the raw image bytes to upload_url YOURSELF (curl/fetch from your shell; this call does not carry bytes), then call polaris.milestone.attachment_create with the same file_key. A link isn't an attachment at all \u2014 just write `[text](url)` straight into the milestone's description_md.",
|
|
214
244
|
inputSchema: objSchema({
|
|
215
245
|
id: intSchema("milestone id"),
|
|
216
|
-
mime: strSchema("
|
|
246
|
+
mime: strSchema(allMimes().join(" | ")),
|
|
217
247
|
size_bytes: intSchema()
|
|
218
248
|
}, ["id", "mime", "size_bytes"]),
|
|
219
249
|
call: async (args) => (await apiCall("POST", `/api/milestones/${args.id}/attachments/presign`, {
|
|
@@ -325,7 +355,7 @@ var TOOLS = [
|
|
|
325
355
|
description: "Step 1 of attaching an image to a task: reserve an upload key. Returns file_key + upload_url \u2014 PUT the raw image bytes to upload_url YOURSELF (curl/fetch from your shell; this call does not carry bytes), then call polaris.task.attachment_create with the same file_key. A link isn't an attachment at all \u2014 just write `[text](url)` straight into the task's description_md.",
|
|
326
356
|
inputSchema: objSchema({
|
|
327
357
|
id: intSchema("task id"),
|
|
328
|
-
mime: strSchema("
|
|
358
|
+
mime: strSchema(allMimes().join(" | ")),
|
|
329
359
|
size_bytes: intSchema()
|
|
330
360
|
}, ["id", "mime", "size_bytes"]),
|
|
331
361
|
call: async (args) => (await apiCall("POST", `/api/tasks/${args.id}/attachments/presign`, {
|
|
@@ -393,9 +423,16 @@ var TOOLS = [
|
|
|
393
423
|
},
|
|
394
424
|
{
|
|
395
425
|
name: "polaris.task.transition",
|
|
396
|
-
description:
|
|
397
|
-
inputSchema: objSchema({ id: intSchema(), status: strSchema() }, ["id", "status"]),
|
|
398
|
-
call: async (args) =>
|
|
426
|
+
description: 'Move a task to its next status when you finish a stage (e.g. dev\u2192test once your PR is up). Enforced flow: draft\u2192backlog\u2192dev\u2192test\u2192approval\u2192release\u2192done (any\u2192canceled). Illegal jumps are rejected. Neither terminal state is a dead end: canceled\u2192draft and done\u2192approval undo the last step, so a mistaken close is recoverable without touching the database. The approval\u2192release gate is polaris.task.approve (human-only).\n\nThree of these moves hand the work to someone else, and `note` is REQUIRED on them \u2014 it is the message that travels with it, and it lands in the task chat as a handover: `dev\u2192test` (what you did and what to look at first), `test\u2192dev` (why it comes back \u2014 it is what the next attempt is made from), and `test\u2192approval`, which also requires `verdict` ("approved" or "rejected": a person is about to decide, and they need to know whether this passed or ran out of rounds). Every other move takes no note.',
|
|
427
|
+
inputSchema: objSchema({ id: intSchema(), status: strSchema(), note: strSchema(), verdict: strSchema() }, ["id", "status"]),
|
|
428
|
+
call: async (args) => {
|
|
429
|
+
const body = { status: args.status };
|
|
430
|
+
if (typeof args.note === "string")
|
|
431
|
+
body.note = args.note;
|
|
432
|
+
if (typeof args.verdict === "string")
|
|
433
|
+
body.verdict = args.verdict;
|
|
434
|
+
return (await apiCall("POST", `/api/tasks/${args.id}/state`, body)).body;
|
|
435
|
+
}
|
|
399
436
|
},
|
|
400
437
|
{
|
|
401
438
|
name: "polaris.task.approve",
|
|
@@ -729,22 +766,54 @@ var TOOLS = [
|
|
|
729
766
|
},
|
|
730
767
|
{
|
|
731
768
|
name: "polaris.presence.list",
|
|
732
|
-
description: "Where a product exists in the world: the channels it publishes on and the directories it is listed in, each with its state (missing \u2192 exists \u2192 connected). Read this before writing a campaign \u2014 a channel that is not connected cannot be published to.",
|
|
769
|
+
description: "Where a product exists in the world: the channels it publishes on and the directories it is listed in, each with its state (missing \u2192 exists \u2192 connected). Read this before writing a campaign \u2014 a channel that is not connected cannot be published to. Each row carries what the catalogue knows in `place`: read `place.actor` before planning work there \u2014 `agent` means there is a publishing tool, `human` means a person does it and records where, and `place.final_state` says how far this particular place can ever get.",
|
|
733
770
|
inputSchema: objSchema({ key: strSchema("project key") }, ["key"]),
|
|
734
771
|
call: async (args) => (await apiCall("GET", `/api/projects/${args.key}/presences`)).body
|
|
735
772
|
},
|
|
773
|
+
{
|
|
774
|
+
name: "polaris.place.list",
|
|
775
|
+
description: "The catalogue of places a product can exist in \u2014 every social network, paid surface, syndication platform, app store and software directory the studio knows about. The world's list, not ours: read it to decide WHERE a product should be. Each entry says what the place is, who acts there (`actor`: agent = there is a publishing tool; human = a person does it and records where), how far it can get (`final_state`), WHY it is worth being there (`note`), and the URL that was verified (`source`). Whether we are actually there is a PRESENCE \u2014 polaris.presence.list.",
|
|
776
|
+
inputSchema: objSchema({}),
|
|
777
|
+
call: async () => (await apiCall("GET", "/api/places")).body
|
|
778
|
+
},
|
|
779
|
+
{
|
|
780
|
+
name: "polaris.org_credential.list",
|
|
781
|
+
description: "The accounts that serve MANY products at once \u2014 Google Play Console, App Store Connect, a vendor login that covers several listings. Read it to know whether an entry can be opened at all, and by whom: the row names the owner, and the password never leaves the server. A presence points at one of these when the credential is the org's rather than the product's.",
|
|
782
|
+
inputSchema: objSchema({}),
|
|
783
|
+
call: async () => (await apiCall("GET", "/api/org-credentials")).body
|
|
784
|
+
},
|
|
785
|
+
{
|
|
786
|
+
name: "polaris.org_credential.add",
|
|
787
|
+
description: "Register an org-wide credential (human-only). Idempotent on slug + login: the same Play Console twice is the same Play Console, and a DIFFERENT login on the same site is a different credential. A place reached by OAuth is refused \u2014 that credential already lives in social accounts. Never send a password you were not given.",
|
|
788
|
+
inputSchema: objSchema({
|
|
789
|
+
slug: strSchema("play-store \xB7 app-store \xB7 capterra \u2026"),
|
|
790
|
+
label: strSchema("human name; defaults to the catalogue's"),
|
|
791
|
+
url: strSchema("where you log in"),
|
|
792
|
+
login_email: strSchema(),
|
|
793
|
+
notes: strSchema("who holds the second factor, and anything the next person needs")
|
|
794
|
+
}, ["slug"]),
|
|
795
|
+
call: async (args) => (await apiCall("POST", "/api/org-credentials", args)).body
|
|
796
|
+
},
|
|
797
|
+
{
|
|
798
|
+
name: "polaris.org_credential.verify",
|
|
799
|
+
description: "Stamp an org credential as CHECKED \u2014 it still opens the door (human-only). A credential does not announce that it expired: that is discovered on the day it is needed, which is always the worst day.",
|
|
800
|
+
inputSchema: objSchema({ id: intSchema("credential id") }, ["id"]),
|
|
801
|
+
call: async (args) => (await apiCall("POST", `/api/org-credentials/${args.id}/verify`, {})).body
|
|
802
|
+
},
|
|
736
803
|
{
|
|
737
804
|
name: "polaris.presence.add",
|
|
738
|
-
description: "Add a place to a project (human-only). kind: channel (we publish there) | listing (we keep an entry there). Idempotent on slug: adding the same
|
|
805
|
+
description: "Add a place to a project (human-only). kind: channel (we publish there) | listing (we keep an entry there). Idempotent on slug + MARKET: adding Instagram BR twice is the same Instagram BR, and Instagram US is a different presence. Never send a password you were not given.",
|
|
739
806
|
inputSchema: objSchema({
|
|
740
807
|
key: strSchema("project key"),
|
|
741
808
|
kind: strSchema("channel | listing"),
|
|
742
809
|
slug: strSchema("instagram \xB7 linkedin \xB7 reddit \xB7 g2 \xB7 capterra \u2026"),
|
|
743
810
|
label: strSchema("human name, e.g. Instagram"),
|
|
811
|
+
market: strSchema("the market this one serves (BR \xB7 US \xB7 \u2026) \u2014 it is half the identity, so a product with an account per market gets one presence per market. Omit where the place has no market (a blog, a store entry)."),
|
|
744
812
|
url: strSchema("public profile or listing URL"),
|
|
745
813
|
handle: strSchema("@handle or account name"),
|
|
746
|
-
state: strSchema("missing | exists | connected
|
|
814
|
+
state: strSchema("missing | exists | connected \u2014 connected means there IS a link"),
|
|
747
815
|
login_email: strSchema(),
|
|
816
|
+
org_credential_id: intSchema("the org-wide account that opens this entry, when there is one"),
|
|
748
817
|
notes: strSchema()
|
|
749
818
|
}, ["key", "kind", "slug", "label"]),
|
|
750
819
|
call: async (args) => {
|
|
@@ -763,6 +832,7 @@ var TOOLS = [
|
|
|
763
832
|
handle: strSchema(),
|
|
764
833
|
state: strSchema("missing | exists | connected"),
|
|
765
834
|
login_email: strSchema(),
|
|
835
|
+
org_credential_id: intSchema("the org-wide account that opens this entry; null unlinks"),
|
|
766
836
|
notes: strSchema()
|
|
767
837
|
}, ["key", "id"]),
|
|
768
838
|
call: async (args) => {
|
|
@@ -907,11 +977,23 @@ var TOOLS = [
|
|
|
907
977
|
inputSchema: objSchema({ id: intSchema("stack id"), task_id: intSchema() }, ["id", "task_id"]),
|
|
908
978
|
call: async (args) => (await apiCall("DELETE", `/api/stacks/${args.id}/tasks`, { task_id: args.task_id })).body
|
|
909
979
|
},
|
|
980
|
+
{
|
|
981
|
+
name: "polaris.task.escalate",
|
|
982
|
+
description: "You are making a piece and something needs a HUMAN DECISION before it can be made \u2014 a premise in the brief that turned out false, two ways forward and no ground to choose between them, a collision with something already live. Stops the piece and puts it in front of a person, in `approval`, with your question attached.\n\nNot for a piece you could not finish: that is what ending the run does. This is for one you are not going to decide alone.\n\nThe `note` is the whole point \u2014 what you found, what the options are, and what you are not choosing on your own. Without it this is an abandoned piece with a flag on it.",
|
|
983
|
+
inputSchema: objSchema({
|
|
984
|
+
id: intSchema(),
|
|
985
|
+
note: strSchema("the question \u2014 what was found, the options, and what you will not decide")
|
|
986
|
+
}, ["id", "note"]),
|
|
987
|
+
call: async (args) => (await apiCall("POST", `/api/tasks/${args.id}/escalate`, { note: args.note })).body
|
|
988
|
+
},
|
|
910
989
|
{
|
|
911
990
|
name: "polaris.task.return_to_backlog",
|
|
912
|
-
description: "Send an approval task back for rework (human-only) \u2014 to its sticky developer (dev) or backlog. Clears escalation.",
|
|
913
|
-
inputSchema: objSchema({
|
|
914
|
-
|
|
991
|
+
description: "Send an approval task back for rework (human-only) \u2014 to its sticky developer (dev) or backlog. Clears escalation.\n\n**Write the `note`.** On a rework the agent does NOT re-read the brief: the request it gets says *you already have the brief*, and the note is the only thing that reaches it. Sending a piece back without one asks for the same piece again \u2014 and an agent that finds the field empty concludes the worker restarted and changes nothing, which is what it should do.",
|
|
992
|
+
inputSchema: objSchema({
|
|
993
|
+
id: intSchema(),
|
|
994
|
+
note: strSchema("why it is coming back \u2014 this is the brief for the next attempt")
|
|
995
|
+
}, ["id"]),
|
|
996
|
+
call: async (args) => (await apiCall("POST", `/api/tasks/${args.id}/return-to-backlog`, args.note ? { note: args.note } : undefined)).body
|
|
915
997
|
},
|
|
916
998
|
{
|
|
917
999
|
name: "polaris.chat.post",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glie/mcp-polaris",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.10.0",
|
|
4
4
|
"description": "Model Context Protocol (stdio) server exposing Polaris, glie's ops platform, as native tools in Claude Code and any MCP client.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "glie <carlos@glie.ai>",
|
|
@@ -8,11 +8,7 @@
|
|
|
8
8
|
"bin": {
|
|
9
9
|
"mcp-polaris": "dist/index.js"
|
|
10
10
|
},
|
|
11
|
-
"files": [
|
|
12
|
-
"dist",
|
|
13
|
-
"README.md",
|
|
14
|
-
"LICENSE"
|
|
15
|
-
],
|
|
11
|
+
"files": ["dist", "README.md", "LICENSE"],
|
|
16
12
|
"engines": {
|
|
17
13
|
"node": ">=18"
|
|
18
14
|
},
|
|
@@ -25,14 +21,7 @@
|
|
|
25
21
|
"directory": "packages/mcp-polaris"
|
|
26
22
|
},
|
|
27
23
|
"homepage": "https://polaris.glie.ai",
|
|
28
|
-
"keywords": [
|
|
29
|
-
"mcp",
|
|
30
|
-
"model-context-protocol",
|
|
31
|
-
"claude",
|
|
32
|
-
"claude-code",
|
|
33
|
-
"polaris",
|
|
34
|
-
"glie"
|
|
35
|
-
],
|
|
24
|
+
"keywords": ["mcp", "model-context-protocol", "claude", "claude-code", "polaris", "glie"],
|
|
36
25
|
"scripts": {
|
|
37
26
|
"build": "bun run build.ts",
|
|
38
27
|
"prepublishOnly": "bun run build.ts"
|