Make app-feature discovery findable from tool descriptions - #71
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
Updates MCP tool descriptions so clients that only surface tool descriptions (and not the server-level instructions) can still discover the intended routing for “app-specific / my data” questions: start with open_app, then compose reads/actions from discovered canisters and capability flags.
Changes:
- Expanded
open_app’s description to include a step-by-step routing decision chain and emphasize composition over “single feature tools”. - Added an upfront nudge in
call_canister’s description to start withopen_appfor app- and user-data-scoped requests.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
aterga
force-pushed
the
claude/app-discovery-tool-hints
branch
from
July 21, 2026 14:31
3125fa5 to
de7f2f8
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
src/main.rs:925
- Grammar: "the user's own data in one" reads like a typo; it likely meant "in it" (referring to the app).
description = "ROUTING. Run this chain before answering anything that names, or implies, a specific app or the user's own data in one (a balance, holdings, bookings, positions, profile, or \"what can it do\"): (1) Is the request about a specific APP's functionality or the user's data in it, rather than the IC protocol itself? (2) Is that app on the Internet Computer? If unsure, THIS tool (or icp_find_app_by_name) is how you find out: a known or verifiable app resolves, while an unknown or non-IC target is REFUSED, never guessed. (3) If so, START HERE: one open_app call resolves the app AND discovers its service. An app feature is almost never a single named tool (there is no \"get_balance\"); you COMPOSE it from what open_app returns, reading the discovered canisters and their `oql`/`api_doc_available` flags to see how to READ (canister_query, including OQL) or ACT (canister_update_call). So never conclude \"there's no tool for that\" from the flat tool list without opening the app first. Open an Internet Computer app in ONE call, given its NAME or its URL — the recommended entry point when a user names an app. It resolves the app's Internet Identity derivation origin (like resolve_app) AND discovers the canisters behind it (like discover_app_canisters) together, so you don't chain those yourself. Pass a NAME (e.g. \"MULTI/DEX\", \"Oisy\", \"NNS\") or a URL (e.g. \"https://oisy.com\"): a name or bare host is matched to the built-in known-app registry FIRST (so even a wrong-TLD guess like \"multidex.com\" repairs to the canonical URL), and an explicit https:// URL is resolved as given. NEVER fabricate a domain from a name — an unknown bare name is refused with instructions to find the real URL (web search / ask the user), and a URL with no Internet-Computer evidence is refused, both instead of guessing a wrong identity. Returns `app_url` (the one used), `derivation_origin` (+ its source) to act with, `alternative_origins`, and the discovered `canisters` (with provenance/labels AND per-canister `oql`/`api_doc_available` capability flags, from a one-shot Candid probe of the app's own canisters). A canister flagged `oql` holds the app's data, GATED BY THE CALLER's principal: to read the USER's own data (\"my …\", \"our …\") pass the returned `derivation_origin` to get_canister_oql_schema (for the entity/field names) and to canister_query (with the `oql` argument, to run the query). Those OQL reads REQUIRE `derivation_origin` — not `app_url` — and reject an anonymous read for now. No authenticated session required for open_app itself (no principal is derived here). Narrower tools remain for single steps: icp_find_app_by_name (name→URL only), resolve_app (origin only), discover_app_canisters (canisters only).",
aterga
force-pushed
the
claude/app-discovery-tool-hints
branch
from
July 21, 2026 14:46
de7f2f8 to
3a45a90
Compare
A client that reads per-tool descriptions but not the server instructions block (e.g. surfacing tools via lazy search) could see the low-level primitives, find no literal "balance"/"get_X" tool, and conclude the capability is missing, giving up instead of composing it. Move the routing know-how into the descriptions themselves: - open_app: lead with a generic decision chain (is the request about a specific app or the user's data in it? is it an ICP app? then open_app to resolve + discover the service), and state that an app feature is composed from what open_app returns (canister_query incl. OQL for reads, canister_update_call for acts), not a single named tool. - canister_query: a one-line nudge to start from open_app when the request is app- or user-data-scoped, rather than reaching for a raw read. Rebased onto main after #70 split call_canister into canister_query / canister_update_call; references updated to the new tool names. Descriptions only; no behavior change. Not app-specific. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014T9N8USDfNK5yzznPGg7Ym
aterga
force-pushed
the
claude/app-discovery-tool-hints
branch
from
July 21, 2026 14:54
3a45a90 to
c72ed7c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A descriptions-only change so that "how to answer a question about an app" is discoverable from the per-tool descriptions, not only from the server
instructionsblock.Motivated by a user report: from the claude.ai Chat connector surface, "what's my balance on <app>" failed — the model enumerated the tools, found no literal "balance"/"get_X" tool, and gave up — while the Code surface answered it fine. The difference is that Claude Code ingests and follows the server
instructions("START WITH open_app", "'my/our …' is an authenticated read"), whereas a client that surfaces tools via lazy search reads each tool's description but not that instructions block, so it never learned to route throughopen_appand compose the read.This moves the routing know-how into the descriptions themselves. No behavior change, and deliberately not app-specific (no "Oisy", no "balance"-only wording).
Related issues
None — external user report; no GitHub issue open.
Changes
open_app: leads with a generic decision chain — (1) is the request about a specific app's functionality or the user's data in one app, rather than the IC protocol itself? (2) is that app on the Internet Computer (this tool /icp_find_app_by_nameis how you find out; an unrecognized app name or a URL with no IC evidence is refused, not guessed)? (3) if so, start here: one call resolves the app and discovers its service. It also states that an app feature is almost never a single named tool — you compose it from whatopen_appreturns (discovered canisters +oql/api_doc_availableflags), reading viacanister_query(incl. OQL) or acting viacanister_update_call.canister_query: a one-line nudge to start fromopen_appwhen the request is app- or user-data-scoped, rather than reaching for a raw read first.Rebased onto
mainafter #70 splitcall_canisterintocanister_query/canister_update_call; the references use the new tool names (this replaces the earlier draft, which nudgedcall_canister).Testing
cargo build --locked --all-targets(via the test build)cargo test --locked— 128 passing (descriptions are string literals)cargo clippy --all-targets— descriptions-only; introduces no new warningsnpm test --prefix monitoring/mcp-status— not applicable (no dashboard change)Checklist
🤖 Generated with Claude Code
https://claude.ai/code/session_014T9N8USDfNK5yzznPGg7Ym