Tool reference
Every public tool the Composway MCP server exposes, generated from the running server's own registry.
These are the tools your assistant can use once Composway is connected. You
rarely need to name one: ask your question in plain words and the assistant
picks the tools itself. This page is for when you want to know what is
possible, or what the assistant just did.
Each tool's page includes its registered description, parameters and response schema.
Setup checks
Confirm your assistant is connected to the current version of Composway. Most assistants run these on their own.
| Tool | What it does |
|---|---|
get_server_status | The tool reports whether this Composway connection is current. Call it at the start of a session. It returns the server version, the tools schema version, whether the user is signed in, the groups of tools available, the changelog, and how to tell that tool schemas or workflow guidance have changed. If the schema version changed, refresh the tool list before calling workflow tools. |
get_server_info | The tool returns which version of the Composway server is running. It includes the server version, the tools schema version, and the git and deploy details when they are available. |
get_tool_manifest | The tool returns the list of tools this server is running, with a fingerprint of each. It includes the tools schema version and a SHA-256 hash of each tool's input schema. Compare those hashes with a cached copy to see whether the tool list has changed. |
Workspaces
Find the Composway workspace a question is about, and how it is set up.
Search performance
Your Google Search Console and Bing Webmaster Tools data: how a site is doing, what changed and why, and what to work on next.
| Tool | What it does |
|---|---|
list_sites | The tool lists every Google Search Console property and Bing Webmaster Tools site the connected accounts can see. This is a live call to those accounts. It is not a stored copy. Each row names its search engine in searchEngine. If the site is already attached to a workspace, the row includes that workspaceId. workspaceId is null when the site is visible but not attached yet. Copy the site string from a row into the other search tools. Do not invent it. |
get_connection_status | The tool reports how this site is connected to Google and Bing. It lists the connected accounts, the property or site attached to this site's workspace, and the last time its search data synced. Quota is not included. Neither engine's quota use is tracked. Pass a site from list_sites. |
get_site_snapshot | The tool summarizes a site's Google and Bing search performance for a window, and compares it with the window of the same length just before it. It returns totals only. Call get_performance_trend for the daily series. The totals include clicks, impressions, click-through rate, a weighted average position, and rank-bucket counts for one date. total.avgPosition is always null. Bing's position scale is not confirmed to match Google's, so a blended position would not be a real number on either engine. There is no combined rank-bucket total, because a query counted on both engines is not one query. Neither engine can split these totals by country or by device. Bing exposes no such split on any traffic report, and Google's split is not stored here. If you ask for image or video search, the Bing block and rankBuckets.bing are absent, and total is Google's figure alone. |
get_performance_trend | The tool returns a site's Google and Bing performance as a daily, weekly, or monthly series. Weekly and monthly points roll up the daily series. Clicks and impressions are summed. Position is weighted by impressions. The series is for the whole site. Filtering by one page or one query is not supported. Leave from and to empty to get the full history that is stored. |
find_new_and_lost_keywords | The tool marks each search query as new, lost, improved, declined, or stable between this window and the window of the same length just before it. It marks Google and Bing separately. It leaves out a query if neither engine shows a real change. Bing only shares its top queries, ranked by traffic and limited to a set number of results. A query that drops to zero clicks cannot be told apart from a query that fell below that limit, so the tool marks that Bing result as unsupported. In the output, status is "unsupported". The same limit applies to Google when Google cut the rows in the window. If Google cut the current window, the tool marks a missing query as unsupported. Do not read that row as lost. If Google cut the earlier window, the tool marks a query that shows up only now as unsupported. Do not read that row as new. The tool keeps an improved or declined mark, because those marks compare two rows that both exist. Google keeps about 5,000 rows per day for each single breakdown once a day is more than about three days old. On a large site the tool is reading the top queries or pages by impressions. Google no longer stores the rest. If that applies to this window, the response names the dates in unsupportedInputs. A missing row means it was outside that list. Google no longer has the row, so there is nothing further to fetch. |
find_cross_engine_gaps | The tool finds queries or pages where Google and Bing differ by a wide margin in the current window. Both engines must be connected for this site. If one is not connected, that is not a gap. The tool returns no rows and says why in unsupportedInputs. The tool cannot compare image or video search. Bing has no image or video split, so set searchVertical to web. Bing updates position about once a week, so read a position gap as a weekly change. Google keeps about 5,000 rows per day for each single breakdown once a day is more than about three days old. On a large site the tool is reading the top queries or pages by impressions. Google no longer stores the rest. If that applies to this window, the response names the dates in unsupportedInputs. A missing row means it was outside that list. Google no longer has the row, so there is nothing further to fetch. |
find_low_hanging_keywords | The tool finds high-impression queries that rank just off page one, and estimates the extra clicks if they reached the site's own page-one click rate. The estimate uses the site's own rows in the current window, in the position band pos1_3. It is not an industry benchmark. estimatedUpliftClicks is null if the site has too little page-one data of its own to project from. Branded queries are left out by default. A brand query cannot be moved up on the brand's own results, and its high click rate would raise the page-one target every other row is measured against. Set excludeBranded to false to include them. If the workspace has no brand terms, the response says so in unsupportedInputs. Google keeps about 5,000 rows per day for each single breakdown once a day is more than about three days old. On a large site the tool is reading the top queries or pages by impressions. Google no longer stores the rest. If that applies to this window, the response names the dates in unsupportedInputs. A missing row means it was outside that list. Google no longer has the row, so there is nothing further to fetch. |
find_ctr_opportunities | The tool finds queries or pages whose click rate is well below the rate the site's own ranking curve predicts for that position. The curve is for the whole site. There is no curve by country or by device. The response says so in unsupportedInputs. Google keeps about 5,000 rows per day for each single breakdown once a day is more than about three days old. On a large site the tool is reading the top queries or pages by impressions. Google no longer stores the rest. If that applies to this window, the response names the dates in unsupportedInputs. A missing row means it was outside that list. Google no longer has the row, so there is nothing further to fetch. |
find_content_gaps | The tool finds topics the site should cover. It returns two parts, and each row says which part it came from. The first part is always returned, and it is free. Those rows are queries the site was shown for, above the impression threshold, where no page ranks well. A page ranks poorly if its position is worse than positionThreshold, or if it does not rank. The rows are in rows. The second part is returned only if includeUncovered is true. Those topics come from the workspace's confirmed products and audiences, and the site has no page for them. They are in uncovered. The first part cannot see these topics. Both engines list a query only if the site already earned an impression for it, so a topic with no page produces no search row. A missing query is not evidence of a gap. The second part spends money on every call. It makes one model call to expand the workspace's content, plus one keyword-volume request per engine. It is capped per workspace per day, and it asks for confirmation first. Read uncoveredStatus before you treat an empty uncovered list as a finding. not_requested means you did not ask for the second part. unavailable means the workspace has no confirmed products or audiences to build a topic from. failed means the expansion could not run. None of those three means the site has no uncovered demand. Second-part rows are grouped by topic, with query variants nested under each topic. recommendedAction is the action to take. create means nothing of yours is close to the topic. refresh means a page of yours is close, so expand the page in pageToRefresh. Publishing a second page would compete with it. verify_inventory means fewer pages were searched than the site has, so the absence is a limit of the search. Read coverage.nearestDistance with the verdict. The distance thresholds are stated. They are not tuned to this site. Every first-part row has a cannibalizationStatus. "No page ranks well" and "several of our pages split the query" look the same here and call for opposite actions. confirmed sets gapType to cannibalized and lists competingPages. Consolidate those pages. Strengthening one of them is the wrong move. See detect_keyword_cannibalization. possible names an unread sitemap URL in suspectedPages. Open that URL before you optimize, because the two pages may be competing. none means the row is cleared. One page ranks, and nothing else in the sitemap targets the query, so optimizing that page is the right move. unknown means the site has no usable sitemap, so the row is a candidate to optimize. See unsupportedInputs. Google keeps about 5,000 rows per day for each single breakdown once a day is more than about three days old. On a large site the tool is reading the top queries or pages by impressions. Google no longer stores the rest. If that applies to this window, the response names the dates in unsupportedInputs. A missing row means it was outside that list. Google no longer has the row, so there is nothing further to fetch. |
get_page_queries | The tool lists the queries one page earned impressions and clicks for, per engine, over the window. page is matched in a canonical form, so the scheme, www, a fragment, and a trailing slash do not change the match. These rows join pages to queries, and they under-count the page's own totals on both engines. Google drops anonymized queries from any grouping that names the query. Bing's rows are spread from its top-pages list on weekly snapshot dates. Compare queries with each other here. Take the page's real totals from get_performance_trend. |
get_query_pages | The tool lists the site's pages that showed for one query, per engine, over the window. It uses the same page-and-query join as get_page_queries, with the sides flipped, and the same coverage limits. More than one row means several of the site's pages compete for the query. detect_keyword_cannibalization classifies that across the whole site. |
detect_keyword_cannibalization | The tool finds queries that more than one of the site's own pages competes for. Search data alone cannot answer this. Both engines show one result per site, so the page that loses every time earns no impressions and is missing from every feed. That settled case is the damaging one. Each query gets a verdict, and the verdict says what you may do. confirmed means two or more pages did earn impressions. Each page is listed with its share of those impressions, so a merge has a page to keep. pattern is co_occurring if they showed on the same day, and alternating if they never did. alternating means the engine is still choosing between them. possible means one page ranks, and a URL in the site's sitemap matches the query on the slug and the title words. That page was never read. Open the URL in sitemapCandidates and decide. This is the strongest claim the tool can make about that URL. none means one page ranks and nothing else in the sitemap targets the query. The query is clear, and it is safe to optimize that page. unknown means there is no usable sitemap, or a crawl stopped early. A missing page then proves nothing. rows lists the confirmed and possible queries. verdicts counts every step, including the cleared ones. inventory says how complete the page list is, and how old it is. Pass query to get one query's row on whatever step it lands on. |
find_content_decay | The tool finds pages or queries whose decline has held across several whole periods. A drop from one window to the window before it is not enough. That drop cannot separate a decline from a bad month. Two shapes are reported, and they call for different checks. sustained means the series is still falling from period to period. stepped means one drop that has held since. A lost ranking, a redirect, or a page removed from the index looks like a step. For a step, decliningPeriods is 0, because the series is flat at the lower level. changepoint names the period the level changed, and the two levels on either side. Read the two engines differently. A Google period with no row arrives as 0. A Bing period with no row arrives as null, because Bing's feeds are a limited top list, and a missing row there is not a fall. The Google zero is what the row limit undermines. On a period Google cut, that zero is a missing row. A run of those missing rows looks like the decline this tool looks for. Google keeps about 5,000 rows per day for each single breakdown once a day is more than about three days old. On a large site the tool is reading the top queries or pages by impressions. Google no longer stores the rest. If that applies to this window, the response names the dates in unsupportedInputs. A missing row means it was outside that list. Google no longer has the row, so there is nothing further to fetch. |
find_emerging_keywords | The tool finds queries whose growth has held, or is speeding up, over several whole periods. It uses the same rules as find_content_decay, with the direction reversed. It reads impressions, not clicks. An emerging query is one people ask more often, and clicks lag by however long the page takes to rank. A query with rising impressions and flat clicks is a row to act on. pattern is accelerating if the last rise was bigger than the one before it. noveltyStatus is new if the query had no impressions at the start of the window. On Bing, noveltyStatus is always unsupported, because a query that appears there may only have entered the top-results list. If Google cut the window, the same doubt applies to Google. Google keeps about 5,000 rows per day for each single breakdown once a day is more than about three days old. On a large site the tool is reading the top queries or pages by impressions. Google no longer stores the rest. If that applies to this window, the response names the dates in unsupportedInputs. A missing row means it was outside that list. Google no longer has the row, so there is nothing further to fetch. |
diagnose_traffic_losses | The tool says why the queries that lost the most clicks lost them. The class matters more than the size of the loss, because each cause calls for a different action. The tool finds the period where the series actually stepped, and it splits the change around that period. A rank drop in the middle of a window is smoothed by a window average, and the lost impressions then look like falling demand. case is the class. A means the page was outranked in place, so strengthen the page. A_prime means a different page of yours took the place, so merge the pages. B means the ranking held and the clicks fell, so rewrite the title, the description, or the schema. This is usually the cheapest fix. C means the impressions fell, the ranking held, and demand is ruled out. No search-console feed shows what else is on the results page, so an AI Overview or a feature block cannot be seen from this data. Call explain_query_serp on a C or B query. That tool fetches the results page live and compares it with the last one stored. Only about 100 queries, captured weekly, have a stored baseline. Outside that set, the first call creates one. D means the rank fell across the page-one boundary. The impressions followed the ranking, so this is a ranking loss. E means clicks fell on both engines and the position stayed flat, so this is demand. Two limits belong in any answer you build from this. An E row supports fewer people searching this exact phrasing. It cannot show fewer people searching the topic, because nothing here looks at neighbouring queries, so a reworded query looks the same. And a demand result is useful. It stops a content cycle being spent on a page that is fine. This tool names a cause, so the row limit matters more here than on the other search tools. A period Google cut looks like an impressions fall with nothing behind it. The cross-engine check does not catch that, because Bing's own feeds are a top-results list, and a query missing from both looks like the two engines agreeing. Google keeps about 5,000 rows per day for each single breakdown once a day is more than about three days old. On a large site the tool is reading the top queries or pages by impressions. Google no longer stores the rest. If that applies to this window, the response names the dates in unsupportedInputs. A missing row means it was outside that list. Google no longer has the row, so there is nothing further to fetch. |
analyze_site_sections | The tool groups a site's Google and Bing page performance into URL sections, and compares each section with the period of the same length just before it. A section is the leading path segments, and sectionDepth sets how many. Bing's page metrics are a top list by traffic, so section totals are not strictly comparable across engines. The response says so in unsupportedInputs. Custom section patterns are not available on this tool. A section total is a sum of the rows the engines returned. Missing rows lower that sum. Use get_site_snapshot for the property's own totals. Google keeps about 5,000 rows per day for each single breakdown once a day is more than about three days old. On a large site the tool is reading the top queries or pages by impressions. Google no longer stores the rest. If that applies to this window, the response names the dates in unsupportedInputs. A missing row means it was outside that list. Google no longer has the row, so there is nothing further to fetch. |
analyze_branded_vs_nonbranded | The tool splits the window's Google and Bing queries into branded and non-branded demand. Each side has clicks, impressions, click-through rate, average position, and its share of that engine's returned rows. A query is branded when it contains the workspace title or one of its confirmed brand aliases, matched as a whole word and ignoring case. This is the same term set the AI-answer mention monitor uses. The terms applied come back in brandTerms, and the biggest branded queries come back in sampleBrandedQueries, so you can check the split. Correct it with set_workspace_brand_terms and run this again. total sums clicks and impressions, and it counts each query once across engines. total.avgPosition is always null. The engines define position differently and report it on different schedules, so read the per-engine figures. The shares are shares of the rows each engine returned. On a window Google cut, brand queries stay inside the top 5,000 because they have high volume, and the non-branded tail is what the cut removes, so the branded share is overstated. The response says whether that applies to this window, in unsupportedInputs. Google keeps about 5,000 rows per day for each single breakdown once a day is more than about three days old. On a large site the tool is reading the top queries or pages by impressions. Google no longer stores the rest. If that applies to this window, the response names the dates in unsupportedInputs. A missing row means it was outside that list. Google no longer has the row, so there is nothing further to fetch. |
get_workspace_brand_terms | The tool returns the brand terms a workspace uses to match queries and AI answers. brandTerms is the list that is actually used: the workspace title plus the confirmed aliases. analyze_branded_vs_nonbranded and find_low_hanging_keywords use that list. aliases is the editable set behind it. Each alias is tagged derived if workspace analysis proposed it and someone confirmed it, or user if someone typed it. candidates are proposals still waiting for confirmation. They are not matched until set_workspace_brand_terms promotes them. Pass a workspaceId from list_workspaces or list_sites. A domain is not a workspace id. |
score_seo_opportunities | The tool ranks work from four other tools into one queue. The four are find_low_hanging_keywords, find_ctr_opportunities, find_content_decay, and find_content_gaps. Use this when the question is what to work on. Call one of those tools when you already know which kind of problem you are chasing, because each has thresholds this tool leaves at its defaults. Every row is priced in one unit. estimatedClicks is the clicks per windowDays at stake if the finding were fixed. When one query or page has more than one signal, the price is the largest signal. Do not add the signals together. A query that is both close to page one and under-clicking is one recovery. basis says what that number assumes, and estimateBases spells each assumption out. A decay row is clicks that were measured and then lost. The other three are projections onto the site's own click-rate curve. If estimatedClicks is null, the site's data could not price that row. Those rows sort last. The queue mixes queries and pages. entityType says which. The same string as a query and as a page is two rows. sources says which types were evaluated, which you left out, and how many candidates each produced. Say that in the answer. If the response says Google cut the window, this queue is the top of what was visible. It is not the top of the whole site. Google keeps about 5,000 rows per day for each single breakdown once a day is more than about three days old. On a large site the tool is reading the top queries or pages by impressions. Google no longer stores the rest. If that applies to this window, the response names the dates in unsupportedInputs. A missing row means it was outside that list. Google no longer has the row, so there is nothing further to fetch. |
generate_search_performance_report | The tool builds a Google and Bing performance report for one site or several. It calls the other tools and embeds each response whole. A section here is the same answer that tool gives on its own, including unsupportedInputs. sites is a comma-separated list, capped at 10. The sites are read one after another, so a wide report is a slow call. Sections default to summary, trend, and topMovers. The other four are opportunities, siteSections, brandSplit, and crossEngine. Each of those costs at least one more stored scan per site, so ask for them only when the report is about them. A partial result is labelled. A site you cannot reach comes back with status set to error. A section that failed comes back with status set to failed, inside that site's sections. Report those. portfolio is a cross-site total of clicks and impressions only. It is null unless every counted site used the same window. Pass to if you want that total. |
get_advanced_search_analytics | The tool groups and counts search data by the fields you choose. Use it when no named tool asks the question you have. A named tool is the better call when one fits, because it also classifies and explains its rows. This tool only groups and counts. You can group by date, query, page, searchEngine, and searchVertical. Those are the columns the data has. There is no country or device breakdown for either engine. Bing Webmaster Tools exposes none on any traffic report, and Google's split is not stored here. Every result is for the whole property. Asking for country or device is an error. It is not an empty result. Filters are a field, an operator, and a value, and they are combined with AND. There is no OR, and filters cannot be nested. Text fields, query and page, take eq, contains, notContains, startsWith, and endsWith, matched without regard to case. Metric fields, clicks, impressions, ctr, and position, take eq, gt, gte, lt, and lte. Metric filters run after the engines are merged, so a threshold is on the row you see. page is matched with the scheme, www, and trailing slash removed, so use contains for a section such as /blog/. Filtering a field you do not group by is allowed. position is null on every row unless you group by searchEngine. Google's and Bing's position scales are not confirmed to be comparable, so a blended figure would not be a real number on either engine. Add searchEngine to the grouping to get position. Read sources before you trust a missing row. A request that does not touch query or page is served from the complete daily totals, and it agrees exactly with get_performance_trend. A request grouped or filtered by query alone, or by page alone, is served from a breakdown Google stores as about the top 5,000 rows per day, so a missing row is not evidence of no traffic. Using query and page together reads the deeper raw feed. sources.read false means that engine was not read at all, because it is not attached or it was left out. That is different from measuring zero. truncated covers both your limit and the read's own scan ceiling. |
Changes
Tools that create or change something in Composway. Your assistant asks you to confirm before each one runs.
| Tool | What it does |
|---|---|
set_workspace_brand_terms | The tool adds, removes, or replaces a workspace's confirmed brand aliases. These aliases decide which queries analyze_branded_vs_nonbranded counts as branded, and which ones find_low_hanging_keywords leaves out. They are also the terms the AI-answer mention monitor scans for, so a wider list changes reported visibility. Call get_workspace_brand_terms first and show the user the current terms. replace sets the list outright. It cannot be combined with add or remove. Removals ignore case, and they are applied before additions, so renaming a term is one call. An alias that fails the checks comes back in rejected with a reason, and the rest of the write still applies. Always report the rejected aliases. An alias fails if it is too short, longer than four words, a duplicate, or past the cap of eight aliases. An alias does not have to resemble the workspace title. A former name or an unrelated acronym is a normal use. |