@zelklab/seevo-mcp-server 0.1.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 +154 -0
- package/dist/analyzer.js +269 -0
- package/dist/auth.js +97 -0
- package/dist/client.js +98 -0
- package/dist/index.js +188 -0
- package/dist/setup.js +151 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Seevo MCP Server
|
|
2
|
+
|
|
3
|
+
Claude CodeからSeevoバックエンドに直接プロジェクトを登録するためのMCPサーバーです。
|
|
4
|
+
|
|
5
|
+
## 機能
|
|
6
|
+
|
|
7
|
+
- **プロジェクト自動登録**: プロジェクトディレクトリを解析してSeevoに自動登録
|
|
8
|
+
- **セキュアな認証**: ログイントークンを安全に保存・管理
|
|
9
|
+
- **自動解析**: README.md、package.json等からサービス情報を自動抽出
|
|
10
|
+
|
|
11
|
+
## セットアップ
|
|
12
|
+
|
|
13
|
+
### 1. 依存関係のインストール
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
cd /Users/sugimoto/Desktop/seevo/mcp-server
|
|
17
|
+
npm install
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 2. ビルド
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm run build
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### 3. Claude Code設定
|
|
27
|
+
|
|
28
|
+
`~/.config/claude-code/config.json` に以下を追加:
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"mcpServers": {
|
|
33
|
+
"seevo": {
|
|
34
|
+
"command": "node",
|
|
35
|
+
"args": ["/Users/sugimoto/Desktop/seevo/mcp-server/dist/index.js"]
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### 4. Claude Codeを再起動
|
|
42
|
+
|
|
43
|
+
設定を反映するためにClaude Codeを再起動してください。
|
|
44
|
+
|
|
45
|
+
## 使い方
|
|
46
|
+
|
|
47
|
+
### 1. ログイン
|
|
48
|
+
|
|
49
|
+
まずSeevoにログインします:
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
User: Seevoにログインして
|
|
53
|
+
Claude Code: [seevo_login ツールを使用]
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
または直接:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
User: メール test@example.com、パスワード password123 でSeevoにログインして
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### 2. プロジェクト登録
|
|
63
|
+
|
|
64
|
+
現在のプロジェクトをSeevoに登録:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
User: このプロジェクトをSeevoに登録して
|
|
68
|
+
Claude Code: [プロジェクトを解析してseevo_register_project ツールを使用]
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
特定のディレクトリを指定:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
User: /Users/sugimoto/Desktop/myproject をSeevoに登録して
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 3. ログアウト
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
User: Seevoからログアウトして
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## 利用可能なツール
|
|
84
|
+
|
|
85
|
+
### `seevo_login`
|
|
86
|
+
- Seevoにログインして認証トークンを保存
|
|
87
|
+
- パラメータ: `email`, `password`
|
|
88
|
+
|
|
89
|
+
### `seevo_register_project`
|
|
90
|
+
- プロジェクトをSeevoに登録
|
|
91
|
+
- パラメータ:
|
|
92
|
+
- `project_path` (省略可): プロジェクトディレクトリのパス
|
|
93
|
+
- `name` (省略可): サービス名
|
|
94
|
+
|
|
95
|
+
### `seevo_logout`
|
|
96
|
+
- ログアウトして認証トークンを削除
|
|
97
|
+
|
|
98
|
+
## プロジェクト解析
|
|
99
|
+
|
|
100
|
+
MCPサーバーは以下のファイルから自動的に情報を抽出します:
|
|
101
|
+
|
|
102
|
+
- **プロジェクト名**: `package.json`, `go.mod`, `Cargo.toml`, またはディレクトリ名
|
|
103
|
+
- **説明**: `README.md` の最初の段落、または `package.json` の description
|
|
104
|
+
- **ターゲットユーザー**: 技術スタックとキーワードから推測
|
|
105
|
+
|
|
106
|
+
## セキュリティ
|
|
107
|
+
|
|
108
|
+
- 認証トークンは `~/.seevo/auth.json` に保存(権限600)
|
|
109
|
+
- トークンは7日間有効
|
|
110
|
+
- MCPサーバー経由のみでAPIにアクセス可能
|
|
111
|
+
|
|
112
|
+
## トラブルシューティング
|
|
113
|
+
|
|
114
|
+
### MCPサーバーが起動しない
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# ビルドエラーがないか確認
|
|
118
|
+
cd /Users/sugimoto/Desktop/seevo/mcp-server
|
|
119
|
+
npm run build
|
|
120
|
+
|
|
121
|
+
# 直接実行してエラーを確認
|
|
122
|
+
node dist/index.js
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### 認証エラー
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# 認証情報をクリア
|
|
129
|
+
rm ~/.seevo/auth.json
|
|
130
|
+
|
|
131
|
+
# 再度ログイン
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Goバックエンドに接続できない
|
|
135
|
+
|
|
136
|
+
- Goバックエンドが起動しているか確認: `http://localhost:8080`
|
|
137
|
+
- 環境変数 `SEEVO_API_URL` で別のURLを指定可能
|
|
138
|
+
|
|
139
|
+
## 開発
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# 開発モード(TypeScriptをビルドして実行)
|
|
143
|
+
npm run dev
|
|
144
|
+
|
|
145
|
+
# TypeScriptをビルド
|
|
146
|
+
npm run build
|
|
147
|
+
|
|
148
|
+
# 実行
|
|
149
|
+
npm start
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## ライセンス
|
|
153
|
+
|
|
154
|
+
MIT
|
package/dist/analyzer.js
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from "fs";
|
|
2
|
+
import { join, basename } from "path";
|
|
3
|
+
/**
|
|
4
|
+
* プロジェクトディレクトリを解析してサービス情報を抽出
|
|
5
|
+
*/
|
|
6
|
+
export async function analyzeProject(projectPath, forcedName) {
|
|
7
|
+
// プロジェクト名を決定
|
|
8
|
+
const service_name = forcedName || detectProjectName(projectPath);
|
|
9
|
+
// README.mdから説明を抽出
|
|
10
|
+
const description = extractDescriptionFromReadme(projectPath) ||
|
|
11
|
+
extractDescriptionFromPackageJson(projectPath) ||
|
|
12
|
+
`${service_name}のマーケティングコンテンツ`;
|
|
13
|
+
// ターゲットオーディエンスを推測
|
|
14
|
+
const target = detectTargetAudience(projectPath);
|
|
15
|
+
// 技術スタックを検出
|
|
16
|
+
const tech_stack = detectTechStack(projectPath);
|
|
17
|
+
// 機能を検出(README.mdから抽出)
|
|
18
|
+
const features = detectFeatures(projectPath);
|
|
19
|
+
return {
|
|
20
|
+
service_name,
|
|
21
|
+
description,
|
|
22
|
+
target,
|
|
23
|
+
tech_stack: tech_stack.length > 0 ? tech_stack : undefined,
|
|
24
|
+
features: features.length > 0 ? features : undefined,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* プロジェクト名を検出
|
|
29
|
+
*/
|
|
30
|
+
function detectProjectName(projectPath) {
|
|
31
|
+
// package.json から取得
|
|
32
|
+
const packageJsonPath = join(projectPath, "package.json");
|
|
33
|
+
if (existsSync(packageJsonPath)) {
|
|
34
|
+
try {
|
|
35
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
36
|
+
if (packageJson.name) {
|
|
37
|
+
return packageJson.name;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
// Ignore
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// go.mod から取得
|
|
45
|
+
const goModPath = join(projectPath, "go.mod");
|
|
46
|
+
if (existsSync(goModPath)) {
|
|
47
|
+
try {
|
|
48
|
+
const goMod = readFileSync(goModPath, "utf-8");
|
|
49
|
+
const match = goMod.match(/module\s+([^\s]+)/);
|
|
50
|
+
if (match && match[1]) {
|
|
51
|
+
const parts = match[1].split("/");
|
|
52
|
+
return parts[parts.length - 1];
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
// Ignore
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
// Cargo.toml から取得
|
|
60
|
+
const cargoTomlPath = join(projectPath, "Cargo.toml");
|
|
61
|
+
if (existsSync(cargoTomlPath)) {
|
|
62
|
+
try {
|
|
63
|
+
const cargoToml = readFileSync(cargoTomlPath, "utf-8");
|
|
64
|
+
const match = cargoToml.match(/name\s*=\s*"([^"]+)"/);
|
|
65
|
+
if (match && match[1]) {
|
|
66
|
+
return match[1];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
// Ignore
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// ディレクトリ名をフォールバック
|
|
74
|
+
return basename(projectPath);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* README.mdから説明を抽出
|
|
78
|
+
*/
|
|
79
|
+
function extractDescriptionFromReadme(projectPath) {
|
|
80
|
+
const readmePaths = [
|
|
81
|
+
join(projectPath, "README.md"),
|
|
82
|
+
join(projectPath, "readme.md"),
|
|
83
|
+
join(projectPath, "README"),
|
|
84
|
+
];
|
|
85
|
+
for (const readmePath of readmePaths) {
|
|
86
|
+
if (existsSync(readmePath)) {
|
|
87
|
+
try {
|
|
88
|
+
const content = readFileSync(readmePath, "utf-8");
|
|
89
|
+
// タイトルの次の段落を抽出
|
|
90
|
+
const lines = content.split("\n");
|
|
91
|
+
let foundTitle = false;
|
|
92
|
+
let description = "";
|
|
93
|
+
for (const line of lines) {
|
|
94
|
+
if (line.startsWith("#")) {
|
|
95
|
+
foundTitle = true;
|
|
96
|
+
continue;
|
|
97
|
+
}
|
|
98
|
+
if (foundTitle && line.trim() !== "") {
|
|
99
|
+
description += line.trim() + " ";
|
|
100
|
+
if (description.length > 200) {
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (description) {
|
|
106
|
+
return description.trim().substring(0, 500);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
// Ignore
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* package.jsonから説明を抽出
|
|
118
|
+
*/
|
|
119
|
+
function extractDescriptionFromPackageJson(projectPath) {
|
|
120
|
+
const packageJsonPath = join(projectPath, "package.json");
|
|
121
|
+
if (existsSync(packageJsonPath)) {
|
|
122
|
+
try {
|
|
123
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
124
|
+
return packageJson.description || null;
|
|
125
|
+
}
|
|
126
|
+
catch (error) {
|
|
127
|
+
// Ignore
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* ターゲットオーディエンスを推測
|
|
134
|
+
*/
|
|
135
|
+
function detectTargetAudience(projectPath) {
|
|
136
|
+
const techStack = detectTechStack(projectPath);
|
|
137
|
+
const keywords = detectKeywords(projectPath);
|
|
138
|
+
// 技術スタックベースの推測
|
|
139
|
+
if (techStack.includes("react") || techStack.includes("vue") || techStack.includes("next.js")) {
|
|
140
|
+
return "Web開発者、スタートアップ";
|
|
141
|
+
}
|
|
142
|
+
if (techStack.includes("go") && keywords.includes("api")) {
|
|
143
|
+
return "バックエンド開発者、API利用者";
|
|
144
|
+
}
|
|
145
|
+
if (techStack.includes("python") && (keywords.includes("ml") || keywords.includes("ai"))) {
|
|
146
|
+
return "データサイエンティスト、AI/ML エンジニア";
|
|
147
|
+
}
|
|
148
|
+
if (keywords.includes("cli") || keywords.includes("tool")) {
|
|
149
|
+
return "開発者、エンジニア";
|
|
150
|
+
}
|
|
151
|
+
// デフォルト
|
|
152
|
+
return "スタートアップの開発者、中小企業";
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* 技術スタックを検出
|
|
156
|
+
*/
|
|
157
|
+
function detectTechStack(projectPath) {
|
|
158
|
+
const stack = [];
|
|
159
|
+
// package.json
|
|
160
|
+
if (existsSync(join(projectPath, "package.json"))) {
|
|
161
|
+
try {
|
|
162
|
+
const packageJson = JSON.parse(readFileSync(join(projectPath, "package.json"), "utf-8"));
|
|
163
|
+
const deps = {
|
|
164
|
+
...packageJson.dependencies,
|
|
165
|
+
...packageJson.devDependencies,
|
|
166
|
+
};
|
|
167
|
+
if (deps.next)
|
|
168
|
+
stack.push("Next.js");
|
|
169
|
+
else if (deps.react)
|
|
170
|
+
stack.push("React");
|
|
171
|
+
if (deps.vue)
|
|
172
|
+
stack.push("Vue");
|
|
173
|
+
if (deps.express)
|
|
174
|
+
stack.push("Express");
|
|
175
|
+
if (deps.typescript || deps["@types/node"])
|
|
176
|
+
stack.push("TypeScript");
|
|
177
|
+
if (deps.tailwindcss || deps["tailwindcss"])
|
|
178
|
+
stack.push("Tailwind CSS");
|
|
179
|
+
if (deps.postgresql || deps.pg)
|
|
180
|
+
stack.push("PostgreSQL");
|
|
181
|
+
}
|
|
182
|
+
catch (error) {
|
|
183
|
+
// Ignore
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// go.mod
|
|
187
|
+
if (existsSync(join(projectPath, "go.mod"))) {
|
|
188
|
+
stack.push("Go");
|
|
189
|
+
}
|
|
190
|
+
// requirements.txt or setup.py
|
|
191
|
+
if (existsSync(join(projectPath, "requirements.txt")) ||
|
|
192
|
+
existsSync(join(projectPath, "setup.py"))) {
|
|
193
|
+
stack.push("Python");
|
|
194
|
+
}
|
|
195
|
+
// Cargo.toml
|
|
196
|
+
if (existsSync(join(projectPath, "Cargo.toml"))) {
|
|
197
|
+
stack.push("Rust");
|
|
198
|
+
}
|
|
199
|
+
// Docker
|
|
200
|
+
if (existsSync(join(projectPath, "Dockerfile")) || existsSync(join(projectPath, "docker-compose.yml"))) {
|
|
201
|
+
stack.push("Docker");
|
|
202
|
+
}
|
|
203
|
+
return stack;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* キーワードを検出
|
|
207
|
+
*/
|
|
208
|
+
function detectKeywords(projectPath) {
|
|
209
|
+
const keywords = [];
|
|
210
|
+
// README.mdからキーワード抽出
|
|
211
|
+
const readmePath = join(projectPath, "README.md");
|
|
212
|
+
if (existsSync(readmePath)) {
|
|
213
|
+
try {
|
|
214
|
+
const content = readFileSync(readmePath, "utf-8").toLowerCase();
|
|
215
|
+
if (content.includes("api"))
|
|
216
|
+
keywords.push("api");
|
|
217
|
+
if (content.includes("cli"))
|
|
218
|
+
keywords.push("cli");
|
|
219
|
+
if (content.includes("tool"))
|
|
220
|
+
keywords.push("tool");
|
|
221
|
+
if (content.includes("machine learning") || content.includes("ml"))
|
|
222
|
+
keywords.push("ml");
|
|
223
|
+
if (content.includes("artificial intelligence") || content.includes("ai"))
|
|
224
|
+
keywords.push("ai");
|
|
225
|
+
if (content.includes("web app") || content.includes("webapp"))
|
|
226
|
+
keywords.push("webapp");
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
// Ignore
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return keywords;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* 機能を検出(README.mdから)
|
|
236
|
+
*/
|
|
237
|
+
function detectFeatures(projectPath) {
|
|
238
|
+
const features = [];
|
|
239
|
+
const readmePath = join(projectPath, "README.md");
|
|
240
|
+
if (existsSync(readmePath)) {
|
|
241
|
+
try {
|
|
242
|
+
const content = readFileSync(readmePath, "utf-8");
|
|
243
|
+
const lines = content.split("\n");
|
|
244
|
+
let inFeaturesSection = false;
|
|
245
|
+
for (const line of lines) {
|
|
246
|
+
// 機能セクションの開始を検出
|
|
247
|
+
if (line.match(/^##?\s+(Features|機能|主な機能|Main Features)/i)) {
|
|
248
|
+
inFeaturesSection = true;
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
// 次のセクション見出しで終了
|
|
252
|
+
if (inFeaturesSection && line.match(/^##?\s+/)) {
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
255
|
+
// リスト項目を抽出
|
|
256
|
+
if (inFeaturesSection) {
|
|
257
|
+
const listMatch = line.match(/^[\s]*[-*+]\s+(.+)/);
|
|
258
|
+
if (listMatch && listMatch[1]) {
|
|
259
|
+
features.push(listMatch[1].trim());
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
// Ignore
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return features.slice(0, 10); // 最大10個まで
|
|
269
|
+
}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
2
|
+
import { homedir } from "os";
|
|
3
|
+
import { join } from "path";
|
|
4
|
+
/**
|
|
5
|
+
* 認証トークン管理クラス
|
|
6
|
+
* ユーザーのホームディレクトリにMCPトークンを安全に保存
|
|
7
|
+
*/
|
|
8
|
+
export class AuthManager {
|
|
9
|
+
configDir;
|
|
10
|
+
authFile;
|
|
11
|
+
authData = null;
|
|
12
|
+
constructor() {
|
|
13
|
+
this.configDir = join(homedir(), ".seevo");
|
|
14
|
+
this.authFile = join(this.configDir, "auth.json");
|
|
15
|
+
this.loadToken();
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* 認証トークンを読み込む
|
|
19
|
+
* 優先順位: 1. 環境変数 SEEVO_MCP_TOKEN, 2. ファイル ~/.seevo/auth.json
|
|
20
|
+
*/
|
|
21
|
+
loadToken() {
|
|
22
|
+
try {
|
|
23
|
+
// 1. 環境変数から読み込み(Claude Code設定で渡される)
|
|
24
|
+
const envToken = process.env.SEEVO_MCP_TOKEN;
|
|
25
|
+
if (envToken) {
|
|
26
|
+
// 環境変数のトークンは30日間有効とみなす
|
|
27
|
+
this.authData = {
|
|
28
|
+
token: envToken,
|
|
29
|
+
expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1000,
|
|
30
|
+
};
|
|
31
|
+
console.error("Auth: Using token from environment variable");
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
// 2. ファイルから読み込み
|
|
35
|
+
if (existsSync(this.authFile)) {
|
|
36
|
+
const data = readFileSync(this.authFile, "utf-8");
|
|
37
|
+
this.authData = JSON.parse(data);
|
|
38
|
+
// トークンが期限切れかチェック
|
|
39
|
+
if (this.authData && this.authData.expiresAt < Date.now()) {
|
|
40
|
+
this.authData = null;
|
|
41
|
+
}
|
|
42
|
+
else if (this.authData) {
|
|
43
|
+
console.error("Auth: Using token from file");
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
console.error("Failed to load auth token:", error);
|
|
49
|
+
this.authData = null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* MCPトークンを保存 (30日間有効)
|
|
54
|
+
*/
|
|
55
|
+
saveToken(token, expiresInDays = 30) {
|
|
56
|
+
try {
|
|
57
|
+
// ディレクトリが存在しない場合は作成
|
|
58
|
+
if (!existsSync(this.configDir)) {
|
|
59
|
+
mkdirSync(this.configDir, { recursive: true });
|
|
60
|
+
}
|
|
61
|
+
const expiresAt = Date.now() + expiresInDays * 24 * 60 * 60 * 1000;
|
|
62
|
+
this.authData = { token, expiresAt };
|
|
63
|
+
writeFileSync(this.authFile, JSON.stringify(this.authData, null, 2), {
|
|
64
|
+
mode: 0o600, // 所有者のみ読み書き可能
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
throw new Error(`Failed to save auth token: ${error}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* MCPトークンを取得
|
|
73
|
+
*/
|
|
74
|
+
getToken() {
|
|
75
|
+
return this.authData?.token || null;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 認証済みかチェック
|
|
79
|
+
*/
|
|
80
|
+
isAuthenticated() {
|
|
81
|
+
return this.authData !== null && this.authData.expiresAt > Date.now();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* 認証トークンをクリア
|
|
85
|
+
*/
|
|
86
|
+
clearToken() {
|
|
87
|
+
this.authData = null;
|
|
88
|
+
try {
|
|
89
|
+
if (existsSync(this.authFile)) {
|
|
90
|
+
writeFileSync(this.authFile, "");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
console.error("Failed to clear auth token:", error);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import fetch from "node-fetch";
|
|
2
|
+
/**
|
|
3
|
+
* Seevoバックエンドとの通信クライアント
|
|
4
|
+
*/
|
|
5
|
+
export class SeeveClient {
|
|
6
|
+
baseUrl;
|
|
7
|
+
authManager;
|
|
8
|
+
constructor(authManager) {
|
|
9
|
+
this.baseUrl = process.env.SEEVO_API_URL || "http://localhost:8080/api/v1";
|
|
10
|
+
this.authManager = authManager;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* ログイン
|
|
14
|
+
*/
|
|
15
|
+
async login(email, password) {
|
|
16
|
+
// Step 1: Login to get JWT token in cookie
|
|
17
|
+
const loginResponse = await fetch(`${this.baseUrl}/auth/login`, {
|
|
18
|
+
method: "POST",
|
|
19
|
+
headers: {
|
|
20
|
+
"Content-Type": "application/json",
|
|
21
|
+
},
|
|
22
|
+
body: JSON.stringify({ email, password }),
|
|
23
|
+
});
|
|
24
|
+
if (!loginResponse.ok) {
|
|
25
|
+
const error = await loginResponse.text();
|
|
26
|
+
throw new Error(`Login failed: ${error}`);
|
|
27
|
+
}
|
|
28
|
+
// Extract JWT token from cookie header
|
|
29
|
+
const setCookie = loginResponse.headers.get("set-cookie");
|
|
30
|
+
if (!setCookie) {
|
|
31
|
+
throw new Error("No authentication cookie received");
|
|
32
|
+
}
|
|
33
|
+
const tokenMatch = setCookie.match(/token=([^;]+)/);
|
|
34
|
+
if (!tokenMatch) {
|
|
35
|
+
throw new Error("Failed to extract authentication token");
|
|
36
|
+
}
|
|
37
|
+
const jwtToken = tokenMatch[1];
|
|
38
|
+
// Step 2: Request MCP token using the JWT token
|
|
39
|
+
const mcpTokenResponse = await fetch(`${this.baseUrl}/auth/mcp-token`, {
|
|
40
|
+
method: "POST",
|
|
41
|
+
headers: {
|
|
42
|
+
Cookie: `token=${jwtToken}`,
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
if (!mcpTokenResponse.ok) {
|
|
46
|
+
const error = await mcpTokenResponse.text();
|
|
47
|
+
throw new Error(`Failed to generate MCP token: ${error}`);
|
|
48
|
+
}
|
|
49
|
+
const mcpTokenData = (await mcpTokenResponse.json());
|
|
50
|
+
// Save the MCP token (not the JWT token)
|
|
51
|
+
this.authManager.saveToken(mcpTokenData.token);
|
|
52
|
+
const loginData = await loginResponse.json();
|
|
53
|
+
return loginData;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* プロジェクトを登録
|
|
57
|
+
*/
|
|
58
|
+
async registerProject(projectData) {
|
|
59
|
+
const token = this.authManager.getToken();
|
|
60
|
+
if (!token) {
|
|
61
|
+
throw new Error("Not authenticated. Please login first.");
|
|
62
|
+
}
|
|
63
|
+
const response = await fetch(`${this.baseUrl}/apps`, {
|
|
64
|
+
method: "POST",
|
|
65
|
+
headers: {
|
|
66
|
+
"Content-Type": "application/json",
|
|
67
|
+
Authorization: `Bearer ${token}`,
|
|
68
|
+
},
|
|
69
|
+
body: JSON.stringify(projectData),
|
|
70
|
+
});
|
|
71
|
+
if (!response.ok) {
|
|
72
|
+
const error = await response.text();
|
|
73
|
+
throw new Error(`Failed to register project: ${error}`);
|
|
74
|
+
}
|
|
75
|
+
const data = await response.json();
|
|
76
|
+
return data;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* 現在のユーザー情報を取得
|
|
80
|
+
*/
|
|
81
|
+
async getCurrentUser() {
|
|
82
|
+
const token = this.authManager.getToken();
|
|
83
|
+
if (!token) {
|
|
84
|
+
throw new Error("Not authenticated. Please login first.");
|
|
85
|
+
}
|
|
86
|
+
const response = await fetch(`${this.baseUrl}/auth/me`, {
|
|
87
|
+
method: "GET",
|
|
88
|
+
headers: {
|
|
89
|
+
Authorization: `Bearer ${token}`,
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
throw new Error("Failed to get current user");
|
|
94
|
+
}
|
|
95
|
+
const data = (await response.json());
|
|
96
|
+
return data.user;
|
|
97
|
+
}
|
|
98
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { analyzeProject } from "./analyzer.js";
|
|
6
|
+
import { SeeveClient } from "./client.js";
|
|
7
|
+
import { AuthManager } from "./auth.js";
|
|
8
|
+
// MCP Server for Seevo
|
|
9
|
+
const server = new Server({
|
|
10
|
+
name: "seevo-mcp-server",
|
|
11
|
+
version: "1.0.0",
|
|
12
|
+
}, {
|
|
13
|
+
capabilities: {
|
|
14
|
+
tools: {},
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
// Initialize auth manager
|
|
18
|
+
const authManager = new AuthManager();
|
|
19
|
+
const seeveClient = new SeeveClient(authManager);
|
|
20
|
+
// Define available tools
|
|
21
|
+
const TOOLS = [
|
|
22
|
+
{
|
|
23
|
+
name: "seevo_register_project",
|
|
24
|
+
description: "現在のプロジェクトをSeevoに登録します。プロジェクトディレクトリを解析してサービス情報を自動抽出し、Seevoバックエンドに登録します。",
|
|
25
|
+
inputSchema: {
|
|
26
|
+
type: "object",
|
|
27
|
+
properties: {
|
|
28
|
+
project_path: {
|
|
29
|
+
type: "string",
|
|
30
|
+
description: "プロジェクトディレクトリのパス(省略時はカレントディレクトリ)",
|
|
31
|
+
},
|
|
32
|
+
name: {
|
|
33
|
+
type: "string",
|
|
34
|
+
description: "サービス名(省略時は自動検出)",
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "seevo_login",
|
|
41
|
+
description: "Seevoにログインして認証トークンを保存します。一度ログインすれば、以降の操作で自動的に認証されます。",
|
|
42
|
+
inputSchema: {
|
|
43
|
+
type: "object",
|
|
44
|
+
properties: {
|
|
45
|
+
email: {
|
|
46
|
+
type: "string",
|
|
47
|
+
description: "メールアドレス",
|
|
48
|
+
},
|
|
49
|
+
password: {
|
|
50
|
+
type: "string",
|
|
51
|
+
description: "パスワード",
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
required: ["email", "password"],
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: "seevo_logout",
|
|
59
|
+
description: "Seevoからログアウトして保存された認証トークンを削除します。",
|
|
60
|
+
inputSchema: {
|
|
61
|
+
type: "object",
|
|
62
|
+
properties: {},
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
];
|
|
66
|
+
// Handle list_tools request
|
|
67
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
68
|
+
return { tools: TOOLS };
|
|
69
|
+
});
|
|
70
|
+
// Handle call_tool request
|
|
71
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
72
|
+
const { name, arguments: args } = request.params;
|
|
73
|
+
try {
|
|
74
|
+
switch (name) {
|
|
75
|
+
case "seevo_register_project": {
|
|
76
|
+
const projectPath = args?.project_path || process.cwd();
|
|
77
|
+
const projectName = args?.name;
|
|
78
|
+
// Check authentication
|
|
79
|
+
if (!authManager.isAuthenticated()) {
|
|
80
|
+
return {
|
|
81
|
+
content: [
|
|
82
|
+
{
|
|
83
|
+
type: "text",
|
|
84
|
+
text: "エラー: Seevoにログインしていません。先に seevo_login ツールでログインしてください。",
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
// Analyze project
|
|
90
|
+
const analysis = await analyzeProject(projectPath, projectName);
|
|
91
|
+
// Register to Seevo
|
|
92
|
+
const result = await seeveClient.registerProject(analysis);
|
|
93
|
+
const techStackText = result.tech_stack && result.tech_stack.length > 0
|
|
94
|
+
? `\n**技術スタック**: ${result.tech_stack.join(", ")}`
|
|
95
|
+
: "";
|
|
96
|
+
const featuresText = result.features && result.features.length > 0
|
|
97
|
+
? `\n**主な機能**:\n${result.features.map(f => ` - ${f}`).join("\n")}`
|
|
98
|
+
: "";
|
|
99
|
+
return {
|
|
100
|
+
content: [
|
|
101
|
+
{
|
|
102
|
+
type: "text",
|
|
103
|
+
text: `✅ プロジェクトをSeevoに登録しました!
|
|
104
|
+
|
|
105
|
+
**サービス名**: ${result.service_name}
|
|
106
|
+
**説明**: ${result.description}
|
|
107
|
+
**ターゲット**: ${result.target}${techStackText}${featuresText}
|
|
108
|
+
**アプリID**: ${result.id}
|
|
109
|
+
|
|
110
|
+
Seevoダッシュボードで確認できます: http://localhost:3000/dashboard?project=${result.id}`,
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
case "seevo_login": {
|
|
116
|
+
const email = args?.email;
|
|
117
|
+
const password = args?.password;
|
|
118
|
+
if (!email || !password) {
|
|
119
|
+
return {
|
|
120
|
+
content: [
|
|
121
|
+
{
|
|
122
|
+
type: "text",
|
|
123
|
+
text: "エラー: emailとpasswordは必須です。",
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
const loginResult = await seeveClient.login(email, password);
|
|
129
|
+
return {
|
|
130
|
+
content: [
|
|
131
|
+
{
|
|
132
|
+
type: "text",
|
|
133
|
+
text: `✅ Seevoにログインしました!
|
|
134
|
+
|
|
135
|
+
**ユーザー名**: ${loginResult.user.name}
|
|
136
|
+
**メール**: ${loginResult.user.email}
|
|
137
|
+
|
|
138
|
+
これで seevo_register_project ツールを使用できます。`,
|
|
139
|
+
},
|
|
140
|
+
],
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
case "seevo_logout": {
|
|
144
|
+
authManager.clearToken();
|
|
145
|
+
return {
|
|
146
|
+
content: [
|
|
147
|
+
{
|
|
148
|
+
type: "text",
|
|
149
|
+
text: "✅ Seevoからログアウトしました。",
|
|
150
|
+
},
|
|
151
|
+
],
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
default:
|
|
155
|
+
return {
|
|
156
|
+
content: [
|
|
157
|
+
{
|
|
158
|
+
type: "text",
|
|
159
|
+
text: `エラー: 不明なツール '${name}'`,
|
|
160
|
+
},
|
|
161
|
+
],
|
|
162
|
+
isError: true,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
168
|
+
return {
|
|
169
|
+
content: [
|
|
170
|
+
{
|
|
171
|
+
type: "text",
|
|
172
|
+
text: `エラー: ${errorMessage}`,
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
isError: true,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
// Start server
|
|
180
|
+
async function main() {
|
|
181
|
+
const transport = new StdioServerTransport();
|
|
182
|
+
await server.connect(transport);
|
|
183
|
+
console.error("Seevo MCP Server running on stdio");
|
|
184
|
+
}
|
|
185
|
+
main().catch((error) => {
|
|
186
|
+
console.error("Fatal error:", error);
|
|
187
|
+
process.exit(1);
|
|
188
|
+
});
|
package/dist/setup.js
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
3
|
+
import { homedir, platform } from "os";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
const SEEVO_API_URL = process.env.SEEVO_API_URL || "http://localhost:8080/api/v1";
|
|
6
|
+
// OS別のグローバル設定パスを取得
|
|
7
|
+
function getGlobalConfigPath() {
|
|
8
|
+
const os = platform();
|
|
9
|
+
switch (os) {
|
|
10
|
+
case "darwin": // macOS
|
|
11
|
+
return join(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
12
|
+
case "win32": // Windows
|
|
13
|
+
return join(process.env.APPDATA || "", "Claude", "claude_desktop_config.json");
|
|
14
|
+
case "linux":
|
|
15
|
+
return join(homedir(), ".config", "Claude", "claude_desktop_config.json");
|
|
16
|
+
default:
|
|
17
|
+
throw new Error(`Unsupported OS: ${os}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function setupMCP(token, isGlobal, projectPath) {
|
|
21
|
+
console.log("\n🚀 Seevo MCP Server セットアップを開始します...\n");
|
|
22
|
+
// トークンの検証
|
|
23
|
+
if (!token || !token.startsWith("seevo_mcp_")) {
|
|
24
|
+
console.error("❌ エラー: 有効なSeevo MCPトークンを指定してください");
|
|
25
|
+
console.error(" トークンは 'seevo_mcp_' で始まる必要があります\n");
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
const configPath = isGlobal
|
|
29
|
+
? getGlobalConfigPath()
|
|
30
|
+
: join(projectPath || process.cwd(), ".mcp.json");
|
|
31
|
+
console.log(`📝 設定ファイル: ${configPath}`);
|
|
32
|
+
console.log(`🌍 スコープ: ${isGlobal ? "グローバル(全プロジェクト)" : "ローカル(このプロジェクトのみ)"}\n`);
|
|
33
|
+
// グローバル設定の場合はディレクトリを確認・作成
|
|
34
|
+
if (isGlobal) {
|
|
35
|
+
const configDir = join(configPath, "..");
|
|
36
|
+
if (!existsSync(configDir)) {
|
|
37
|
+
console.log("📁 設定ディレクトリを作成中...");
|
|
38
|
+
mkdirSync(configDir, { recursive: true });
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// 既存の設定を読み込む(あれば)
|
|
42
|
+
let config = {};
|
|
43
|
+
if (existsSync(configPath)) {
|
|
44
|
+
try {
|
|
45
|
+
const existingConfig = readFileSync(configPath, "utf-8");
|
|
46
|
+
config = JSON.parse(existingConfig);
|
|
47
|
+
console.log("✓ 既存の設定ファイルを読み込みました");
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
console.warn("⚠️ 既存の設定ファイルの読み込みに失敗しました。新規作成します。");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// mcpServersセクションがなければ作成
|
|
54
|
+
if (!config.mcpServers) {
|
|
55
|
+
config.mcpServers = {};
|
|
56
|
+
}
|
|
57
|
+
// Seevo MCPサーバーの設定を追加
|
|
58
|
+
config.mcpServers.seevo = {
|
|
59
|
+
command: "npx",
|
|
60
|
+
args: ["@zelklab/seevo-mcp-server"],
|
|
61
|
+
env: {
|
|
62
|
+
SEEVO_MCP_TOKEN: token,
|
|
63
|
+
SEEVO_API_URL: SEEVO_API_URL,
|
|
64
|
+
},
|
|
65
|
+
};
|
|
66
|
+
// 設定ファイルに書き込み
|
|
67
|
+
try {
|
|
68
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
|
|
69
|
+
console.log("✓ 設定ファイルを更新しました");
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error("❌ 設定ファイルの書き込みに失敗しました:", error);
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
// 完了メッセージ
|
|
76
|
+
console.log("\n" + "=".repeat(60));
|
|
77
|
+
console.log("✅ セットアップ完了!");
|
|
78
|
+
console.log("=".repeat(60));
|
|
79
|
+
console.log(`\n📍 設定ファイルの場所: ${configPath}\n`);
|
|
80
|
+
console.log("次のステップ:\n");
|
|
81
|
+
if (!isGlobal) {
|
|
82
|
+
console.log(` 1. プロジェクトのルートディレクトリで Claude Code を開いてください`);
|
|
83
|
+
console.log(` (.mcp.json が置かれているディレクトリ)`);
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
console.log(` 1. Claude Codeを再起動してください`);
|
|
87
|
+
}
|
|
88
|
+
console.log(" 2. 以下のように話しかけてください:\n");
|
|
89
|
+
console.log(' "このプロジェクトをSeevoに登録して"\n');
|
|
90
|
+
if (!isGlobal) {
|
|
91
|
+
console.log("⚠️ 重要:");
|
|
92
|
+
console.log(" • .mcp.json ファイルには認証トークンが含まれています");
|
|
93
|
+
console.log(" • このファイルを .gitignore に追加することを推奨します:");
|
|
94
|
+
console.log(" echo '.mcp.json' >> .gitignore");
|
|
95
|
+
console.log(" • または、チームで共有する場合は環境変数を使ってください\n");
|
|
96
|
+
}
|
|
97
|
+
console.log("📚 利用可能なツール:");
|
|
98
|
+
console.log(" • seevo_register_project - プロジェクトを自動解析して登録");
|
|
99
|
+
console.log(" • seevo_login - 別アカウントでログイン");
|
|
100
|
+
console.log(" • seevo_logout - ログアウト\n");
|
|
101
|
+
console.log("💡 ヒント:Claude Codeは自動的にプロジェクトを解析し、");
|
|
102
|
+
console.log(" 目的、ターゲット、機能、技術スタックを理解します。\n");
|
|
103
|
+
}
|
|
104
|
+
// CLI実行
|
|
105
|
+
const args = process.argv.slice(2);
|
|
106
|
+
if (args.length === 0) {
|
|
107
|
+
console.error("❌ エラー: トークンを指定してください\n");
|
|
108
|
+
console.log("使い方:");
|
|
109
|
+
console.log(" npx @zelklab/seevo-mcp-server setup YOUR_TOKEN # デフォルト: ローカル");
|
|
110
|
+
console.log(" npx @zelklab/seevo-mcp-server setup YOUR_TOKEN --local # プロジェクトローカル(推奨)");
|
|
111
|
+
console.log(" npx @zelklab/seevo-mcp-server setup YOUR_TOKEN --global # グローバル設定");
|
|
112
|
+
console.log(" npx @zelklab/seevo-mcp-server setup YOUR_TOKEN --path /path/to/project # 別のプロジェクトに設定\n");
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
// 引数をパース
|
|
116
|
+
let token = "";
|
|
117
|
+
let isGlobal = false;
|
|
118
|
+
let projectPath;
|
|
119
|
+
// setupコマンドが含まれている場合はスキップ
|
|
120
|
+
const startIndex = args[0] === "setup" ? 1 : 0;
|
|
121
|
+
for (let i = startIndex; i < args.length; i++) {
|
|
122
|
+
const arg = args[i];
|
|
123
|
+
if (arg === "--global") {
|
|
124
|
+
isGlobal = true;
|
|
125
|
+
}
|
|
126
|
+
else if (arg === "--local") {
|
|
127
|
+
isGlobal = false;
|
|
128
|
+
}
|
|
129
|
+
else if (arg === "--path" && args[i + 1]) {
|
|
130
|
+
projectPath = args[i + 1];
|
|
131
|
+
i++; // 次の引数をスキップ
|
|
132
|
+
}
|
|
133
|
+
else if (arg === "--token" && args[i + 1]) {
|
|
134
|
+
token = args[i + 1];
|
|
135
|
+
i++; // 次の引数をスキップ
|
|
136
|
+
}
|
|
137
|
+
else if (!arg.startsWith("--") && !token) {
|
|
138
|
+
// フラグでなく、まだトークンが設定されていない場合
|
|
139
|
+
token = arg;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (!token) {
|
|
143
|
+
console.error("❌ エラー: トークンが見つかりません\n");
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
// グローバルとプロジェクトパスが同時に指定された場合はエラー
|
|
147
|
+
if (isGlobal && projectPath) {
|
|
148
|
+
console.error("❌ エラー: --global と --path は同時に指定できません\n");
|
|
149
|
+
process.exit(1);
|
|
150
|
+
}
|
|
151
|
+
setupMCP(token, isGlobal, projectPath);
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zelklab/seevo-mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP Server for Seevo - AI-powered project registration from Claude Code",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"seevo-mcp": "./dist/setup.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"dev": "tsc && node dist/index.js",
|
|
14
|
+
"setup": "node dist/setup.js",
|
|
15
|
+
"prepublishOnly": "npm run build"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"keywords": [
|
|
23
|
+
"mcp",
|
|
24
|
+
"seevo",
|
|
25
|
+
"claude-code",
|
|
26
|
+
"ai",
|
|
27
|
+
"marketing",
|
|
28
|
+
"automation"
|
|
29
|
+
],
|
|
30
|
+
"author": "Your Name <your-email@example.com>",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/your-username/seevo.git",
|
|
35
|
+
"directory": "mcp-server"
|
|
36
|
+
},
|
|
37
|
+
"homepage": "https://github.com/your-username/seevo#readme",
|
|
38
|
+
"bugs": {
|
|
39
|
+
"url": "https://github.com/your-username/seevo/issues"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=18.0.0"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@modelcontextprotocol/sdk": "^0.6.0",
|
|
46
|
+
"node-fetch": "^3.3.2"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^22.0.0",
|
|
50
|
+
"typescript": "^5.6.0"
|
|
51
|
+
}
|
|
52
|
+
}
|