From d5618fdcec952af4afcefb9c1bdd41fe9e4fee35 Mon Sep 17 00:00:00 2001 From: Nur Date: Tue, 18 Aug 2026 14:27:54 -0700 Subject: [PATCH] feat(plugins): add aixplain-marketplace Claude Code plugin MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a `plugins/` tree as a sibling to `skills/`, plus the first plugin: `aixplain-marketplace`. A plugin bundles a skill together with the MCP servers it needs, so one install gives a coding agent both the knowledge and the live connection. `aixplain-marketplace` wires up the first-party Marketplace Search MCP server (tool 6960f934f316da19e5f22494, stable across environments) and ships a `marketplace-search` skill that drives it: find agents, models, tools, and integrations in one call, filter by category/developer/ supplier/host/function, read pricing and hosting, then turn a hit into working code — SDK call, REST call, MCP config, or an `aix.Agent(tools=[...])` attach block. The skill builds snippets from each asset's real input schema (`list_inputs_*`) rather than placeholders, and uses keyword arguments on `run()` — verified against Cloud Translation on PROD: aix.Model.get("66aa869f6eb56342c26057e1").run( text="Good morning", sourcelanguage="en", targetlanguage="ar") It also records two paths that do not work today, so an agent does not retry them: the MCP `run_*` actions (a single `input` string cannot express multi-field inputs) and sorting (`search` has no sort parameter, so ordering requires paging and sorting locally). Execution is routed through generated SDK code instead. No secrets are committed — `.mcp.json` references ${AIXPLAIN_API_KEY}. Co-Authored-By: Claude Opus 5 --- .claude-plugin/marketplace.json | 22 ++ plugins/README.md | 81 +++++++ .../.claude-plugin/plugin.json | 11 + plugins/aixplain-marketplace/.mcp.json | 10 + plugins/aixplain-marketplace/README.md | 130 +++++++++++ .../skills/marketplace-search/SKILL.md | 216 ++++++++++++++++++ skills/README.md | 3 + 7 files changed, 473 insertions(+) create mode 100644 .claude-plugin/marketplace.json create mode 100644 plugins/README.md create mode 100644 plugins/aixplain-marketplace/.claude-plugin/plugin.json create mode 100644 plugins/aixplain-marketplace/.mcp.json create mode 100644 plugins/aixplain-marketplace/README.md create mode 100644 plugins/aixplain-marketplace/skills/marketplace-search/SKILL.md diff --git a/.claude-plugin/marketplace.json b/.claude-plugin/marketplace.json new file mode 100644 index 00000000..78319abb --- /dev/null +++ b/.claude-plugin/marketplace.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://anthropic.com/claude-code/marketplace.schema.json", + "name": "aixplain", + "description": "Claude Code plugins for the aixplain platform — search the marketplace and work with aixplain assets directly from your editor.", + "owner": { + "name": "aixplain", + "url": "https://aixplain.com" + }, + "plugins": [ + { + "name": "aixplain-marketplace", + "description": "Search the aixplain marketplace from your editor — find agents, models, tools, and integrations across the whole catalog, read pricing and hosting, and get working code to call any asset via SDK, REST, or MCP.", + "source": "./plugins/aixplain-marketplace", + "category": "development", + "author": { + "name": "aixplain", + "url": "https://aixplain.com" + }, + "homepage": "https://studio.aixplain.com" + } + ] +} diff --git a/plugins/README.md b/plugins/README.md new file mode 100644 index 00000000..289b2f82 --- /dev/null +++ b/plugins/README.md @@ -0,0 +1,81 @@ +# aixplain Plugins + +Claude Code **plugins** for the [aixplain](https://aixplain.com) platform. + +A plugin bundles a [skill](../skills/README.md) together with the MCP servers it needs, so one install +gives your coding agent both the knowledge and the live connection. Where a skill teaches an agent how +to do something, a plugin also hands it the tools. + +--- + +## Available plugins + +| Plugin | Description | +|--------|-------------| +| [aixplain-marketplace](./aixplain-marketplace) | Search the aixplain marketplace from your editor — find agents, models, tools, and integrations in one call, read pricing and hosting, and get working code to call any asset via SDK, REST, or MCP. | + +--- + +## Install + +``` +/plugin marketplace add aixplain/aiXplain +``` + +Then install the plugin you want. Each plugin's README lists the environment variables it expects — +typically just an aixplain API key: + +```bash +export AIXPLAIN_API_KEY=your_api_key +``` + +Create a key at [studio.aixplain.com](https://studio.aixplain.com) under Settings → API Keys. + +--- + +## Plugin or skill? + +Both work. Pick by what you need: + +| | Skill alone | Plugin | +|---|---|---| +| Teaches the agent aixplain patterns | yes | yes | +| Connects live MCP servers | no — add them yourself | yes, bundled | +| Install | copy a folder to `~/.claude/skills/` | one command | + +A plugin's skill can always be lifted out and used on its own — copy its `skills//SKILL.md` to +`~/.claude/skills//SKILL.md` and configure the MCP server separately. Useful for clients that +read skills but not Claude Code plugins. + +--- + +## Layout + +``` +plugins// +├── .claude-plugin/plugin.json # manifest: name, description, author +├── .mcp.json # MCP servers, keys referenced as ${ENV_VAR} +├── README.md # what it does, install, what works +└── skills// + └── SKILL.md # the instructions the agent loads +``` + +`.mcp.json` must never contain a literal API key — reference an environment variable +(`"Authorization": "Bearer ${AIXPLAIN_API_KEY}"`) so nothing secret is committed. + +--- + +## Other MCP clients + +The MCP servers a plugin declares are client-agnostic and work in Cursor, VS Code, Codex, and Claude +Desktop. Only the plugin *packaging* is Claude Code specific. Each plugin's README documents the +equivalent config for other clients. + +--- + +## Contributing + +Add a folder under `plugins/`, following the layout above, and register it in the `plugins` array of +[`.claude-plugin/marketplace.json`](../.claude-plugin/marketplace.json) at the repo root. Verify every +documented call against a real run before committing it — a plugin that describes behavior the platform +does not have is worse than no plugin. diff --git a/plugins/aixplain-marketplace/.claude-plugin/plugin.json b/plugins/aixplain-marketplace/.claude-plugin/plugin.json new file mode 100644 index 00000000..3582a44d --- /dev/null +++ b/plugins/aixplain-marketplace/.claude-plugin/plugin.json @@ -0,0 +1,11 @@ +{ + "name": "aixplain-marketplace", + "description": "Search the aixplain marketplace from your editor — find agents, models, tools, and integrations across the whole catalog, read pricing and hosting, and get working code to call any asset via SDK, REST, or MCP.", + "version": "0.1.0", + "author": { + "name": "aixplain", + "url": "https://aixplain.com" + }, + "homepage": "https://studio.aixplain.com", + "keywords": ["aixplain", "marketplace", "search", "models", "agents", "mcp"] +} diff --git a/plugins/aixplain-marketplace/.mcp.json b/plugins/aixplain-marketplace/.mcp.json new file mode 100644 index 00000000..79d4f594 --- /dev/null +++ b/plugins/aixplain-marketplace/.mcp.json @@ -0,0 +1,10 @@ +{ + "aixplain-marketplace-search": { + "type": "http", + "url": "https://models-mcp.aixplain.com/mcp/6960f934f316da19e5f22494", + "headers": { + "Authorization": "Bearer ${AIXPLAIN_API_KEY}", + "Accept": "application/json, text/event-stream" + } + } +} diff --git a/plugins/aixplain-marketplace/README.md b/plugins/aixplain-marketplace/README.md new file mode 100644 index 00000000..6151a019 --- /dev/null +++ b/plugins/aixplain-marketplace/README.md @@ -0,0 +1,130 @@ +# aixplain Marketplace plugin + +Search the aixplain marketplace from inside Claude Code, and get working code back. + +Driven by the first-party Marketplace Search tool (`6960f934f316da19e5f22494`). A hosted equivalent — +the **Marketplace Concierge** agent — is published on the marketplace at +`aixplain/marketplace-concierge/aixplain` for anyone who would rather ask in Studio than in an editor. +Neither depends on the other. + +## Sharing this with someone + +**If they use Claude Code and you can send them files** — two steps, no repo access needed: + +1. Add the server: + ```bash + claude mcp add --transport http aixplain-marketplace-search \ + https://models-mcp.aixplain.com/mcp/6960f934f316da19e5f22494 \ + --header "Authorization: Bearer THEIR_API_KEY" + ``` +2. Send them `skills/marketplace-search/SKILL.md` to save at + `~/.claude/skills/marketplace-search/SKILL.md`. + +That is the whole thing. The plugin wrapper is a convenience for installing both at once — it is not +required, and the skill works standalone. + +**If they use Codex, Cursor, or another MCP client** — the server works anywhere; only the skill +packaging is Claude Code specific. See [Other clients](#other-clients) below. + +**As an installable plugin** — one command: + +``` +/plugin marketplace add aixplain/aiXplain +``` + +then install `aixplain-marketplace`. This also installs the `marketplace-search` skill and wires up the +MCP server in one step. + +## Other clients + +The MCP server is client-agnostic. The skill is not — `SKILL.md` is a Claude Code format. + +**Codex** (`~/.codex/config.toml`) — Codex supports remote HTTP MCP servers via a bare `url =`. For a +static auth header the reliable path is the `mcp-remote` stdio bridge: + +```toml +[mcp_servers.aixplain-marketplace-search] +command = "npx" +args = ["-y", "mcp-remote", "https://models-mcp.aixplain.com/mcp/6960f934f316da19e5f22494", "--header", "Authorization:${AUTH_HEADER}"] + +[mcp_servers.aixplain-marketplace-search.env] +AUTH_HEADER = "Bearer YOUR_API_KEY" +PATH = "/opt/homebrew/bin:/usr/bin:/bin" +``` + +To give Codex the same query knowledge, paste the body of `skills/marketplace-search/SKILL.md` into +`~/.codex/AGENTS.md`. + +**Claude Desktop and older clients** without native remote MCP use the same `mcp-remote` bridge in +JSON form — see the MCP config block inside the skill. + +## Install + +```bash +export AIXPLAIN_API_KEY=your_aixplain_api_key +``` + +Get a key from https://studio.aixplain.com under account settings, then add this plugin. The bundled +`.mcp.json` wires up the marketplace search MCP server with that key — no config editing. + +The server is PROD, so you are searching the live catalog. + +## What you get + +The `marketplace-search` skill, plus the MCP server it drives. Ask in plain language: + +``` +Do we have a Whisper model? Who hosts it and what does it cost? +How many LLMs are on aixplain? How many hosted by OpenAI? +Which integrations are developed by aixplain? +Find me a speech-to-text model and show me how to call it +Find a web search tool and attach it to a new agent +``` + +One `search` spans agents, models, tools, and integrations at once — you do not need to know the asset +type up front. + +## What works today + +Verified against PROD on 2026-08-18: + +| | | +|---|---| +| Search across agents, models, tools, integrations in one call | yes | +| Filter by category, developer, supplier, host, function, type | yes | +| Read pricing, host, supplier, status | yes | +| Read an asset's real input schema | yes | +| Emit SDK / REST / MCP / agent-attach code from that schema | yes | +| Run and test an asset via generated SDK code | yes | +| Sort results (cheapest, newest) | no — no sort parameter; sort locally after paging | +| Run an asset via the MCP `run_*` actions | no — broken, use generated code instead | + +## Beyond search + +The skill reads each asset's real input schema (`list_inputs_*`) before writing a snippet, so the code +it emits uses the asset's actual parameter names rather than placeholders. From a single hit it can +produce: + +- a Python SDK call +- an `aix.Agent(tools=[...])` block that attaches the asset to a new agent +- a REST call with the right endpoint for that asset type +- an MCP config block so another client can use that specific asset directly + +## Layout + +``` +plugins/aixplain-marketplace/ + .claude-plugin/plugin.json manifest + .mcp.json marketplace search server, ${AIXPLAIN_API_KEY} + skills/marketplace-search/ the skill +``` + +The skill is usable on its own: copy `skills/marketplace-search/SKILL.md` to +`~/.claude/skills/marketplace-search/SKILL.md` and add the MCP server separately. + +## Notes + +- Models and tools are individually available over hosted MCP; agents and integrations are not. +- Pricing comes back in two shapes — per-unit (`price` + `unit_type`) and per-token (`input_price` / + `output_price`). The skill reports whichever applies. +- The search MCP tool ID (`6960f934f316da19e5f22494`) is stable across environments. diff --git a/plugins/aixplain-marketplace/skills/marketplace-search/SKILL.md b/plugins/aixplain-marketplace/skills/marketplace-search/SKILL.md new file mode 100644 index 00000000..9d3f2f99 --- /dev/null +++ b/plugins/aixplain-marketplace/skills/marketplace-search/SKILL.md @@ -0,0 +1,216 @@ +--- +name: marketplace-search +description: Search the aixplain marketplace for agents, models, tools, and integrations — check whether an asset exists, what it costs, who hosts it, how many of a kind there are — and turn any hit into working code (SDK, REST, MCP config, or an agent that attaches it). Use whenever the user asks what is on aixplain, asks for a model/tool by name or capability, asks the price or host of an aixplain asset, or asks how to call or attach one. +--- + +# aixplain Marketplace Search + +Searches the aixplain catalog through the `aixplain-marketplace-search` MCP server, then hands back +something runnable. One `search` covers all four asset types at once — you never need to know whether +the thing you want is a model, a tool, an agent, or an integration. + +Every fact you report must come from a tool result. Never invent an asset, price, host, or count. +If every type returns `total: 0`, say the asset is not on the marketplace. + +## Setup check + +The tools are named `mcp__aixplain-marketplace-search__*`. If they are not available, the plugin's MCP +server has not connected — almost always a missing key. Tell the user: + +```bash +export AIXPLAIN_API_KEY=your_aixplain_api_key +``` + +Keys come from https://studio.aixplain.com under account settings. The server is PROD. + +## Which tool to call + +| Question | Call | +|---|---| +| Does X exist? What is it? | `search` with `query` | +| Price, host, supplier, status | `get_asset_details` with `asset_id` | +| How many X are there? | `search` with `query: ""` plus filters, read `stats.total` | +| What inputs does it take? | `list_inputs_models` / `list_inputs_tools` / `list_inputs_agents` / `list_inputs_integrations` | +| What actions does it have? | `list_actions_models` / `list_actions_tools` / … | +| What filter values are valid? | `list_filters` (no arguments) | + +`search` parameters are all flat strings or numbers — **not** arrays: `query`, `asset_type`, +`categories`, `developers`, `suppliers`, `hosts`, `function`, `num_results`, `page_number`, `page_size`. +`get_asset_details` takes `asset_id` (snake_case) and optionally `asset_type`. + +`search` returns one block per asset type, each `{results: [...], stats: {total, pages_count, current_page}}`. + +### The surface is only universal at discovery + +Of the 19 actions, three are universal — `search`, `get_asset_details`, `list_filters` — and sixteen are +per-type variants of `search_*`, `list_actions_*`, `list_inputs_*`, `run_*`. **There is no universal +`run`.** Do not look for one. Resolve the asset's type from the `search` block it came back in (or from +`get_asset_details.asset_type`), then use the matching per-type action. + +`get_asset_details` is the exception worth knowing: it takes `asset_id` alone, with `asset_type` +optional, so you can read any asset's details without knowing its type first. + +### Counting + +Pass an empty `query` as a wildcard and read `stats.total`. Add `page_size: 1` so you are not paying for +rows you will not read: + +``` +search(query: "", asset_type: "model", categories: "LLM", page_size: 1) → stats.total = 177 +``` + +Filter by `hosts` or `developers` the same way to narrow a count ("how many hosted by OpenAI"). + +There is **no sort parameter** — `search` orders by relevance only. To answer "cheapest", "newest", or +"most expensive" you must page through the filtered set and sort locally, which for a big category +(LLM alone is 177) means several calls. Say that is what you are doing rather than presenting a +single page's minimum as the catalog's minimum. +Do not count with `search_models` / `search_tools` / `search_agents` / `search_integrations` — those cap +results and carry no reliable total. Use them only to list examples. + +Valid `categories` (from `list_filters`): LLM, Productivity, Marketing, Finance & Accounting, Utility, +Sales, Customer Support, Communication, Cybersecurity, Developer Tools, Search, Speech, +E-commerce & Payments, Analytics, Data & Storage, Language, Miscellaneous, Media & Creative, +Development, Image, Classification, Video, OCR, Guardrails. Call `list_filters` for the current +developer/host/supplier lists rather than guessing a name. + +### Matching behavior + +Keyword matching is literal. If a multi-word phrase returns nothing, retry with one distinctive token +before concluding the asset is absent — "speaker diarization whisper" may miss where "whisper" hits. + +### Pricing has two shapes + +Report whichever the tool returned; do not normalize one into the other. + +- Per-unit assets: `{price, unit_type, unit_type_scale}` → "0.0018 per MINUTE" +- Token-priced LLMs: `{input_price, output_price}` → "0.000003 in / 0.000015 out per token" +- `null` or absent → say pricing is not listed. + +## Always finish the lookup + +When the user asks about cost, host, supplier, function, or status, call `get_asset_details` on the +best match in the same response as the `search`. Do not stop at `search` and do not ask permission to +look up details. If several assets match strongly, detail the most relevant and name the others. + +## Turning a hit into code + +Resolve the asset's `id`, `path`, and `asset_type` first. Then **call the matching `list_inputs_*` +tool** and build the snippet from the real input names it returns — `source_audio`, `text`, +`sourcelanguage`, whatever the asset actually declares. Only fall back to a `""` +placeholder if `list_inputs_*` returns nothing usable. Never invent a parameter name. + +Note which inputs are `required`, and which are `isFixed: true` with a single allowed value — a fixed +input should be emitted as that literal value, not as a choice for the user to fill in. Inputs with an +`availableOptions` list are enums: pick from it (language codes, for example) rather than free-texting. + +## Testing an asset before you wire it in + +**Do not use the `run_models` / `run_tools` / `run_agents` / `run_integrations` MCP actions.** They take +a single `input` string, which cannot express the multi-field input real assets declare, and they fail in +practice — verified 2026-08-18: an LLM returned `err.supplier_error` ("Input required: specify prompt or +messages") and a translation model returned HTTP 491, while the same asset ran fine through the SDK. + +To actually test an asset, write the SDK call from `list_inputs_*` and run it in the shell: + +```bash +python3 -c ' +from aixplain import Aixplain +aix = Aixplain(api_key="'"$AIXPLAIN_API_KEY"'") +r = aix.Model.get("").run() +print(r.status, r.data) +' +``` + +Report the real `status` and `data`. That closes the loop — found, verified running, then integrated — +and it is the only execution path that works today. + +### Python SDK + +`run()` takes the input names as **keyword arguments** — not a positional dict. Use the exact `name` +values from `list_inputs_*`: + +```python +from aixplain import Aixplain +aix = Aixplain(api_key="YOUR_API_KEY") + +# model — one kwarg per declared input (verified against Cloud Translation) +r = aix.Model.get("66aa869f6eb56342c26057e1").run( + text="Good morning", sourcelanguage="en", targetlanguage="ar") +print(r.status, r.data) # SUCCESS صباح الخير + +aix.Tool.get("").run(action="", data={...}) # tool +aix.Agent.get("").run(query="...") # agent +``` + +`Model.get("").run({...})` with a positional dict raises `TypeError` — always kwargs. +Read the result off `r.status` and `r.data`. + +`Model.get` / `Tool.get` also accept the supplier path (`"openai/whisper-large/groq"`), not just the id. +Integrations need a one-time connect (OAuth or API key) before they can run — point the user at the +integration's page rather than emitting a one-line call. + +### Attach it to an agent + +This is usually what the user actually wants after finding a tool: + +```python +from aixplain import Aixplain +aix = Aixplain(api_key="YOUR_API_KEY") + +agent = aix.Agent( + name="...", + description="...", + instructions="...", + tools=[aix.Tool.get("")], +).save() + +agent.run(query="...") +``` + +### REST + +Headers `x-api-key: YOUR_API_KEY` and `Content-Type: application/json`. + +- model: `POST https://models.aixplain.com/api/v2/execute/` — body from `list_inputs_models` +- tool: `POST https://models.aixplain.com/api/v2/execute/` — body `{"action": "", "data": {...}}` +- agent: `POST https://platform-api.aixplain.com/v2/agents//run` — body `{"query": "..."}` + +A response may return a `requestId` to poll: models and tools at +`GET https://models.aixplain.com/api/v2/data/`, agents at +`GET https://platform-api.aixplain.com/sdk/agents//result`. + +### MCP config for another asset + +Models and tools are each individually available over hosted MCP — agents and integrations are not. +Endpoint: `https://models-mcp.aixplain.com/mcp/` (encode `/` as `%2F`). + +Native streamable HTTP — Claude Code, VS Code, newer Cursor: + +```json +{"mcpServers": {"": { + "type": "http", + "url": "https://models-mcp.aixplain.com/mcp/", + "headers": {"Authorization": "Bearer YOUR_API_KEY", "Accept": "application/json, text/event-stream"} +}}} +``` + +stdio bridge — Claude Desktop and older clients without native remote MCP: + +```json +{"mcpServers": {"": { + "command": "npx", + "args": ["-y", "mcp-remote", "https://models-mcp.aixplain.com/mcp/", "--header", "Authorization:${AUTH_HEADER}"], + "env": {"AUTH_HEADER": "Bearer YOUR_API_KEY", "PATH": "/opt/homebrew/bin:/usr/bin:/bin"} +}}} +``` + +Pass the key via `env.AUTH_HEADER` and reference it as `Authorization:${AUTH_HEADER}` — a literal space +inside a single `mcp-remote` arg breaks it. On Apple Silicon `npx` is usually `/opt/homebrew/bin/npx`; +keep its directory on `PATH`. + +## Answering + +Lead with the direct answer — yes/no, or the number — then a short bulleted detail block: path, +function, price, host, supplier, status. When listing matches, give name plus path so the user can +identify the exact asset. Never paste raw tool JSON. diff --git a/skills/README.md b/skills/README.md index f7c9d02b..0443289d 100644 --- a/skills/README.md +++ b/skills/README.md @@ -32,6 +32,9 @@ The agent reads `SKILL.md` first and pulls in the reference files only when it n > More skills coming soon. See [Contributing](#contributing) to add one. +Looking for a one-command install that also wires up live MCP servers? See +[`plugins/`](../plugins/README.md) — a plugin bundles a skill together with the servers it needs. + --- ## Prerequisites