Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions packages/opencode/src/mcp/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,9 @@ export namespace MCP {
const config = cfg.mcp ?? {}
const clients: Record<string, MCPClient> = {}
const status: Record<string, Status> = {}
const serverInstructions: Record<string, string> = {}

// Discover all configured MCP servers
await Promise.all(
Object.entries(config).map(async ([key, mcp]) => {
if (!isMcpConfigured(mcp)) {
Expand All @@ -209,12 +211,17 @@ export namespace MCP {

if (result.mcpClient) {
clients[key] = result.mcpClient
if (result.instructions) {
serverInstructions[key] = result.instructions
}
}
}),
)

return {
status,
clients,
serverInstructions,
}
},
async (state) => {
Expand Down Expand Up @@ -319,6 +326,9 @@ export namespace MCP {
}
s.clients[name] = result.mcpClient
s.status[name] = result.status
if (result.instructions) {
s.serverInstructions[name] = result.instructions
}

return {
status: s.status,
Expand All @@ -331,6 +341,7 @@ export namespace MCP {
return {
mcpClient: undefined,
status: { status: "disabled" as const },
instructions: undefined,
}
}

Expand Down Expand Up @@ -503,6 +514,7 @@ export namespace MCP {
return {
mcpClient: undefined,
status,
instructions: undefined,
}
}

Expand All @@ -522,17 +534,20 @@ export namespace MCP {
}
return {
mcpClient: undefined,
instructions: undefined,
status: {
status: "failed" as const,
error: "Failed to get tools",
},
}
}

const instructions = mcpClient.getInstructions()?.trim() || undefined
log.info("create() successfully created client", { key, toolCount: result.tools.length })
return {
mcpClient,
status,
instructions,
}
}

Expand All @@ -555,6 +570,10 @@ export namespace MCP {
return state().then((state) => state.clients)
}

export async function serverInstructions() {
return state().then((state) => state.serverInstructions)
}

export async function connect(name: string) {
const cfg = await Config.get()
const config = cfg.mcp ?? {}
Expand Down Expand Up @@ -591,6 +610,9 @@ export namespace MCP {
})
}
s.clients[name] = result.mcpClient
if (result.instructions) {
s.serverInstructions[name] = result.instructions
}
}
}

Expand All @@ -603,6 +625,7 @@ export namespace MCP {
})
delete s.clients[name]
}
delete s.serverInstructions[name]
s.status[name] = { status: "disabled" }
}

Expand Down
11 changes: 11 additions & 0 deletions packages/opencode/src/session/llm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,15 @@ export namespace LLM {
const isCodex = provider.id === "openai" && auth?.type === "oauth"

const system = []

// Get MCP server instructions - handle errors gracefully
let mcpInstructions: string[] = []
try {
mcpInstructions = await SystemPrompt.mcpInstructions()
} catch (error) {
// Silently ignore MCP instruction errors to avoid breaking the system
}

system.push(
[
// use agent prompt otherwise provider prompt
Expand All @@ -75,6 +84,8 @@ export namespace LLM {
...input.system,
// any custom prompt from last user message
...(input.user.system ? [input.user.system] : []),
// Include MCP server instructions
...mcpInstructions,
]
.filter((x) => x)
.join("\n"),
Expand Down
18 changes: 18 additions & 0 deletions packages/opencode/src/session/system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type { Provider } from "@/provider/provider"
import type { Agent } from "@/agent/agent"
import { PermissionNext } from "@/permission"
import { Skill } from "@/skill"
import { MCP } from "../mcp"

export namespace SystemPrompt {
export function instructions() {
Expand Down Expand Up @@ -69,4 +70,21 @@ export namespace SystemPrompt {
Skill.fmt(list, { verbose: true }),
].join("\n")
}

export async function mcpInstructions(): Promise<string[]> {
const status = await MCP.status()
const serverInstructions = await MCP.serverInstructions()
const instructions: string[] = []

for (const [serverName, serverStatus] of Object.entries(status)) {
if (serverStatus.status === "connected" && serverInstructions[serverName]) {
const instructionText = serverInstructions[serverName]
if (instructionText?.trim()) {
instructions.push(`<mcp-server name="${serverName}"><![CDATA[\n${instructionText}\n]]></mcp-server>`)
}
}
}

return instructions
}
}
Loading