@zibby/skills 0.1.49 → 0.1.51
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/bin/mcp-sentry.mjs +59 -2
- package/dist/datasetStore.d.ts +106 -0
- package/dist/datasetStore.js +18 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +112 -93
- package/dist/package.json +1 -1
- package/dist/sentry.d.ts +39 -0
- package/dist/sentry.js +4 -2
- package/package.json +1 -1
package/bin/mcp-sentry.mjs
CHANGED
|
@@ -31,7 +31,7 @@ import { z } from 'zod';
|
|
|
31
31
|
// Sentry endpoint = one edit in src/sentry.js, not three. Deterministic
|
|
32
32
|
// workflow nodes import the same functions for cost-optimized fetches
|
|
33
33
|
// that skip the LLM entirely.
|
|
34
|
-
import { sentryListProjects, sentryListIssues, sentryGetIssue } from '../dist/sentry.js';
|
|
34
|
+
import { sentryListProjects, sentryListIssues, sentryGetIssue, sentryUpdateIssue, sentryAddComment } from '../dist/sentry.js';
|
|
35
35
|
|
|
36
36
|
const server = new McpServer(
|
|
37
37
|
{ name: 'zibby-sentry', version: '1.0.0' },
|
|
@@ -121,10 +121,67 @@ server.registerTool(
|
|
|
121
121
|
},
|
|
122
122
|
);
|
|
123
123
|
|
|
124
|
+
// ── sentry_update_issue ─────────────────────────────────────────────
|
|
125
|
+
server.registerTool(
|
|
126
|
+
'sentry_update_issue',
|
|
127
|
+
{
|
|
128
|
+
title: 'Update Sentry Issue',
|
|
129
|
+
description: "Update a Sentry issue's status (resolved | resolvedInNextRelease | unresolved | ignored | muted), assignment, or bookmark. Requires the connected Sentry integration to have the event:write scope.",
|
|
130
|
+
inputSchema: z.object({
|
|
131
|
+
issueId: z.string().describe('Sentry issue ID'),
|
|
132
|
+
status: z.string().optional().describe('resolved | resolvedInNextRelease | unresolved | ignored | muted'),
|
|
133
|
+
statusDetails: z.object({}).passthrough().optional().describe('Optional status details, e.g. { "inRelease": "latest" }'),
|
|
134
|
+
assignedTo: z.string().optional().describe('Assignee actor id, e.g. "user:123" or "team:456"'),
|
|
135
|
+
isBookmarked: z.boolean().optional().describe('Bookmark/unbookmark the issue'),
|
|
136
|
+
hasSeen: z.boolean().optional().describe('Mark the issue seen/unseen'),
|
|
137
|
+
}),
|
|
138
|
+
},
|
|
139
|
+
async (args = {}) => {
|
|
140
|
+
try {
|
|
141
|
+
const data = await sentryUpdateIssue(args.issueId, {
|
|
142
|
+
status: args.status,
|
|
143
|
+
statusDetails: args.statusDetails,
|
|
144
|
+
assignedTo: args.assignedTo,
|
|
145
|
+
isBookmarked: args.isBookmarked,
|
|
146
|
+
hasSeen: args.hasSeen,
|
|
147
|
+
});
|
|
148
|
+
const text = JSON.stringify({
|
|
149
|
+
ok: true, id: data.id ?? args.issueId, status: data.status,
|
|
150
|
+
assignedTo: data.assignedTo, isBookmarked: data.isBookmarked,
|
|
151
|
+
});
|
|
152
|
+
return { content: [{ type: 'text', text }] };
|
|
153
|
+
} catch (err) {
|
|
154
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
);
|
|
158
|
+
|
|
159
|
+
// ── sentry_add_comment ──────────────────────────────────────────────
|
|
160
|
+
server.registerTool(
|
|
161
|
+
'sentry_add_comment',
|
|
162
|
+
{
|
|
163
|
+
title: 'Comment on a Sentry Issue',
|
|
164
|
+
description: 'Post a comment/note on a Sentry issue. Requires the connected Sentry integration to have the event:write scope.',
|
|
165
|
+
inputSchema: z.object({
|
|
166
|
+
issueId: z.string().describe('Sentry issue ID'),
|
|
167
|
+
text: z.string().describe('Comment body (markdown)'),
|
|
168
|
+
}),
|
|
169
|
+
},
|
|
170
|
+
async (args = {}) => {
|
|
171
|
+
try {
|
|
172
|
+
const data = await sentryAddComment(args.issueId, args.text);
|
|
173
|
+
const text = JSON.stringify({ ok: true, id: data.id, issueId: args.issueId });
|
|
174
|
+
return { content: [{ type: 'text', text }] };
|
|
175
|
+
} catch (err) {
|
|
176
|
+
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
);
|
|
180
|
+
|
|
124
181
|
const transport = new StdioServerTransport();
|
|
125
182
|
await server.connect(transport);
|
|
126
183
|
|
|
127
184
|
// Tiny diagnostic line on stderr so operators can confirm the MCP
|
|
128
185
|
// server actually started. stdout is reserved for MCP JSON-RPC; only
|
|
129
186
|
// stderr is safe for human-readable logs.
|
|
130
|
-
console.error('[mcp-sentry] connected (
|
|
187
|
+
console.error('[mcp-sentry] connected (5 tools: sentry_list_projects, sentry_list_issues, sentry_get_issue, sentry_update_issue, sentry_add_comment)');
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
export namespace datasetStoreSkill {
|
|
2
|
+
let id: string;
|
|
3
|
+
let serverName: string;
|
|
4
|
+
let allowedTools: string[];
|
|
5
|
+
let description: string;
|
|
6
|
+
let promptFragment: string;
|
|
7
|
+
function resolve(): {
|
|
8
|
+
command: any;
|
|
9
|
+
args: any[];
|
|
10
|
+
env: {};
|
|
11
|
+
description: string;
|
|
12
|
+
type?: undefined;
|
|
13
|
+
alwaysLoad?: undefined;
|
|
14
|
+
} | {
|
|
15
|
+
type: string;
|
|
16
|
+
command: string;
|
|
17
|
+
args: any[];
|
|
18
|
+
env: {};
|
|
19
|
+
description: string;
|
|
20
|
+
alwaysLoad: boolean;
|
|
21
|
+
};
|
|
22
|
+
function handleToolCall(name: any, args: any): Promise<string>;
|
|
23
|
+
let tools: ({
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
input_schema: {
|
|
27
|
+
type: string;
|
|
28
|
+
properties: {
|
|
29
|
+
storeId: {
|
|
30
|
+
type: string;
|
|
31
|
+
description: string;
|
|
32
|
+
};
|
|
33
|
+
dataset: {
|
|
34
|
+
type: string;
|
|
35
|
+
description: string;
|
|
36
|
+
};
|
|
37
|
+
record: {
|
|
38
|
+
type: string;
|
|
39
|
+
description: string;
|
|
40
|
+
};
|
|
41
|
+
agent: {
|
|
42
|
+
type: string;
|
|
43
|
+
description: string;
|
|
44
|
+
};
|
|
45
|
+
select?: undefined;
|
|
46
|
+
where?: undefined;
|
|
47
|
+
groupBy?: undefined;
|
|
48
|
+
orderBy?: undefined;
|
|
49
|
+
limit?: undefined;
|
|
50
|
+
since?: undefined;
|
|
51
|
+
until?: undefined;
|
|
52
|
+
};
|
|
53
|
+
required: string[];
|
|
54
|
+
};
|
|
55
|
+
} | {
|
|
56
|
+
name: string;
|
|
57
|
+
description: string;
|
|
58
|
+
input_schema: {
|
|
59
|
+
type: string;
|
|
60
|
+
properties: {
|
|
61
|
+
storeId: {
|
|
62
|
+
type: string;
|
|
63
|
+
description: string;
|
|
64
|
+
};
|
|
65
|
+
dataset: {
|
|
66
|
+
type: string;
|
|
67
|
+
description: string;
|
|
68
|
+
};
|
|
69
|
+
select: {
|
|
70
|
+
type: string;
|
|
71
|
+
description: string;
|
|
72
|
+
};
|
|
73
|
+
where: {
|
|
74
|
+
type: string;
|
|
75
|
+
description: string;
|
|
76
|
+
};
|
|
77
|
+
groupBy: {
|
|
78
|
+
type: string;
|
|
79
|
+
description: string;
|
|
80
|
+
};
|
|
81
|
+
orderBy: {
|
|
82
|
+
type: string;
|
|
83
|
+
description: string;
|
|
84
|
+
};
|
|
85
|
+
limit: {
|
|
86
|
+
type: string;
|
|
87
|
+
description: string;
|
|
88
|
+
};
|
|
89
|
+
since: {
|
|
90
|
+
type: string;
|
|
91
|
+
description: string;
|
|
92
|
+
};
|
|
93
|
+
until: {
|
|
94
|
+
type: string;
|
|
95
|
+
description: string;
|
|
96
|
+
};
|
|
97
|
+
agent: {
|
|
98
|
+
type: string;
|
|
99
|
+
description: string;
|
|
100
|
+
};
|
|
101
|
+
record?: undefined;
|
|
102
|
+
};
|
|
103
|
+
required: any[];
|
|
104
|
+
};
|
|
105
|
+
})[];
|
|
106
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import{existsSync as c,readFileSync as l}from"node:fs";import{homedir as y}from"node:os";import{join as f,dirname as m,resolve as g}from"node:path";import{fileURLToPath as h}from"node:url";function O(){if(process.env.MCP_SKILL_PATH)return process.env.MCP_SKILL_PATH;let r=m(h(import.meta.url)),e=g(r,"..","bin","mcp-skill.mjs");return c(e)?e:null}function u(){if(process.env.PROJECT_API_TOKEN)return process.env.PROJECT_API_TOKEN;if(process.env.ZIBBY_USER_TOKEN)return process.env.ZIBBY_USER_TOKEN;try{let r=f(y(),".zibby","config.json");return c(r)&&JSON.parse(l(r,"utf-8")).sessionToken||null}catch{return null}}function p(){return process.env.ZIBBY_ACCOUNT_API_URL?process.env.ZIBBY_ACCOUNT_API_URL.replace(/\/$/,""):(process.env.ZIBBY_ENV||"prod")==="local"?"http://localhost:3001":process.env.ZIBBY_PROD_ACCOUNT_API_URL||"https://api-prod.zibby.app"}function _(){return(typeof process.env.WORKFLOW_TYPE=="string"?process.env.WORKFLOW_TYPE.trim():"")||"agent"}async function i(r,e,n){let t=u();if(!t)throw new Error("No backend credential (PROJECT_API_TOKEN). Dataset store is only available inside a Zibby run.");let o=`${p()}/datasets/${encodeURIComponent(r)}/${e}`,s=await fetch(o,{method:"POST",headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"},body:JSON.stringify(n)});if(!s.ok){let a=await s.text().catch(()=>"");throw new Error(`Dataset ${e} failed (${s.status}): ${a.slice(0,300)}`)}return s.json()}function w(){let r=typeof process.env.ZIBBY_STORES=="string"?process.env.ZIBBY_STORES.trim():"";if(!r)return null;let e=r.split(",").map(n=>n.trim()).filter(Boolean);return e.length?e:null}async function d(r,e,n){let t=u();if(!t)throw new Error("No backend credential (PROJECT_API_TOKEN). Dataset store is only available inside a Zibby run.");let o=`${p()}/datasets/stores/${encodeURIComponent(r)}/${e}`,s=await fetch(o,{method:"POST",headers:{Authorization:`Bearer ${t}`,"Content-Type":"application/json"},body:JSON.stringify(n)});if(!s.ok){let a=await s.text().catch(()=>"");throw new Error(`Store ${e} failed (${s.status}): ${a.slice(0,300)}`)}return s.json()}var E={id:"dataset-store",serverName:"dataset_store",allowedTools:["mcp__dataset_store__*"],description:"Dataset store \u2014 a durable, queryable store for structured JSON records; append rows now, run SQL-style aggregations/reports later",promptFragment:`## Dataset Store (durable, queryable structured-record store)
|
|
2
|
+
You have a durable store for STRUCTURED records that survives across your
|
|
3
|
+
stateless runs. Unlike key-value memory (for picking up where you left off),
|
|
4
|
+
this is for accumulating DATA you want to QUERY and AGGREGATE later \u2014 e.g.
|
|
5
|
+
per-run metrics, processed items, findings \u2014 and turn into a report.
|
|
6
|
+
|
|
7
|
+
If your node has provisioned stores, an "AVAILABLE STORES" list appears below \u2014
|
|
8
|
+
pick one BY DESCRIPTION and pass its \`storeId\` to the tools. Otherwise records
|
|
9
|
+
are grouped by a named \`dataset\` (your choice, e.g. "scout-metrics").
|
|
10
|
+
Each appended record is an arbitrary JSON object and is auto-tagged with YOUR
|
|
11
|
+
agent type, so you can later filter to just your own writes.
|
|
12
|
+
|
|
13
|
+
Tools:
|
|
14
|
+
- dataset_append: Append ONE structured JSON \`record\` to a \`dataset\`. Use to
|
|
15
|
+
durably persist a row of data each run (e.g. {repo, stars, ts}).
|
|
16
|
+
- dataset_query: Run a SQL-style query over a \`dataset\` \u2014 select/aggregate
|
|
17
|
+
(count|sum|avg|min|max), filter (where), group (groupBy), order, limit, and
|
|
18
|
+
bound by month (since/until). Use to compute reports from what you've stored.`,resolve(){let r=O();if(!r)return{command:null,args:[],env:{},description:this.description};let e={};for(let n of["PROJECT_API_TOKEN","ZIBBY_ACCOUNT_API_URL","ZIBBY_ENV","ZIBBY_PROD_ACCOUNT_API_URL","ZIBBY_USER_TOKEN","WORKFLOW_TYPE","ZIBBY_STORES"])process.env[n]&&(e[n]=process.env[n]);return{type:"stdio",command:"node",args:[r,"../dist/datasetStore.js","datasetStoreSkill"],env:e,description:this.description,alwaysLoad:!1}},async handleToolCall(r,e){try{let n=()=>{let t=typeof e?.storeId=="string"?e.storeId.trim():typeof e?.store=="string"?e.store.trim():"",o=w();if(!t&&o&&o.length===1&&(t=o[0]),t)return o&&!o.includes(t)?{error:`storeId '${t}' is not in this node's store allowlist (${o.join(", ")})`}:{storeId:t};let s=typeof e?.dataset=="string"?e.dataset.trim():"";return s?{dataset:s}:{error:"a storeId (or legacy dataset name) is required"}};switch(r){case"dataset_append":{if(e?.record==null||typeof e.record!="object"||Array.isArray(e.record))return JSON.stringify({error:"record is required (a JSON object)"});let t=n();if(t.error)return JSON.stringify({error:t.error});let o=typeof e?.agent=="string"&&e.agent.trim()?e.agent.trim():_();if(t.storeId){let a=await d(t.storeId,"append",{record:e.record,agent:o});return JSON.stringify({...a,storeId:t.storeId})}let s=await i(t.dataset,"append",{record:e.record,agent:o});return JSON.stringify(s)}case"dataset_query":{let t=n();if(t.error)return JSON.stringify({error:t.error});let o={};for(let a of["select","where","groupBy","orderBy","limit","since","until","agent"])e?.[a]!=null&&(o[a]=e[a]);if(t.storeId){let a=await d(t.storeId,"query",o);return JSON.stringify({...a,storeId:t.storeId})}let s=await i(t.dataset,"query",o);return JSON.stringify(s)}default:return JSON.stringify({error:`Unknown tool: ${r}`})}}catch(n){return JSON.stringify({error:n.message})}},tools:[{name:"dataset_append",description:"Append ONE structured JSON record to a named dataset, durably. Records persist across your stateless runs and are auto-tagged with your agent type so you can filter to your own writes later. Use to accumulate data you will query/aggregate (e.g. per-run metrics, processed items).",input_schema:{type:"object",properties:{storeId:{type:"string",description:"A provisioned store id (from AVAILABLE STORES \u2014 pick by description). Preferred. If your node has exactly one store, you may omit this and it defaults to that store."},dataset:{type:"string",description:'Legacy: an ad-hoc dataset name (your choice, e.g. "scout-metrics"). Use `storeId` when a store is provisioned; only use `dataset` when no store is available.'},record:{type:"object",description:'An arbitrary JSON object \u2014 one row of data. Its keys become queryable fields (e.g. {"repo":"owner/x","stars":1200}).'},agent:{type:"string",description:"Optional writing-agent tag. Defaults to your own agent type \u2014 leave unset to auto-tag."}},required:["record"]}},{name:"dataset_query",description:"Run a SQL-style query over a dataset to build reports: select/aggregate (count|sum|avg|min|max), filter, group, order, limit, and bound by month. Returns { columns, rows }. Use this to compute summaries/aggregations from records you appended earlier.",input_schema:{type:"object",properties:{storeId:{type:"string",description:"A provisioned store id (from AVAILABLE STORES \u2014 pick by description). Preferred. If your node has exactly one store, you may omit this and it defaults to that store."},dataset:{type:"string",description:"Legacy: the ad-hoc dataset name you appended under. Use `storeId` when a store is provisioned."},select:{type:"array",description:"Columns to return. Each item is { field?, agg?, as? }. agg \u2208 count|sum|avg|min|max; omit field for count(*). Omit `select` entirely to return raw rows."},where:{type:"array",description:"Filters, ANDed. Each item is { field, op, value }; op \u2208 eq|ne|gt|gte|lt|lte|like. `field` is a JSON key of the stored record."},groupBy:{type:"array",description:"Field names to group by (array of strings) for aggregation."},orderBy:{type:"array",description:"Sort spec. Each item is { field|as, dir }; dir \u2208 asc|desc."},limit:{type:"number",description:"Maximum number of rows to return."},since:{type:"string",description:"Inclusive lower bound month, 'yyyy-MM' (e.g. '2026-01')."},until:{type:"string",description:"Inclusive upper bound month, 'yyyy-MM' (e.g. '2026-06')."},agent:{type:"string",description:"Filter to records written by one agent namespace. Omit to query across all writers."}},required:[]}}]};export{E as datasetStoreSkill};
|
package/dist/index.d.ts
CHANGED
|
@@ -20,6 +20,7 @@ export namespace SKILLS {
|
|
|
20
20
|
let CORE_TOOLS: string;
|
|
21
21
|
let CHAT_MEMORY: string;
|
|
22
22
|
let KV_MEMORY: string;
|
|
23
|
+
let DATASET_STORE: string;
|
|
23
24
|
let CODEBASE_MEMORY: string;
|
|
24
25
|
let WORKFLOW_BUILDER: string;
|
|
25
26
|
let OPENAI_BILLING: string;
|
|
@@ -44,12 +45,13 @@ import { sentrySkill } from './sentry.js';
|
|
|
44
45
|
import { memorySkill } from './memory.js';
|
|
45
46
|
import { chatMemorySkill } from './chat-memory.js';
|
|
46
47
|
import { kvMemorySkill } from './kvMemory.js';
|
|
48
|
+
import { datasetStoreSkill } from './datasetStore.js';
|
|
47
49
|
import { codebaseMemorySkill } from './codebaseMemory.js';
|
|
48
50
|
import { testRunnerSkill } from './test-runner.js';
|
|
49
51
|
import { skillInstallerSkill } from './skill-installer.js';
|
|
50
52
|
import { coreToolsSkill } from './core-tools.js';
|
|
51
53
|
import { workflowBuilderSkill } from './workflow-builder.js';
|
|
52
|
-
export { browserSkill, jiraSkill, githubSkill, gitlabSkill, figmaSkill, linearSkill, planeSkill, opendesignSkill, gitSkill, gitWriteSkill, slackSkill, larkSkill, notionSkill, chatNotifySkill, sentrySkill, memorySkill, chatMemorySkill, kvMemorySkill, codebaseMemorySkill, testRunnerSkill, testRunnerSkill as runnerSkill, skillInstallerSkill, coreToolsSkill, workflowBuilderSkill };
|
|
54
|
+
export { browserSkill, jiraSkill, githubSkill, gitlabSkill, figmaSkill, linearSkill, planeSkill, opendesignSkill, gitSkill, gitWriteSkill, slackSkill, larkSkill, notionSkill, chatNotifySkill, sentrySkill, memorySkill, chatMemorySkill, kvMemorySkill, datasetStoreSkill, codebaseMemorySkill, testRunnerSkill, testRunnerSkill as runnerSkill, skillInstallerSkill, coreToolsSkill, workflowBuilderSkill };
|
|
53
55
|
export { openaiBillingSkill, anthropicBillingSkill, cursorAdminSkill, fetchOpenAICosts, fetchOpenAIProjects, fetchAnthropicCosts, fetchAnthropicWorkspaces, fetchCursorSpend, fetchAllProviders, groupByKey, meanStddev } from "./llm-billing.js";
|
|
54
56
|
export { reportObjectSchema, reportToBlockKit, reportToLarkCard, SEVERITIES as REPORT_SEVERITIES } from "./report.js";
|
|
55
57
|
export { skill, functionSkill } from "./function-skill.js";
|