Model Context Protocol

Walls.io Echo MCP Server

Read and manage the authenticated user's Echo campaigns, their sharing visuals, their folders, and their analytics. All tools operate only on campaigns and folders owned by the connected user. Reference a campaign by its numeric id or slug, a folder or visual by its numeric id. Each campaign holds up to 10 sharing visuals, each with its own box_* element layout and its own sharing_url and sharing_text (empty values inherit from the primary visual at share time); the first visual (lowest position) is the primary one used when the campaign is shared. Add visuals by https URL (preferred) or base64, update their layout and sharing fields, or reorder them. Analytics tools accept an optional from/to date range (YYYY-MM-DD); omitting it returns lifetime totals (summary) or the last 30 days (timeseries/breakdown).

Connection URL

Point any MCP-compatible client at this endpoint:

POST https://mcp.echo.walls.io/mcp

Authentication is handled automatically over OAuth — no manual token needed.

1Add it to Claude

  1. In Claude Desktop or claude.ai, open Settings → Connectors.
  2. Choose Add custom connector.
  3. Paste the connection URL above and confirm.
  4. On first use, a browser window opens our authorization screen — sign in and approve the mcp:use scope.
  5. Claude can now call the tools below against your campaigns.

2Add it to Claude Code

  1. In a terminal, register the server with the claude CLI:
    $ claude mcp add --transport http echo https://mcp.echo.walls.io/mcp

    This adds the server for the current project — append --scope user to make it available everywhere.

  2. Start Claude Code and run /mcp, then select echo to authenticate.
  3. A browser window opens our authorization screen — sign in and approve the mcp:use scope.
  4. Claude Code can now call the tools below against your campaigns.

3Add it to ChatGPT

  1. In ChatGPT, open Settings → Security and login and turn on Developer mode.
  2. Open Settings → Plugins (or chatgpt.com/plugins), select the plus button, and create a developer-mode app using the connection URL above as the server URL.
  3. When prompted, sign in and approve the mcp:use scope on our authorization screen.
  4. In a chat, enable the app from the tools menu — ChatGPT can then call the tools below against your campaigns.

4How authentication works

The server speaks OAuth 2.1, so clients connect without you copying any secrets:

5What it can access

Every tool operates only on campaigns owned by the connected user — other users' data is never exposed. Reference a campaign by its numeric id or slug.

Available tools

16 tools, kept in sync with the server.

List Campaigns Tool

list-campaigns-tool

List the campaigns in the acting organisation, newest first, each with its id, title, slug, public URL and short link. Paged: the response carries the total count, so request further pages until page * per_page >= total.

InputTypeRequiredDescription
per_page integer no Campaigns per page (1-100).
page integer no Page number (1-based) for paging through results.

Get Campaign Tool

get-campaign-tool

Get the full configuration and lifetime metrics for one of the authenticated user's campaigns, identified by its numeric id or slug.

InputTypeRequiredDescription
campaign string yes The campaign id or slug.

Get Campaign Analytics Tool

get-campaign-analytics-tool

Get analytics totals (views, clicks, shares, conversions) and engagement rates for one of the user's campaigns. Omit the dates for lifetime figures, or pass from/to for a window.

InputTypeRequiredDescription
campaign string yes The campaign id or slug.
from string no Start date (YYYY-MM-DD). Optional; omit with "to" for lifetime totals.
to string no End date (YYYY-MM-DD). Optional.

Get Campaign Timeseries Tool

get-campaign-timeseries-tool

Get a daily time series for one metric (views, clicks, shares or conversions) of one of the user's campaigns. Defaults to the last 30 days; gaps are zero-filled.

InputTypeRequiredDescription
campaign string yes The campaign id or slug.
metric string no Which metric to chart.
from string no Start date (YYYY-MM-DD). Optional.
to string no End date (YYYY-MM-DD). Optional.

Get Campaign Breakdown Tool

get-campaign-breakdown-tool

Break down one of the user's campaign analytics by a dimension: "device" (works for any metric) or "platform" (share platforms). Defaults to the last 30 days.

InputTypeRequiredDescription
campaign string yes The campaign id or slug.
dimension string yes Group by device or by share platform.
metric string no Metric to break down (ignored for the platform dimension, which always uses shares).
from string no Start date (YYYY-MM-DD). Optional.
to string no End date (YYYY-MM-DD). Optional.

Get Campaign Shares Tool

get-campaign-shares-tool

List a campaign's recent shares — the same merged groups shown in the dashboard, where repeat shares from the same person are combined and their clicks and conversions summed. Newest first by default; sortable by date, clicks or conversions, and paged. Each row carries the participant's name, role, platform, device, picture, share URL, code, sharing text, clicks, conversions, merged_count and timestamps — never their email.

InputTypeRequiredDescription
campaign string yes The campaign id or slug.
sort string no Sort field: share date, total clicks, or total conversions.
direction string no Sort direction.
per_page integer no Rows per page (1-100).
page integer no Page number (1-based) for paging through results.

Create Campaign Tool

create-campaign-tool

Create a new campaign in the acting organisation, attributed to the authenticated user. Only "title" is required; a unique slug is generated from the title when omitted.

InputTypeRequiredDescription
title string yes Campaign title.
slug string no URL slug. Optional; generated from the title when omitted.
folder_id integer no Id of one of your folders to file the campaign into. Optional.
utm_source string no UTM source.
utm_medium string no UTM medium.
utm_campaign string no UTM campaign.
utm_content string no UTM content.
hide_branding boolean no Hide Echo branding.
viral_tracking boolean no Enable viral chain tracking.
conversion_tracking boolean no Enable conversion tracking.
social_proof boolean no Show recent sharers.
language_default string no Default language code.

Update Campaign Tool

update-campaign-tool

Update fields on one of the authenticated user's campaigns. Identify it by id or slug; only the provided fields are changed.

InputTypeRequiredDescription
campaign string yes The campaign id or slug to update.
title string no Campaign title.
slug string no URL slug.
folder_id integer|null no Id of one of your folders to file the campaign into; pass null to move it back to the root level.
utm_source string no UTM source.
utm_medium string no UTM medium.
utm_campaign string no UTM campaign.
utm_content string no UTM content.
hide_branding boolean no Hide Echo branding.
viral_tracking boolean no Enable viral chain tracking.
conversion_tracking boolean no Enable conversion tracking.
social_proof boolean no Show recent sharers.
language_default string no Default language code.

List Campaign Visuals Tool

list-campaign-visuals-tool

List a campaign's sharing visuals in position order, each with its id, file URL, composited preview URL and box_* element layout. The first visual is the primary one, used when the campaign is shared. A campaign holds up to 10 visuals.

InputTypeRequiredDescription
campaign string yes The campaign id or slug.

Create Campaign Visual Tool

create-campaign-visual-tool

Add a sharing visual to a campaign, appended at the end of the strip (a campaign holds at most 10). Provide the image either as a public https image_url (preferred) or as base64-encoded image_base64 data; jpeg, png and webp up to 10 MB are accepted. Optionally pass box_* fields to set the element layout right away, and sharing_url / sharing_text to give the visual its own sharing settings (empty values inherit from the primary visual at share time).

InputTypeRequiredDescription
campaign string yes The campaign id or slug.
image_url string no Public https URL of the visual's image file (jpeg, png, or webp, max 10 MB). Preferred over image_base64.
image_base64 string no Base64-encoded image data (optionally as a data: URI). Use only for small images; prefer image_url.
sharing_url string no Destination URL opened when a share of this visual is clicked. Leave empty to inherit the primary visual's URL at share time.
sharing_text string no Sharing text for this visual (max 1000 characters). Leave empty to inherit the primary visual's text.
box_name_enabled boolean no Show the name element on the image.
box_name_x integer no X position of the name element, in px on the source image.
box_name_y integer no Y position of the name element, in px on the source image.
box_name_width integer no Width of the name element in px.
box_name_height integer no Height of the name element in px.
box_name_text_align string no Text alignment of the name element.
box_name_font_size integer no Font size of the name element in px (8-120).
box_name_color string no Text color of the name element as a hex value, e.g. #ffffff.
box_name_font string no Font of the name element: a Google font from the editor's list or one of the organisation's custom fonts; invalid fonts fall back to the default.
box_name_style string no Comma-joined text styles for the name element: bold, italic, underline.
box_role_enabled boolean no Show the role element on the image.
box_role_x integer no X position of the role element, in px on the source image.
box_role_y integer no Y position of the role element, in px on the source image.
box_role_width integer no Width of the role element in px.
box_role_height integer no Height of the role element in px.
box_role_text_align string no Text alignment of the role element.
box_role_font_size integer no Font size of the role element in px (8-120).
box_role_color string no Text color of the role element as a hex value, e.g. #ffffff.
box_role_font string no Font of the role element: a Google font from the editor's list or one of the organisation's custom fonts; invalid fonts fall back to the default.
box_role_style string no Comma-joined text styles for the role element: bold, italic, underline.
box_custom_1_enabled boolean no Show the custom field 1 element on the image.
box_custom_1_x integer no X position of the custom field 1 element, in px on the source image.
box_custom_1_y integer no Y position of the custom field 1 element, in px on the source image.
box_custom_1_width integer no Width of the custom field 1 element in px.
box_custom_1_height integer no Height of the custom field 1 element in px.
box_custom_1_text_align string no Text alignment of the custom field 1 element.
box_custom_1_font_size integer no Font size of the custom field 1 element in px (8-120).
box_custom_1_color string no Text color of the custom field 1 element as a hex value, e.g. #ffffff.
box_custom_1_font string no Font of the custom field 1 element: a Google font from the editor's list or one of the organisation's custom fonts; invalid fonts fall back to the default.
box_custom_1_style string no Comma-joined text styles for the custom field 1 element: bold, italic, underline.
box_custom_2_enabled boolean no Show the custom field 2 element on the image.
box_custom_2_x integer no X position of the custom field 2 element, in px on the source image.
box_custom_2_y integer no Y position of the custom field 2 element, in px on the source image.
box_custom_2_width integer no Width of the custom field 2 element in px.
box_custom_2_height integer no Height of the custom field 2 element in px.
box_custom_2_text_align string no Text alignment of the custom field 2 element.
box_custom_2_font_size integer no Font size of the custom field 2 element in px (8-120).
box_custom_2_color string no Text color of the custom field 2 element as a hex value, e.g. #ffffff.
box_custom_2_font string no Font of the custom field 2 element: a Google font from the editor's list or one of the organisation's custom fonts; invalid fonts fall back to the default.
box_custom_2_style string no Comma-joined text styles for the custom field 2 element: bold, italic, underline.
box_custom_3_enabled boolean no Show the custom field 3 element on the image.
box_custom_3_x integer no X position of the custom field 3 element, in px on the source image.
box_custom_3_y integer no Y position of the custom field 3 element, in px on the source image.
box_custom_3_width integer no Width of the custom field 3 element in px.
box_custom_3_height integer no Height of the custom field 3 element in px.
box_custom_3_text_align string no Text alignment of the custom field 3 element.
box_custom_3_font_size integer no Font size of the custom field 3 element in px (8-120).
box_custom_3_color string no Text color of the custom field 3 element as a hex value, e.g. #ffffff.
box_custom_3_font string no Font of the custom field 3 element: a Google font from the editor's list or one of the organisation's custom fonts; invalid fonts fall back to the default.
box_custom_3_style string no Comma-joined text styles for the custom field 3 element: bold, italic, underline.
box_custom_1_label string no Label of custom field 1 (max 64 characters).
box_custom_2_label string no Label of custom field 2 (max 64 characters).
box_custom_3_label string no Label of custom field 3 (max 64 characters).
box_picture_enabled boolean no Show the profile-picture element on the image.
box_picture_x integer no X position of the profile picture, in px on the source image.
box_picture_y integer no Y position of the profile picture, in px on the source image.
box_picture_width integer no Width of the profile picture in px.
box_picture_height integer no Height of the profile picture in px.
box_picture_z_index string no Whether the profile picture renders behind or in front of the image.
box_picture_shape string no Shape of the profile picture.
box_picture_border_color string no Border color of the profile picture as a hex value.
box_picture_border_width integer no Border width of the profile picture in px (0-30).

Update Campaign Visual Tool

update-campaign-visual-tool

Update one of a campaign's sharing visuals: its box_* element layout and its own sharing_url / sharing_text (empty values inherit from the primary visual at share time); only the provided fields are changed. The composited preview is not regenerated (it is produced by the dashboard editor), but layout changes affect how shares are rendered.

InputTypeRequiredDescription
campaign string yes The campaign id or slug.
visual_id integer yes The id of the visual to update.
sharing_url string no Destination URL opened when a share of this visual is clicked. Leave empty to inherit the primary visual's URL at share time.
sharing_text string no Sharing text for this visual (max 1000 characters). Leave empty to inherit the primary visual's text.
box_name_enabled boolean no Show the name element on the image.
box_name_x integer no X position of the name element, in px on the source image.
box_name_y integer no Y position of the name element, in px on the source image.
box_name_width integer no Width of the name element in px.
box_name_height integer no Height of the name element in px.
box_name_text_align string no Text alignment of the name element.
box_name_font_size integer no Font size of the name element in px (8-120).
box_name_color string no Text color of the name element as a hex value, e.g. #ffffff.
box_name_font string no Font of the name element: a Google font from the editor's list or one of the organisation's custom fonts; invalid fonts fall back to the default.
box_name_style string no Comma-joined text styles for the name element: bold, italic, underline.
box_role_enabled boolean no Show the role element on the image.
box_role_x integer no X position of the role element, in px on the source image.
box_role_y integer no Y position of the role element, in px on the source image.
box_role_width integer no Width of the role element in px.
box_role_height integer no Height of the role element in px.
box_role_text_align string no Text alignment of the role element.
box_role_font_size integer no Font size of the role element in px (8-120).
box_role_color string no Text color of the role element as a hex value, e.g. #ffffff.
box_role_font string no Font of the role element: a Google font from the editor's list or one of the organisation's custom fonts; invalid fonts fall back to the default.
box_role_style string no Comma-joined text styles for the role element: bold, italic, underline.
box_custom_1_enabled boolean no Show the custom field 1 element on the image.
box_custom_1_x integer no X position of the custom field 1 element, in px on the source image.
box_custom_1_y integer no Y position of the custom field 1 element, in px on the source image.
box_custom_1_width integer no Width of the custom field 1 element in px.
box_custom_1_height integer no Height of the custom field 1 element in px.
box_custom_1_text_align string no Text alignment of the custom field 1 element.
box_custom_1_font_size integer no Font size of the custom field 1 element in px (8-120).
box_custom_1_color string no Text color of the custom field 1 element as a hex value, e.g. #ffffff.
box_custom_1_font string no Font of the custom field 1 element: a Google font from the editor's list or one of the organisation's custom fonts; invalid fonts fall back to the default.
box_custom_1_style string no Comma-joined text styles for the custom field 1 element: bold, italic, underline.
box_custom_2_enabled boolean no Show the custom field 2 element on the image.
box_custom_2_x integer no X position of the custom field 2 element, in px on the source image.
box_custom_2_y integer no Y position of the custom field 2 element, in px on the source image.
box_custom_2_width integer no Width of the custom field 2 element in px.
box_custom_2_height integer no Height of the custom field 2 element in px.
box_custom_2_text_align string no Text alignment of the custom field 2 element.
box_custom_2_font_size integer no Font size of the custom field 2 element in px (8-120).
box_custom_2_color string no Text color of the custom field 2 element as a hex value, e.g. #ffffff.
box_custom_2_font string no Font of the custom field 2 element: a Google font from the editor's list or one of the organisation's custom fonts; invalid fonts fall back to the default.
box_custom_2_style string no Comma-joined text styles for the custom field 2 element: bold, italic, underline.
box_custom_3_enabled boolean no Show the custom field 3 element on the image.
box_custom_3_x integer no X position of the custom field 3 element, in px on the source image.
box_custom_3_y integer no Y position of the custom field 3 element, in px on the source image.
box_custom_3_width integer no Width of the custom field 3 element in px.
box_custom_3_height integer no Height of the custom field 3 element in px.
box_custom_3_text_align string no Text alignment of the custom field 3 element.
box_custom_3_font_size integer no Font size of the custom field 3 element in px (8-120).
box_custom_3_color string no Text color of the custom field 3 element as a hex value, e.g. #ffffff.
box_custom_3_font string no Font of the custom field 3 element: a Google font from the editor's list or one of the organisation's custom fonts; invalid fonts fall back to the default.
box_custom_3_style string no Comma-joined text styles for the custom field 3 element: bold, italic, underline.
box_custom_1_label string no Label of custom field 1 (max 64 characters).
box_custom_2_label string no Label of custom field 2 (max 64 characters).
box_custom_3_label string no Label of custom field 3 (max 64 characters).
box_picture_enabled boolean no Show the profile-picture element on the image.
box_picture_x integer no X position of the profile picture, in px on the source image.
box_picture_y integer no Y position of the profile picture, in px on the source image.
box_picture_width integer no Width of the profile picture in px.
box_picture_height integer no Height of the profile picture in px.
box_picture_z_index string no Whether the profile picture renders behind or in front of the image.
box_picture_shape string no Shape of the profile picture.
box_picture_border_color string no Border color of the profile picture as a hex value.
box_picture_border_width integer no Border width of the profile picture in px (0-30).

Reorder Campaign Visuals Tool

reorder-campaign-visuals-tool

Reorder a campaign's sharing visuals. Pass every visual id of the campaign exactly once, in the desired order; the first id becomes the primary visual used when the campaign is shared.

InputTypeRequiredDescription
campaign string yes The campaign id or slug.
visual_ids array yes Every visual id of the campaign exactly once, in the desired order.

List Folders Tool

list-folders-tool

List the campaign folders in the acting organisation, sorted by name, each with its id, name and campaign count. Paged: the response carries the total count.

InputTypeRequiredDescription
per_page integer no Folders per page (1-100).
page integer no Page number (1-based) for paging through results.

Create Folder Tool

create-folder-tool

Create a new campaign folder in the acting organisation, attributed to the authenticated user. Use folders to organize campaigns; file a campaign into one by passing folder_id to create-campaign or update-campaign.

InputTypeRequiredDescription
name string yes Folder name.

Update Folder Tool

update-folder-tool

Rename one of the authenticated user's campaign folders, identified by its numeric id.

InputTypeRequiredDescription
folder integer yes The folder id to update.
name string no New folder name.

List Organisations Tool

list-organisations-tool

Report the organisation this connection acts within — its id and name — plus a has_other_memberships flag saying whether you belong to any others. It never lists the other organisations and never discloses fellow members' names or emails.

No inputs.