@flowrelay/mcp-server 1.0.3 → 1.0.5
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 +1 -1
- package/dist/index.js +79 -52
- package/package.json +3 -3
package/README.md
CHANGED
package/dist/index.js
CHANGED
|
@@ -3,6 +3,11 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
import { FlowRelayAPI } from './api.js';
|
|
6
|
+
import { createRequire } from 'node:module';
|
|
7
|
+
const { version: PKG_VERSION } = createRequire(import.meta.url)('../package.json');
|
|
8
|
+
// Canonical source vocabulary. Mirrors ALL_SOURCES in the web app's @/types
|
|
9
|
+
// (this is a separate published package, so it can't import it). The parity
|
|
10
|
+
// test tests/client-source-parity.test.ts fails if the two ever diverge.
|
|
6
11
|
const SOURCES = [
|
|
7
12
|
'github',
|
|
8
13
|
'slack',
|
|
@@ -19,17 +24,19 @@ const SOURCES = [
|
|
|
19
24
|
'microsoft_teams',
|
|
20
25
|
'sentry',
|
|
21
26
|
'datadog',
|
|
27
|
+
'pagerduty',
|
|
28
|
+
'asana',
|
|
22
29
|
];
|
|
23
30
|
const SourceEnum = z.enum(SOURCES);
|
|
24
31
|
const SourceFilterSchema = z.object({
|
|
25
|
-
projects: z.array(z.string()).optional().describe('
|
|
26
|
-
eventTypes: z.array(z.string()).optional().describe('
|
|
27
|
-
branches: z.array(z.string()).optional().describe('Git branch names (e.g. "main", "develop") –
|
|
28
|
-
priorities: z.array(z.string()).optional().describe('Priority
|
|
32
|
+
projects: z.array(z.string()).optional().describe('Resource ids from list_filter_options[source].projects (repos, channels, boards). Use the exact id, not the display label.'),
|
|
33
|
+
eventTypes: z.array(z.string()).optional().describe('Event-type values from list_filter_options (e.g. "push", "issue_created"). Case-sensitive; provider-driven. A value that does not exist matches no events (it is not rejected).'),
|
|
34
|
+
branches: z.array(z.string()).optional().describe('Git branch names (e.g. "main", "develop") – git sources only (github, gitlab, bitbucket, azure_devops). Using this on a non-git source is a 400.'),
|
|
35
|
+
priorities: z.array(z.string()).optional().describe('Priority values from list_filter_options (e.g. "high", "urgent") – jira, linear, sentry, pagerduty only. Using this on another source is a 400; unrecognized values simply match no events.'),
|
|
29
36
|
});
|
|
30
37
|
const FiltersSchema = z.record(z.string(), SourceFilterSchema)
|
|
31
38
|
.optional()
|
|
32
|
-
.describe('Per-source advanced filters, AND-combined across dimensions');
|
|
39
|
+
.describe('Per-source advanced filters, AND-combined across dimensions. Keys MUST be source ids (an unknown source id is rejected with 400). The dimension VALUES are matched leniently – call list_filter_options first to get the real selectable values for the project rather than guessing.');
|
|
33
40
|
function normalizeProjectId(value) {
|
|
34
41
|
if (typeof value !== 'string')
|
|
35
42
|
return null;
|
|
@@ -59,7 +66,27 @@ const api = new FlowRelayAPI(apiKey, process.env.FLOWRELAY_BASE_URL);
|
|
|
59
66
|
let activeProjectId = normalizeProjectId(process.env.FLOWRELAY_PROJECT_ID);
|
|
60
67
|
const server = new McpServer({
|
|
61
68
|
name: 'flowrelay',
|
|
62
|
-
version:
|
|
69
|
+
version: PKG_VERSION,
|
|
70
|
+
websiteUrl: 'https://www.flowrelay.it',
|
|
71
|
+
icons: [
|
|
72
|
+
{ src: 'https://www.flowrelay.it/icon.png', mimeType: 'image/png', sizes: ['1024x1024'] },
|
|
73
|
+
],
|
|
74
|
+
}, {
|
|
75
|
+
instructions: [
|
|
76
|
+
'Flow Relay captures your team\'s work context from connected integrations (GitHub, Slack, Jira, Linear, and more) and synthesizes it into two kinds of artifact:',
|
|
77
|
+
'- A HANDOFF: a snapshot of recent activity, decisions, open questions and next steps for a project – used to hand work off or catch up.',
|
|
78
|
+
'- An INSIGHT, in three flavors: CORRELATION (links related events across different sources), ONBOARDING BRIEF (a getting-started guide for someone new to the project) and ARCHITECTURE (trade-offs, risks and patterns inferred from the code).',
|
|
79
|
+
'',
|
|
80
|
+
'Typical flow:',
|
|
81
|
+
'1. Call list_projects to see accessible projects and their ids. Every id you ever pass (project, handoff, insight, Discord channel) comes from a list_* tool – never invent one.',
|
|
82
|
+
'2. Optionally set_active_project so later tools can omit project_id.',
|
|
83
|
+
'3. Before generating with filters, call list_filter_options to get the real selectable values for that project.',
|
|
84
|
+
'4. Call a generate_* tool. These run the AI synchronously here: the tool waits for completion (tens of seconds) and returns the finished artifact as Markdown – you do not poll.',
|
|
85
|
+
'',
|
|
86
|
+
'Cost: every generate_* call consumes credits from the user\'s plan and is charged once on success (architecture is the deepest and most expensive, handoff the cheapest). Do not regenerate an artifact you can retrieve with list_handoffs / list_insights, and confirm intent before generating repeatedly.',
|
|
87
|
+
'',
|
|
88
|
+
'Scope and access follow the API key\'s tenant role; a tool only ever sees projects the key can access.',
|
|
89
|
+
].join('\n'),
|
|
63
90
|
});
|
|
64
91
|
async function getTenantContext() {
|
|
65
92
|
const context = await api.listProjects();
|
|
@@ -97,7 +124,7 @@ async function requireProject(projectId) {
|
|
|
97
124
|
return { projectId: resolvedProjectId, project };
|
|
98
125
|
}
|
|
99
126
|
// ── Tool: workspace context ─────────────────────────────────────────
|
|
100
|
-
server.tool('get_workspace_context', 'Show Flow Relay
|
|
127
|
+
server.tool('get_workspace_context', 'Show the current Flow Relay context: personal vs business mode, number of organizations and accessible projects, the active project scope and the caller\'s role. Good first call to orient yourself before other tools.', {}, async () => {
|
|
101
128
|
const context = await getTenantContext();
|
|
102
129
|
const activeProject = activeProjectId
|
|
103
130
|
? context.projects.find((project) => project.id === activeProjectId) ?? null
|
|
@@ -116,7 +143,7 @@ server.tool('get_workspace_context', 'Show Flow Relay tenant context: personal/b
|
|
|
116
143
|
return { content: [{ type: 'text', text: lines.join('\n') }] };
|
|
117
144
|
});
|
|
118
145
|
// ── Tool: list projects ─────────────────────────────────────────────
|
|
119
|
-
server.tool('list_projects', 'List
|
|
146
|
+
server.tool('list_projects', 'List every project the API key can access (personal and organization), each with its id, scope and the caller\'s role. The id returned here is what you pass as project_id to the generate_* and list tools – start here whenever you need one.', {}, async () => {
|
|
120
147
|
const context = await getTenantContext();
|
|
121
148
|
if (context.projects.length === 0) {
|
|
122
149
|
return {
|
|
@@ -141,9 +168,9 @@ server.tool('list_projects', 'List all projects available to this API key, inclu
|
|
|
141
168
|
};
|
|
142
169
|
});
|
|
143
170
|
// ── Tool: set active project ────────────────────────────────────────
|
|
144
|
-
server.tool('set_active_project', 'Set
|
|
145
|
-
project_id: z.string().optional().describe('Project
|
|
146
|
-
clear: z.boolean().default(false).describe('Clear active project
|
|
171
|
+
server.tool('set_active_project', 'Set the active project so later tools can omit project_id (a convenience for a multi-step session on one project). Set it once from a list_projects id, then call generate_handoff / list_events / etc. without repeating project_id. Not required if you always pass project_id explicitly.', {
|
|
172
|
+
project_id: z.string().optional().describe('Project id (from list_projects) to set as active. Omit, or set clear, to unset it.'),
|
|
173
|
+
clear: z.boolean().default(false).describe('Clear the active project. Generation then requires an explicit project_id again.'),
|
|
147
174
|
}, async ({ project_id, clear }) => {
|
|
148
175
|
if (clear || !normalizeProjectId(project_id)) {
|
|
149
176
|
activeProjectId = null;
|
|
@@ -168,10 +195,10 @@ server.tool('set_active_project', 'Set or clear the active project context used
|
|
|
168
195
|
};
|
|
169
196
|
});
|
|
170
197
|
// ── Tool: list handoffs ──────────────────────────────────────────────
|
|
171
|
-
server.tool('list_handoffs', 'List
|
|
172
|
-
status: z.enum(['active', 'archived', 'all']).default('active').describe('
|
|
173
|
-
limit: z.number().min(1).max(50).default(10).describe('Max
|
|
174
|
-
project_id: z.string().optional().describe('
|
|
198
|
+
server.tool('list_handoffs', 'List existing handoffs (newest first) with their full content, across all accessible projects or one project. Use this to read what has already been generated before spending credits on a new generate_handoff. Each row\'s id can be sent to Discord via discord_send_message.', {
|
|
199
|
+
status: z.enum(['active', 'archived', 'all']).default('active').describe('active = current handoffs, archived = superseded ones, all = both.'),
|
|
200
|
+
limit: z.number().int().min(1).max(50).default(10).describe('Max handoffs to return (1-50, default 10).'),
|
|
201
|
+
project_id: z.string().optional().describe('Project id (from list_projects) to scope to. Omit to span every accessible project, or rely on the active project.'),
|
|
175
202
|
}, async ({ status, limit, project_id }) => {
|
|
176
203
|
const explicitProjectId = normalizeProjectId(project_id);
|
|
177
204
|
const resolvedProjectId = explicitProjectId ?? activeProjectId;
|
|
@@ -206,12 +233,12 @@ server.tool('list_handoffs', 'List Flow Relay handoffs in the current tenant sco
|
|
|
206
233
|
return { content: [{ type: 'text', text }] };
|
|
207
234
|
});
|
|
208
235
|
// ── Tool: generate handoff ───────────────────────────────────────────
|
|
209
|
-
server.tool('generate_handoff', 'Generate a
|
|
236
|
+
server.tool('generate_handoff', 'Generate a project handoff: an AI summary of recent activity, key changes, decisions, open questions and next steps for a project. Runs synchronously – waits for completion (tens of seconds) and returns the finished Markdown. Requires an active project (set_active_project) or an explicit project_id from list_projects. Consumes credits from the user\'s plan, charged once on success – prefer list_handoffs to read an existing one before generating a new one. To scope it, pass sources and/or filters (call list_filter_options first for valid values); omit both to use the project\'s saved scope preferences.', {
|
|
210
237
|
sources: z.array(SourceEnum)
|
|
211
238
|
.optional()
|
|
212
|
-
.describe('
|
|
239
|
+
.describe('Restrict to these source ids (omit for all connected sources). Unknown source ids are rejected with 400.'),
|
|
213
240
|
filters: FiltersSchema,
|
|
214
|
-
project_id: z.string().optional().describe('
|
|
241
|
+
project_id: z.string().optional().describe('Project id from list_projects. Overrides the active project for this call; required if no active project is set.'),
|
|
215
242
|
}, async ({ sources, filters, project_id }) => {
|
|
216
243
|
try {
|
|
217
244
|
const resolved = await requireProject(project_id);
|
|
@@ -231,8 +258,8 @@ server.tool('generate_handoff', 'Generate a new context handoff for personal sco
|
|
|
231
258
|
}
|
|
232
259
|
});
|
|
233
260
|
// ── Tool: list integrations ─────────────────────────────────────────
|
|
234
|
-
server.tool('list_integrations', 'List integrations
|
|
235
|
-
project_id: z.string().optional().describe('
|
|
261
|
+
server.tool('list_integrations', 'List connected integrations. With a project scope it returns the resources bound to that project plus their health (connection status, provider coverage); without one it returns the sources the API key owner has connected. Use it to check what data a generation can draw on.', {
|
|
262
|
+
project_id: z.string().optional().describe('Project id (from list_projects) for project-scoped resources. Omit (or rely on the active project) for the owner\'s connected sources.'),
|
|
236
263
|
}, async ({ project_id }) => {
|
|
237
264
|
const resolved = await resolveProject(project_id);
|
|
238
265
|
const { integrations } = await api.listIntegrations(resolved.projectId);
|
|
@@ -254,7 +281,7 @@ server.tool('list_integrations', 'List integrations in the current scope. In pro
|
|
|
254
281
|
return { content: [{ type: 'text', text: `**Connected integrations:**\n${text}` }] };
|
|
255
282
|
});
|
|
256
283
|
// ── Tool: list untracked resources ───────────────────────────────────
|
|
257
|
-
server.tool('list_untracked_resources', 'List
|
|
284
|
+
server.tool('list_untracked_resources', 'List active resources (repos, channels, boards) that produced events recently but are not yet assigned to any project. Use it to spot data the user connected but has not organized into a project yet – mapping them (in the web dashboard) makes their events available to generations.', {}, async () => {
|
|
258
285
|
try {
|
|
259
286
|
const resources = await api.listUntrackedResources();
|
|
260
287
|
if (resources.length === 0) {
|
|
@@ -280,12 +307,12 @@ server.tool('list_untracked_resources', 'List discovered active resources across
|
|
|
280
307
|
}
|
|
281
308
|
});
|
|
282
309
|
// ── Tool: list recent events ─────────────────────────────────────────
|
|
283
|
-
server.tool('list_events', 'List recent context events
|
|
310
|
+
server.tool('list_events', 'List recent raw context events (individual pieces of tracked activity: a push, a message, an issue update) newest first. Use it to inspect the underlying signal a generation would draw on, or to check whether a source is producing data. With a project scope it is limited to that project\'s bound resources.', {
|
|
284
311
|
source: SourceEnum
|
|
285
312
|
.optional()
|
|
286
|
-
.describe('
|
|
287
|
-
limit: z.number().min(1).max(100).default(20).describe('Max
|
|
288
|
-
project_id: z.string().optional().describe('
|
|
313
|
+
.describe('Restrict to one source id (e.g. "github"). Unknown ids are rejected with 400.'),
|
|
314
|
+
limit: z.number().int().min(1).max(100).default(20).describe('Max events to return (1-100, default 20).'),
|
|
315
|
+
project_id: z.string().optional().describe('Project id (from list_projects) to scope to. Omit (or rely on the active project) for the owner\'s personal-stream events.'),
|
|
289
316
|
}, async ({ source, limit, project_id }) => {
|
|
290
317
|
const resolved = await resolveProject(project_id);
|
|
291
318
|
const { events } = await api.listEvents(source, limit, resolved.projectId);
|
|
@@ -301,7 +328,7 @@ server.tool('list_events', 'List recent context events in current scope (persona
|
|
|
301
328
|
return { content: [{ type: 'text', text: `**Recent events:**\n${text}` }] };
|
|
302
329
|
});
|
|
303
330
|
// ── Tool: discord list channels ──────────────────────────────────────
|
|
304
|
-
server.tool('discord_list_channels', 'List text channels in
|
|
331
|
+
server.tool('discord_list_channels', 'List the text channels in the Discord server connected to this account, each with its id. Call this to get a channel_id before discord_send_message.', {}, async () => {
|
|
305
332
|
try {
|
|
306
333
|
const { channels } = await api.discordListChannels();
|
|
307
334
|
if (channels.length === 0) {
|
|
@@ -319,10 +346,10 @@ server.tool('discord_list_channels', 'List text channels in your connected Disco
|
|
|
319
346
|
});
|
|
320
347
|
// ── Tool: discord send message ──────────────────────────────────────
|
|
321
348
|
server.tool('discord_send_message', 'Send to a Discord channel in your connected server. Provide exactly one of: content (inline text); handoff_id or insight_id (sends that artifact, rendered to Markdown, as a .md file attachment); or artifact (last_handoff / last_correlation / last_onboarding / last_architecture, with project_id) to send the latest active artifact of that kind.', {
|
|
322
|
-
channel_id: z.string().describe('
|
|
349
|
+
channel_id: z.string().describe('Discord channel id from discord_list_channels.'),
|
|
323
350
|
content: z.string().optional().describe('Inline message text. Mutually exclusive with handoff_id / insight_id / artifact'),
|
|
324
|
-
handoff_id: z.string().optional().describe('
|
|
325
|
-
insight_id: z.string().optional().describe('
|
|
351
|
+
handoff_id: z.string().optional().describe('Id of a handoff (from list_handoffs) to render and attach as a .md file'),
|
|
352
|
+
insight_id: z.string().optional().describe('Id of an insight (from list_insights) to render and attach as a .md file'),
|
|
326
353
|
artifact: z
|
|
327
354
|
.enum(['last_handoff', 'last_correlation', 'last_onboarding', 'last_architecture'])
|
|
328
355
|
.optional()
|
|
@@ -341,12 +368,12 @@ server.tool('discord_send_message', 'Send to a Discord channel in your connected
|
|
|
341
368
|
}
|
|
342
369
|
});
|
|
343
370
|
// ── Tool: generate correlation insight ──────────────────────────────
|
|
344
|
-
server.tool('generate_correlation_insight', 'Generate a cross-source correlation
|
|
345
|
-
project_id: z.string().describe('
|
|
346
|
-
sources: z.array(SourceEnum).optional().describe('
|
|
371
|
+
server.tool('generate_correlation_insight', 'Generate a cross-source correlation insight: finds related events across different sources (e.g. a Slack thread, a Jira ticket and the PR that resolved it) and surfaces the links, patterns and open threads. Use when the user wants to understand how activity connects across tools. Runs synchronously and returns Markdown. Consumes credits, charged once on success. Call list_filter_options before using filters.', {
|
|
372
|
+
project_id: z.string().describe('Project id from list_projects to generate the insight for.'),
|
|
373
|
+
sources: z.array(SourceEnum).optional().describe('Restrict to these source ids (e.g. "github", "slack"). Unknown ids are rejected with 400.'),
|
|
347
374
|
filters: FiltersSchema,
|
|
348
|
-
lookback_hours: z.number().optional().describe('
|
|
349
|
-
max_events: z.number().optional().describe('
|
|
375
|
+
lookback_hours: z.number().int().optional().describe('Hours of activity to analyze (1-2160, default 168 = 7 days).'),
|
|
376
|
+
max_events: z.number().int().optional().describe('Cap on events processed (1-1000, default 150).'),
|
|
350
377
|
}, async ({ project_id, sources, filters, lookback_hours, max_events }) => {
|
|
351
378
|
try {
|
|
352
379
|
const res = await api.generateInsight(project_id, 'correlation', {
|
|
@@ -368,14 +395,14 @@ server.tool('generate_correlation_insight', 'Generate a cross-source correlation
|
|
|
368
395
|
}
|
|
369
396
|
});
|
|
370
397
|
// ── Tool: generate onboarding brief ──────────────────────────────────
|
|
371
|
-
server.tool('generate_onboarding_brief', 'Generate an onboarding brief
|
|
372
|
-
project_id: z.string().describe('
|
|
373
|
-
sources: z.array(SourceEnum).optional().describe('
|
|
398
|
+
server.tool('generate_onboarding_brief', 'Generate an onboarding brief: a getting-started guide for someone new to the project – key people, key decisions, pitfalls and recommended reading drawn from recent activity. Use when a new team member needs to get up to speed. Runs synchronously and returns Markdown. Consumes credits, charged once on success. Call list_filter_options before using filters.', {
|
|
399
|
+
project_id: z.string().describe('Project id from list_projects to generate the brief for.'),
|
|
400
|
+
sources: z.array(SourceEnum).optional().describe('Restrict to these source ids. Unknown ids are rejected with 400.'),
|
|
374
401
|
filters: FiltersSchema,
|
|
375
|
-
new_member_role: z.string().optional().describe('
|
|
376
|
-
focus_area: z.string().optional().describe('
|
|
377
|
-
lookback_days: z.number().optional().describe('
|
|
378
|
-
max_events: z.number().optional().describe('
|
|
402
|
+
new_member_role: z.string().optional().describe('Role/focus of the person being onboarded (e.g. "backend engineer"). Tailors the brief.'),
|
|
403
|
+
focus_area: z.string().optional().describe('Repository or feature area they will work on. Narrows the brief.'),
|
|
404
|
+
lookback_days: z.number().int().optional().describe('Days of history to review (1-365, default 30).'),
|
|
405
|
+
max_events: z.number().int().optional().describe('Cap on events processed (1-1000, default 400).'),
|
|
379
406
|
}, async ({ project_id, sources, filters, new_member_role, focus_area, lookback_days, max_events }) => {
|
|
380
407
|
try {
|
|
381
408
|
const res = await api.generateInsight(project_id, 'onboarding', {
|
|
@@ -399,13 +426,13 @@ server.tool('generate_onboarding_brief', 'Generate an onboarding brief AI insigh
|
|
|
399
426
|
}
|
|
400
427
|
});
|
|
401
428
|
// ── Tool: generate architecture insight ─────────────────────────────
|
|
402
|
-
server.tool('generate_architecture_insight', 'Generate an architecture insight
|
|
403
|
-
project_id: z.string().describe('
|
|
404
|
-
sources: z.array(SourceEnum).optional().describe('
|
|
429
|
+
server.tool('generate_architecture_insight', 'Generate an architecture insight: trade-offs, risks, patterns and recommendations inferred from the project\'s code activity (requires a connected code source – github, gitlab, bitbucket or azure_devops). This is the deepest and most expensive insight (it runs extended reasoning). Use for technical review of architectural direction. Runs synchronously and returns Markdown. Consumes credits, charged once on success. Call list_filter_options before using filters.', {
|
|
430
|
+
project_id: z.string().describe('Project id from list_projects to generate the insight for.'),
|
|
431
|
+
sources: z.array(SourceEnum).optional().describe('Restrict to these source ids. Unknown ids are rejected with 400.'),
|
|
405
432
|
filters: FiltersSchema,
|
|
406
|
-
focus_question: z.string().optional().describe('
|
|
407
|
-
lookback_days: z.number().optional().describe('
|
|
408
|
-
max_events: z.number().optional().describe('
|
|
433
|
+
focus_question: z.string().optional().describe('A specific architectural question or component to investigate (e.g. "is the billing layer coupled to providers?").'),
|
|
434
|
+
lookback_days: z.number().int().optional().describe('Days of history to review (1-365, default 14).'),
|
|
435
|
+
max_events: z.number().int().optional().describe('Cap on events processed (1-1000, default 250).'),
|
|
409
436
|
}, async ({ project_id, sources, filters, focus_question, lookback_days, max_events }) => {
|
|
410
437
|
try {
|
|
411
438
|
const res = await api.generateInsight(project_id, 'architecture', {
|
|
@@ -428,11 +455,11 @@ server.tool('generate_architecture_insight', 'Generate an architecture insight A
|
|
|
428
455
|
}
|
|
429
456
|
});
|
|
430
457
|
// ── Tool: list insights ─────────────────────────────────────────────
|
|
431
|
-
server.tool('list_insights', 'List
|
|
432
|
-
project_id: z.string().describe('
|
|
433
|
-
kind: z.enum(['onboarding_brief', 'cross_source_correlation', 'architecture_insight']).optional().describe('
|
|
434
|
-
status: z.enum(['active', 'archived', 'all']).default('active').describe('
|
|
435
|
-
limit: z.number().min(1).max(50).default(20).describe('Max
|
|
458
|
+
server.tool('list_insights', 'List existing insights for a project (newest first) with their content. Use this to read what has already been generated before spending credits on a new generate_*_insight. Each row\'s id can be sent to Discord via discord_send_message.', {
|
|
459
|
+
project_id: z.string().describe('Project id from list_projects to list insights for.'),
|
|
460
|
+
kind: z.enum(['onboarding_brief', 'cross_source_correlation', 'architecture_insight']).optional().describe('Restrict to one kind (matches the three generate_*_insight tools). Omit for all kinds.'),
|
|
461
|
+
status: z.enum(['active', 'archived', 'all']).default('active').describe('active = current, archived = superseded, all = both.'),
|
|
462
|
+
limit: z.number().int().min(1).max(50).default(20).describe('Max insights to return (1-50, default 20).'),
|
|
436
463
|
}, async ({ project_id, kind, status, limit }) => {
|
|
437
464
|
try {
|
|
438
465
|
const { insights } = await api.listInsights(project_id, kind, status, limit);
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flowrelay/mcp-server",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "Flow Relay MCP Server for Claude Desktop and Claude Code – handoffs, integrations
|
|
3
|
+
"version": "1.0.5",
|
|
4
|
+
"description": "Flow Relay MCP Server for Claude Desktop and Claude Code – handoffs, integrations and context events via natural conversation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"author": "
|
|
7
|
+
"author": "atrisorb",
|
|
8
8
|
"homepage": "https://www.flowrelay.it",
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|