MCP App Proxyfier
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MCP App Proxyfiersearch for running shoes under $100"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MCP App Proxyfier
MCP-сервер, который отдаёт в чат с моделью интерактивные MCP Apps (официальное UI-расширение MCP, рендерится в песочнице-iframe хоста). Вместо текстовой обёртки над запросами зритель получает нативный UI прямо в диалоге.
Реализован один вылизанный флоу на настоящих данных: Megamarket — поиск товаров → грид → детальная страница → корзина → оформление.
Данные статические: каталог собран из сохранённых снапшотов реальных страниц
megamarket.ru (pages/) скриптом pnpm update:data. Сеть и браузер на демо не нужны —
сервер стартует мгновенно и отвечает одинаково при любом Wi-Fi в зале.
Сценарий живого демо (без MCP → MCP без UI → MCP с UI → MCP с UI и скиллом) — в
DEMO.md.
Структура
packages/
ui/ React + Vite; собирается в самодостаточные HTML (по одному на приложение)
server/ MCP-сервер, отдаёт UI как ui:// ресурсы + инструменты
pages/ HAR/HTML-снапшоты megamarket.ru — сырьё для pnpm update:dataUI собирается в два самодостаточных HTML-бандла — index (каркасный ping) и
megamarket; все JS/CSS встроены, внешних ссылок нет (требование песочницы-iframe).
Сервер на старте читает эти HTML и регистрирует как ui:// ресурсы.
Инструменты
Инструмент | Вход | UI | Назначение |
|
|
| Каркасная проверка рендера iframe |
|
| — | Поиск товаров, результат только текстом (список позиций) |
|
|
| Тот же поиск + грид карточек виджетом |
|
|
| Тот же поиск + виджет; описание обязывает прочитать |
|
|
| Карточка товара: галерея, таблица «О товаре», описание |
| — | — | Сегодня/завтра + ближайшие 7 дней с днями недели |
|
|
| Добавляет товар в корзину |
| — |
| Текущее состояние корзины |
| — |
| Оформляет заказ по корзине, возвращает подтверждение и очищает её |
filters — ценовой коридор priceMin / priceMax и срок доставки deliveryBy
(YYYY-MM-DD; оставляет только то, что приедет не позже).
get_delivery_calendar существует потому, что у модели нет часов: «до пятницы» она сама
в число не превратит — либо выдумает, либо отсчитает от даты обучения. Скилл обязывает
вызвать календарь до поиска, отсюда и порядок вызовов в демо.
Три варианта поиска — это ступени живого демо (без UI → с UI → с UI и методичкой). Они
существуют одновременно на одном подключении, переключение идёт формулировкой запроса, без
перезапуска сервера. Почему их три, а не один с параметром: привязка UI живёт в
_meta.ui.resourceUri на регистрации инструмента и уезжает клиенту в tools/list —
результат вызова её изменить не может.
Корзина — in-memory, одна на процесс сервера: перезапуск её обнуляет.
Ресурсы ui://
MCP Apps: самодостаточный HTML, который хост рендерит в песочнице-iframe и кормит
structuredContent результата инструмента через мост. MIME — text/html;profile=mcp-app.
URI | Собирается из | Кто рендерит |
|
|
|
|
| все инструменты Megamarket |
Приложение Megamarket — мини-SPA: выдача → деталка → корзина → подтверждение. Какой вид
показать, оно решает по форме пришедшего structuredContent: products — выдача,
product — деталка, cart — корзина.
Виджет интерактивный, а не картинка:
чипы фильтров над гридом (бренд, шумоподавление) — фильтруют внутри iframe, без вызова инструмента и без нового пузыря в чате;
клик по карточке открывает деталку (
get_productчерез мост), «Назад» возвращает в тот же отфильтрованный список — состояние фильтров переживает переход;деталка открывается и голосом («покажи подробнее вот эти») — вид тот же самый;
«В корзину» на карточке и на деталке — app-initiated
add_to_cart(id); ответ несёт актуальную корзину, поэтому бейдж обновляется без отдельногоview_cart.
Фильтры виджета сознательно не трогают доставку: срок задаёт агент через
filters.deliveryBy на сервере. Иначе виджет молча показывал бы то, что агент уже отсёк.
Ресурсы skill://
Методички для агента. В отличие от ui:// это не MCP Apps — рендерить нечего, это
обычный текст, который агент читает перед вызовом инструмента.
URI | MIME | Назначение |
|
| Индекс скиллов — точка входа, по которой агент находит остальные |
|
| Подбор товара: уточнить бюджет и сценарий, перевести бюджет в |
Индекс и сами методички собираются из одного SkillDefinition
(packages/server/src/skills/skill-registry.ts), поэтому имя и описание в индексе не могут
разъехаться с ресурсом.
Данные
Каталог — packages/server/data/market.json (70 товаров, у всех есть детальная карточка).
Пересобирается из снапшотов:
pnpm update:data # разбирает pages/ → packages/server/data/market.json
pnpm update:data -- --dry-run # только показать, что распарсилось, ничего не писатьСкрипт идемпотентен: повторный прогон просто перезаписывает файл. Сеть не трогает.
Выдача поиска ограничена девятью позициями (SEARCH_RESULT_LIMIT) — грид 3×3 в узком
чат-iframe.
Сроки доставки — синтетические
packages/server/data/delivery.json не собирается из снапшотов: настоящий срок
(calculatedDeliveryDate в SSR-стейте страниц) есть ровно у одного товара каталога из 70, а
на выдаче Мегамаркет его не отдаёт вовсе. Формат подписей при этом взят у сайта: он пишет
только «Сегодня», «Завтра» и дату вида «15 июля» — «Послезавтра» у него нет.
В файле лежат дни, а не даты: дата считается в рантайме от сегодня, поэтому «Завтра» остаётся завтрашним и через месяц. Товары, которых в файле нет, получают детерминированный срок по хешу id — одинаковый между запусками, чтобы выдача не «дышала».
Флаг anc (активное шумоподавление) поднимается в «плоский» DTO из характеристик, чтобы
виджет фильтровал грид без запроса деталки на каждый товар. null означает «характеристики
нет в снапшоте», а не «шумоподавления нет».
Требования
Node.js 22+ (рекомендуется 24)
pnpm 11+
Сборка
pnpm install
pnpm build # сначала собирает HTML-бандлы UI, затем серверpnpm build сначала собирает UI (самодостаточные HTML со встроенными JS/CSS — без внешних
источников, как требует песочница-iframe), затем компилирует сервер, который на старте
читает эти HTML и регистрирует как ui:// ресурсы.
Превью виджета в браузере
Посмотреть виджет без Claude Desktop:
pnpm --filter @mcp-app-proxyfier/ui exec vite
# → http://localhost:5173/preview.htmlРендерит те же компоненты вью, что и боевое приложение, на настоящем ответе сервера.
Работают чипы фильтров, заход в карточку и возврат в отфильтрованный список. Кейс
открывается ссылкой: ?case=friday, ?case=detail, ?case=cart.
Фикстуры пересобираются с живого сервера, руками их править не надо:
pnpm build # превью читает ответы собранного сервера
pnpm update:fixtures # → packages/ui/src/preview/fixtures.jsonДаты доставки в фикстуре заморожены на момент снятия (превью — про вёрстку, не про
календарь). Протухли подписи вроде «Завтра» — просто перезапустите update:fixtures.
Чего в превью нет: postMessage-моста и вызовов инструментов — «Подробнее» берёт деталку из
фикстуры, а не дёргает get_product; «В корзину» показывает снимок корзины, а не вызывает
add_to_cart. Мост и рендер iframe проверяются только вживую, в Claude Desktop (см.
«Ручная проверка рендера» ниже). В продакшен-сборку превью не попадает: pnpm build:ui
собирает только index и megamarket.
Тесты
pnpm test # typecheck (включая тесты) + прогонТесты проверяют внешнее поведение через швы: инструменты MCP как чёрные ящики (поднимается
настоящий McpServer на in-memory транспорте), загрузку статического каталога (включая
деградацию товара без богатой детали), сроки доставки, реестр скиллов и выбор транспорта.
Рендер iframe проверяется вручную (см. ниже) — в CI его нет.
Тесты тайпчекаются вместе с кодом: гоняет их tsx, который типы не проверяет, поэтому
раньше tsc молча зеленел на тестах, ссылающихся на удалённые модули. Сборка идёт отдельным
конфигом (tsconfig.build.json), чтобы тесты не попадали в dist/.
Запуск / регистрация в Claude Desktop
Сервер говорит по MCP через stdio: Claude Desktop запускает его как дочерний процесс.
После pnpm build пропишите его в конфиг Claude Desktop.
Расположение файла конфигурации:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.jsonLinux:
~/.config/Claude/claude_desktop_config.json
Добавьте (замените путь на абсолютный путь к этому репозиторию):
{
"mcpServers": {
"mcp-app-proxyfier": {
"command": "node",
"args": ["/absolute/path/to/mcp-app-proxyfier/packages/server/dist/index.js"]
}
}
}Затем полностью закройте и заново откройте Claude Desktop.
Ручная проверка рендера (главный риск демо)
Главный риск — баг рендера iframe на хосте (ext-apps #671): клиент согласует UI-возможность и тянет ресурс, но не рисует iframe. Поэтому его проверяют глазами на боевой сборке.
В чате Claude Desktop попросите модель вызвать инструмент ping (например, «вызови
инструмент ping с echo hello»). Убедитесь визуально:
В чате нарисован интерактивный iframe (карточка с заголовком «MCP App Proxyfier»), а не только текстовый результат.
Карточка показывает
message: pong,echo: helloи таймстамп — то естьstructuredContentинструмента дошёл до UI через мост.
Если виден только текст и iframe не рисуется — баг #671 воспроизведён: зафиксируйте версию Claude Desktop и держите наготове запасной текстовый сценарий для демо.
Абстракция транспорта
Сервер не зависит от транспорта. Инструменты и ресурсы регистрируются на McpServer без
знания о канале. Транспорт выбирается за швом ServerTransportProvider
(packages/server/src/transport/): stdio (по умолчанию) и http (Streamable HTTP). Оба
провайдера регистрируют ровно те же инструменты и ui:// ресурсы — добавление HTTP не
потребовало правок кода инструментов или ресурсов.
Транспорт выбирается флагом или переменной окружения (флаг приоритетнее):
Параметр | Флаг | Env | По умолчанию |
Транспорт |
|
|
|
Интерфейс прослушивания |
|
|
|
Порт |
|
|
|
Путь эндпоинта |
|
|
|
Bearer-токен |
|
| (выкл.) |
Флаги понимают обе формы: --port 3000 и --port=3000.
Удалённый коннектор (Streamable HTTP)
Для демо, где владелец подключает коннектор сам (custom connector в claude.ai), а не Claude Desktop запускает его локально. Это альтернативный канал к тому же серверу — stdio-демо он не блокирует.
Соберите и запустите сервер по HTTP (слушает на
127.0.0.1:3000/mcp). Туннель делает порт публичным, поэтому задайтеMCP_HTTP_TOKEN— запросы безAuthorization: Bearer <token>отклоняются с401:pnpm build MCP_TRANSPORT=http MCP_HTTP_TOKEN="$(openssl rand -hex 16)" pnpm start # токен выкл. (только локально, без туннеля): pnpm start -- --transport httpОткройте публичный HTTPS-туннель к этому локальному порту:
cloudflared tunnel --url http://127.0.0.1:3000 # → печатает https://<random>.trycloudflare.com # альтернатива ngrok: # ngrok http 3000 → https://<random>.ngrok-free.appURL коннектора — это origin туннеля плюс путь эндпоинта, например
https://<random>.trycloudflare.com/mcp.В claude.ai → Settings → Connectors → Add custom connector вставьте этот URL (и Bearer-токен в поле авторизации коннектора, если вы его задали). Claude инициализирует сессию Streamable HTTP и показывает те же инструменты и
ui://приложения, что и stdio.
Ручная проверка (рендер iframe на хосте, ext-apps #671). Как и для stdio, убедитесь визуально, что результат инструмента рисует интерактивный iframe в чате claude.ai, а не только текст. Баг рендера #671 — клиентский и не связан с транспортом, но его нужно перепроверить на claude.ai: сборка хоста отличается от Claude Desktop.
Замечания:
Один запущенный процесс держит одну сессию Streamable HTTP — одного докладчика за туннелем.
Реконнект = перезапуск. При чистом отключении claude.ai шлёт завершение сессии и повторное подключение работает; после грязного обрыва (туннель умер) проще всего
Ctrl-Cи заново--transport http, если коннектор потерял сессию.Прослушивание остаётся на localhost намеренно; не слушайте
0.0.0.0— доступ к серверу только через туннель. Защита от DNS-rebinding выключена намеренно (host туннеля динамический); доступ охраняет Bearer-токенMCP_HTTP_TOKEN.После демо погасите туннель — URL является секретом.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/DreamShaded/MCP-Apps-data-proxyfier'
If you have feedback or need assistance with the MCP directory API, please join our Discord server