edition-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 +90 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +363 -0
- package/package.json +32 -0
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# edition-mcp-server
|
|
2
|
+
|
|
3
|
+
MCP server for the **EDITION Intelligence Platform** — contextual intelligence infrastructure for AI agents operating in Japan.
|
|
4
|
+
|
|
5
|
+
## What it does
|
|
6
|
+
|
|
7
|
+
Provides 8 tools that give AI agents the ability to:
|
|
8
|
+
|
|
9
|
+
- **Remember** conversations with Japanese-aware fact extraction (keigo analysis, social hierarchy detection, confidence scoring)
|
|
10
|
+
- **Navigate** Japanese business regulations across 10 industries + tourist rules
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npx edition-mcp-server
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or install globally:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g edition-mcp-server
|
|
22
|
+
edition-mcp
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Configure
|
|
26
|
+
|
|
27
|
+
### Claude Desktop
|
|
28
|
+
|
|
29
|
+
Add to `claude_desktop_config.json`:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"mcpServers": {
|
|
34
|
+
"edition": {
|
|
35
|
+
"command": "npx",
|
|
36
|
+
"args": ["-y", "edition-mcp-server"],
|
|
37
|
+
"env": {
|
|
38
|
+
"EDITION_API_URL": "http://localhost:8000",
|
|
39
|
+
"EDITION_API_KEY": "your_api_key"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Cursor
|
|
47
|
+
|
|
48
|
+
Add to MCP settings:
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"edition": {
|
|
53
|
+
"command": "npx",
|
|
54
|
+
"args": ["-y", "edition-mcp-server"],
|
|
55
|
+
"env": {
|
|
56
|
+
"EDITION_API_URL": "http://localhost:8000",
|
|
57
|
+
"EDITION_API_KEY": "your_api_key"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Tools
|
|
64
|
+
|
|
65
|
+
| Tool | Description |
|
|
66
|
+
|------|-------------|
|
|
67
|
+
| `memory_store` | Store episode + auto-extract structured facts from Japanese text |
|
|
68
|
+
| `memory_recall` | Semantic search across stored episodes |
|
|
69
|
+
| `memory_facts` | List structured facts (subject → predicate → object with confidence) |
|
|
70
|
+
| `memory_context` | Get context summary for an entity or session |
|
|
71
|
+
| `memory_extract` | Extract facts from text with keigo/hierarchy analysis |
|
|
72
|
+
| `regulation_check` | Check Japanese business regulations by industry |
|
|
73
|
+
| `regulation_industries` | List all 10 supported industries |
|
|
74
|
+
| `regulation_tourist` | Tourist regulation lookup (visa, tax-free, transit, etc.) |
|
|
75
|
+
|
|
76
|
+
## Backend
|
|
77
|
+
|
|
78
|
+
This MCP server connects to the EDITION REST API backend. To run your own:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
git clone https://github.com/hiroshic9-png/edition.git
|
|
82
|
+
cd edition
|
|
83
|
+
python3 -m venv venv && source venv/bin/activate
|
|
84
|
+
pip install -r requirements.txt
|
|
85
|
+
python -m uvicorn backend.api.main:app --reload
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* EDITION Intelligence Platform — MCP Server
|
|
4
|
+
*
|
|
5
|
+
* AI agents can use these tools to:
|
|
6
|
+
* - Store and recall memories with Japanese language understanding
|
|
7
|
+
* - Check Japanese business regulations and compliance requirements
|
|
8
|
+
* - Get tourist/visitor information for Japan
|
|
9
|
+
*
|
|
10
|
+
* Connects to the EDITION REST API backend.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
/**
|
|
4
|
+
* EDITION Intelligence Platform — MCP Server
|
|
5
|
+
*
|
|
6
|
+
* AI agents can use these tools to:
|
|
7
|
+
* - Store and recall memories with Japanese language understanding
|
|
8
|
+
* - Check Japanese business regulations and compliance requirements
|
|
9
|
+
* - Get tourist/visitor information for Japan
|
|
10
|
+
*
|
|
11
|
+
* Connects to the EDITION REST API backend.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
const mcp_js_1 = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
15
|
+
const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
16
|
+
const zod_1 = require("zod");
|
|
17
|
+
// ── Configuration ───────────────────────────────────
|
|
18
|
+
const API_BASE = process.env.EDITION_API_URL || "https://edition-api.onrender.com";
|
|
19
|
+
const API_KEY = process.env.EDITION_API_KEY || "edition_dev_key_for_testing";
|
|
20
|
+
// ── HTTP helpers ────────────────────────────────────
|
|
21
|
+
async function apiGet(path) {
|
|
22
|
+
const res = await fetch(`${API_BASE}${path}`, {
|
|
23
|
+
headers: {
|
|
24
|
+
Authorization: `Bearer ${API_KEY}`,
|
|
25
|
+
"Content-Type": "application/json",
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
if (!res.ok) {
|
|
29
|
+
throw new Error(`API error ${res.status}: ${await res.text()}`);
|
|
30
|
+
}
|
|
31
|
+
return res.json();
|
|
32
|
+
}
|
|
33
|
+
async function apiPost(path, body) {
|
|
34
|
+
const res = await fetch(`${API_BASE}${path}`, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: {
|
|
37
|
+
Authorization: `Bearer ${API_KEY}`,
|
|
38
|
+
"Content-Type": "application/json",
|
|
39
|
+
},
|
|
40
|
+
body: JSON.stringify(body),
|
|
41
|
+
});
|
|
42
|
+
if (!res.ok) {
|
|
43
|
+
throw new Error(`API error ${res.status}: ${await res.text()}`);
|
|
44
|
+
}
|
|
45
|
+
return res.json();
|
|
46
|
+
}
|
|
47
|
+
// ── MCP Server ──────────────────────────────────────
|
|
48
|
+
const server = new mcp_js_1.McpServer({
|
|
49
|
+
name: "edition",
|
|
50
|
+
version: "0.1.0",
|
|
51
|
+
});
|
|
52
|
+
// ── Tool: memory_store ──────────────────────────────
|
|
53
|
+
server.tool("memory_store", "会話やイベントのエピソードを永続記憶に保存します。日本語の文脈(敬語レベル、主語省略、暗黙の了解)も構造化して保持します。auto_extract=trueにすると、テキストからファクト(主語→述語→目的語の三つ組)を自動抽出します。", {
|
|
54
|
+
content: zod_1.z.string().describe("保存する内容(日本語/英語対応)"),
|
|
55
|
+
session_id: zod_1.z.string().optional().describe("セッション識別子"),
|
|
56
|
+
role: zod_1.z.enum(["user", "assistant", "system"]).default("user").describe("発話者の役割"),
|
|
57
|
+
auto_extract: zod_1.z.boolean().default(false).describe("LLMでファクトを自動抽出するか"),
|
|
58
|
+
}, async ({ content, session_id, role, auto_extract }) => {
|
|
59
|
+
const result = await apiPost("/api/v1/memory/episodes", {
|
|
60
|
+
content,
|
|
61
|
+
session_id,
|
|
62
|
+
role,
|
|
63
|
+
auto_extract,
|
|
64
|
+
});
|
|
65
|
+
let text = `✅ エピソードを保存しました (ID: ${result.id})`;
|
|
66
|
+
if (result.extracted_facts?.length) {
|
|
67
|
+
text += `\n\n📋 自動抽出されたファクト (${result.extracted_facts.length}件):`;
|
|
68
|
+
for (const f of result.extracted_facts) {
|
|
69
|
+
text += `\n - ${f.subject} → ${f.predicate} → ${f.object} (確度: ${(f.confidence * 100).toFixed(0)}%)`;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return { content: [{ type: "text", text }] };
|
|
73
|
+
});
|
|
74
|
+
// ── Tool: memory_recall ─────────────────────────────
|
|
75
|
+
server.tool("memory_recall", "過去の記憶をセマンティック検索で呼び出します。「前回の会議で○○部長が仰った件」のような曖昧な日本語クエリにも対応します。", {
|
|
76
|
+
query: zod_1.z.string().describe("検索クエリ(日本語/英語対応)"),
|
|
77
|
+
limit: zod_1.z.number().int().min(1).max(20).default(5).describe("取得件数"),
|
|
78
|
+
}, async ({ query, limit }) => {
|
|
79
|
+
const result = await apiPost("/api/v1/memory/episodes/search", {
|
|
80
|
+
query,
|
|
81
|
+
limit,
|
|
82
|
+
});
|
|
83
|
+
if (!result.results?.length) {
|
|
84
|
+
return { content: [{ type: "text", text: "該当する記憶が見つかりませんでした。" }] };
|
|
85
|
+
}
|
|
86
|
+
let text = `🔍 検索結果 (${result.count}件):`;
|
|
87
|
+
for (const r of result.results) {
|
|
88
|
+
const dist = r.distance ? ` [類似度: ${(1 - r.distance).toFixed(2)}]` : "";
|
|
89
|
+
text += `\n\n---\n${r.document}${dist}`;
|
|
90
|
+
}
|
|
91
|
+
return { content: [{ type: "text", text }] };
|
|
92
|
+
});
|
|
93
|
+
// ── Tool: memory_facts ──────────────────────────────
|
|
94
|
+
server.tool("memory_facts", "現在有効なファクト(構造化された事実)の一覧を取得します。ファクトは「主語→述語→目的語」の三つ組で、確度と有効期限を持ちます。", {
|
|
95
|
+
valid_only: zod_1.z.boolean().default(true).describe("有効なファクトのみ取得するか"),
|
|
96
|
+
}, async ({ valid_only }) => {
|
|
97
|
+
const result = await apiGet(`/api/v1/memory/facts?valid_only=${valid_only}`);
|
|
98
|
+
if (!result.facts?.length) {
|
|
99
|
+
return { content: [{ type: "text", text: "保存されたファクトはありません。" }] };
|
|
100
|
+
}
|
|
101
|
+
let text = `📝 ファクト一覧 (${result.count}件):`;
|
|
102
|
+
for (const f of result.facts) {
|
|
103
|
+
const conf = f.confidence < 1.0 ? ` (確度: ${(f.confidence * 100).toFixed(0)}%)` : "";
|
|
104
|
+
text += `\n - ${f.subject} → ${f.predicate} → ${f.object}${conf}`;
|
|
105
|
+
}
|
|
106
|
+
return { content: [{ type: "text", text }] };
|
|
107
|
+
});
|
|
108
|
+
// ── Tool: memory_context ────────────────────────────
|
|
109
|
+
server.tool("memory_context", "現在のセッション状態(有効な事実・合意事項のサマリー)を取得します。エージェントのプロンプトに注入して文脈を維持するために使います。", {
|
|
110
|
+
session_id: zod_1.z.string().optional().describe("セッションID(省略で全体)"),
|
|
111
|
+
}, async ({ session_id }) => {
|
|
112
|
+
const params = session_id ? `?session_id=${encodeURIComponent(session_id)}` : "";
|
|
113
|
+
const result = await apiGet(`/api/v1/memory/context${params}`);
|
|
114
|
+
let text = `📌 コンテキストサマリー\n`;
|
|
115
|
+
text += `有効なファクト: ${result.active_facts_count}件\n`;
|
|
116
|
+
text += `直近のエピソード: ${result.recent_episodes_count}件\n\n`;
|
|
117
|
+
text += result.summary;
|
|
118
|
+
return { content: [{ type: "text", text }] };
|
|
119
|
+
});
|
|
120
|
+
// ── Tool: memory_extract ────────────────────────────
|
|
121
|
+
server.tool("memory_extract", "テキストからファクトを自動抽出します。日本語の敬語・主語省略・社会的階層を分析して構造化します。store=trueで永続保存。", {
|
|
122
|
+
text: zod_1.z.string().describe("ファクトを抽出するテキスト"),
|
|
123
|
+
context_hint: zod_1.z.string().default("").describe("コンテキストヒント(例: ビジネスミーティング)"),
|
|
124
|
+
store: zod_1.z.boolean().default(false).describe("抽出したファクトを永続保存するか"),
|
|
125
|
+
}, async ({ text, context_hint, store }) => {
|
|
126
|
+
const result = await apiPost("/api/v1/memory/extract", {
|
|
127
|
+
text,
|
|
128
|
+
context_hint,
|
|
129
|
+
store,
|
|
130
|
+
});
|
|
131
|
+
if (!result.extracted_facts?.length) {
|
|
132
|
+
return { content: [{ type: "text", text: "テキストからファクトを抽出できませんでした。" }] };
|
|
133
|
+
}
|
|
134
|
+
let response = `📋 抽出されたファクト (${result.extracted_facts.length}件):`;
|
|
135
|
+
for (const f of result.extracted_facts) {
|
|
136
|
+
const conf = f.confidence ? ` (確度: ${(f.confidence * 100).toFixed(0)}%)` : "";
|
|
137
|
+
response += `\n - ${f.subject} → ${f.predicate} → ${f.object}${conf}`;
|
|
138
|
+
}
|
|
139
|
+
response += `\n\n${result.stored ? "💾 保存済み" : "💡 未保存(store=trueで保存)"}`;
|
|
140
|
+
return { content: [{ type: "text", text: response }] };
|
|
141
|
+
});
|
|
142
|
+
// ── Tool: regulation_check ──────────────────────────
|
|
143
|
+
server.tool("regulation_check", "特定のビジネスアクションに必要な日本の規制・許認可情報を回答します。10業種の詳細データベース + 訪日旅行者向け規制に対応。", {
|
|
144
|
+
action: zod_1.z.string().describe("実行しようとしているアクション(例: 東京でレストランを開業する)"),
|
|
145
|
+
industry: zod_1.z.string().optional().describe("業種(省略可、自動判定)"),
|
|
146
|
+
entity_type: zod_1.z.enum(["foreign_company", "domestic_company", "individual", "tourist"]).default("foreign_company").describe("主体の種別"),
|
|
147
|
+
}, async ({ action, industry, entity_type }) => {
|
|
148
|
+
const result = await apiPost("/api/v1/regulation/check", {
|
|
149
|
+
action,
|
|
150
|
+
industry,
|
|
151
|
+
entity_type,
|
|
152
|
+
});
|
|
153
|
+
let text = "";
|
|
154
|
+
if (result.category === "tourist") {
|
|
155
|
+
// Tourist regulation response
|
|
156
|
+
text = `🗾 訪日旅行者向け規制: ${result.matched_topic}\n\n`;
|
|
157
|
+
text += `📋 概要: ${result.overview}\n\n`;
|
|
158
|
+
text += `📌 主なルール:\n`;
|
|
159
|
+
for (const rule of result.key_rules || []) {
|
|
160
|
+
text += ` - ${rule}\n`;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else if (result.matched_industry) {
|
|
164
|
+
// Business regulation response
|
|
165
|
+
text = `🏢 業種: ${result.matched_industry}\n`;
|
|
166
|
+
text += `📋 必要な許認可: ${(result.licenses_required || []).join(", ")}\n`;
|
|
167
|
+
text += `🏛️ 管轄: ${result.governing_body || ""}\n`;
|
|
168
|
+
text += `📖 根拠法: ${result.governing_law || ""}\n\n`;
|
|
169
|
+
text += `📌 要件:\n`;
|
|
170
|
+
for (const req of result.requirements || []) {
|
|
171
|
+
text += ` - ${req}\n`;
|
|
172
|
+
}
|
|
173
|
+
text += `\n⏱️ 期間: ${result.estimated_timeline || ""}`;
|
|
174
|
+
text += `\n💰 費用: ${result.costs || ""}`;
|
|
175
|
+
if (result.foreign_company_notes) {
|
|
176
|
+
text += `\n\n🌐 外国企業向け: ${result.foreign_company_notes}`;
|
|
177
|
+
}
|
|
178
|
+
if (result.penalties_for_non_compliance) {
|
|
179
|
+
text += `\n\n⚠️ 違反時: ${result.penalties_for_non_compliance}`;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
text = `❌ ${result.message || "該当する規制情報が見つかりませんでした。"}`;
|
|
184
|
+
if (result.suggestion)
|
|
185
|
+
text += `\n\n💡 ${result.suggestion}`;
|
|
186
|
+
}
|
|
187
|
+
text += `\n\n📊 確度: ${((result.confidence || 0) * 100).toFixed(0)}%`;
|
|
188
|
+
text += `\n⚠️ ${result.disclaimer || "この情報は参考用です。法的助言ではありません。"}`;
|
|
189
|
+
return { content: [{ type: "text", text }] };
|
|
190
|
+
});
|
|
191
|
+
// ── Tool: regulation_industries ──────────────────────
|
|
192
|
+
server.tool("regulation_industries", "日本の規制データベースに登録されている業種の一覧を取得します。", {}, async () => {
|
|
193
|
+
const result = await apiGet("/api/v1/regulation/industries");
|
|
194
|
+
let text = `🗾 対応業種一覧 (${result.count}業種):\n\n`;
|
|
195
|
+
for (const ind of result.industries) {
|
|
196
|
+
text += ` 🏢 ${ind.industry}\n`;
|
|
197
|
+
text += ` 許認可: ${ind.licenses.join(", ")}\n`;
|
|
198
|
+
text += ` 管轄: ${ind.governing_body}\n`;
|
|
199
|
+
text += ` 根拠法: ${ind.governing_law}\n\n`;
|
|
200
|
+
}
|
|
201
|
+
return { content: [{ type: "text", text }] };
|
|
202
|
+
});
|
|
203
|
+
// ── Tool: regulation_tourist ────────────────────────
|
|
204
|
+
server.tool("regulation_tourist", "訪日旅行者向けの規制・マナー情報のカテゴリ一覧を取得します。ビザ、免税、交通、宿泊、医療、マナーの6カテゴリ。", {}, async () => {
|
|
205
|
+
const result = await apiGet("/api/v1/regulation/tourist");
|
|
206
|
+
let text = `🗾 訪日旅行者向け規制カテゴリ (${result.count}件):\n\n`;
|
|
207
|
+
for (const cat of result.categories) {
|
|
208
|
+
text += ` 📋 ${cat.category}: ${cat.overview}\n\n`;
|
|
209
|
+
}
|
|
210
|
+
return { content: [{ type: "text", text }] };
|
|
211
|
+
});
|
|
212
|
+
// ── Tool: protocol_check ────────────────────────────
|
|
213
|
+
server.tool("protocol_check", "日本のビジネスプロトコル(根回し、稟議、報連相、名刺交換、席順、贈答)を検索します。", {
|
|
214
|
+
query: zod_1.z.string().describe("検索クエリ(例: '名刺交換の作法', '根回し')"),
|
|
215
|
+
}, async ({ query }) => {
|
|
216
|
+
const result = await apiPost("/api/v1/protocol/check", { query });
|
|
217
|
+
if (!result.protocol_id && !result.name_ja) {
|
|
218
|
+
return { content: [{ type: "text", text: `❌ '${query}' に該当するプロトコルが見つかりませんでした。` }] };
|
|
219
|
+
}
|
|
220
|
+
let text = `🤝 ${result.name_ja || result.protocol_id}\n`;
|
|
221
|
+
text += `📋 ${result.summary || ""}\n`;
|
|
222
|
+
if (result.how_to) {
|
|
223
|
+
text += `\n📌 手順:\n`;
|
|
224
|
+
for (const step of result.how_to) {
|
|
225
|
+
text += ` ${step.step}. ${step.action}: ${step.detail}\n`;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
if (result.protocol) {
|
|
229
|
+
text += `\n📌 手順:\n`;
|
|
230
|
+
for (const step of result.protocol) {
|
|
231
|
+
text += ` ${step.step}. ${step.action}: ${step.detail}\n`;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
text += `\n📊 確度: ${((result.confidence || 0) * 100).toFixed(0)}%`;
|
|
235
|
+
return { content: [{ type: "text", text }] };
|
|
236
|
+
});
|
|
237
|
+
// ── Tool: protocol_list ─────────────────────────────
|
|
238
|
+
server.tool("protocol_list", "日本のビジネスプロトコルの一覧を取得します。", {}, async () => {
|
|
239
|
+
const result = await apiGet("/api/v1/protocol/list");
|
|
240
|
+
let text = `🤝 プロトコル一覧 (${result.count}件):\n\n`;
|
|
241
|
+
for (const p of result.protocols) {
|
|
242
|
+
text += ` • ${p.name_ja} (${p.name_en}) — ${p.importance}\n ${p.summary}\n\n`;
|
|
243
|
+
}
|
|
244
|
+
return { content: [{ type: "text", text }] };
|
|
245
|
+
});
|
|
246
|
+
// ── Tool: calendar_check ────────────────────────────
|
|
247
|
+
server.tool("calendar_check", "日本のビジネスカレンダー情報を検索します。祝日、決算期、贈答シーズン、行政締切、季節性ビジネスの5カテゴリ。", {
|
|
248
|
+
query: zod_1.z.string().describe("検索クエリ(例: '開業のベストタイミング', 'GW', '確定申告の締切')"),
|
|
249
|
+
}, async ({ query }) => {
|
|
250
|
+
const result = await apiPost("/api/v1/calendar/check", { query });
|
|
251
|
+
if (!result.category_id) {
|
|
252
|
+
return { content: [{ type: "text", text: `❌ '${query}' に該当するカレンダー情報が見つかりませんでした。` }] };
|
|
253
|
+
}
|
|
254
|
+
let text = `📅 ${result.name_ja}\n📋 ${result.summary}\n`;
|
|
255
|
+
text += `\n📊 確度: ${((result.confidence || 0) * 100).toFixed(0)}%`;
|
|
256
|
+
return { content: [{ type: "text", text }] };
|
|
257
|
+
});
|
|
258
|
+
// ── Tool: calendar_list ─────────────────────────────
|
|
259
|
+
server.tool("calendar_list", "日本のビジネスカレンダーの全カテゴリ一覧を取得します。", {}, async () => {
|
|
260
|
+
const result = await apiGet("/api/v1/calendar/list");
|
|
261
|
+
let text = `📅 カレンダーカテゴリ一覧 (${result.count}件):\n\n`;
|
|
262
|
+
for (const c of result.categories) {
|
|
263
|
+
text += ` • ${c.name_ja} (${c.name_en})\n ${c.summary}\n\n`;
|
|
264
|
+
}
|
|
265
|
+
return { content: [{ type: "text", text }] };
|
|
266
|
+
});
|
|
267
|
+
// ── Tool: regional_check ────────────────────────────
|
|
268
|
+
server.tool("regional_check", "日本の地域別ビジネス情報を検索します。主要都市の特性、自治体の助成金・補助金、地域条例、商慣習の違い。", {
|
|
269
|
+
query: zod_1.z.string().describe("検索クエリ(例: '大阪の飲食店条例', '東京のスタートアップ助成金')"),
|
|
270
|
+
}, async ({ query }) => {
|
|
271
|
+
const result = await apiPost("/api/v1/regional/check", { query });
|
|
272
|
+
if (!result.category_id) {
|
|
273
|
+
return { content: [{ type: "text", text: `❌ '${query}' に該当する地域情報が見つかりませんでした。` }] };
|
|
274
|
+
}
|
|
275
|
+
let text = `🗺️ ${result.name_ja}\n📋 ${result.summary}\n`;
|
|
276
|
+
text += `\n📊 確度: ${((result.confidence || 0) * 100).toFixed(0)}%`;
|
|
277
|
+
return { content: [{ type: "text", text }] };
|
|
278
|
+
});
|
|
279
|
+
// ── Tool: regional_list ─────────────────────────────
|
|
280
|
+
server.tool("regional_list", "日本の地域別ビジネス情報の全カテゴリ一覧を取得します。", {}, async () => {
|
|
281
|
+
const result = await apiGet("/api/v1/regional/list");
|
|
282
|
+
let text = `🗺️ 地域情報カテゴリ一覧 (${result.count}件):\n\n`;
|
|
283
|
+
for (const c of result.categories) {
|
|
284
|
+
text += ` • ${c.name_ja} (${c.name_en})\n ${c.summary}\n\n`;
|
|
285
|
+
}
|
|
286
|
+
return { content: [{ type: "text", text }] };
|
|
287
|
+
});
|
|
288
|
+
// ── Tool: organization_check ────────────────────────
|
|
289
|
+
server.tool("organization_check", "日本の組織構造・商慣行を検索します。役職体系、系列、支払慣行、契約慣行、業界団体。", {
|
|
290
|
+
query: zod_1.z.string().describe("検索クエリ(例: '支払いサイトの標準', '契約書の印鑑', '部長と課長の違い')"),
|
|
291
|
+
}, async ({ query }) => {
|
|
292
|
+
const result = await apiPost("/api/v1/organization/check", { query });
|
|
293
|
+
if (!result.category_id) {
|
|
294
|
+
return { content: [{ type: "text", text: `❌ '${query}' に該当する組織情報が見つかりませんでした。` }] };
|
|
295
|
+
}
|
|
296
|
+
let text = `🏛️ ${result.name_ja}\n📋 ${result.summary}\n`;
|
|
297
|
+
text += `\n📊 確度: ${((result.confidence || 0) * 100).toFixed(0)}%`;
|
|
298
|
+
return { content: [{ type: "text", text }] };
|
|
299
|
+
});
|
|
300
|
+
// ── Tool: organization_list ─────────────────────────
|
|
301
|
+
server.tool("organization_list", "日本の組織構造・商慣行の全カテゴリ一覧を取得します。", {}, async () => {
|
|
302
|
+
const result = await apiGet("/api/v1/organization/list");
|
|
303
|
+
let text = `🏛️ 組織情報カテゴリ一覧 (${result.count}件):\n\n`;
|
|
304
|
+
for (const c of result.categories) {
|
|
305
|
+
text += ` • ${c.name_ja} (${c.name_en})\n ${c.summary}\n\n`;
|
|
306
|
+
}
|
|
307
|
+
return { content: [{ type: "text", text }] };
|
|
308
|
+
});
|
|
309
|
+
// ── Tool: foreign_entry_check ───────────────────────
|
|
310
|
+
server.tool("foreign_entry_check", "外国企業・外国人の日本進出に必要な基盤知識を検索します。法人設立、経営管理ビザ、銀行口座開設、物件探し、税務届出の5カテゴリ。", {
|
|
311
|
+
query: zod_1.z.string().describe("検索クエリ(例: '法人設立の手順', 'ビザ取得', '銀行口座開設')"),
|
|
312
|
+
}, async ({ query }) => {
|
|
313
|
+
const result = await apiPost("/api/v1/foreign-entry/check", { query });
|
|
314
|
+
if (!result.category_id) {
|
|
315
|
+
return { content: [{ type: "text", text: `❌ '${query}' に該当する進出情報が見つかりませんでした。` }] };
|
|
316
|
+
}
|
|
317
|
+
let text = `🌐 ${result.name_ja}\n📋 ${result.summary}\n`;
|
|
318
|
+
if (result.procedures) {
|
|
319
|
+
text += `\n📌 手順 (${result.procedures.length}ステップ):\n`;
|
|
320
|
+
for (const s of result.procedures) {
|
|
321
|
+
text += ` ${s.step}. ${s.what}: ${s.detail}\n`;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
text += `\n📊 確度: ${((result.confidence || 0) * 100).toFixed(0)}%`;
|
|
325
|
+
text += `\n⚠️ ${result.disclaimer || "この情報は一般的なガイダンスです。"}`;
|
|
326
|
+
return { content: [{ type: "text", text }] };
|
|
327
|
+
});
|
|
328
|
+
// ── Tool: foreign_entry_list ────────────────────────
|
|
329
|
+
server.tool("foreign_entry_list", "外国企業・外国人の日本進出に関する知識カテゴリの一覧を取得します。", {}, async () => {
|
|
330
|
+
const result = await apiGet("/api/v1/foreign-entry/list");
|
|
331
|
+
let text = `🌐 日本進出カテゴリ一覧 (${result.count}件):\n\n`;
|
|
332
|
+
for (const c of result.categories) {
|
|
333
|
+
text += ` • ${c.name_ja} (${c.name_en})\n ${c.summary}\n\n`;
|
|
334
|
+
}
|
|
335
|
+
return { content: [{ type: "text", text }] };
|
|
336
|
+
});
|
|
337
|
+
// ── Tool: search ────────────────────────────────────
|
|
338
|
+
server.tool("search", "EDITION全ドメインを横断検索します。1回のリクエストで規制・プロトコル・カレンダー・地域・組織・進出手続きの全6ドメインを同時検索。", {
|
|
339
|
+
query: zod_1.z.string().describe("検索クエリ(例: '大阪で飲食店を開業', '外国人のビザ取得と銀行口座')"),
|
|
340
|
+
}, async ({ query }) => {
|
|
341
|
+
const result = await apiPost("/api/v1/search", { query });
|
|
342
|
+
let text = `🔍 横断検索結果: ${result.domains_matched}/${result.domains_searched} ドメインでヒット\n\n`;
|
|
343
|
+
for (const [domain, data] of Object.entries(result.results)) {
|
|
344
|
+
const name = data.name_ja || data.industry || domain;
|
|
345
|
+
text += ` ✅ ${domain}: ${name} (確度: ${((data.confidence || 0) * 100).toFixed(0)}%)\n`;
|
|
346
|
+
if (data.summary)
|
|
347
|
+
text += ` ${data.summary}\n`;
|
|
348
|
+
}
|
|
349
|
+
if (result.domains_matched === 0) {
|
|
350
|
+
text += ` ❌ 該当する情報が見つかりませんでした。\n`;
|
|
351
|
+
}
|
|
352
|
+
return { content: [{ type: "text", text }] };
|
|
353
|
+
});
|
|
354
|
+
// ── Start ───────────────────────────────────────────
|
|
355
|
+
async function main() {
|
|
356
|
+
const transport = new stdio_js_1.StdioServerTransport();
|
|
357
|
+
await server.connect(transport);
|
|
358
|
+
console.error("EDITION Intelligence Platform MCP server started (stdio)");
|
|
359
|
+
}
|
|
360
|
+
main().catch((err) => {
|
|
361
|
+
console.error("Fatal error:", err);
|
|
362
|
+
process.exit(1);
|
|
363
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "edition-mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "EDITION Intelligence Platform — MCP server for Japanese business memory + regulation check",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"edition-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"start": "node dist/index.js",
|
|
13
|
+
"dev": "tsc && node dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"mcp",
|
|
17
|
+
"japan",
|
|
18
|
+
"memory",
|
|
19
|
+
"regulation",
|
|
20
|
+
"agent",
|
|
21
|
+
"ai",
|
|
22
|
+
"compliance"
|
|
23
|
+
],
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@modelcontextprotocol/sdk": "^1.12.1"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"typescript": "^5.7.0",
|
|
30
|
+
"@types/node": "^22.0.0"
|
|
31
|
+
}
|
|
32
|
+
}
|