diff --git a/apps/api/src/app.ts b/apps/api/src/app.ts index abf18a6..d0bf9b6 100644 --- a/apps/api/src/app.ts +++ b/apps/api/src/app.ts @@ -1335,6 +1335,11 @@ export async function buildApp(params: { env: Env; store: RegistryStore }) { : { mcpServers: {} }; const claudeDesktopConfig = JSON.parse(JSON.stringify(genericConfig)); + const claudeDesktopNote = primaryRemote + ? 'Claude Desktop remote MCP servers may need to be added via Settings > Connectors. Remote servers might not connect when configured only in claude_desktop_config.json.' + : stdioCommand + ? 'Claude Desktop local stdio MCP servers can be configured in claude_desktop_config.json.' + : ''; return { serverName: entry.server.name, @@ -1384,7 +1389,8 @@ export async function buildApp(params: { env: Env; store: RegistryStore }) { genericMcpHostConfig: { object: genericConfig, json: JSON.stringify(genericConfig, null, 2) - } + }, + claudeDesktopNote }; }); @@ -1439,6 +1445,7 @@ export async function buildApp(params: { env: Env; store: RegistryStore }) { totalLatestServers, countRagScoreGte1, countRagScoreGte25, + reachabilityPolicy: params.env.reachabilityPolicy, reachabilityCandidates, reachabilityKnown, reachabilityTrue, diff --git a/apps/api/tests/api.test.ts b/apps/api/tests/api.test.ts index d55e5e6..ca80d86 100644 --- a/apps/api/tests/api.test.ts +++ b/apps/api/tests/api.test.ts @@ -809,6 +809,9 @@ test('rag install returns copy-ready config object', async () => { assert.equal(body.serverName, 'example/installable'); assert.equal(body.version, '1.2.3'); assert.equal(body.transport.hasStdio, true); + assert.equal(body.primaryRemoteType, null); + assert.equal(typeof body.claudeDesktopNote, 'string'); + assert.equal(body.claudeDesktopNote.includes('claude_desktop_config.json'), true); assert.equal(typeof body.genericMcpHostConfig?.json, 'string'); assert.equal(body.genericMcpHostConfig.json.includes('mcpServers'), true); await app.close(); @@ -841,6 +844,8 @@ test('rag install emits SSE transport and endpoint list for SSE-only servers', a assert.equal(body.remoteEndpoints[0].type, 'sse'); assert.equal(body.remoteEndpoints[0].url, 'https://example.com/mcp'); assert.equal(body.genericMcpHostConfig.object?.mcpServers?.['example_sse-installable']?.transport, 'sse'); + assert.equal(typeof body.claudeDesktopNote, 'string'); + assert.equal(body.claudeDesktopNote.includes('Connectors'), true); await app.close(); }); @@ -912,6 +917,7 @@ test('rag stats returns freshness and coverage fields', async () => { assert.equal(typeof body.totalLatestServers, 'number'); assert.equal(typeof body.countRagScoreGte1, 'number'); assert.equal(typeof body.countRagScoreGte25, 'number'); + assert.equal(body.reachabilityPolicy, env.reachabilityPolicy); assert.equal(body.reachabilityCandidates, 2); assert.equal(body.reachabilityKnown, 1); assert.equal(body.reachabilityTrue, 1); diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md index 2dfb2c3..1e4277e 100644 --- a/docs/DEPLOYMENT.md +++ b/docs/DEPLOYMENT.md @@ -99,6 +99,7 @@ For repository workflows that call `/internal/*` routes: - `sse`: short `GET` with `Accept: text/event-stream`, then immediate body cancel so checks do not hang on streaming responses. - `/rag/install` now emits remote configs for both `streamable-http` and `sse` endpoints. Note: SSE support depends on the MCP host/client; Ragmap only emits the correct transport config. +- `/rag/install` also emits `claudeDesktopNote` so UIs can clarify that Claude Desktop remote MCP servers may need to be added via the Connectors UI. This applies to both scheduled ingest (`/internal/ingest/run`) and scheduled reachability refresh (`/internal/reachability/run`). diff --git a/docs/hosting/api/browse/index.html b/docs/hosting/api/browse/index.html index 4512c17..bfa0650 100644 --- a/docs/hosting/api/browse/index.html +++ b/docs/hosting/api/browse/index.html @@ -53,6 +53,15 @@ .card button:hover { background: var(--bg); } .card button.primary { background: var(--accent); color: white; border-color: var(--accent); } .card button.primary:hover { opacity: 0.92; } + .install-info { margin-top: 10px; border: 1px solid var(--border); border-radius: 10px; padding: 10px; background: #faf8f4; font-size: 12px; color: var(--muted); } + .install-info:empty { display: none; } + .install-info .row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 8px; } + .install-info .row:last-child { margin-bottom: 0; } + .transport-badge { display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 999px; font-size: 11px; border: 1px solid var(--border); color: var(--ink); background: #fff; } + .transport-remote { border-color: #9ec3ff; background: #eef5ff; } + .transport-local { border-color: #b8dcbf; background: #eefaf0; } + .install-info details { margin-top: 6px; } + .install-info summary { cursor: pointer; color: var(--ink); } .empty { color: var(--muted); padding: 24px; text-align: center; } .top-cta { background: var(--card); border: 1px solid var(--border); border-radius: 12px; padding: 12px 16px; margin-bottom: 20px; font-size: 13px; } .top-cta strong { display: block; margin-bottom: 6px; } @@ -166,6 +175,30 @@
' + esc(remoteUrl) + '' : '') +
+ '