# Shredly Docs > Connect your data to any AI agent in minutes. This file contains all documentation content in a single document following the llmstxt.org standard. ## Getting Started Shredly turns your APIs and databases into hosted MCP servers — no infrastructure to manage, no code to deploy. This guide gets you connected in under 5 minutes. AI agent? Consume these docs directly: [llms.txt](https://docs.shredly.io/llms.txt) · [llms-full.txt](https://docs.shredly.io/llms-full.txt) ## 1. Sign in Go to [shredly.io](https://shredly.io) and sign in with Google. No credit card required. ## 2. Generate an API key From your dashboard, click **Generate API Key**. Copy the key — you'll use it in the next step. :::caution Your API key is shown once. Store it somewhere safe (a password manager or `.env` file). If you lose it, generate a new one from the dashboard. ::: ## 3. Connect your agent Pick the client you're using and follow the relevant setup guide: - [Claude Code](./mcp-setup/claude-desktop) — `claude mcp add` command - [Codex](./mcp-setup/cursor) — `.codex/config.toml` + env var - [Gemini](./mcp-setup/http-sse) — `.gemini/config/mcp_config.json` --- ## MCP Server Schema ### Top-level fields | Field | Type | Required | Description | |---|---|---|---| | `name` | string | yes | Display name for your MCP server | | `slug` | string | yes | URL identifier — your server becomes available at `/mcp/{slug}` | | `description` | string | no | Short description of what the server does | | `authentication` | object | no | Server-level auth applied to every tool call (see below) | | `oauth` | object | no | OAuth 2.0 configuration for user-delegated auth flows (see below) | | `tools` | array | yes | List of tools your server exposes (see below) | ### `authentication` object Defines how the caller's API token is forwarded to your upstream service. When present, Shredly automatically injects the token into every outbound request using the specified scheme. | Field | Type | Required | Description | |---|---|---|---| | `type` | string | yes | Auth scheme: `Bearer` (prepends `"Bearer "`), `ApiKey` (sends the raw token), `Basic` (prepends `"Basic "`), or `QueryParam` (appends the token as a query parameter) | | `header` | string | no | Override header name for `Bearer`, `ApiKey`, or `Basic` — e.g. `X-My-Key` | | `query_key` | string | no | Query parameter name when `type` is `QueryParam` — defaults to `api_key` | ```json { "authentication": { "type": "Bearer" } } ``` Using `ApiKey` with a custom header name: ```json { "authentication": { "type": "ApiKey", "header": "X-My-Key" } } ``` ### `oauth` object Configures an OAuth 2.0 authorization code flow for your server. When present, Shredly handles the redirect and token exchange on behalf of the user. | Field | Type | Required | Description | |---|---|---|---| | `authorization_url` | string | yes | The provider's authorization endpoint where users are redirected to grant access | | `token_url` | string | yes | The endpoint Shredly calls to exchange an authorization code for an access token | | `client_id` | string | yes | Your OAuth application's client ID | | `client_secret` | string | yes | Your OAuth application's client secret | | `scopes` | array | yes | List of OAuth scopes to request — e.g. `["openid", "profile", "email"]` | | `extra_params` | object | no | Additional query parameters appended to the authorization URL — e.g. `{"access_type": "offline"}` for refresh tokens | ```json { "oauth": { "authorization_url": "https://accounts.google.com/o/oauth2/v2/auth", "token_url": "https://your-backend.com/oauth/token", "client_id": "your-client-id", "client_secret": "your-client-secret", "scopes": ["openid", "profile", "email"], "extra_params": { "access_type": "offline" } } } ``` ### `tools` array Each entry describes one callable tool. All fields are required. | Field | Type | Description | |---|---|---| | `name` | string | Tool name exposed to the MCP client | | `description` | string | Natural-language description of what the tool does | | `method` | string | HTTP verb: `GET`, `POST`, `PUT`, `PATCH`, or `DELETE` | | `url` | string | Upstream URL. Supports `:param` path templates (e.g. `/users/:id`). For GET requests, any `input_schema` args not consumed by a path template are automatically appended as query string parameters. | | `headers` | object | Static key/value headers sent on every request (e.g. `{"Content-Type": "application/json"}`) | | `input_schema` | object | Flat map of argument name → field definition. Each field has a `type` (`string`, `number`, etc.) and optional `description` and `optional: true`. | | `response_transform` | string | Dot-path into the response JSON to extract — e.g. `data.results`. Use `.` to return the full response. | | `timeout_ms` | number | Request timeout in milliseconds. Maximum `20000`. | ### URL templates and GET query parameters The `url` field supports two mechanisms for injecting `input_schema` arguments into requests: **Path templates** — use `:param` tokens anywhere in the URL (path or query string). Shredly replaces each token with the corresponding argument value before sending the request. **Automatic query parameters (GET only)** — for `GET` requests, any `input_schema` arguments not consumed by a path template are automatically appended to the URL as query string parameters. These two mechanisms compose: you can use path templates for some arguments and let the rest fall through as query params. **Example — simple GET with query params:** ```json { "name": "listProjects", "description": "List projects, optionally filtered by status.", "method": "GET", "url": "https://api.yourapp.com/projects", "headers": {}, "input_schema": { "status": { "type": "string", "description": "Filter by status (e.g. active, archived)", "optional": true } }, "response_transform": ".", "timeout_ms": 5000 } ``` Called with `{ "status": "active" }` → `GET /projects?status=active` **Example — path template for resource ID:** ```json { "name": "getProject", "description": "Fetch a single project by ID.", "method": "GET", "url": "https://api.yourapp.com/projects/:id", "headers": {}, "input_schema": { "id": { "type": "string", "description": "The project ID" } }, "response_transform": ".", "timeout_ms": 5000 } ``` Called with `{ "id": "proj_123" }` → `GET /projects/proj_123` **Example — PostgREST / Supabase filter syntax:** PostgREST-style APIs (like Supabase) use query param values in the form `eq.{value}`. Embed the operator prefix directly in the URL template so callers only need to pass the plain value: ```json { "name": "getProjectById", "description": "Fetch a project from Supabase by ID.", "method": "GET", "url": "https://.supabase.co/rest/v1/projects?id=eq.:id", "headers": { "apikey": "" }, "input_schema": { "id": { "type": "string", "description": "The project UUID" } }, "response_transform": ".", "timeout_ms": 5000 } ``` Called with `{ "id": "abc-123" }` → `GET /rest/v1/projects?id=eq.abc-123` **Example tool definition:** ```json { "name": "getUser", "description": "Fetch a user by ID from your backend.", "method": "GET", "url": "https://api.yourapp.com/users/:user_id", "headers": { "Content-Type": "application/json" }, "input_schema": { "user_id": { "type": "string", "description": "The ID of the user to fetch" } }, "response_transform": "data", "timeout_ms": 5000 } ``` **Example full server configuration:** ```json { "name": "My App MCP", "slug": "my-app", "description": "MCP server for My App", "authentication": { "type": "Bearer" }, "oauth": { "authorization_url": "https://accounts.google.com/o/oauth2/v2/auth", "token_url": "https://your-backend.com/oauth/token", "client_id": "your-client-id", "client_secret": "your-client-secret", "scopes": ["openid", "profile", "email"], "extra_params": { "access_type": "offline" } }, "tools": [ { "name": "createRecord", "description": "Create a new record in My App.", "method": "POST", "url": "https://api.yourapp.com/records", "headers": { "Content-Type": "application/json" }, "input_schema": { "title": { "type": "string" } }, "response_transform": ".", "timeout_ms": 10000 } ] } ``` --- ## Claude Code Connect Shredly to Claude Code using the `claude mcp add` command. ## Prerequisites - [Claude Code](https://claude.ai/code) installed - A Shredly API key ([get one here](https://shredly.io)) ## Setup Run this command in your terminal, replacing `your-api-key-here` with your key: ```bash claude mcp add --transport http shredly \ https://mcp.shredly.io/mcp/shredly \ --header "Authorization: Bearer your-api-key-here" ``` That's it. Shredly will be available as an MCP server in your next Claude Code session. ## Verify the connection In a Claude Code session, ask: > "What MCP tools do you have available from Shredly?" Claude will list the tools exposed by your connected data sources. --- ## Codex Connect Shredly to OpenAI Codex using the config file and an environment variable. ## Prerequisites - [Codex CLI](https://github.com/openai/codex) installed - A Shredly API key ([get one here](https://shredly.io)) ## Setup **1. Add to `.codex/config.toml`** ```toml [mcp_servers.shredly] url = "https://mcp.shredly.io/mcp/shredly" bearer_token_env_var = "SHREDLY_API_KEY" ``` **2. Export your API key** Run this command, or add it to your `.bashrc` / `.zshrc` to make it permanent: ```bash export SHREDLY_API_KEY="your-api-key-here" ``` Codex will pick up the server on next launch. ## Verify the connection Ask Codex to list available MCP tools: > "What MCP tools do you have from Shredly?" --- ## Gemini Connect Shredly to Gemini (Antigravity) using the `mcp_config.json` config file. ## Prerequisites - [Gemini CLI](https://github.com/google-gemini/gemini-cli) installed - A Shredly API key ([get one here](https://shredly.io)) - Node.js 18+ (for `npx mcp-remote`) ## Setup Add the following to `.gemini/config/mcp_config.json`, replacing `your-api-key-here` with your key: ```json { "mcpServers": { "shredly": { "command": "npx", "args": [ "mcp-remote", "https://mcp.shredly.io/mcp/shredly", "--header", "Authorization: Bearer your-api-key-here" ] } } } ``` Restart Gemini. Shredly tools will be available in your next session. ## Verify the connection Ask Gemini to list available MCP tools: > "What MCP tools do you have from Shredly?" --- ## Quick Start Once you have an MCP client connected, you can use Shredly to create MCP servers backed by any HTTP API — no code required. This walkthrough shows a common agent flow end to end. ## 1. Check your existing servers Ask your agent to list what you've already built: > "Can you list the MCP servers I've created on Shredly?" ``` Me: Can you list the MCP servers I've created on Shredly? Agent: Let me fetch the schema for the Shredly list tool first. Called shredly → listMcpServers() You don't have any MCP servers created on Shredly yet. ``` ## 2. Create an MCP server from your API Tell the agent about your backend and the tool you want to expose: > "Can you use the Shredly MCP to create an MCP server for my backend? My backend API is at `https://api.example.com/`. Create one tool called `search_products` — it makes a `POST` request to `/products/search`, accepts a `query` parameter (string), and the backend authorizes requests using the header `X-Api-Key`." The agent will call `shredly.createMcpServer` with the right shape: ``` Agent: I'll create that MCP server for you now. Called shredly → createMcpServer( name: "Example API", slug: "example", tools: [ { "name": "search_products", "description": "Search for products by keyword", "method": "POST", "url": "https://api.example.com/products/search", "headers": { "Content-Type": "application/json", "X-Api-Key": "{{X_API_KEY}}" }, "input_schema": { "query": { "type": "string" } }, "response_transform": ".", "timeout_ms": 10000 } ] ) Your MCP server "Example API" has been created. Connect to it at: https://mcp.shredly.io/mcp/example ``` Your new MCP server is hosted at `https://mcp.shredly.io/mcp/:slug` with the tools and configuration you defined. See [MCP Server Schema](../mcp-server-schema) for more details on how to configure your own server. ## 3. Use the new server Add the new server URL to your MCP client config (see [Claude Code](./claude-desktop), [Codex](./cursor), or [Gemini](./http-sse)), then start querying it: > "Search my products for 'wireless headphones'." ``` Agent: Called example → search_products(query: "wireless headphones") Found 12 results: 1. Sony WH-1000XM5 — $349 2. Bose QuietComfort 45 — $279 ... ``` ## Next steps - [MCP Server Schema](../mcp-server-schema) — full reference for tool definitions, auth options, and response transforms. - [HTTP / SSE setup](./http-sse) — connect any HTTP client to your Shredly servers. --- ## OAuth Setup # Setting Up OAuth for Your MCP Server Shredly supports OAuth 2.0 for MCP servers, allowing AI agents (like Claude) to authenticate on behalf of users before making tool calls. This guide walks through how the OAuth flow works and how to configure it for your provider. ## How It Works When an AI agent connects to your MCP server and no token is present, Shredly acts as an OAuth proxy — handling the full authorization code flow on your behalf and returning an access token to the agent. The high-level flow: 1. Agent hits your MCP endpoint → receives a `401` with OAuth discovery hints 2. Agent discovers the authorization server metadata (endpoints, scopes) 3. Agent registers as a client (dynamic registration) 4. Agent redirects the user to your provider's login page 5. User authenticates → your provider redirects back to Shredly's callback 6. Shredly exchanges the authorization code for a token via your `token_url` 7. Agent receives the access token and uses it for subsequent MCP calls --- ## Configuration Fields When creating or updating an MCP server, provide an `oauth` object with the following fields: | Field | Required | Description | | ------------------- | -------- | ----------------------------------------------------------------------- | | `authorization_url` | Yes | Your provider's authorization endpoint — where users are sent to log in | | `token_url` | Yes | The endpoint that exchanges the authorization code for an access token | | `client_id` | Yes | OAuth client ID from your provider | | `client_secret` | Yes | OAuth client secret — stored securely, never exposed to end users | | `scopes` | No | Array of scopes to request (e.g. `["openid", "profile", "email"]`) | | `extra_params` | No | Additional query parameters appended to the authorization URL | --- ## Redirect URI Regardless of provider, you must register the following redirect URI with your OAuth app: ``` https://mcp.shredly.io/mcp/{your-slug}/callback ``` Replace `{your-slug}` with the slug of your MCP server (e.g. `https://mcp.shredly.io/mcp/my-app/callback`). --- ## Provider Examples ### Google OAuth **OAuth app setup:** 1. Go to [Google Cloud Console](https://console.cloud.google.com/) → APIs & Services → Credentials 2. Create an OAuth 2.0 Client ID (Web application) 3. Add your redirect URI: `https://mcp.shredly.io/mcp/{slug}/callback` **Configuration:** ```json { "oauth": { "authorization_url": "https://accounts.google.com/o/oauth2/v2/auth", "token_url": "https://your-backend.com/auth/google", "client_id": "your-client-id.apps.googleusercontent.com", "client_secret": "your-client-secret", "scopes": ["openid", "profile", "email"], "extra_params": { "access_type": "offline" } } } ``` `access_type: offline` is recommended if you need a refresh token. :::note Google OAuth requires a custom `token_url` in your own backend. You cannot point directly to Google's token endpoint because the token returned by Google is not a token your backend can validate on MCP tool calls. Your `token_url` should exchange the code with Google, use the resulting Google access token to authenticate or create a session in your system, and return an `access_token` that is valid in your backend. See [Custom Token Endpoints](#custom-token-endpoints) for the required request/response format. ::: --- ### Auth0 **OAuth app setup:** 1. In your Auth0 dashboard, create a Regular Web Application 2. Add your redirect URI under Allowed Callback URLs: `https://mcp.shredly.io/mcp/{slug}/callback` **Configuration:** ```json { "oauth": { "authorization_url": "https://your-tenant.auth0.com/authorize", "token_url": "https://your-tenant.auth0.com/oauth/token", "client_id": "your-auth0-client-id", "client_secret": "your-auth0-client-secret", "scopes": ["openid", "profile", "email"] } } ``` With Auth0, the `token_url` points directly to Auth0's token endpoint — no custom proxy needed. Auth0 speaks standard OAuth 2.0 and returns `{ access_token, token_type, expires_in }` natively. --- ## Custom Token Endpoints If you need custom logic during token exchange (e.g. bridging to an internal session system like Shredly does for Google), you can provide your own `token_url`. Your custom endpoint must: **Accept** a `POST` request with `Content-Type: application/x-www-form-urlencoded` containing: | Field | Description | | --------------- | ----------------------------------------------------------------------- | | `grant_type` | Always `authorization_code` | | `code` | The authorization code from the provider | | `redirect_uri` | The Shredly callback URL (`https://mcp.shredly.io/mcp/{slug}/callback`) | | `client_id` | The client ID from your OAuth config | | `client_secret` | The client secret from your OAuth config | | `code_verifier` | PKCE verifier (if PKCE was used in the authorization request) | **Return** a JSON response: ```json { "access_token": "the-token-the-agent-will-use", "token_type": "bearer", "expires_in": 3600 } ``` The `access_token` returned here is what the AI agent will send as the `Authorization: Bearer` (or custom ApiKey) header on all subsequent MCP tool calls. --- ## Troubleshooting **`redirect_uri_mismatch` from your provider** The redirect URI registered in your OAuth app doesn't match. Make sure you've added exactly `https://mcp.shredly.io/mcp/{your-slug}/callback` to your provider's allowed redirect URIs. **Agent stops after the login page / token not returned** Confirm your `token_url` endpoint returns the required JSON format with `access_token`, `token_type`, and `expires_in`. **OAuth flow doesn't start (agent gets a plain 401)** The `oauth` config is missing or not saved on your MCP server. Verify it's set by fetching your server config. --- ## Supabase Supabase's auto-generated REST API (PostgREST) pairs naturally with Shredly — every table in your database becomes a set of HTTP endpoints with no backend code required. This guide covers authentication, PostgREST filter syntax, and a complete CRUD example across two related tables. ## Authentication Supabase authenticates REST requests via the `apikey` header. Use the `ApiKey` auth type with `header: "apikey"` so Shredly forwards the caller's token on every request: ```json { "authentication": { "type": "ApiKey", "header": "apikey" } } ``` Use your **service role key** for full read/write access bypassing Row Level Security, or your **anon key** for tools where RLS policies should apply. :::caution Your service role key has unrestricted database access. Never expose it in client-side code or commit it to source control. ::: ## PostgREST filter syntax PostgREST identifies rows using query parameters in the form `column=operator.value` — for example, `?id=eq.abc-123`. Shredly's `:param` URL templates let you embed the operator prefix directly in the tool URL, so callers only pass a plain value. **PATCH and DELETE** use this to target a specific row: ``` PATCH /rest/v1/projects?id=eq.:id DELETE /rest/v1/projects?id=eq.:id ``` The `:id` token is replaced before the request is sent. For `PATCH`, the remaining `input_schema` fields are sent as the JSON body — the filter goes in the query string and the update data goes in the body, exactly as PostgREST expects. **GET** list endpoints support optional filters via automatic query parameters. Any `input_schema` field not consumed by a URL template is appended as a query param. Pass PostgREST operator values directly from the caller: ``` GET /rest/v1/tasks?status=eq.todo&priority=eq.high ``` ## Returning the created or updated row Add `"Prefer": "return=representation"` to `POST` and `PATCH` headers. This tells PostgREST to return the full row in the response instead of an empty `204` — without it, create and update tools return nothing useful to the agent. ## Full example: projects and tasks Suppose you're building a project management tool backed by Supabase. You have two tables: **`projects`** — top-level containers for work, with fields for name, description, and a status that's either `active` or `archived`. **`tasks`** — individual units of work that belong to a project. Each task has a title, description, status (`todo`, `in_progress`, `done`), priority (`low`, `medium`, `high`), an optional assignee, and an optional due date. Deleting a project cascades to its tasks. Supabase exposes these as REST endpoints automatically: | Method | Endpoint | Description | |---|---|---| | `GET` | `/rest/v1/projects` | List projects, with optional status filter | | `POST` | `/rest/v1/projects` | Create a project | | `PATCH` | `/rest/v1/projects?id=eq.` | Update a project by UUID | | `DELETE` | `/rest/v1/projects?id=eq.` | Delete a project by UUID | | `GET` | `/rest/v1/tasks` | List tasks, with optional project, status, and priority filters | | `POST` | `/rest/v1/tasks` | Create a task | | `PATCH` | `/rest/v1/tasks?id=eq.` | Update a task by UUID | | `DELETE` | `/rest/v1/tasks?id=eq.` | Delete a task by UUID | To expose all of this through a single Shredly MCP server, you define one tool per endpoint. The `:id` URL template handles row targeting for `PATCH` and `DELETE`, and optional GET filters fall through as query parameters automatically. Here's the complete server definition: ```json { "name": "My App — Project Management", "slug": "my-app-pm", "description": "CRUD for projects and tasks via Supabase.", "authentication": { "type": "ApiKey", "header": "apikey" }, "tools": [ { "name": "list_projects", "description": "List all projects. Optionally filter by status - pass eq.active or eq.archived.", "method": "GET", "url": "https://.supabase.co/rest/v1/projects", "headers": { "Accept": "application/json" }, "input_schema": { "status": { "type": "string", "description": "Filter by status. PostgREST format: eq.active or eq.archived.", "optional": true } }, "response_transform": ".", "timeout_ms": 10000 }, { "name": "create_project", "description": "Create a new project.", "method": "POST", "url": "https://.supabase.co/rest/v1/projects", "headers": { "Content-Type": "application/json", "Prefer": "return=representation" }, "input_schema": { "name": { "type": "string", "description": "Project name." }, "description": { "type": "string", "description": "Project description.", "optional": true }, "status": { "type": "string", "description": "active or archived. Defaults to active.", "optional": true } }, "response_transform": ".", "timeout_ms": 10000 }, { "name": "update_project", "description": "Update one or more fields on a project by UUID.", "method": "PATCH", "url": "https://.supabase.co/rest/v1/projects?id=eq.:id", "headers": { "Content-Type": "application/json", "Prefer": "return=representation" }, "input_schema": { "id": { "type": "string", "description": "UUID of the project to update." }, "name": { "type": "string", "description": "New project name.", "optional": true }, "description": { "type": "string", "description": "New project description.", "optional": true }, "status": { "type": "string", "description": "New status: active or archived.", "optional": true } }, "response_transform": ".", "timeout_ms": 10000 }, { "name": "delete_project", "description": "Delete a project by UUID. Cascades to all associated tasks.", "method": "DELETE", "url": "https://.supabase.co/rest/v1/projects?id=eq.:id", "headers": { "Accept": "application/json" }, "input_schema": { "id": { "type": "string", "description": "UUID of the project to delete." } }, "response_transform": ".", "timeout_ms": 10000 }, { "name": "list_tasks", "description": "List tasks. Filter by project_id, status, or priority using PostgREST format (e.g. eq.todo, eq.high).", "method": "GET", "url": "https://.supabase.co/rest/v1/tasks", "headers": { "Accept": "application/json" }, "input_schema": { "project_id": { "type": "string", "description": "Filter by project UUID. PostgREST format: eq..", "optional": true }, "status": { "type": "string", "description": "Filter by status: eq.todo, eq.in_progress, or eq.done.", "optional": true }, "priority": { "type": "string", "description": "Filter by priority: eq.low, eq.medium, or eq.high.", "optional": true } }, "response_transform": ".", "timeout_ms": 10000 }, { "name": "create_task", "description": "Create a new task within a project.", "method": "POST", "url": "https://.supabase.co/rest/v1/tasks", "headers": { "Content-Type": "application/json", "Prefer": "return=representation" }, "input_schema": { "project_id": { "type": "string", "description": "UUID of the parent project." }, "title": { "type": "string", "description": "Task title." }, "description": { "type": "string", "description": "Task description.", "optional": true }, "status": { "type": "string", "description": "todo, in_progress, or done. Defaults to todo.", "optional": true }, "priority": { "type": "string", "description": "low, medium, or high. Defaults to medium.", "optional": true }, "assignee": { "type": "string", "description": "Name or identifier of the assignee.", "optional": true }, "due_date": { "type": "string", "description": "Due date in YYYY-MM-DD format.", "optional": true } }, "response_transform": ".", "timeout_ms": 10000 }, { "name": "update_task", "description": "Update one or more fields on a task by UUID.", "method": "PATCH", "url": "https://.supabase.co/rest/v1/tasks?id=eq.:id", "headers": { "Content-Type": "application/json", "Prefer": "return=representation" }, "input_schema": { "id": { "type": "string", "description": "UUID of the task to update." }, "title": { "type": "string", "description": "New task title.", "optional": true }, "description": { "type": "string", "description": "New task description.", "optional": true }, "status": { "type": "string", "description": "New status: todo, in_progress, or done.", "optional": true }, "priority": { "type": "string", "description": "New priority: low, medium, or high.", "optional": true }, "assignee": { "type": "string", "description": "New assignee.", "optional": true }, "due_date": { "type": "string", "description": "New due date in YYYY-MM-DD format.", "optional": true } }, "response_transform": ".", "timeout_ms": 10000 }, { "name": "delete_task", "description": "Delete a task by UUID.", "method": "DELETE", "url": "https://.supabase.co/rest/v1/tasks?id=eq.:id", "headers": { "Accept": "application/json" }, "input_schema": { "id": { "type": "string", "description": "UUID of the task to delete." } }, "response_transform": ".", "timeout_ms": 10000 } ] } ``` ## Connecting the server Once created in Shredly, add it to your MCP client using your Supabase service role key as the API key. **Claude Code:** ```bash claude mcp add --transport http my-app-pm \ https://mcp.shredly.io/mcp/my-app-pm \ --header "Authorization: Bearer " ``` ## Next steps - [MCP Server Schema](./mcp-server-schema) — full reference for tool definitions, auth options, and URL templates. - [Quick Start](./mcp-setup/quick-start) — end-to-end walkthrough of creating your first MCP server with an agent.