From 7fb1e9ece4125bf0fedfe137eb3c45e37aeb414f Mon Sep 17 00:00:00 2001 From: Ompragash Viswanathan Date: Sat, 21 Feb 2026 02:03:26 +0530 Subject: [PATCH 1/2] feat: add CHORUS_TOOL_MODE for readonly/all tool filtering Split write tools (create_moment, delete_moment, upload_recording, delete_recording) into separate registration functions. The server reads CHORUS_TOOL_MODE env var at startup: - "readonly" (default): registers 35 read-only tools only - "all": registers all 39 tools including writes Integration tests now verify both modes: readonly excludes write tools, all mode includes them. --- src/index.ts | 18 +- src/tools/moments.ts | 3 + src/tools/video-conferences.ts | 3 + tests/integration/tool-registration.test.ts | 222 +++++++++++--------- tests/unit/tools/moments.test.ts | 3 +- tests/unit/tools/remaining-tools.test.ts | 3 +- 6 files changed, 151 insertions(+), 101 deletions(-) diff --git a/src/index.ts b/src/index.ts index c8d32db..a944c61 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,22 +10,24 @@ import { registerUserTools } from "./tools/users.js"; import { registerTeamTools } from "./tools/teams.js"; import { registerScorecardTools } from "./tools/scorecards.js"; import { registerPlaylistTools } from "./tools/playlists.js"; -import { registerMomentTools } from "./tools/moments.js"; +import { registerMomentTools, registerMomentWriteTools } from "./tools/moments.js"; import { registerEmailTools } from "./tools/emails.js"; import { registerEngagementTools } from "./tools/engagements.js"; import { registerReportTools } from "./tools/reports.js"; import { registerSavedSearchTools } from "./tools/saved-searches.js"; -import { registerVideoConferenceTools } from "./tools/video-conferences.js"; +import { registerVideoConferenceTools, registerVideoConferenceWriteTools } from "./tools/video-conferences.js"; import { registerIntegrationTools } from "./tools/integrations.js"; import { registerResources } from "./resources/index.js"; import { registerPrompts } from "./prompts/index.js"; +const toolMode = process.env.CHORUS_TOOL_MODE || "readonly"; + const server = new McpServer({ name: "chorus-mcp-server", version: "1.0.0", }); -// Register all tools +// Register read-only tools (always) registerConversationTools(server); registerUserTools(server); registerTeamTools(server); @@ -39,6 +41,12 @@ registerSavedSearchTools(server); registerVideoConferenceTools(server); registerIntegrationTools(server); +// Register write tools only when mode is "all" +if (toolMode === "all") { + registerMomentWriteTools(server); + registerVideoConferenceWriteTools(server); +} + // Register resources and prompts registerResources(server); registerPrompts(server); @@ -46,7 +54,7 @@ registerPrompts(server); async function runStdio(): Promise { const transport = new StdioServerTransport(); await server.connect(transport); - console.error("Chorus MCP server running via stdio"); + console.error(`Chorus MCP server running via stdio (tool mode: ${toolMode})`); } async function runHTTP(): Promise { @@ -67,7 +75,7 @@ async function runHTTP(): Promise { const port = parseInt(process.env.PORT || "3000"); app.listen(port, () => { - console.error(`Chorus MCP server running on http://localhost:${port}/mcp`); + console.error(`Chorus MCP server running on http://localhost:${port}/mcp (tool mode: ${toolMode})`); }); } diff --git a/src/tools/moments.ts b/src/tools/moments.ts index a8b4d30..7085a96 100644 --- a/src/tools/moments.ts +++ b/src/tools/moments.ts @@ -117,6 +117,9 @@ Returns: Moment with timestamp, title, description, type, and transcript text.`, } ); +} + +export function registerMomentWriteTools(server: McpServer): void { server.registerTool( "chorus_create_moment", { diff --git a/src/tools/video-conferences.ts b/src/tools/video-conferences.ts index 8a29e09..3ee8538 100644 --- a/src/tools/video-conferences.ts +++ b/src/tools/video-conferences.ts @@ -103,6 +103,9 @@ Returns: Conference details with title, date, participants, recording URL, and d } ); +} + +export function registerVideoConferenceWriteTools(server: McpServer): void { server.registerTool( "chorus_upload_recording", { diff --git a/tests/integration/tool-registration.test.ts b/tests/integration/tool-registration.test.ts index 888a3b1..fd2980c 100644 --- a/tests/integration/tool-registration.test.ts +++ b/tests/integration/tool-registration.test.ts @@ -4,122 +4,156 @@ import { registerUserTools } from '../../src/tools/users.js'; import { registerTeamTools } from '../../src/tools/teams.js'; import { registerScorecardTools } from '../../src/tools/scorecards.js'; import { registerPlaylistTools } from '../../src/tools/playlists.js'; -import { registerMomentTools } from '../../src/tools/moments.js'; +import { registerMomentTools, registerMomentWriteTools } from '../../src/tools/moments.js'; import { registerEmailTools } from '../../src/tools/emails.js'; import { registerEngagementTools } from '../../src/tools/engagements.js'; import { registerReportTools } from '../../src/tools/reports.js'; import { registerSavedSearchTools } from '../../src/tools/saved-searches.js'; -import { registerVideoConferenceTools } from '../../src/tools/video-conferences.js'; +import { registerVideoConferenceTools, registerVideoConferenceWriteTools } from '../../src/tools/video-conferences.js'; import { registerIntegrationTools } from '../../src/tools/integrations.js'; import { ANNOTATIONS } from '../../src/constants.js'; +function registerReadOnlyTools(server: McpServer): void { + registerConversationTools(server); + registerUserTools(server); + registerTeamTools(server); + registerScorecardTools(server); + registerPlaylistTools(server); + registerMomentTools(server); + registerEmailTools(server); + registerEngagementTools(server); + registerReportTools(server); + registerSavedSearchTools(server); + registerVideoConferenceTools(server); + registerIntegrationTools(server); +} + +function registerAllTools(server: McpServer): void { + registerReadOnlyTools(server); + registerMomentWriteTools(server); + registerVideoConferenceWriteTools(server); +} + +function getRegisteredTools(server: McpServer): Record { + return (server as any)._registeredTools || {}; +} + +const READ_ONLY_TOOLS = [ + 'chorus_list_conversations', + 'chorus_get_conversation', + 'chorus_get_transcript', + 'chorus_get_conversation_trackers', + 'chorus_search_conversations', + 'chorus_list_users', + 'chorus_get_user', + 'chorus_search_users', + 'chorus_list_teams', + 'chorus_get_team', + 'chorus_get_team_members', + 'chorus_list_scorecards', + 'chorus_get_scorecard', + 'chorus_list_scorecard_templates', + 'chorus_get_scorecard_template', + 'chorus_list_playlists', + 'chorus_get_playlist', + 'chorus_list_playlist_moments', + 'chorus_list_moments', + 'chorus_get_moment', + 'chorus_list_emails', + 'chorus_get_email', + 'chorus_filter_engagements', + 'chorus_get_engagement', + 'chorus_list_reports', + 'chorus_get_report', + 'chorus_get_activity_metrics', + 'chorus_list_video_conferences', + 'chorus_get_video_conference', + 'chorus_list_saved_searches', + 'chorus_get_saved_search', + 'chorus_execute_saved_search', + 'chorus_list_integrations', + 'chorus_get_integration', + 'chorus_get_session', +]; + +const WRITE_TOOLS = [ + 'chorus_create_moment', + 'chorus_delete_moment', + 'chorus_upload_recording', + 'chorus_delete_recording', +]; + describe('Tool Registration', () => { - let server: McpServer; - - beforeAll(() => { - server = new McpServer({ name: 'test', version: '1.0.0' }); - registerConversationTools(server); - registerUserTools(server); - registerTeamTools(server); - registerScorecardTools(server); - registerPlaylistTools(server); - registerMomentTools(server); - registerEmailTools(server); - registerEngagementTools(server); - registerReportTools(server); - registerSavedSearchTools(server); - registerVideoConferenceTools(server); - registerIntegrationTools(server); - }); + describe('readonly mode (default)', () => { + let server: McpServer; - function getRegisteredTools(): Record { - return (server as any)._registeredTools || {}; - } + beforeAll(() => { + server = new McpServer({ name: 'test', version: '1.0.0' }); + registerReadOnlyTools(server); + }); - it('registers all 38 expected tools', () => { - const tools = getRegisteredTools(); - const toolNames = Object.keys(tools); - expect(toolNames.length).toBe(39); - }); + it('registers 35 read-only tools', () => { + const tools = getRegisteredTools(server); + expect(Object.keys(tools).length).toBe(35); + }); - it('prefixes all tool names with chorus_', () => { - const tools = getRegisteredTools(); - for (const name of Object.keys(tools)) { - expect(name).toMatch(/^chorus_/); - } - }); + it.each(READ_ONLY_TOOLS)('%s is registered', (toolName) => { + const tools = getRegisteredTools(server); + expect(tools[toolName]).toBeDefined(); + }); - it('uses snake_case for all tool names', () => { - const tools = getRegisteredTools(); - for (const name of Object.keys(tools)) { - expect(name).toMatch(/^[a-z_]+$/); - } + it.each(WRITE_TOOLS)('%s is NOT registered', (toolName) => { + const tools = getRegisteredTools(server); + expect(tools[toolName]).toBeUndefined(); + }); }); - it('has no duplicate tool names', () => { - const tools = getRegisteredTools(); - const names = Object.keys(tools); - const unique = new Set(names); - expect(unique.size).toBe(names.length); - }); + describe('all mode', () => { + let server: McpServer; + + beforeAll(() => { + server = new McpServer({ name: 'test', version: '1.0.0' }); + registerAllTools(server); + }); + + it('registers all 39 tools', () => { + const tools = getRegisteredTools(server); + expect(Object.keys(tools).length).toBe(39); + }); - describe('read-only tools', () => { - const readOnlyTools = [ - 'chorus_list_conversations', - 'chorus_get_conversation', - 'chorus_get_transcript', - 'chorus_get_conversation_trackers', - 'chorus_search_conversations', - 'chorus_list_users', - 'chorus_get_user', - 'chorus_search_users', - 'chorus_list_teams', - 'chorus_get_team', - 'chorus_get_team_members', - 'chorus_list_scorecards', - 'chorus_get_scorecard', - 'chorus_list_scorecard_templates', - 'chorus_get_scorecard_template', - 'chorus_list_playlists', - 'chorus_get_playlist', - 'chorus_list_playlist_moments', - 'chorus_list_moments', - 'chorus_get_moment', - 'chorus_list_emails', - 'chorus_get_email', - 'chorus_filter_engagements', - 'chorus_get_engagement', - 'chorus_list_reports', - 'chorus_get_report', - 'chorus_get_activity_metrics', - 'chorus_list_video_conferences', - 'chorus_get_video_conference', - 'chorus_list_saved_searches', - 'chorus_get_saved_search', - 'chorus_execute_saved_search', - 'chorus_list_integrations', - 'chorus_get_integration', - 'chorus_get_session', - ]; - - it.each(readOnlyTools)('%s is registered', (toolName) => { - const tools = getRegisteredTools(); + it.each(WRITE_TOOLS)('%s is registered', (toolName) => { + const tools = getRegisteredTools(server); expect(tools[toolName]).toBeDefined(); }); }); - describe('write tools', () => { - const createTools = ['chorus_create_moment', 'chorus_upload_recording']; - const deleteTools = ['chorus_delete_moment', 'chorus_delete_recording']; + describe('tool naming conventions', () => { + let server: McpServer; - it.each(createTools)('%s is registered', (toolName) => { - const tools = getRegisteredTools(); - expect(tools[toolName]).toBeDefined(); + beforeAll(() => { + server = new McpServer({ name: 'test', version: '1.0.0' }); + registerAllTools(server); }); - it.each(deleteTools)('%s is registered', (toolName) => { - const tools = getRegisteredTools(); - expect(tools[toolName]).toBeDefined(); + it('prefixes all tool names with chorus_', () => { + const tools = getRegisteredTools(server); + for (const name of Object.keys(tools)) { + expect(name).toMatch(/^chorus_/); + } + }); + + it('uses snake_case for all tool names', () => { + const tools = getRegisteredTools(server); + for (const name of Object.keys(tools)) { + expect(name).toMatch(/^[a-z_]+$/); + } + }); + + it('has no duplicate tool names', () => { + const tools = getRegisteredTools(server); + const names = Object.keys(tools); + const unique = new Set(names); + expect(unique.size).toBe(names.length); }); }); diff --git a/tests/unit/tools/moments.test.ts b/tests/unit/tools/moments.test.ts index c669407..135e27e 100644 --- a/tests/unit/tools/moments.test.ts +++ b/tests/unit/tools/moments.test.ts @@ -1,6 +1,6 @@ import axios from 'axios'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; -import { registerMomentTools } from '../../../src/tools/moments.js'; +import { registerMomentTools, registerMomentWriteTools } from '../../../src/tools/moments.js'; import { makeMoment, wrapJsonApiList, wrapJsonApiSingle } from '../../fixtures/chorus-responses.js'; jest.mock('axios'); @@ -15,6 +15,7 @@ describe('Moment Tools', () => { process.env = { ...originalEnv, CHORUS_API_KEY: 'test-key' }; server = new McpServer({ name: 'test', version: '1.0.0' }); registerMomentTools(server); + registerMomentWriteTools(server); }); afterAll(() => { process.env = originalEnv; }); diff --git a/tests/unit/tools/remaining-tools.test.ts b/tests/unit/tools/remaining-tools.test.ts index 648b10a..f7bd697 100644 --- a/tests/unit/tools/remaining-tools.test.ts +++ b/tests/unit/tools/remaining-tools.test.ts @@ -6,7 +6,7 @@ import { registerEmailTools } from '../../../src/tools/emails.js'; import { registerEngagementTools } from '../../../src/tools/engagements.js'; import { registerReportTools } from '../../../src/tools/reports.js'; import { registerSavedSearchTools } from '../../../src/tools/saved-searches.js'; -import { registerVideoConferenceTools } from '../../../src/tools/video-conferences.js'; +import { registerVideoConferenceTools, registerVideoConferenceWriteTools } from '../../../src/tools/video-conferences.js'; import { registerIntegrationTools } from '../../../src/tools/integrations.js'; import { makeTeam, makeUser, makePlaylist, makeMoment, @@ -231,6 +231,7 @@ describe('Video Conference Tools', () => { process.env = { ...originalEnv, CHORUS_API_KEY: 'test-key' }; server = new McpServer({ name: 'test', version: '1.0.0' }); registerVideoConferenceTools(server); + registerVideoConferenceWriteTools(server); }); afterAll(() => { process.env = originalEnv; }); From 8213920e3f2711970b5c373f3468e1015e558dc8 Mon Sep 17 00:00:00 2001 From: Ompragash Viswanathan Date: Sat, 21 Feb 2026 02:05:52 +0530 Subject: [PATCH 2/2] fix: resolve 20 high severity vulnerabilities and relax node engine Override minimatch (>=10.2.1) and glob (>=11.0.0) in Jest's dependency tree to patch the ReDoS vulnerability (GHSA-3ppc-4f35-3m26). These are devDependencies only and do not affect the published package. Relax the engines.node field from pinned LTS caret ranges to >=18 so the server runs on any supported Node version including odd releases. --- package-lock.json | 157 +++++++++++++++++++++++++++------------------- package.json | 7 ++- 2 files changed, 97 insertions(+), 67 deletions(-) diff --git a/package-lock.json b/package-lock.json index 509eb35..b8deab9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,16 @@ { - "name": "@anthropic-chorus/chorus-mcp-server", + "name": "@opensourceops/chorus-mcp", "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "@anthropic-chorus/chorus-mcp-server", + "name": "@opensourceops/chorus-mcp", "version": "0.1.0", "license": "Apache-2.0", "dependencies": { "@modelcontextprotocol/sdk": "^1.26.0", + "@opensourceops/chorus-mcp": "^0.1.0", "axios": "^1.7.9", "express": "^4.21.0", "zod": "^3.23.8" @@ -27,7 +28,7 @@ "typescript": "^5.7.2" }, "engines": { - "node": "^20.9.0 || ^22.0.0 || ^24.0.0", + "node": ">=18", "npm": ">=9.0.0" } }, @@ -2265,6 +2266,25 @@ "node": ">= 0.6" } }, + "node_modules/@opensourceops/chorus-mcp": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@opensourceops/chorus-mcp/-/chorus-mcp-0.1.0.tgz", + "integrity": "sha512-0Km+U0FbeyZugSU+AJfr3l0rtP1PwzN15swwVZEuwNVbHSmoFv8X2zH+FH00+AC4JGWwUUplyOUuwfn8HSqQvA==", + "license": "Apache-2.0", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.26.0", + "axios": "^1.7.9", + "express": "^4.21.0", + "zod": "^3.23.8" + }, + "bin": { + "chorus-mcp-server": "dist/index.js" + }, + "engines": { + "node": "^20.9.0 || ^22.0.0 || ^24.0.0", + "npm": ">=9.0.0" + } + }, "node_modules/@sinclair/typebox": { "version": "0.27.10", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", @@ -2759,11 +2779,14 @@ } }, "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.3.tgz", + "integrity": "sha512-1pHv8LX9CpKut1Zp4EXey7Z8OfH11ONNH6Dhi2WDUt31VVZFXZzKwXcysBgqSumFCmR+0dqjMK5v5JiFHzi0+g==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": "20 || >=22" + } }, "node_modules/baseline-browser-mapping": { "version": "2.10.0", @@ -2818,14 +2841,16 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.2.tgz", + "integrity": "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==", "dev": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" } }, "node_modules/braces": { @@ -3099,13 +3124,6 @@ "node": ">= 0.8" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -3778,13 +3796,6 @@ "node": ">= 0.6" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3903,22 +3914,18 @@ } }, "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" @@ -4102,18 +4109,6 @@ "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -6012,16 +6007,19 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.2.tgz", + "integrity": "sha512-+G4CpNBxa5MprY+04MbgOw1v7So6n5JY166pFi9KfYwT78fxScCeSNQSNzp6dpPSW2rONOps6Ocam1wFhCgoVw==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^5.0.2" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -6034,6 +6032,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -6251,16 +6259,6 @@ "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -6277,6 +6275,33 @@ "dev": true, "license": "MIT" }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.2.6", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.2.6.tgz", + "integrity": "sha512-ESL2CrkS/2wTPfuend7Zhkzo2u0daGJ/A2VucJOgQ/C48S/zB8MMeMHSGKYpXhIjbPxfuezITkaBH1wqv00DDQ==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/path-to-regexp": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", diff --git a/package.json b/package.json index 9ccbdda..1b20ce4 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "dist" ], "engines": { - "node": "^20.9.0 || ^22.0.0 || ^24.0.0", + "node": ">=18", "npm": ">=9.0.0" }, "scripts": { @@ -47,6 +47,7 @@ }, "dependencies": { "@modelcontextprotocol/sdk": "^1.26.0", + "@opensourceops/chorus-mcp": "^0.1.0", "axios": "^1.7.9", "express": "^4.21.0", "zod": "^3.23.8" @@ -59,5 +60,9 @@ "ts-jest": "^29.1.1", "tsx": "^4.19.2", "typescript": "^5.7.2" + }, + "overrides": { + "minimatch": ">=10.2.1", + "glob": ">=11.0.0" } }