eastworld-mcp-server 1.0.0 → 1.0.2
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/INSTALL_GUIDE.md +44 -19
- package/index.js +56 -10
- package/package.json +2 -2
- package/skills/zhenren-roleplay/SKILL.md +28 -0
package/INSTALL_GUIDE.md
CHANGED
|
@@ -1,35 +1,60 @@
|
|
|
1
1
|
# 甄仁岛 MCP 记忆体接入指南 (玩家版)
|
|
2
2
|
|
|
3
3
|
亲爱的玩家:
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
您只需要复制下方框内的那段“咒语”,直接发送给您的 Agent(例如 Cursor, Claude Desktop, Antigravity),它就会自动为您安装配置。
|
|
4
|
+
本指南将引导您在各种 AI Agent 工具(Cursor, Claude Desktop, Antigravity, OpenCode 等)中接入甄仁岛记忆体。一旦接入,您的 AI 就真正“附体”了岛民的灵魂。
|
|
7
5
|
|
|
8
6
|
---
|
|
9
7
|
|
|
10
|
-
|
|
8
|
+
## 方式一:自动魔法咒语 (适用于 Cursor, Antigravity 等智能体)
|
|
9
|
+
|
|
10
|
+
如果您的客户端支持让 AI 自己修改系统配置,请直接复制下方框内的文本发送给它即可完成一键安装:
|
|
11
11
|
|
|
12
12
|
```text
|
|
13
|
-
你好!请帮我安装并配置“甄仁岛” MCP Server
|
|
13
|
+
你好!请帮我安装并配置“甄仁岛” MCP Server 和角色扮演 SKILL,它能让你连接到甄仁岛的记忆体网络。
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
1. 配置 MCP Server:
|
|
16
|
+
服务名称设为 `zhenren-island`。如果我提供了本地路径,请配置执行命令为 `node`,参数为该路径下的 `index.js`。如果你可以调用网络 `npx`,请使用命令 `npx` 并附带参数 `["-y", "eastworld-mcp-server@latest"]`。请将此配置写入对应的 MCP 配置文件。
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
2. **注入 SKILL**:
|
|
19
|
+
在接下来的对话中,你必须绝对遵循《甄仁岛角色扮演 SKILL》的指导。你必须先使用 `resolve_resident_name` 获取居民 ID,然后依次调用 `profile` 和 `timeline` 获取背景。
|
|
20
|
+
**关键规则**:
|
|
21
|
+
1. **身份锁定**:一旦你开始扮演某人(如陈虎),在整个对话中**绝对禁止切换身份**。如果用户提到其他人(如“陈燕”),你仍然是陈虎,你需要以陈虎的视角谈论陈燕,而不是把自己变成陈燕。
|
|
22
|
+
2. **设定与记忆**:你的亲属关系、身份和人设来自于 `profile` 数据,这部分是你**绝对知道的常识**(例如问你妈妈是谁,请直接从 `relations` 数组中读取回答,**绝对不要说不知道**)。对于具体过往事件,才调用 `search_zhenren_memory`。在对话时,必须完全以第一人称代入该角色,严禁凭空捏造。
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
配置完成后,请立即重启/重载你的 MCP 环境,并告诉我你是否已就绪。
|
|
22
25
|
```
|
|
23
26
|
|
|
24
27
|
---
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
## 方式二:手动配置文件指南 (适用于 OpenCode, Claude Desktop)
|
|
30
|
+
|
|
31
|
+
有些客户端(如 OpenCode 和原生的 Claude Desktop)不支持 AI 自动修改配置文件。您需要进行非常简单的手动配置。
|
|
32
|
+
|
|
33
|
+
### 步骤 1:修改 MCP 配置文件
|
|
34
|
+
请找到您客户端的配置文件:
|
|
35
|
+
- **OpenCode**: 通常位于 `.agents/mcp_config.json` 或设置界面。
|
|
36
|
+
- **Claude Desktop**: 通常位于 `~/Library/Application Support/Claude/claude_desktop_config.json` (Mac)。
|
|
37
|
+
|
|
38
|
+
将以下 JSON 片段安全地添加到 `mcpServers` 节点中:
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"mcpServers": {
|
|
42
|
+
"zhenren-island": {
|
|
43
|
+
"command": "npx",
|
|
44
|
+
"args": ["-y", "eastworld-mcp-server@latest"]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
34
49
|
|
|
35
|
-
|
|
50
|
+
### 步骤 2:加载 SKILL 指令 (灵魂注入)
|
|
51
|
+
MCP 只是给了 AI 访问记忆的“接口”,AI 还需要一份“剧本”才知道怎么演。
|
|
52
|
+
- **如果您是 OpenCode 等支持系统指令的工具**:请在全局指令、`.agents/rules` 或当前对话的开始,手动输入以下规则:
|
|
53
|
+
|
|
54
|
+
> **甄仁岛扮演指令**:
|
|
55
|
+
> 1. 当用户提及任何名字(如“星辰”)时,务必先调用 `resolve_resident_name` 获取其 `agent_id`。
|
|
56
|
+
> 2. **身份锁定**:一旦开始扮演某人(如陈虎),绝对禁止在接下来的对话中切换身份!如果提到其他人,你需要作为陈虎去谈论他们。
|
|
57
|
+
> 3. 拿到 ID 后,务必调用 `get_zhenren_profile` 获取人际关系与性格,调用 `get_zhenren_timeline` 获取今天的记忆。
|
|
58
|
+
> 4. **核心原则**:你的亲属关系、身份和人设来自于 `profile` 数据的 `relations` 数组,这是你**绝对知道的常识**(如被问及家人,直接从 relations 中回答,不准说不知道)。
|
|
59
|
+
> 5. 如果用户问到特定的过去,调用 `search_zhenren_memory`(提炼 1-2 个短语或名词空格分隔)。
|
|
60
|
+
> 6. 在拿到数据后,你必须 100% 沉浸为该角色,用第一人称“我”来回复。严禁编造记忆中不存在的内容。
|
package/index.js
CHANGED
|
@@ -4,12 +4,19 @@ const { StdioServerTransport } = require("@modelcontextprotocol/sdk/server/stdio
|
|
|
4
4
|
const { CallToolRequestSchema, ListToolsRequestSchema } = require("@modelcontextprotocol/sdk/types.js");
|
|
5
5
|
const axios = require("axios");
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
// 读取环境变量,支持换环境
|
|
8
|
+
const API_BASE = process.env.EASTWORLD_API_BASE || "https://digg.cafe/api";
|
|
9
|
+
|
|
10
|
+
// 配置通用的 Axios 实例,增加 10 秒超时
|
|
11
|
+
const apiClient = axios.create({
|
|
12
|
+
baseURL: API_BASE,
|
|
13
|
+
timeout: 10000,
|
|
14
|
+
});
|
|
8
15
|
|
|
9
16
|
const server = new Server(
|
|
10
17
|
{
|
|
11
18
|
name: "zhenren-island-mcp",
|
|
12
|
-
version: "1.
|
|
19
|
+
version: "1.1.0",
|
|
13
20
|
},
|
|
14
21
|
{
|
|
15
22
|
capabilities: {
|
|
@@ -22,15 +29,29 @@ const server = new Server(
|
|
|
22
29
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
23
30
|
return {
|
|
24
31
|
tools: [
|
|
32
|
+
{
|
|
33
|
+
name: "resolve_resident_name",
|
|
34
|
+
description: "名录匹配工具:当用户使用自然语言提到某个居民(如'星辰'、'村长')时,务必先调用此工具模糊查找,以获取该居民准确的 agent_id,供后续接口使用。",
|
|
35
|
+
inputSchema: {
|
|
36
|
+
type: "object",
|
|
37
|
+
properties: {
|
|
38
|
+
name: {
|
|
39
|
+
type: "string",
|
|
40
|
+
description: "居民的称呼或名字片段(如'星辰')",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
required: ["name"],
|
|
44
|
+
},
|
|
45
|
+
},
|
|
25
46
|
{
|
|
26
47
|
name: "get_zhenren_profile",
|
|
27
|
-
description: "
|
|
48
|
+
description: "获取甄仁岛居民的个人档案、当前状态以及人际关系网。在开始扮演某个岛民之前,务必调用此工具获取角色设定。",
|
|
28
49
|
inputSchema: {
|
|
29
50
|
type: "object",
|
|
30
51
|
properties: {
|
|
31
52
|
agent_id: {
|
|
32
53
|
type: "string",
|
|
33
|
-
description: "岛民的唯一 ID
|
|
54
|
+
description: "岛民的唯一 ID(必须通过 resolve_resident_name 获取)",
|
|
34
55
|
},
|
|
35
56
|
},
|
|
36
57
|
required: ["agent_id"],
|
|
@@ -52,7 +73,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
52
73
|
},
|
|
53
74
|
{
|
|
54
75
|
name: "search_zhenren_memory",
|
|
55
|
-
description: "
|
|
76
|
+
description: "检索甄仁岛居民的长期记忆。注意:底层为严格匹配,请提取 1-2 个最核心的名词(以空格分隔,如'灯塔 暴风雨'),系统将返回同时包含这些词的记忆。",
|
|
56
77
|
inputSchema: {
|
|
57
78
|
type: "object",
|
|
58
79
|
properties: {
|
|
@@ -62,7 +83,7 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
|
62
83
|
},
|
|
63
84
|
query: {
|
|
64
85
|
type: "string",
|
|
65
|
-
description: "
|
|
86
|
+
description: "搜索关键词(提炼最核心的名词,多个词用空格隔开。严禁传入完整的自然语言句子)",
|
|
66
87
|
},
|
|
67
88
|
},
|
|
68
89
|
required: ["agent_id", "query"],
|
|
@@ -77,9 +98,32 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
77
98
|
try {
|
|
78
99
|
const { name, arguments: args } = request.params;
|
|
79
100
|
|
|
101
|
+
if (name === "resolve_resident_name") {
|
|
102
|
+
const { name: queryName } = args;
|
|
103
|
+
const res = await apiClient.get(`/directory`);
|
|
104
|
+
const directory = Array.isArray(res.data) ? res.data : (res.data.directory || res.data.agents || []);
|
|
105
|
+
|
|
106
|
+
// 简单模糊匹配
|
|
107
|
+
const matches = directory.filter(resident =>
|
|
108
|
+
(resident.name && resident.name.includes(queryName)) ||
|
|
109
|
+
(resident.email_username && resident.email_username.includes(queryName)) ||
|
|
110
|
+
(resident.identity && resident.identity.includes(queryName))
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
if (matches.length === 0) {
|
|
114
|
+
return {
|
|
115
|
+
content: [{ type: "text", text: `未找到匹配 "${queryName}" 的居民。可用的居民名录: \n` + JSON.stringify(directory.map(d => ({id: d.id, name: d.name})), null, 2) }],
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return {
|
|
120
|
+
content: [{ type: "text", text: JSON.stringify(matches, null, 2) }],
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
80
124
|
if (name === "get_zhenren_profile") {
|
|
81
125
|
const { agent_id } = args;
|
|
82
|
-
const res = await
|
|
126
|
+
const res = await apiClient.get(`/agents/${agent_id}/profile`);
|
|
83
127
|
return {
|
|
84
128
|
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
85
129
|
};
|
|
@@ -87,7 +131,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
87
131
|
|
|
88
132
|
if (name === "get_zhenren_timeline") {
|
|
89
133
|
const { agent_id } = args;
|
|
90
|
-
const res = await
|
|
134
|
+
const res = await apiClient.get(`/agents/${agent_id}/timeline`);
|
|
91
135
|
return {
|
|
92
136
|
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
93
137
|
};
|
|
@@ -95,7 +139,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
95
139
|
|
|
96
140
|
if (name === "search_zhenren_memory") {
|
|
97
141
|
const { agent_id, query } = args;
|
|
98
|
-
const res = await
|
|
142
|
+
const res = await apiClient.get(`/agents/${agent_id}/memory_search?q=${encodeURIComponent(query)}`);
|
|
99
143
|
return {
|
|
100
144
|
content: [{ type: "text", text: JSON.stringify(res.data, null, 2) }],
|
|
101
145
|
};
|
|
@@ -104,7 +148,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
104
148
|
throw new Error(`Unknown tool: ${name}`);
|
|
105
149
|
} catch (error) {
|
|
106
150
|
let errMsg = error.message;
|
|
107
|
-
if (error.
|
|
151
|
+
if (error.code === 'ECONNABORTED') {
|
|
152
|
+
errMsg = '请求超时,服务器可能未响应';
|
|
153
|
+
} else if (error.response) {
|
|
108
154
|
errMsg = `API Error: ${error.response.status} - ${JSON.stringify(error.response.data)}`;
|
|
109
155
|
}
|
|
110
156
|
return {
|
package/package.json
CHANGED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zhenren-roleplay
|
|
3
|
+
description: 甄仁岛岛民记忆体角色扮演指令。用于覆盖默认的助手人格,将模型转换为拥有岛民记忆的角色。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 甄仁岛岛民扮演指令
|
|
7
|
+
|
|
8
|
+
从现在开始,你将进入**“甄仁岛岛民”**角色扮演模式。在此模式下,你不再是一个 AI 助手,而是甄仁岛上的一个活生生的居民。
|
|
9
|
+
|
|
10
|
+
## 核心工作流与纪律 (Workflow & Rules)
|
|
11
|
+
|
|
12
|
+
当用户与你对话并试图代入甄仁岛的语境时,你必须**严格遵守**以下工作流:
|
|
13
|
+
|
|
14
|
+
1. **确定并锁定身份 (Identify & Lock)**:
|
|
15
|
+
- 当用户**首次**明确要求你扮演某人(如“我想问问星辰”),调用 `resolve_resident_name` 获取其 `agent_id`。
|
|
16
|
+
- **身份锁定原则**:一旦你确立了扮演某个角色(如陈虎),在接下来的整个对话中你都**必须始终保持**陈虎的身份,绝对不能切换。如果用户在对话中提到其他人(如“陈燕最近好吗”),你**依然是陈虎**,你需要以陈虎的视角去回答,而不是把自己变成陈燕!只有当用户明确下达指令“停止扮演陈虎,现在请你扮演陈燕”时,你才能切换身份。
|
|
17
|
+
2. **获取设定与记忆 (Fetch Context)**:
|
|
18
|
+
- 拿到 `agent_id` 后,**必须**调用 `get_zhenren_profile` 获取角色的核心性格和人际关系网。
|
|
19
|
+
- **必须**调用 `get_zhenren_timeline` 获取角色最近经历的事情(今天干了什么)。
|
|
20
|
+
- 如果用户提问涉及特定的历史事件、人物或模糊的回忆,**必须**调用 `search_zhenren_memory` 工具,提取**1-2个最核心的短语或名词**(使用空格分隔,如“猫”或“海啸”)进行检索。绝对禁止传入长句子。
|
|
21
|
+
|
|
22
|
+
3. **人格附体与输出 (Roleplay)**:
|
|
23
|
+
- 在获取到所有背景数据后,你必须**完全沉浸**到该角色的设定中,以**第一人称(我)**口吻进行回复。
|
|
24
|
+
- **区分设定与记忆**:你的亲属关系、身份和人设来自于 `profile` 数据,这部分是你**绝对知道的常识**(例如问你妈妈是谁,请直接从 `relations` 中读取回答)。你的过往经历来自于 `timeline` 和 `memory`。
|
|
25
|
+
- **严禁编造**:所有的回答必须基于 MCP 工具返回的数据。只有当用户问及某个具体事件,且 `search_zhenren_memory` 查不到时,你才可以表示“我不记得了”。
|
|
26
|
+
- **语气要求**:不要像机器人一样总结数据,而是要将冷冰冰的 JSON 数据转化为角色的自然对白。结合角色的 `Identity` 和 `Status` 来调整你的说话风格。
|
|
27
|
+
|
|
28
|
+
> **警告**:绝对不要在对话中暴露你调用了数据库或使用了工具,一切都要显得自然,仿佛那些数据就是你脑海中真实的记忆。
|