diff --git a/apps/worker/src/sandbox-server/lib/harnesses/__tests__/opencode-server-bootstrap.test.ts b/apps/worker/src/sandbox-server/lib/harnesses/__tests__/opencode-server-bootstrap.test.ts index f51669f0d..3726f2b70 100644 --- a/apps/worker/src/sandbox-server/lib/harnesses/__tests__/opencode-server-bootstrap.test.ts +++ b/apps/worker/src/sandbox-server/lib/harnesses/__tests__/opencode-server-bootstrap.test.ts @@ -511,7 +511,7 @@ describe('opencode-server bootstrap', () => { expect(content).toContain('Do not wait for the user to ask'); }); - it('skips the integration usage instructions file when attached MCP servers define none', async () => { + it('injects Linear mutation guidance for attached Linear MCP servers', async () => { const { prepareOpenCodeCommandEnv } = await import('../opencode-server/bootstrap'); @@ -541,10 +541,16 @@ describe('opencode-server bootstrap', () => { 'roomote-opencode-integration-instructions.md', ); - expect(config.instructions ?? []).not.toContain( - integrationInstructionsPath, + expect(config.instructions).toContain(integrationInstructionsPath); + + const content = fs.readFileSync(integrationInstructionsPath, 'utf8'); + + expect(content).toContain('# Connected integration: Linear'); + expect(content).toContain('dedicated comment-creation tool'); + expect(content).toContain( + 'do not pass comment text to an issue-update or status-update tool', ); - expect(fs.existsSync(integrationInstructionsPath)).toBe(false); + expect(content).toContain('report the returned tool error verbatim'); }); it('writes only developer instructions and skips the legacy system prompt file', async () => { diff --git a/packages/types/src/__tests__/mcp-oauth.test.ts b/packages/types/src/__tests__/mcp-oauth.test.ts index 921e65b75..ca397d20a 100644 --- a/packages/types/src/__tests__/mcp-oauth.test.ts +++ b/packages/types/src/__tests__/mcp-oauth.test.ts @@ -12,6 +12,18 @@ import { } from '../mcp-oauth'; describe('Linear OAuth scopes', () => { + it('keeps issue comments separate from issue field updates', () => { + expect(getMcpIntegration('linear')?.instructions).toContain( + 'dedicated comment-creation tool', + ); + expect(getMcpIntegration('linear')?.instructions).toContain( + 'do not pass comment text to an issue-update or status-update tool', + ); + expect(getMcpIntegration('linear')?.instructions).toContain( + 'report the returned tool error verbatim', + ); + }); + it('makes deployment app actors assignable and mentionable', () => { expect( getMcpIntegrationOauthScopes('linear', 'linear_org_install'), diff --git a/packages/types/src/mcp-oauth.ts b/packages/types/src/mcp-oauth.ts index 41e6c70de..c2b8e3332 100644 --- a/packages/types/src/mcp-oauth.ts +++ b/packages/types/src/mcp-oauth.ts @@ -387,6 +387,8 @@ export const MCP_INTEGRATIONS: McpIntegration[] = [ url: 'https://mcp.linear.app/mcp', description: `Enable Linear so this deployment can route issue context and task entry through it.`, icon: 'linear', + instructions: + 'Use Linear tools to read and update Linear issues. Add issue discussion with the dedicated comment-creation tool; do not pass comment text to an issue-update or status-update tool. Use issue-update tools only for issue fields such as status, title, description, assignee, or labels. Before calling a mutation tool, follow its advertised input schema exactly. If a Linear tool rejects a request, report the returned tool error verbatim instead of inferring a different failure reason.', connectionScope: 'deployment', connectionMode: 'oauth', serverMode: 'upstream_proxy',