# ChatGPT Task runtime bugs — code change spec

Planning doc for engineering fixes related to AdMedia MCP failures in **ChatGPT
scheduled Tasks**, while individual MCP calls work in normal chat.

**Companion docs (no code):**

- [`CHATGPT-TASK-RUNTIME.md`](./CHATGPT-TASK-RUNTIME.md) — standard Task header + diagnostics (already shipped)
- [`LOCAL-CHATGPT-NGROK.md`](./LOCAL-CHATGPT-NGROK.md) — connector URL and auth

---

## Bugs reported

| ID | Symptom | Where it happens | Root cause class |
| --- | --- | --- | --- |
| **B1** | `Unknown tool` on `jira_*`, `slack_*`, `hubspot_*`, etc. | Complex Task with hybrid connectors | ChatGPT routes MCP tool names to native Jira/Slack namespace (or vice versa) |
| **B2** | Blanket “AdMedia MCP not functional” after startup probe | Full audit Task prompt | Agent tests all MCP collab tools at startup; one collision → declares total failure |
| **B3** | `AdMedia namespace/tools are not exposed in this runtime` on `health_stub` | Scheduled Task | Task runtime did not attach custom MCP (platform/config), not server bug |
| **B4** | `Session not found. Re-initialize the MCP session.` | Long multi-step Tasks | Streamable HTTP session dropped mid-run ([`server/http-app.ts`](../server/http-app.ts)) |
| **B5** | `Unknown collaboration tool` / `TOOL_NOT_SUPPORTED` for specific tools | MCP call reaches gateway | Tool missing from gateway allowlist or slack-bot registry (distinct from B1) |

**Important:** B3 cannot be fixed in MCP server code if ChatGPT Tasks do not expose
custom MCP connectors. B1/B2 are primarily **prompt + Task connector** fixes
(already documented). This file covers **optional server-side** hardening.

---

## Fix matrix (what requires code)

| Bug | Prompt / Task config only | Server code change |
| --- | --- | --- |
| B1 Hybrid `Unknown tool` | **Yes** — standard header in [`CHATGPT-TASK-RUNTIME.md`](./CHATGPT-TASK-RUNTIME.md) | Optional: tool profile (CC-2), MCP_INSTRUCTIONS (CC-1) |
| B2 Startup probe failure | **Yes** — remove MCP collab verification from Task prompt | No |
| B3 Namespace not exposed | **Yes** — attach MCP on Task; graceful fallback in header | No |
| B4 Session loss | Split Task into shorter runs (ops) | Optional: session TTL / recovery (CC-3) |
| B5 Gateway allowlist | No | Verify `api.lucos.com` + slack-bot deploy (CC-4) |

**Default rollout:** Phases 0–2 from the audit plan (prompt + Task connectors) —
**zero server deploy**, individual MCP usage unchanged.

---

## Code changes (prioritized)

### CC-1 — Extend `MCP_INSTRUCTIONS` for hybrid Tasks (recommended, low risk)

**Fixes:** B1 (reduces model calling MCP collab when native plugins exist)

**Risk:** None functional — initialize text only; all tools remain registered.

| File | Change |
| --- | --- |
| [`server/create-mcp-server.ts`](../server/create-mcp-server.ts) | Append hybrid Task routing sentence to `MCP_INSTRUCTIONS` |
| [`tests/collab-vendor-routing.test.ts`](../tests/collab-vendor-routing.test.ts) | Assert new instruction text present |

**Current:**

```typescript
export const MCP_INSTRUCTIONS =
  'Answer from the CURRENT user turn only. Call slack_* only when this turn is about Slack; ...';
```

**Proposed append:**

```typescript
export const MCP_INSTRUCTIONS =
  'Answer from the CURRENT user turn only. Call slack_* only when this turn is about Slack; call confluence_* only when this turn is about Confluence wiki. Do not replay a previous Slack question between Confluence tool calls or in the Confluence answer. Mix vendors only when the current question explicitly asks for both. ' +
  'For ChatGPT Tasks that also have native Slack/Jira/Drive plugins: prefer native connectors for collab evidence; use AdMedia MCP for monitor_*, hubspot_*, and cake/mngt reports only. Do not call slack_*, jira_*, confluence_*, gdrive_*, or fireflies_* via MCP when native plugins are available.';
```

**Tests:** Extend existing `MCP initialize instructions isolate vendors` test in
`collab-vendor-routing.test.ts`.

---

### CC-2 — Optional audit tool profile (`LUCOS_MCP_TOOL_PROFILE=audit`)

**Fixes:** B1 when prompt routing is insufficient — shrinks `tools/list` from ~202
to ~15 tools so ChatGPT Task agent sees fewer collab names.

**Risk:** **Only when env is set.** Default unset = no behavior change.

| File | Change |
| --- | --- |
| [`server/config.ts`](../server/config.ts) | Add optional `toolProfile?: 'audit' \| 'full'` from `LUCOS_MCP_TOOL_PROFILE` |
| [`server/tool-profiles.ts`](../server/tool-profiles.ts) | **New** — `AUDIT_TOOL_NAMES` set + `filterRegistryForProfile()` |
| [`server/create-mcp-server.ts`](../server/create-mcp-server.ts) | Filter `TOOL_REGISTRY` in registration loop when profile is `audit` |
| [`server/index.ts`](../server/index.ts) | Pass `toolProfile` into `createMcpServer` / `createHttpApp` |
| [`.env.example`](../.env.example) | Document `LUCOS_MCP_TOOL_PROFILE=audit` |
| [`deploy/business-mcp.staging.env.example`](../deploy/business-mcp.staging.env.example) | Same |
| [`tests/tool-profiles.test.ts`](../tests/tool-profiles.test.ts) | **New** — profile filters correctly; default is full |

**Audit profile allowlist (initial set):**

```typescript
export const AUDIT_TOOL_NAMES = new Set([
  'health_stub',
  'monitor_identity_lookup',
  'monitor_team_activity',
  'monitor_jira_activity',
  'monitor_slack_activity',
  'monitor_bitbucket_activity',
  'hubspot_list_accounts',
  'hubspot_search_deals',
  'hubspot_get_deal',
  'search_affiliates',
  'get_affiliate_report',
  'get_advertiser_report',
]);
```

**Registration change sketch** in `createMcpServer`:

```typescript
const registry =
  config.toolProfile === 'audit'
    ? TOOL_REGISTRY.filter((def) => AUDIT_TOOL_NAMES.has(def.name))
    : TOOL_REGISTRY;

for (const def of registry) {
  // existing registerTool loop
}
```

**Deploy rule:** Use a **separate MCP connector URL or VM** with
`LUCOS_MCP_TOOL_PROFILE=audit` for ChatGPT Tasks only. **Do not** set on the
main `dev-mcp.lucos.com` instance used for individual chat/Cursor.

---

### CC-3 — Session recovery hints for long Tasks (optional)

**Fixes:** B4 — clearer errors when ChatGPT drops `mcp-session-id`

| File | Change |
| --- | --- |
| [`server/http-app.ts`](../server/http-app.ts) | Include actionable message in `MCP_SESSION_NOT_FOUND_MESSAGE` |
| [`tests/mcp-sse-session-auth.test.ts`](../tests/mcp-sse-session-auth.test.ts) | Update expected message if changed |

**Proposed message:**

```typescript
export const MCP_SESSION_NOT_FOUND_MESSAGE =
  'Session not found. Re-initialize the MCP session (send initialize again). ' +
  'Long ChatGPT Tasks may drop sessions — split into shorter runs or retry health_stub to reopen.';
```

**Not in scope:** Persisting sessions across process restarts (would need Redis/session store).

**Existing mitigations already in code:**

- SSE keepalive: `SSE_KEEPALIVE_MS = 15_000` in [`server/http-app.ts`](../server/http-app.ts)
- Session bearer cache: [`server/session-bearer.ts`](../server/session-bearer.ts)
- Stale session re-init on Streamable initialize: [`server/http-app.ts`](../server/http-app.ts) ~L197–199

---

### CC-4 — Gateway / slack-bot allowlist verification (ops, not MCP repo)

**Fixes:** B5 — real `Unknown collaboration tool` from backend

| Repo | Check |
| --- | --- |
| [`api.lucos.com/src/constants/collaboration-upstream.js`](../../api.lucos.com/src/constants/collaboration-upstream.js) | `COLLABORATION_TOOL_PREFIX_RE` includes tool prefix |
| [`api.lucos.com/src/routes/tools.routes.js`](../../api.lucos.com/src/routes/tools.routes.js) | Returns 404 `TOOL_NOT_SUPPORTED` only for unknown names |
| [`slack-bot-service.com/src/collab/router.js`](../../slack-bot-service.com/src/collab/router.js) | Tool in `ALL_TOOLS` |
| [`business-mcp.lucos.com/broker_client/index.ts`](../broker_client/index.ts) | `rewriteUnknownCollabToolReason()` surfaces allowlist hint |

**Smoke:** Individual `hubspot_list_accounts` / `monitor_identity_lookup` in chat —
if pass, B5 is not your Task issue.

---

### CC-5 — README cross-link (docs only)

| File | Change |
| --- | --- |
| [`README.md`](../README.md) | Add bullet under ChatGPT section linking to `CHATGPT-TASK-RUNTIME.md` and this file |

---

## Implementation order

```text
1. [Done] CHATGPT-TASK-RUNTIME.md — Task header (no deploy)
2. CC-1  MCP_INSTRUCTIONS append          — small PR, safe for all clients
3. CC-5  README link                      — docs PR
4. CC-2  tool profile (audit)             — only if Task still hits B1 after header
5. CC-3  session message polish             — optional UX
6. CC-4  gateway/slack-bot verify         — if B5 symptoms on specific tools
```

---

## Test plan (after code merges)

| Test | Command / action |
| --- | --- |
| Unit | `npm test` in `business-mcp.lucos.com` |
| MCP instructions | `tests/collab-vendor-routing.test.ts` |
| Tool profile | `tests/tool-profiles.test.ts` (new) |
| Individual chat regression | `health_stub`, `jira_search_issues`, `slack_ask` in normal ChatGPT chat — must still work |
| Task smoke | One-line Task: `health_stub { ping: "task-smoke" }` |
| Hybrid Task | Full audit Task with standard header — no MCP collab calls in trace |

---

## Non-regression guarantees

| Change | Individual MCP / Cursor chat |
| --- | --- |
| CC-1 MCP_INSTRUCTIONS | Unchanged tool list and execution |
| CC-2 tool profile | Unchanged when env **unset**; audit profile only on dedicated instance |
| CC-3 session message | Error text only |
| CC-4 gateway | Independent of MCP server release |
| Task header (prompt) | No server impact |

---

## Out of scope (cannot fix in this repo)

- ChatGPT Tasks not exposing custom MCP namespace (B3) — OpenAI platform / Task connector UI
- Native Jira/Slack plugin tool schemas — ChatGPT-side
- Shortening ChatGPT Task tool-call budget — product limit
- Employee audit PDF generation — ChatGPT feature

---

## Ticket / epic linkage

- Epic: TW-283 / parent TW-321
- Collaboration tools: TW-338
- MCP SSE runtime: TW-323
- Gateway client: TW-325

---

## Summary for reviewers

Most Task failures are **orchestration**, not MCP server bugs. Ship the Task header
first. Server code is optional hardening: **CC-1** is safe to merge globally;
**CC-2** only on a Task-dedicated MCP instance; **CC-3–CC-4** as needed.
