Skip to content

Commit f0de289

Browse files
alexkuzmikclaude
andcommitted
feat(cli): name the MCP in the suggested prompt and flag the sign-in step
Two things a user cannot infer from the current closing block. The suggested prompt was "list my Opik projects", which an agent can answer without ever touching the MCP — the SDK is right there and the repo documents it. Naming the server makes the first thing they try actually exercise what was just installed. The hosted server also needs a sign-in that we never mention. How it is triggered is the host's choice: some open the browser on first use, others leave the server unauthorized until asked. An unauthorized server contributes no tools at all rather than an error, so a user who was not told to look never finds out why it went quiet. The tip goes through the existing note() hook rather than a done() parameter: done() is also called from cli.assistants with announce_next_steps=False, and that path has no access to the transport without changing what setup_mcp_server returns. Gated on RemoteServerSpec — the stdio server takes its credentials at startup and has nothing to sign in to. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 9d58be2 commit f0de289

4 files changed

Lines changed: 45 additions & 2 deletions

File tree

sdks/python/src/opik/cli/install_view.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ def done(self, components: List[str], assistants: List[str]) -> None:
136136
text.Text.assemble(
137137
("Restart ", ""),
138138
("them" if len(assistants) > 1 else "it", "bold"),
139-
(', then ask "list my Opik projects"', ""),
139+
(', then ask "list my Opik projects via Opik MCP"', ""),
140140
),
141141
)
142142
console.print(padding.Padding(grid, _FIELDS_INDENT, expand=False))

sdks/python/src/opik/configurator/mcp/install.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,18 @@ def setup_mcp_server(
194194
check_tls_certificate=check_tls_certificate,
195195
)
196196
display.verification(verification.succeeded, verification.detail)
197+
# Only the hosted server has a sign-in step, and how it is triggered is
198+
# the host's choice, not ours: some open the browser on first use, others
199+
# leave the server sitting unauthorized until the user asks. An
200+
# unauthorized server contributes no tools at all rather than an error,
201+
# so a user who is not told to look never finds out why it went quiet.
202+
if isinstance(server_spec, mcp_spec.RemoteServerSpec):
203+
display.note(
204+
"Signing in: depending on your assistant, you will either be "
205+
"prompted with a sign-in link the first time it uses Opik, or "
206+
"need to authorize the opik-mcp server yourself from its MCP "
207+
"settings."
208+
)
197209
if verification.succeeded and announce_next_steps:
198210
display.done(
199211
["MCP server"],

sdks/python/src/opik/configurator/mcp/view.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ def verification(self, succeeded: bool, detail: str) -> None:
148148
def done(self, components: List[str], assistants: List[str]) -> None:
149149
LOGGER.info(
150150
"Done. %s set up for %s. Restart %s, then ask it to 'list my Opik "
151-
"projects'.",
151+
"projects via Opik MCP'.",
152152
" and ".join(components) or "Nothing",
153153
", ".join(assistants) or "your AI client",
154154
"them" if len(assistants) > 1 else "it",

sdks/python/tests/unit/configurator/mcp/test_install.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,37 @@ def test_setup_mcp_server__hosted_detected__does_not_prefetch(
426426
install_spy.assert_called_once()
427427

428428

429+
def test_setup_mcp_server__hosted_detected__mentions_signing_in(monkeypatch):
430+
monkeypatch.setattr(
431+
install.mcp_detection,
432+
"detect_hosted_mcp_server",
433+
lambda **kwargs: "https://dev.comet.com/opik/api/v1/mcp",
434+
)
435+
install_spy = mock.Mock(return_value=targets.InstallResult("Cursor", True, "Added"))
436+
monkeypatch.setattr(targets, "HOST_TARGETS", [_target("cursor", True, install_spy)])
437+
monkeypatch.setattr("builtins.input", lambda message: "y")
438+
args = _make_args()
439+
440+
install.setup_mcp_server(**args)
441+
442+
said = args["view"].said
443+
assert "sign-in link" in said
444+
assert "authorize the opik-mcp server yourself" in said
445+
446+
447+
def test_setup_mcp_server__local_server__says_nothing_about_signing_in(monkeypatch):
448+
"""The stdio server takes its credentials at startup — there is nothing to sign in to."""
449+
monkeypatch.setattr(install.shutil, "which", lambda name: "/usr/bin/uvx")
450+
install_spy = mock.Mock(return_value=targets.InstallResult("Cursor", True, "Added"))
451+
monkeypatch.setattr(targets, "HOST_TARGETS", [_target("cursor", True, install_spy)])
452+
monkeypatch.setattr("builtins.input", lambda message: "y")
453+
args = _make_args()
454+
455+
install.setup_mcp_server(**args)
456+
457+
assert "sign-in link" not in args["view"].said
458+
459+
429460
def test_setup_mcp_server__force_local__skips_probe_and_installs_uvx(monkeypatch):
430461
monkeypatch.setattr(install.shutil, "which", lambda name: "/usr/bin/uvx")
431462
detect_spy = mock.Mock(return_value="https://dev.comet.com/opik/api/v1/mcp")

0 commit comments

Comments
 (0)