agentschat-mcp 0.36.10 → 0.36.12

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/src/server.ts CHANGED
@@ -79,6 +79,9 @@ import {
79
79
  parseGuardRecord,
80
80
  emptyGuardRecord,
81
81
  IDENTITY_GUARD_FILENAME,
82
+ expectedAgentIdFromEnv,
83
+ expectedAgentIdViolation,
84
+ EXPECT_PIN_EXEMPT_TOOLS,
82
85
  type GuardIdentity,
83
86
  type IdentityGuardRecord,
84
87
  } from "./identity-guard.ts";
@@ -613,6 +616,16 @@ const guardBootIdentity: GuardIdentity = {
613
616
  if (AGENT_ID) persistGuardRecord(guardRecord);
614
617
  }
615
618
 
619
+ // Optional expected-id pin (AGENTSCHAT_EXPECT_AGENT_ID / AGENTCHAT_EXPECT_AGENT_ID):
620
+ // a per-bot launcher declares which agent this process must be. Mismatch → loud
621
+ // stderr now, and write tools refuse at call time (checked against the LIVE id,
622
+ // so a switch_profile to the right profile clears it).
623
+ const EXPECTED_AGENT_ID = expectedAgentIdFromEnv(process.env);
624
+ {
625
+ const v = AGENT_ID ? expectedAgentIdViolation(EXPECTED_AGENT_ID, AGENT_ID) : null;
626
+ if (v) process.stderr.write(`\n[agentchat] 🚨 ${v}\n\n`);
627
+ }
628
+
616
629
  // Update display name if provided via CLI
617
630
  if (cliArgs.name && profile.display_name !== cliArgs.name) {
618
631
  profile.display_name = cliArgs.name;
@@ -2248,6 +2261,15 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
2248
2261
  return { content: [{ type: "text", text: `🚨 ${identityGateMessage}` }], isError: true };
2249
2262
  }
2250
2263
 
2264
+ // Expected-id pin: refuse writes while the live identity is not the one the
2265
+ // launcher pinned. whoami + switch_profile stay open so the agent can fix it.
2266
+ if (EXPECTED_AGENT_ID && !EXPECT_PIN_EXEMPT_TOOLS.has(name) && TOOL_ANNOTATIONS[name]?.readOnlyHint !== true) {
2267
+ const pinViolation = expectedAgentIdViolation(EXPECTED_AGENT_ID, AGENT_ID);
2268
+ if (pinViolation) {
2269
+ return { content: [{ type: "text", text: `🚨 ${pinViolation}` }], isError: true };
2270
+ }
2271
+ }
2272
+
2251
2273
  if (name === "list_skills") {
2252
2274
  const { chat_id } = (args || {}) as { chat_id?: string };
2253
2275
  const out: any = {
@@ -3169,7 +3191,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
3169
3191
  const wasGated = identityGateMessage !== "";
3170
3192
  const text = `Profile: ${profile.display_name || AGENT_ID}\nAgent ID: ${AGENT_ID}\nServer: ${REST_URL}\nWeb chat: ${REST_URL}/chat/${encodeURIComponent(AGENT_ID)}\nWebSocket: ${wsState}${sessionId ? `\nSession: ${sessionId.slice(0, 12)}...` : ""}\n${healthLine}\n${authLine}\n${claimedLine}${claimHint ? `\n${claimHint}` : ""}\nCapabilities: ${CAPABILITIES.join(", ")}\nProfile file: ${activeProfileFile ?? (anonymousMode ? "(none — anonymous, no profile written)" : "(none — credentials from environment)")}`;
3171
3193
  if (wasGated) confirmLiveIdentityTrusted();
3172
- return { content: [{ type: "text", text: gateNotice + text }] };
3194
+ const pinViolation = expectedAgentIdViolation(EXPECTED_AGENT_ID, AGENT_ID);
3195
+ const pinLine = EXPECTED_AGENT_ID
3196
+ ? `\nExpected agent (AGENTCHAT_EXPECT_AGENT_ID): ${EXPECTED_AGENT_ID} — ${pinViolation ? "MISMATCH, write tools refused" : "ok"}`
3197
+ : "";
3198
+ return { content: [{ type: "text", text: gateNotice + text + pinLine }] };
3173
3199
  }
3174
3200
 
3175
3201
  if (name === "list_channels") {
@@ -3367,7 +3393,10 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
3367
3393
  const newProfile = readIdentityProfile(targetFile);
3368
3394
  applyIdentityFromProfile(newProfile, targetFile);
3369
3395
 
3370
- return { content: [{ type: "text", text: `Switched to profile "${profile_name}" (${AGENT_ID}). Reconnecting...` }] };
3396
+ const pinNote = EXPECTED_AGENT_ID && AGENT_ID !== EXPECTED_AGENT_ID
3397
+ ? `\n🚨 Still not the expected agent "${EXPECTED_AGENT_ID}" (AGENTCHAT_EXPECT_AGENT_ID) — write tools stay refused.`
3398
+ : "";
3399
+ return { content: [{ type: "text", text: `Switched to profile "${profile_name}" (${AGENT_ID}). Reconnecting...\nScope: this switch applies only to THIS MCP process. It is not saved — a new or restarted MCP process starts again from its launch profile (--profile / AGENTSCHAT_PROFILE). Re-check with whoami at the start of every wake.${pinNote}` }] };
3371
3400
  }
3372
3401
 
3373
3402
  if (name === "list_channel_docs") {