@fruition/fcp-mcp-server 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 +151 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +433 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# FCP MCP Server
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server that gives Claude Code direct access to the FCP Launch Coordination System.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
### Tools
|
|
8
|
+
|
|
9
|
+
| Tool | Description |
|
|
10
|
+
|------|-------------|
|
|
11
|
+
| `fcp_list_launches` | List launches with optional filters (status, platform, upcoming days) |
|
|
12
|
+
| `fcp_get_launch` | Get detailed launch info including checklist and team |
|
|
13
|
+
| `fcp_get_legacy_access` | Get legacy hosting access info for migrations |
|
|
14
|
+
| `fcp_get_checklist` | Get checklist items with Claude instructions |
|
|
15
|
+
| `fcp_update_checklist_item` | Update checklist item status as you complete work |
|
|
16
|
+
| `fcp_add_progress_note` | Add progress notes to document work done |
|
|
17
|
+
| `fcp_get_claude_md` | Generate CLAUDE.md content for a launch |
|
|
18
|
+
|
|
19
|
+
### Resources
|
|
20
|
+
|
|
21
|
+
- `fcp://launches` - List of all launches
|
|
22
|
+
- `fcp://launches/{id}` - Single launch details
|
|
23
|
+
|
|
24
|
+
## Setup
|
|
25
|
+
|
|
26
|
+
### 1. Install Dependencies
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
cd mcp-server
|
|
30
|
+
npm install
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2. Build
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm run build
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### 3. Configure Environment
|
|
40
|
+
|
|
41
|
+
Create a `.env` file or set environment variables:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
FCP_API_URL=https://fcp.fru.io # or http://localhost:3090 for local dev
|
|
45
|
+
FCP_API_TOKEN=your_api_token # Get from FCP Settings > API Tokens
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 4. Add to Claude Code
|
|
49
|
+
|
|
50
|
+
Add to your Claude Code settings (`~/.claude/settings.json`):
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"mcpServers": {
|
|
55
|
+
"fcp": {
|
|
56
|
+
"command": "node",
|
|
57
|
+
"args": ["/path/to/fcp/mcp-server/dist/index.js"],
|
|
58
|
+
"env": {
|
|
59
|
+
"FCP_API_URL": "https://fcp.fru.io",
|
|
60
|
+
"FCP_API_TOKEN": "your_api_token"
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Or for development:
|
|
68
|
+
|
|
69
|
+
```json
|
|
70
|
+
{
|
|
71
|
+
"mcpServers": {
|
|
72
|
+
"fcp": {
|
|
73
|
+
"command": "npx",
|
|
74
|
+
"args": ["tsx", "/path/to/fcp/mcp-server/src/index.ts"],
|
|
75
|
+
"env": {
|
|
76
|
+
"FCP_API_URL": "http://localhost:3090",
|
|
77
|
+
"FCP_API_TOKEN": "dev_token"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Usage Examples
|
|
85
|
+
|
|
86
|
+
Once configured, Claude Code can use these tools naturally:
|
|
87
|
+
|
|
88
|
+
### Get launch context for current project
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
"What's the status of launch 3 and what checklist items are remaining?"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Claude will call `fcp_get_launch` and `fcp_get_checklist` to get the info.
|
|
95
|
+
|
|
96
|
+
### Work through checklist items
|
|
97
|
+
|
|
98
|
+
```
|
|
99
|
+
"I've completed the database export. Mark that checklist item as done."
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Claude will call `fcp_update_checklist_item` to update the status.
|
|
103
|
+
|
|
104
|
+
### Get legacy access info
|
|
105
|
+
|
|
106
|
+
```
|
|
107
|
+
"How do I access the legacy hosting for this migration?"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Claude will call `fcp_get_legacy_access` to get hosting, database, and file access details.
|
|
111
|
+
|
|
112
|
+
### Document progress
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
"Add a note that I've migrated all user accounts successfully."
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Claude will call `fcp_add_progress_note` to log the progress.
|
|
119
|
+
|
|
120
|
+
## Development
|
|
121
|
+
|
|
122
|
+
Run in development mode:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
npm run dev
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
This uses `tsx` to run TypeScript directly without building.
|
|
129
|
+
|
|
130
|
+
## API Token
|
|
131
|
+
|
|
132
|
+
To get an API token for the MCP server:
|
|
133
|
+
|
|
134
|
+
1. Go to FCP: https://fcp.fru.io/dashboard/settings
|
|
135
|
+
2. Navigate to "API Tokens" section
|
|
136
|
+
3. Create a new token with "Launch Management" permissions
|
|
137
|
+
4. Copy the token to your MCP server configuration
|
|
138
|
+
|
|
139
|
+
## Troubleshooting
|
|
140
|
+
|
|
141
|
+
### "Authentication failed"
|
|
142
|
+
- Check that `FCP_API_TOKEN` is set correctly
|
|
143
|
+
- Verify the token has the required permissions
|
|
144
|
+
|
|
145
|
+
### "Connection refused"
|
|
146
|
+
- Check that `FCP_API_URL` is correct
|
|
147
|
+
- For local dev, ensure FCP is running on port 3090
|
|
148
|
+
|
|
149
|
+
### Tools not appearing
|
|
150
|
+
- Restart Claude Code after updating settings
|
|
151
|
+
- Check Claude Code logs for MCP server errors
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* FCP MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Provides Claude Code with direct access to FCP Launch Coordination System:
|
|
6
|
+
* - Query launches, checklists, and legacy access info
|
|
7
|
+
* - Update checklist item status
|
|
8
|
+
* - Get project context for migrations
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* FCP MCP Server
|
|
4
|
+
*
|
|
5
|
+
* Provides Claude Code with direct access to FCP Launch Coordination System:
|
|
6
|
+
* - Query launches, checklists, and legacy access info
|
|
7
|
+
* - Update checklist item status
|
|
8
|
+
* - Get project context for migrations
|
|
9
|
+
*/
|
|
10
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
11
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
12
|
+
import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
13
|
+
// Configuration
|
|
14
|
+
const FCP_API_URL = process.env.FCP_API_URL || 'https://fcp.fru.io';
|
|
15
|
+
const FCP_API_TOKEN = process.env.FCP_API_TOKEN || '';
|
|
16
|
+
// API Client
|
|
17
|
+
class FCPClient {
|
|
18
|
+
baseUrl;
|
|
19
|
+
token;
|
|
20
|
+
constructor(baseUrl, token) {
|
|
21
|
+
this.baseUrl = baseUrl;
|
|
22
|
+
this.token = token;
|
|
23
|
+
}
|
|
24
|
+
async fetch(path, options = {}) {
|
|
25
|
+
const url = `${this.baseUrl}${path}`;
|
|
26
|
+
const headers = {
|
|
27
|
+
'Content-Type': 'application/json',
|
|
28
|
+
...(options.headers || {}),
|
|
29
|
+
};
|
|
30
|
+
if (this.token) {
|
|
31
|
+
// Support dev bypass mode for local testing
|
|
32
|
+
if (this.token === 'dev_bypass') {
|
|
33
|
+
headers['X-Dev-Bypass'] = 'true';
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
// Production mode: use X-API-Key header
|
|
37
|
+
headers['X-API-Key'] = this.token;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const response = await fetch(url, {
|
|
41
|
+
...options,
|
|
42
|
+
headers,
|
|
43
|
+
});
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
const error = await response.text();
|
|
46
|
+
throw new Error(`FCP API error (${response.status}): ${error}`);
|
|
47
|
+
}
|
|
48
|
+
return response.json();
|
|
49
|
+
}
|
|
50
|
+
async listLaunches(filters) {
|
|
51
|
+
const params = new URLSearchParams();
|
|
52
|
+
if (filters?.status)
|
|
53
|
+
params.set('status', filters.status);
|
|
54
|
+
if (filters?.platform)
|
|
55
|
+
params.set('platform', filters.platform);
|
|
56
|
+
if (filters?.upcoming)
|
|
57
|
+
params.set('upcoming', filters.upcoming.toString());
|
|
58
|
+
if (filters?.limit)
|
|
59
|
+
params.set('limit', filters.limit.toString());
|
|
60
|
+
const query = params.toString();
|
|
61
|
+
return this.fetch(`/api/launches${query ? `?${query}` : ''}`);
|
|
62
|
+
}
|
|
63
|
+
async getLaunch(id) {
|
|
64
|
+
return this.fetch(`/api/launches/${id}`);
|
|
65
|
+
}
|
|
66
|
+
async updateChecklistItem(launchId, itemId, updates) {
|
|
67
|
+
return this.fetch(`/api/launches/${launchId}/checklist/${itemId}`, {
|
|
68
|
+
method: 'PUT',
|
|
69
|
+
body: JSON.stringify(updates),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async getClaudeMd(launchId) {
|
|
73
|
+
return this.fetch(`/api/launches/${launchId}/claude-md`);
|
|
74
|
+
}
|
|
75
|
+
async addNote(launchId, content) {
|
|
76
|
+
return this.fetch(`/api/launches/${launchId}/notes`, {
|
|
77
|
+
method: 'POST',
|
|
78
|
+
body: JSON.stringify({ content }),
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Create server
|
|
83
|
+
const server = new Server({
|
|
84
|
+
name: 'fcp-mcp-server',
|
|
85
|
+
version: '1.0.0',
|
|
86
|
+
}, {
|
|
87
|
+
capabilities: {
|
|
88
|
+
tools: {},
|
|
89
|
+
resources: {},
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
const client = new FCPClient(FCP_API_URL, FCP_API_TOKEN);
|
|
93
|
+
// Tool definitions
|
|
94
|
+
const TOOLS = [
|
|
95
|
+
{
|
|
96
|
+
name: 'fcp_list_launches',
|
|
97
|
+
description: 'List launches from FCP with optional filters. Returns upcoming launches, their status, and basic info.',
|
|
98
|
+
inputSchema: {
|
|
99
|
+
type: 'object',
|
|
100
|
+
properties: {
|
|
101
|
+
status: {
|
|
102
|
+
type: 'string',
|
|
103
|
+
description: 'Filter by status: planning, in_progress, soft_launched, launched, on_hold, cancelled',
|
|
104
|
+
},
|
|
105
|
+
platform: {
|
|
106
|
+
type: 'string',
|
|
107
|
+
description: 'Filter by platform: wordpress, drupal, nextjs, other',
|
|
108
|
+
},
|
|
109
|
+
upcoming: {
|
|
110
|
+
type: 'number',
|
|
111
|
+
description: 'Show launches within next N days',
|
|
112
|
+
},
|
|
113
|
+
limit: {
|
|
114
|
+
type: 'number',
|
|
115
|
+
description: 'Maximum number of launches to return',
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: 'fcp_get_launch',
|
|
122
|
+
description: 'Get detailed information about a specific launch including checklist items, legacy access info, and team assignments.',
|
|
123
|
+
inputSchema: {
|
|
124
|
+
type: 'object',
|
|
125
|
+
properties: {
|
|
126
|
+
launch_id: {
|
|
127
|
+
type: 'number',
|
|
128
|
+
description: 'The ID of the launch to retrieve',
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
required: ['launch_id'],
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
name: 'fcp_get_legacy_access',
|
|
136
|
+
description: 'Get legacy hosting access information for a migration launch. Includes hosting provider, database access, file access, git repo, and DNS details.',
|
|
137
|
+
inputSchema: {
|
|
138
|
+
type: 'object',
|
|
139
|
+
properties: {
|
|
140
|
+
launch_id: {
|
|
141
|
+
type: 'number',
|
|
142
|
+
description: 'The ID of the launch',
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
required: ['launch_id'],
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
name: 'fcp_get_checklist',
|
|
150
|
+
description: 'Get the launch checklist with item statuses and any Claude-specific instructions for completing tasks.',
|
|
151
|
+
inputSchema: {
|
|
152
|
+
type: 'object',
|
|
153
|
+
properties: {
|
|
154
|
+
launch_id: {
|
|
155
|
+
type: 'number',
|
|
156
|
+
description: 'The ID of the launch',
|
|
157
|
+
},
|
|
158
|
+
category: {
|
|
159
|
+
type: 'string',
|
|
160
|
+
description: 'Optional: filter by category (pre_launch, content, technical, seo, testing, dns, monitoring, post_launch)',
|
|
161
|
+
},
|
|
162
|
+
status: {
|
|
163
|
+
type: 'string',
|
|
164
|
+
description: 'Optional: filter by status (pending, in_progress, completed, blocked, skipped)',
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
required: ['launch_id'],
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
name: 'fcp_update_checklist_item',
|
|
172
|
+
description: 'Update the status of a checklist item. Use this to mark items as completed, in_progress, or blocked as you work through tasks.',
|
|
173
|
+
inputSchema: {
|
|
174
|
+
type: 'object',
|
|
175
|
+
properties: {
|
|
176
|
+
launch_id: {
|
|
177
|
+
type: 'number',
|
|
178
|
+
description: 'The ID of the launch',
|
|
179
|
+
},
|
|
180
|
+
item_id: {
|
|
181
|
+
type: 'number',
|
|
182
|
+
description: 'The ID of the checklist item',
|
|
183
|
+
},
|
|
184
|
+
status: {
|
|
185
|
+
type: 'string',
|
|
186
|
+
enum: ['pending', 'in_progress', 'completed', 'blocked', 'skipped'],
|
|
187
|
+
description: 'New status for the item',
|
|
188
|
+
},
|
|
189
|
+
notes: {
|
|
190
|
+
type: 'string',
|
|
191
|
+
description: 'Optional notes about the status change',
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
required: ['launch_id', 'item_id', 'status'],
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
name: 'fcp_add_progress_note',
|
|
199
|
+
description: 'Add a progress note to a launch. Use this to document what work was done or any issues encountered.',
|
|
200
|
+
inputSchema: {
|
|
201
|
+
type: 'object',
|
|
202
|
+
properties: {
|
|
203
|
+
launch_id: {
|
|
204
|
+
type: 'number',
|
|
205
|
+
description: 'The ID of the launch',
|
|
206
|
+
},
|
|
207
|
+
content: {
|
|
208
|
+
type: 'string',
|
|
209
|
+
description: 'The note content',
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
required: ['launch_id', 'content'],
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
{
|
|
216
|
+
name: 'fcp_get_claude_md',
|
|
217
|
+
description: 'Generate CLAUDE.md content for a launch. Returns formatted markdown with project context, legacy access info, and checklist.',
|
|
218
|
+
inputSchema: {
|
|
219
|
+
type: 'object',
|
|
220
|
+
properties: {
|
|
221
|
+
launch_id: {
|
|
222
|
+
type: 'number',
|
|
223
|
+
description: 'The ID of the launch',
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
required: ['launch_id'],
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
];
|
|
230
|
+
// Register tool handlers
|
|
231
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
232
|
+
return { tools: TOOLS };
|
|
233
|
+
});
|
|
234
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
235
|
+
const { name, arguments: args } = request.params;
|
|
236
|
+
try {
|
|
237
|
+
switch (name) {
|
|
238
|
+
case 'fcp_list_launches': {
|
|
239
|
+
const result = await client.listLaunches(args);
|
|
240
|
+
return {
|
|
241
|
+
content: [
|
|
242
|
+
{
|
|
243
|
+
type: 'text',
|
|
244
|
+
text: JSON.stringify(result, null, 2),
|
|
245
|
+
},
|
|
246
|
+
],
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
case 'fcp_get_launch': {
|
|
250
|
+
const { launch_id } = args;
|
|
251
|
+
const result = await client.getLaunch(launch_id);
|
|
252
|
+
return {
|
|
253
|
+
content: [
|
|
254
|
+
{
|
|
255
|
+
type: 'text',
|
|
256
|
+
text: JSON.stringify(result, null, 2),
|
|
257
|
+
},
|
|
258
|
+
],
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
case 'fcp_get_legacy_access': {
|
|
262
|
+
const { launch_id } = args;
|
|
263
|
+
const result = await client.getLaunch(launch_id);
|
|
264
|
+
const legacyAccess = {
|
|
265
|
+
launch_id,
|
|
266
|
+
launch_name: result.launch.name,
|
|
267
|
+
launch_type: result.launch.launch_type,
|
|
268
|
+
legacy_domain: result.launch.legacy_domain,
|
|
269
|
+
legacy_access_info: result.launch.legacy_access_info || {},
|
|
270
|
+
};
|
|
271
|
+
return {
|
|
272
|
+
content: [
|
|
273
|
+
{
|
|
274
|
+
type: 'text',
|
|
275
|
+
text: JSON.stringify(legacyAccess, null, 2),
|
|
276
|
+
},
|
|
277
|
+
],
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
case 'fcp_get_checklist': {
|
|
281
|
+
const { launch_id, category, status } = args;
|
|
282
|
+
const result = await client.getLaunch(launch_id);
|
|
283
|
+
let checklist = result.checklist || [];
|
|
284
|
+
if (category) {
|
|
285
|
+
checklist = checklist.filter((item) => item.category === category);
|
|
286
|
+
}
|
|
287
|
+
if (status) {
|
|
288
|
+
checklist = checklist.filter((item) => item.status === status);
|
|
289
|
+
}
|
|
290
|
+
// Format for readability
|
|
291
|
+
const formatted = checklist.map((item) => ({
|
|
292
|
+
id: item.id,
|
|
293
|
+
title: item.title,
|
|
294
|
+
status: item.status,
|
|
295
|
+
category: item.category,
|
|
296
|
+
is_blocker: item.is_blocker,
|
|
297
|
+
description: item.description,
|
|
298
|
+
claude_instructions: item.claude_instructions,
|
|
299
|
+
}));
|
|
300
|
+
return {
|
|
301
|
+
content: [
|
|
302
|
+
{
|
|
303
|
+
type: 'text',
|
|
304
|
+
text: JSON.stringify({
|
|
305
|
+
launch_id,
|
|
306
|
+
launch_name: result.launch.name,
|
|
307
|
+
total_items: formatted.length,
|
|
308
|
+
completed: formatted.filter((i) => i.status === 'completed').length,
|
|
309
|
+
blockers: formatted.filter((i) => i.is_blocker && i.status !== 'completed').length,
|
|
310
|
+
items: formatted,
|
|
311
|
+
}, null, 2),
|
|
312
|
+
},
|
|
313
|
+
],
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
case 'fcp_update_checklist_item': {
|
|
317
|
+
const { launch_id, item_id, status, notes } = args;
|
|
318
|
+
const result = await client.updateChecklistItem(launch_id, item_id, {
|
|
319
|
+
status,
|
|
320
|
+
notes,
|
|
321
|
+
});
|
|
322
|
+
return {
|
|
323
|
+
content: [
|
|
324
|
+
{
|
|
325
|
+
type: 'text',
|
|
326
|
+
text: JSON.stringify({
|
|
327
|
+
success: true,
|
|
328
|
+
message: `Checklist item ${item_id} updated to status: ${status}`,
|
|
329
|
+
item: result,
|
|
330
|
+
}, null, 2),
|
|
331
|
+
},
|
|
332
|
+
],
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
case 'fcp_add_progress_note': {
|
|
336
|
+
const { launch_id, content } = args;
|
|
337
|
+
const result = await client.addNote(launch_id, content);
|
|
338
|
+
return {
|
|
339
|
+
content: [
|
|
340
|
+
{
|
|
341
|
+
type: 'text',
|
|
342
|
+
text: JSON.stringify({
|
|
343
|
+
success: true,
|
|
344
|
+
message: 'Progress note added',
|
|
345
|
+
note: result,
|
|
346
|
+
}, null, 2),
|
|
347
|
+
},
|
|
348
|
+
],
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
case 'fcp_get_claude_md': {
|
|
352
|
+
const { launch_id } = args;
|
|
353
|
+
const result = await client.getClaudeMd(launch_id);
|
|
354
|
+
return {
|
|
355
|
+
content: [
|
|
356
|
+
{
|
|
357
|
+
type: 'text',
|
|
358
|
+
text: result.content,
|
|
359
|
+
},
|
|
360
|
+
],
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
default:
|
|
364
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
369
|
+
return {
|
|
370
|
+
content: [
|
|
371
|
+
{
|
|
372
|
+
type: 'text',
|
|
373
|
+
text: JSON.stringify({ error: message }, null, 2),
|
|
374
|
+
},
|
|
375
|
+
],
|
|
376
|
+
isError: true,
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
// Resource handlers
|
|
381
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
382
|
+
return {
|
|
383
|
+
resources: [
|
|
384
|
+
{
|
|
385
|
+
uri: 'fcp://launches',
|
|
386
|
+
name: 'FCP Launches',
|
|
387
|
+
description: 'List of all launches in FCP',
|
|
388
|
+
mimeType: 'application/json',
|
|
389
|
+
},
|
|
390
|
+
],
|
|
391
|
+
};
|
|
392
|
+
});
|
|
393
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
394
|
+
const { uri } = request.params;
|
|
395
|
+
if (uri === 'fcp://launches') {
|
|
396
|
+
const result = await client.listLaunches({ limit: 50 });
|
|
397
|
+
return {
|
|
398
|
+
contents: [
|
|
399
|
+
{
|
|
400
|
+
uri,
|
|
401
|
+
mimeType: 'application/json',
|
|
402
|
+
text: JSON.stringify(result, null, 2),
|
|
403
|
+
},
|
|
404
|
+
],
|
|
405
|
+
};
|
|
406
|
+
}
|
|
407
|
+
// Handle fcp://launches/{id}
|
|
408
|
+
const launchMatch = uri.match(/^fcp:\/\/launches\/(\d+)$/);
|
|
409
|
+
if (launchMatch) {
|
|
410
|
+
const launchId = parseInt(launchMatch[1], 10);
|
|
411
|
+
const result = await client.getLaunch(launchId);
|
|
412
|
+
return {
|
|
413
|
+
contents: [
|
|
414
|
+
{
|
|
415
|
+
uri,
|
|
416
|
+
mimeType: 'application/json',
|
|
417
|
+
text: JSON.stringify(result, null, 2),
|
|
418
|
+
},
|
|
419
|
+
],
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
423
|
+
});
|
|
424
|
+
// Start server
|
|
425
|
+
async function main() {
|
|
426
|
+
const transport = new StdioServerTransport();
|
|
427
|
+
await server.connect(transport);
|
|
428
|
+
console.error('FCP MCP Server running on stdio');
|
|
429
|
+
}
|
|
430
|
+
main().catch((error) => {
|
|
431
|
+
console.error('Fatal error:', error);
|
|
432
|
+
process.exit(1);
|
|
433
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fruition/fcp-mcp-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP Server for FCP Launch Coordination System - enables Claude Code to interact with FCP launches",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"fcp-mcp-server": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"start": "node dist/index.js",
|
|
16
|
+
"dev": "tsx src/index.ts",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"mcp",
|
|
21
|
+
"claude",
|
|
22
|
+
"fcp",
|
|
23
|
+
"launch-coordination",
|
|
24
|
+
"anthropic"
|
|
25
|
+
],
|
|
26
|
+
"author": "Fruition",
|
|
27
|
+
"license": "MIT",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/fruition/fcp.git",
|
|
31
|
+
"directory": "mcp-server"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/node": "^20.0.0",
|
|
41
|
+
"tsx": "^4.7.0",
|
|
42
|
+
"typescript": "^5.3.0"
|
|
43
|
+
}
|
|
44
|
+
}
|