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 === connectionId

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. List the actual declared entries (marketplaceMcpServerEntries output / marketplace MCP section of the config object) and use an exact matching name for serverName.
  2. Verify you are pointing at the correct configObject and its latest version — the declaration may exist only in a different version.
  3. Trim and fix case: the comparison is exact equality on the trimmed name, so match capitalization and spelling precisely.
  4. 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

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


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/9315c52c2c54ecdf. Report an issue: GitHub.