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

# Snappy MCP Server: Connect Claude & ChatGPT

> Plug Snappy into Claude, ChatGPT, and other MCP-compatible AI clients. Setup, supported tools, and security model.

Snappy's MCP (Model Context Protocol) Server allows AI systems - such as Microsoft Copilot, custom AI agents, or any MCP-compatible client - to send gifts through natural language interactions. Instead of building API integrations manually, your AI agent can call Snappy's MCP tools directly to manage campaigns and send gifts on behalf of users.

<Note>
  This integration path is designed for AI-driven environments. If you're building a standard programmatic integration, use the [Snappy REST API](/pages/quickstart) instead.
</Note>

## Prerequisites

Before connecting an AI system to the MCP server, make sure the following are configured in your Snappy Dashboard:

* A valid Snappy user account (username, password, and optional TOTP)
* At least one Company and Account
* At least one Collection configured for your Account
* Recipients set up, or ready to be managed via API

The MCP server endpoint is provisioned by Snappy. Contact your account manager to get the URL for your environment.

***

## How It Works

Your AI system connects to the Snappy MCP server and authenticates using user credentials. Once authenticated, it can call a set of structured tools to retrieve collections, generate personalized content, create campaigns, and send gifts - all through a standardized protocol.

### Authentication

The MCP server uses session-based authentication. Call the `sign-in` tool with your Snappy credentials to establish a session:

```json theme={null}
{
  "method": "tools/call",
  "params": {
    "name": "sign-in",
    "arguments": {
      "username": "your@email.com",
      "password": "your_password",
      "totp": "123456"
    }
  }
}
```

**Successful response:**

```json theme={null}
{
  "content": [
    {
      "type": "text",
      "text": "Successfully signed in. Available accounts: [Account data]"
    }
  ]
}
```

For **HTTP transport**, each request must include authentication. For **SSE transport**, the session is maintained automatically after sign-in.

<Warning>
  Never hardcode usernames, passwords, or TOTP codes. Use environment variables or a secrets manager. See [Best Practices](#best-practices) below.
</Warning>

***

## Available Tools

| Tool                      | Purpose                                  | Required auth | Key parameters                                                               |
| :------------------------ | :--------------------------------------- | :------------ | :--------------------------------------------------------------------------- |
| `sign-in`                 | Authenticate with the MCP server         | No            | `username`, `password`, `totp?`                                              |
| `check-sign-in`           | Verify current authentication status     | No            | None                                                                         |
| `get-account-collections` | List collections available to an Account | Yes           | `accountId`                                                                  |
| `get-collection-products` | Retrieve products within a collection    | Yes           | `collectionId`, `maxBudget?`, `country?`                                     |
| `create-email`            | Generate AI-powered email content        | Yes           | `occasion`, `tone?`, `primaryColor?`                                         |
| `create-greeting`         | Generate a personalized greeting card    | Yes           | `occasion`, `tone?`, `primaryColor?`                                         |
| `choose-reveal`           | Select the gift reveal experience        | Yes           | `occasion`, `brandColors?`                                                   |
| `create-campaign`         | Create a new gift campaign               | Yes           | `companyId`, `accountId`, `collectionId`, `name`, `budgets`, `recipientsIds` |
| `send-gifts`              | Send gifts within a campaign             | Yes           | `campaignId`, `recipients`, `budget`, `productCollectionId`                  |

### Tool examples

#### `get-account-collections`

```json theme={null}
{
  "method": "tools/call",
  "params": {
    "name": "get-account-collections",
    "arguments": {
      "accountId": "account_12345"
    }
  }
}
```

**Response:**

```json theme={null}
{
  "content": [{
    "type": "text",
    "text": "[{\"_id\":\"coll_123\",\"name\":\"Premium Business Collection\",\"rank\":1},{\"_id\":\"coll_456\",\"name\":\"Holiday Special Collection\",\"rank\":2}]"
  }]
}
```

#### `create-campaign`

```json theme={null}
{
  "method": "tools/call",
  "params": {
    "name": "create-campaign",
    "arguments": {
      "companyId": "comp_789",
      "accountId": "acc_123",
      "collectionId": "coll_456",
      "name": "Q4 Employee Appreciation Campaign",
      "maxBudget": 75,
      "minBudget": 25,
      "recipientsIds": ["recipient_1", "recipient_2"],
      "email": {
        "mailSubject": "A special gift for you!",
        "mailGreeting": "Dear {receiver_first_name}",
        "mailBody": "We appreciate your hard work this quarter.",
        "mailSignature": "Best regards, The Team"
      }
    }
  }
}
```

***

## The Gift Sending Flow

Regardless of which AI system you're connecting, the gifting flow follows the same sequence:

1. `sign-in` - authenticate and establish a session
2. `get-account-collections` - retrieve available collections
3. `create-email` + `create-greeting` + `choose-reveal` - generate personalized content (these three can run in parallel)
4. `create-campaign` - set up the campaign with recipients and content
5. `send-gifts` - trigger the gift send

***

## Quick Start: Adding to Your AI Agent (MCP Config)

To add Snappy to any MCP-compatible AI environment, point your MCP configuration to the Snappy server URL provided by your account manager:

```javascript theme={null}
const mcpConfig = {
  serverUrl: "<your-snappy-mcp-server-url>",
  transport: "http",
  authentication: {
    type: "user_credentials",
    endpoint: "/auth/sign-in"
  }
};
```

***

## Worked Example: Node.js Bot

A complete Node.js example that handles a `/sendgift` chat command, authenticates, generates personalized content in parallel, and creates and sends a campaign.

```javascript theme={null}
const MCPClient = require('./mcp-client');

class SnappyGiftBot {
  constructor() {
    this.mcpClient = new MCPClient(process.env.SNAPPY_MCP_URL);
  }

  async sendGift(params) {
    // 1. Authenticate (use cached session in production)
    await this.mcpClient.signIn(
      process.env.SNAPPY_USERNAME,
      process.env.SNAPPY_PASSWORD
    );

    // 2. Get collections and pick one for the occasion
    const collections = await this.mcpClient.getAccountCollections(params.accountId);
    const selectedCollection = this.selectBestCollection(collections, params.occasion);

    // 3. Generate personalized content in parallel
    const [email, greeting, reveal] = await Promise.all([
      this.mcpClient.createEmail({ occasion: params.occasion, tone: 'professional' }),
      this.mcpClient.createGreeting({ occasion: params.occasion }),
      this.mcpClient.chooseReveal({ occasion: params.occasion })
    ]);

    // 4. Create campaign
    const campaign = await this.mcpClient.createCampaign({
      companyId: params.companyId,
      accountId: params.accountId,
      collectionId: selectedCollection._id,
      name: `${params.occasion} Gift - ${new Date().toLocaleDateString()}`,
      maxBudget: params.maxBudget,
      minBudget: params.minBudget,
      recipientsIds: [params.recipientId],
      email: JSON.parse(email.content)
    });

    // 5. Send gifts
    await this.mcpClient.sendGifts({
      campaignId: campaign.created._id,
      recipients: { type: 'ids', recipientsList: [params.recipientId] },
      budget: { plan: params.budget, max: params.maxBudget, min: params.minBudget },
      productCollectionId: selectedCollection._id
    });

    return { campaignName: campaign.name, collectionName: selectedCollection.name };
  }
}
```

***

## Error Handling

### Common error scenarios

**Authentication failed**

```json theme={null}
{
  "error": {
    "code": "AUTH_FAILED",
    "message": "Login failed",
    "details": "Invalid username or password"
  }
}
```

**TOTP required**

```json theme={null}
{
  "content": [{
    "type": "text",
    "text": "Please enter your TOTP code from your authenticator app"
  }]
}
```

When you see this response, prompt the user (or your secret store) for the current TOTP and re-call `sign-in` with the `totp` argument populated.

**Resource not found**

```json theme={null}
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Collection not found",
    "collectionId": "invalid_collection_id"
  }
}
```

**No products available for criteria**

```json theme={null}
{
  "error": {
    "code": "NO_PRODUCTS_AVAILABLE",
    "message": "No products available for the specified criteria",
    "details": {
      "budget": 25,
      "country": "US",
      "collectionId": "coll_123"
    }
  }
}
```

### Retry strategy

Use exponential backoff for transient failures (network errors, timeouts, 5xx). Do not retry `AUTH_FAILED` or `NOT_FOUND`.

```javascript theme={null}
class MCPErrorHandler {
  static async withRetry(operation, maxRetries = 3) {
    for (let attempt = 1; attempt <= maxRetries; attempt++) {
      try {
        return await operation();
      } catch (error) {
        if (attempt === maxRetries || !this.isRetryableError(error)) {
          throw error;
        }
        const delay = Math.pow(2, attempt) * 1000;
        await new Promise(resolve => setTimeout(resolve, delay));
      }
    }
  }

  static isRetryableError(error) {
    return ['NETWORK_ERROR', 'TIMEOUT', 'SERVER_ERROR'].includes(error.code);
  }
}
```

***

## Best Practices

**Secure credentials.** Never hardcode username, password, or TOTP. Pull them from environment variables or a secrets manager. When logging tool calls for observability, redact `password` and `totp` before writing.

**Reuse sessions.** Don't call `sign-in` on every request. Cache the session and refresh only when expired:

```javascript theme={null}
class MCPSessionManager {
  constructor() {
    this.session = null;
    this.lastAuth = null;
  }

  async getValidSession() {
    if (this.isSessionExpired()) {
      this.session = await this.authenticate();
      this.lastAuth = Date.now();
    }
    return this.session;
  }
}
```

**Run content generation in parallel.** `create-email`, `create-greeting`, and `choose-reveal` are independent - call them concurrently to cut latency.

**Cache collections.** Collection data changes infrequently. A 5-minute in-memory cache keyed by `accountId` is usually sufficient.

***

## Troubleshooting

**Check authentication status** before debugging tool calls:

```javascript theme={null}
const authStatus = await mcpClient.checkSignIn();
console.log('Auth Status:', authStatus);
```

**Confirm account setup** if collections come back empty:

```javascript theme={null}
const collections = await mcpClient.getAccountCollections(accountId);
if (collections.length === 0) {
  throw new Error('No collections available. Set up collections in the Snappy Dashboard.');
}
```

**Test individual tools** in isolation when narrowing down a failing flow - call `get-account-collections` and `get-collection-products` directly to verify the data exists before calling `create-campaign`.

For additional support, contact your Snappy account manager.
