{"record":{"id":"9d02ab54e534c138","repo":"different-ai/openwork","slug":"mcp-server-not-remote","errorCode":"mcp_server_not_remote","errorMessage":"Only declared remote MCP servers with a URL can be configured.","messagePattern":"Only declared remote MCP servers with a URL can be configured\\.","errorType":"http","errorClass":"PluginArchRouteFailure","httpStatus":400,"severity":"error","filePath":"ee/apps/den-api/src/routes/org/plugin-system/store.ts","lineNumber":4892,"sourceCode":"  })\n  await deletePluginMcpRequirementBindingsByIds({ bindingIds: staleBindingIds })\n}\n\nfunction mcpRequirementServerFromVersion(input: {\n  configObject: ConfigObjectRow\n  serverName: string\n  version: ConfigObjectVersionRow\n}): PluginMcpRequirementServer {\n  const spec = parseConfigObjectVersionSpec(input.version)\n  const serverName = input.serverName.trim()\n  const entry = marketplaceMcpServerEntries(spec, input.configObject.title).find((candidate) => candidate.name === serverName)\n  if (!entry) {\n    throw new PluginArchRouteFailure(404, \"mcp_server_not_found\", \"MCP server declaration not found on this config object.\")\n  }\n\n  const url = readRecordString(entry.config, \"url\")\n  if (!url) {\n    throw new PluginArchRouteFailure(400, \"mcp_server_not_remote\", \"Only declared remote MCP servers with a URL can be configured.\")\n  }\n\n  return { config: entry.config, name: entry.name, url }\n}\n\nfunction configVersionOwnsImportedExternalMcpConnection(version: ConfigObjectVersionRow, connectionId: string) {\n  const spec = parseConfigObjectVersionSpec(version)\n  const metadata = isRecord(spec.metadata) ? spec.metadata : null\n  const recordedConnectionId = readRecordString(spec, \"externalMcpConnectionId\")\n    || (metadata ? readRecordString(metadata, \"externalMcpConnectionId\") : null)\n  const owned = spec.externalMcpConnectionOwnedByPlugin === true\n    || metadata?.externalMcpConnectionOwnedByPlugin === true\n  return owned && recordedConnectionId === connectionId\n}\n\nasync function assertRemotePluginMcpUrl(url: string) {\n  let parsed: URL\n  try {","sourceCodeStart":4874,"sourceCodeEnd":4910,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/ee/apps/den-api/src/routes/org/plugin-system/store.ts#L4874-L4910","documentation":"Thrown as PluginArchRouteFailure(400, 'mcp_server_not_remote') after the server declaration was found but its config record has no `url` field. The store only supports configuring declared remote MCP servers (HTTP/SSE URLs), so local/stdio command-based servers or declarations missing `url` are rejected.","triggerScenarios":"Resolving an MCP requirement server whose config entry declares a local server (command/args based, no url key) or whose url is absent/empty — readRecordString(entry.config, 'url') returns undefined.","commonSituations":"Marketplace config declares a stdio-based MCP server (e.g. { command: 'npx', args: [...] }) which the hosted pipeline cannot configure; a declaration typo like 'uri' or 'endpoint' instead of 'url'; url defined but empty string.","solutions":["Add a valid `url` field to the MCP server declaration in the config object spec, converting it to a remote server if it was local/stdio.","Confirm the key is spelled `url` (not uri/endpoint/address) and is a non-empty string.","If a local server is genuinely needed, host it as a remote HTTP MCP endpoint and declare that URL instead.","Check the config object version you are using — a newer version may already declare the remote form."],"exampleFix":"// before (mcpServers in config spec)\n\"github\": { \"command\": \"npx\", \"args\": [\"-y\", \"@modelcontextprotocol/server-github\"] }\n// after\n\"github\": { \"url\": \"https://mcp.github.com/sse\" }","handlingStrategy":"validation","validationCode":"const entry = marketplaceMcpServerEntries(spec, title).find((s) => s.name === serverName)\nif (entry && typeof readRecordString(entry.config, \"url\") !== \"string\") {\n  throw new Error(`MCP server '${serverName}' is not remote; add a 'url' field.`)\n}","typeGuard":"function isRemoteMcpEntry(entry: { config: Record<string, unknown> }): boolean {\n  const url = entry.config[\"url\"]\n  return typeof url === \"string\" && url.length > 0\n}","tryCatchPattern":"try {\n  await configureMcpServer({ version, configObject, serverName })\n} catch (e) {\n  if (isPluginArchRouteFailure(e) && e.code === \"mcp_server_not_remote\") {\n    // convert declaration to remote or host it via HTTP\n  }\n}","preventionTips":["Declare marketplace MCP servers with an explicit `url` key","Prefer remote (HTTP/SSE) transports over stdio for hosted setups","Validate config specs at publish time, not only at configure time","Watch for typos like uri/endpoint instead of url"],"tags":["mcp","validation","remote","config"],"backgroundTag":"mcp-server-not-remote","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}