Settings & Credentials
Plugins can declare a settings schema that the desktop app uses to auto-render a configuration UI. This eliminates the need for custom Svelte components — you describe what settings you need, and the app builds the form.
PluginSettingsSchema
Section titled “PluginSettingsSchema”The settings property on MondayMorningPlugin accepts a PluginSettingsSchema:
interface PluginSettingsSchema { /** Credential fields (API keys, tokens, passwords) */ credentials?: CredentialField[]; /** Global configuration fields (apply to all projects) */ config?: ConfigField[]; /** Per-project configuration fields */ projectConfig?: ConfigField[];}There are three levels of settings:
| Level | Scope | Where Rendered |
|---|---|---|
credentials | Global (all projects) | Settings > Plugins |
config | Global (all projects) | Settings > Plugins |
projectConfig | Per-project | Project Settings > Plugins |
Credential Fields
Section titled “Credential Fields”Use CredentialField for API tokens, passwords, and secrets. The desktop app renders these with masked input fields and optional help links.
interface CredentialField { /** Storage key, e.g., "github_token" */ key: string; /** Display label */ label: string; /** Input type: "text" for visible, "password" for masked */ type: "text" | "password"; /** Whether the credential is required for the plugin to function */ required: boolean; /** URL to help the user generate/find this credential */ helpUrl?: string; /** Explanatory text shown below the input */ helpText?: string; /** OAuth scopes or permissions needed */ scopes?: string[]; /** Endpoint to test the credential against */ testEndpoint?: string;}Example: API Token
Section titled “Example: API Token”settings: { credentials: [ { key: "github_token", label: "Personal Access Token", type: "password", required: true, helpUrl: "https://github.com/settings/tokens/new", helpText: "Generate a PAT with 'repo' and 'read:org' scopes", scopes: ["repo", "read:org"], }, ],},The desktop app renders this as:
- A masked password input for the token value
- A clickable help link that opens the GitHub token creation page
- A description showing the required scopes
- A “Test Connection” button if
testEndpointis provided
Multiple Credentials
Section titled “Multiple Credentials”Some integrations need more than one credential:
settings: { credentials: [ { key: "api_key", label: "API Key", type: "password", required: true, helpUrl: "https://example.com/api-keys", helpText: "Find your API key in Account Settings", }, { key: "workspace_id", label: "Workspace ID", type: "text", required: true, helpText: "The numeric workspace ID from your dashboard URL", }, ],},Configuration Fields
Section titled “Configuration Fields”Use ConfigField for non-secret settings like feature toggles, default values, and picker fields.
interface ConfigField { /** Storage key */ key: string; /** Display label */ label: string; /** Input type */ type: "text" | "number" | "boolean" | "select" | "channel" | "repo-picker" | "board-picker"; /** Default value */ default?: string | number | boolean; /** Options for "select" type */ options?: { label: string; value: string }[]; /** Description shown below the input */ description?: string; /** Only show this field when another field has a truthy value */ dependsOn?: string; /** Placeholder text for text/number inputs */ placeholder?: string; /** Tauri command to fetch options for picker types */ fetchCommand?: string;}Field Types
Section titled “Field Types”Text Input
Section titled “Text Input”{ key: "default_label", label: "Default Label", type: "text", default: "bug", placeholder: "Enter a label name", description: "Applied to new issues by default",}Number Input
Section titled “Number Input”{ key: "sync_interval", label: "Sync Interval (minutes)", type: "number", default: 30, description: "How often to check for changes",}Boolean Toggle
Section titled “Boolean Toggle”{ key: "auto_sync", label: "Auto-sync on project open", type: "boolean", default: true, description: "Automatically sync when switching to this project",}Select Dropdown
Section titled “Select Dropdown”{ key: "sync_direction", label: "Sync Direction", type: "select", default: "both", options: [ { label: "Pull only", value: "pull" }, { label: "Push only", value: "push" }, { label: "Bidirectional", value: "both" }, ],}Picker Fields
Section titled “Picker Fields”Picker types (channel, repo-picker, board-picker) fetch their options dynamically from a Tauri command:
{ key: "github_repo", label: "Repository", type: "repo-picker", description: "Select the GitHub repository for this project", fetchCommand: "list_github_repos",}Conditional Fields
Section titled “Conditional Fields”Use dependsOn to show a field only when another setting is enabled:
config: [ { key: "notifications_enabled", label: "Enable Notifications", type: "boolean", default: false, }, { key: "notification_channel", label: "Notification Channel", type: "channel", dependsOn: "notifications_enabled", description: "Only shown when notifications are enabled", },],Per-Project Configuration
Section titled “Per-Project Configuration”Use projectConfig for settings that vary between projects. These appear in the project settings panel rather than global plugin settings:
settings: { credentials: [ { key: "api_token", label: "API Token", type: "password", required: true, }, ], projectConfig: [ { key: "board_id", label: "Board", type: "board-picker", description: "Select the board to sync with this project", fetchCommand: "list_boards", }, { key: "sync_labels", label: "Sync Labels", type: "boolean", default: true, description: "Include labels when syncing issues", }, ],},Credential Storage
Section titled “Credential Storage”Credentials entered through the settings UI are stored securely by the desktop app:
- On macOS, credentials are stored in the system Keychain via Tauri’s secure storage API.
- Credential values are never written to disk in plain text.
- The MCP server accesses credentials through environment variables or the Tauri command bridge.
Accessing Credentials in Tool Handlers
Section titled “Accessing Credentials in Tool Handlers”Tool handlers can read credential values from the integration config files that the desktop app writes:
import * as fs from "fs/promises";import * as path from "path";
export async function myToolHandler(input: MyToolInput): Promise<MyToolOutput> { // Read integration config written by the desktop app const configPath = path.join(input.project_path, ".mm", "integrations", "my-plugin.json"); try { const raw = await fs.readFile(configPath, "utf-8"); const config = JSON.parse(raw); const token = config.api_token;
if (!token) { return { success: false, error: "API token not configured. Set it in Settings > Plugins.", }; }
// Use the token... } catch { return { success: false, error: "Plugin not configured. Set credentials in Settings > Plugins.", }; }}Complete Example
Section titled “Complete Example”Here is a full plugin with credentials, global config, and per-project config:
const slackPlugin: MondayMorningPlugin = { id: "slack", name: "Slack Integration", description: "Post updates and digests to Slack channels", version: "1.0.0", category: "integration", uiCategory: "communications",
settings: { credentials: [ { key: "slack_bot_token", label: "Bot Token", type: "password", required: true, helpUrl: "https://api.slack.com/apps", helpText: "Create a Slack app and install it to your workspace", scopes: ["chat:write", "channels:read"], }, ], config: [ { key: "digest_enabled", label: "Daily Digest", type: "boolean", default: false, description: "Post a daily summary to the configured channel", }, { key: "digest_time", label: "Digest Time", type: "select", default: "09:00", dependsOn: "digest_enabled", options: [ { label: "8:00 AM", value: "08:00" }, { label: "9:00 AM", value: "09:00" }, { label: "10:00 AM", value: "10:00" }, ], }, ], projectConfig: [ { key: "slack_channel", label: "Channel", type: "channel", description: "Slack channel for this project's updates", fetchCommand: "list_slack_channels", }, ], },
tools: [ // ... tool definitions ],
register: async (context) => { context.logger.info("Slack plugin registered"); },};Next Steps
Section titled “Next Steps”- Tool Registration — Define MCP tools with Zod schemas and handlers.
- Plugin Architecture — Understand the full plugin lifecycle.