@doraincident/mcp-server 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/dist/client.d.ts CHANGED
@@ -31,5 +31,29 @@ export declare class DoraIncidentClient {
31
31
  priority?: string;
32
32
  }): Promise<unknown>;
33
33
  getTicket(id: string): Promise<unknown>;
34
+ describeFilterFields(): Promise<unknown>;
35
+ searchTickets(query: string, params?: {
36
+ limit?: number;
37
+ cursor?: string;
38
+ count?: boolean;
39
+ }): Promise<unknown>;
40
+ listSavedFilters(): Promise<unknown>;
41
+ runSavedFilter(id: string, params?: {
42
+ limit?: number;
43
+ cursor?: string;
44
+ count?: boolean;
45
+ }): Promise<unknown>;
34
46
  searchKnowledgeBase(query: string, limit?: number): Promise<unknown>;
47
+ roiValidationReport(): Promise<unknown>;
48
+ roiConcentration(): Promise<unknown>;
49
+ listRoiProviders(): Promise<unknown>;
50
+ listRoiArrangements(status?: string): Promise<unknown>;
51
+ getRoiArrangement(id: string): Promise<unknown>;
52
+ tagIncidentProvider(incidentId: string, providerId: string, note?: string): Promise<unknown>;
53
+ checkProviderGleif(providerId: string): Promise<unknown>;
54
+ listAiSystems(): Promise<unknown>;
55
+ getAiSystem(id: string): Promise<unknown>;
56
+ aiActValidationReport(): Promise<unknown>;
57
+ tagIncidentAiSystem(incidentId: string, aiSystemId: string, note?: string): Promise<unknown>;
58
+ assessAiIncident(incidentId: string, aiSystemId: string, bases: string[], widespread?: boolean, note?: string): Promise<unknown>;
35
59
  }
package/dist/client.js CHANGED
@@ -99,6 +99,29 @@ export class DoraIncidentClient {
99
99
  async getTicket(id) {
100
100
  return this.request(`/api/tickets/${id}`);
101
101
  }
102
+ // --- Ticket filtering (DIQL + saved filters) ---
103
+ async describeFilterFields() {
104
+ return this.request('/api/tickets/filter-fields');
105
+ }
106
+ async searchTickets(query, params) {
107
+ const q = new URLSearchParams({ q: query });
108
+ if (params?.limit)
109
+ q.set('limit', String(params.limit));
110
+ if (params?.cursor)
111
+ q.set('cursor', params.cursor);
112
+ if (params?.count)
113
+ q.set('count', 'true');
114
+ return this.request(`/api/tickets?${q.toString()}`);
115
+ }
116
+ async listSavedFilters() {
117
+ return this.request('/api/saved-filters');
118
+ }
119
+ async runSavedFilter(id, params) {
120
+ return this.request(`/api/saved-filters/${id}/run`, {
121
+ method: 'POST',
122
+ body: JSON.stringify(params ?? {}),
123
+ });
124
+ }
102
125
  // --- Knowledge base ---
103
126
  async searchKnowledgeBase(query, limit) {
104
127
  return this.request('/api/knowledge-base/search', {
@@ -106,4 +129,56 @@ export class DoraIncidentClient {
106
129
  body: JSON.stringify({ query, ...(limit ? { limit } : {}) }),
107
130
  });
108
131
  }
132
+ // --- Register of Information (DORA Chapter V) ---
133
+ async roiValidationReport() {
134
+ return this.request('/api/roi/validation');
135
+ }
136
+ async roiConcentration() {
137
+ return this.request('/api/roi/concentration');
138
+ }
139
+ async listRoiProviders() {
140
+ return this.request('/api/roi/providers');
141
+ }
142
+ async listRoiArrangements(status) {
143
+ const q = status ? `?status=${encodeURIComponent(status)}` : '';
144
+ return this.request(`/api/roi/arrangements${q}`);
145
+ }
146
+ async getRoiArrangement(id) {
147
+ return this.request(`/api/roi/arrangements/${encodeURIComponent(id)}`);
148
+ }
149
+ async tagIncidentProvider(incidentId, providerId, note) {
150
+ return this.request(`/api/incidents/${encodeURIComponent(incidentId)}/providers`, {
151
+ method: 'POST',
152
+ body: JSON.stringify({ roi_provider_id: providerId, ...(note ? { note } : {}) }),
153
+ });
154
+ }
155
+ async checkProviderGleif(providerId) {
156
+ return this.request(`/api/roi/providers/${encodeURIComponent(providerId)}/gleif`, { method: 'POST' });
157
+ }
158
+ // --- EU AI Act module ---
159
+ async listAiSystems() {
160
+ return this.request('/api/roi/ai-systems');
161
+ }
162
+ async getAiSystem(id) {
163
+ return this.request(`/api/roi/ai-systems/${encodeURIComponent(id)}`);
164
+ }
165
+ async aiActValidationReport() {
166
+ return this.request('/api/roi/ai-systems/validation');
167
+ }
168
+ async tagIncidentAiSystem(incidentId, aiSystemId, note) {
169
+ return this.request(`/api/incidents/${encodeURIComponent(incidentId)}/ai-systems`, {
170
+ method: 'POST',
171
+ body: JSON.stringify({ ai_system_id: aiSystemId, ...(note ? { note } : {}) }),
172
+ });
173
+ }
174
+ async assessAiIncident(incidentId, aiSystemId, bases, widespread, note) {
175
+ return this.request(`/api/incidents/${encodeURIComponent(incidentId)}/ai-systems/${encodeURIComponent(aiSystemId)}`, {
176
+ method: 'PUT',
177
+ body: JSON.stringify({
178
+ bases,
179
+ ...(widespread !== undefined ? { widespread } : {}),
180
+ ...(note ? { assessment_note: note } : {}),
181
+ }),
182
+ });
183
+ }
109
184
  }
package/dist/index.js CHANGED
@@ -5,6 +5,9 @@ import { DoraIncidentClient } from './client.js';
5
5
  import { alertToolDefs, handleAlertTool } from './tools/alerts.js';
6
6
  import { incidentToolDefs, handleIncidentTool } from './tools/incidents.js';
7
7
  import { knowledgeToolDefs, handleKnowledgeTool } from './tools/knowledge.js';
8
+ import { filterToolDefs, handleFilterTool } from './tools/filters.js';
9
+ import { roiToolDefs, handleRoiTool } from './tools/roi.js';
10
+ import { aiactToolDefs, handleAiactTool } from './tools/aiact.js';
8
11
  const DORAINCIDENT_URL = process.env.DORAINCIDENT_URL ?? 'https://www.doraincident.io';
9
12
  const DORAINCIDENT_API_KEY = process.env.DORAINCIDENT_API_KEY ?? '';
10
13
  if (!DORAINCIDENT_API_KEY) {
@@ -13,10 +16,13 @@ if (!DORAINCIDENT_API_KEY) {
13
16
  process.exit(1);
14
17
  }
15
18
  const client = new DoraIncidentClient(DORAINCIDENT_URL, DORAINCIDENT_API_KEY);
16
- const ALL_TOOLS = [...alertToolDefs, ...incidentToolDefs, ...knowledgeToolDefs];
19
+ const ALL_TOOLS = [...alertToolDefs, ...incidentToolDefs, ...knowledgeToolDefs, ...filterToolDefs, ...roiToolDefs, ...aiactToolDefs];
17
20
  const ALERT_TOOL_NAMES = new Set(alertToolDefs.map(t => t.name));
18
21
  const INCIDENT_TOOL_NAMES = new Set(incidentToolDefs.map(t => t.name));
19
22
  const KNOWLEDGE_TOOL_NAMES = new Set(knowledgeToolDefs.map(t => t.name));
23
+ const FILTER_TOOL_NAMES = new Set(filterToolDefs.map(t => t.name));
24
+ const ROI_TOOL_NAMES = new Set(roiToolDefs.map(t => t.name));
25
+ const AIACT_TOOL_NAMES = new Set(aiactToolDefs.map(t => t.name));
20
26
  const server = new Server({ name: 'doraincident', version: '0.1.0' }, {
21
27
  capabilities: {
22
28
  tools: {},
@@ -70,6 +76,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
70
76
  else if (KNOWLEDGE_TOOL_NAMES.has(name)) {
71
77
  text = await handleKnowledgeTool(name, safeArgs, client);
72
78
  }
79
+ else if (FILTER_TOOL_NAMES.has(name)) {
80
+ text = await handleFilterTool(name, safeArgs, client);
81
+ }
82
+ else if (ROI_TOOL_NAMES.has(name)) {
83
+ text = await handleRoiTool(name, safeArgs, client);
84
+ }
85
+ else if (AIACT_TOOL_NAMES.has(name)) {
86
+ text = await handleAiactTool(name, safeArgs, client);
87
+ }
73
88
  else {
74
89
  throw new Error(`Unknown tool: ${name}`);
75
90
  }
@@ -0,0 +1,4 @@
1
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
2
+ import type { DoraIncidentClient } from '../client.js';
3
+ export declare const aiactToolDefs: Tool[];
4
+ export declare function handleAiactTool(name: string, args: Record<string, unknown>, client: DoraIncidentClient): Promise<string>;
@@ -0,0 +1,92 @@
1
+ // EU AI Act module tools. Read-heavy by design, like the RoI set. The two
2
+ // writes (tagging a system on an incident, recording the Article 73
3
+ // assessment) are additive and audited; classification decisions, obligation
4
+ // states and FRIA content are deliberately NOT exposed here - those are
5
+ // formal compliance decisions recorded by a named person in the UI, and
6
+ // nothing on this surface can submit anything to any authority.
7
+ export const aiactToolDefs = [
8
+ {
9
+ name: 'list_ai_systems',
10
+ description: 'List the EU AI Act inventory: every registered AI system with its name, customer role (provider/deployer/' +
11
+ 'both), deployment status, supplier, GPAI dependency, and current classification (high_risk / ' +
12
+ 'not_high_risk_art6_3 / out_of_scope with the Annex III point). Use the id with get_ai_system, ' +
13
+ 'tag_incident_ai_system or assess_ai_incident.',
14
+ inputSchema: { type: 'object', properties: {}, required: [] },
15
+ },
16
+ {
17
+ name: 'get_ai_system',
18
+ description: 'Full detail of one AI system: classification decision history (append-only, with rationale, Annex III ' +
19
+ 'point, Article 6(3) condition, profiling flag), the twelve Article 26 deployer obligations with their ' +
20
+ 'states and the automatic audit-log evidence, the Article 27 FRIA record, linked DORA business functions, ' +
21
+ 'incident history, and the activation-gate status.',
22
+ inputSchema: {
23
+ type: 'object',
24
+ properties: { id: { type: 'string', description: 'AI system id (uuid) from list_ai_systems.' } },
25
+ required: ['id'],
26
+ },
27
+ },
28
+ {
29
+ name: 'ai_act_validation_report',
30
+ description: 'Run the EU AI Act module validation and return the report: systems in use without classification ' +
31
+ 'decisions, missing rationales, outstanding Article 26 obligations, missing or overdue Article 73 ' +
32
+ 'assessments, FRIA gaps for Annex III 5(b)/(c) deployers, and GPAI due-diligence gaps. Use this to answer ' +
33
+ '"where do we stand on AI Act readiness?".',
34
+ inputSchema: { type: 'object', properties: {}, required: [] },
35
+ },
36
+ {
37
+ name: 'tag_incident_ai_system',
38
+ description: 'Tag an AI system on an incident (the dual-threshold hook). Additive and audited: incidents never require ' +
39
+ 'a tag, and tagging never changes register content. Tagging a HIGH-RISK system is what opens the Article ' +
40
+ '73 serious-incident assessment alongside the DORA deadlines - follow up with assess_ai_incident.',
41
+ inputSchema: {
42
+ type: 'object',
43
+ properties: {
44
+ incident_id: { type: 'string', description: 'Incident id (uuid).' },
45
+ ai_system_id: { type: 'string', description: 'AI system id (uuid) from list_ai_systems.' },
46
+ note: { type: 'string', description: 'Optional note on how the system was involved.' },
47
+ },
48
+ required: ['incident_id', 'ai_system_id'],
49
+ },
50
+ },
51
+ {
52
+ name: 'assess_ai_incident',
53
+ description: 'Record the Article 73 serious-incident assessment for a tagged, high-risk AI system. Pass the Article ' +
54
+ '3(49) bases that apply: 49a (death or serious harm to health), 49b (serious and irreversible disruption ' +
55
+ 'of critical infrastructure), 49c (infringement of fundamental-rights obligations), 49d (serious harm to ' +
56
+ 'property or environment) - or an empty list for a documented negative assessment. The platform computes ' +
57
+ 'the outer clock (15 days default, 10 on death, 2 on widespread infringement or 49b) and the role-aware ' +
58
+ 'duty (a deployer informs the PROVIDER first per Art 26(5)). It drafts and tracks; a human submits any ' +
59
+ 'report; nothing is ever transmitted by the platform.',
60
+ inputSchema: {
61
+ type: 'object',
62
+ properties: {
63
+ incident_id: { type: 'string', description: 'Incident id (uuid).' },
64
+ ai_system_id: { type: 'string', description: 'AI system id (uuid); must already be tagged on the incident.' },
65
+ bases: {
66
+ type: 'array',
67
+ items: { type: 'string', enum: ['49a', '49b', '49c', '49d'] },
68
+ description: 'The Article 3(49) bases that apply; empty for a negative assessment.',
69
+ },
70
+ widespread: { type: 'boolean', description: 'Widespread infringement (Art 73(3): 2-day clock).' },
71
+ note: { type: 'string', description: 'Optional assessment note.' },
72
+ },
73
+ required: ['incident_id', 'ai_system_id', 'bases'],
74
+ },
75
+ },
76
+ ];
77
+ export async function handleAiactTool(name, args, client) {
78
+ switch (name) {
79
+ case 'list_ai_systems':
80
+ return JSON.stringify(await client.listAiSystems(), null, 2);
81
+ case 'get_ai_system':
82
+ return JSON.stringify(await client.getAiSystem(args.id), null, 2);
83
+ case 'ai_act_validation_report':
84
+ return JSON.stringify(await client.aiActValidationReport(), null, 2);
85
+ case 'tag_incident_ai_system':
86
+ return JSON.stringify(await client.tagIncidentAiSystem(args.incident_id, args.ai_system_id, args.note), null, 2);
87
+ case 'assess_ai_incident':
88
+ return JSON.stringify(await client.assessAiIncident(args.incident_id, args.ai_system_id, args.bases ?? [], args.widespread, args.note), null, 2);
89
+ default:
90
+ throw new Error(`Unknown AI Act tool: ${name}`);
91
+ }
92
+ }
@@ -0,0 +1,4 @@
1
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
2
+ import type { DoraIncidentClient } from '../client.js';
3
+ export declare const filterToolDefs: Tool[];
4
+ export declare function handleFilterTool(name: string, args: Record<string, unknown>, client: DoraIncidentClient): Promise<string>;
@@ -0,0 +1,75 @@
1
+ export const filterToolDefs = [
2
+ {
3
+ name: 'describe_filter_fields',
4
+ description: 'List the fields you can filter tickets by (built-in fields plus this tenant\'s custom fields), with each ' +
5
+ 'field\'s key, type, and the comparators it allows. Call this FIRST before writing a search_tickets query so ' +
6
+ 'you use real field keys and valid comparators instead of guessing. Custom fields are prefixed cf:.',
7
+ inputSchema: { type: 'object', properties: {}, required: [] },
8
+ },
9
+ {
10
+ name: 'search_tickets',
11
+ description: 'Search tickets with a DIQL query (a Jira-like filter language). Results are scoped to your permissions and ' +
12
+ 'cursor-paginated. Examples:\n' +
13
+ ' status IN (open, in_progress) AND priority = P1 AND assignee = currentUser()\n' +
14
+ ' labels CONTAINS ANY (payments, sepa) AND created_at >= -30d ORDER BY created_at DESC\n' +
15
+ ' ticket_type = bug AND dora_applicable = true AND status != closed\n' +
16
+ 'Comparators: =, !=, >, >=, <, <=, IN, NOT IN, CONTAINS [ANY|ALL|NONE], STARTS WITH, DOES NOT CONTAIN, ' +
17
+ 'IS EMPTY, IS NOT EMPTY, BETWEEN x AND y. Values with spaces need double quotes. Reference fields ' +
18
+ '(project, sprint, release, epic, parent, incident_id) filter by record id, not display name. Use ' +
19
+ 'describe_filter_fields to get valid field keys. To page, pass the returned next_cursor back as cursor.',
20
+ inputSchema: {
21
+ type: 'object',
22
+ properties: {
23
+ query: { type: 'string', description: 'A DIQL query string.' },
24
+ limit: { type: 'number', description: 'Page size (1-200, default 50).' },
25
+ cursor: { type: 'string', description: 'The next_cursor from a previous page.' },
26
+ count: { type: 'boolean', description: 'Also return a capped total count.' },
27
+ },
28
+ required: ['query'],
29
+ },
30
+ },
31
+ {
32
+ name: 'list_saved_filters',
33
+ description: 'List the saved ticket filters available to you: your own plus any shared with the tenant. Returns each ' +
34
+ 'filter\'s id, name, description, visibility, and whether you have favourited it. Use run_saved_filter with an ' +
35
+ 'id to execute one.',
36
+ inputSchema: { type: 'object', properties: {}, required: [] },
37
+ },
38
+ {
39
+ name: 'run_saved_filter',
40
+ description: 'Run a saved filter by id and return the matching tickets, scoped to YOUR permissions (so the same shared ' +
41
+ 'filter can return different rows for different people). Cursor-paginated. Get ids from list_saved_filters.',
42
+ inputSchema: {
43
+ type: 'object',
44
+ properties: {
45
+ id: { type: 'string', description: 'The saved filter id.' },
46
+ limit: { type: 'number', description: 'Page size (1-200, default 50).' },
47
+ cursor: { type: 'string', description: 'The next_cursor from a previous page.' },
48
+ count: { type: 'boolean', description: 'Also return a capped total count.' },
49
+ },
50
+ required: ['id'],
51
+ },
52
+ },
53
+ ];
54
+ export async function handleFilterTool(name, args, client) {
55
+ switch (name) {
56
+ case 'describe_filter_fields':
57
+ return JSON.stringify(await client.describeFilterFields(), null, 2);
58
+ case 'search_tickets':
59
+ return JSON.stringify(await client.searchTickets(args.query, {
60
+ limit: args.limit,
61
+ cursor: args.cursor,
62
+ count: args.count,
63
+ }), null, 2);
64
+ case 'list_saved_filters':
65
+ return JSON.stringify(await client.listSavedFilters(), null, 2);
66
+ case 'run_saved_filter':
67
+ return JSON.stringify(await client.runSavedFilter(args.id, {
68
+ limit: args.limit,
69
+ cursor: args.cursor,
70
+ count: args.count,
71
+ }), null, 2);
72
+ default:
73
+ throw new Error(`Unknown filter tool: ${name}`);
74
+ }
75
+ }
@@ -0,0 +1,4 @@
1
+ import type { Tool } from '@modelcontextprotocol/sdk/types.js';
2
+ import type { DoraIncidentClient } from '../client.js';
3
+ export declare const roiToolDefs: Tool[];
4
+ export declare function handleRoiTool(name: string, args: Record<string, unknown>, client: DoraIncidentClient): Promise<string>;
@@ -0,0 +1,100 @@
1
+ // Register of Information (DORA Chapter V third-party risk) tools.
2
+ // Read-heavy by design: the register is compliance data. The two writes here
3
+ // (incident tagging, GLEIF check) are additive and audited; neither can
4
+ // change register content, and nothing here can submit anything anywhere.
5
+ export const roiToolDefs = [
6
+ {
7
+ name: 'roi_validation_report',
8
+ description: 'Run the Register of Information validation and return the report: blocker/warning/info counts, whether the ' +
9
+ 'register is exportable, and every finding with its rule id, category (technical/business/foreign_key/' +
10
+ 'primary_key) and legal basis. Blockers prevent the register export. Use this to answer "is the register ' +
11
+ 'ready?" or "what is missing for DORA third-party compliance?".',
12
+ inputSchema: { type: 'object', properties: {}, required: [] },
13
+ },
14
+ {
15
+ name: 'roi_concentration',
16
+ description: 'The Article 29 ICT concentration risk view, computed live from active arrangements and rolled up by provider ' +
17
+ 'and identified ultimate-parent group. It includes dependency breadth, critical or important services, active ' +
18
+ 'provider spend share, worst-case substitutability, latest monitoring status, GLEIF status, incident history, ' +
19
+ 'and explainable risk indicators. No opaque score is invented.',
20
+ inputSchema: { type: 'object', properties: {}, required: [] },
21
+ },
22
+ {
23
+ name: 'list_roi_providers',
24
+ description: 'List the ICT third-party service providers in the Register of Information (B_05.01): id, legal name, ' +
25
+ 'identification code and type, headquarters country, GLEIF status. Use the id with tag_incident_provider or ' +
26
+ 'check_provider_gleif.',
27
+ inputSchema: { type: 'object', properties: {}, required: [] },
28
+ },
29
+ {
30
+ name: 'list_roi_arrangements',
31
+ description: 'List contractual arrangements (B_02.01): reference number, type, status (draft/active/terminated). ' +
32
+ 'Optionally filter by status. Use get_roi_arrangement for the full picture of one.',
33
+ inputSchema: {
34
+ type: 'object',
35
+ properties: {
36
+ status: { type: 'string', enum: ['draft', 'active', 'terminated'], description: 'Filter by lifecycle status.' },
37
+ },
38
+ required: [],
39
+ },
40
+ },
41
+ {
42
+ name: 'get_roi_arrangement',
43
+ description: 'Full detail of one contractual arrangement: services (B_02.02) with provider/function/entity, signatories, ' +
44
+ 'using entities, supply chain (B_05.02), assessments (B_07.01), the Article 30(2)/(3) provisions checklist, ' +
45
+ 'the Article 28(4) due-diligence checklist, structured material-subcontracting assessments, the tested exit ' +
46
+ 'strategy, whether the arrangement supports a critical or important function, and every outstanding item in ' +
47
+ 'the complete draft-to-active compliance gate.',
48
+ inputSchema: {
49
+ type: 'object',
50
+ properties: { id: { type: 'string', description: 'Arrangement id (uuid) from list_roi_arrangements.' } },
51
+ required: ['id'],
52
+ },
53
+ },
54
+ {
55
+ name: 'tag_incident_provider',
56
+ description: 'Tag an ICT third-party provider on an incident (Article 28(6) ongoing monitoring). Additive and audited: ' +
57
+ 'incidents never require a tag and tagging never changes register content, but the provider\'s incident ' +
58
+ 'history feeds the concentration view. Use during or after an incident when a third-party provider was ' +
59
+ 'involved (e.g. a cloud or payment-processor outage).',
60
+ inputSchema: {
61
+ type: 'object',
62
+ properties: {
63
+ incident_id: { type: 'string', description: 'Incident id (uuid).' },
64
+ provider_id: { type: 'string', description: 'RoI provider id (uuid) from list_roi_providers.' },
65
+ note: { type: 'string', description: 'Optional note on how the provider was involved.' },
66
+ },
67
+ required: ['incident_id', 'provider_id'],
68
+ },
69
+ },
70
+ {
71
+ name: 'check_provider_gleif',
72
+ description: 'Look up an LEI-coded provider\'s registration status on the public GLEIF API and cache it on the provider ' +
73
+ '(explicit enrichment; a lapsed LEI surfaces as a validation warning but never blocks anything).',
74
+ inputSchema: {
75
+ type: 'object',
76
+ properties: { provider_id: { type: 'string', description: 'RoI provider id (uuid) from list_roi_providers.' } },
77
+ required: ['provider_id'],
78
+ },
79
+ },
80
+ ];
81
+ export async function handleRoiTool(name, args, client) {
82
+ switch (name) {
83
+ case 'roi_validation_report':
84
+ return JSON.stringify(await client.roiValidationReport(), null, 2);
85
+ case 'roi_concentration':
86
+ return JSON.stringify(await client.roiConcentration(), null, 2);
87
+ case 'list_roi_providers':
88
+ return JSON.stringify(await client.listRoiProviders(), null, 2);
89
+ case 'list_roi_arrangements':
90
+ return JSON.stringify(await client.listRoiArrangements(args.status), null, 2);
91
+ case 'get_roi_arrangement':
92
+ return JSON.stringify(await client.getRoiArrangement(args.id), null, 2);
93
+ case 'tag_incident_provider':
94
+ return JSON.stringify(await client.tagIncidentProvider(args.incident_id, args.provider_id, args.note), null, 2);
95
+ case 'check_provider_gleif':
96
+ return JSON.stringify(await client.checkProviderGleif(args.provider_id), null, 2);
97
+ default:
98
+ throw new Error(`Unknown RoI tool: ${name}`);
99
+ }
100
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doraincident/mcp-server",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "MCP server for DoraIncident — query live incidents, acknowledge alerts, and track DORA regulatory deadlines from any AI assistant.",
5
5
  "type": "module",
6
6
  "private": false,
@@ -43,7 +43,9 @@
43
43
  "build": "tsc",
44
44
  "prepublishOnly": "npm run build",
45
45
  "start": "node dist/index.js",
46
- "dev": "node --loader ts-node/esm src/index.ts"
46
+ "dev": "node --loader ts-node/esm src/index.ts",
47
+ "release": "npm publish --access public",
48
+ "release:patch": "npm version patch --no-git-tag-version && npm publish --access public"
47
49
  },
48
50
  "dependencies": {
49
51
  "@modelcontextprotocol/sdk": "^1.0.0"