different-ai/openwork · error · PluginArchRouteFailure
mcp_server_not_found
mcp_server_not_found
Error message
MCP server declaration not found on this config object.
What it means
Thrown as PluginArchRouteFailure(404, 'mcp_server_not_found') when resolving an MCP requirement server for a marketplace config object version. The code parses the config object version spec, collects all marketplace MCP server declarations via marketplaceMcpServerEntries(), and looks for one whose name equals the requested serverName (trimmed). A missing name means the requested server is not declared in that config version.
Source
Thrown at ee/apps/den-api/src/routes/org/plugin-system/store.ts:4887
const declaredUrl = entries.get(row.binding.serverName)
if (!declaredUrl) return [row.binding.id]
return comparablePluginMcpRequirementUrl(row.connection.url) === comparablePluginMcpRequirementUrl(declaredUrl)
? []
: [row.binding.id]
})
await deletePluginMcpRequirementBindingsByIds({ bindingIds: staleBindingIds })
}
function mcpRequirementServerFromVersion(input: {
configObject: ConfigObjectRow
serverName: string
version: ConfigObjectVersionRow
}): PluginMcpRequirementServer {
const spec = parseConfigObjectVersionSpec(input.version)
const serverName = input.serverName.trim()
const entry = marketplaceMcpServerEntries(spec, input.configObject.title).find((candidate) => candidate.name === serverName)
if (!entry) {
throw new PluginArchRouteFailure(404, "mcp_server_not_found", "MCP server declaration not found on this config object.")
}
const url = readRecordString(entry.config, "url")
if (!url) {
throw new PluginArchRouteFailure(400, "mcp_server_not_remote", "Only declared remote MCP servers with a URL can be configured.")
}
return { config: entry.config, name: entry.name, url }
}
function configVersionOwnsImportedExternalMcpConnection(version: ConfigObjectVersionRow, connectionId: string) {
const spec = parseConfigObjectVersionSpec(version)
const metadata = isRecord(spec.metadata) ? spec.metadata : null
const recordedConnectionId = readRecordString(spec, "externalMcpConnectionId")
|| (metadata ? readRecordString(metadata, "externalMcpConnectionId") : null)
const owned = spec.externalMcpConnectionOwnedByPlugin === true
|| metadata?.externalMcpConnectionOwnedByPlugin === true
return owned && recordedConnectionId === connectionIdView on GitHub (pinned to 2b7df46e8a)
Solutions
- List the actual declared entries (marketplaceMcpServerEntries output / marketplace MCP section of the config object) and use an exact matching name for serverName.
- Verify you are pointing at the correct configObject and its latest version — the declaration may exist only in a different version.
- Trim and fix case: the comparison is exact equality on the trimmed name, so match capitalization and spelling precisely.
- If the server was intentionally removed, update the client/requirement manifest to stop requesting that server.
Example fix
// before
await configureMcpServer({ version, configObject, serverName: "Github MCP" })
// after (name matches a declared entry exactly)
await configureMcpServer({ version, configObject, serverName: "github-mcp" }) Defensive patterns
Strategy: validation
Validate before calling
const declared = marketplaceMcpServerEntries(spec, configObject.title)
if (!declared.some((s) => s.name === serverName.trim())) {
throw new Error(`Unknown MCP server '${serverName}'. Available: ${declared.map((s) => s.name).join(", ")}`)
} Type guard
function isDeclaredServer(spec: ConfigObjectSpec, title: string, serverName: string): boolean {
return marketplaceMcpServerEntries(spec, title).some((s) => s.name === serverName.trim())
} Try / catch
try {
await configureMcpServer({ version, configObject, serverName })
} catch (e) {
if (isPluginArchRouteFailure(e) && e.code === "mcp_server_not_found") {
// re-list declared entries and correct the name
}
} Prevention
- Fetch and cache declared server names from the config object before configuring
- Treat names as case-sensitive exact strings
- Refresh cached names after marketplace config version updates
- Keep a canonical registry of server names instead of free-text input
When it happens
Trigger: Calling the API to configure/resolve an MCP requirement server passing a serverName that does not match any entry name in the given config object version — typo'd name, wrong configObject/version supplied, or the server declaration was removed/renamed in a newer version.
Common situations: Client cached an old server name after a marketplace config update; name compared against candidate.name after trimming, so whitespace is tolerated but case differences are not; requesting a local (non-remote) or stdio server entry by a stale name.
Related errors
- protocol "${url.protocol}" is not allowed
- the hostname does not resolve
- mcp_server_not_remote
- invalid_mcp_token_payload
- invalid_mcp_connection_payload
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/9315c52c2c54ecdf.
Report an issue: GitHub.