MCP and external AI tool integration

PolyApiIDE does not run a standalone MCP server. Instead, an external AI tool submits a collection patch through a simple REST API, the user sees it under "Incoming patches" inside the IDE, and decides whether to apply or reject it. Below: how to get access and what to send. Available on any paid plan (Month, Year, Lifetime).

How it works

There is no standalone MCP server. "Patches from an assistant" is a queue of JSON documents on polyapiclient.ru: an external tool submits a collection patch, the extension polls the queue and shows the user a diff card. Only the user applies or rejects the patch inside the IDE — an external tool cannot change the collection directly.

1. Get a client_id / client_secret

This is the same kind of technical API client the IDE itself uses for AI chats and backups — there is no separate website registration form for third-party tools (that's an anti-abuse measure on email verification).

Open PolyApiIDE → Settings → Integrations and click "Show integration credentials". Copy the client_id and client_secret — the secret is revealed on click, treat it like a password. The section only appears when the account has an active paid plan.

If the secret is compromised, re-run email verification in the extension — the server reissues a secret for the same client_id.

2. Authenticating requests

The official method for third-party tools is plain headers:

X-Client-Id: <client_id>
X-Client-Secret: <client_secret>

Send them over HTTPS only. Do not put client_id/client_secret in the request body or query string — the server rejects that (401 client_auth_plaintext_forbidden).

The PolyApiIDE extension itself uses a more locked-down sealed protocol (RSA-OAEP + AES, X-Client-Auth header) — third-party integrators don't need it and it isn't documented as a public API.

3. Endpoints

  • POST https://polyapiclient.ru/api/v1/collections/patches — create a patch. Body: {"payload": {...}, "source": "my-tool"}. Returns 201 with the patch object (id, status=pending).
  • GET https://polyapiclient.ru/api/v1/collections/patches?status=pending — check the status of previously submitted patches (pending/applied/rejected). Optional for a basic integration.

Only the IDE itself calls the acknowledge endpoint, after the user clicks Apply/Reject — an external tool never needs to call it.

4. Patch schema — polyapiide.collection-patch

The payload field:

{
  "type": "polyapiide.collection-patch",
  "version": 1,
  "base": { "collectionId": "col_example", "collectionName": "My collection" },
  "ops": [
    { "op": "setCollectionMeta", "fields": { "name": "...", "description": "..." } },
    { "op": "upsertRequest", "request": { "id": "req_1", "name": "Ping", "method": "GET",
        "folderPath": [], "url": { "raw": "https://api.example.com/ping", "query": [] },
        "headers": [ { "key": "Accept", "value": "application/json", "disabled": false } ] } },
    { "op": "removeRequest", "requestId": "req_old" },
    { "op": "patchRequest", "requestId": "req_1", "fields": { "name": "Ping (renamed)" } }
  ]
}

Valid op values: upsertRequest, removeRequest, patchRequest, setCollectionMeta. A patch with an empty ops[] or an unknown op is rejected with 422. Full working example — example-polyapiide-patch.json.

5. Limits

  • Patch size — up to 2 MiB (serialized JSON).
  • Operations per patch — up to 2000.
  • A patch stays queued for 7 days, then expires.
  • Up to 20 unprocessed patches queued per client at a time.

Over a limit, the server responds 422 with reason: payload_too_large, too_many_ops, or pending_limit.

6. Plan requirements

Available on any paid plan — Month, Year, or Lifetime (not Lifetime only). If the client_id has no active paid/demo license, any request to /collections/patches returns 403 feature_required.

7. Secrets inside a patch

The server heuristically scans the payload for likely secrets (tokens, passwords, keys) and flags the patch with contains_possible_secret — this is only a warning shown to the user in the IDE before applying; the request itself is never blocked.

Example: curl

curl -X POST https://polyapiclient.ru/api/v1/collections/patches \
  -H "X-Client-Id: $CLIENT_ID" \
  -H "X-Client-Secret: $CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d @example-polyapiide-patch.json

(the top-level field is the patch itself; the server also accepts the {"payload": {...}} wrapper.)

Example: Python

import os, json, urllib.request

def send_patch(payload: dict, source: str = "my-ai-tool") -> dict:
    body = json.dumps({"payload": payload, "source": source}).encode()
    req = urllib.request.Request(
        "https://polyapiclient.ru/api/v1/collections/patches",
        data=body,
        method="POST",
        headers={
            "X-Client-Id": os.environ["POLYAPIIDE_CLIENT_ID"],
            "X-Client-Secret": os.environ["POLYAPIIDE_CLIENT_SECRET"],
            "Content-Type": "application/json",
        },
    )
    with urllib.request.urlopen(req) as res:
        return json.load(res)

patch = {
    "type": "polyapiide.collection-patch",
    "version": 1,
    "base": {"collectionId": "col_example", "collectionName": "My collection"},
    "ops": [
        {"op": "upsertRequest", "request": {
            "id": "req_ping", "name": "Ping", "method": "GET",
            "folderPath": [], "url": {"raw": "https://api.example.com/ping", "query": []},
            "headers": [{"key": "Accept", "value": "application/json", "disabled": False}],
        }},
    ],
}
print(send_patch(patch))

Ready-to-run file — example-mcp-client.py.

Example: JavaScript (Node.js 18+ / browser)

Uses the built-in fetch — no dependencies. For Node < 18, add any fetch polyfill (e.g. node-fetch).

async function sendPatch(payload, source = "my-ai-tool") {
  const res = await fetch("https://polyapiclient.ru/api/v1/collections/patches", {
    method: "POST",
    headers: {
      "X-Client-Id": process.env.POLYAPIIDE_CLIENT_ID,
      "X-Client-Secret": process.env.POLYAPIIDE_CLIENT_SECRET,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ payload, source }),
  });
  return res.json();
}

const patch = {
  type: "polyapiide.collection-patch",
  version: 1,
  base: { collectionId: "col_example", collectionName: "My collection" },
  ops: [
    {
      op: "upsertRequest",
      request: {
        id: "req_ping",
        name: "Ping",
        method: "GET",
        folderPath: [],
        url: { raw: "https://api.example.com/ping", query: [] },
        headers: [{ key: "Accept", value: "application/json", disabled: false }],
      },
    },
  ],
};

sendPatch(patch).then((result) => console.log(result));

Check the status of previously submitted patches:

async function listPendingPatches() {
  const res = await fetch("https://polyapiclient.ru/api/v1/collections/patches?status=pending", {
    headers: {
      "X-Client-Id": process.env.POLYAPIIDE_CLIENT_ID,
      "X-Client-Secret": process.env.POLYAPIIDE_CLIENT_SECRET,
    },
  });
  return res.json();
}

Ready-to-run file — example-mcp-client.js.

8. Prompt for your AI agent

If you use an AI assistant with code execution or tool calling (for example, Claude with code execution, a custom agent, or any LLM with function calling) — paste this prompt once at the start of the conversation, then describe in plain words what you want added or changed in the collection. The agent will assemble the patch JSON itself and send it, using the curl/Python/JS examples above.

You are an assistant that keeps my request collection in PolyApiIDE
up to date through the collection-patch API.

Patch format — JSON:
{
  "type": "polyapiide.collection-patch",
  "version": 1,
  "base": { "collectionId": "<my collection>", "collectionName": "<name>" },
  "ops": [ ... ]
}

Allowed operations in ops[] (do not use any other type):
- upsertRequest — add or update a request:
  { "op": "upsertRequest", "request": { "id", "name", "method", "folderPath": [],
    "url": { "raw", "query": [] }, "headers": [ { "key", "value", "disabled" } ] } }
- removeRequest — delete a request: { "op": "removeRequest", "requestId": "..." }
- patchRequest — change specific fields of a request: { "op": "patchRequest", "requestId": "...", "fields": { ... } }
- setCollectionMeta — change the collection's name/description:
  { "op": "setCollectionMeta", "fields": { "name", "description" } }

Rules:
1. Use only these 4 operation types — never invent new ones.
2. A single patch is limited to 2000 operations and 2 MiB of JSON.
3. Before sending, show me the final patch JSON and wait for my confirmation.
4. Send the patch as a POST request to
   https://polyapiclient.ru/api/v1/collections/patches
   with body {"payload": <patch>, "source": "<your tool's name>"}
   and headers X-Client-Id / X-Client-Secret — I will provide their values
   separately; never fill them in yourself or print them in chat.
5. Nothing is applied in the IDE automatically: I will confirm or reject the
   patch myself under "Incoming patches" inside the extension.

Next, I'll describe what changed in the API and what should be added or fixed in the collection.

Avoid pasting the secret into the conversation text unless it's a secured code-execution environment: if your agent has access to environment variables (as in the curl/Python/JS examples above), put POLYAPIIDE_CLIENT_ID/POLYAPIIDE_CLIENT_SECRET there and ask the agent to read them from there.