Salla MCP Server
Provides tools for interacting with the Salla Admin API to manage a Salla store's resources, such as listing and creating categories (including nested parent/child categories). Operations are defined by declarative task contracts, can be combined in sandboxed Python code, and any change to the store is staged in a change plan that the user must approve before it is applied to the live store.
Click on "Deploy 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., "@Salla MCP ServerAdd a "Cat food" category under "Pets" in my Salla store."
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.
Salla MCP Demo: contract-driven Code Mode
A teaching project showing how to build a scalable MCP server for a real e-commerce API and an agent that uses it. It has four parts:
Part | Folder | Command | What it does |
MCP server |
|
| One generic engine for the Salla Admin API. Everything it can do comes from task contracts: YAML and Markdown files that partners add without writing code, including the screens the agent can show (A2UI views). |
Chat agent |
|
| An OpenAI-powered web chat that uses the server. You approve every change it wants to make to your store. |
Task Contract Studio |
|
| A form for building, previewing, validating and installing task contracts on the running server. |
A2UI renderer |
| (served by the two web apps) | A small plain-JavaScript renderer for A2UI v0.9.1 screens. |
⚠️ This project calls the real Salla API. Approved changes modify a real store, so use a Salla demo store while learning.
Contents:
Deeper reading: docs/architecture.md (flows, safety, scaling) and docs/adding-a-task.md (the partner guide).
1. The idea in one picture
flowchart LR
subgraph P["Partner files (data, no code)"]
T["tasks/categories/<br/>task.yaml · functions.yaml · ui.yaml<br/>prompts/*.md · skills/*/SKILL.md"]
end
subgraph E["mcp_server engine (code, written once)"]
C["catalog<br/>(validated)"] --> S["search · describe"]
C --> X["call · execute<br/>(Monty sandbox)"]
X -->|reads| H["HTTP executor"]
X -->|writes| PL["change plan"]
PL --> A["apply_changes<br/>ONE approval gate"] --> H
C --> V["render_ui<br/>(A2UI views)"]
end
T --> C
H <-->|HTTPS| API["Salla Admin API"]
AG["chat_agent<br/>(OpenAI)"] <-->|"MCP · Streamable HTTP"| E
B["Browser<br/>(draws A2UI)"] <-->|WebSocket| AG
ST["task_studio"] -->|"admin API"| CFive ideas carry the whole design:
Tasks are data, the engine is code. Adding a business domain means adding a folder of YAML and Markdown. The server, the agent and the Studio don't change.
Code Mode. The LLM gets 6 fixed tools, whatever the number of tasks. It finds functions with
search, reads their typed signatures withdescribe, and combines them in short Python scripts that run in a secure sandbox (Monty).One approval gate, one HITL broker. Every write is staged into a change plan. Nothing changes in the store until the human approves the whole plan through MCP elicitation. On the agent side, one small file, the HITL broker, handles every interrupt and resume, for any task.
Planned screens. Partners design each screen ahead of time in A2UI. The LLM only fills in the data, and button clicks come back to the LLM.
Built for scale. The prompt sent on every LLM call doesn't grow with the tasks; everything else is loaded on demand. A CI test with 100 generated tasks enforces this.
Related MCP server: Shopify Store MCP Server
2. Reproduce it exactly
2.1 The environment it was built and tested with
Item | Version used | Notes |
OS | Windows 11 Pro | Commands below are given for bash and PowerShell |
Python | 3.13.12 |
|
0.11.29 | Installs the exact dependency versions from | |
Node.js | 22.14 | Optional, only to run an MCP inspector with |
Browser | Edge / Chrome | Needs internet access for two CDN scripts: marked 12.0.2 and DOMPurify 3.1.6 |
Key libraries, pinned in uv.lock:
Library | Version | Used for |
| 2.2.0 | MCP Python SDK: |
| 0.0.23 | The Code Mode sandbox (pre-1.0, so pinned exactly) |
| 3.13.0 | Responses API (the agent's LLM) |
| 0.141.1 / 1.6.0 / 0.52.4 | The chat and Studio web apps, WebSocket |
| 0.28.1 | Calls to the Salla API |
| 2.13.5 / 2.15.0 | Contract models, settings from |
| 6.0.3 | Contract files (uses libyaml's C parser when available) |
| 4.26.0 / 0.37.0 | Argument validation, and A2UI schema checks |
| 9.1.1 / 1.4.0 / 0.23.1 | Tests, with the Salla API mocked |
Protocols and services:
MCP over Streamable HTTP;
A2UI v0.9.1 with the basic catalog (the official schemas are copied into
src/mcp_server/engine/a2ui_spec/);OpenAI Responses API with the model
gpt-5.5;Salla Admin API v2 (
https://api.salla.dev/admin/v2).
2.2 Accounts you need
A Salla demo store and an access token.
Create a free account on the Salla Partners portal, and create a demo store.
Create an app with the scopes
categories.readandcategories.read_write.Install the app on the demo store and get its access token. See Salla's authorization guide. In Easy mode, the token arrives in the
app.store.authorizewebhook event.Tokens expire after about 14 days. A
401means it's time for a new one.
An OpenAI API key with access to
gpt-5.5, the default. Other models that support the Responses API and function calling can be set withOPENAI_MODEL, but onlygpt-5.5was tested.
The tests need neither: Salla is mocked, and the LLM is scripted.
2.3 Step by step
1. Get the code and install the exact versions.
git clone https://github.com/jamalla/salla-api-operation-mcp-task.git
cd salla-api-operation-mcp-task
uv sync --locked # creates .venv with the versions from uv.lock2. Create your .env, from the repository root. Every app reads ./.env from the folder it's started in.
cp .env.example .env # PowerShell: Copy-Item .env.example .env
uv run python -c "import secrets; print(secrets.token_hex(24))" # a value for MCP_ADMIN_TOKENFill in at least these three:
SALLA_ACCESS_TOKEN=... # from 2.2
OPENAI_API_KEY=sk-... # from 2.2
MCP_ADMIN_TOKEN=... # the random value above; the Studio needs it3. Check the contracts and run the tests. Neither needs a token.
uv run salla-mcp validate # → OK categories: 8 functions, 3 prompts, 1 skills, 2 views
uv run pytest # → 90 passed4. Start the three apps, each in its own terminal, from the repository root:
uv run salla-mcp serve # MCP server → http://127.0.0.1:8001/mcp (+ /admin/tasks)
uv run salla-agent # chat agent → http://127.0.0.1:8000
uv run salla-studio # the Studio → http://127.0.0.1:8020 (optional)The MCP server prints:
Salla MCP server → http://127.0.0.1:8001/mcp
Profiles → none (set MCP_PROFILES)
Admin API → http://127.0.0.1:8001/admin/tasks5. Open http://127.0.0.1:8000 and try:
"List my hidden categories":
search→describe→execute, and no approval is needed."Create Pets with a sub-category Cat food": one approval card with 2 changes. Try Reject, then Approve.
"Show my hidden categories as cards": the
category_listview is drawn.Click Details: the detail view appears.
Edit the name and click Save name: an approval card shows the new name.
In the sidebar, Prompts → Build a category tree.
Write in Arabic: «اعرض الأقسام المخفية».
Under each answer, the chat shows what the turn cost, for example: 4 LLM calls · 7,493 input tokens (1,792 cached) · 252 output.
2.4 Check that it works
Check | Expected |
|
|
|
|
| JSON with |
Chat sidebar |
|
Studio (http://127.0.0.1:8020) | The brands template form, with a live UI views preview (two cards with a Rename button) |
MCP inspector (optional) |
|
3. Configuration reference
Every setting is an environment variable, usually set in .env (see .env.example). The three apps read the same .env, from the folder they're started in.
MCP server (src/mcp_server/config.py):
Variable | Default | Meaning |
| (required to serve) | Token of the Salla app installed on your store |
|
| Salla Admin API |
|
| Where the task folders are |
| (empty = all) | Comma-separated tasks to load, e.g. |
|
| Streamable HTTP endpoint: |
|
| Items per page for MCP lists and |
|
| JSON, e.g. |
| (empty = admin API off) | Bearer token for |
|
| Time limit per |
|
| Memory limit per script |
|
| Staged change plans expire after 15 minutes |
Chat agent (src/chat_agent/config.py):
Variable | Default | Meaning |
| (required) | OpenAI key |
|
| Model for the Responses API |
|
| Maximum LLM ⇄ tool round trips per user message |
|
| Longer tool results are cut before the LLM reads them |
|
| The MCP server. Add |
|
| The chat web app |
Task Contract Studio (src/task_studio/app.py):
Variable | Default | Meaning |
| (required to install) | Must equal the server's value |
|
| The admin API is derived from it: same host and port, path |
| (derived) | Set it only if the admin API is somewhere else |
|
| The Studio web app |
CLI (uv run salla-mcp …):
Command | Does |
| Run the server (the default command) |
| Check task folders against the contract; prints the file and field of every problem |
| Regenerate |
4. How it works
4.1 What a partner writes (no Python)
A task is a folder: tasks/<task>/ with task.yaml, functions.yaml, ui.yaml (optional), prompts/*.md and skills/*/SKILL.md. A function is a few lines of YAML:
- name: create # exposed as categories_create
summary: Create a category, optionally under a parent.
effect: write # read | write | destructive: decides the approval
method: POST
path: /categories
params: # JSON Schema: validated, and turned into a typed signature
type: object
required: [name]
properties:
name: { type: string }
parent_id: { type: integer }
status: { type: string, enum: [active, hidden], default: hidden }
request:
body: { name: name, parent_id: parent_id, status: status }
approval: "Create category “{name}” ({status})"tasks/_template/ is the contract: JSON Schemas generated from the engine, plus commented examples. The server refuses to start on an invalid contract, and uv run salla-mcp validate shows the same messages. The full guide is docs/adding-a-task.md.
4.2 Planned screens: ui.yaml (A2UI)
A task can plan the screens the agent shows, in A2UI v0.9.1. The partner writes each layout once; the LLM only sends the data:
views:
- name: category_list # render_ui(view="categories_category_list", data=...)
summary: Show several categories as cards.
data: {type: object, required: [heading, categories], properties: {...}} # JSON Schema, validated
actions: # button events: a click goes back to the LLM
- {name: hide_category, label: Hide this category, function: categories_update}
components: # A2UI components, used exactly as written
- {id: root, component: Column, children: [heading, cards]}
- {id: cards, component: List, children: {path: /categories, componentId: card}}
# …Checked at load. Views must be valid A2UI, use only the components the bundled renderer can draw, and account for every binding and button.
Rendering.
render_ui(view, data)checks the data and returns three A2UI messages (createSurface,updateComponents,updateDataModel), which the chat draws.Clicks. A click sends an A2UI
actionback to the LLM as a[UI action]message. Any change that follows still needs your approval.
4.3 What the LLM sees: 6 tools, whatever the number of tasks
Tool | Purpose |
| Ranked search (BM25) over functions, views, prompts and skills (paginated) |
| Exact Python signatures of functions, and the data schema of views |
| Run one function deterministically |
| Run a short Python script in the Monty sandbox that combines functions (Code Mode) |
| Show a planned screen filled with data; also callable inside |
| The only way the store changes. The user approves or rejects the whole plan |
# what an LLM sends to execute(): reads run now; writes are only staged
pets = await categories_create(name="حيوانات أليفة", en_name="Pets")
await categories_create(name="طعام قطط", en_name="Cat food", parent_id=pets["data"]["id"]) # "$w1.id"This produces one approval card for 2 changes. On approve, the engine applies them in order, and "$w1.id" becomes the parent's real ID. The agent also has its own tool, load_skill, which reads a skill's full text on demand.
4.4 Human in the loop: one gate in the server, one broker in the agent
Every change to the store stops and waits for a human. This happens in two places, each written once and shared by every task:
Where | File | Role |
The gate (server) |
| Decides what to ask. It renders the change plan as a table and asks through MCP elicitation. |
The HITL broker (agent) |
| Handles every interrupt and resume. It pauses the tool call, asks the browser, and resumes the call with the answer. |
The card (browser) |
| Draws any elicitation form from its JSON Schema. An |
The broker knows nothing about tasks. It never sees categories, plans or Salla. It receives an elicitation (a message and the JSON Schema of a small form) and returns the human's answer: accept with the form data, decline or cancel. A new task, or a new kind of question from the server, goes through it with no change to the agent.
How one interrupt and resume works:
sequenceDiagram
participant L as Agent loop (agent.py)
participant C as MCP client
participant B as HITL broker (hitl.py)
participant W as Browser (app.js)
participant M as MCP server
L->>C: call_tool("apply_changes", plan_id)
C->>M: tools/call
Note over M: resolver confirm_plan returns Elicit(render_plan(plan), Approval)
M-->>C: elicitation request (message + form schema)
C->>B: elicitation_callback(params)
B->>W: approval_request (id, message, schema)
Note over L,B: the tool call is paused on an asyncio.Future
W->>B: approval_response (id, action, content), via main.py and broker.resolve
B-->>C: ElicitResult(accept, approve=true, note)
C-->>M: the answer
Note over M: approved: apply the plan in order. Otherwise nothing is sent to Salla
M-->>C: tool result
C-->>L: the loop resumes with the resultWhat makes it reliable:
One pending question, one future.
elicitation_callbackcreates a request id and anasyncio.Future, sendsapproval_requestover the tab's WebSocket and awaits the future.resolve(id, action, content)completes it when the browser answers.The chat keeps listening while it waits. The agent turn runs as a background task (
main.py), so the WebSocket loop can deliver the answer to the paused call.Answers reach the right tab. Each browser tab has its own MCP session and its own broker.
One question at a time. The agent asks the LLM for one tool call at a time (
parallel_tool_calls=False).Nothing hangs.
A question expires after 10 minutes: the browser gets
approval_expired, and the server getscancel.Closing the tab cancels every open question (
cancel_all).An unknown answer counts as
cancel.URL-mode elicitation (e.g. "log in at this URL") is declined.
Fail closed. Only an accepted form with
approve: trueapplies the plan. A rejection, decline, cancel or timeout sends nothing to Salla, and the LLM is told why, so it doesn't retry. Plans are single-use and expire afterPLAN_TTL_SECONDS.
Reusing it. The broker depends only on the MCP SDK's elicitation types and a send(event) function. To use it in another client, such as a CLI, a Slack bot or a mobile app, keep hitl.py and replace the transport: whatever shows the question calls broker.resolve(...) with the answer.
4.5 The Studio and the admin API
The Studio edits a form and renders it into contract files, shown as live YAML tabs with an A2UI preview for views. It sends them to the MCP server's admin API, which validates them with the start-up rules and installs them live, with no restart. The admin API runs next to /mcp, is protected by MCP_ADMIN_TOKEN, and is not part of MCP, so LLMs never see it.
Endpoint | Purpose |
| List installed tasks |
| Get a task's contract files |
| Dry run: |
| Install and hot-reload ( |
| Uninstall |
4.6 Pagination at three levels
MCP lists (prompts, resources) come in pages with an opaque
next_cursor(MCP_PAGE_SIZE).search()returns anext_cursor.Salla's own pages:
fetch_all_pages("categories_list", {...})insideexecutewalks them all.
5. Built for 100+ tasks
Every LLM call sends the agent's instructions and the tool schemas again, and one user message often makes 4–6 calls. So the rule is: the fixed part of the prompt must not grow with the tasks; everything else is loaded when needed.
Sent on every LLM call | Loaded only when needed |
6 tools + | functions and views ( |
Measured with 100 generated tasks (800 functions, 200 views, 100 skills):
Result | |
Fixed prompt, 1 task → 100 tasks | about 1,800 → 2,050 tokens, roughly 3 tokens per task |
Listing every skill's description instead | about 5,700 extra tokens on every call |
Search over 1,400 entries | about 3 ms |
Server start-up with 100 tasks / reload after changing one task | about 7 s / 0.3 s |
How:
No skill list in the prompt. The agent's prompt names the tasks; skills are found with
search(kind="skill").Size limits in the contract. Summaries are limited to 200 characters, action labels to 150, skill descriptions to 300, and a skill's text to 12,000.
Ranked search (BM25). Rare words and words in names count more, so the LLM needs fewer search rounds.
Small results.
Scripts return only the fields they need.
render_uiinsideexecutesends list data straight to the screen.The agent cuts results longer than
MAX_TOOL_OUTPUT_CHARS.
Only the stubs a script uses.
executetype-checks a script against the functions it names, not against all of them.Profiles.
MCP_PROFILESplus…/mcp?profile=<name>gives each kind of agent only its tasks, and this is enforced for every tool, prompt and resource.Incremental reloads. Installing a task re-reads only the folders whose files changed.
Measured. The chat shows real token usage per turn.
test_token_budget.pyfails if the fixed part goes over 4,000 tokens with 100 tasks or grows by more than 10 tokens per task.
Details: docs/architecture.md → Scaling to 100+ tasks.
6. Project tour
.env.example every setting, commented (copy to .env)
pyproject.toml / uv.lock dependencies and their exact locked versions; the 3 CLI commands
docs/
architecture.md flows, the approval gate, A2UI, scaling, errors
adding-a-task.md the partner guide (contract fields, views, size limits, checklist)
tasks/ ── DATA: partner task contracts (no code) ──
categories/ task.yaml, functions.yaml (8), ui.yaml (2 views), prompts/ (3), skills/ (1)
_template/ the contract: *.schema.json (generated) + a commented brands example
src/mcp_server/ ── THE MCP SERVER (uv run salla-mcp serve) ──
server.py entry point: wires engine + api; LLM instructions; CLI serve | validate | schema
config.py settings from .env
engine/ core logic: no MCP or HTTP code
contracts.py the partner contract (Pydantic): validation, request building, size limits, views
catalog.py live catalog: load, validate, BM25 search, install/uninstall, CatalogScope
runtime.py the Engine: call / execute / render / apply
plans.py change plans: staged writes + "$wN.id" placeholders
sandbox.py Monty sandbox + the typed stubs scripts are checked against
store_client.py HTTP to Salla: auth, retries, readable errors
a2ui.py A2UI: load-time checks of views + the messages that show them
a2ui_spec/ the official A2UI v0.9.1 JSON Schemas (copied, Apache-2.0)
api/ how clients reach the engine (the only MCP / HTTP code)
tools.py the 6 MCP tools
approval.py the approval question and its answer (MCP elicitation)
protocol.py resources, prompts, pagination, profile scoping (replaces SDK handlers)
admin.py admin HTTP API: validate / install / uninstall tasks live
profiles.py one endpoint per kind of agent (/mcp?profile=<name>)
src/chat_agent/ ── THE CHAT AGENT (uv run salla-agent) ──
main.py FastAPI + WebSocket; one MCP session per browser tab
mcp_connection.py connect by URL + paginated discovery
agent.py agent loop (OpenAI Responses API), MCP ⇄ OpenAI, A2UI hand-off, usage
hitl.py the HITL broker: pauses on any MCP elicitation, asks the browser, resumes with the answer
static/ index.html, app.js, style.css
src/task_studio/ ── THE TASK CONTRACT STUDIO (uv run salla-studio) ──
app.py the page + /api/* in front of the MCP admin API (token stays server-side)
files.py draft ⇄ contract files (YAML + Markdown)
static/ index.html, studio.js, studio.css
src/a2ui_renderer/ ── A2UI RENDERER, shared by the chat and the Studio ──
static/ a2ui.js (the renderer), a2ui.css
tests/ mcp_server/, agent/, studio/ (each app alone) + integration/ (apps together)Rules the layout follows:
Isolated apps. The three apps never import each other; they talk over HTTP only. Both web apps serve the shared A2UI renderer the way they'd use a CDN script.
Protocol-free engine.
engine/has no MCP or HTTP imports;api/is the only MCP code.One place for SDK internals.
api/protocol.pyis the only module that touches them.
Concept | Where to look |
Partner contract (Pydantic → JSON Schema) | |
Live catalog, search, scopes | |
call / execute / render / apply | |
Change plans and placeholders | |
Code Mode sandbox + typed stubs | |
A2UI views | |
The 6 tools | |
Human in the loop (elicitation) | |
Resources, prompts, pagination, profiles | |
Admin API | |
Agent loop, token usage |
7. Build a similar project from scratch
Use this as a recipe for your own API (Shopify, Zid, an internal API…). Each step names the file here to copy ideas from.
Step 0. Set up the project.
uv init my-mcp-demo && cd my-mcp-demo
uv add "mcp==2.2.*" httpx pydantic-settings "pydantic-monty==0.0.23" pyyaml jsonschema openai fastapi "uvicorn[standard]"
uv add --dev pytest pytest-asyncio respxUse a src/ layout with one package per app, and declare them in pyproject.toml under [tool.hatch.build.targets.wheel] packages. Define the CLI commands under [project.scripts], and set [tool.pytest.ini_options] asyncio_mode = "auto".
Steps, in the order that works best:
# | Build | Key decisions | Look at |
1 | The contract | Pydantic models with |
|
2 | The catalog | Strict loading: an invalid task stops the server and names the file and field. Live |
|
3 | The HTTP executor | Contract + arguments → request: path placeholders, query or body, dotted keys for nesting. Retries and readable errors. |
|
4 | Change plans | Writes are staged, never run. |
|
5 | The sandbox | Monty: no filesystem, network or environment. Type-check scripts against generated stubs before running them, and hand the script only the functions it names. |
|
6 | The MCP tools | A fixed set (search, describe, call, execute, render_ui, apply_changes), with read-only annotations. Engine errors become |
|
7 | The approval gate | A resolver ( |
|
8 | Protocol extras | Paginated |
|
9 | Admin API |
|
|
10 | The agent |
|
|
11 | Human in the loop in the browser | One WebSocket per tab. An |
|
12 | Skills on demand | Skills are |
|
13 | A2UI views | Copy the official v0.9.1 schemas, check views at load time with a |
|
14 | The Studio | A form to a draft to files, then the admin API. The token stays server-side. It uses the same renderer for previews. |
|
15 | Scaling guards | Size limits, BM25 search, profiles, clipped results, token usage, and a token-budget test with 100 generated tasks. | |
16 | Tests | Run the MCP server in memory ( |
|
Design rules worth keeping:
Tasks are data. Adding one never changes code.
The tool count is fixed, and the prompt must not grow with the tasks.
Every change passes one approval gate, which fails closed.
The LLM can't approve, invent screens or reach undeclared endpoints.
The engine has no protocol code, and apps talk over HTTP only.
Check everything at load time, with messages that name the file and field.
8. Tests
uv run pytest # everything (90 tests, about 20 s)
uv run pytest tests/mcp_server # the server alone
uv run pytest tests/integration # apps together (agent ⇄ server, Studio ⇄ server, token budget)The server runs in memory, Salla's API is mocked with respx, the sandbox runs for real, and the LLM is scripted. Among other things, the tests check that:
a rejected plan sends no write request, and a client that can't show approval forms can't change the store;
placeholders become real IDs, and apply stops at the first failure;
type errors reach the LLM before any code runs, and the sandbox has no filesystem and a time limit;
contracts are strict, the template schemas match the engine, and texts respect the size limits;
views are valid A2UI, and
render_uionly accepts data that matches the view, including from inside scripts;profiles hide everything outside their tasks, and search ranks the best match first;
with 100 tasks, the fixed part of the prompt stays within its token budget.
9. Troubleshooting
Symptom | Fix |
The agent says "Could not talk to the MCP server" | Start it with |
The server exits with "SALLA_ACCESS_TOKEN is not set" | Create |
The server exits with "Invalid task contract(s)" | Run |
| The token has expired, or the app is missing the |
The LLM's script fails with "type errors" | Expected: it gets the message back and fixes the script. |
The Studio says the admin API is disabled | Put the same |
| The |
Windows: | A running app holds the |
Windows: | The console isn't UTF-8. Run |
The chat shows raw Markdown | The browser couldn't load marked / DOMPurify from the CDN; check internet access. |
10. Versions, limits and history
History (git):
tag
v1-per-tool: the first design, with one Python-coded MCP tool per operation;the
v2commit: contract-driven Code Mode, the chat agent and the Studio;the current version adds A2UI views and the scaling work in section 5.
Known limits:
PlanStoreis in memory. With several server replicas, swap it for a Redis-backed class with the same methods.Monty is pre-1.0 (0.0.23, pinned). All sandbox code lives in
engine/sandbox.py.Only part of A2UI is drawn. The renderer supports Column, Row, List, Card, Text, Image, Divider, Button, TextField and
formatString. The server refuses views that use anything else.A2UI checks are slow at start-up. With 100 tasks, start-up takes about 7 s, mostly checking views against the A2UI schemas.
Token counts in the budget test are estimates (4 characters per token). The chat's usage line shows real numbers from the API.
Reads can't see staged writes. Stage related writes together, and read after applying.
A note on the word "task": here, a task is a business domain folder (categories, brands, …). The MCP specification also has an experimental Tasks feature for long-running requests. That is a different thing, and the MCP Python SDK 2.2 used here doesn't implement it.
License and credits:
The repository doesn't have a license file yet.
The A2UI JSON Schemas in
src/mcp_server/engine/a2ui_spec/are © the A2UI authors, Apache-2.0 (see NOTICE.md).The sandbox is Monty by Pydantic.
The MCP SDK is the official modelcontextprotocol/python-sdk.
This server cannot be deployed
Maintenance
Related MCP Connectors
- SkilderOAuthai.skilder
One place to build, share, and govern the skills and tools your AI agents use at work.
- mcp-serverOAuthcom.make
Give your AI agents the tools to build, manage, and run automation workflows.
Connect, monitor, and control AI agents — tasks, approvals, schedules, and governance.
Supervised API-write gateway for AI agents with policy, human approval and execution receipts.
Related MCP Servers
- AlicenseAqualityFmaintenanceEnables AI models to dynamically create and execute their own custom tools through a meta-function architecture, supporting JavaScript, Python, and Shell runtimes with sandboxed security and human approval flows.510MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to interact with live Shopify stores through Admin and Storefront APIs for tasks like GraphQL execution, bulk operations, and file uploads. It includes built-in rate limiting and operation logging to manage store data and schema discovery securely.13 npm3ISC
- AlicenseAqualityCmaintenanceExposes Shopify Admin API capabilities to LLMs, enabling product, order, customer, and inventory management via natural language.4964 npm1MIT
- AlicenseNot gradedqualityBmaintenanceEnables conversational Admin API read/write across multiple Shopify stores with a production write-gate for safety.1MIT