> ## Documentation Index
> Fetch the complete documentation index at: https://docs.impellabs.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> A tool server the platform will talk to, in about ten minutes.

You will build an MCP server with one tool, connect it, and watch an assistant
call it.

## 1. Serve three methods

Any language. The transport is JSON-RPC 2.0 over `POST` to one URL.

<CodeGroup>
  ```python server.py theme={null}
  from fastapi import FastAPI, Request

  app = FastAPI()

  TOOLS = [{
      "name": "search_products",
      "description": "Look up a design by its design ID and return price and stock.",
      "inputSchema": {
          "type": "object",
          "properties": {"query": {"type": "string", "description": "Design ID, e.g. MC2045"}},
          "required": ["query"],
      },
  }]

  @app.post("/mcp")
  async def mcp(request: Request):
      body = await request.json()
      method, rid = body.get("method"), body.get("id")

      if method == "initialize":
          result = {
              "protocolVersion": "2025-06-18",
              "serverInfo": {"name": "acme-commerce", "version": "1.0"},
              "capabilities": {"tools": {}},
          }
      elif method == "tools/list":
          result = {"tools": TOOLS}
      elif method == "tools/call":
          params = body.get("params") or {}
          # Authenticate: the token identifies WHICH workspace is calling.
          # tenant = tenant_for(request.headers.get("authorization"))
          query = (params.get("arguments") or {}).get("query", "")
          result = {"content": [{"type": "text",
                                 "text": f"{query}: georgette, 5 colours, Rs 1,450"}]}
      else:
          return {"jsonrpc": "2.0", "id": rid, "result": {}}

      return {"jsonrpc": "2.0", "id": rid, "result": result}
  ```

  ```typescript server.ts theme={null}
  import express from "express";

  const app = express();
  app.use(express.json());

  const TOOLS = [{
    name: "search_products",
    description: "Look up a design by its design ID and return price and stock.",
    inputSchema: {
      type: "object",
      properties: { query: { type: "string", description: "Design ID, e.g. MC2045" } },
      required: ["query"],
    },
  }];

  app.post("/mcp", (req, res) => {
    const { method, id, params } = req.body;
    let result: unknown = {};

    if (method === "initialize") {
      result = {
        protocolVersion: "2025-06-18",
        serverInfo: { name: "acme-commerce", version: "1.0" },
        capabilities: { tools: {} },
      };
    } else if (method === "tools/list") {
      result = { tools: TOOLS };
    } else if (method === "tools/call") {
      // const tenant = tenantFor(req.headers.authorization);
      const query = params?.arguments?.query ?? "";
      result = { content: [{ type: "text", text: `${query}: georgette, 5 colours, Rs 1,450` }] };
    }

    res.json({ jsonrpc: "2.0", id, result });
  });
  ```
</CodeGroup>

<Note>
  Notifications (`notifications/initialized`) arrive with no `id` and expect
  no result. Answer `202` and move on.
</Note>

## 2. Get the host allowlisted

The platform refuses any host that is not on `MCP_ALLOWED_HOSTS`. This is not
configurable per workspace — it is a platform setting, and an empty list
denies everything.

Send us the hostname before you try to connect.

## 3. Connect it

In the ops console, **Tool servers → Connect a server**:

<ParamField path="company" type="string" required>
  Workspace slug this server serves.
</ParamField>

<ParamField path="label" type="string" required>
  Shown to operators, e.g. `Acme Commerce`.
</ParamField>

<ParamField path="url" type="string" required>
  Your MCP endpoint, e.g. `https://acme.example.com/mcp`.
</ParamField>

<ParamField path="auth_token" type="string">
  Minted by you, sent as `Authorization: Bearer …` on every request. Write-only
  once stored.
</ParamField>

Press **Re-discover**. Your tools appear.

## 4. Switch it on — twice

<Steps>
  <Step title="An operator enables the tool">
    Discovered tools arrive **disabled**. Connecting a server never silently
    grants an assistant a new ability.
  </Step>

  <Step title="The customer enables the capability">
    On the assistant, **Connected tools** must be on. Both gates are
    required; neither implies the other.
  </Step>
</Steps>

## 5. Watch it get called

Message the assistant on WhatsApp with something your tool answers. The turn
debugger shows every tool called and whether it succeeded.

<Check>
  If the tool is never called, check the two gates above before you look at
  your server. That is the usual answer.
</Check>

## Next

<CardGroup cols={2}>
  <Card title="Tool contract" icon="wrench" href="/mcp/tool-contract">
    Naming rules and the schema subset we accept.
  </Card>

  <Card title="Side effects" icon="rotate" href="/mcp/side-effects">
    What happens when the model retries a call that spends money.
  </Card>
</CardGroup>
