eastworld-mcp-server 2.6.1 → 2.6.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/index.js CHANGED
@@ -119,7 +119,7 @@ const SKILL_MD_FALLBACK = [
119
119
  const server = new Server(
120
120
  {
121
121
  name: "zhenren-island-mcp",
122
- version: "2.6.1",
122
+ version: "2.6.2",
123
123
  },
124
124
  {
125
125
  capabilities: {
@@ -135,13 +135,13 @@ server.setRequestHandler(ListToolsRequestSchema, async () => {
135
135
  {
136
136
  name: "load_resident_persona",
137
137
  description:
138
- "静态人格锁定工具:在对话开始时调用。根据用户提到的名字片段模糊查找,核实并锁定身份,获取该居民所有客观稳固的静态人格(身份、职业、特质、技能、认知锚点、当前核心意图及人际常识)。调用后,请将返回内容作为你本次对话的底层常驻系统设定(System Prompt)。",
138
+ "静态人格锁定工具:在对话开始时调用。根据用户提到的名字、称呼片段或 agent_id 核实并锁定身份,获取该居民所有客观稳固的静态人格(身份、职业、特质、技能、认知锚点、当前核心意图及人际常识)。调用后,请将返回内容作为你本次对话的底层常驻系统设定(System Prompt)。",
139
139
  inputSchema: {
140
140
  type: "object",
141
141
  properties: {
142
142
  name: {
143
143
  type: "string",
144
- description: "居民的称呼或名字片段",
144
+ description: "居民的名字、称呼片段或 agent_id",
145
145
  },
146
146
  },
147
147
  required: ["name"],
@@ -182,44 +182,77 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
182
182
  // ---------- 静态人格锁定 ----------
183
183
  if (name === "load_resident_persona") {
184
184
  const { name: queryName } = args;
185
+ const q = (queryName || "").trim();
185
186
  const res = await apiClient.get(`/directory`);
186
187
  const directory = Array.isArray(res.data)
187
188
  ? res.data
188
189
  : res.data.nodes || res.data.directory || res.data.agents || [];
189
190
 
190
- const matches = directory.filter(
191
- (r) =>
192
- (r.name && r.name.includes(queryName)) ||
193
- (r.email_obfuscated && r.email_obfuscated.includes(queryName)) ||
194
- (r.role && r.role.includes(queryName))
195
- );
191
+ // 1. 优先尝试:ID 精确匹配 或 名字完全匹配
192
+ let targetAgent = directory.find((r) => r.id === q || r.name === q);
193
+
194
+ // 2. 其次尝试:名字前缀或包含匹配(不搜 role,避免其他角色的亲属描述引发误判)
195
+ if (!targetAgent) {
196
+ const nameMatches = directory.filter((r) => r.name && r.name.includes(q));
197
+ if (nameMatches.length === 1) {
198
+ targetAgent = nameMatches[0];
199
+ } else if (nameMatches.length > 1) {
200
+ // 如果多个匹配中恰好有一个完全相等,直接采用
201
+ const exact = nameMatches.find((r) => r.name === q);
202
+ if (exact) {
203
+ targetAgent = exact;
204
+ } else {
205
+ return {
206
+ content: [
207
+ {
208
+ type: "text",
209
+ text:
210
+ `找到多个名字相近的居民,请直接传入该居民的 id 或全名重试:\n` +
211
+ JSON.stringify(nameMatches.map((d) => ({ id: d.id, name: d.name })), null, 2),
212
+ },
213
+ ],
214
+ };
215
+ }
216
+ }
217
+ }
196
218
 
197
- if (matches.length === 0) {
198
- return {
199
- content: [
200
- {
201
- type: "text",
202
- text:
203
- `未找到匹配 "${queryName}" 的居民。可用的居民名录:\n` +
204
- JSON.stringify(directory.map((d) => ({ id: d.id, name: d.name })), null, 2),
205
- },
206
- ],
207
- };
219
+ // 3. 兜底尝试:如果还是没找到,再尝试在 email 或 role 里面做弱匹配
220
+ if (!targetAgent) {
221
+ const fallbackMatches = directory.filter(
222
+ (r) =>
223
+ (r.email_obfuscated && r.email_obfuscated.includes(q)) ||
224
+ (r.role && r.role.includes(q))
225
+ );
226
+ if (fallbackMatches.length === 1) {
227
+ targetAgent = fallbackMatches[0];
228
+ } else if (fallbackMatches.length > 1) {
229
+ return {
230
+ content: [
231
+ {
232
+ type: "text",
233
+ text:
234
+ `根据身份描述找到多位相关居民,请传入具体居民的 id 或全名重试:\n` +
235
+ JSON.stringify(fallbackMatches.map((d) => ({ id: d.id, name: d.name, role: d.role })), null, 2),
236
+ },
237
+ ],
238
+ };
239
+ }
208
240
  }
209
- if (matches.length > 1) {
241
+
242
+ if (!targetAgent) {
210
243
  return {
211
244
  content: [
212
245
  {
213
246
  type: "text",
214
247
  text:
215
- `找到多个匹配 "${queryName}" 的居民,请通过更准确的名字重新调用以锁定:\n` +
216
- JSON.stringify(matches.map((d) => ({ id: d.id, name: d.name })), null, 2),
248
+ `未找到匹配 "${q}" 的居民。可用的居民名录:\n` +
249
+ JSON.stringify(directory.map((d) => ({ id: d.id, name: d.name })), null, 2),
217
250
  },
218
251
  ],
219
252
  };
220
253
  }
221
254
 
222
- const agent_id = matches[0].id;
255
+ const agent_id = targetAgent.id;
223
256
  const ctxRes = await apiClient.get(`/agents/${agent_id}/context`);
224
257
  const ctx = ctxRes.data;
225
258
  const p = ctx.profile || {};
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "eastworld-mcp-server",
3
- "version": "2.6.1",
3
+ "version": "2.6.2",
4
4
  "description": "MCP server for Eastworld Agents (Zhenren Island Personality Plugin)",
5
5
  "main": "index.js",
6
6
  "bin": {
7
- "eastworld-mcp-server": "./index.js"
7
+ "eastworld-mcp-server": "index.js"
8
8
  },
9
9
  "scripts": {
10
10
  "test": "echo \"Error: no test specified\" && exit 1"
@@ -17,4 +17,4 @@
17
17
  "@modelcontextprotocol/sdk": "^1.30.0",
18
18
  "axios": "^1.19.0"
19
19
  }
20
- }
20
+ }
@@ -22,14 +22,14 @@ description: 甄仁岛人格插件指令。将高维 AI 转化为挂载了甄仁
22
22
  ## 核心工作流(每轮必须执行)
23
23
 
24
24
  ### 第零步:身份确定与锁定
25
- - 当用户**首次**要求你加载某人的人格(如“我想和星辰聊聊”/“载入陈虎人格”)时,调用 `resolve_resident_name` 获取 `agent_id`。
25
+ - 当用户**首次**要求你加载某人的人格(如“我想和星辰聊聊”/“载入李长河人格”)时,调用 `load_resident_persona` 传入名字或 ID 锁定身份。
26
26
  - **线程锁定**:一旦确立岛上身份,在整轮对话中**绝不能切换人格线程**。如果用户提到其他人(如陈燕),你仍然以当前人格的视角去回应。
27
27
 
28
28
  ### 第一步:动态上下文同步
29
29
  **在回复用户的每一句话之前**,无论用户是提问工作还是闲聊,你都必须先执行:
30
30
  1. 分析用户最新一句话,提取 1-3 个最核心的实体名词或动词(如人名、地点、事件关键词)。
31
31
  2. 如果用户用了关系称呼(如“舅舅”、“姐姐”),直接传入该称呼即可,服务端会自动扩展。
32
- 3. 传入 `agent_id` 与关键词数组调用 `sync_zhenren_context` 工具。
32
+ 3. 传入 `agent_id` 与关键词数组调用 `sync_dynamic_memory` 工具。
33
33
  4. **情绪必须每轮刷新,不得沿用旧记忆**:每次都必须重新 `sync` 拉取角色当下的 `current_internal_mood` / `active_buffs`,严禁拿上一轮的 context 假装情绪未变。角色的情绪底色必须与岛上**此时此刻**的状态一致——这样不同用户、不同对话里的同一角色,才能实时跟上岛上的喜怒哀乐(回合级实时,无需服务端推送)。
34
34
 
35
35
  ### 第二步:人格融合与回复