rc-ffs-mcp 1.0.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/README.md +231 -0
- package/dist/ffs-client.d.ts +103 -0
- package/dist/ffs-client.d.ts.map +1 -0
- package/dist/ffs-client.js +158 -0
- package/dist/ffs-client.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +404 -0
- package/dist/index.js.map +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# RC FFS MCP Server
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/rc-ffs-mcp)
|
|
4
|
+
|
|
5
|
+
A Model Context Protocol (MCP) server for interacting with RingCentral Feature Flag Service (FFS).
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **search_flag**: Search for feature flags by name (exact or fuzzy match)
|
|
10
|
+
- **list_flags**: List all feature flags with filtering options
|
|
11
|
+
- **create_flag**: Create new feature flags
|
|
12
|
+
- **update_flag**: Update flag properties (description, status, public)
|
|
13
|
+
- **update_rules**: Update or replace all rules for a flag
|
|
14
|
+
- **add_rule**: Add a single rule to an existing flag
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
### Install from npm
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g rc-ffs-mcp
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Or use directly with npx:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx rc-ffs-mcp
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Install from source
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
git clone https://github.com/ringcentral/rc-ffs-mcp.git
|
|
34
|
+
cd rc-ffs-mcp
|
|
35
|
+
npm install
|
|
36
|
+
npm run build
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Cursor IDE Configuration
|
|
40
|
+
|
|
41
|
+
Add the following to your Cursor MCP configuration file (`~/.cursor/mcp.json`):
|
|
42
|
+
|
|
43
|
+
### Using npm global install
|
|
44
|
+
|
|
45
|
+
```json
|
|
46
|
+
{
|
|
47
|
+
"mcpServers": {
|
|
48
|
+
"rc_ffs_mcp": {
|
|
49
|
+
"command": "rc-ffs-mcp",
|
|
50
|
+
"env": {
|
|
51
|
+
"FFS_BASE_URL": "http://your-ffs-server:8080"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Using npx
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"mcpServers": {
|
|
63
|
+
"rc_ffs_mcp": {
|
|
64
|
+
"command": "npx",
|
|
65
|
+
"args": ["-y", "rc-ffs-mcp"],
|
|
66
|
+
"env": {
|
|
67
|
+
"FFS_BASE_URL": "http://your-ffs-server:8080"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Using local installation
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"mcpServers": {
|
|
79
|
+
"rc_ffs_mcp": {
|
|
80
|
+
"command": "node",
|
|
81
|
+
"args": ["/path/to/rc-ffs-mcp/dist/index.js"],
|
|
82
|
+
"env": {
|
|
83
|
+
"FFS_BASE_URL": "http://your-ffs-server:8080"
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Environment Variables
|
|
91
|
+
|
|
92
|
+
| Variable | Description | Default |
|
|
93
|
+
|----------|-------------|---------|
|
|
94
|
+
| `FFS_BASE_URL` | Base URL of the FFS server | `http://aws16-c01-ffs01.ffs.svc.c01.eks02.k8s.aws16.lab.nordigy.ru:8080` |
|
|
95
|
+
|
|
96
|
+
## Available Tools
|
|
97
|
+
|
|
98
|
+
### 1. search_flag
|
|
99
|
+
|
|
100
|
+
Search for a feature flag by name.
|
|
101
|
+
|
|
102
|
+
**Parameters:**
|
|
103
|
+
- `name` (required): The name/ID of the feature flag
|
|
104
|
+
- `exact` (optional): If true, perform exact match. If false, perform fuzzy search (default: true)
|
|
105
|
+
|
|
106
|
+
**Example:**
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"name": "my_feature_flag",
|
|
110
|
+
"exact": true
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 2. list_flags
|
|
115
|
+
|
|
116
|
+
List all feature flags with optional filtering.
|
|
117
|
+
|
|
118
|
+
**Parameters:**
|
|
119
|
+
- `limit` (optional): Maximum number of flags to return (default: 100)
|
|
120
|
+
- `statusFilter` (optional): Filter by status: "Active", "Inactive", "Archived", or "All" (default: "All")
|
|
121
|
+
|
|
122
|
+
**Example:**
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"limit": 50,
|
|
126
|
+
"statusFilter": "Active"
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 3. create_flag
|
|
131
|
+
|
|
132
|
+
Create a new feature flag.
|
|
133
|
+
|
|
134
|
+
**Parameters:**
|
|
135
|
+
- `id` (required): Unique ID/name of the flag
|
|
136
|
+
- `dataType` (required): One of "Boolean", "Integer", "String", "JSON", "ListString", "ListInteger"
|
|
137
|
+
- `description` (optional): Description of the flag
|
|
138
|
+
- `status` (optional): Initial status: "Active", "Inactive", "Archived" (default: "Inactive")
|
|
139
|
+
- `public` (optional): Whether the flag is public (default: true)
|
|
140
|
+
|
|
141
|
+
**Example:**
|
|
142
|
+
```json
|
|
143
|
+
{
|
|
144
|
+
"id": "my_new_flag",
|
|
145
|
+
"description": "My new feature flag",
|
|
146
|
+
"dataType": "Boolean",
|
|
147
|
+
"status": "Inactive",
|
|
148
|
+
"public": true
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### 4. add_rule
|
|
153
|
+
|
|
154
|
+
Add a single rule to an existing feature flag.
|
|
155
|
+
|
|
156
|
+
**Parameters:**
|
|
157
|
+
- `flagId` (required): ID of the feature flag
|
|
158
|
+
- `value` (required): Value to return when rule matches
|
|
159
|
+
- `valueName` (optional): Name for the value
|
|
160
|
+
- `valueDescription` (optional): Description for the value
|
|
161
|
+
- `conditions` (required): Array of conditions
|
|
162
|
+
|
|
163
|
+
**Condition Properties:**
|
|
164
|
+
- `dimension`: One of "GlipUserId", "ExtensionId", "AccountId", "AppId", "BrandId", "EnvName", "EndpointId", "GlipCompanyId"
|
|
165
|
+
- `operator`: One of "Equal", "NotEqual", "Contains", "StartsWith", "EndsWith", "IsOneOf", "NotOneOf", "LessThan", "GreaterThan", etc.
|
|
166
|
+
- `argumentDataType`: "Integer", "String", or "ListString"
|
|
167
|
+
- `argument`: Value to compare against
|
|
168
|
+
- `description` (optional): Description of the condition
|
|
169
|
+
|
|
170
|
+
**Example:**
|
|
171
|
+
```json
|
|
172
|
+
{
|
|
173
|
+
"flagId": "my_flag",
|
|
174
|
+
"value": "true",
|
|
175
|
+
"valueName": "enabled",
|
|
176
|
+
"conditions": [
|
|
177
|
+
{
|
|
178
|
+
"dimension": "AccountId",
|
|
179
|
+
"operator": "Equal",
|
|
180
|
+
"argumentDataType": "Integer",
|
|
181
|
+
"argument": "12345",
|
|
182
|
+
"description": "Enable for account 12345"
|
|
183
|
+
}
|
|
184
|
+
]
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### 5. update_rules
|
|
189
|
+
|
|
190
|
+
Replace all rules for a feature flag.
|
|
191
|
+
|
|
192
|
+
**Parameters:**
|
|
193
|
+
- `flagId` (required): ID of the feature flag
|
|
194
|
+
- `rules` (required): Array of rules
|
|
195
|
+
|
|
196
|
+
### 6. update_flag
|
|
197
|
+
|
|
198
|
+
Update flag properties.
|
|
199
|
+
|
|
200
|
+
**Parameters:**
|
|
201
|
+
- `flagId` (required): ID of the feature flag
|
|
202
|
+
- `description` (optional): New description
|
|
203
|
+
- `status` (optional): New status
|
|
204
|
+
- `public` (optional): New public visibility
|
|
205
|
+
|
|
206
|
+
## Supported Dimensions
|
|
207
|
+
|
|
208
|
+
- GlipUserId
|
|
209
|
+
- ExtensionId
|
|
210
|
+
- AccountId
|
|
211
|
+
- AppId
|
|
212
|
+
- BrandId
|
|
213
|
+
- EnvName
|
|
214
|
+
- EndpointId
|
|
215
|
+
- GlipCompanyId
|
|
216
|
+
|
|
217
|
+
## Supported Operators
|
|
218
|
+
|
|
219
|
+
- Equal, NotEqual
|
|
220
|
+
- Contains, StartsWith, EndsWith
|
|
221
|
+
- NotStartsWith, NotEndsWith
|
|
222
|
+
- IsOneOf, NotOneOf
|
|
223
|
+
- LessThan, LessThanOrEqual
|
|
224
|
+
- GreaterThan, GreaterThanOrEqual
|
|
225
|
+
- SegmentMatch, NotSegmentMatch
|
|
226
|
+
- Percent
|
|
227
|
+
- SemVer comparisons (SemVerEqual, SemVerLessThan, etc.)
|
|
228
|
+
|
|
229
|
+
## License
|
|
230
|
+
|
|
231
|
+
MIT
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FFS API Types
|
|
3
|
+
*/
|
|
4
|
+
export interface FFSCondition {
|
|
5
|
+
id?: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
priority?: number;
|
|
8
|
+
dimension?: string;
|
|
9
|
+
operator: string;
|
|
10
|
+
argumentDataType?: string;
|
|
11
|
+
argument?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface FFSValue {
|
|
14
|
+
id?: string;
|
|
15
|
+
name?: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
value: string;
|
|
18
|
+
}
|
|
19
|
+
export interface FFSRule {
|
|
20
|
+
conditions: FFSCondition[];
|
|
21
|
+
value: FFSValue;
|
|
22
|
+
}
|
|
23
|
+
export interface FFSTag {
|
|
24
|
+
id: string;
|
|
25
|
+
accessControlId?: number;
|
|
26
|
+
}
|
|
27
|
+
export interface FFSFlag {
|
|
28
|
+
id: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
creationTime?: string;
|
|
31
|
+
lastModifiedTime?: string;
|
|
32
|
+
effectiveFrom?: string;
|
|
33
|
+
public: boolean;
|
|
34
|
+
status: 'Active' | 'Inactive' | 'Archived';
|
|
35
|
+
dataType: 'Boolean' | 'Integer' | 'String' | 'JSON' | 'ListString' | 'ListInteger';
|
|
36
|
+
rules: FFSRule[];
|
|
37
|
+
tags?: FFSTag[];
|
|
38
|
+
}
|
|
39
|
+
export interface CreateFlagRequest {
|
|
40
|
+
id: string;
|
|
41
|
+
description?: string;
|
|
42
|
+
effectiveFrom?: string;
|
|
43
|
+
public?: boolean;
|
|
44
|
+
status?: 'Active' | 'Inactive' | 'Archived';
|
|
45
|
+
dataType: 'Boolean' | 'Integer' | 'String' | 'JSON' | 'ListString' | 'ListInteger';
|
|
46
|
+
rules?: FFSRule[];
|
|
47
|
+
}
|
|
48
|
+
export interface CreateRuleInput {
|
|
49
|
+
value: string;
|
|
50
|
+
valueName?: string;
|
|
51
|
+
valueDescription?: string;
|
|
52
|
+
conditions: Omit<FFSCondition, 'id'>[];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* FFS API Client
|
|
56
|
+
*/
|
|
57
|
+
export declare class FFSClient {
|
|
58
|
+
private client;
|
|
59
|
+
private baseUrl;
|
|
60
|
+
constructor(baseUrl?: string);
|
|
61
|
+
/**
|
|
62
|
+
* Get all flags
|
|
63
|
+
*/
|
|
64
|
+
getAllFlags(): Promise<FFSFlag[]>;
|
|
65
|
+
/**
|
|
66
|
+
* Search flags by name (id)
|
|
67
|
+
*/
|
|
68
|
+
searchFlag(name: string): Promise<FFSFlag | null>;
|
|
69
|
+
/**
|
|
70
|
+
* Search flags by pattern (fuzzy search)
|
|
71
|
+
*/
|
|
72
|
+
searchFlagsByPattern(pattern: string): Promise<FFSFlag[]>;
|
|
73
|
+
/**
|
|
74
|
+
* Create a new flag
|
|
75
|
+
*/
|
|
76
|
+
createFlag(request: CreateFlagRequest): Promise<FFSFlag>;
|
|
77
|
+
/**
|
|
78
|
+
* Remove read-only fields from flag data before update
|
|
79
|
+
* Note: creationTime must be null for updates, but lastModifiedTime is required
|
|
80
|
+
*/
|
|
81
|
+
private removeReadOnlyFields;
|
|
82
|
+
/**
|
|
83
|
+
* Update a flag
|
|
84
|
+
*/
|
|
85
|
+
updateFlag(flagId: string, updates: Partial<FFSFlag>): Promise<FFSFlag>;
|
|
86
|
+
/**
|
|
87
|
+
* Update or create rules for a flag
|
|
88
|
+
*/
|
|
89
|
+
updateRules(flagId: string, rules: FFSRule[]): Promise<FFSFlag>;
|
|
90
|
+
/**
|
|
91
|
+
* Add a rule to a flag
|
|
92
|
+
*/
|
|
93
|
+
addRule(flagId: string, ruleInput: CreateRuleInput): Promise<FFSFlag>;
|
|
94
|
+
/**
|
|
95
|
+
* Delete a flag
|
|
96
|
+
*/
|
|
97
|
+
deleteFlag(flagId: string): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* Get server URL
|
|
100
|
+
*/
|
|
101
|
+
getServerUrl(): string;
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=ffs-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ffs-client.d.ts","sourceRoot":"","sources":["../src/ffs-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.FFSClient = void 0;
|
|
7
|
+
const axios_1 = __importDefault(require("axios"));
|
|
8
|
+
/**
|
|
9
|
+
* FFS API Client
|
|
10
|
+
*/
|
|
11
|
+
class FFSClient {
|
|
12
|
+
constructor(baseUrl = 'http://aws16-c01-ffs01.ffs.svc.c01.eks02.k8s.aws16.lab.nordigy.ru:8080') {
|
|
13
|
+
this.baseUrl = baseUrl;
|
|
14
|
+
this.client = axios_1.default.create({
|
|
15
|
+
baseURL: `${baseUrl}/feature-flags/management/v1`,
|
|
16
|
+
headers: {
|
|
17
|
+
'Content-Type': 'application/json',
|
|
18
|
+
},
|
|
19
|
+
timeout: 30000,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Get all flags
|
|
24
|
+
*/
|
|
25
|
+
async getAllFlags() {
|
|
26
|
+
const response = await this.client.get('/flags/');
|
|
27
|
+
// API returns { flags: [...] }
|
|
28
|
+
return response.data.flags || [];
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Search flags by name (id)
|
|
32
|
+
*/
|
|
33
|
+
async searchFlag(name) {
|
|
34
|
+
try {
|
|
35
|
+
const response = await this.client.get(`/flags/${encodeURIComponent(name)}/`);
|
|
36
|
+
return response.data;
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (error.response?.status === 404) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
throw error;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Search flags by pattern (fuzzy search)
|
|
47
|
+
*/
|
|
48
|
+
async searchFlagsByPattern(pattern) {
|
|
49
|
+
const allFlags = await this.getAllFlags();
|
|
50
|
+
const lowerPattern = pattern.toLowerCase();
|
|
51
|
+
return allFlags.filter(flag => flag.id.toLowerCase().includes(lowerPattern));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Create a new flag
|
|
55
|
+
*/
|
|
56
|
+
async createFlag(request) {
|
|
57
|
+
const payload = {
|
|
58
|
+
id: request.id,
|
|
59
|
+
description: request.description || '',
|
|
60
|
+
effectiveFrom: request.effectiveFrom || null,
|
|
61
|
+
public: request.public ?? true,
|
|
62
|
+
status: request.status || 'Inactive',
|
|
63
|
+
dataType: request.dataType,
|
|
64
|
+
rules: request.rules || [],
|
|
65
|
+
};
|
|
66
|
+
const response = await this.client.post('/flags/', payload);
|
|
67
|
+
return response.data;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Remove read-only fields from flag data before update
|
|
71
|
+
* Note: creationTime must be null for updates, but lastModifiedTime is required
|
|
72
|
+
*/
|
|
73
|
+
removeReadOnlyFields(flag) {
|
|
74
|
+
const { creationTime, ...writableFields } = flag;
|
|
75
|
+
return writableFields;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Update a flag
|
|
79
|
+
*/
|
|
80
|
+
async updateFlag(flagId, updates) {
|
|
81
|
+
// First get the existing flag
|
|
82
|
+
const existingFlag = await this.searchFlag(flagId);
|
|
83
|
+
if (!existingFlag) {
|
|
84
|
+
throw new Error(`Flag '${flagId}' not found`);
|
|
85
|
+
}
|
|
86
|
+
// Merge updates with existing data and remove read-only fields
|
|
87
|
+
const updatedFlag = this.removeReadOnlyFields({
|
|
88
|
+
...existingFlag,
|
|
89
|
+
...updates,
|
|
90
|
+
id: flagId, // Ensure ID doesn't change
|
|
91
|
+
});
|
|
92
|
+
const response = await this.client.put(`/flags/${encodeURIComponent(flagId)}/`, updatedFlag);
|
|
93
|
+
return response.data;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Update or create rules for a flag
|
|
97
|
+
*/
|
|
98
|
+
async updateRules(flagId, rules) {
|
|
99
|
+
const existingFlag = await this.searchFlag(flagId);
|
|
100
|
+
if (!existingFlag) {
|
|
101
|
+
throw new Error(`Flag '${flagId}' not found`);
|
|
102
|
+
}
|
|
103
|
+
// Update the flag with new rules and remove read-only fields
|
|
104
|
+
const updatedFlag = this.removeReadOnlyFields({
|
|
105
|
+
...existingFlag,
|
|
106
|
+
rules: rules,
|
|
107
|
+
});
|
|
108
|
+
const response = await this.client.put(`/flags/${encodeURIComponent(flagId)}/`, updatedFlag);
|
|
109
|
+
return response.data;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Add a rule to a flag
|
|
113
|
+
*/
|
|
114
|
+
async addRule(flagId, ruleInput) {
|
|
115
|
+
const existingFlag = await this.searchFlag(flagId);
|
|
116
|
+
if (!existingFlag) {
|
|
117
|
+
throw new Error(`Flag '${flagId}' not found`);
|
|
118
|
+
}
|
|
119
|
+
// Calculate next priority for conditions
|
|
120
|
+
let maxPriority = 0;
|
|
121
|
+
existingFlag.rules.forEach(rule => {
|
|
122
|
+
rule.conditions.forEach(cond => {
|
|
123
|
+
if (cond.priority && cond.priority > maxPriority) {
|
|
124
|
+
maxPriority = cond.priority;
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
// Create conditions with priorities
|
|
129
|
+
const conditions = ruleInput.conditions.map((cond, idx) => ({
|
|
130
|
+
...cond,
|
|
131
|
+
priority: maxPriority + idx + 1,
|
|
132
|
+
}));
|
|
133
|
+
const newRule = {
|
|
134
|
+
conditions,
|
|
135
|
+
value: {
|
|
136
|
+
name: ruleInput.valueName || ruleInput.value,
|
|
137
|
+
description: ruleInput.valueDescription || '',
|
|
138
|
+
value: ruleInput.value,
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
const updatedRules = [...existingFlag.rules, newRule];
|
|
142
|
+
return this.updateRules(flagId, updatedRules);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Delete a flag
|
|
146
|
+
*/
|
|
147
|
+
async deleteFlag(flagId) {
|
|
148
|
+
await this.client.delete(`/flags/${encodeURIComponent(flagId)}/`);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Get server URL
|
|
152
|
+
*/
|
|
153
|
+
getServerUrl() {
|
|
154
|
+
return this.baseUrl;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
exports.FFSClient = FFSClient;
|
|
158
|
+
//# sourceMappingURL=ffs-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ffs-client.js","sourceRoot":"","sources":["../src/ffs-client.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
|
|
5
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
6
|
+
const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
|
|
7
|
+
const ffs_client_js_1 = require("./ffs-client.js");
|
|
8
|
+
// Initialize FFS client with default URL
|
|
9
|
+
const FFS_BASE_URL = process.env.FFS_BASE_URL || 'http://aws16-c01-ffs01.ffs.svc.c01.eks02.k8s.aws16.lab.nordigy.ru:8080';
|
|
10
|
+
const ffsClient = new ffs_client_js_1.FFSClient(FFS_BASE_URL);
|
|
11
|
+
// Define available tools
|
|
12
|
+
const tools = [
|
|
13
|
+
{
|
|
14
|
+
name: 'search_flag',
|
|
15
|
+
description: 'Search for a feature flag by name (exact match or pattern). Returns the flag details including rules and conditions.',
|
|
16
|
+
inputSchema: {
|
|
17
|
+
type: 'object',
|
|
18
|
+
properties: {
|
|
19
|
+
name: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
description: 'The name/ID of the feature flag to search for. Can be exact name or a pattern for fuzzy search.',
|
|
22
|
+
},
|
|
23
|
+
exact: {
|
|
24
|
+
type: 'boolean',
|
|
25
|
+
description: 'If true, perform exact match. If false, perform fuzzy search (default: true).',
|
|
26
|
+
default: true,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
required: ['name'],
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'list_flags',
|
|
34
|
+
description: 'List all feature flags with summary information including id, status, dataType, and values count.',
|
|
35
|
+
inputSchema: {
|
|
36
|
+
type: 'object',
|
|
37
|
+
properties: {
|
|
38
|
+
limit: {
|
|
39
|
+
type: 'number',
|
|
40
|
+
description: 'Maximum number of flags to return (default: 100)',
|
|
41
|
+
default: 100,
|
|
42
|
+
},
|
|
43
|
+
statusFilter: {
|
|
44
|
+
type: 'string',
|
|
45
|
+
enum: ['Active', 'Inactive', 'Archived', 'All'],
|
|
46
|
+
description: 'Filter flags by status (default: All)',
|
|
47
|
+
default: 'All',
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
name: 'create_flag',
|
|
54
|
+
description: 'Create a new feature flag with the specified name and configuration.',
|
|
55
|
+
inputSchema: {
|
|
56
|
+
type: 'object',
|
|
57
|
+
properties: {
|
|
58
|
+
id: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
description: 'The unique ID/name of the feature flag.',
|
|
61
|
+
},
|
|
62
|
+
description: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
description: 'Description of the feature flag.',
|
|
65
|
+
},
|
|
66
|
+
dataType: {
|
|
67
|
+
type: 'string',
|
|
68
|
+
enum: ['Boolean', 'Integer', 'String', 'JSON', 'ListString', 'ListInteger'],
|
|
69
|
+
description: 'The data type of the flag value.',
|
|
70
|
+
},
|
|
71
|
+
status: {
|
|
72
|
+
type: 'string',
|
|
73
|
+
enum: ['Active', 'Inactive', 'Archived'],
|
|
74
|
+
description: 'Initial status of the flag (default: Inactive).',
|
|
75
|
+
default: 'Inactive',
|
|
76
|
+
},
|
|
77
|
+
public: {
|
|
78
|
+
type: 'boolean',
|
|
79
|
+
description: 'Whether the flag is public (default: true).',
|
|
80
|
+
default: true,
|
|
81
|
+
},
|
|
82
|
+
defaultValue: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: 'The default value for the flag.',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
required: ['id', 'dataType'],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: 'update_rules',
|
|
92
|
+
description: 'Update or create rules for a specific feature flag. This replaces all existing rules with the provided ones.',
|
|
93
|
+
inputSchema: {
|
|
94
|
+
type: 'object',
|
|
95
|
+
properties: {
|
|
96
|
+
flagId: {
|
|
97
|
+
type: 'string',
|
|
98
|
+
description: 'The ID of the feature flag to update.',
|
|
99
|
+
},
|
|
100
|
+
rules: {
|
|
101
|
+
type: 'array',
|
|
102
|
+
description: 'Array of rules to set for the flag.',
|
|
103
|
+
items: {
|
|
104
|
+
type: 'object',
|
|
105
|
+
properties: {
|
|
106
|
+
priority: {
|
|
107
|
+
type: 'number',
|
|
108
|
+
description: 'Priority of the rule (lower = higher priority).',
|
|
109
|
+
},
|
|
110
|
+
value: {
|
|
111
|
+
type: 'string',
|
|
112
|
+
description: 'The value to return when this rule matches.',
|
|
113
|
+
},
|
|
114
|
+
conditions: {
|
|
115
|
+
type: 'array',
|
|
116
|
+
description: 'Array of conditions for this rule (AND logic).',
|
|
117
|
+
items: {
|
|
118
|
+
type: 'object',
|
|
119
|
+
properties: {
|
|
120
|
+
description: {
|
|
121
|
+
type: 'string',
|
|
122
|
+
description: 'Description of the condition.',
|
|
123
|
+
},
|
|
124
|
+
dimension: {
|
|
125
|
+
type: 'string',
|
|
126
|
+
enum: ['GlipUserId', 'ExtensionId', 'AccountId', 'AppId', 'BrandId', 'EnvName', 'EndpointId', 'GlipCompanyId'],
|
|
127
|
+
description: 'The dimension to evaluate.',
|
|
128
|
+
},
|
|
129
|
+
customDimension: {
|
|
130
|
+
type: 'string',
|
|
131
|
+
description: 'Custom dimension name (if dimension is not specified).',
|
|
132
|
+
},
|
|
133
|
+
operator: {
|
|
134
|
+
type: 'string',
|
|
135
|
+
enum: ['Equal', 'NotEqual', 'Contains', 'StartsWith', 'EndsWith', 'NotStartsWith', 'NotEndsWith', 'IsOneOf', 'NotOneOf', 'LessThan', 'LessThanOrEqual', 'GreaterThan', 'GreaterThanOrEqual', 'SegmentMatch', 'NotSegmentMatch', 'Percent', 'SemVerEqual', 'NotSemVerEqual', 'SemVerLessThan', 'SemVerLessThanOrEqual', 'SemVerGreaterThan', 'SemVerGreaterThanOrEqual'],
|
|
136
|
+
description: 'The comparison operator.',
|
|
137
|
+
},
|
|
138
|
+
argumentDataType: {
|
|
139
|
+
type: 'string',
|
|
140
|
+
enum: ['Integer', 'String'],
|
|
141
|
+
description: 'Data type of the argument.',
|
|
142
|
+
},
|
|
143
|
+
argument: {
|
|
144
|
+
type: 'string',
|
|
145
|
+
description: 'The value to compare against.',
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
required: ['operator', 'argumentDataType', 'argument'],
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
required: ['priority', 'value', 'conditions'],
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
required: ['flagId', 'rules'],
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
name: 'add_rule',
|
|
161
|
+
description: 'Add a single rule to an existing feature flag without removing existing rules.',
|
|
162
|
+
inputSchema: {
|
|
163
|
+
type: 'object',
|
|
164
|
+
properties: {
|
|
165
|
+
flagId: {
|
|
166
|
+
type: 'string',
|
|
167
|
+
description: 'The ID of the feature flag.',
|
|
168
|
+
},
|
|
169
|
+
value: {
|
|
170
|
+
type: 'string',
|
|
171
|
+
description: 'The value to return when this rule matches.',
|
|
172
|
+
},
|
|
173
|
+
valueName: {
|
|
174
|
+
type: 'string',
|
|
175
|
+
description: 'Optional name for the value.',
|
|
176
|
+
},
|
|
177
|
+
valueDescription: {
|
|
178
|
+
type: 'string',
|
|
179
|
+
description: 'Optional description for the value.',
|
|
180
|
+
},
|
|
181
|
+
conditions: {
|
|
182
|
+
type: 'array',
|
|
183
|
+
description: 'Array of conditions for this rule.',
|
|
184
|
+
items: {
|
|
185
|
+
type: 'object',
|
|
186
|
+
properties: {
|
|
187
|
+
description: {
|
|
188
|
+
type: 'string',
|
|
189
|
+
},
|
|
190
|
+
dimension: {
|
|
191
|
+
type: 'string',
|
|
192
|
+
enum: ['GlipUserId', 'ExtensionId', 'AccountId', 'AppId', 'BrandId', 'EnvName', 'EndpointId', 'GlipCompanyId'],
|
|
193
|
+
},
|
|
194
|
+
operator: {
|
|
195
|
+
type: 'string',
|
|
196
|
+
enum: ['Equal', 'NotEqual', 'Contains', 'StartsWith', 'EndsWith', 'NotStartsWith', 'NotEndsWith', 'IsOneOf', 'NotOneOf', 'LessThan', 'LessThanOrEqual', 'GreaterThan', 'GreaterThanOrEqual', 'SegmentMatch', 'NotSegmentMatch', 'Percent', 'SemVerEqual', 'NotSemVerEqual', 'SemVerLessThan', 'SemVerLessThanOrEqual', 'SemVerGreaterThan', 'SemVerGreaterThanOrEqual'],
|
|
197
|
+
},
|
|
198
|
+
argumentDataType: {
|
|
199
|
+
type: 'string',
|
|
200
|
+
enum: ['Integer', 'String', 'ListString'],
|
|
201
|
+
},
|
|
202
|
+
argument: {
|
|
203
|
+
type: 'string',
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
required: ['operator', 'argumentDataType', 'argument'],
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
required: ['flagId', 'value', 'conditions'],
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
{
|
|
214
|
+
name: 'update_flag',
|
|
215
|
+
description: 'Update flag properties like description, status, public visibility, or default value.',
|
|
216
|
+
inputSchema: {
|
|
217
|
+
type: 'object',
|
|
218
|
+
properties: {
|
|
219
|
+
flagId: {
|
|
220
|
+
type: 'string',
|
|
221
|
+
description: 'The ID of the feature flag to update.',
|
|
222
|
+
},
|
|
223
|
+
description: {
|
|
224
|
+
type: 'string',
|
|
225
|
+
description: 'New description for the flag.',
|
|
226
|
+
},
|
|
227
|
+
status: {
|
|
228
|
+
type: 'string',
|
|
229
|
+
enum: ['Active', 'Inactive', 'Archived'],
|
|
230
|
+
description: 'New status for the flag.',
|
|
231
|
+
},
|
|
232
|
+
public: {
|
|
233
|
+
type: 'boolean',
|
|
234
|
+
description: 'Whether the flag should be public.',
|
|
235
|
+
},
|
|
236
|
+
defaultValue: {
|
|
237
|
+
type: 'string',
|
|
238
|
+
description: 'New default value for the flag.',
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
required: ['flagId'],
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
];
|
|
245
|
+
// Create MCP server
|
|
246
|
+
const server = new index_js_1.Server({
|
|
247
|
+
name: 'rc_ffs_mcp',
|
|
248
|
+
version: '1.0.0',
|
|
249
|
+
}, {
|
|
250
|
+
capabilities: {
|
|
251
|
+
tools: {},
|
|
252
|
+
},
|
|
253
|
+
});
|
|
254
|
+
// Handle list tools request
|
|
255
|
+
server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
|
|
256
|
+
return { tools };
|
|
257
|
+
});
|
|
258
|
+
// Handle tool calls
|
|
259
|
+
server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
|
|
260
|
+
const { name, arguments: args } = request.params;
|
|
261
|
+
try {
|
|
262
|
+
switch (name) {
|
|
263
|
+
case 'search_flag': {
|
|
264
|
+
const { name: flagName, exact = true } = args;
|
|
265
|
+
if (exact) {
|
|
266
|
+
const flag = await ffsClient.searchFlag(flagName);
|
|
267
|
+
if (flag) {
|
|
268
|
+
return {
|
|
269
|
+
content: [
|
|
270
|
+
{
|
|
271
|
+
type: 'text',
|
|
272
|
+
text: JSON.stringify(flag, null, 2),
|
|
273
|
+
},
|
|
274
|
+
],
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
return {
|
|
279
|
+
content: [
|
|
280
|
+
{
|
|
281
|
+
type: 'text',
|
|
282
|
+
text: `Flag '${flagName}' not found.`,
|
|
283
|
+
},
|
|
284
|
+
],
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
const flags = await ffsClient.searchFlagsByPattern(flagName);
|
|
290
|
+
return {
|
|
291
|
+
content: [
|
|
292
|
+
{
|
|
293
|
+
type: 'text',
|
|
294
|
+
text: `Found ${flags.length} flags matching '${flagName}':\n${JSON.stringify(flags, null, 2)}`,
|
|
295
|
+
},
|
|
296
|
+
],
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
case 'list_flags': {
|
|
301
|
+
const { limit = 100, statusFilter = 'All' } = args;
|
|
302
|
+
let flags = await ffsClient.getAllFlags();
|
|
303
|
+
if (statusFilter !== 'All') {
|
|
304
|
+
flags = flags.filter(f => f.status === statusFilter);
|
|
305
|
+
}
|
|
306
|
+
flags = flags.slice(0, limit);
|
|
307
|
+
return {
|
|
308
|
+
content: [
|
|
309
|
+
{
|
|
310
|
+
type: 'text',
|
|
311
|
+
text: `Found ${flags.length} flags:\n${JSON.stringify(flags, null, 2)}`,
|
|
312
|
+
},
|
|
313
|
+
],
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
case 'create_flag': {
|
|
317
|
+
const createRequest = args;
|
|
318
|
+
const newFlag = await ffsClient.createFlag(createRequest);
|
|
319
|
+
return {
|
|
320
|
+
content: [
|
|
321
|
+
{
|
|
322
|
+
type: 'text',
|
|
323
|
+
text: `Successfully created flag '${newFlag.id}':\n${JSON.stringify(newFlag, null, 2)}`,
|
|
324
|
+
},
|
|
325
|
+
],
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
case 'update_rules': {
|
|
329
|
+
const { flagId, rules } = args;
|
|
330
|
+
const updatedFlag = await ffsClient.updateRules(flagId, rules);
|
|
331
|
+
return {
|
|
332
|
+
content: [
|
|
333
|
+
{
|
|
334
|
+
type: 'text',
|
|
335
|
+
text: `Successfully updated rules for flag '${flagId}':\n${JSON.stringify(updatedFlag, null, 2)}`,
|
|
336
|
+
},
|
|
337
|
+
],
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
case 'add_rule': {
|
|
341
|
+
const { flagId, value, valueName, valueDescription, conditions } = args;
|
|
342
|
+
const ruleInput = {
|
|
343
|
+
value,
|
|
344
|
+
valueName,
|
|
345
|
+
valueDescription,
|
|
346
|
+
conditions,
|
|
347
|
+
};
|
|
348
|
+
const updatedFlag = await ffsClient.addRule(flagId, ruleInput);
|
|
349
|
+
return {
|
|
350
|
+
content: [
|
|
351
|
+
{
|
|
352
|
+
type: 'text',
|
|
353
|
+
text: `Successfully added rule to flag '${flagId}':\n${JSON.stringify(updatedFlag, null, 2)}`,
|
|
354
|
+
},
|
|
355
|
+
],
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
case 'update_flag': {
|
|
359
|
+
const { flagId, ...updates } = args;
|
|
360
|
+
const updatedFlag = await ffsClient.updateFlag(flagId, updates);
|
|
361
|
+
return {
|
|
362
|
+
content: [
|
|
363
|
+
{
|
|
364
|
+
type: 'text',
|
|
365
|
+
text: `Successfully updated flag '${flagId}':\n${JSON.stringify(updatedFlag, null, 2)}`,
|
|
366
|
+
},
|
|
367
|
+
],
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
default:
|
|
371
|
+
return {
|
|
372
|
+
content: [
|
|
373
|
+
{
|
|
374
|
+
type: 'text',
|
|
375
|
+
text: `Unknown tool: ${name}`,
|
|
376
|
+
},
|
|
377
|
+
],
|
|
378
|
+
isError: true,
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
catch (error) {
|
|
383
|
+
return {
|
|
384
|
+
content: [
|
|
385
|
+
{
|
|
386
|
+
type: 'text',
|
|
387
|
+
text: `Error: ${error.message || String(error)}`,
|
|
388
|
+
},
|
|
389
|
+
],
|
|
390
|
+
isError: true,
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
// Start the server
|
|
395
|
+
async function main() {
|
|
396
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
397
|
+
await server.connect(transport);
|
|
398
|
+
console.error('RC FFS MCP server started');
|
|
399
|
+
}
|
|
400
|
+
main().catch((error) => {
|
|
401
|
+
console.error('Fatal error:', error);
|
|
402
|
+
process.exit(1);
|
|
403
|
+
});
|
|
404
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "rc-ffs-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for RingCentral Feature Flag Service (FFS) - provides tools to search, create, and manage feature flags",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"rc-ffs-mcp": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"start": "node dist/index.js",
|
|
17
|
+
"dev": "ts-node src/index.ts",
|
|
18
|
+
"prepublishOnly": "npm run build",
|
|
19
|
+
"test": "node test-client.js"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"mcp",
|
|
23
|
+
"model-context-protocol",
|
|
24
|
+
"ringcentral",
|
|
25
|
+
"ffs",
|
|
26
|
+
"feature-flags",
|
|
27
|
+
"feature-toggle",
|
|
28
|
+
"cursor",
|
|
29
|
+
"ai",
|
|
30
|
+
"llm"
|
|
31
|
+
],
|
|
32
|
+
"author": "RingCentral",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/ringcentral/rc-ffs-mcp"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/ringcentral/rc-ffs-mcp#readme",
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/ringcentral/rc-ffs-mcp/issues"
|
|
41
|
+
},
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=18.0.0"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
47
|
+
"axios": "^1.6.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^20.10.0",
|
|
51
|
+
"typescript": "^5.3.0",
|
|
52
|
+
"ts-node": "^10.9.0"
|
|
53
|
+
}
|
|
54
|
+
}
|