owner-clone-ai-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/index.js +193 -0
- package/package.json +30 -0
package/index.js
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
|
|
5
|
+
const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
|
|
6
|
+
const { CallToolRequestSchema, ListToolsRequestSchema } = require('@modelcontextprotocol/sdk/types.js');
|
|
7
|
+
|
|
8
|
+
const API_KEY = process.env.OCR_API_KEY;
|
|
9
|
+
const BASE_URL = (process.env.OCR_BASE_URL || 'https://api.ownercloneai.com').replace(/\/$/, '');
|
|
10
|
+
|
|
11
|
+
if (!API_KEY) {
|
|
12
|
+
process.stderr.write('Error: OCR_API_KEY environment variable is required\n');
|
|
13
|
+
process.exit(1);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async function callApi(path, options = {}) {
|
|
17
|
+
const url = `${BASE_URL}/api/mcp/v1${path}`;
|
|
18
|
+
const res = await fetch(url, {
|
|
19
|
+
...options,
|
|
20
|
+
headers: {
|
|
21
|
+
'Authorization': `Bearer ${API_KEY}`,
|
|
22
|
+
'Content-Type': 'application/json',
|
|
23
|
+
...(options.headers || {}),
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
const json = await res.json();
|
|
27
|
+
if (!res.ok) throw new Error(json.error || `API error ${res.status}`);
|
|
28
|
+
return json;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ── ツール定義 ─────────────────────────────────────────────────
|
|
32
|
+
const TOOLS = [
|
|
33
|
+
{
|
|
34
|
+
name: 'search_knowledge',
|
|
35
|
+
description: 'Owner Clone AIのナレッジベースを検索します。セマンティック検索(意味検索)とキーワード検索を使用します。',
|
|
36
|
+
inputSchema: {
|
|
37
|
+
type: 'object',
|
|
38
|
+
properties: {
|
|
39
|
+
query: { type: 'string', description: '検索クエリ' },
|
|
40
|
+
limit: { type: 'number', description: '取得件数(デフォルト: 10)' },
|
|
41
|
+
},
|
|
42
|
+
required: ['query'],
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: 'list_knowledge_items',
|
|
47
|
+
description: 'Owner Clone AIに登録されたナレッジの一覧を取得します。フォルダやカテゴリで絞り込み可能。',
|
|
48
|
+
inputSchema: {
|
|
49
|
+
type: 'object',
|
|
50
|
+
properties: {
|
|
51
|
+
folder_id: { type: 'string', description: 'フォルダIDで絞り込み(省略可)' },
|
|
52
|
+
category: { type: 'string', description: 'カテゴリで絞り込み(省略可)' },
|
|
53
|
+
limit: { type: 'number', description: '取得件数(デフォルト: 50)' },
|
|
54
|
+
offset: { type: 'number', description: 'オフセット(デフォルト: 0)' },
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'get_knowledge_item',
|
|
60
|
+
description: '指定したIDのナレッジの全文を取得します。',
|
|
61
|
+
inputSchema: {
|
|
62
|
+
type: 'object',
|
|
63
|
+
properties: {
|
|
64
|
+
id: { type: 'string', description: 'ナレッジID' },
|
|
65
|
+
},
|
|
66
|
+
required: ['id'],
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
name: 'list_knowledge_folders',
|
|
71
|
+
description: 'ナレッジのフォルダ一覧を取得します。',
|
|
72
|
+
inputSchema: { type: 'object', properties: {} },
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'list_agent_presets',
|
|
76
|
+
description: 'AIパートナー(エージェントプリセット)の一覧を取得します。システムプリセットも含みます。ナレッジ内容は含みません。',
|
|
77
|
+
inputSchema: { type: 'object', properties: {} },
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'get_agent_preset',
|
|
81
|
+
description: '指定したIDのAIパートナーの詳細(システムプロンプト・ルール)を取得します。セキュリティ上、紐づくナレッジの内容は返しません。',
|
|
82
|
+
inputSchema: {
|
|
83
|
+
type: 'object',
|
|
84
|
+
properties: {
|
|
85
|
+
id: { type: 'string', description: 'プリセットID' },
|
|
86
|
+
},
|
|
87
|
+
required: ['id'],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
// ── ツール実行 ─────────────────────────────────────────────────
|
|
93
|
+
async function executeTool(name, args) {
|
|
94
|
+
switch (name) {
|
|
95
|
+
case 'search_knowledge': {
|
|
96
|
+
const data = await callApi('/knowledge/search', {
|
|
97
|
+
method: 'POST',
|
|
98
|
+
body: JSON.stringify({ query: args.query, limit: args.limit }),
|
|
99
|
+
});
|
|
100
|
+
if (!data.results || data.results.length === 0) {
|
|
101
|
+
return `「${args.query}」に一致するナレッジは見つかりませんでした。`;
|
|
102
|
+
}
|
|
103
|
+
const lines = data.results.map((r, i) =>
|
|
104
|
+
`[${i + 1}] ${r.title} (${r.category || 'その他'})\n${r.matched_content}`
|
|
105
|
+
);
|
|
106
|
+
return `検索方法: ${data.method}\n\n${lines.join('\n\n')}`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
case 'list_knowledge_items': {
|
|
110
|
+
const params = new URLSearchParams();
|
|
111
|
+
if (args.folder_id) params.set('folder_id', args.folder_id);
|
|
112
|
+
if (args.category) params.set('category', args.category);
|
|
113
|
+
if (args.limit) params.set('limit', String(args.limit));
|
|
114
|
+
if (args.offset) params.set('offset', String(args.offset));
|
|
115
|
+
const data = await callApi(`/knowledge?${params}`);
|
|
116
|
+
if (!data.items || data.items.length === 0) return 'ナレッジが登録されていません。';
|
|
117
|
+
const lines = data.items.map(item =>
|
|
118
|
+
`- [${item.id}] ${item.title} (${item.category || 'その他'}) 更新: ${item.updated_at?.slice(0, 10)}\n ${item.preview || ''}`
|
|
119
|
+
);
|
|
120
|
+
return `ナレッジ一覧(${data.items.length}件):\n\n${lines.join('\n')}`;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
case 'get_knowledge_item': {
|
|
124
|
+
const data = await callApi(`/knowledge/${args.id}`);
|
|
125
|
+
return `タイトル: ${data.title}\nカテゴリ: ${data.category || 'その他'}\n更新日: ${data.updated_at?.slice(0, 10)}\n\n--- 内容 ---\n${data.text_content}`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
case 'list_knowledge_folders': {
|
|
129
|
+
const data = await callApi('/knowledge-folders');
|
|
130
|
+
if (!data.folders || data.folders.length === 0) return 'フォルダが作成されていません。';
|
|
131
|
+
const lines = data.folders.map(f => `- [${f.id}] ${f.name}`);
|
|
132
|
+
return `フォルダ一覧(${data.folders.length}件):\n\n${lines.join('\n')}`;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
case 'list_agent_presets': {
|
|
136
|
+
const data = await callApi('/agent-presets');
|
|
137
|
+
if (!data.presets || data.presets.length === 0) return 'AIパートナーが登録されていません。';
|
|
138
|
+
const lines = data.presets.map(p =>
|
|
139
|
+
`- [${p.id}] ${p.name}${p.is_system ? ' (システム)' : ''}\n ${p.description || ''}`
|
|
140
|
+
);
|
|
141
|
+
return `AIパートナー一覧(${data.presets.length}件):\n\n${lines.join('\n')}`;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
case 'get_agent_preset': {
|
|
145
|
+
const data = await callApi(`/agent-presets/${args.id}`);
|
|
146
|
+
const parts = [
|
|
147
|
+
`名前: ${data.name}`,
|
|
148
|
+
data.description ? `説明: ${data.description}` : '',
|
|
149
|
+
data.is_system ? '種別: システムプリセット' : '種別: カスタム',
|
|
150
|
+
data.base_prompt ? `\n--- システムプロンプト ---\n${data.base_prompt}` : '',
|
|
151
|
+
data.rules_allow ? `\n--- 許可ルール ---\n${data.rules_allow}` : '',
|
|
152
|
+
data.rules_deny ? `\n--- 禁止ルール ---\n${data.rules_deny}` : '',
|
|
153
|
+
data.sales_flow ? `\n--- セールスフロー ---\n${data.sales_flow}` : '',
|
|
154
|
+
].filter(Boolean);
|
|
155
|
+
return parts.join('\n');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
default:
|
|
159
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// ── MCPサーバー起動 ────────────────────────────────────────────
|
|
164
|
+
async function main() {
|
|
165
|
+
const server = new Server(
|
|
166
|
+
{ name: 'owner-clone-ai', version: '1.0.0' },
|
|
167
|
+
{ capabilities: { tools: {} } }
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
171
|
+
|
|
172
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
173
|
+
const { name, arguments: args } = request.params;
|
|
174
|
+
try {
|
|
175
|
+
const result = await executeTool(name, args || {});
|
|
176
|
+
return { content: [{ type: 'text', text: result }] };
|
|
177
|
+
} catch (err) {
|
|
178
|
+
return {
|
|
179
|
+
content: [{ type: 'text', text: `エラー: ${err.message}` }],
|
|
180
|
+
isError: true,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
const transport = new StdioServerTransport();
|
|
186
|
+
await server.connect(transport);
|
|
187
|
+
process.stderr.write('Owner Clone AI MCP server started\n');
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
main().catch(err => {
|
|
191
|
+
process.stderr.write(`Fatal: ${err.message}\n`);
|
|
192
|
+
process.exit(1);
|
|
193
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "owner-clone-ai-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for Owner Clone AI — exposes knowledge and agent presets to Claude Code",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"owner-clone-ai-mcp": "index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"index.js"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"start": "node index.js"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"mcp",
|
|
17
|
+
"claude",
|
|
18
|
+
"claude-code",
|
|
19
|
+
"owner-clone-ai",
|
|
20
|
+
"ai",
|
|
21
|
+
"knowledge"
|
|
22
|
+
],
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18.0.0"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@modelcontextprotocol/sdk": "^1.0.0"
|
|
29
|
+
}
|
|
30
|
+
}
|