# How clients are named Source: https://docs.alpic.ai/analytics/clients How Alpic groups the MCP clients that connect to your server, and what the Unnamed client row means. Every chart in Analytics can be split by client. The client name comes from the MCP handshake: when a client connects, it announces itself with a name of its own choosing. Nobody standardizes those names, so Alpic maps them to a canonical list before showing them to you. ### Why the raw names need mapping Three things happen with raw client names, and all three make a breakdown harder to read than it needs to be. * **Vendors rename their clients.** Claude.ai used to announce itself as `claude-ai` and now sends `Anthropic/ClaudeAI`. Codex moved from `codex-mcp-client` to `openai-mcp (Codex)`, and that switch is still in progress, so its traffic is split across both names right now. Older builds keep sending the old name for months, so without mapping the same product shows up as two rows forever. * **Proxies add their own version to the name.** A client reached through `mcp-remote` announces itself as `claude-code (via mcp-remote 0.1.37)`, so one client turns into one row per release of the proxy. * **Clients that never set a name still send one.** The Python MCP SDK defaults `clientInfo.name` to `mcp`, so a large share of traffic arrives under a name that means nothing. ### What Alpic does Alpic keeps a list of the clients it recognizes and folds every name a vendor has shipped for the same product into one row. `claude-ai` and `Anthropic/ClaudeAI` both count as **Claude**. `codex-mcp-client` and `openai-mcp (Codex)` both count as **Codex**. Proxy versions are stripped before the lookup, so all `mcp-remote` variants of a client land on that client. Surfaces stay separate. Claude Code, Claude, Claude Cowork and the Anthropic API each get their own row under the same vendor logo, and so do ChatGPT, Codex and the Responses API under OpenAI's. They are different ways of using your server, so you probably want to tell them apart. A name Alpic does not recognize is left alone. It gets its own row, spelled exactly as it was received, without a logo. Alpic will not guess at what it is, and neither should you read too much into it: on a private server these are usually your own agents, scripts and uptime probes, but on a public server anyone can connect under any name they like. One row deserves an explanation: **Unnamed client** is traffic that sent no name at all, so all Alpic received was the SDK default. There is nothing more to say about it, it could be any client or script. ### What to keep in mind when reading the breakdown * **The client breakdown counts connections, not engagement.** A session is one MCP handshake, and every client reconnects on its own schedule. Claude Code handshakes when a conversation starts and again whenever it considers what it knows about your server stale, whether or not it ends up calling a tool, so it racks up handshakes with very few tool calls behind them. A client like the Alpic Playground is the other way round, several tool calls per handshake. A tall bar means a client connects a lot, not that people are using your server through it a lot. Look at tool calls for that. * **OpenAI surfaces cannot always be told apart.** Every OpenAI surface used the same `openai-mcp` name before they started adding a suffix, so ChatGPT, the Responses API and Agent Builder are mixed together in the **OpenAI Other** row. A number labelled ChatGPT is therefore a floor, not a total. Vendor-level OpenAI totals are reliable. * **Client names are self-reported.** Anything can claim any name in the handshake. Alpic shows the mapped name for readability and nothing more: it is never used to authenticate or authorize a request, and the vendor logos are decoration, not verification. * **Raw names are always available.** Filtering and the session list use the exact name received, so you can still search for `claude-ai` or your own agent name and find those sessions. # Custom Events Source: https://docs.alpic.ai/analytics/custom-events Record your own events and user traits from inside your MCP server's tool handlers. ### Overview Alpic tracks every tool call automatically, but only your server knows what happened inside one: which backend was hit, how many results came back, whether a payment went through. Custom events let you record those moments from inside your tool handlers. Each event is attached to the current session, interleaved with the tool calls on its timeline. You can also attach traits to the user behind the request (an email, a name, a plan) with `identify`. Events are buffered while your handler runs and shipped through private metadata configured by the Alpic runtime, so there is no extra network call. Alpic ingests and strips them at the proxy before the response reaches the MCP client. Outside Alpic, no analytics metadata is added to the response. To capture what happens in the UI your tools render, see [View events](/analytics/view-events). ### 1. Install the package ```bash theme={null} pnpm add @alpic-ai/insights ``` ### 2. Wire it into your server The package ships two entry points depending on which MCP framework you're using. Use `analyticsMiddleware`: it returns a Skybridge `McpMiddlewareFn` you register via `mcpMiddleware()`. Add it before your tool/widget registrations: ```typescript theme={null} import { analyticsMiddleware } from "@alpic-ai/insights"; import { McpServer } from "skybridge/server"; const server = new McpServer({ name: "my-mcp-server", version: "1.0.0" }, { capabilities: {} }) .mcpMiddleware(analyticsMiddleware()) .registerTool(/* ... */); ``` Use `track`, it accepts an `McpServer` (or a low-level `Server`) and patches the `tools/call` handlers in place. It can be called before or after your tools are registered: ```typescript theme={null} import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { track } from "@alpic-ai/insights"; const server = new McpServer( { name: "my-mcp-server", version: "1.0.0" }, { capabilities: {} }, ); server.registerTool(/* ... */); track(server); ``` ### 3. Capture events from your tool handlers Once wired in, every tool handler receives an `analytics` object on its `extra` argument. Cast `extra` with the exported `AnalyticsExtra` type to get typed access: ```typescript theme={null} import type { AnalyticsExtra } from "@alpic-ai/insights"; server.registerTool("search_flights", {/* ... */}, async ({ from, to }, extra) => { const { analytics } = extra as unknown as AnalyticsExtra; const startedAt = performance.now(); const flights = await flightApi.search(from, to); analytics.capture("flights_searched", { duration: performance.now() - startedAt, properties: { from, to, resultCount: flights.length }, }); return { content: [/* ... */] }; }); ``` `capture(name, options)` takes the event name plus optional details: | Option | Type | Description | | ------------ | ------------------------- | -------------------------------------------------------------------------------------- | | `message` | `string` | A human-readable line shown with the event. Max 500 characters. | | `duration` | `number` | How long the operation took, in milliseconds. Fractional values are fine. | | `properties` | `Record` | Freeform structured detail. Max 8 KB serialized. | | `isError` | `boolean` | Marks the event as an error on the timeline. | | `error` | `string` | An error description. Setting it also marks the event as an error. Max 500 characters. | ### 4. Identify the user `identify` attaches string traits to the user making the current request. Alpic resolves who that is from the request's auth context (see how users are counted), so you don't pass any id: ```typescript theme={null} analytics.identify({ email: user.email, plan: user.plan, }); ``` Each `identify` call is a complete snapshot. Calling it several times in one request keeps only the last snapshot, and the next request's call replaces the traits stored for that user. After Alpic has observed user-unique traits, choose one under **Project settings → Privacy → Primary user identity**. That environment-wide choice is shown as the main user label in analytics while Alpic keeps the stable internal user ID for grouping and navigation. Traits are user data. They are only stored on a paid plan with **Collect user data** enabled for the environment, like the rest of the privacy settings . On the Free plan or with the setting off, `identify` calls are dropped. ### 5. Deploy Deploy on Alpic as usual. Once the new version is live, events captured by your handlers start flowing into your project's analytics. ### Run locally or on another host Pass a handler to receive each request's analytics batch yourself. The same option works with `analyticsMiddleware`: ```typescript theme={null} track(server, { handler: async ({ events, traits }) => { await myAnalytics.write({ events, traits }); }, }); ``` The handler also runs on Alpic, in addition to dashboard ingestion. Handler failures are logged and never fail the tool call. ### Good to know * Only `tools/call` requests carry an `analytics` object; other request types pass through untouched. * Call `capture` and `identify` before your handler returns. Calls made after the response is sent (for example from a detached promise) are dropped, with a warning outside production. * At most 50 events are kept per tool call; extra ones are dropped. * Event names are capped at 200 characters. * Event timestamps are set when `capture` is called. Timestamps more than 24 hours old, or in the future, are replaced by the time Alpic received the event. * The middleware never throws into your handler: if analytics can't be attached, your tool result is returned as-is. # Metric definitions Source: https://docs.alpic.ai/analytics/metrics Exactly what each analytics metric measures. Every metric on the analytics dashboard is computed from the MCP requests Alpic records as they reach your server. This page defines each one precisely, so you always know what you are looking at. ### Sessions and conversations Two concepts matter before reading any session number, because they are easy to confuse: **A session is an MCP protocol session.** When an MCP client connects to your server, it sends an initialize request that starts a new session. This handshake announces the client's name and capabilities, which is how Alpic knows whether traffic comes from ChatGPT, Claude, Cursor, or another client. The session then carries every request from that client until the connection ends or expires. **A conversation is a chat thread in the end user's client.** The MCP protocol itself has no notion of a conversation: your server never sees the chat. Some clients choose to share a conversation identifier with each request. Today only ChatGPT does this, so for ChatGPT traffic Alpic knows which chat thread each session belongs to. The two do not map one to one. A single conversation can create several MCP sessions: clients reconnect, users return to an older chat, sessions expire and new ones open. This is normal protocol behavior, not a sign of anything wrong. | | ChatGPT | Other clients (Claude, Cursor, ...) | | --------------------------------- | ------- | ----------------------------------- | | MCP session | Yes | Yes | | Conversation identifier | Yes | No | | Sessions grouped per conversation | Yes | No, each session stands alone | How it's measured: * The **Sessions** metric counts `initialize` requests received from recognized MCP clients over the selected period. Think of it as how many times your app was opened or reconnected to. See [How clients are named](/analytics/clients) for how each client is identified in the breakdowns. * Session-level metrics (**Sessions with errors** and **Session error rate**) group by conversation when the client provides one, and by MCP session otherwise. For ChatGPT traffic this means a conversation counts once, even if it opened several sessions along the way. Because one conversation can span several sessions, the Sessions count for ChatGPT traffic can be higher than the number of actual conversations. That gap is expected. ### Requests A request is any MCP request received by your server: tool calls, but also protocol traffic such as `initialize`, `tools/list`, `prompts/get`, or `resources/read`. Request charts can be scoped to tool calls only, to protocol requests only (excluding 'initialize'), or to everything. Protocol requests don't necessarily reflect active usage. MCP clients send them frequently just by being configured to connect to your server, so look at tool calls when you want to measure real engagement. ### Tool calls The number of `tools/call` requests received. This is the best proxy for actual usage of your server: each tool call means an LLM decided to use one of your tools. The tool performance table breaks this down per tool, with: * **Requests**: the number of calls to that tool * **p50 / p95 latency**: median and 95th percentile response time * **Success rate**: the share of calls that completed without any error ### Users The number of distinct identified people who used your server over the period. This metric has enough subtlety to deserve its own page: see How users are counted. ### Output tokens An estimate of how many tokens your server's responses add to the LLM's context window, shown as an average per call. Alpic estimates the token equivalent of each response part that gets passed to the model: tool call results, tool lists and descriptions, prompt contents, resource contents, and server instructions sent during `initialize`. Use this to spot tools that flood the context window with oversized responses. These are estimates of context usage, not billed tokens from any LLM provider. ### Latency The time between a request reaching Alpic and your server's response, measured at the platform level. Charts show p50, p95, and p99 percentiles rather than averages, so slow outliers stay visible. ### Errors Alpic separates two kinds of errors, because they mean very different things: * **Tool errors**: a tool call returned a result with `isError` set to true. These are common and by design: the error is passed back to the LLM so it can recover, retry, or rephrase. A baseline of tool errors is normal. If you want to design recoverable errors well, check out this article. * **MCP errors**: protocol-level errors that are not passed to the LLM and usually surface as error messages in the user's client. These deserve your attention. Check your logs if you see a spike. MCP errors are further classified by type: | Type | Meaning | | ------------ | --------------------------------------------------- | | Timeout | The request timed out before your server answered | | Missing tool | The client called a tool your server doesn't expose | | Protocol | Malformed or invalid request | | Connection | The connection to your server failed | | Server error | Your server returned an unexpected error | Protocol implementation quality varies across MCP clients and can generate more errors than expected. For instance, Claude requests the list of resources and prompts even when your server doesn't advertise any, which produces MCP errors you can safely ignore. ### Session error rate The share of sessions that contained at least one error, whether a tool error or an MCP error. As explained [above](#sessions-and-conversations), sessions are grouped by conversation when the client provides one. This is a good health metric to watch over time: a rising session error rate means a growing share of your users are hitting problems. # Overview Source: https://docs.alpic.ai/analytics/overview Understand how your MCP server is used, out of the box. ### Overview Alpic Analytics gives you a complete picture of how your MCP server is used: how many sessions and users you have, which tools are called, how fast they respond, and where errors happen. There is nothing to install. Alpic sits in front of your MCP server and records every MCP request as it passes through: the method called, the MCP client, the response time, the outcome, and the user identity when one is available. Your code stays untouched and no SDK is required. Analytics are collected separately for each environment. The dashboard defaults to your production environment; use the environment picker to switch. ### Key indicators Analytics overview Analytics overview The top of the dashboard shows five key indicators for the selected period, each compared to the previous period of the same length: * **Sessions**: how many times your app was opened * **Tool calls**: how many `tools/call` requests users, agents and an LLM intentionally invoked * **Users**: how many distinct identified people used your server * **Sessions with errors**: how many sessions contained at least one error * **Session error rate**: the share of sessions that contained an error Every metric has a precise definition. See [Metric definitions](/analytics/metrics) for exactly what each one measures, and [How users are counted](/analytics/unique-users) for the full story on user identification. ### Sessions Sessions section Sessions section The sessions chart shows sessions over time, broken down per MCP client (ChatGPT, Claude, Cursor, and so on). Below it, a daily activity calendar shows when your app is used over the past year, switchable between request volume, latency, and errors, so you can spot usage patterns and growth at a glance. ### Users Users section Users section The users chart shows unique users over time, broken down per MCP client. When your server has identified users, a Top users card ranks the most active ones. ### Tools Tools section Tools section The tool performance table lists every tool with its request count, p50 and p95 latency, and success rate. Select one or more tools to focus the charts below on them: * **Requests** over time * **Latency** over time (p50, p95, p99) * **Tokens** per call Each chart can be scoped to tool calls only, to protocol requests only (tools/list, prompts/get, and resources/read; excluding 'initialize' requests), or to everything (including `initialize` requests). ### Reliability Reliability section Reliability section The reliability section tracks errors over time, split between tool errors and MCP errors, with breakdowns by tool and by error type. See [Metric definitions](/analytics/metrics#errors) for what each error type means. ### Time ranges and granularity You can view analytics over the last day, week, month, or year, or pick a custom date range. Chart granularity adjusts automatically to the range you select, from 5 minute buckets on short ranges up to daily buckets on long ones. How far back you can look depends on your plan's analytics retention, from 7 days on the Free plan to unlimited on Enterprise. Time ranges beyond your retention appear locked in the picker. See [Plans](/pricing/plans) for details. ### Go further Exactly what each metric measures Identity sources and unique user counting Control what data is collected # Privacy & Data Collection Source: https://docs.alpic.ai/analytics/privacy Control what data Alpic collects about your MCP server's traffic. Alpic is conservative by default: analytics work out of the box on metadata alone, and anything that could contain end-user content is opt-in. ### What is collected by default For every MCP request, Alpic records metadata only: * The method and tool name called * The MCP client name (ChatGPT, Claude, Cursor, ...) * Timestamp, response time, and estimated output tokens * The error type and code, if the request failed * A user identity when one can be resolved, stored as a hash for keys and tokens (see How users are counted) What is never collected, on any plan: * **IP addresses** * **Raw API keys or tokens**, only hashes are stored * **Request or response contents**, unless you explicitly enable payload collection below ### Data collection settings Privacy settings Privacy settings Data collection is configured in **Project Settings → Privacy**, separately for each environment. This lets you, for example, collect payloads on staging while keeping production metadata-only. | Setting | Default | What it does | | ----------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Session replay** | Off | Captures sessions so they can be replayed. Required before payload collection can be enabled. | | **Collect request payloads** | Off | Stores request bodies so they can be inspected in session replay. | | **Collect response payloads** | Off | Stores response bodies so they can be inspected in session replay. | | **Collect error messages** | On | Stores error messages alongside analytics events. May echo end-user input. | | **Collect user data** | Off | Stores the authenticated end user's email (from their OIDC token, when present), so sessions show who made each request, plus the coarse location ChatGPT reports alongside the call. | All of these settings require a paid plan. On the Free plan they appear locked, and nothing beyond metadata is ever stored, including error messages. Payloads and error messages may contain end-user PII. You are responsible for what your server puts in them. Review your obligations in our Privacy Policy before enabling collection. A few practical notes: * The coarse location is only what ChatGPT itself sends with the call: country, city, and coordinates rounded to two decimals (about 1.1 km). It is never derived from the caller's IP address, and calls from other MCP clients carry no location at all. * Payloads are collected only for `tools/call`, `prompts/get`, and `resources/read` requests, and only while both the corresponding toggle and session replay are enabled. * Payloads larger than 256 KB are skipped. * Collected data follows your plan's analytics retention. # How users are counted Source: https://docs.alpic.ai/analytics/unique-users Exactly how Alpic identifies unique users of your MCP server. The **Users** metric counts distinct identified people. Each identity is counted once over the selected period, no matter how many sessions it opened or requests it made. This page explains where identities come from, so you can trust the number and know its limits. ### Where identity comes from On every request, Alpic tries to resolve who is calling. Four identity sources exist, checked in this order, and the first one that applies wins: 1. **OAuth identity**: if your server uses OAuth authentication, the user is identified by the subject of their access token. This is the strongest signal: one entry per authenticated person. 2. **Client-provided subject**: ChatGPT attaches a stable, anonymized identifier for the end user to each request. Alpic uses it when no OAuth identity is present, so ChatGPT users are counted individually even without OAuth. 3. **API key**: for requests authenticated with an `x-api-key` header, the identity is a SHA-256 hash of the key. The dashboard shows a short fingerprint of it, never the key itself. 4. **Bearer token**: for opaque bearer tokens that carry no user subject, the identity is a hash of the token. If none of these apply, the request is **anonymous**. ### What this means in practice * **Anonymous traffic is never counted as users.** Alpic does not guess identities from IP addresses, does not fingerprint clients, and does not create synthetic anonymous users. In fact, Alpic never collects IP addresses at all. This is why you won’t see anonymous users from Claude, Cursor, or other clients that do not provide a subject identifier - currently, only ChatGPT provides one. If your Users number looks low compared to Sessions, it usually means most of your traffic is unauthenticated. * **A shared credential counts as one user.** An API key or token used by a whole team appears as a single user, since Alpic has no way to tell the individuals apart. * **Raw credentials are never stored.** API keys and tokens are hashed before anything is written; only the hash is kept. * **Large counts are approximate.** Beyond tens of thousands of users, counts use an approximation algorithm and are displayed with a `~` prefix. The error margin is well under 1%. * **User metrics have a start date.** Unique users, session error rate, and the session list are new metrics that can't be reconstructed from older data. Charts show a "Tracking started" marker; there is no user data before it. ### Getting accurate user counts The quality of your Users metric follows directly from how your server authenticates: * **OAuth** gives you the most accurate picture: every user is counted individually, on every client. See OAuth authentication to set it up. * **ChatGPT traffic** is counted per user even without OAuth, thanks to the client-provided subject. * **API keys and bearer tokens** count credentials, not people. Fine if each key belongs to one person, misleading if keys are shared. * **No authentication** means no user counting at all. # View Events Source: https://docs.alpic.ai/analytics/view-events Capture events from inside your MCP App or ChatGPT App view with the React provider. ### Overview [Custom events](/analytics/custom-events) let your server record what happens inside a tool call. View events are the other half: they capture what happens in the UI your tools render, the [MCP App / ChatGPT App view](https://modelcontextprotocol.io/extensions/apps/overview) shown in the client. The `@alpic-ai/insights/react` provider captures a baseline of view activity on its own, and lets you record your own events with a hook. Both land on the same session timeline as your server-side events, so a session reads end to end: the tool call that opened the view, what the user did in it, and any error along the way. There are no keys to configure. The provider discovers where to send events from the metadata Alpic stamps onto each tool result, and ships them best-effort, so a delivery failure never affects the host view. ### 1. Install the package ```bash theme={null} pnpm add @alpic-ai/insights ``` The React entry point is shipped under `@alpic-ai/insights/react`. It expects `react` as a peer dependency, which your view already has. ### 2. Wrap your view Render `AlpicAnalytics` once at the root of your view, above everything that captures events: ```tsx theme={null} import { AlpicAnalytics } from "@alpic-ai/insights/react"; import { createRoot } from "react-dom/client"; import { App } from "./App"; createRoot(document.getElementById("root")!).render( , ); ``` That is all the setup required. Events captured before the ingest endpoint is known are buffered and flushed automatically once it arrives. ### 3. Capture events Call `useAnalytics()` from any component under the provider and use `capture` to record an event: ```tsx theme={null} import { useAnalytics } from "@alpic-ai/insights/react"; function BookButton({ from, to }: { from: string; to: string }) { const analytics = useAnalytics(); return ( ); } ``` `capture(name, options)` takes the event name plus optional details: | Option | Type | Description | | ------------ | ------------------------- | -------------------------------------------------------------------------------------- | | `message` | `string` | A human-readable line shown with the event. Max 500 characters. | | `duration` | `number` | How long the operation took, in milliseconds. Fractional values are fine. | | `properties` | `Record` | Freeform structured detail. Max 8 KB serialized. | | `isError` | `boolean` | Marks the event as an error on the timeline. | | `error` | `string` | An error description. Setting it also marks the event as an error. Max 500 characters. | Event names starting with `$` are reserved for the events the SDK captures itself (see below). Use plain names for your own events. ### Auto-captured events The provider captures a baseline of activity without any `capture` calls. Each surface is gated by the `autoCapture` prop: | Surface | Default | Events | | -------------- | ------- | ------------------------------------------------------------------------------------------------------------ | | `lifecycle` | On | `$loaded` when the view mounts, `$visible` / `$hidden` as it is shown or hidden, `$closed` when it goes away | | `errors` | On | `$error` for every uncaught error and unhandled promise rejection, with the message, stack, and source | | `interactions` | Off | A click event for any element carrying a `data-alpic-event` attribute (see below) | Toggle any surface with the prop. Lifecycle and errors are on by default; interactions are opt-in: ```tsx theme={null} ``` #### Declarative interaction capture With `interactions` enabled, add `data-alpic-event` to any element to capture its clicks. The attribute value is the event name; every other `data-alpic-*` attribute becomes a string property: ```tsx theme={null} ``` A click on that button captures `cta_clicked` with `{ plan: "pro" }`. Capture is delegated from a single `document` listener and resolves the nearest matching ancestor, so it works for elements added after mount. ### Transform or drop events with `beforeSend` Pass `beforeSend` to inspect, rewrite, or drop each event before it is buffered. Return the event to keep it, a modified event to change it, or `null` to drop it. It runs synchronously for every event, whether captured by you or by auto-capture: ```tsx theme={null} { if (!hasConsent) { return null; } return { ...event, properties: { ...event.properties, appVersion } }; }} > ``` `beforeSend` is read live on every event, so deriving it from state (a consent flag, say) takes effect without remounting the provider. ### Good to know * The provider is client-only: it discovers the ingest endpoint from the tool-result metadata and needs no API key. * Delivery is best-effort. Failures are swallowed so analytics never affects the view; events are flushed when the view is hidden or unloaded, and on a short interval otherwise. * At most 100 events are buffered at a time; once full, further events are dropped with a single console warning. * View events follow the same [privacy settings](/analytics/privacy) and [plan retention](/pricing/plans) as the rest of your analytics. Do not put end-user PII in event names or properties unless you intend to collect it. # Using the REST API Source: https://docs.alpic.ai/api-reference Learn how to use Alpic's REST API to programmatically manage your MCP servers, teams, and projects ## Who is this API for? Alpic's REST API is designed for developers who want to automate deployment workflows and manage MCP server projects programmatically. The API supports: * **Teams** — list teams available to the authenticated user * **Projects** — create, list, retrieve, update, and delete MCP server projects * **Environments** — create and retrieve environments, deploy them, and fetch runtime logs * **Environment Variables** — list, add, update, and delete environment variables per environment * **Deployments** — upload artifacts, list deployments, inspect deployment details, and retrieve deployment logs * **Analytics and Tunnels** — fetch project analytics and generate tunnel tickets * **Distribution** — publish to the MCP Registry ([Publishing docs](/distribution/publishing)) * **Beacon** — check a MCP server readiness for chatGPT and Claude Use the API to integrate Alpic into your development workflow, automate deployments, and operate your MCP servers end to end. ## Getting Started ### Get Your API Key To use the REST API, you'll need an API key. Here's how to get one: Navigate to [https://app.alpic.ai](https://app.alpic.ai) and sign in to your account. Click on your team name in the top left corner of the screen, then select the **API Keys** tab on the left sidebar. Click **New API key** and give it a name (e.g., "CI/CD Pipeline"). Copy the API key immediately—you won't be able to see it again. Store it securely in your environment variables or secrets manager. Keep your API keys secure and never commit them to version control. Treat them like passwords—if exposed, revoke them immediately and generate new ones. ## Alpic teams structure Understanding the hierarchy of Alpic's resources is important when working with the API: * **API Key**: Each API key is associated with a specific team. The API key grants access to resources within that team. * **Team**: A team can contain multiple projects and is the top-level organizational unit. * **Project**: Each project represents an MCP server and can have multiple environments. * **Environment**: Environments represent different deployment environments (e.g., production, staging, development) for your MCP server, linked to a specific branch of your git repository. Learn more about [environments here](/build-deploy/environments). ```mermaid theme={null} flowchart LR A[API Key] <--> B[Team] B --> C1[Project 1] B --> C2[Project N] C1 --> D1[Env: production] C1 --> D2[Env: staging] C2 --> D3[Env: production] C2 --> D4[Env: dev] ``` When making API requests, you'll work with resources at the project and environment levels, all scoped to the team associated with your API key. ## Authentication All API requests require authentication using your API key. Include it in the `Authorization` header as a Bearer token: ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` ## Base URL All API requests should be made to: ``` https://api.alpic.ai ``` ## API Versioning The API uses versioning in the URL path. The current version is `v1`, so all endpoints are prefixed with `/v1/`. Example: ``` https://api.alpic.ai/v1/projects ``` ## Response Format All API responses are returned in JSON format. Successful responses use standard HTTP status codes (200, 201, etc.), while errors return appropriate error codes (400, 401, 404, 500, etc.) with error details in the response body. # Get project analytics Source: https://docs.alpic.ai/api-reference/analytics/get-project-analytics https://api.alpic.ai/openapi.json get /v1/analytics/{projectId} Get analytics data for a project over a time range # Create a beacon audit Source: https://docs.alpic.ai/api-reference/beacon/create-a-beacon-audit https://api.alpic.ai/openapi.json post /v1/beacon/audits Audit an MCP server for spec compliance and AI client compatibility # Get a beacon audit Source: https://docs.alpic.ai/api-reference/beacon/get-a-beacon-audit https://api.alpic.ai/openapi.json get /v1/beacon/audits/{auditId} Get a beacon audit by ID, including the report if completed # Get a deployment Source: https://docs.alpic.ai/api-reference/deployments/get-a-deployment https://api.alpic.ai/openapi.json get /v1/deployments/{deploymentId} Get a deployment by ID # Get deployment logs Source: https://docs.alpic.ai/api-reference/deployments/get-deployment-logs https://api.alpic.ai/openapi.json get /v1/deployments/{deploymentId}/logs Get the logs for a deployment # List project deployments Source: https://docs.alpic.ai/api-reference/deployments/list-project-deployments https://api.alpic.ai/openapi.json get /v1/projects/{projectId}/deployments List all deployments for a project # Get server info Source: https://docs.alpic.ai/api-reference/distribution/get-server-info https://api.alpic.ai/openapi.json get /v1/distribution/get Get info about a server # Publish a server to the MCP registry Source: https://docs.alpic.ai/api-reference/distribution/publish-a-server-to-the-mcp-registry https://api.alpic.ai/openapi.json post /v1/distribution/publish # Add environment variables Source: https://docs.alpic.ai/api-reference/environments/add-environment-variables https://api.alpic.ai/openapi.json post /v1/environments/{environmentId}/environment-variables Add one or more environment variables to an environment # Create an environment Source: https://docs.alpic.ai/api-reference/environments/create-an-environment https://api.alpic.ai/openapi.json post /v1/environments Create an environment for a project # Delete an environment variable Source: https://docs.alpic.ai/api-reference/environments/delete-an-environment-variable https://api.alpic.ai/openapi.json delete /v1/environment-variables/{environmentVariableId} Delete an environment variable by ID # Deploy an environment Source: https://docs.alpic.ai/api-reference/environments/deploy-an-environment https://api.alpic.ai/openapi.json post /v1/environments/{environmentId}/deploy Deploy an environment # Get an environment Source: https://docs.alpic.ai/api-reference/environments/get-an-environment https://api.alpic.ai/openapi.json get /v1/environments/{environmentId} Get an environment by ID # Get latest logs Source: https://docs.alpic.ai/api-reference/environments/get-latest-logs https://api.alpic.ai/openapi.json get /v1/environments/{environmentId}/latest-logs Get the N most recent logs for an environment # Get logs Source: https://docs.alpic.ai/api-reference/environments/get-logs https://api.alpic.ai/openapi.json get /v1/environments/{environmentId}/logs Get logs for an environment # Get playground configuration Source: https://docs.alpic.ai/api-reference/environments/get-playground-configuration https://api.alpic.ai/openapi.json get /v1/environments/{environmentId}/playground Get the playground configuration for an environment # List environment variables Source: https://docs.alpic.ai/api-reference/environments/list-environment-variables https://api.alpic.ai/openapi.json get /v1/environments/{environmentId}/environment-variables List all environment variables for an environment # Update an environment variable Source: https://docs.alpic.ai/api-reference/environments/update-an-environment-variable https://api.alpic.ai/openapi.json patch /v1/environment-variables/{environmentVariableId} Update an environment variable by ID # Update playground configuration Source: https://docs.alpic.ai/api-reference/environments/update-playground-configuration https://api.alpic.ai/openapi.json put /v1/environments/{environmentId}/playground Update the playground configuration for an environment. All fields are optional — only provided fields are updated. # Create an intent category Source: https://docs.alpic.ai/api-reference/insights/create-an-intent-category https://api.alpic.ai/openapi.json post /v1/environments/{environmentId}/intent-categories Create an intent category, optionally linking it to existing intents # Delete an intent category Source: https://docs.alpic.ai/api-reference/insights/delete-an-intent-category https://api.alpic.ai/openapi.json delete /v1/environments/{environmentId}/intent-categories/{categoryId} Delete an intent category; its intents are unlinked but not deleted # Link an intent category Source: https://docs.alpic.ai/api-reference/insights/link-an-intent-category https://api.alpic.ai/openapi.json post /v1/environments/{environmentId}/intent-categories/{categoryId}/link Link an intent category to intents; already linked intents are ignored # List feedbacks Source: https://docs.alpic.ai/api-reference/insights/list-feedbacks https://api.alpic.ai/openapi.json get /v1/environments/{environmentId}/feedbacks List user feedback for an environment over a time range # List intent categories Source: https://docs.alpic.ai/api-reference/insights/list-intent-categories https://api.alpic.ai/openapi.json get /v1/environments/{environmentId}/intent-categories List intent categories for an environment, including how many intents each category is linked to # List intents Source: https://docs.alpic.ai/api-reference/insights/list-intents https://api.alpic.ai/openapi.json get /v1/environments/{environmentId}/intents List grouped user intents for an environment over a time range # Unlink an intent category Source: https://docs.alpic.ai/api-reference/insights/unlink-an-intent-category https://api.alpic.ai/openapi.json post /v1/environments/{environmentId}/intent-categories/{categoryId}/unlink Unlink an intent category from intents; intents without the category are ignored # Update an intent category Source: https://docs.alpic.ai/api-reference/insights/update-an-intent-category https://api.alpic.ai/openapi.json patch /v1/environments/{environmentId}/intent-categories/{categoryId} Rename or recolor an intent category # Create a project Source: https://docs.alpic.ai/api-reference/projects/create-a-project https://api.alpic.ai/openapi.json post /v1/projects Create a project for a team # Delete a project Source: https://docs.alpic.ai/api-reference/projects/delete-a-project https://api.alpic.ai/openapi.json delete /v1/projects/{projectId} Delete a project and all its environments # Get a project Source: https://docs.alpic.ai/api-reference/projects/get-a-project https://api.alpic.ai/openapi.json get /v1/projects/{projectId} Get a project by ID # List projects Source: https://docs.alpic.ai/api-reference/projects/list-projects https://api.alpic.ai/openapi.json get /v1/projects List all projects for a team # Update a project Source: https://docs.alpic.ai/api-reference/projects/update-a-project https://api.alpic.ai/openapi.json patch /v1/projects/{projectId} Update project settings # Get team usage Source: https://docs.alpic.ai/api-reference/teams/get-team-usage https://api.alpic.ai/openapi.json get /v1/teams/{teamId}/usage Get the MCP request usage of a team for its current billing window. A team that has made no request in the window reports zero. # List teams Source: https://docs.alpic.ai/api-reference/teams/list-teams https://api.alpic.ai/openapi.json get /v1/teams List all teams for the authenticated user # Get a tunnel ticket Source: https://docs.alpic.ai/api-reference/tunnels/get-a-tunnel-ticket https://api.alpic.ai/openapi.json get /v1/tunnels/ticket Get a signed ticket for establishing a tunnel connection. Requires user authentication (API keys are not supported). # Hosting Assets Source: https://docs.alpic.ai/build-deploy/assets Learn how to host complete ChatGPT Apps on Alpic ## Overview [ChatGPT Apps](https://openai.com/index/introducing-apps-in-chatgpt/) are a new way for ChatGPT users to interact with your services directly from the ChatGPT interface. In practice, ChatGPT Apps are MCP servers exposing tools and MCP resources linking to UI components. Alpic allows you to host complete ChatGPT Apps with zero-configuration, by hosting both the MCP server and the UI assets used by your ChatGPT App. To learn more in detail about how OpenAI ChatGPT Apps work, read our blog post: [Inside OpenAI’s Apps SDK: How to Build Interactive ChatGPT Apps with MCP](https://alpic.ai/blog/inside-openai-s-apps-sdk-how-to-build-interactive-chatgpt-apps-with-mcp). ## Building your ChatGPT App Alpic provides a minimal starter kit in TypeScript to help you bootstrap your ChatGPT App. To get started, fork the [Alpic Apps SDK starter kit](https://github.com/alpic-ai/apps-sdk-template) or simply use the following link to clone the repository and deploy it on Alpic: [![Deploy on Alpic](https://assets.alpic.ai/button.svg)](https://app.alpic.ai/new/clone?repositoryUrl=https%3A%2F%2Fgithub.com%2Falpic-ai%2Fapps-sdk-template) Alpic supports ChatGPT apps written in any language and framework. You can of course use your favorite framework to build your ChatGPT App. ## Hosting your ChatGPT App assets on Alpic Alpic provides the `/assets` endpoint on all deployed servers. This allows you to serve static files like images, JavaScript, and CSS files used by your ChatGPT App. The `/assets` endpoint is populated in the following way: * We look for assets in the `/assets` folder at the project root location (your repository root by default) * We look for assets built during deployment and stored in the `/assets` folder in the build **output directory** specified in your Settings. By default, this is the `dist` folder, so we look for assets in the `dist/assets` folder by default * If both folders contain assets, a merge is done, with priority given to freshly built assets in case of conflict You can access your assets in your MCP server tools and resources code by using the relative path `/assets`. Note that OpenAI heavily caches ChatGPT Apps assets. In development mode, you can go to **Settings** > **Apps & Connectors**, then select your app and click on "**Refresh**" to clear the cache. # Builds Source: https://docs.alpic.ai/build-deploy/builds Learn how Alpic builds and configures your MCP server during deployment When you deploy your MCP server to Alpic, the platform automatically analyzes your project to detect configuration and build requirements. This ensures your server is configured correctly without any manual setup. ## Build Configuration Alpic automatically detects your MCP framework, build commands, and transport type from your repository. You can customize build settings if needed. Alpic detects configuration from your project source code. Most projects work out of the box without additional configuration. ### Configuration hierarchy 1. **alpic.json**: Branch-specific configuration located in your project's repository root directory. 2. **Project settings**: Set in the Alpic UI and applied to all environments. 3. **Default configuration**: Automatically detected by Alpic. ### Configuring projects with alpic.json This file should be created in your project's root directory and allows you to set: * [`$schema`](#schema-autocomplete) * [`buildCommand`](#buildcommand) * [`buildOutputDir`](#buildoutputdir) * [`installCommand`](#installcommand) * [`startCommand`](#startcommand) #### Schema Autocomplete To enable autocompletion, type checking, and schema validation to your alpic.json file, add the following to the top of your file: ```json theme={null} { "$schema": "https://assets.alpic.ai/alpic.json" } ``` #### buildCommand **Type**: `string` Use `buildCommand` to override the **Build Command** in the Project Settings dashboard. ```json theme={null} { "$schema": "https://assets.alpic.ai/alpic.json", "buildCommand": "npm run build" } ``` #### buildOutputDir **Type**: `string` Use `buildOutputDir` to override the **Output Directory** in the Project Settings dashboard. ```json theme={null} { "$schema": "https://assets.alpic.ai/alpic.json", "buildOutputDir": "server/dist" } ``` #### installCommand **Type**: `string` Use `installCommand` to override the **Install Command** in the Project Settings dashboard. ```json theme={null} { "$schema": "https://assets.alpic.ai/alpic.json", "installCommand": "npm ci" } ``` #### startCommand **Type**: `string` Use `startCommand` to override the **Start Command** in the Project Settings dashboard. ```json theme={null} { "$schema": "https://assets.alpic.ai/alpic.json", "startCommand": "npm run --silent start" } ``` ## Transport Sourcing During Deployment Alpic automatically detects which transport type your MCP server uses by analyzing your project source code. Detection follows a priority order, using the first match found: ### xmcp.config.ts configuration file (highest priority) If `xmcp.config.ts` exists: * `http:` → streamablehttp * `stdio:` → stdio ### TypeScript imports Searches for imports from `@modelcontextprotocol/sdk/server/`: * `stdio` → stdio * `sse` → sse * `streamableHttp` → streamablehttp ### Python mcp.run() or mcp.http\_app() calls Searches for explicit transport parameters: * `transport="stdio"` → stdio * `transport="sse"` → sse * `transport="streamable-http"` → streamable-http * `transport="http"` → http ### Python mcp.run() fallback (lowest priority) If `mcp.run()` is found without an explicit transport → defaults to stdio ## Python Project Setup Alpic uses [uv](https://docs.astral.sh/uv/) as the default Python package manager. By default, Alpic expects your Python project to use a **uv project** structure with a `pyproject.toml` file. If your project follows this convention, no additional configuration is needed — Alpic will automatically detect and install your dependencies. ### Using `requirements.txt` instead of `pyproject.toml` If your project uses a simple `main.py` file with a `requirements.txt` for dependencies, you need to override the install command either in your **Project Settings** or in your `alpic.json`: ```json theme={null} { "$schema": "https://assets.alpic.ai/alpic.json", "installCommand": "uv venv && uv pip install -r requirements.txt" } ``` The default start command (`uv run main.py`) works as-is, so you don't need to override `startCommand`. We recommend migrating to a `pyproject.toml`-based uv project for the best experience. You can initialize one by running `uv init` in your project directory. ## Troubleshooting ### Build Fails: "No MCP transport found" If Alpic cannot detect a transport type, the build will fail. To resolve: 1. Create an `xmcp.config.ts` file with your transport type 2. Ensure you're importing from the correct MCP SDK path (TypeScript) 3. Add an explicit transport parameter to `mcp.run()` (Python) Make sure your project uses one of the supported MCP frameworks. Alpic automatically detects transport for projects using the official MCP SDKs. # Alpic Endpoints Source: https://docs.alpic.ai/build-deploy/endpoints Learn about the endpoints and assets exposed by Alpic ## Alpic architecture overview To allow zero-configuration deployments of MCP servers and Apps that scale with your users, Alpic uses a serverless architecture. Alpic exposes an MPC gateway that handles protocol-specific specificities like transport and authentication, and proxies requests to the MCP server built from your connected repository. This means that your repository **needs to expose an MCP server endpoint** that can be accessed by the Alpic gateway, either locally in stdio, or via SSE or Streamable HTTP. ## Public Endpoints All deployed servers are hosted by default on domains in the form of `https://my-domain-123456.alpic.live`. Each environment receives its own unique domain that you can use to connect your MCP clients. Here is the list of available endpoints on your MCP server domain: * `/` - Main MCP Server Endpoint. It supports both **SSE** and **StreamableHTTP** transports. * `/mcp` - it supports **StreamableHTTP** transport only and is used for compatibility with certain MCP Clients. * `/try` - The [Playground](/distribution/playground), an AI-powered interface where users can try your MCP server directly from their browser. ## Internal Endpoints The following endpoints are used internally by Alpic for authentication and server management. #### OAuth Authentication Endpoints These endpoints are only available if your server is not public and requires authentication: * **`/.well-known/protected-resource-metadata`**: Part of the OAuth authentication flow, provides metadata about protected resources * **`/.well-known/oauth-authorization-server`**: Part of the OAuth authentication flow. Only available if authentication is not delegated to an external authorization server #### Dynamic Client Registration (DCR) Proxy Endpoints These endpoints are only available if Dynamic Client Registration (DCR) proxy is activated: * **`/register`**: Endpoint for client registration * **`/authorize`**: OAuth authorization endpoint * **`/token`**: OAuth token endpoint * **`/callback`**: OAuth callback endpoint ## Static Assets **`/assets`**: Static assets exposed by your MCP server. This endpoint serves any static files you've configured for deployment in your repository. Learn more about how static assets are generated and served by Alpic in our guide on [Hosting ChatGPT Apps](/build-deploy/assets#hosting-your-chatgpt-app-assets-on-alpic). # Environment Variables Source: https://docs.alpic.ai/build-deploy/env-variables System-provided environment variables available in your MCP server deployments Alpic automatically provides system environment variables to your MCP server deployments. These variables are set automatically and cannot be overridden by users. ## System environment variables ### ALPIC\_HOST **Available at:** Both build and runtime The hostname of your environment's MCP server URL. Used internally to treat the deployed host as an internal host (like `localhost`) when it's used as the OAuth server. ``` ALPIC_HOST=server-123456.alpic.live ``` ### ALPIC\_CUSTOM\_DOMAINS **Available at:** Both build and runtime A comma-separated list of custom domains that are configured for your environment. Used internally to treat the deployed host as an internal host (like `localhost`) when it's used as the OAuth server. ``` ALPIC_CUSTOM_DOMAINS=yourdomain.com,anotherdomain.com ``` # Environments Source: https://docs.alpic.ai/build-deploy/environments How to manage your deployment environments Alpic allows you to create multiple deployment environments for your MCP server. Each environment is linked to a specific branch of your git repository and corresponds to a different version of your MCP server. To create a new environment: 1. Go to your project overview page. 2. Click on **Environments**. 3. Click on **New environment**. 4. Name your new environment. 5. Select the branch you want to link to this environment. 6. Add any environment variables you need for this environment. 7. Click **Create**. This will generate a new URL that you can use to access this environment's MCP server. Create a new environment ## Changing the tracked branch You can change the branch linked to an environment after creation: 1. Go to your project overview page. 2. Click on **Environments** and select the environment you want to update. 3. Click the edit icon next to the current branch name. 4. Select or type the new branch name and click **Save**. You'll be notified of the branch tracking update result and you'll get a chance to trigger a redeploy with the latest code from the new branch if the update was successful. You can delete environments at any time by clicking the **Delete** button in your environment settings. # audit Source: https://docs.alpic.ai/cli/audit Run a Beacon audit on an MCP server Runs a [Beacon](/testing/beacon) audit against a remote MCP server and prints a summary of passed, failed, and skipped checks. Beacon verifies spec compliance, tool and resource metadata, and readiness for ChatGPT and Claude.ai. End-to-end widget rendering checks are skipped from the CLI because they take several minutes per platform. Run the full audit — including live browser widget tests — from the Beacon tab in the Alpic dashboard. ## Usage Audit a server by URL (standalone mode, no project association): ```bash theme={null} alpic audit --url https://my-server.example.com/mcp ``` Runs the audit against the specified MCP server URL and prints a summary report with passed, failed, and skipped checks. ## Extended Usage Output the full report as JSON (useful for CI or further processing): ```bash theme={null} alpic audit --url https://my-server.example.com/mcp --json ``` Skip confirmation prompts: ```bash theme={null} alpic audit --url https://my-server.example.com/mcp --non-interactive ``` ## Options | Flag | Description | Default | | ------------------- | ---------------------------------------------------------------------------------- | ------- | | `--url` | The HTTPS URL of the MCP server to audit (standalone mode, no project association) | | | `--json` | Output the full report as JSON | `false` | | `--team-id` | Team ID (only with `--url` for standalone audits) | | | `--project-id` | Project ID to audit | | | `--environment-id` | Environment ID to audit (defaults to production) | | | `--non-interactive` | Skip all confirmation prompts | `false` | ## Exit codes `alpic audit` exits with code `1` when at least one error-severity check fails, and `0` otherwise. Warnings and skipped checks do not fail the command, so you can gate CI on blocking issues while still surfacing lower-severity findings in the output. Authentication is required. Run `alpic login` or set `ALPIC_API_KEY` before running an audit. If the current directory is linked to an Alpic project, the audit automatically associates with that project. Use `--non-interactive` to skip the confirmation prompt. Beacon only supports unauthenticated MCP servers today. If the target returns `HTTP 401`, Beacon reports that auth is required and skips the remaining checks. # deploy Source: https://docs.alpic.ai/cli/deploy Deploy a project to Alpic Package and deploy an MCP server project to Alpic. The command collects source files, uploads them, and waits for the deployment to complete before printing the server URL. ## Usage ```bash theme={null} alpic deploy ``` Deploys the current directory. Prompts for any missing configuration (project name, runtime) if not already set. ## Extended Usage Skip all prompts (useful in CI): ```bash theme={null} alpic deploy --non-interactive --project-name my-app --runtime node24 ``` Create and deploy a new project whose app root is a monorepo subdirectory (path is relative to the directory where you run the command): ```bash theme={null} alpic deploy --project-name my-app --root-dir ./packages/my-mcp-server ``` `--root-dir` is passed through the same linking flow as `alpic link`: it only applies when this run **creates** a new Alpic project. For an already linked directory, the app root was set at link/create time. Import environment variables from a `.env` file when creating a new project: ```bash theme={null} alpic deploy --project-name my-app --runtime node24 --env-file .env ``` ## Options | Flag | Description | | ------------------- | ------------------------------------------------------------------------------------------------------------------------- | | `--non-interactive` | Skip all confirmation prompts | | `--runtime` | Runtime to use: `node24`, `node22`, `python3.14`, `python3.13` | | `--root-dir` | Relative path to the app root for builds and deployments; only when **creating** a new project (omit for repository root) | | `--project-name` | Name for a new project | | `--team-id` | Team ID | | `--project-id` | Project ID to deploy to directly | | `--environment-id` | Environment ID to deploy to directly | | `--env-file` | Path to a `.env` file to source environment variables from (new projects only) | Project names can be renamed. For CI/CD pipelines, prefer `--project-id` to avoid breakage. Authentication is required. Run `alpic login` or set `ALPIC_API_KEY` before deploying. # deployment inspect Source: https://docs.alpic.ai/cli/deployment-inspect Show details of a deployment Displays detailed information about a specific deployment, including its status, environment, author, source branch, commit, and duration. ## Usage ```bash theme={null} alpic deployment inspect --deployment-id ``` Fetches and prints the details of the specified deployment. ## Extended Usage Inspect the latest deployment for an environment: ```bash theme={null} alpic deployment inspect --environment-id ``` Wait for an in-progress deployment to reach a final state before printing its details: ```bash theme={null} alpic deployment inspect --deployment-id --wait ``` ## Options | Flag | Description | Default | | ------------------ | ---------------------------------------------------------------------------------------------- | ------- | | `--deployment-id` | The ID of the deployment. Mutually exclusive with `--environment-id`. | — | | `--environment-id` | Inspect the latest deployment for this environment. Mutually exclusive with `--deployment-id`. | — | | `--wait` | Wait for the deployment to reach a final state (deployed, failed, or canceled). | `false` | # deployment list Source: https://docs.alpic.ai/cli/deployment-list List deployments for the current project Lists all deployments for the current project, showing their ID, age, environment, status, whether the deployment is current, duration, and author. ## Usage ```bash theme={null} alpic deployment list ``` Lists all deployments for the project linked to the current directory. ## Extended Usage List deployments by project ID: ```bash theme={null} alpic deployment list --project-id ``` List deployments by project name: ```bash theme={null} alpic deployment list --project-name ``` Filter deployments by environment: ```bash theme={null} alpic deployment list --environment-id ``` Filter by one or more statuses: ```bash theme={null} alpic deployment list --status deployed --status failed ``` ## Options | Flag | Description | Default | | ------------------ | ---------------------------------------------------------------------------------------------------------------- | ------- | | `--project-id` | The ID of the project. | — | | `--project-name` | The name of the project. | — | | `--environment-id` | Filter by environment ID. | — | | `--status` | Filter by status. Accepted values: `deployed`, `ongoing`, `failed`, `canceled`. Can be specified multiple times. | — | # deployment logs Source: https://docs.alpic.ai/cli/deployment-logs Retrieve build logs for a deployment Retrieves the build logs for a specific deployment or the latest deployment of an environment. ## Usage ```bash theme={null} alpic deployment logs --deployment-id ``` Prints the build logs for the specified deployment. ## Extended Usage Follow logs while the build is still running: ```bash theme={null} alpic deployment logs --deployment-id --follow ``` Retrieve logs for the latest deployment of an environment: ```bash theme={null} alpic deployment logs --environment-id ``` Disable colorized output: ```bash theme={null} alpic deployment logs --deployment-id --no-color ``` ## Options | Flag | Description | Default | | ------------------ | --------------------------------------------------------------------------------------------------- | ------- | | `--deployment-id` | The ID of the deployment (e.g. `dpl_xxx`). Mutually exclusive with `--environment-id`. | — | | `--environment-id` | Show logs for the latest deployment of this environment. Mutually exclusive with `--deployment-id`. | — | | `-f, --follow` | Poll for new logs while the build is still running. | `false` | | `--no-color` | Disable colorized output. | `false` | # environment inspect Source: https://docs.alpic.ai/cli/environment-inspect Show details of an environment Displays detailed information about an environment, including its ID, name, project, team, source branch, MCP server URL, custom domains, and creation date. ## Usage ```bash theme={null} alpic environment inspect --environment-id ``` Shows details of the specified environment. ## Extended Usage Inspect an environment by name: ```bash theme={null} alpic environment inspect --environment-name --project-name ``` When no identifier is provided, you will be prompted to select a project and then an environment interactively: ```bash theme={null} alpic environment inspect ``` ## Options | Flag | Description | Default | | -------------------- | --------------------------------------------------------------------------------- | ------- | | `--environment-id` | The ID of the environment. | — | | `--environment-name` | The name of the environment. | — | | `--project-id` | The ID of the project. | — | | `--project-name` | The name of the project. | — | | `--non-interactive` | Disable interactive prompts. Requires `--environment-id` or `--environment-name`. | `false` | # environment list Source: https://docs.alpic.ai/cli/environment-list List environments for a project Lists all environments for a project, showing their ID, name, project, team, source branch, MCP server URL, and creation date. ## Usage ```bash theme={null} alpic environment list --project-id ``` Lists all environments for the specified project. ## Extended Usage List environments by project name: ```bash theme={null} alpic environment list --project-name ``` When no project identifier is provided, you will be prompted to select a project interactively: ```bash theme={null} alpic environment list ``` ## Options | Flag | Description | Default | | ------------------- | ------------------------------------------------------------------------- | ------- | | `--project-id` | The ID of the project. | — | | `--project-name` | The name of the project. | — | | `--non-interactive` | Disable interactive prompts. Requires `--project-id` or `--project-name`. | `false` | # environment-variable add Source: https://docs.alpic.ai/cli/environment-variable-add Add one or more environment variables to an Alpic environment Adds environment variables to an Alpic environment. Runs interactively by default. Variables are marked as secret by default, meaning their values are masked when listed. ## Usage ```bash theme={null} alpic environment-variable add ``` Prompts for a key, value, and secret preference interactively. ## Extended Usage **Add a single variable non-interactively:** ```bash theme={null} alpic environment-variable add --key DATABASE_URL --value postgres://localhost/db ``` **Add a non-secret (visible) variable:** ```bash theme={null} alpic environment-variable add --key PORT --value 3000 --no-secret ``` **Import all variables from a `.env` file:** ```bash theme={null} alpic environment-variable add --env-file .env ``` **Import from a `.env` file into a specific environment:** ```bash theme={null} alpic environment-variable add --env-file .env --environment-id ``` ## Options | Flag | Description | | ------------------- | ----------------------------------------------------------------------------- | | `--environment-id` | The ID of the environment (optional — read from local config if omitted) | | `--key` | The environment variable key | | `--value` | The environment variable value | | `--secret` | Mark as secret (default: true). Use `--no-secret` to store in plain text | | `--env-file` | Path to a `.env` file to import (mutually exclusive with `--key`/`--value`) | | `--non-interactive` | Disable interactive prompts. Requires `--key` and `--value` (or `--env-file`) | When running from a directory linked to an Alpic project (via `alpic deploy`), `--environment-id` is optional — the CLI reads it from the local `.alpic` config file. # environment-variable list Source: https://docs.alpic.ai/cli/environment-variable-list List all environment variables for an Alpic environment Lists all environment variables for an Alpic environment. Secret variable values are displayed as ``. ## Usage ```bash theme={null} alpic environment-variable list ``` Lists all environment variables for the current linked environment. ## Extended Usage **List variables for a specific environment by ID:** ```bash theme={null} alpic environment-variable list --environment-id ``` ## Options | Flag | Description | | ------------------ | ------------------------------------------------------------------------ | | `--environment-id` | The ID of the environment (optional — read from local config if omitted) | When running from a directory linked to an Alpic project (via `alpic deploy`), `--environment-id` is optional — the CLI reads it from the local `.alpic` config file. # environment-variable remove Source: https://docs.alpic.ai/cli/environment-variable-remove Remove an environment variable from an Alpic environment Removes an environment variable from an Alpic environment. Prompts to select the key interactively unless `--key` is provided. ## Usage ```bash theme={null} alpic environment-variable remove ``` Prompts to select the variable to remove interactively. ## Extended Usage **Remove a specific variable non-interactively:** ```bash theme={null} alpic environment-variable remove --key DATABASE_URL ``` **Remove a variable from a specific environment:** ```bash theme={null} alpic environment-variable remove --key DATABASE_URL --environment-id ``` ## Options | Flag | Description | | ------------------- | ------------------------------------------------------------------------ | | `--environment-id` | The ID of the environment (optional — read from local config if omitted) | | `--key` | The key of the environment variable to remove | | `--non-interactive` | Disable interactive prompts. Requires `--key` | When running from a directory linked to an Alpic project (via `alpic deploy`), `--environment-id` is optional — the CLI reads it from the local `.alpic` config file. # environment-variable update Source: https://docs.alpic.ai/cli/environment-variable-update Update the value and/or secret status of an environment variable Updates the value and/or secret status of an existing environment variable in an Alpic environment. ## Usage ```bash theme={null} alpic environment-variable update ``` Prompts to select the variable and enter the new value interactively. ## Extended Usage **Update a variable's value:** ```bash theme={null} alpic environment-variable update --key DATABASE_URL --value postgres://prod/db ``` **Update a variable in a specific environment:** ```bash theme={null} alpic environment-variable update --key PORT --value 8080 --environment-id ``` **Change a variable's secret status:** ```bash theme={null} alpic environment-variable update --key PORT --no-secret ``` ## Options | Flag | Description | | ------------------- | ---------------------------------------------------------------------------------------------- | | `--environment-id` | The ID of the environment (optional — read from local config if omitted) | | `--key` | The key of the environment variable to update | | `--value` | The new value (omit to keep the current value) | | `--secret` | Mark as secret. Use `--no-secret` to make it visible | | `--non-interactive` | Disable interactive prompts. Requires `--key` and one of `--value` or `--secret`/`--no-secret` | When running from a directory linked to an Alpic project (via `alpic deploy`), `--environment-id` is optional — the CLI reads it from the local `.alpic` config file. # git connect Source: https://docs.alpic.ai/cli/git-connect Connect a linked Alpic project to a git remote source Links an Alpic project to a GitHub remote repository. Once connected, you can install the Alpic GitHub App to trigger automatic deployments on every push. The directory must already be linked to an Alpic project (via `alpic deploy`) and must be a git repository with at least one GitHub remote configured. ## Usage ```bash theme={null} alpic git connect ``` Detects GitHub remotes in the current directory and prompts to select one. ## Extended Usage ```bash theme={null} # Auto-select the only available remote without prompting alpic git connect --non-interactive # Connect using a specific named remote alpic git connect --remote-name origin ``` ## Options | Flag | Description | Default | | ------------------- | ---------------------------------------------------------- | ------- | | `--non-interactive` | Automatically select the remote when only one is available | `false` | | `--remote-name` | Name of the remote to connect | | # git disconnect Source: https://docs.alpic.ai/cli/git-disconnect Disconnect a linked Alpic project from its git remote source Removes the git remote repository link from an Alpic project. The project remains deployed; only the source repository association is cleared. ## Usage ```bash theme={null} alpic git disconnect ``` Prompts for confirmation before removing the git remote link from the linked project in the current directory. ## Extended Usage ```bash theme={null} # Skip the confirmation prompt alpic git disconnect --non-interactive ``` ## Options | Flag | Description | Default | | ------------------- | ---------------------------- | ------- | | `--non-interactive` | Skip the confirmation prompt | `false` | # insights category create Source: https://docs.alpic.ai/cli/insights-category-create Create an intent category in an Alpic environment Create an intent category, optionally linking it to existing intents. ## Usage ```bash theme={null} alpic insights category create ``` Prompts for a name and creates the category in the environment from the local `.alpic` configuration. ## Extended Usage Create a category with an explicit name and color: ```bash theme={null} alpic insights category create --name Scheduling --color blue ``` When `--color` is omitted, a color is derived from the category name. Available colors: `red`, `orange`, `yellow`, `green`, `blue`, `purple`, `pink`, `gray`. Link the new category to existing intents right away: ```bash theme={null} alpic insights category create \ --name Scheduling \ --intent-id \ --intent-id ``` Create in automation and print the created category: ```bash theme={null} alpic insights category create --environment-id --name Scheduling --json --non-interactive ``` `--name` is required in non-interactive mode. ## Options | Flag | Description | Default | | -------------------- | ------------------------------------------------------ | ------- | | `--environment-id` | Select an environment by ID | | | `--environment-name` | Select an environment by name | | | `--project-id` | Provide the project context by ID | | | `--project-name` | Provide the project context by name | | | `--name` | The category name | | | `--color` | The category color; derived from the name when omitted | | | `--intent-id` | Link the new category to this intent ID. Repeatable. | | | `--json` | Print the unmodified API response as JSON | `false` | | `--non-interactive` | Skip interactive prompts | | When the current directory is linked to an environment, the environment and project flags can be omitted. # insights category delete Source: https://docs.alpic.ai/cli/insights-category-delete Delete an intent category Delete an intent category. Intents linked to the category are unlinked but not deleted. ## Usage ```bash theme={null} alpic insights category delete ``` Prompts for the category to delete and asks for confirmation. ## Extended Usage Select the category explicitly: ```bash theme={null} alpic insights category delete --category-id ``` Delete in automation: ```bash theme={null} alpic insights category delete \ --environment-id \ --category-id \ --non-interactive ``` `--category-id` is required in non-interactive mode, and the confirmation prompt is skipped. ## Options | Flag | Description | Default | | -------------------- | ----------------------------------- | ------- | | `--environment-id` | Select an environment by ID | | | `--environment-name` | Select an environment by name | | | `--project-id` | Provide the project context by ID | | | `--project-name` | Provide the project context by name | | | `--category-id` | The ID of the intent category | | | `--non-interactive` | Skip interactive prompts | | When the current directory is linked to an environment, the environment and project flags can be omitted. # insights category link Source: https://docs.alpic.ai/cli/insights-category-link Link an intent category to intents Link an intent category to one or more intents. Intents that already carry the category are ignored. Intent IDs are returned by [`insights intent list`](/cli/insights-intent-list) in the `--json` output (`intentIds`). ## Usage ```bash theme={null} alpic insights category link --intent-id ``` Prompts for the category to link in the environment from the local `.alpic` configuration. ## Extended Usage Link several intents to an explicit category: ```bash theme={null} alpic insights category link \ --category-id \ --intent-id \ --intent-id ``` Link in automation: ```bash theme={null} alpic insights category link \ --environment-id \ --category-id \ --intent-id \ --non-interactive ``` `--category-id` is required in non-interactive mode. ## Options | Flag | Description | Default | | -------------------- | ---------------------------------------- | ------- | | `--environment-id` | Select an environment by ID | | | `--environment-name` | Select an environment by name | | | `--project-id` | Provide the project context by ID | | | `--project-name` | Provide the project context by name | | | `--category-id` | The ID of the intent category | | | `--intent-id` | The ID of an intent to link. Repeatable. | | | `--non-interactive` | Skip interactive prompts | | When the current directory is linked to an environment, the environment and project flags can be omitted. # insights category list Source: https://docs.alpic.ai/cli/insights-category-list List intent categories for an Alpic environment List the intent categories of an environment, including how many intents each category is linked to. ## Usage ```bash theme={null} alpic insights category list ``` Lists categories for the environment in the local `.alpic` configuration. ## Extended Usage Select an environment by ID: ```bash theme={null} alpic insights category list --environment-id ``` Select an environment by name within a project: ```bash theme={null} alpic insights category list --project-name my-project --environment-name production ``` Emit the complete API response for automation: ```bash theme={null} alpic insights category list --environment-id --json --non-interactive ``` ## Options | Flag | Description | Default | | -------------------- | ----------------------------------------- | ------- | | `--environment-id` | Select an environment by ID | | | `--environment-name` | Select an environment by name | | | `--project-id` | Provide the project context by ID | | | `--project-name` | Provide the project context by name | | | `--json` | Print the unmodified API response as JSON | `false` | | `--non-interactive` | Skip interactive prompts | | When the current directory is linked to an environment, the environment and project flags can be omitted. # insights category unlink Source: https://docs.alpic.ai/cli/insights-category-unlink Unlink an intent category from intents Remove an intent category from one or more intents. Intents that do not carry the category are ignored. ## Usage ```bash theme={null} alpic insights category unlink --intent-id ``` Prompts for the category to unlink in the environment from the local `.alpic` configuration. ## Extended Usage Unlink several intents from an explicit category: ```bash theme={null} alpic insights category unlink \ --category-id \ --intent-id \ --intent-id ``` Unlink in automation: ```bash theme={null} alpic insights category unlink \ --environment-id \ --category-id \ --intent-id \ --non-interactive ``` `--category-id` is required in non-interactive mode. ## Options | Flag | Description | Default | | -------------------- | ------------------------------------------ | ------- | | `--environment-id` | Select an environment by ID | | | `--environment-name` | Select an environment by name | | | `--project-id` | Provide the project context by ID | | | `--project-name` | Provide the project context by name | | | `--category-id` | The ID of the intent category | | | `--intent-id` | The ID of an intent to unlink. Repeatable. | | | `--non-interactive` | Skip interactive prompts | | When the current directory is linked to an environment, the environment and project flags can be omitted. # insights category update Source: https://docs.alpic.ai/cli/insights-category-update Rename or recolor an intent category Rename or recolor an intent category. ## Usage ```bash theme={null} alpic insights category update --name "New name" ``` Prompts for the category to update in the environment from the local `.alpic` configuration. ## Extended Usage Select the category explicitly and change both fields: ```bash theme={null} alpic insights category update \ --category-id \ --name "New name" \ --color green ``` Update in automation: ```bash theme={null} alpic insights category update \ --environment-id \ --category-id \ --color green \ --non-interactive ``` At least one of `--name` or `--color` is required. `--category-id` is required in non-interactive mode. ## Options | Flag | Description | Default | | -------------------- | ----------------------------------------- | ------- | | `--environment-id` | Select an environment by ID | | | `--environment-name` | Select an environment by name | | | `--project-id` | Provide the project context by ID | | | `--project-name` | Provide the project context by name | | | `--category-id` | The ID of the intent category | | | `--name` | The new category name | | | `--color` | The new category color | | | `--json` | Print the unmodified API response as JSON | `false` | | `--non-interactive` | Skip interactive prompts | | When the current directory is linked to an environment, the environment and project flags can be omitted. # insights feedback list Source: https://docs.alpic.ai/cli/insights-feedback-list List user feedback for an Alpic environment List feedback captured from users and models, including its source, client, and timestamp. ## Usage ```bash theme={null} alpic insights feedback list ``` Lists feedback from the last seven days for the environment in the local `.alpic` configuration. ## Extended Usage Select an environment by ID and use an explicit time range: ```bash theme={null} alpic insights feedback list \ --environment-id \ --since 24h \ --until 1h ``` Select an environment by name within a project: ```bash theme={null} alpic insights feedback list --project-name my-project --environment-name production ``` The project can also be selected by ID: ```bash theme={null} alpic insights feedback list --project-id --environment-name production ``` Filter and page through feedback: ```bash theme={null} alpic insights feedback list \ --search timeout \ --client-id claude-desktop \ --limit 100 \ --offset 100 ``` Emit the complete API response for automation: ```bash theme={null} alpic insights feedback list --environment-id --json --non-interactive ``` Human-readable output truncates long feedback content. `--json` preserves complete content. ## Options | Flag | Description | Default | | -------------------- | --------------------------------------------------------- | ------- | | `--environment-id` | Select an environment by ID | | | `--environment-name` | Select an environment by name | | | `--project-id` | Provide the project context by ID | | | `--project-name` | Provide the project context by name | | | `--since` | Show feedback after a relative duration or ISO 8601 date | `7d` | | `--until` | Show feedback before a relative duration or ISO 8601 date | now | | `--search` | Search feedback content and source | | | `--client-id` | Filter by stable MCP client ID. Repeatable. | | | `--limit` | Return between 1 and 200 feedback entries | `50` | | `--offset` | Skip this many feedback entries | `0` | | `--json` | Print the unmodified API response as JSON | `false` | | `--non-interactive` | Skip interactive prompts | | When the current directory is linked to an environment, the environment and project flags can be omitted. # insights intent list Source: https://docs.alpic.ai/cli/insights-intent-list List grouped user intents for an Alpic environment List grouped examples of what users tried to accomplish, including occurrence counts, tools, clients, and categories. ## Usage ```bash theme={null} alpic insights intent list ``` Lists intents from the last seven days for the environment in the local `.alpic` configuration. ## Extended Usage Select an environment by ID and use an explicit time range: ```bash theme={null} alpic insights intent list \ --environment-id \ --since 2026-08-01T00:00:00Z \ --until 2026-08-08T00:00:00Z ``` Select an environment by name within a project: ```bash theme={null} alpic insights intent list --project-name my-project --environment-name production ``` The project can also be selected by ID: ```bash theme={null} alpic insights intent list --project-id --environment-name production ``` Filter and page through grouped intents: ```bash theme={null} alpic insights intent list \ --search scheduling \ --tool create-event \ --tool update-event \ --client-id claude-desktop \ --category-id \ --sort asc \ --limit 100 \ --offset 100 ``` Emit the complete API response for automation: ```bash theme={null} alpic insights intent list --environment-id --json --non-interactive ``` Human-readable output truncates long intent messages. `--json` preserves complete messages. ## Options | Flag | Description | Default | | -------------------- | -------------------------------------------------------- | ------- | | `--environment-id` | Select an environment by ID | | | `--environment-name` | Select an environment by name | | | `--project-id` | Provide the project context by ID | | | `--project-name` | Provide the project context by name | | | `--since` | Show intents after a relative duration or ISO 8601 date | `7d` | | `--until` | Show intents before a relative duration or ISO 8601 date | now | | `--search` | Search intent messages, tools, and categories | | | `--tool` | Filter by tool name. Repeatable. | | | `--client-id` | Filter by stable MCP client ID. Repeatable. | | | `--category-id` | Filter by category ID. Repeatable. | | | `--sort` | Sort by date: `asc` or `desc` | `desc` | | `--limit` | Return between 1 and 200 grouped intents | `50` | | `--offset` | Skip this many grouped intents | `0` | | `--json` | Print the unmodified API response as JSON | `false` | | `--non-interactive` | Skip interactive prompts | | When the current directory is linked to an environment, the environment and project flags can be omitted. # link Source: https://docs.alpic.ai/cli/link Link the current directory to an Alpic project Associate the current directory with an existing or new Alpic project. Once linked, commands like `deploy` and `git connect` operate on the linked project without requiring additional flags. ## Usage ```bash theme={null} alpic link ``` Interactively links the current directory to an Alpic project. Prompts for project selection or creation if not already linked. ## Extended Usage Skip all prompts (useful in CI): ```bash theme={null} alpic link --non-interactive --project-name my-app --runtime node24 ``` Link to an existing project by ID: ```bash theme={null} alpic link --project-id ``` Create a new project whose app lives in a monorepo subdirectory (path is relative to the directory where you run the command): ```bash theme={null} alpic link --project-name my-app --root-dir ./packages/my-mcp-server ``` When linking interactively, **Root directory** defaults to `.` (repository root). Alpic stores this path on the project so builds and deployments run from that folder inside the connected repository. ## Options | Flag | Description | | ------------------- | ------------------------------------------------------------------------------------------------------------------------- | | `--non-interactive` | Skip all confirmation prompts | | `--team-id` | Team ID to use | | `--project-id` | Link to this existing project ID | | `--environment-id` | Use this environment ID | | `--project-name` | New project name | | `--runtime` | Runtime to use: `node24`, `node22`, `python3.14`, `python3.13` | | `--root-dir` | Relative path to the app root for builds and deployments; only when **creating** a new project (omit for repository root) | | `--env-file` | Path to a `.env` file to source environment variables from (new projects only) | Authentication is required. Run `alpic login` or set `ALPIC_API_KEY` before linking. If the current directory is a git repository, `link` will offer to connect the project to a GitHub remote after linking. # login Source: https://docs.alpic.ai/cli/login Log in to Alpic using browser-based OAuth authentication Authenticate with Alpic by completing an OAuth flow in your browser. Tokens are stored locally and reused across sessions. ## Usage ```bash theme={null} alpic login ``` Opens a browser window to complete authentication. Once done, credentials are saved locally so subsequent commands run without re-authenticating. If already logged in, the command exits immediately without opening the browser. ## Options This command has no flags. `login` only applies to browser-based authentication. If you use an API key via `ALPIC_API_KEY`, no login is required. # logout Source: https://docs.alpic.ai/cli/logout Log out from Alpic and remove stored OAuth credentials Removes the OAuth credentials stored on this machine. Has no effect if no credentials are stored. ## Usage ```bash theme={null} alpic logout ``` Clears locally stored OAuth tokens. ## Extended Usage ```bash theme={null} # Log out and then log back in as a different user alpic logout alpic login ``` This command only removes OAuth tokens. If you authenticate via `ALPIC_API_KEY`, unset the environment variable to stop using that key. ## Options This command has no flags. # logs Source: https://docs.alpic.ai/cli/logs Stream runtime logs for an Alpic environment Stream runtime logs for an environment. Fetches recent log entries and optionally follows new ones as they arrive. ## Usage ```bash theme={null} alpic logs --environment-id ``` Fetches log entries for the specified environment. ## Extended Usage Show logs from the last hour: ```bash theme={null} alpic logs --environment-id --since 1h ``` Follow logs continuously as new entries arrive: ```bash theme={null} alpic logs --environment-id --follow ``` When `--follow` is used without `--since`, the CLI defaults to showing logs from the last 10 minutes before polling for new entries. Show logs up to a specific point in time: ```bash theme={null} alpic logs --environment-id --since 1h --until 30m ``` `--until` cannot be used together with `--follow`. Filter by one or more log levels: ```bash theme={null} alpic logs --environment-id --level ERROR --level WARNING ``` Search log entries by keyword or filter expression: ```bash theme={null} alpic logs --environment-id --search 'timeout' --limit 50 ``` Disable colorized output: ```bash theme={null} alpic logs --environment-id --no-color ``` ## Options | Flag | Short | Description | Default | | ------------------ | ----- | ----------------------------------------------------------------------------------------------------- | ------- | | `--environment-id` | | The ID of the environment | | | `--since` | | Show logs after this time (e.g. `1h`, `30m`, `2024-01-01T00:00:00Z`) | | | `--until` | | Show logs before this time (e.g. `1h`, `30m`, `2024-01-01T00:00:00Z`). Cannot be used with `--follow` | | | `--limit` | `-n` | Maximum number of log entries to fetch (1–1000). Cannot be used with `--follow` | | | `--follow` | `-f` | Poll for new logs continuously | `false` | | `--level` | | Filter by log level (`INFO`, `ERROR`, `WARNING`, `DEBUG`). Repeatable. | | | `--search` | | Filter logs by text or regex pattern | | | `--no-color` | | Disable colorized output and show log levels as text | `false` | # Alpic CLI Source: https://docs.alpic.ai/cli/overview Deploy and manage your MCP servers from the command line ## Installing Alpic CLI Install the CLI globally with npm or pnpm: ```bash theme={null} npm install -g alpic # or pnpm add -g alpic ``` Run it without installing via npx: ```bash theme={null} npx alpic ``` ## Authentication The CLI supports two authentication methods: browser-based login and API key. ### Browser login (recommended) ```bash theme={null} alpic login ``` Opens a browser window to authenticate. Tokens are stored locally and reused across sessions. ### API key Set the `ALPIC_API_KEY` environment variable to authenticate without a browser: In the [Alpic dashboard](https://app.alpic.ai), open your team and go to **API Keys** in the sidebar. Click **New API key**, name it, and copy the key. Export the key in your shell or add it to your CI/CD secrets: ```bash theme={null} export ALPIC_API_KEY=your_api_key_here ``` If both OAuth login credentials and `ALPIC_API_KEY` are present, the CLI uses `ALPIC_API_KEY`. Keep your API key secure and never commit it to version control. If exposed, revoke it in the dashboard and create a new one. ## Checking the version ```bash theme={null} alpic --version ``` Prints the installed CLI version. ## Available Commands | Command | What it does | Full reference | | ---------------------------------- | ------------------------------------------------------------------------- | -------------------------------------------------- | | `team list` | List teams for the current user | [View docs](/cli/team-list) | | `team inspect` | Show details of a team and its projects | [View docs](/cli/team-inspect) | | `project list` | List projects | [View docs](/cli/project-list) | | `project inspect` | Show details of a project and its environments | [View docs](/cli/project-inspect) | | `environment list` | List environments for a project | [View docs](/cli/environment-list) | | `environment inspect` | Show details of an environment | [View docs](/cli/environment-inspect) | | `audit` | Run a beacon audit on an MCP server | [View docs](/cli/audit) | | `link` | Link the current directory to an Alpic project | [View docs](/cli/link) | | `deploy` | Deploy a project from the current directory or a specified path | [View docs](/cli/deploy) | | `publish` | Publish an MCP server to the MCP registry | [View docs](/cli/publish) | | `deployment list` | List deployments for the current project | [View docs](/cli/deployment-list) | | `deployment inspect` | Show details of a specific deployment | [View docs](/cli/deployment-inspect) | | `deployment logs` | Retrieve build logs for a deployment | [View docs](/cli/deployment-logs) | | `login` | Authenticate via browser OAuth | [View docs](/cli/login) | | `logout` | Remove stored OAuth credentials | [View docs](/cli/logout) | | `whoami` | Show the current authenticated identity | [View docs](/cli/whoami) | | `logs` | Stream runtime logs for an Alpic environment | [View docs](/cli/logs) | | `insights intent list` | List grouped user intents for an environment | [View docs](/cli/insights-intent-list) | | `insights feedback list` | List user feedback for an environment | [View docs](/cli/insights-feedback-list) | | `insights category list` | List intent categories for an environment | [View docs](/cli/insights-category-list) | | `insights category create` | Create an intent category | [View docs](/cli/insights-category-create) | | `insights category update` | Rename or recolor an intent category | [View docs](/cli/insights-category-update) | | `insights category delete` | Delete an intent category | [View docs](/cli/insights-category-delete) | | `insights category link` | Link an intent category to intents | [View docs](/cli/insights-category-link) | | `insights category unlink` | Unlink an intent category from intents | [View docs](/cli/insights-category-unlink) | | `git connect` | Link a project to a git remote repository | [View docs](/cli/git-connect) | | `git disconnect` | Unlink a project from its git remote repository | [View docs](/cli/git-disconnect) | | `environment-variable add` | Add one or more environment variables to an Alpic environment | [View docs](/cli/environment-variable-add) | | `environment-variable list` | List all environment variables for an Alpic environment | [View docs](/cli/environment-variable-list) | | `environment-variable remove` | Remove an environment variable from an Alpic environment | [View docs](/cli/environment-variable-remove) | | `environment-variable update` | Update the value and/or secret status of an existing environment variable | [View docs](/cli/environment-variable-update) | | `playground enable` | Enable the playground for an environment | [View docs](/cli/playground-enable) | | `playground disable` | Disable the playground for an environment | [View docs](/cli/playground-disable) | | `playground status` | Show playground configuration for an environment | [View docs](/cli/playground-status) | | `playground configure` | Set the playground server name and description | [View docs](/cli/playground-configure) | | `playground example-prompt add` | Add an example prompt to the playground (max 5) | [View docs](/cli/playground-example-prompt-add) | | `playground example-prompt list` | List playground example prompts for an environment | [View docs](/cli/playground-example-prompt-list) | | `playground example-prompt remove` | Remove an example prompt from the playground | [View docs](/cli/playground-example-prompt-remove) | | `playground headers add` | Add a header to the playground configuration | [View docs](/cli/playground-headers-add) | | `playground headers list` | List playground headers for an environment | [View docs](/cli/playground-headers-list) | | `playground headers remove` | Remove a playground header | [View docs](/cli/playground-headers-remove) | | `telemetry enable` | Opt this machine into anonymous CLI usage reporting | [View docs](/cli/telemetry-enable) | | `telemetry disable` | Opt this machine out of anonymous CLI usage reporting | [View docs](/cli/telemetry-disable) | | `telemetry status` | Show the current telemetry setting and anonymous machine ID | [View docs](/cli/telemetry-status) | | `tunnel` | Expose a local server to the internet through an Alpic tunnel | [View docs](/cli/tunnel) | # playground configure Source: https://docs.alpic.ai/cli/playground-configure Set the playground server name and description Sets the display name and description shown in the Alpic playground for an environment. ## Usage ```bash theme={null} alpic playground configure ``` Prompts for a name and description interactively. ## Extended Usage **Set name and description non-interactively:** ```bash theme={null} alpic playground configure --name "My Server" --description "A helpful MCP server" ``` **Configure a specific environment:** ```bash theme={null} alpic playground configure --environment-id --name "My Server" --description "A helpful MCP server" ``` ## Options | Flag | Description | | ------------------- | ------------------------------------------------------------------------ | | `--environment-id` | The ID of the environment (optional — read from local config if omitted) | | `--name` | The server name (max 100 characters) | | `--description` | The server description (max 500 characters) | | `--non-interactive` | Disable interactive prompts. Requires `--name` and `--description`. | When running from a directory linked to an Alpic project, `--environment-id` is optional — the CLI reads it from the local `.alpic` config file. # playground disable Source: https://docs.alpic.ai/cli/playground-disable Disable the playground for an environment Disables the Alpic playground for a given environment. ## Usage ```bash theme={null} alpic playground disable ``` Disables the playground for the environment linked to the current directory. ## Extended Usage **Disable the playground for a specific environment:** ```bash theme={null} alpic playground disable --environment-id ``` ## Options | Flag | Description | | ------------------ | ------------------------------------------------------------------------ | | `--environment-id` | The ID of the environment (optional — read from local config if omitted) | When running from a directory linked to an Alpic project, `--environment-id` is optional — the CLI reads it from the local `.alpic` config file. # playground enable Source: https://docs.alpic.ai/cli/playground-enable Enable the playground for an environment Enables the Alpic playground for a given environment, making it accessible to users. ## Usage ```bash theme={null} alpic playground enable ``` Enables the playground for the environment linked to the current directory. ## Extended Usage **Enable the playground for a specific environment:** ```bash theme={null} alpic playground enable --environment-id ``` ## Options | Flag | Description | | ------------------ | ------------------------------------------------------------------------ | | `--environment-id` | The ID of the environment (optional — read from local config if omitted) | When running from a directory linked to an Alpic project, `--environment-id` is optional — the CLI reads it from the local `.alpic` config file. # playground example-prompt add Source: https://docs.alpic.ai/cli/playground-example-prompt-add Add an example prompt to the playground Adds an example prompt to the Alpic playground for an environment. A maximum of 5 example prompts can be added per environment. ## Usage ```bash theme={null} alpic playground example-prompt add ``` Prompts for a title and prompt text interactively. ## Extended Usage **Add an example prompt non-interactively:** ```bash theme={null} alpic playground example-prompt add --title "Hello" --prompt "Say hello to the user" ``` **Add a prompt to a specific environment:** ```bash theme={null} alpic playground example-prompt add --environment-id --title "Hello" --prompt "Say hello to the user" ``` ## Options | Flag | Description | | ------------------- | ------------------------------------------------------------------------ | | `--environment-id` | The ID of the environment (optional — read from local config if omitted) | | `--title` | The example prompt title (max 100 characters) | | `--prompt` | The example prompt text (max 500 characters) | | `--non-interactive` | Disable interactive prompts. Requires `--title` and `--prompt`. | Each environment supports a maximum of 5 example prompts. When running from a directory linked to an Alpic project, `--environment-id` is optional — the CLI reads it from the local `.alpic` config file. # playground example-prompt list Source: https://docs.alpic.ai/cli/playground-example-prompt-list List playground example prompts for an environment Lists all example prompts configured for the Alpic playground in a given environment. ## Usage ```bash theme={null} alpic playground example-prompt list ``` Lists example prompts for the environment linked to the current directory. ## Extended Usage **List example prompts for a specific environment:** ```bash theme={null} alpic playground example-prompt list --environment-id ``` ## Options | Flag | Description | | ------------------ | ------------------------------------------------------------------------ | | `--environment-id` | The ID of the environment (optional — read from local config if omitted) | When running from a directory linked to an Alpic project, `--environment-id` is optional — the CLI reads it from the local `.alpic` config file. # playground example-prompt remove Source: https://docs.alpic.ai/cli/playground-example-prompt-remove Remove an example prompt from the playground Removes an example prompt from the Alpic playground for an environment. ## Usage ```bash theme={null} alpic playground example-prompt remove ``` Prompts to select an example prompt to remove interactively. ## Extended Usage **Remove a specific example prompt non-interactively:** ```bash theme={null} alpic playground example-prompt remove --title "Hello" ``` **Remove a prompt from a specific environment:** ```bash theme={null} alpic playground example-prompt remove --environment-id --title "Hello" ``` ## Options | Flag | Description | | ------------------- | ------------------------------------------------------------------------ | | `--environment-id` | The ID of the environment (optional — read from local config if omitted) | | `--title` | The title of the example prompt to remove | | `--non-interactive` | Disable interactive prompts. Requires `--title`. | When running from a directory linked to an Alpic project, `--environment-id` is optional — the CLI reads it from the local `.alpic` config file. # playground headers add Source: https://docs.alpic.ai/cli/playground-headers-add Add a header to the playground configuration Adds a custom HTTP header definition to the Alpic playground for an environment. Headers can be marked as required or secret to control how users provide them when accessing the playground. ## Usage ```bash theme={null} alpic playground headers add ``` Prompts for header details interactively. ## Extended Usage **Add a required secret header non-interactively:** ```bash theme={null} alpic playground headers add --name "X-Api-Key" --description "API key for authentication" --required --secret ``` **Add an optional, visible header:** ```bash theme={null} alpic playground headers add --name "X-Tenant-Id" --description "Tenant identifier" --no-required --no-secret ``` **Add a header to a specific environment:** ```bash theme={null} alpic playground headers add --environment-id --name "X-Api-Key" --description "API key for authentication" --required --secret ``` ## Options | Flag | Description | | ------------------- | ------------------------------------------------------------------------ | | `--environment-id` | The ID of the environment (optional — read from local config if omitted) | | `--name` | The header name (max 100 characters) | | `--description` | The header description (max 200 characters) | | `--required` | Whether the header is required. Use `--no-required` to make it optional | | `--secret` | Whether the header value is secret. Use `--no-secret` to keep it visible | | `--non-interactive` | Disable interactive prompts. Requires `--name` and `--description`. | When running from a directory linked to an Alpic project, `--environment-id` is optional — the CLI reads it from the local `.alpic` config file. # playground headers list Source: https://docs.alpic.ai/cli/playground-headers-list List playground headers for an environment Lists all custom HTTP headers configured for the Alpic playground in a given environment. ## Usage ```bash theme={null} alpic playground headers list ``` Lists headers for the environment linked to the current directory. ## Extended Usage **List headers for a specific environment:** ```bash theme={null} alpic playground headers list --environment-id ``` ## Options | Flag | Description | | ------------------ | ------------------------------------------------------------------------ | | `--environment-id` | The ID of the environment (optional — read from local config if omitted) | When running from a directory linked to an Alpic project, `--environment-id` is optional — the CLI reads it from the local `.alpic` config file. # playground headers remove Source: https://docs.alpic.ai/cli/playground-headers-remove Remove a playground header Removes a custom HTTP header from the Alpic playground configuration for an environment. ## Usage ```bash theme={null} alpic playground headers remove ``` Prompts to select a header to remove interactively. ## Extended Usage **Remove a specific header non-interactively:** ```bash theme={null} alpic playground headers remove --name "X-Api-Key" ``` **Remove a header from a specific environment:** ```bash theme={null} alpic playground headers remove --environment-id --name "X-Api-Key" ``` ## Options | Flag | Description | | ------------------- | ------------------------------------------------------------------------ | | `--environment-id` | The ID of the environment (optional — read from local config if omitted) | | `--name` | The name of the header to remove | | `--non-interactive` | Disable interactive prompts. Requires `--name`. | When running from a directory linked to an Alpic project, `--environment-id` is optional — the CLI reads it from the local `.alpic` config file. # playground status Source: https://docs.alpic.ai/cli/playground-status Show playground configuration for an environment Displays the current playground configuration for an environment, including enabled state, name, description, example prompts, and headers. ## Usage ```bash theme={null} alpic playground status ``` Shows playground configuration for the environment linked to the current directory. ## Extended Usage **Show status for a specific environment:** ```bash theme={null} alpic playground status --environment-id ``` ## Options | Flag | Description | | ------------------ | ------------------------------------------------------------------------ | | `--environment-id` | The ID of the environment (optional — read from local config if omitted) | When running from a directory linked to an Alpic project, `--environment-id` is optional — the CLI reads it from the local `.alpic` config file. # project inspect Source: https://docs.alpic.ai/cli/project-inspect Show details of a project and its environments Displays detailed information about a project, including its ID, name, team, runtime, transport, repository, build settings, and creation date. Also lists all environments belonging to the project. ## Usage ```bash theme={null} alpic project inspect --project-id ``` Shows details of the specified project and its environments. ## Extended Usage Inspect a project by name: ```bash theme={null} alpic project inspect --project-name ``` When no project identifier is provided, you will be prompted to select a project interactively: ```bash theme={null} alpic project inspect ``` ## Options | Flag | Description | Default | | ------------------- | ------------------------------------------------------------------------- | ------- | | `--project-id` | The ID of the project. | — | | `--project-name` | The name of the project. | — | | `--non-interactive` | Disable interactive prompts. Requires `--project-id` or `--project-name`. | `false` | # project list Source: https://docs.alpic.ai/cli/project-list List projects Lists all projects accessible to the authenticated user, showing their ID, name, runtime, source repository, and creation date. ## Usage ```bash theme={null} alpic project list ``` Lists all projects across all teams. ## Extended Usage Filter projects by team: ```bash theme={null} alpic project list --team-id ``` ## Options | Flag | Description | Default | | ------------------- | --------------------------- | ------- | | `--team-id` | Filter by team ID | — | | `--non-interactive` | Disable interactive prompts | `false` | # publish Source: https://docs.alpic.ai/cli/publish Publish your MCP server to the MCP registry Publish an MCP server project to the MCP registry, making it discoverable to users. ## Usage ```bash theme={null} alpic publish ``` Prompts for any missing information (domain, title, description) if not already provided. ## Extended Usage Skip all prompts (useful in CI): ```bash theme={null} alpic publish --non-interactive --domain my.domain.com --title 'My Server' --description 'Does things' ``` Publish a specific project by ID: ```bash theme={null} alpic publish --project-id ``` Publish a project by name: ```bash theme={null} alpic publish --project-name ``` ## Options | Flag | Description | | ------------------- | ------------------------------------- | | `--non-interactive` | Skip all prompts | | `--domain` | Domain to publish for | | `--title` | Server title (1–100 characters) | | `--description` | Server description (1–100 characters) | | `--website-url` | Website URL | | `--icon-src` | Icon URL | | `--project-id` | The ID of the project. | | `--project-name` | The name of the project. | Authentication is required. Run `alpic login` or set `ALPIC_API_KEY` before publishing. Learn how to publish your MCP server to the official MCP Registry from your Alpic dashboard. # team inspect Source: https://docs.alpic.ai/cli/team-inspect Show details of a team and its projects Displays detailed information about a team, including its ID, name, Stripe account status, current usage, and creation date. Also lists all projects belonging to the team. ## Usage ```bash theme={null} alpic team inspect --team-id ``` Shows details of the specified team and its projects. When no `--team-id` is provided, you will be prompted to select a team interactively. ```bash theme={null} alpic team inspect ``` ## Request usage The `Usage` row reports the MCP requests settled during the team's current billing window, against the allowance included in its plan: ``` Usage 4,231 / 200,000 requests (resets in 12 days) ``` Plans with no published allowance report the count alone — `4,231 requests (resets in 12 days)`. ## Options | Flag | Description | Default | | ------------------- | --------------------------- | ------- | | `--team-id` | The ID of the team | — | | `--non-interactive` | Disable interactive prompts | `false` | # team list Source: https://docs.alpic.ai/cli/team-list List teams for the current user Lists all teams the authenticated user belongs to, showing their ID, name, and creation date. ## Usage ```bash theme={null} alpic team list ``` Lists all teams for the current user. ## Options | Flag | Description | Default | | ------------------- | --------------------------- | ------- | | `--non-interactive` | Disable interactive prompts | `false` | # telemetry disable Source: https://docs.alpic.ai/cli/telemetry-disable Disable anonymous CLI telemetry on this machine Opts this machine out of anonymous CLI usage reporting. The setting is saved to `~/.alpic/config.json`. ## Usage ```bash theme={null} alpic telemetry disable ``` Disables telemetry and saves the preference locally. ## Options This subcommand has no flags. Telemetry can also be disabled without running this command by setting `ALPIC_TELEMETRY_DISABLED=1` or `DO_NOT_TRACK=1` in your environment. Alpic never collects Personally Identifiable Information (PII). # telemetry enable Source: https://docs.alpic.ai/cli/telemetry-enable Enable anonymous CLI telemetry on this machine Opts this machine into anonymous CLI usage reporting. The setting is saved to `~/.alpic/config.json`. ## Usage ```bash theme={null} alpic telemetry enable ``` Enables telemetry and saves the preference locally. ## Options This subcommand has no flags. Alpic never collects Personally Identifiable Information (PII). Telemetry only covers anonymous CLI usage patterns (commands run, outcomes, platform info). # telemetry status Source: https://docs.alpic.ai/cli/telemetry-status Show anonymous CLI telemetry settings for this machine Prints the current telemetry setting (enabled or disabled) and the anonymous machine ID used for reporting. ## Usage ```bash theme={null} alpic telemetry status ``` Displays whether telemetry is enabled and the machine ID assigned to this installation. ## Options This subcommand has no flags. ## Environment Variables | Variable | Description | | ---------------------------- | ------------------------------------------------- | | `ALPIC_TELEMETRY_DISABLED=1` | Disables telemetry regardless of the saved config | | `DO_NOT_TRACK=1` | Disables telemetry regardless of the saved config | | `ALPIC_TELEMETRY_DEBUG=1` | Enables debug output for telemetry events | # tunnel Source: https://docs.alpic.ai/cli/tunnel Expose a local server to the internet through an Alpic tunnel Open a tunnel from your local machine so your MCP server is reachable at a public `https` URL. The tunnel stays open until you press Ctrl+C. ## Usage ```bash theme={null} alpic tunnel --port 3000 ``` Requests to the assigned URL (e.g. `https://superb-marmot-fondue-420.alpic.dev`) are forwarded to `http://localhost:3000` on your machine. Your subdomain is stable and unique to your account — you'll get the same URL every time. ## Playground Test your local MCP server *in situ* using the [playground](/testing/playground) — a real LLM chat interface. Access it at `/try` on your tunnel URL (e.g. `https://superb-marmot-fondue-420.alpic.dev/try`). ## Options | Flag | Description | | -------- | -------------------- | | `--port` | Local port to tunnel | Team API keys are not supported for this command. User OAuth authentication is required. # whoami Source: https://docs.alpic.ai/cli/whoami Show the current Alpic identity Prints information about the currently authenticated identity. Works for both browser-based OAuth sessions and API key authentication. ## Usage ```bash theme={null} alpic whoami ``` Displays the authenticated user name and email (OAuth) or the team name (API key). ## Extended Usage ```bash theme={null} # Verify authentication before running a deployment alpic whoami alpic deploy ``` If the command reports that you are not logged in, run `alpic login` or set the `ALPIC_API_KEY` environment variable. ## Options This command has no flags. # API Source: https://docs.alpic.ai/developer-tools/api Alpic REST API See the full [API reference](/api-reference). # CLI Source: https://docs.alpic.ai/developer-tools/cli Alpic command-line interface See the full [CLI reference](/cli/overview). # Alpic MCP Server Source: https://docs.alpic.ai/developer-tools/mcp Manage your projects, debug deployment, and check analytics for any MCP server you host with Alpic ### Overview The Alpic MCP Server is a hosted MCP server at `mcp.alpic.ai` that lets you interact with your Alpic account from any MCP-compatible client. You can browse teams and projects, inspect deployment logs, and review analytics. ### Available Tools | Tool | Description | | ----------------- | ------------------------------------------------------------------- | | `list-teams` | List all teams you belong to. | | `list-projects` | List all projects for a given team. | | `deployment-logs` | Fetch deployment logs for a specific project and environment. | | `get-analytics` | Retrieve analytics data (sessions, requests, errors) for a project. | #### Project Browser Widget The `list-projects` tool returns a widget that displays your projects as interactive cards. Each card shows the project name, environment status, and key analytics at a glance. The widget supports both inline and fullscreen display modes so you can quickly scan your projects or dive deeper into a specific one. Analytics widget ### Try it in the Playground The fastest way to explore the Alpic MCP Server is the built-in [Playground](/distribution/playground) at [`mcp.alpic.ai/try`](https://mcp.alpic.ai/try). It runs a full MCP client in your browser, so you can chat with the tools through a conversational AI interface — no client setup required. Sign in with your Alpic account and start exploring the tools. Connection instructions for other MCP clients are detailed directly in the [Playground](/testing/playground). ### Clients supporting MCP Apps Our MCP Server is using the MCP Apps extension that allows rendering of rich UI interfaces through custom Views. When used with MCP Apps compatible clients, it provides interactive visual components alongside the standard tool responses. Install the official app directly: * **ChatGPT** — [Alpic on the ChatGPT app directory](https://chatgpt.com/apps/alpic/asdk_app_6996e5762c508191846b87c57edbbebe) * **Claude** — [Alpic on the Claude directory](https://claude.ai/directory/3a931cc2-bfb7-463f-a2a5-dea7d1254d1e) # Domains Source: https://docs.alpic.ai/distribution/domains Connect your MCP server to your domain Alpic supports custom domains (CNAMEs) for your MCP servers, allowing you to use your own domain name instead of the default Alpic one. This feature enables you to maintain your brand identity and provide a more professional experience for your users. Custom domains are available only on the Pro plan and above. ## Activating Custom CNAMEs To activate a custom CNAME for your MCP server environment, follow these steps: In your Alpic dashboard, go to your Project **Settings** tab. In the Settings page, navigate to the **Domains** section. You will see the list of domains you have added for your project. Click on **Add** to add a new domain. Enter your custom domain name and select the environment you want to configure. The CNAME records you need to add to your DNS provider will be displayed in the modal. Add domain name form Add domain name form Before validating the new domain name in Alpic, configure your DNS provider to point your domain to the Alpic endpoint as shown above. Once you have added the DNS records required to link the domain name to Alpic, you can validate it by clicking on **Save & Deploy**. It usually takes a few minutes for Alpic to validate the domain name addition. You can check the custom domain status in the Domains section as shown below. CNAMES configuration in Settings CNAMES configuration in Settings Currently, we don't support root domains (e.g., example.com) or wildcard domains (e.g., \*.example.com). ## Routing multiple environments on one domain A single custom domain can serve **multiple environments of the same project** at once, each mounted under its own path prefix. This lets you advertise multiple versions of your server side by side on the same domain. It's very handy if you deploy tenant-specific versions of your server (configured by environment variables) or want to version your app for hosts that implement metadata caching (like ChatGPT and Claude). The mapping is flexible: the same environment can be served under several path prefixes if you want to expose it on more than one route. ### Editing a domain's environment mappings In your Project **Settings** → **Domains** section, click the **edit** (pencil) button next to the domain you want to configure. Each row maps one **environment** to one **path prefix**. Leave the path prefix empty to serve that environment on the root path, or enter a prefix such as `v1` to serve it under `/v1`. Edit domain environment mappings Edit domain environment mappings Use **Add mapping** to route another environment under a new prefix, or the trash icon to remove a mapping. A domain must keep at least one mapping. Click **Save** to apply your changes. Updates are live immediately and may take up to a minute to propagate. **Path prefix rules**: each prefix must be unique within the domain and be a single URL-safe path segment (letters, numbers and `-._~`, no slashes, up to 63 characters). The prefixes `mcp`, `oauth2`, `.well-known`, `assets`, `try` and `health-check` are reserved, because they collide with the routes served on the root path. This is the recommended way to publish a new version without breaking an existing deployment on the same domain. See [Versioning](/distribution/versioning#serving-multiple-versions-on-one-domain) for the full workflow. ## Cloudflare users If your domain is managed by Cloudflare, make sure the CNAME record is set to **DNS only** (gray cloud icon) — not **Proxied** (orange cloud). When the Cloudflare proxy is enabled, Cloudflare intercepts traffic and replaces your CNAME with its own anycast IPs in public DNS. Alpic's infrastructure (powered by AWS CloudFront) validates the CNAME at registration time, and will fail to verify ownership if the record is proxied. Adding a domain will fail with a DNS configuration error if the Cloudflare proxy is enabled on the CNAME record. Keep the record set to **DNS only** while saving — you can re-enable the proxy afterwards only if you intend to route traffic through Cloudflare rather than directly to Alpic. # Playground Source: https://docs.alpic.ai/distribution/playground Let users try your MCP server directly from their browser with an AI-powered playground. When you host an MCP server on Alpic, you automatically get a **Playground** accessible at the `/try` path of your server URL. It lets anyone try your server instantly with an AI agent, and provides all the information needed to connect it to their favorite AI client. Use the Playground to quickly test your app in a production environment, share it with your team for testing and feedback, or showcase your MCP App to external users and guide them through the install process in their favorite AI client. For example, if your server URL is `https://my-server.alpic.live`, the playground is available at `https://my-server.alpic.live/try`. Alpic Playground If you've configured a [custom domain](/distribution/domains), the playground will be available at `https://your-custom-domain.com/try`. Open the Everything App playground to see all features in action — MCP Apps, ChatGPT App widgets, tool execution, and more. ## What the Playground offers The playground is a full-featured MCP client running in the browser. It includes: * **AI-powered chat** — Users can interact with your MCP server through a conversational interface powered by a leading LLM. You can [choose which model](#model-selection) powers the playground. * **Tool execution** — All your MCP tools are listed in the sidebar and can be called by the AI during the conversation. * **MCP App & ChatGPT App rendering** — If your tools return [MCP Apps](https://modelcontextprotocol.io/extensions/apps/overview) or [ChatGPT App widgets](https://platform.openai.com/docs/plugins/actions/rendering-output), they are rendered directly in the chat with support for inline, fullscreen, picture-in-picture, and modal display modes. * **Installation guide** — A built-in modal shows step-by-step instructions to connect your server to 10 different AI clients. Each tab includes copyable code snippets with your server URL pre-filled, so users can get started in seconds. ## Credits Each team on Alpic receives **\$5 of free credits** to power playground conversations. Credits are shared across all projects within the team. When credits run out, playground users will see a message asking to contact support. Credits are tracked per team and deducted after each AI response. The amount deducted depends on the [model](#model-selection) in use — more capable models consume credits faster. ## Configuring the Playground You can customize the playground experience from the **Distribution > Alpic Playground** section of your project in the Alpic dashboard. ### Enable or disable The playground is **enabled by default** for all environments. You can toggle it off if you don't want to expose the `/try` page. ### Model selection Choose which AI model powers the playground from the **model dropdown** next to the enable toggle. The selected model handles every conversation in that environment and takes effect immediately. Available models: * **Claude Haiku 4.5** *(default)* — Anthropic's fast, cost-efficient model. A good default for quick testing and demos. * **Claude Sonnet 4.5** — Anthropic's more capable model for complex reasoning and tool use. * **GPT-5.4** — OpenAI model. * **GPT-5.5** — OpenAI's latest model. More capable models produce higher-quality responses but consume [credits](#credits) faster. Claude Haiku 4.5 is the most economical choice for high-traffic playgrounds. ### Edit Playground settings Click **Edit Playground** to configure: * **Server name** — Displayed in the playground header (1–100 characters). * **Server description** — Shown on the welcome screen and provided to the AI as context so it understands what your server does (1–500 characters). * **Example prompts** (up to 5) — Quick-start suggestions shown on the welcome screen. Each prompt has a title and a message that gets sent when clicked. **Example prompts are a great way to onboard new users.** They guide visitors toward the most valuable features of your server right from the first interaction. Pick prompts that showcase what makes your MCP server unique. Distribution configuration ### Custom headers If your MCP server requires authentication or custom parameters, you can declare **custom headers** in the playground settings: * **Required headers** — Users must fill them in before they can send messages. A red indicator appears when required headers are missing. * **Secret headers** — Displayed as password fields so sensitive values are not visible on screen. # Publishing Source: https://docs.alpic.ai/distribution/publishing How to distribute your MCP server to the world ## Publishing to the Official MCP Registry Alpic supports direct publishing to the [official MCP Registry](https://registry.modelcontextprotocol.io/). This is the recommended way to make your MCP server discoverable in the ecosystem. Learn how to publish your MCP server directly to the official MCP Registry from your Alpic dashboard. ## Adding your MCP Server to other registries and app stores In addition to the official MCP Registry, you can submit your MCP server to other popular MCP registries and stores. | Registry | Type | Submission Process | Link | | ------------------- | --------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | **Claude** | Official | Approval process by Anthropic | [Submit Form](https://docs.google.com/forms/d/e/1FAIpQLSeafJF2NDI7oYx1r8o0ycivCSVLNq92Mpc1FPxMKSw1CzDkqA/viewform) | | **OpenAI** | Official | Official OpenAI ChatGPT App Store | Coming soon | | **VSCode Registry** | Official | Now linked to Official MCP Registry | N/A | | **Pulse MCP** | Community | Now linked to Official MCP Registry | N/A | | **Goose Registry** | Official | GitHub discussion submission | [GitHub Discussion](https://github.com/block/goose/discussions/2075) | | **Cursor** | Official | Direct submission to Cursor's registry | [Submit Form](https://anysphere.typeform.com/to/DX0Pjqgb?typeform-source=docs.cursor.com) | When submitting to these registries, make sure to provide clear descriptions, installation instructions, and examples of your MCP server's capabilities. ## Generating MCP Client Install Instructions You can also distribute your MCP server directly to your users using our [MCP Install Instructions Generator](https://mcp-install-instructions.alpic.cloud/). It allows you to generate a complete tutorial and 1-click install links for the most popular MCP clients. See how the Kiwi Flight Search MCP server is distributed with complete installation instructions for all major MCP clients. The submission process and requirements may vary between registries. Always check the specific requirements for each registry before submitting. # Registry Source: https://docs.alpic.ai/distribution/registry Publish your MCP server to the official MCP Registry Alpic allows you to publish your MCP server directly to the official [MCP Registry](https://registry.modelcontextprotocol.io/). Having your server listed on the registry provides several benefits: * **Discoverability:** Makes it easier for people and AI agents to find your server from a single, authoritative source of the MCP ecosystem. * **Subregistry distribution:** The registry feeds into subregistries like [GitHub MCP](https://github.com/mcp), [Pulse MCP](https://www.pulsemcp.com/) and more. * **Standardization:** Your server gets a valid `server.json`, ensuring compatibility across MCP clients. Published servers follow the MCP Registry [server.json schema](https://static.modelcontextprotocol.io/schemas/2025-10-17/server.schema.json). Alpic automatically generates and maintains this file for you. ## Publishing Your Server In your Alpic dashboard, go to your Project and click on the **Publishing** tab. The MCP Registry card shows your current publishing status: - If you haven't published yet, you'll see "No published version yet" - If you've published before, you'll see your latest published version with a link to view it on the MCP Registry Click the **New Version** button to open the publishing dialog. Complete the required fields for your server: | Field | Required | Description | | --------------- | -------- | -------------------------------------------------------------------------------- | | **Title** | Yes | A human-readable name for your server (max 100 characters) | | **Description** | Yes | A brief description of what your server does (max 100 characters) | | **Website URL** | No | Link to your server's documentation or homepage | | **Icon URL** | No | URL to a 200×200 pixel icon image for your server (png format) | | **Headers** | No | The specific headers required by your MCP server, often used for authentication. | If your server requires additional headers (e.g. API key authentication), you can configure them in the optional fields section. For each header, specify: * **Name:** The HTTP header name (e.g., `Authorization`, `X-API-Key`) * **Description:** Explain what this header is for (can be displayed to the user when installing your server from the registry). If you are requiring an API key, you can add the URL to get one here. * **Required:** Whether users must provide this header when installing your server from the registry * **Secret:** Whether the value should be treated as sensitive data Review the JSON preview showing your server.json file, then click **Publish** to submit your server to the registry. Once published, your server will be available on the [MCP Registry](https://registry.modelcontextprotocol.io/). You can click "View on MCP Registry →" to see your server listed there. Registry publishing is only available for the **Production** environment of your project. ## Additional Notes ### Server Naming Convention When you publish to the registry, your server is automatically named using the reverse domain notation: ``` {reversed-domain}/{project-name} ``` For example, if your production domain is `mcp.example.com` and your project is named `my-server`, the registry name will be: ``` com.example.mcp/my-server ``` This naming convention ensures uniqueness and clear ownership of servers in the registry. ### Version Management Alpic uses [semantic versioning](https://semver.org/) (semver) for registry publishing. Each time you publish: * The version number is automatically incremented (patch version) * Your first publication starts at version `0.0.1` * Subsequent publications increment: `0.0.1` → `0.0.2` → `0.0.3`, etc. Only semantic versioning is supported. If your existing server.json has a non-semver version, you'll need to update it before publishing. ### Publishing with a Custom Domain If you have [custom domains](/distribution/domains) configured for your production environment, you can publish your server under any of your verified domains. When you have multiple domains, you'll see tabs in the Publishing section allowing you to manage registry entries for each domain separately. ## Next Steps Learn about other distribution options beyond the MCP Registry. # Updating a published app Source: https://docs.alpic.ai/distribution/versioning Safely roll out changes to your workloads on ChatGPT and Claude.ai ## Why versioning matters Most hosts cache some of your MCP workload responses when your submission is accepted. Knowing which response is cached and which isn't tells you whether a change ships immediately or needs a new submission. **Cached at submission (frozen until you submit a new version):** * **`tools/list` response**: tool descriptions, annotations and input/output schemas, on all workloads. * **`resources/read` response**: the views entrypoint HTML, on MCP apps specifically. Everything else reaches your server on every user interaction (an actual `tools/call`, for example) and runs your latest deployment. This split is what makes versioning tricky: say you deploy an update that adds a required input parameter to a tool. The host still sources its input schema from the cached `tools/list`, so it fires a `tools/call` without the new parameter. However, your freshly deployed handler now expects it and rejects the request with a validation error. All calls to this tool now fail, with no possible recovery other than reverting your deployment. You just broke your production workload. In order to avoid this scenario, the following table summarizes how to handle the most common operations safely. All recommended migration paths keep host knowledge of your server and your actual service deployment compatible. ## Operation-specific migration paths ### For all workloads | Operation | How to prepare | How to release | Notes | | ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Add a new tool | Add the tool | Submit a new version | The tool stays invisible to the host until you submit. | | Remove a tool | Add `_meta.ui.visibility: ["app"]` on your tool description | Submit a new version | Do not remove your tool altogether. It is still referenced in the cached `tools/list` on hosts and will keep being called by the model until you submit a new version. You can safely remove it after this revised version has been submitted. | | Add a new param in an existing tool | Add the param in the input schema, but make it optional | Submit a new version | Do not add a required param. Your handler is updated right away with the new requirement, but hosts won't be aware of it until a new release is made and will fail all input validation on your tool. | | Update a param in an existing tool | Keep changes backward compatible: relax validation, don't tighten it, and avoid renaming. Widen accepted values rather than narrowing them | Submit a new version | Hosts validate inputs against the cached schema. If you tighten validation (e.g. make an optional param required, add new constraints) before resubmitting, the host keeps sending values your handler now rejects. | | Remove a param in an existing tool | Stop reading the param in your handler, but keep accepting it (leave it optional in the input schema) | Submit a new version | The model keeps sending the param while the host references the cached `tools/list`. Removing it from the input schema before resubmitting can cause input validation to fail. | ### For MCP apps specifically | Operation | How to prepare | How to release | Notes | | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Add a new view | Add the view resource and reference it from the relevant tool's `_meta.ui.resourceUri` | Submit a new version | Both `tools/list` and `resources/read` are cached, so the host won't discover the new view until you submit. | | Update a view | To change view behavior or styling only, ship new assets under stable, deterministic names (see [Asset naming strategy](#asset-naming-strategy)) | Update the assets content. You only need a new submission to change the view entrypoint HTML | The `resources/read` entrypoint HTML is cached. With deterministic asset names you can ship updated assets without resubmitting, because the cached HTML keeps pointing at the same asset URLs. | | Remove a view | Remove the view and stop referencing it from your tools' `_meta`. Keep the referenced static assets available. | Submit a new version | The view is still referenced by the cached `tools/list` content, and the view content itself is still cached by the host. Removing them from your workload before you submit a new version therefore has no effect on the host. Just make sure the external public assets referenced by the view stay available. | ## Recommended release workflow We recommend using a **dedicated [environment](/build-deploy/environments)** for each version you submit to a host store. Because hosts freeze a snapshot of your workload at submission time, a dedicated environment with its dedicated URL gives you a stable, immutable target for each published version: * Your ongoing development on other environments never affects an already-submitted version. * You can keep shipping fixes to a submitted version (within the limits described above) without disturbing your next release. * When you want a clean break, you cut a new release against a new environment and submit it as a new version. Name your environments after the released version (for example `v1`, `v2`) so it stays obvious which environment backs which submission on each host. ### Serving multiple versions on one domain Some hosts, like ChatGPT, require you to **keep the same domain** when you publish a new version of your plugin. In order to be able to use a dedicated environment per version, you should leverage custom domains and advertise multiple versions of your app. You can map several environments of the same project onto a **single domain using path prefixes**. Each version keeps its own immutable environment (and therefore its own frozen submission snapshot), while sharing one public subdomain. You can satisfy the same-domain requirement without disturbing your existing deployment. Configure this from your Project **Settings** → **Domains** tab with the domain **edit** button (see [Routing multiple environments on one domain](/distribution/domains#routing-multiple-environments-on-one-domain)). For example, this is how Alpic routes its own MCP server: | URL | Environment | Purpose | | ------------------------- | ------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | | `https://mcp.alpic.ai` | Production (tracking `main`) | The default route we advertise for people installing our server themselves. | | `https://mcp.alpic.ai/v1` | `v1` (tracking the `v1` branch, patches only) | The version submitted to ChatGPT, kept stable and only receiving patches. | | `https://mcp.alpic.ai/v2` | `v2` (tracking `main`, will later move to tracking `v2` just before submitting) | The next version under review with OpenAI, carrying breaking `tools/list` and schema changes. | Keep the route you advertise to end users on the root path (empty prefix), and reserve versioned prefixes (`v1`, `v2`, …) for host submissions. Point each prefix at the environment whose branch matches that version's release line. ## Asset naming strategy For MCP apps, the `resources/read` response serves as the views entrypoint HTML. How your build pipeline bundles and references built assets directly determines your release strategy. TL;DR: Use **deterministic asset names within a released version and its fixes**. This lets you ship small updates to your views by simply redeploying, while the host serves the latest asset content from the stable URL it already cached. Next and previous versions use version-specific asset names and aren't affected. ### Inline assets in HTML All CSS and JS content is included in the `resources/read` content. You can't update the view behavior without a new submission. ### Assets bundled separately with unique names per build Your build pipeline produces content-hashed names that change on every build (`assets-fdsiucv7384.js` on the first build, then `assets-ytiroiu4253.js` on the next one). The cached entrypoint HTML keeps pointing at the old name, so a new deployment exposes assets the host will never download, and the old assets keep being served. You can't update the view behavior without a new submission. ### Assets bundled separately with deterministic, stable names Your build pipeline produces assets with names that stay the same across builds (always `assets.js`). The cached entrypoint HTML keeps pointing at the same URL, and a redeploy replaces the content served at that URL. Updated assets ship without resubmission: you control the application lifecycle through deployment, not submission. However, your changes then impact all existing views across all conversations. If you use a single environment for all your workload versions, make sure to keep deterministic names only **within** a single released version scope. You would otherwise risk breaking all existing views. See details below. Hosts don't just render a view once. To rebuild the conversation as the user scrolls, they persist the view's tool input, output, metadata and — depending on the host's capabilities — its view state in the conversation history. When an old view re-enters the viewport (for example, the user scrolls back in time or reopens an old conversation), the host **re-renders it by re-fetching the asset referenced in that turn's entrypoint HTML**. If you keep the same asset name across versions, that re-render pulls your **latest** asset code, but feeds it the **old** turn's input/output/metadata. The new asset expects the updated sidecar tool input/output schemas, so it ends up rendering against data shaped for a previous version — breaking or corrupting views in past conversations that were perfectly valid when they were created. Giving each released version its own asset names keeps every historical turn pinned to the asset it was built against, so old views keep rendering correctly while new views get the new code. # Deploy from GitLab CI Source: https://docs.alpic.ai/guides/deploy-from-gitlab-ci Deploy your MCP server from a GitLab CI/CD pipeline using the Alpic CLI ## Prerequisites In the [Alpic dashboard](https://app.alpic.ai), open your team and go to **API Keys** in the sidebar. Click **New API key**, name it, and copy the key. * **Project ID** : In your project, copy the project ID from **Settings** → **General**, - **Environment ID** : from the environment's card, in the **Environments** tab. In your GitLab project, go to **Settings** → **CI/CD** → **Variables** and add `ALPIC_API_KEY` (masked), `ALPIC_PROJECT_ID`, and `ALPIC_ENVIRONMENT_ID`. ## Configure the pipeline Add a deploy job to your `.gitlab-ci.yml`: ```yaml .gitlab-ci.yml theme={null} stages: - deploy deploy-alpic: stage: deploy image: node:24 script: - npx alpic@latest deploy --non-interactive --project-id "$ALPIC_PROJECT_ID" --environment-id "$ALPIC_ENVIRONMENT_ID" rules: - if: '$CI_COMMIT_BRANCH == "main"' ``` Every push to `main` now deploys to your Alpic environment. ## Deploy to multiple environments To target several environments (for example staging and production), extend a shared job and set the IDs per environment. Here production is a manual action: ```yaml .gitlab-ci.yml theme={null} .deploy-alpic: stage: deploy image: node:24 script: - npx alpic@latest deploy --non-interactive --project-id "$ALPIC_PROJECT_ID" --environment-id "$ALPIC_ENVIRONMENT_ID" deploy-staging: extends: .deploy-alpic environment: staging variables: ALPIC_PROJECT_ID: $ALPIC_STAGING_PROJECT_ID ALPIC_ENVIRONMENT_ID: $ALPIC_STAGING_ENV_ID rules: - if: '$CI_COMMIT_BRANCH == "main"' deploy-production: extends: .deploy-alpic environment: production variables: ALPIC_PROJECT_ID: $ALPIC_PROD_PROJECT_ID ALPIC_ENVIRONMENT_ID: $ALPIC_PROD_ENV_ID rules: - if: '$CI_COMMIT_BRANCH == "main"' when: manual allow_failure: true ``` Use `--project-id` and `--environment-id` rather than `--project-name` in CI: names can be changed, IDs are stable. See the `alpic deploy` reference [right here](/cli/deploy). # Deploy on Alpic Button Source: https://docs.alpic.ai/guides/work-with-deploy-button How to distribute your MCP server template Github repository to Alpic users ## How does it work? The **Deploy on Alpic** button allows users to deploy a new project through the Alpic Project creation flow, while cloning the source Git repository to their own GitHub namespace. It can be used to easily add a 1-click Alpic deployment option to your MCP framework, starter template or project. ## Add your own Deploy Button to your repository Use the snippets below in your Git repositories or your dashboards for users to deploy, replacing the repositoryUrl in the query parameter with your own public git repository URL. ```md Markdown theme={null} [![Deploy on Alpic](https://assets.alpic.ai/button.svg)](https://app.alpic.ai/new/clone?repositoryUrl=https://github.com/alpic-ai/mcp-server-template-nodejs) ``` ```html HTML theme={null} Deploy on Alpic ``` ```txt URL theme={null} https://app.alpic.ai/new/clone?repositoryUrl=https://github.com/alpic-ai/mcp-server-template-nodejs ``` The end-result should look like this: [![Deploy on Alpic](https://assets.alpic.ai/button.svg)](https://app.alpic.ai/new/clone?repositoryUrl=https://github.com/alpic-ai/mcp-server-template-nodejs) Currently, the Deploy on Alpic Button only supports GitHub repositories. # Welcome to Alpic! Source: https://docs.alpic.ai/index Alpic is an all-in-one MCP cloud platform where you can spin up servers, track them with AI-specific analytics, monitor everything, and ship to users without breaking a sweat. ## Getting started Get your MCP server up and running in minutes. Follow our step-by-step quickstart guide to deploy your first MCP server. ## Features Explore our platform functionalities. See how your MCP servers are performing and get insights on your users. Capture what users really ask for and collect model feedback directly from your MCP server. Set up your deployment environments and consult your MCP server logs. Secure your MCP server with Oauth or API keys. Use your own domain to access your MCP servers. Publish your MCP server to the official MCP Registry. Use Alpic's REST API to programmatically manage your MCP servers, teams, and projects. ## Guides Read our guides to see how to manage your teams and projects, as well as how to test and distribute your MCP servers. Learn how to test your MCP server before deploying to production. Learn how to distribute your MCP server to your users. Learn how to add a one-click deployment button to your repository. # Plans Source: https://docs.alpic.ai/pricing/plans Alpic pricing plans and what's included | | Free | Pro | Enterprise | | ----------------------- | --------------- | --------------- | ---------- | | **Price** | \$0/mo | \$30/mo | Custom | | **Requests** | 10,000/mo | 200,000/mo | Custom | | **Analytics retention** | 7 days | 30 days | Unlimited | | **Support** | Email & Discord | Email & Discord | Dedicated | | **Custom domains** | | Yes | Yes | | **OAuth DCR proxy** | | Yes | Yes | | **BYO Cloud** | | | Yes | All plans include Git-native CI/CD, MCP-native observability, and playground distribution. ## Analytics retention Retention defines how far back your [analytics](/analytics/overview) can go. Time ranges beyond your plan's retention appear locked in the dashboard, and upgrading unlocks longer ranges immediately. ## Overage Extra requests are billed at **\$150/million requests**. ## Enterprise For large-scale deployments requiring specialized support. [Contact us](mailto:support@alpic.ai) to learn more. # Request limit reached Source: https://docs.alpic.ai/pricing/request-limit-exceeded The error returned when a team on the Free plan has used every request it includes `request-limit-exceeded` is the Alpic reason code returned when a team on the Free plan has used every request that plan includes for the current billing period. Paid plans are never refused: requests beyond the included allowance are billed as [overage](/pricing/plans#overage). It is a stable identifier: match on it rather than on the message text, which may be reworded. This reason code is not returned today. Request limits are counted but not enforced. This page documents the response shape so clients can handle it before enforcement is turned on. ## The response The request is refused at admission. It never reaches your MCP server, and it is not counted against your plan. * **HTTP status**: `402 Payment Required` * **JSON-RPC error code**: `-32002` * **Alpic reason code**: `request-limit-exceeded`, under the reserved `alpic/reason` key ```json theme={null} { "jsonrpc": "2.0", "error": { "code": -32002, "message": "Request limit reached for the current billing period.", "data": { "alpic/reason": "request-limit-exceeded", "documentation": "https://docs.alpic.ai/pricing/request-limit-exceeded" } }, "id": null } ``` ## What counts as a request Every settled MCP request counts, whatever its outcome — including `initialize`, `tools/list` and `ping`. Because the check runs at admission, a refused request is not added to your count. The limit applies to the whole team, across every project and environment, for the current billing period. See [Plans](/pricing/plans) for the requests included in each plan and the overage rate. ## Handling it in a client `initialize` goes through the same check, so a Free-plan team over its limit fails at connection time. Most MCP clients render that as a generic "server unavailable" rather than showing the message, so treat a `402` on connect as a quota problem, not an outage. ## What to do Check the current period's usage against your allowance on your team's billing page in the [dashboard](https://app.alpic.ai), then move to a paid plan — see [Plans](/pricing/plans). Paid plans keep serving requests beyond their included allowance and bill the extra, so this reason code cannot be returned once you are on one. A new billing period starts your count again from zero. # Quickstart Source: https://docs.alpic.ai/quickstart Deploy your first MCP server on Alpic in minutes! ## Creating your first deployment 1. Go to [app.alpic.ai](https://app.alpic.ai). 2. Click on **Sign in with GitHub**. 3. Authorize **Alpic AI** to access your GitHub account. 1. Click on **New Project**. 2. You'll be asked to add the Alpic AI app to your GitHub organization. This connection enables seamless sync between deployments and your git workflow. 3. Click on **Add Github Account**. 4. Select the organization and repositories you want Alpic to access. 5. Click on **Install**. You can link several organizations to your Alpic account. 1. Choose the organization and repository containing your MCP server. 2. Click **Import**. If you don't have an existing MCP server repository yet, you can get started with one of our templates: - [Typescript template](https://app.alpic.ai/new/clone?repositoryUrl=https://github.com/alpic-ai/mcp-server-template-nodejs). - [Python template](https://app.alpic.ai/new/clone?repositoryUrl=https://github.com/alpic-ai/mcp-server-template-python). - [ChatGPT App template](https://app.alpic.ai/new/clone?repositoryUrl=https://github.com/alpic-ai/apps-sdk-template). 1. Choose which branch to sync with your main production environment. Alpic deploys a new version of your MCP server each time you push changes to this branch. 2. Specify the environment variables your MCP server needs. You can edit these later in your project settings. 3. Confirm the build commands used to build your MCP server. We automatically detect your MCP framework and build commands from your repository metadata, but you can customize them if needed: * **Build command:** Command to build your MCP server. * **Output directory:** Directory where the built files are located. * **Install command:** Dependencies installation command. 4. Click **Deploy** and you're done! 🚀 ## Your MCP server is deployed! What's next? Now that your MCP server is deployed, you can start using and testing it in your favorite MCP client. To learn more about how to test and distribute your MCP server, check out our guides: Learn how to host your ChatGPT App on Alpic. Test and debug your MCP server with the MCP inspector and connect it different MCP clients. Learn how to distribute your MCP server to your users. Learn about the Alpic internal endpoints and URLs exposed by your server. Also take a look at our additional features, like Authentication, Analytics, Custom Domains, and more. Track how your MCP servers are performing and get insights on your users. Learn what users really ask for and collect model feedback directly from your MCP server. Enable secure authentication with Dynamic Client Registration. Set up staging and development environments to preview and test new versions of your server. Use your own domain to access your MCP servers. Make your server discoverable in the official MCP ecosystem. Use Alpic's REST API to programmatically manage your MCP servers, teams, and projects. Learn how to add a one-click deployment button to your repository. # Dynamic Client Registration Proxy Source: https://docs.alpic.ai/secure/auth/dcr-proxy Understand how Alpic's in-house DCR proxy works and when you should use it ## What is Alpic's DCR proxy? MCP only support OAuth as an official authentication mechanism to protect servers. While most features required to make MCP work lives within OAuth 2.O, the protocol require a specific feature of OAuth 2.1: [Dynamic Client Registration (DCR)](https://datatracker.ietf.org/doc/html/rfc7591). Many identity providers (Auth0, Google, etc.) don't natively support DCR. Alpic bridges this gap with a **DCR proxy**: Alpic exposes a set of OAuth endpoints on top of your provider. When an MCP client connects to your server, it goes through Alpic endpoints which in turn use the OAuth metadata from your server. Alpic issues client credentials as part of the DCR spec. Only a single set of client credentials are in effective use from your auth provider perspective. We handle the complexity of keeping track of all OAuth client issued to use your MCP server. All those clients are stored in Alpic in a **client pool**. ## How it works 1. You create a **client pool** in your environment's authentication settings, providing the client ID, secret, and scopes of a single OAuth client you created on your identity provider. 2. Alpic advertises a `registration_endpoint` in your server's OAuth discovery metadata. 3. When an MCP client connects, it calls the registration endpoint and receives a unique `client_id` and `client_secret`. 4. The MCP client caches these credentials locally and uses them for all subsequent OAuth flows against your identity provider. 5. Under the hood, Alpic proxies all token requests through the single upstream client you configured. ## Managing your client pool You can **create**, **update**, or **delete** your client pool from the **Settings → Authentication** tab of your project. * **Create** — set up the DCR proxy for the first time by providing your upstream client credentials. In order to have the option to setup your DCR proxy, your MCP server must reference itself as the issuer and lack a registration\_endpoint.s * **Update** — change the client ID, secret, or scopes. This is safe for existing MCP clients as their issued credentials remain valid. * **Delete** — remove the client pool entirely. This is a destructive action with consequences detailed below. ## Impact of deleting the client pool Deleting a client pool is an irreversible operation that will break existing MCP client connections. When you delete a client pool: * **All dynamic client registrations are permanently removed.** Every `client_id` / `client_secret` pair that was issued to MCP clients ceases to exist on Alpic's side. * **MCP clients still hold their cached credentials.** The MCP OAuth specification mandates that clients cache their registration credentials locally. Alpic cannot invalidate or revoke those cached values. * **Reconnection attempts will fail.** When an MCP client tries to reconnect using its cached credentials, the token exchange will fail because Alpic no longer recognizes the client. * **The registration endpoint disappears.** Your server's OAuth discovery metadata will no longer advertise a `registration_endpoint`, so new clients cannot register via DCR until a new pool is created. ### When is it safe to delete? | Scenario | Safe? | Why | | ------------------------------------------------------ | ----- | ------------------------------------------------------------------------ | | Your server has never been used by an MCP client | ✅ | No credentials have been issued | | You are decommissioning the server entirely | ✅ | No future connections are expected | | You are switching to an IdP that natively supports DCR | ✅ | You'll remove the proxy in favor of your IdP's own registration endpoint | | Your server has active users | ❌ | Existing clients will break — update the pool instead | If you need to rotate credentials or change identity providers, **update your client pool** rather than deleting it. Updating preserves all existing dynamic client registrations — only the upstream OAuth client credentials change. MCP clients will continue authenticating without interruption. # OAuth Providers Source: https://docs.alpic.ai/secure/auth/oauth-providers List of popular Identity Providers (IdP) and their corresponding configuration endpoints. Here is a list of popular Identity Providers (IdP) and their corresponding configuration endpoints. Those endpoints are public and contain information that you'll need to properly configure your MCP server OAuth protection. OpenID Connect (OIDC) is a superset of OAuth 2.0 - if a platform is OIDC compliant, it's OAuth 2.0 compliant. # OpenID Connect (OIDC) compliant Providers These providers are popular IdPs compliant with OpenID Connect. You can use them as identity pools for your MCP server (meaning you don't have to own yourself a database of users, you can instead simply gate access to your MCP server with these identity providers). None of these providers have Dynamic Client Registration enabled. You'll need to use [Alpic DCR proxy](/secure/auth/oauth-setup#using-an-oauth-2-0-compatible-identity-provider-idp) in order to use them as valid identity providers for your MCP server. | Identity Provider | OpenID Connect Configuration Well-Known Endpoint | | :---------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Apple | [https://account.apple.com/.well-known/openid-configuration](https://account.apple.com/.well-known/openid-configuration) | | Coinbase | [https://login.coinbase.com/.well-known/openid-configuration](https://login.coinbase.com/.well-known/openid-configuration) | | Discord | [https://discord.com/.well-known/openid-configuration](https://discord.com/.well-known/openid-configuration) | | Dropbox | [https://www.dropbox.com/.well-known/openid-configuration](https://www.dropbox.com/.well-known/openid-configuration) | | Facebook | [https://www.facebook.com/.well-known/openid-configuration](https://www.facebook.com/.well-known/openid-configuration) | | Github | [https://github.com/login/oauth/.well-known/openid-configuration](https://github.com/login/oauth/.well-known/openid-configuration) | | GitLab | [https://gitlab.com/.well-known/openid-configuration](https://gitlab.com/.well-known/openid-configuration) | | Google | [https://accounts.google.com/.well-known/openid-configuration](https://accounts.google.com/.well-known/openid-configuration) | | Hugging Face | [https://huggingface.co/.well-known/openid-configuration](https://huggingface.co/.well-known/openid-configuration) | | Kakao | [https://kauth.kakao.com/.well-known/openid-configuration](https://kauth.kakao.com/.well-known/openid-configuration) | | Line | [https://access.line.me/.well-known/openid-configuration](https://access.line.me/.well-known/openid-configuration) | | LinkedIn | [https://www.linkedin.com/oauth/.well-known/openid-configuration](https://www.linkedin.com/oauth/.well-known/openid-configuration) | | Microsoft | [https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration](https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration) | | Salesforce | [https://login.salesforce.com/.well-known/openid-configuration](https://login.salesforce.com/.well-known/openid-configuration) | | Slack | [https://slack.com/.well-known/openid-configuration](https://slack.com/.well-known/openid-configuration) | | Spotify | [https://accounts.spotify.com/.well-known/openid-configuration](https://accounts.spotify.com/.well-known/openid-configuration) | | Twitch | [https://id.twitch.tv/oauth2/.well-known/openid-configuration](https://id.twitch.tv/oauth2/.well-known/openid-configuration) | | Xero | [https://identity.xero.com/.well-known/openid-configuration](https://identity.xero.com/.well-known/openid-configuration) | # Identity Management Platforms You'll find below the most popular IdPs compliant with OAuth 2.1. You can use them to provision your own user pools for your MCP server. | Identity Management Platform | OpenID Connect Configuration Well-Known Endpoint | | :---------------------------------------------------------: | :------------------------------------------------------------------------------------------- | | Auth0 | `https://{tenant}.us.auth0.com/.well-known/openid-configuration` | | Amazon Cognito | `https://cognito-idp.{region}.amazonaws.com/{user-pool-id}/.well-known/openid-configuration` | | Clerk | `https://{tenant}.clerk.accounts.dev/.well-known/openid-configuration` | | Google Identity Platform (formerly Firebase Authentication) | `https://securetoken.google.com/{tenant}/.well-known/openid-configuration` | | Logto | `https://{tenant}.logto.app/.well-known/openid-configuration` | | Microsoft Entra ID (formerly Azure AD) | `https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration` | | Okta | `https://{tenant}.okta.com/.well-known/openid-configuration` | | Stytch | `https://{tenant}.customers.stytch.com/.well-known/openid-configuration` | | WorkOS | `https://{tenant}.authkit.app/.well-known/openid-configuration` | You might want to try `https://{your - domain}/.well-known/openid-configuration` instead of the provider specific URL if a custom domain has been setup on your Identity Management Platform. # Other Identity Providers You can use any IdP to configure authorization on your MCP server. Use the login page domain to discover `/.well-known/oauth-authorization-server` endpoint. For exemple, you can login to `Box` using `https://account.box.com/login`. Box's OAuth Authorization Server metadata endpoint is `https://account.box.com/.well-known/oauth-authorization-server` # OAuth authentication Source: https://docs.alpic.ai/secure/auth/oauth-setup Configure OAuth authentication for your MCP servers on Alpic To add OAuth authentication to your MCP server, you need to have an Identity Provider (IdP) that manages your users identities. Depending on your IdP, you can be in one of the 4 following cases: Your IdP is OAuth 2.1 compatible and implements Dynamic Client Registration (DCR) Your IdP is OAuth 2.0 compatible but doesn't implement DCR Your IdP doesn't provide OAuth metadata endpoints You don't have an IdP yet as you are starting from scratch ### Using an OAuth 2.1 compatible Identity Providers (IdP) If you're already using an OAuth 2.1 identity provider with Dynamic Client Registration (DCR), you simply need to configure your MCP server to advertise your IdP through OAuth metadata endpoints. The easiest way to do so is to rely on existing SDK helpers to provide such configuration on your server: ```ts MCP Typescript SDK theme={null} import { requireBearerAuth } from "@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js"; import { mcpAuthMetadataRouter } from "@modelcontextprotocol/sdk/server/auth/router.js"; //... app.use( mcpAuthMetadataRouter({ oauthMetadata: { authorization_endpoint: "https://my-idp.com/oauth2/authorize", token_endpoint: "https://my-idp.com/oauth2/token", registration_endpoint: "https://my-idp.com/oauth2/register", response_types_supported: ["code"], code_challenge_methods_supported: ["S256"], token_endpoint_auth_methods_supported: ["client_secret_post"], issuer: "https://my-idp.com", }, resourceServerUrl: new URL("http://localhost:3000"), }), ); const authMiddleware = requireBearerAuth({ verifier: { verifyAccessToken: async (token) => { // Generic jwtDecode for JWT auth token or any IDP custom verification method return { token, clientId: "clientId", scopes: [], expiresAt: Date.now() / 1000 + 600 }; }, }, }); app.post("/mcp", authMiddleware, async (req: Request, res: Response) => {}); app.get("/mcp", authMiddleware, async (req: Request, res: Response) => {}); app.delete("/mcp", authMiddleware, async (req: Request, res: Response) => {}); app.listen(3000); ``` ```python FastMCP theme={null} from typing import Any from fastmcp.server.auth import AccessToken, RemoteAuthProvider, TokenVerifier from mcp.server.auth.handlers.metadata import MetadataHandler from mcp.server.auth.routes import cors_middleware from mcp.shared.auth import OAuthMetadata from starlette.routing import Route from pydantic import AnyHttpUrl class CustomTokenVerifier(TokenVerifier): """Token verifier for the custom auth provider.""" async def verify_token(self, token: str) -> AccessToken | None: """Generic jwtDecode for JWT auth token or any IDP custom verification method""" return AccessToken(token=token, client_id="clientId", scopes=[]) class CustomAuthProvider(RemoteAuthProvider): """Authentication provider for MCP servers that act both as an authorization server and a resource server. """ base_url: AnyHttpUrl def __init__( self, base_url: AnyHttpUrl | str, ): """Initialize the custom auth provider. Args: token_verifier: TokenVerifier instance for token validation base_url: The base URL of this server """ super().__init__( token_verifier=CustomTokenVerifier(), base_url=base_url, authorization_servers=[base_url], ) def get_routes(self, mcp_path: str | None = None, mcp_endpoint: Any | None = None) -> list[Route]: routes = super().get_routes(mcp_path, mcp_endpoint) routes.append(Route( "/.well-known/oauth-authorization-server", endpoint=cors_middleware( MetadataHandler( OAuthMetadata( issuer=AnyHttpUrl("http://localhost:8000"), authorization_endpoint=AnyHttpUrl("https://my-idp.com/oauth2/authorize"), token_endpoint=AnyHttpUrl("https://my-idp.com/oauth2/token"), registration_endpoint=AnyHttpUrl("https://my-idp.com/oauth2/register"), response_types_supported=["code"], code_challenge_methods_supported=["S256"], token_endpoint_auth_methods_supported=["client_secret_post"], ) ).handle, ["GET", "OPTIONS"], ), methods=["GET", "OPTIONS"], )) return routes auth = CustomAuthProvider(base_url="http://localhost:8000") mcp = FastMCP("My MCP Server", auth=auth) ``` Configuring your MCP server to use an existing Identity Provider (IdP) with OAuth requires knowledge of a the different oauth endpoint URLs. We have curated a list of endpoints for the most used IdPs [here](/secure/auth/oauth-providers). After deploying a new version of your MCP server on Alpic with such a configuration, you should see your server as **Protected** in the **Settings** tab of your project page. This will confirm that your MCP server is protected by OAuth. We made Alpic to be fully compatible with your local server code. If your authentication code runs locally, it should work on Alpic. In the example above, you should keep the localhost URL for the resource server when your deploy to Alpic. If you want to use your deployed MCP server URL as the OAuth server instead of `localhost`, the `ALPIC_HOST` environment variable was conceived for this use case. It's automatically set at both build and runtime, allowing Alpic to treat your deployed host as an internal host for OAuth metadata discovery. Learn more about [system environment variables](/build-deploy/env-variables). ### Using an OAuth 2.0 compatible Identity Provider (IdP) with no DCR If you're not using an OAuth 2.1 IdP with DCR, you can rely on [**Alpic's Dynamic Client Registration proxy**](./dcr-proxy) to handle the complexity associated with multiple OAuth clients registering to use your IdP. In order to leverage Alpic's DCR proxy feature, you should configure your MCP server to advertise your IdP through OAuth metadata endpoints without mentioning a `registration_endpoint` property. The easiest way to do so is to rely on existing SDK helpers to provide such configuration on your server: ```ts MCP Typescript SDK theme={null} import { requireBearerAuth } from "@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js"; import { mcpAuthMetadataRouter } from "@modelcontextprotocol/sdk/server/auth/router.js"; //... app.use( mcpAuthMetadataRouter({ oauthMetadata: { authorization_endpoint: "https://my-idp.com/oauth2/authorize", token_endpoint: "https://my-idp.com/oauth2/token", response_types_supported: ["code"], code_challenge_methods_supported: ["S256"], token_endpoint_auth_methods_supported: ["client_secret_post"], issuer: "https://my-idp.com", }, resourceServerUrl: new URL("http://localhost:3000"), }), ); const authMiddleware = requireBearerAuth({ verifier: { verifyAccessToken: async (token) => { // Generic jwtDecode for JWT auth token or any IDP custom verification method return { token, clientId: "clientId", scopes: [], expiresAt: Date.now() / 1000 + 600 }; }, }, }); app.post("/mcp", authMiddleware, async (req: Request, res: Response) => {}); app.get("/mcp", authMiddleware, async (req: Request, res: Response) => {}); app.delete("/mcp", authMiddleware, async (req: Request, res: Response) => {}); app.listen(3000); ``` ```python FastMCP theme={null} from typing import Any from fastmcp.server.auth import AccessToken, RemoteAuthProvider, TokenVerifier from mcp.server.auth.handlers.metadata import MetadataHandler from mcp.server.auth.routes import cors_middleware from mcp.shared.auth import OAuthMetadata from starlette.routing import Route from pydantic import AnyHttpUrl class CustomTokenVerifier(TokenVerifier): """Token verifier for the custom auth provider.""" async def verify_token(self, token: str) -> AccessToken | None: """Generic jwtDecode for JWT auth token or any IDP custom verification method""" return AccessToken(token=token, client_id="clientId", scopes=[]) class CustomAuthProvider(RemoteAuthProvider): """Authentication provider for MCP servers that act both as an authorization server and a resource server. """ base_url: AnyHttpUrl def __init__( self, base_url: AnyHttpUrl | str, ): """Initialize the custom auth provider. Args: token_verifier: TokenVerifier instance for token validation base_url: The base URL of this server """ super().__init__( token_verifier=CustomTokenVerifier(), base_url=base_url, authorization_servers=[base_url], ) def get_routes(self, mcp_path: str | None = None, mcp_endpoint: Any | None = None) -> list[Route]: routes = super().get_routes(mcp_path, mcp_endpoint) routes.append(Route( "/.well-known/oauth-authorization-server", endpoint=cors_middleware( MetadataHandler( OAuthMetadata( issuer=AnyHttpUrl("http://localhost:8000"), authorization_endpoint=AnyHttpUrl("https://my-idp.com/oauth2/authorize"), token_endpoint=AnyHttpUrl("https://my-idp.com/oauth2/token"), response_types_supported=["code"], code_challenge_methods_supported=["S256"], token_endpoint_auth_methods_supported=["client_secret_post"], ) ).handle, ["GET", "OPTIONS"], ), methods=["GET", "OPTIONS"], )) return routes auth = CustomAuthProvider(base_url="http://localhost:8000") mcp = FastMCP("My MCP Server", auth=auth) ``` After deploying a new version of your MCP server on Alpic with such a configuration, check that your server is detected as **Protected** in the **Settings** tab of your project page. If that's the case, you will see an option to **activate Alpic DCR**. In order to activate DCR, you should create a single OAuth client on your IdP. This client will be the one proxied by Alpic for every request users make to identify on your MCP server. Make sure to choose a generic enough name in case it's displayed during the authentication process. The callback URL to use for this client is specified by Alpic when activating DCR. Please fill-in the activation form with newly created OAuth **client ID**, **client secret** and **scopes** to complete the DCR proxy setup. ### Using and IdP without OAuth support In the case you have an internal identity management system, or are using an identity management system that doesn't support Oauth, you can use providers that take care of Oauth and DCR flow for you while keeping your identity system. Here are some providers supporting the MCP use-case: * [Stytch Standalone Apps](https://stytch.com/docs/guides/connected-apps/overview) * [WorkOS Connect](https://workos.com/docs/authkit/connect/standalone) Once you have configured your MCP Oauth 2.1 workflow with that provider, you can use the [examples above](#using-an-oauth-21-compatible-identity-providers-idp) to integrate it into your MCP server. ### Building from scratch If you don't have any identity system, you can build yours, or rely on one of the many Identiy Managment Systems out there. You can check our OAuth [providers list](/secure/auth/oauth-providers#identity-management-platforms) to see which of them is supporting OAuth 2.1 with DCR or not. # Overview Source: https://docs.alpic.ai/secure/auth/overview Secure your MCP servers with flexible authentication options on Alpic Alpic supports many different authentication options for your MCP servers, from simple public access to enterprise-grade OAuth integration. By default, servers deployed on Alpic are **public** and accessible to anyone with the server URL. ## Authentication Options If you want to protect your server with authentication, you have two main options: Integrate with identity providers using OAuth. Protect your server with API keys via custom headers. Alpic itself is not an authentication provider or IdP, but is compatible with all authentication options above. You implement authentication in your MCP server code, and Alpic will host and serve your protected server. # API Key authentication Source: https://docs.alpic.ai/secure/auth/token-bearer-setup Protect your MCP server with API Keys Alpic also supports API key Authentication via the *x-api-key* header. You can get the value of the api key headers in your tool callback: ```ts Typescript theme={null} server.tool( "greet", "A simple greeting tool", { name: z.string().describe("Name to greet"), }, async ( args: { name: string }, extra: RequestHandlerExtra, ): Promise => { const apiKey = extra.requestInfo?.headers["x-api-key"]; if (!apiKey) { return { content: [ isError: true, { type: "text", text: `You need to have a valid api key to use this tool.`, }, ], }; } const yourApiClient = new yourApiClient(apiKey); const yourApiResponse = await yourApiClient.greet(name); return { content: [ { type: "text", text: `${yourApiResponse}`, }, ], }; }, ); ``` ```python Python theme={null} from mcp.server.fastmcp import Context, FastMCP from pydantic import Field mcp = FastMCP("Echo Server", stateless_http=True) @mcp.tool( title="Echo Tool", description="Echo the input text", ) async def echo(ctx: Context, text: str = Field(description="The text to echo")) -> str: api_key = ctx.request_context.request.get("x-api-key") if not api_key: raise ValueError("API key is required") your_api_client = YourApiClient(api_key) your_api_response = await your_api_client.echo(text) return your_api_response ``` You can then instruct your users to add this custom headers when adding your MCP server to their MCP Client. ```json Cursor theme={null} { "mcpServers": { "yourMcpServer": { "url": "https://your-mcp-server.alpic.live", "headers": { "x-api-key": "" } } } } ``` ```json Claude Desktop theme={null} { "mcpServers": { "yourMcpServer": { "command": "npx", "args": ["mcp-remote", "https://your-mcp-server.alpic.live", "--header", "x-api-key: "] } } } ``` ```bash VSCode theme={null} code --add-mcp '{"type":"http","name":"yourMcpServer","version":"0.0.1","description":"your amazing server","url":"https://your-mcp-server.alpic.live","author":"You","categories":["mcp"],"headers":{"x-api-key":""}}' ``` ```bash Claude Code theme={null} claude mcp add --transport http yourMcpServer https://your-mcp-server.alpic.live \ --header "x-api-key: " ``` ```md Goose theme={null} Go to Extensions Click on Add custom extension Fill the following information: - Extension Name: yourMcpServer - Type: Streamable HTTP - Description: Your amazing MCP server - Endpoint: https://your-mcp-server.alpic.live Enter authentication headers: Scroll down to the Request Headers section Click the + Add button Enter Header name: x-api-key Enter Value: ``` # Fixed Outbound IP Source: https://docs.alpic.ai/secure/fixed-outbound-ip Route your MCP server's outbound traffic through fixed IP addresses If your MCP server calls external APIs that require IP whitelisting, you can enable fixed outbound IPs so all outbound traffic uses predictable addresses. Available on the **Enterprise plan** only. ## Setup In your project **Settings**, toggle the **Fixed Outbound IP** switch. This may take a few minutes. The current IP list is always available at [`https://assets.alpic.ai/ip-ranges.json`](https://assets.alpic.ai/ip-ranges.json). The IPs are stable and won't change without advance notice. # IP Whitelisting Source: https://docs.alpic.ai/secure/ip-whitelisting Restrict access to your MCP server by IP address or MCP client IP whitelisting lets you control which IP addresses can reach your MCP server. When enabled, only requests from approved IPs or MCP clients are allowed — all others receive a `403 Forbidden` response. This is useful when you want to limit access to known clients, such as ChatGPT or Claude, or restrict usage to your corporate network. IP whitelisting is configured **per environment**. Make sure you configure it for the right environment (e.g., production, staging). ## Platform Selection For common platforms, Alpic maintains up-to-date IP lists so you don't have to manage them manually. Simply select the platforms you want to allow. ### Conversational platforms Select the MCP clients whose users reach your server directly: | Platform | IP Source | | ----------- | ------------------------------------------------------------------------------------------------------------------------------------ | | **ChatGPT** | Fetched automatically from [OpenAI's published IP list](https://openai.com/chatgpt-connectors.json), refreshed every 15 minutes | | **Claude** | Based on [Anthropic's published IP addresses](https://platform.claude.com/docs/en/api/ip-addresses), updated with each Alpic release | ChatGPT IPs are fetched dynamically and remain up to date automatically. Claude IPs are updated with Alpic releases, so if Anthropic changes their egress IP ranges, there may be a short delay before the changes are reflected. ### WAF / CDN platforms If your MCP server is fronted by a WAF or CDN, trust that provider's egress IP ranges so requests forwarded through it aren't blocked: | Platform | IP Source | | -------------- | --------------------------------------------------------------------------------------------------------------------------- | | **Akamai** | Fetched from [Akamai's published edge CIDR lists](https://techdocs.akamai.com/origin-ip-acl/docs/update-your-origin-server) | | **Cloudflare** | Fetched from [Cloudflare's IP ranges API](https://api.cloudflare.com/client/v4/ips) | | **Fastly** | Fetched from [Fastly's public IP list](https://api.fastly.com/public-ip-list) | ## Custom IPs You can also add up to **20 custom IP addresses or CIDR ranges** per environment. Supported formats: * IPv4 addresses (e.g., `203.0.113.10`) * IPv6 addresses (e.g., `2001:db8::1`) * IPv4 CIDR ranges (e.g., `203.0.113.0/24`) * IPv6 CIDR ranges (e.g., `2001:db8::/32`) Custom IPs and platform selections work together — a request is allowed if it matches **either** list. ## Setup In your Alpic dashboard, open your project and go to the **Distribution** tab, then select the **Trusted IPs** section. Toggle the IP whitelist switch to enable the feature. Check the platforms you want to allow — conversational clients (ChatGPT, Claude) and/or WAF/CDN providers (Akamai, Cloudflare, Fastly) — and optionally add custom IP addresses or CIDR ranges. Click **Save** to apply the changes. The restrictions take effect immediately for new requests. IPv4-mapped IPv6 addresses (e.g., `::ffff:192.168.1.1`) are automatically normalized, so you only need to add the IPv4 form. # Beacon Source: https://docs.alpic.ai/testing/beacon Audit your MCP server and MCP Apps for spec compliance and AI client compatibility. Beacon is Alpic's automated audit for remote MCP servers and [MCP Apps](https://modelcontextprotocol.io/extensions/apps/overview). Point it at a URL and it reports whether the server is ready to ship to ChatGPT and Claude.ai — including protocol conformance, tool and resource metadata, app rendering in each client, and how the server handles unexpected inputs. Beacon doesn't just static-check your manifest: it **launches your server inside a real ChatGPT and Claude.ai conversation in a headless browser**, triggers a tool that exposes an MCP App, and asserts that the app actually renders end-to-end. Screenshots from each run are attached to the report so you can see what your users will see. Use Beacon before publishing a new server, after every significant change, or as a CI gate on your deployments. ## What Beacon checks Beacon evaluates your server and any MCP Apps it exposes against the specifications and platform requirements that ChatGPT and Claude.ai apply when reviewing an app. **MCP server specs** — protocol conformance and tool/resource shape: * [MCP specification — tools](https://modelcontextprotocol.io/specification/2025-11-25/server/tools) * [MCP specification — resources](https://modelcontextprotocol.io/specification/2025-11-25/server/resources) **MCP Apps specs** — requirements that apply once your server ships an MCP App (a view resource rendered by the client): * [Apps SDK reference](https://developers.openai.com/apps-sdk/reference/) — ChatGPT Apps requirements (metadata, CSP, widget descriptions) * [Remote MCP Server Submission Guide](https://support.claude.com/en/articles/12922490-remote-mcp-server-submission-guide) — Claude.ai-specific requirements for remote MCP Apps Every check carries a severity. **Errors** must be fixed before a platform will accept the server; **warnings** should be fixed before submission; **info** is surfaced for awareness. The report also outputs a per-platform readiness verdict (`ChatGPT` / `Claude.ai`) derived from the checks that apply to each platform. Beacon currently only supports unauthenticated MCP servers. If your server responds with `HTTP 401`, Beacon reports that authentication is required and skips the rest of the checks. Support for authenticated audits is on the roadmap. ## Running an audit ### From the dashboard Open your team's **Beacon** tab, paste an HTTPS URL, and hit **Run**. The page streams progress as each collector finishes and opens a detailed report when the audit completes. Past audits for the team are listed so you can revisit or compare them. Beacon audit report ### From the CLI Use [`alpic audit`](/cli/audit) to run Beacon from your terminal or CI pipeline: ```bash theme={null} alpic audit --url https://my-server.example.com/mcp ``` When run inside a linked project, Beacon targets the project's deployed MCP URL automatically. Pass `--json` to get the full report for further processing in CI. The CLI skips the end-to-end app rendering category by default because it takes several minutes per platform. Run the full audit (including live app rendering) from the dashboard. ## Reading the report The report groups results by severity and surfaces: * A **readiness badge** for ChatGPT and Claude.ai — green when no blocking errors remain and, for servers that ship an MCP App, at least one app check succeeded for that platform. * A **list of issues** with a short message, affected tool/resource, and a one-line hint explaining how to fix it. * **App screenshots** captured from the real ChatGPT and Claude.ai browser sessions Beacon ran, so you can visually confirm what your MCP App looks like in each client. * A **Fix with AI** action that packages the failing checks into a prompt you can paste into Claude Code, Cursor, or any other coding agent. The prompt references the same specs listed above so the agent can reason against the source of truth. If a check is `skip`ped, it's because its required artifact wasn't available — for example, a tool-level check has no tools to run against, or an app-rendering check has no MCP App resources to render. Skips are informational and never block platform readiness. # Playground Source: https://docs.alpic.ai/testing/playground How to access and test your MCP Server Once your deployment on Alpic is successful, you get a remote URL to connect to your MCP server. MCP Server Overview ### Try it instantly with the Playground Every server deployed on Alpic comes with a built-in [Playground](/distribution/playground) at the `/try` path of your server URL. It lets you and your users test tools through a conversational AI interface directly in the browser — no client setup required. ### Test and debug your MCP server with the MCP Inspector While in development mode, you can use the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) to test and debug your MCP server: 1. Launch the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) ```bash theme={null} npx @modelcontextprotocol/inspector ``` 2. Select **Streamable HTTP** transport. 3. Add your MCP server URL (e.g. `https://mcp-server-XXXXXXX.alpic.live`). 4. Click **Connect**. The status should change to **Connected**, and you should be able to access all of your ressources, prompts and tools to test them via the inspector UI. The MCP Inspector is particularly useful for debugging authentication issues, testing tool parameters, and verifying that your server responds correctly to different requests. ### Connect your MCP server to any compatible MCP client You can also connect your MCP server to any MCP client supporting SSE or Streamable HTTP transport. Below are some configuration examples: ```json mcp.json theme={null} { "mcpServers": { "your-server-name": { "url": "https://mcp-server-XXXXXXX.alpic.live", "transport": "http" } } } ``` ```json mcp.json (with Auth Bearer Token) theme={null} { "mcpServers": { "your-server-name": { "url": "https://mcp-server-XXXXXXX.alpic.live", "transport": "http", "headers": { "X-API-KEY": "your-api-key-here" } } } } ``` Replace `https://mcp-server-XXXXXXX.alpic.live` with your actual MCP server URL. # Troubleshooting Source: https://docs.alpic.ai/troubleshooting Common deployment issues and how to fix them This page covers the most common issues you may encounter when deploying and running your MCP server on Alpic. Each section describes what you see, why it happens, and how to fix it. Before diving in: verify your project builds and runs locally first. Most deployment issues stem from differences between your local environment and Alpic's serverless runtime. ## Build fails during install **What you see:** Build fails during the install phase with errors related to a missing lock file or `pyproject.toml`. **Why it happens:** Alpic's default install commands expect a lock file in your repository. Without one, the install step fails. **How to fix it:** Run your package manager's install command locally (e.g., `pnpm install`) to generate a lock file, then commit it (`pnpm-lock.yaml`, `yarn.lock`, or `package-lock.json`) to your repository. This is the recommended approach. Alternatively, override the install command in your `alpic.json`: ```json theme={null} { "$schema": "https://assets.alpic.ai/alpic.json", "installCommand": "npm install" } ``` Override the install command in your `alpic.json`: ```json theme={null} { "$schema": "https://assets.alpic.ai/alpic.json", "installCommand": "uv pip install -r requirements.txt" } ``` Or migrate to a `pyproject.toml`-based project with `uv init`. You can also set the install command from **Settings > Build Settings** in the dashboard. ## Custom HTTP endpoints are not exposed Alpic only routes MCP protocol traffic and standard OAuth endpoints. Custom REST API routes on your server are not reachable from the outside. **What you see:** HTTP requests to custom paths like `/api/search` or `/rag-stream` return 404. **Why it happens:** Alpic acts as an MCP gateway, not a generic HTTP proxy. It only forwards [MCP protocol messages](/build-deploy/endpoints) to your server. The exposed paths are `/mcp` (and `/` as an alias), and `/assets/*`. **How to fix it:** You have two options: 1. **Convert your endpoint into an MCP tool.** The tool is invoked through the standard MCP protocol and has full access to your server's logic. ```diff theme={null} - @app.get("/api/search") - def search(q: str): - return {"results": do_search(q)} + @mcp.tool() + def search(q: str) -> list[str]: + """Search the knowledge base.""" + return do_search(q) ``` 2. **Call the endpoint logic directly from an existing tool.** If you already have a tool that needs data from your endpoint, import and call the underlying function directly instead of making an HTTP request. Note: for MCP apps, you can invoke tools directly from your widget, using [`window.openai.callTool(name, args)`](https://developers.openai.com/apps-sdk/reference) for ChatGPT, or the portable [`tools/call` JSON-RPC method](https://modelcontextprotocol.io/extensions/apps/overview) over postMessage for Claude. No custom HTTP endpoint needed. ## Assets return 404 **What you see:** Static files (HTML, images, CSS, JavaScript) referenced from your MCP server or ChatGPT App return 404. **Why it happens:** Assets are served from a separate CDN path, not from your server runtime. They need to be placed in a specific directory to be picked up at build time. **How to fix it:** Place your static files in an `assets/` directory at your project root. They become available at: ``` https://.alpic.live/assets/ ``` For Node.js projects, assets generated during the build step in `/assets/` are also picked up. If both locations contain files, built assets take priority on conflict. Reference these files in your MCP tools and resources using the relative path `/assets/`. Learn more about asset hosting in our [Hosting Assets](/build-deploy/assets) guide. ## Deployment doesn't reflect my latest changes **What you see:** Pushes to your branch don't trigger a deployment, your latest changes aren't live, or the build uses the wrong `package.json` / `pyproject.toml`. **Why it happens:** Each environment tracks a specific Git branch. Pushes to other branches are silently ignored, no deployment is triggered. Similarly, if your project lives in a subdirectory (monorepo) and the root directory is misconfigured, the build reads configuration from the wrong location. **How to fix it:** 1. Check your environment's tracked branch in **Environments > \[your environment]**. Click the edit icon next to the branch name to update it. 2. Check the root directory in **Settings > Build Settings**. For monorepos, set it to the subdirectory containing your MCP server (e.g., `packages/my-mcp-server`). ## New environment crashes on startup **What you see:** Your new environment deploys but crashes at runtime with missing API keys, database URLs, or other configuration errors. **Why it happens:** Environment variables are **per-environment**, not shared across a project. When you create a new environment, it starts with an empty set of variables, even if your production environment has them all configured. **How to fix it:** When creating a new environment, manually add all required environment variables for that environment. You can use different values per environment (e.g., a staging API key vs a production one). A few things to keep in mind: * **Runtime changes are instant:** Updating an environment variable takes effect immediately, no redeploy needed. * **Build-time variables need a redeploy:** If a variable is used during the install or build step (e.g., a private registry token), you need to redeploy after changing it. * **4 KB total limit:** The combined size of all keys and values is capped at 4 KB per environment. For more on managing environments, see [Environments](/build-deploy/environments). ## Tool calls fail with a timeout error **What you see:** Tool calls return an `Internal Server Error` or stop responding after approximately 30 seconds. **Why it happens:** Each tool invocation has a **30-second timeout**. Any single tool call that exceeds this limit is terminated. **How to fix it:** * **Optimize the tool:** Reduce API call latency, use smaller models, cache results, or paginate large responses. * **Use long-running tasks:** For operations that genuinely need more time (data processing, complex API orchestrations, ML inference), implement your tool using the MCP Tasks API. Long-running tasks run on a separate compute path with a default TTL of up to 6 hours. The 30-second limit applies to each individual tool invocation, not to the entire MCP session. If you're hitting this limit on a specific tool, consider breaking it into smaller, sequential tool calls. ## Deployment fails with 404 on `/mcp` **What you see:** Deployment fails with `Server returned status 404 on /mcp after 3 attempts` in build logs. **Why it happens:** Alpic expects your MCP server to listen on `/mcp` (Streamable HTTP) or `/sse` (SSE). If your server uses a different path (e.g., `/`), the deployment health check fails. **How to fix it:** Ensure your server uses the default MCP SDK paths: ```typescript theme={null} // Streamable HTTP, listens on /mcp by default import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"; ``` If you're using Express or another framework, mount the MCP handler on `/mcp`: ```typescript theme={null} app.post("/mcp", handleMcpRequest); ``` With FastMCP, the default path is correct. If you're overriding it, make sure you keep `/mcp`: ```python theme={null} mcp = FastMCP("my-server") mcp.run(transport="streamable-http", port=8000) # Listens on /mcp by default ``` ## Server shows as "Public" despite OAuth configuration Your server has OAuth configured locally, but the Alpic dashboard shows "Public" and clients can't authenticate. **What you see:** The Authentication section in your project settings shows "Public". Clients like ChatGPT report that OAuth is not enabled for your server. **Why it happens:** Alpic detects OAuth at **deploy time** by sending an unauthenticated `initialize` request to your server. If your server returns `200` instead of `401`, or returns `401` without the correct `WWW-Authenticate` header, Alpic classifies it as public. **How to fix it:** Your server must return the following on unauthenticated requests: 1. **HTTP 401** status code 2. A `WWW-Authenticate` header with this format: ``` WWW-Authenticate: Bearer resource_metadata="http://localhost:/.well-known/oauth-protected-resource" ``` Your server must also expose `/.well-known/oauth-protected-resource` locally, returning **valid OAuth Protected Resource Metadata**. After making changes, **redeploy**, OAuth status is only evaluated during deployment. For a complete guide on configuring OAuth with Alpic, see [OAuth Setup](/secure/auth/oauth-setup). ## "Server already initialized" error **What you see:** The first tool call succeeds, but subsequent calls fail with `Invalid Request: Server already initialized`. **Why it happens:** Your server creates a single `StreamableHTTPServerTransport` at module scope and reuses it across requests. The MCP SDK rejects the second initialization attempt. **How to fix it:** Create a fresh transport per incoming HTTP request: ```typescript theme={null} // Wrong, reuses transport across warm Lambda invocations const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID() }); // Right, fresh transport per request app.post("/mcp", (req, res) => { const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID() }); const server = getServer(); server.connect(transport); // handle request... }); ``` Alternatively, use **stdio transport** and let Alpic handle transport management entirely. With stdio, you don't manage any HTTP server or transport, just expose your tools. ## Deployment fails after a successful build **What you see:** The build completes successfully, but the deployment fails during the post-build health check with a timeout error. **Why it happens:** After building, Alpic verifies your server starts correctly. If your server takes too long to boot (approximately 10 seconds), the health check times out. Common causes: heavy dependencies (PyTorch, sentence-transformers, Playwright) or loading large models at import time. **How to fix it:** 1. **Trim dependencies:** Remove non-critical packages. Every megabyte adds to cold start time. 2. **Defer expensive initialization:** Don't load ML models or establish database connections at import time. Do it lazily on the first tool call instead. 3. **Pre-download assets at build time:** If your server needs large files (models, datasets), download them during the install command, not at runtime. ```json theme={null} { "$schema": "https://assets.alpic.ai/alpic.json", "installCommand": "uv sync && uv run python download_models.py" } ``` 4. **Minimize import chains:** In Python, importing `torch` or `transformers` at the top level triggers heavy initialization. Use lazy imports inside tool functions. *** ## Still stuck? If none of the above resolves your issue: * Check the build logs in your [Alpic Dashboard](https://app.alpic.ai) under **Deployments** for your environment * Reach out on [Discord](https://discord.gg/2jc92tZQdn) for community help * Email [support@alpic.ai](mailto:support@alpic.ai) with your project ID and a description of the issue # User Feedbacks Source: https://docs.alpic.ai/user-insights/user-feedbacks Collect feedback from your users or the LLM directly inside your MCP server. ### Overview When something doesn't work as expected, neither users nor models have a way to tell you. User Feedback adds a `send_feedback` tool to your MCP server so both the model and the user can report issues and send you feedback. User Feedback dashboard User Feedback dashboard The [`@alpic-ai/insights`](https://www.npmjs.com/package/@alpic-ai/insights) (TypeScript) and [`alpic-ai-insights`](https://pypi.org/project/alpic-ai-insights/) (Python SDK) packages inject the feedback tool into your server's tool list. Alpic stores the feedback for you to explore in the dashboard. ### 1. Install the package `bash pnpm add @alpic-ai/insights ` `bash pip install alpic-ai-insights # or: uv add alpic-ai-insights ` ### 2. Wire it into your server Choose the entry point for your language and MCP framework. Use `feedbackMiddleware`, it returns a Skybridge `McpMiddlewareFn` you register via `mcpMiddleware()`. Add it before your tool/widget registrations: ```typescript theme={null} import { feedbackMiddleware } from "@alpic-ai/insights"; import { McpServer } from "skybridge/server"; const server = new McpServer({ name: "my-mcp-server", version: "1.0.0" }, { capabilities: {} }) .mcpMiddleware(feedbackMiddleware()) .registerTool(/* ... */); ``` Use `captureFeedback`, it accepts an `McpServer` and patches the `tools/list` and `tools/call` in place. ```typescript theme={null} import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { captureFeedback } from "@alpic-ai/insights"; const server = new McpServer( { name: "my-mcp-server", version: "1.0.0" }, { capabilities: {} }, ); server.registerTool(/* ... */); captureFeedback(server); ``` Register your tools first, then enable the feedback tool before starting the server: ```python theme={null} from alpic_ai_insights import capture_feedback from mcp.server.fastmcp import FastMCP mcp = FastMCP("my-mcp-server") @mcp.tool() def search(query: str) -> str: return query capture_feedback(mcp) ``` `capture_feedback` also accepts `mcp.server.lowlevel.Server`. Register its `list_tools` and `call_tool` handlers first, then enable capture: ```python theme={null} from alpic_ai_insights import capture_feedback from mcp import types from mcp.server.lowlevel import Server server = Server("my-mcp-server") @server.list_tools() async def list_tools() -> list[types.Tool]: return [] @server.call_tool() async def call_tool(name, arguments): return [types.TextContent(type="text", text="ok")] capture_feedback(server) ``` The `FastMCP` example above uses the class bundled with the official MCP Python SDK (`mcp.server.fastmcp.FastMCP`), not the separate `fastmcp` package. The middleware adds a `send_feedback` tool to your server at runtime. It is handled entirely by the middleware; you don't need to register it yourself. ### 3. How the LLM uses it The tool instructs the LLM to: * Use it **only** for feedback about your MCP server, not about other MCP servers. * Call it **autonomously** when it detects a genuine issue (e.g. a tool that failed unexpectedly, an unhelpful response, a missing capability). No explicit user consent required. * Strip any **Personally Identifiable Information** from the content before sending. The tool accepts two arguments: | Argument | Required | Description | | --------- | -------- | -------------------------------------------------------------------------------------------------- | | `content` | Yes | The feedback content, stripped of any PII. | | `source` | Yes | Who initiated the feedback: `"user"` if the user asked to send it, `"model"` if sent autonomously. | ### 4. Deploy Deploy on Alpic as usual. Once the new version is live on the [production environment](/build-deploy/environments), feedback starts flowing in. ### 5. View feedback in the dashboard In the Alpic dashboard, open your project and click the **Insights** tab, then **Feedbacks**. Each entry shows: * **Content:** what the feedback says * **Source:** whether it was sent by the user or the model autonomously * **Date:** when it was submitted ### Optional: run a custom handler alongside Alpic Pass a `handler` to run your own logic (e.g. forwarding to Slack or your own analytics) on every captured feedback. The handler runs **in addition to** Alpic's dashboard delivery (feedback still appears in the **Feedbacks** page) and executes inside your MCP server process: ```typescript theme={null} .mcpMiddleware( feedbackMiddleware({ handler: async ({ content, source }) => { await slack.postMessage({ text: `Feedback [${source}]: ${content}` }); }, }), ) ``` ```typescript theme={null} captureFeedback(server, { handler: async ({ content, source }) => { await slack.postMessage({ text: `Feedback [${source}]: ${content}` }); }, }); ``` ```python theme={null} async def handle_feedback(feedback): await slack.post_message( text=f"Feedback [{feedback.source}]: {feedback.content}", ) capture_feedback(mcp, handler=handle_feedback) ``` ### Combining with User Intents `feedbackMiddleware`/`captureFeedback` and `intentMiddleware`/`captureIntents` are independent and can be used together: ```typescript theme={null} import { feedbackMiddleware, intentMiddleware } from "@alpic-ai/insights"; const server = new McpServer({ name: "my-mcp-server", version: "1.0.0" }, { capabilities: {} }) .mcpMiddleware(feedbackMiddleware()) .mcpMiddleware(intentMiddleware()) .registerTool(/* ... */); ``` ```typescript theme={null} import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { captureFeedback, captureIntents } from "@alpic-ai/insights"; const server = new McpServer( { name: "my-mcp-server", version: "1.0.0" }, { capabilities: {} }, ); server.registerTool(/* ... */); captureFeedback(server); captureIntents(server); ``` ```python theme={null} from alpic_ai_insights import capture_feedback, capture_intents capture_feedback(mcp) capture_intents(mcp) ``` `intentMiddleware`/`captureIntents` and `capture_intents` automatically skip the `send_feedback` tool so they don't inject a `user_intent` field into the feedback tool's schema. # User Intents Source: https://docs.alpic.ai/user-insights/user-intents Understand what your users really want from your MCP server. ### Overview MCP apps and servers can see tool calls and their parameters, but not the conversation that triggered them. User Intents offer an easy way to gather the user's intent behind each tool call, and help you analyze and categorise them. User Intent dashboard User Intent dashboard The [`@alpic-ai/insights`](https://www.npmjs.com/package/@alpic-ai/insights) (TypeScript) and [`alpic-ai-insights`](https://pypi.org/project/alpic-ai-insights/) (Python SDK) packages dynamically add an extra parameter to all your tools, asking the LLM to include the user intent while making sure to remove any **Personally Identifiable Information**. Alpic then collects and stores those intents for you to explore. ### 1. Install the package `bash pnpm add @alpic-ai/insights ` `bash pip install alpic-ai-insights # or: uv add alpic-ai-insights ` ### 2. Wire it into your MCP app/server Choose the entry point for your language and MCP framework. Use `intentMiddleware`: it returns a Skybridge `McpMiddlewareFn` you can register via `mcpMiddleware()`. Add it before your tool/widget registrations: ```typescript theme={null} import { intentMiddleware } from "@alpic-ai/insights"; import { McpServer } from "skybridge/server"; const server = new McpServer( { name: "my-mcp-server", version: "1.0.0" }, { capabilities: {} }, ) .mcpMiddleware(intentMiddleware()) .registerTool(/* ... */); ``` Use `captureIntents`, it accepts an `McpServer` and patches the `tools/list` and `tools/call` in place. ```typescript theme={null} import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { captureIntents } from "@alpic-ai/insights"; const server = new McpServer( { name: "my-mcp-server", version: "1.0.0" }, { capabilities: {} }, ); server.registerTool(/* ... */); captureIntents(server); ``` Register your tools first, then call `capture_intents` before starting the server: ```python theme={null} from alpic_ai_insights import capture_intents from mcp.server.fastmcp import FastMCP mcp = FastMCP("my-mcp-server") @mcp.tool() def search(query: str) -> str: return query capture_intents(mcp) ``` `capture_intents` also accepts `mcp.server.lowlevel.Server`. Register both the `list_tools` and `call_tool` handlers before enabling capture: ```python theme={null} from typing import Any from alpic_ai_insights import capture_intents from mcp import types from mcp.server.lowlevel import Server server = Server("my-mcp-server") @server.list_tools() async def list_tools() -> list[types.Tool]: return [ types.Tool( name="search", inputSchema={ "type": "object", "properties": {"query": {"type": "string"}}, "required": ["query"], }, ) ] @server.call_tool() async def call_tool(name: str, arguments: dict[str, Any]): return [types.TextContent(type="text", text=str(arguments["query"]))] capture_intents(server) ``` The `FastMCP` example above uses the class bundled with the official MCP Python SDK (`mcp.server.fastmcp.FastMCP`), not the separate `fastmcp` package. ### 3. Deploy Deploy your application on Alpic as usual. As soon as the new version is live on the [production environment](/build-deploy/environments), intents start flowing in. ### 4. View intents in the dashboard In the Alpic dashboard, open your project and click the **Insights** tab. You'll see a paginated table with the following columns: * **Intent:** the user's intent behind the tool call, summarized by the LLM. * **Tool:** the name of the tool that was called. * **Client:** the MCP client the call came from (ChatGPT, Claude, Cursor, ...). * **Category:** automatically categorized into a reusable label. You can modify it directly in the table. * **Date:** the timestamp of the tool call. * **Replay:** a link to the matching session replay, shown when session replay is enabled. Identical intents on the same tool are grouped into a single row with a `×N` badge showing how many times they occurred. Changing the category on a grouped row applies it to every occurrence in the group. Use the search box to look through intents, tools and categories, and the **Filters** button to narrow the table by tool, client, or category. Select rows to categorize or delete several intents at once. ### 5. Spot trends and signals **Hot Categories** & **Signals** offer you a high-level overview of user intents trends over the selected period. Hot categories and Signals cards above the intents table Hot categories and Signals cards above the intents table **Hot categories** show you the most common intent categories. It helps you understand what your users are trying to do with your MCP App/server. **Signals** give you an overview of the important trends in user intent between the current period and the previous one. Switch the time range to update it. ### Optional: run a custom handler alongside Alpic Pass a `handler` to run your own logic (e.g. sending intents to your own analytics pipeline) on every captured intent. The handler runs **in addition to** Alpic's dashboard delivery, intents still appear in the **User Insights** page. The handler runs inside your MCP server process: ```typescript theme={null} .mcpMiddleware( intentMiddleware({ handler: async ({ toolName, userPrompt }) => { await myAnalytics.track("mcp_tool_call", { toolName, userPrompt }); }, }), ) ``` ```typescript theme={null} captureIntents(server, { handler: async ({ toolName, userPrompt }) => { await myAnalytics.track("mcp_tool_call", { toolName, userPrompt }); }, }); ``` ```python theme={null} async def handle_intent(prompt): await analytics.track( "mcp_tool_call", {"tool_name": prompt.tool_name, "user_prompt": prompt.user_prompt}, ) capture_intents(mcp, handler=handle_intent) ``` ### Optional: capture from specific tools only By default, `intentMiddleware` injects the `user_intent` field into every tool's schema. Use the `tools` option to restrict capture to a subset of your tools: ```typescript theme={null} .mcpMiddleware( intentMiddleware({ tools: ["search", "ask"], }), ) ``` ```typescript theme={null} captureIntents(server, { tools: ["search", "ask"], }); ``` ```python theme={null} capture_intents(mcp, tools=["search", "ask"]) ``` ### Optional: capture from an existing tool field If your tool already has a parameter that conveys user intent (for example, a `query`, `rationale`, or `question` parameter on a search tool), you can capture its value instead of asking the LLM to copy the intent into a synthetic `user_intent` field. Use the `argumentNameOverride` option in TypeScript or `argument_name_override` in Python: a map of tool names to the input field whose value should be captured as the intent. ```typescript theme={null} .mcpMiddleware( intentMiddleware({ argumentNameOverride: { search: "query", // The tool "search" has a "query" parameter that conveys user intent ask: "question", // The tool "ask" has a "question" parameter that conveys user intent }, }), ) ``` ```typescript theme={null} captureIntents(server, { argumentNameOverride: { search: "query", // The tool "search" has a "query" parameter that conveys user intent ask: "question", // The tool "ask" has a "question" parameter that conveys user intent }, }); ``` ```python theme={null} capture_intents( mcp, argument_name_override={ "search": "query", "ask": "question", }, ) ``` ### 6. Export your data Export your intent data as a CSV file whenever you want to analyze it in your own tools or combine it with your existing workflows.