Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.sigmic.ai/llms.txt

Use this file to discover all available pages before exploring further.

When you embed the widget, each end user likely needs the agent to connect to their data — their database, their API, their tenant. Environment variables and secrets let you pass per-user credentials at token exchange time so the agent’s MCP servers connect to the right services for each end user.

How It Works

Your Backend                        Sigmic AI                          Agent Sandbox
     |                                   |                                |
     | 1. POST /api/v1/auth/token        |                                |
     |   { env: { TENANT_ID: "acme" },   |                                |
     |     secrets: { API_KEY: "sk-…" } } |                                |
     |---------------------------------->|                                |
     |   Stores env + secrets            |                                |
     |   server-side (encrypted)         |                                |
     |                                   |                                |
     |                                   | 2. User sends a message        |
     |                                   |   (Authorization: Bearer JWT)  |
     |                                   |                                |
     |                                   | 3. Retrieves stored env+secrets|
     |                                   |   Injects into MCP server      |
     |                                   |   configuration                |
     |                                   |------------------------------->|
     |                                   |   {{mcp.KEY}} → actual value   |
  1. Your backend passes env and secrets when exchanging credentials for a widget JWT
  2. Sigmic AI stores them server-side — secrets are encrypted at rest. Neither env nor secrets are included in the JWT itself or sent to the browser.
  3. When the user chats, the platform retrieves the stored values and injects them into every MCP server in the project. Template placeholders like {{mcp.API_KEY}} in your server config are resolved to the actual values before the connection is established.

env vs secrets

Both env and secrets are key-value string maps passed in the token exchange request. The difference is how they are stored:
envsecrets
StorageEncrypted at restEncrypted at rest
Returned in API responsesNeverNever
Sent to the browserNeverNever
Use forTenant IDs, regions, feature flagsAPI tokens, database URLs, passwords
Available as{{mcp.KEY}} in MCP config{{mcp.KEY}} in MCP config
If the same key appears in both env and secrets, the secrets value takes precedence.
The env/secrets distinction exists for forward compatibility. Today both are stored securely. Use secrets for anything sensitive (tokens, passwords, connection strings) and env for non-sensitive configuration (tenant IDs, regions, feature flags).

Using Variables in MCP Server Config

MCP servers are configured in your project settings (via the Console or the project config API). Use {{mcp.KEY}} placeholders in the server’s headers, env, or url fields. These placeholders are resolved at runtime using the env/secrets from the active widget token.

Example: HTTP server with API key in headers

Step 1 — Configure the MCP server in your project:
curl -X PUT "https://api.sigmic.ai/api/users/you/projects/my-project/config/mcp/my-api-server" \
  -H "Authorization: Bearer YOUR_JWT" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://mcp.example.com/v1",
    "type": "http",
    "headers": {
      "Authorization": "Bearer {{mcp.MY_API_TOKEN}}",
      "X-Tenant-ID": "{{mcp.TENANT_ID}}"
    },
    "enabled": true
  }'
Step 2 — Pass the values when issuing a widget token:
// Your backend — token exchange
const response = await fetch('https://api.sigmic.ai/api/v1/auth/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    appId: process.env.SIGMIC_APP_ID,
    appSecret: process.env.SIGMIC_APP_SECRET,
    endUserId: 'user-123',
    env: {
      TENANT_ID: currentUser.tenantId
    },
    secrets: {
      MY_API_TOKEN: currentUser.apiToken
    }
  })
});
Result: When the agent connects to my-api-server, the headers are resolved to:
Authorization: Bearer sk-actual-token-value
X-Tenant-ID: acme-corp

Example: stdio server with environment variables

MCP server config:
{
  "command": "npx",
  "args": ["-y", "@your-org/db-mcp-server"],
  "type": "stdio",
  "env": {
    "DATABASE_URL": "{{mcp.DATABASE_URL}}",
    "SCHEMA": "{{mcp.DB_SCHEMA}}"
  },
  "enabled": true
}
Widget token request:
const response = await fetch('https://api.sigmic.ai/api/v1/auth/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    appId: process.env.SIGMIC_APP_ID,
    appSecret: process.env.SIGMIC_APP_SECRET,
    endUserId: 'user-123',
    env: { DB_SCHEMA: 'public' },
    secrets: { DATABASE_URL: 'postgres://user:pass@host/acme_db' }
  })
});
Result: The MCP server process launches with these environment variables:
DATABASE_URL=postgres://user:pass@host/acme_db
SCHEMA=public

Example: SSE server with dynamic URL

{
  "url": "https://{{mcp.REGION}}.analytics.example.com/mcp/sse",
  "type": "sse",
  "headers": {
    "X-API-Key": "{{mcp.ANALYTICS_KEY}}"
  },
  "enabled": true
}
With env: { REGION: 'us-east-1' } and secrets: { ANALYTICS_KEY: 'ak-12345' }, the agent connects to https://us-east-1.analytics.example.com/mcp/sse with header X-API-Key: ak-12345.

Template Reference

AspectDetail
Syntax{{mcp.KEY_NAME}}
Supported fieldsheaders, env, and url in MCP server configs
Resolution timingWhen the MCP server connection is established (not at token issuance)
Missing keysIf a {{mcp.KEY}} has no matching value, it is left unchanged and a warning is logged
ScopeAll MCP servers in the project receive the same set of variables

Key naming rules

Keys must be valid environment variable names:
  • Start with a letter or underscore
  • Contain only letters, digits, and underscores
  • All values must be strings
ValidInvalid
TENANT_ID123-invalid (starts with digit)
API_KEYhas-dashes (contains hyphens)
db_urlhas spaces (contains spaces)
_INTERNALkey.with.dots (contains dots)

Multi-Tenant Example

A common pattern is passing per-tenant credentials so each end user’s widget session connects the agent to that user’s data:
// Express backend — /api/sigmic-chat/token
app.post('/api/sigmic-chat/token', async (req, res) => {
  // 1. Authenticate your own user
  const user = await authenticateRequest(req);

  // 2. Look up tenant-specific config
  const tenant = await db.tenants.findById(user.tenantId);

  // 3. Exchange for widget JWT with tenant-scoped context
  const response = await fetch('https://api.sigmic.ai/api/v1/auth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      appId: process.env.SIGMIC_APP_ID,
      appSecret: process.env.SIGMIC_APP_SECRET,
      endUserId: user.id,
      expiresIn: '1h',
      env: {
        TENANT_ID: tenant.id,
        TENANT_NAME: tenant.name,
        REGION: tenant.region
      },
      secrets: {
        DATABASE_URL: tenant.databaseUrl,
        API_TOKEN: tenant.apiToken
      }
    })
  });

  const data = await response.json();
  res.json({ token: data.data.token });
});
With the corresponding project MCP server config:
{
  "tenant-api": {
    "url": "https://{{mcp.REGION}}.api.example.com/mcp",
    "type": "http",
    "headers": {
      "Authorization": "Bearer {{mcp.API_TOKEN}}",
      "X-Tenant-ID": "{{mcp.TENANT_ID}}"
    },
    "enabled": true
  },
  "tenant-db": {
    "command": "npx",
    "args": ["-y", "@your-org/postgres-mcp"],
    "type": "stdio",
    "env": {
      "DATABASE_URL": "{{mcp.DATABASE_URL}}"
    },
    "enabled": true
  }
}
Each end user’s widget session connects the agent to that user’s database and API — with credentials that never leave the server.

Token Refresh and Variables

Each widget token has its own set of env/secrets. When you refresh a token, you must pass env and secrets again — the new token does not inherit values from the previous one. This also means you can update credentials on refresh without interrupting the session. For example, if an end user’s API key is rotated, the next token refresh can include the new key.
// fetchToken callback — re-fetch credentials on every refresh
fetchToken: async function() {
  const response = await fetch('/api/sigmic-chat/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ userId: currentUser.id })
  });
  const data = await response.json();
  return data.token;  // Backend re-fetches tenant credentials each time
}

Security

  • env and secrets are never included in the JWT — they are stored server-side only
  • They are never sent to the browser — the widget iframe only receives the JWT
  • Values are stored encrypted and automatically cleaned up when the token expires
  • Secrets are only decrypted when the agent session needs them
This is the same mechanism used by the Task API for passing environment variables. If you are already using env/secrets with the Task API, they work identically in the widget.