Skip to main content
Glama
modesty

Fluent MCP Server

by modesty
README.md
# Fluent MCP Server

An [MCP server](https://modelcontextprotocol.io) that brings [ServiceNow Fluent SDK](https://www.servicenow.com/docs/bundle/yokohama-application-development/page/build/servicenow-sdk/concept/servicenow-fluent.html) capabilities to AI-assisted development environments. Enables natural language interaction with ServiceNow SDK commands, API specifications, code snippets, and development resources.

Built for [@servicenow/sdk@v4.11.2](https://github.com/ServiceNow/sdk/releases#release-v4.11.0).

> **Note** : Since v0.6.0 the server speaks **both** [MCP@2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28) and [MCP@2025-11-25](https://modelcontextprotocol.io/specification/2025-11-25) from one handler set — the stdio entry inspects the opening message and serves whichever era the client opens with. [v0.5.1](https://github.com/modesty/fluent-mcp/releases#release-v0.5.1) is the last release built on the v1 MCP SDK (2025-11-25 only).

## Key Features

- **SDK Command Tools** - `sdk_info` plus ServiceNow SDK command tools for `init`, `build`, `install`, `dependencies`, `transform`, `download`, `clean`, `pack`, `explain`, `query`, and `cicd`
- **Rich Resources** - API specifications, instructions, and code snippets for **70 ServiceNow metadata types**
- **API Documentation Lookup** - `explain_fluent_api` returns SDK docs for any Fluent API or guide — no project required
- **Lazy Auto-Authentication** - Detects and caches an auth profile only when an auth-requiring command or `check_auth_status` needs it
- **Explicit Project Context** - Resolves each project command from its `workingDirectory` argument, the initialized session, or `FLUENT_MCP_WORKING_DIR`, then fails with actionable guidance instead of guessing
- **MCPB Bundle** - Builds a self-contained `.mcpb` distribution with the server, resources, and production dependencies
- **Client-Friendly Schemas** - Optional inputs advertise their canonical value types while the enforced schema accepts `null` as an omitted-value compatibility form

This MCP server implements the [Model Context Protocol](https://modelcontextprotocol.io) specification with the following capabilities:

### Core

- **Resources** - 300+ resources across 70 ServiceNow metadata types (API specs, instructions, snippets, prompts)
- **Tools** - 13 ServiceNow SDK command tools plus 4 resource/auth tools (17 total), with full parameter validation. Read tools (`get-api-spec`, `get-snippet`, `get-instruct`, `check_auth_status`) declare an `outputSchema` and return `structuredContent` for programmatic consumers
- **Prompts** - Development workflow templates for common ServiceNow tasks (`coding_in_fluent`, `create_custom_ui`)
- **Logging & Progress** - Structured logs are written to stderr; progress notifications are sent for long-running commands (any command with a 30s or longer timeout — deploy, build, transform, download, dependencies, query, pack, cicd) when the client supplies a progress token

### Project Context & Sessions

The server requires **no client capabilities** and issues **no server→client requests**: Roots, Sampling, and Elicitation are not used (MCP 2026-07-28 removed server-initiated requests, and all input arrives with the `tools/call` arguments). Automatic workspace detection through Roots is gone for every client, including MCPB hosts.

- **Session Management** - Tracks the directory established by `init_fluent_app` for subsequent project commands
- **Working Directory Resolution** - `workingDirectory` tool argument → initialized session → `FLUENT_MCP_WORKING_DIR` → actionable failure. Accepted paths are non-empty absolute paths other than the filesystem root. The server never guesses from its process cwd or installed package directory. Clients must pass `workingDirectory` or configure `FLUENT_MCP_WORKING_DIR` when no session directory exists.
- **Non-interactive `init_fluent_app`** - Intent-specific arguments must be supplied with the call (creation: `appName`, `packageName`, `scopeName`, `template`; conversion: `from`); a missing argument fails with an error naming exactly what is absent. The tool does not prompt or elicit missing values.
- **Error Handling** - Comprehensive error messages with actionable guidance
- **Type Safety** - Full TypeScript implementation with strict typing

### Protocol Behavior

- Dual-era stdio: a 2026-07-28 opening (per-request `_meta` envelope, `server/discover`) and a 2025-11-25 `initialize` are both served from the same handler set; the SDK entry point pins one era per connection.
- The six cacheable results of 2026-07-28 (`tools/list`, `prompts/list`, `resources/list`, `resources/templates/list`, `resources/read`, `server/discover`) advertise `ttlMs: 3600000` / `cacheScope: 'public'` — everything they return is static for the process lifetime.
- The server advertises instructions during initialization; `tools/list` is a side-effect-free read that returns tools in deterministic name order.
- Optional tool arguments advertise their canonical JSON types so clients render normal form fields. The enforced call schema additionally accepts `null` as an omitted value; `workingDirectory` also treats an empty string as omitted before applying the fallback chain.
- Structured logs go to stderr, keeping stdout reserved for MCP protocol traffic. Runtime `logging/setLevel` and `notifications/message` are not used.
- Resource misses use the standard JSON-RPC invalid-params code (`-32602`).

## Quick Start

```bash
# Test with MCP Inspector
npx @modelcontextprotocol/inspector npx @modesty/fluent-mcp

# Build the optional self-contained MCPB distribution
npm run bundle

# Or use in your MCP client (see Configuration below)
```

### MCPB Distribution

The optional `npm run bundle` command produces `fluent-mcp-<version>.mcpb`. The bundle contains `dist/`, `res/`, and production dependencies, and its `manifest.json` declares all 17 tools. MCPB hosts expose these user-configurable values to the server:

- `FLUENT_MCP_WORKING_DIR` — optional default project directory; otherwise pass `workingDirectory` on project-aware tool calls
- `SN_INSTANCE_URL` — optional instance URL for lazy authentication validation
- `SN_AUTH_TYPE` — authentication type (`basic` or `oauth`, default `oauth`)

The npm package remains the primary distribution channel. MCPB does not restore Roots-based workspace detection or interactive `init_fluent_app` prompting.

**Example prompt:**

```text
Create a new Fluent app in ~/projects/time-off-tracker to manage employee PTO requests
```

## Available Tools

### SDK Command Tools (13)

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `sdk_info` | Get SDK version or help | `flag` (-v/-h), `command` (optional for -h) |
| `explain_fluent_api` | Look up Fluent SDK documentation for any API or guide. No Fluent project required. | `topic` (optional API/guide name or tag keyword — required unless `list=true`), `list` (boolean — list topics), `peek` (boolean — brief summary), `format` (`pretty`\|`raw`), `source` (optional project path override), `debug` (optional) |
| `init_fluent_app` | Initialize or convert a ServiceNow app. Non-interactive: missing intent-specific arguments fail with an error naming them. | `intent`, `from` (conversion), `appName`/`packageName`/`scopeName`/`template` (creation), `auth`, `workingDirectory` (required), `debug` |
| `build_fluent_app` | Build the application | `workingDirectory`, `debug` (optional) |
| `deploy_fluent_app` | Deploy to a ServiceNow instance. SDK flow activation can be skipped. | `workingDirectory`, `auth` (auto-injected), `skipFlowActivation`, `debug` |
| `fluent_transform` | Convert XML or instance metadata to Fluent TypeScript. Local paths do not require auth; instance transforms do. | `workingDirectory`, `from`, `directory`, `auth` (auto-injected), `table`, `id`, `debug` |
| `download_fluent_dependencies` | Download dependencies and type definitions | `workingDirectory`, `auth` (auto-injected), `debug` |
| `download_fluent_app` | Download metadata from an instance | `workingDirectory`, `directory` (required), `source`, `auth` (auto-injected), `incremental`, `debug` |
| `clean_fluent_app` | Clean output directory | `workingDirectory`, `source` (optional), `debug` |
| `pack_fluent_app` | Create an installable artifact | `workingDirectory`, `source` (optional), `debug` |
| `query_fluent_records` | Read-only Table REST query against an instance; returns a JSON envelope | `workingDirectory`, `table` (required), `query` (required encoded query), `fields`, `limit`, `offset`, `displayValue`, `view`, `queryCategory`, `excludeReferenceLink`, `noCount`, `queryNoDomain`, `timeout`, `select`, `auth` (auto-injected), `debug` |
| `cicd_fluent_app` | Install, publish, or rollback an app via the ServiceNow CI/CD API (`sn_cicd`). **Changes instance state.** | `workingDirectory`, `action` (required: `install`\|`publish`\|`rollback`), `scope`\|`appSysId`, `appVersion` (required for rollback, and for install/publish outside a Fluent project), `baseAppVersion`, `autoUpgradeBaseApp`, `devNotes`, `wait`, `pollTimeout`, `auth` (auto-injected), `output` (`json`\|`raw`), `select`, `debug` |
| `cicd_fluent_test` | Run, watch, or fetch results for ATF test suites and tests via the CI/CD API. `run` executes real ATF steps on the instance. No Fluent project required (and none accepted). | `target` (required: `testsuite`\|`test`), `action` (required: `run`\|`watch`\|`result`), `testSuiteSysId`\|`testSuiteName`, `testSysId`\|`testName`, `progressId` (watch), `resultId` (result), `browserName`, `browserVersion`, `osName`, `osVersion`, `runInCloud`, `isPerformanceRun`, `captureNodeLogs`, `wait`, `pollTimeout`, `auth` (auto-injected), `output` (`json`\|`raw`), `select`, `debug` |

### Resource and Authentication Tools (4)

| Tool | Description | Key Parameters |
|------|-------------|----------------|
| `get-api-spec` | Get an API specification or list all available metadata types | `metadataType` (optional; omit to list all) |
| `get-snippet` | Get a Fluent code snippet; without `id`, returns the first available snippet and any additional snippet IDs | `metadataType` (required), `id` (optional) |
| `get-instruct` | Get authoring guidance, conventions, and common pitfalls for a metadata type | `metadataType` (required) |
| `check_auth_status` | Lazily validate configured ServiceNow authentication and return structured status information | No arguments |

> **Note:** Authentication is validated lazily on the first auth-requiring command or `check_auth_status`, then cached for the session. Use `init_fluent_app` to establish project context, pass `workingDirectory` per call, or set `FLUENT_MCP_WORKING_DIR`. Any optional argument sent as `null` is treated as omitted; `workingDirectory` also treats an empty string as omitted and falls through to the next source.

#### Looking up Fluent APIs with `explain_fluent_api`

`explain_fluent_api` wraps `now-sdk explain` and returns SDK documentation for any Fluent API class **or** topic guide. It works from any directory — no Fluent project required.

| Invocation | Result |
|---|---|
| `explain_fluent_api({ topic: 'BusinessRule' })` | Full API reference for `BusinessRule` |
| `explain_fluent_api({ topic: 'BusinessRule', peek: true })` | Brief summary of `BusinessRule` |
| `explain_fluent_api({ topic: 'BusinessRule', format: 'raw' })` | Full API reference as plain markdown (good for piping into other tools) |
| `explain_fluent_api({ list: true })` | Full topic index (all APIs and guides) |
| `explain_fluent_api({ list: true, topic: 'atf' })` | Topic index filtered to entries matching `atf` |

`topic` matches an API name (e.g. `BusinessRule`, `Acl`), a guide name (e.g. `business-rule-guide`, `atf-guide`), or a tag keyword (e.g. `flow`, `atf`, `email`). The SDK resolves by exact name first, then by tag.

## Resources

Standardized URI patterns following MCP specification:

| Resource Type | URI Pattern | Example | Purpose |
|---------------|-------------|---------|----------|
| **API Specs** | `sn-spec://{type}` | `sn-spec://business-rule` | API documentation and parameters |
| **Instructions** | `sn-instruct://{type}` | `sn-instruct://script-include` | Best practices and guidance |
| **Code Snippets** | `sn-snippet://{type}/{id}` | `sn-snippet://acl/0001` | Practical code examples |
| **Prompts** | `sn-prompt://{id}` | `sn-prompt://coding_in_fluent` | Development guides |

### Supported Metadata Types

71 metadata types across the following categories:

**Core Types:** `acl`, `application-menu`, `business-rule`, `client-script`, `cross-scope-privilege`, `data-policy`, `field-style`, `form`, `import-set`, `instance-scan`, `list`, `property`, `role`, `scheduled-script`, `script-action`, `script-include`, `scripted-rest`, `sla`, `state-model`, `table`, `ui-action`, `ui-page`, `ui-policy`, `user-preference`

**Table Types:** `column`, `column-generic`

**Service Catalog:** `catalog-item`, `catalog-item-record-producer`, `catalog-ui-policy`, `catalog-client-script`, `catalog-variable`, `variable-set`

**Email:** `email-notification`, `inbound-email-action`

**Automation & Workflow:** `flow`, `custom-action`, `playbook`

**Integration & Connections:** `alias`, `alias-template`, `retry-policy`, `rest-message`, `data-lookup`, `graphql-api`

**AI & Now Assist:** `ai-agent`, `ai-agent-workflow`, `now-assist-skill-config`

**Service Portal:** `service-portal`, `sp-header-footer`, `sp-page-route-map`

**Workspace & Analytics:** `workspace`, `dashboard`

**ATF (Automated Test Framework):** `atf` (the `Test()` container and family entry point — start here, then route to a step sub-type), `atf-appnav`, `atf-catalog-action`, `atf-catalog-validation`, `atf-catalog-variable`, `atf-email`, `atf-form`, `atf-form-action`, `atf-form-declarative-action`, `atf-form-field`, `atf-form-sp`, `atf-list`, `atf-reporting`, `atf-rest-api`, `atf-rest-assert-payload`, `atf-server`, `atf-server-catalog-item`, `atf-server-record`, `atf-ui-test-script`, `test-suite`

### What's new in 4.11.2

This release of the MCP server tracks `@servicenow/sdk` 4.11.2, covering the authoring-surface additions shipped across 4.11.0 and 4.11.2 (4.11.1 was never published to npm, and 4.11.2 shipped no release notes — its surface was established by diffing the installed package):

- **New metadata type**: `test-suite` — the `TestSuite` API groups existing ATF `Test()` records into a named, orderable, optionally nested suite, writing `sys_atf_test_suite` plus one `sys_atf_test_suite_test` membership row per entry. Run order comes from **array position**, not an authored field. It is **authoring only**: it never triggers or schedules a run — use ATF's UI/scheduler or `cicd_fluent_test`.
- **New metadata type**: `graphql-api` — the `GraphQLApi` API defines a scripted GraphQL API (`sys_graphql_schema`) with its resolvers, type resolvers, and two-tier security: schema-gate ACLs on the whole API plus standalone field-level `Acl({ type: 'graphql' })` path ACLs. Resolver `paths` use `Type:field`; ACL names use the slash-delimited runtime query path.
- **New metadata type**: `field-style` — `sys_ui_style` is now a supported `Record()` table, making conditional list/form field styling authorable in Fluent (there is no `FieldStyle()` constructor). `style` accepts any CSS property, so this is also the mechanism for list column `width` and `text-align`.
- **Flow do-while loop** — `wfa.flowLogic.doTheFollowing({ $id, label?, annotation? }, () => { ... })` repeats a body until `wfa.flowLogic.until('<condition>')`, called as the body's last statement, is satisfied. The body always runs at least once and the condition may reference outputs of actions inside the same body, which makes it the right construct for polling and retries.
- **Playbook on-demand execution** — `executionType` widened to `'record_driven' | 'on_demand'`. A standalone playbook must omit `triggers` entirely, cannot set `parentTable` or reference `params.parentRecord`, may finally set `allowAsNested: true`, and **must grant `launch: true` in at least one permission set** or the build fails.
- **Playbook permissions** — new `permissions` on argument 2 (a **callback**, so pills can reach `params.parentRecord`) and on each `LaneConfig` (a **plain object**), each grouping `users`/`userGroups`/`roles`/`userCriterias`. On a playbook set `view` is required and gates every other flag; on a lane set all four flags are independent. `wfa.playbook.activityRef(Now.ID['x'])` reaches an activity's outputs from inside a permissions block.
- **Playbook optional activities** — `startRule: wfa.playbook.run.Manually()` declares an activity a user starts by hand. It returns a `ManualActivityReference` with no outputs that is deliberately outside the dependency union: because it may never run, nothing can wait on it with `run.After()`.
- **Playbook launcher and outputs** — `launcherTitle`, `launcherDescription`, and `launcherInputs` configure the on-demand launcher; the record-form fields (`launcherShowRecordForm`, `launcherRecordFormView`, `launcherTemplateFields`) belong to **record-driven** playbooks. New OOB activity `ActivityDefinitions.Core.SetPlaybookOutputs` writes the playbook's own declared `outputs`.
- **Playbook AI-agent activities** — AI-agent configuration is exposed on the four OOB definitions that opted in (`RecordForm`, `AutocompletingRecordForm`, `NewRecordForm`, `EmailForm`). `aiAgentObjective` becomes mandatory once `enableAiAgent` is true. The SDK validates neither platform prerequisite (`sn_genai_platform` installed, `sn_pa_designer.enable_agentic_playbooks` true).
- **Dependent record inputs** — `UpdateRecord`/`CreateNewRecord` now type-check a `record` pill against the sibling `table_name` input, and `Action()` carries `rawInputs` for the same purpose, so a wrong-table pill is a compile error rather than a runtime surprise.
- **`Table.sizeClass` and `List.domain`** — `Table` accepts `sizeClass?: number`; `List` accepts `domain?: string` (the `sys_domain` applied to the list, defaulting to `'global'`).
- **17 new `Record()`-addressable tables** (176 → 193), including `sys_ui_style`, `cmn_schedule_span` (schedule entries), `business_calendar_span`, `cmdb`, `sysrule_view_workspace`, and `sysevent_script_action`.

> Source-of-truth note: five release-note claims are not corroborated by the installed package and were treated as corrections. `doTheFollowingUntil` was **not** "reworked" — that identifier exists in neither 4.10.1 nor 4.11.2; the construct is **new**, and is authored as `doTheFollowing` + `until`. `enforceAcl` is **not** a secure-by-default boolean — it is an ACL reference array defaulting to **empty**, i.e. no schema gate (only the three `requires*` booleans and `contextualAclMaxDepth` are secure-by-default). The new-table claim under-reports: 17 tables were added, not 2. A GraphQL resolver `script` **cannot** be an inline function literal even though the type accepts a function. And the `launcher*` record-form fields are **forbidden** on `executionType: 'on_demand'`, the opposite of what "On-Demand launcher configurations" suggests. Separately, the "`Decimal` inside `FlowObject`/`FlowArray`" item is a build-pipeline fix, not a type change — `FlowTypes.d.ts` and `db/types/Decimal.d.ts` are byte-identical to 4.10.1. See `.mosey/upgrade-sdk-4.11.2.md`.

### Previously (4.10.x)

Authoring-surface additions shipped across `@servicenow/sdk` 4.10.0 and 4.10.1:

- **New metadata type**: `state-model` — the `StateModel` API defines a table's **state machine** (states, transitions, and the conditions that gate them) in a single call, writing `sttrm_model`/`sttrm_state`/`sttrm_state_transition`/`sttrm_transition_condition` records, or the `chg_model`/`prb_model`/`prb_task_model` subclass auto-selected from `table`. It can also edit out-of-box models in place by referencing their real sys_ids.
- **New metadata type**: `atf-list` — the `atf.list.*` ATF steps (`relatedListVisibility`, `applyFilterToList`, `recordPresentInList`, `openRecordInList`, `listUIActionVisibility`, `clickListUIAction`) exercise list and related-list UI behavior.
- **New tools**: `cicd_fluent_app` (install/publish/rollback an app through the `sn_cicd` API — changes instance state) and `cicd_fluent_test` (run, watch, or fetch results for ATF suites and tests), wrapping the new `now-sdk cicd` command. `query_fluent_records` gains `select` for the new `--select` path extractor.
- **`$meta.useEsLatest`** — new cross-cutting flag that runs a record's script field(s) at the latest ECMAScript version the platform supports. It reaches the APIs whose type carries `$meta` (`BusinessRule`, `Acl`, `ScriptInclude`, `ScriptAction`, `ScheduledScript`, `UiPage`, `RestApi` routes, `SPWidget`, `SPMenu`, and others) — **not every API with a server-side script field**: `StateModel` transition conditions are server-side scripts whose type accepts no `$meta` at all (see the source-of-truth note below).
- **Table `actions` object form** — `actions` now accepts the exported `TableActionAccess` shape `{ read?, update?, delete?, create? }`, where each action is three-state. **The array form is deprecated**: it is a complete enumeration, so `actions: ['read']` also writes the other three as `false`. The SDK also no longer derives defaults for `actions`, `allowClientScripts`, `allowNewFields`, `allowUiActions`, `allowWebServiceAccess`, or `maxLength`.
- **Reference column `mtom`** — creates a many-to-many relationship. Note the semantic split: `referenceKey` no longer means many-to-many, and now stores a field from the referenced table in place of `sys_id`.
- **UI Action icons** — `UiAction`'s `form` and `list` objects both accept `iconName` and `showIconOnly`.
- **`Form` `$meta`** — `Form` now honors `$meta.installMethod` to route its output folder (previously accepted but inert).
- **Playbook `timerSchedule`** — `startWithDelay` can evaluate its delay against a `cmn_schedule` record instead of elapsed clock time, on all three variants.
- **Catalog dynamic default values** — a variable's `dependentQuestion` widened to accept a `ReferenceVariable`/`RequestedForVariable` in addition to a name string; `CatalogUiPolicy` actions accept `variable`, and `CatalogClientScript` accepts `order`.
- **`$override` on `sys_*` fields** — `$override` can set `sys_domain` and most other `sys_*` columns on any table; `sys_id`, `sys_scope`, `sys_update_name`, and `sys_domainpath` remain framework-managed and error if overridden.
- **Service Portal** — widget/page/instance CSS fields accept SCSS or CSS, `widgetParameters` now correctly serializes a plain object, `SPInstance`'s placeholder properties are functional rather than ignored, and `urlSuffix` accepts hyphens. The `service-portal` spec also gained the previously undocumented `ServicePortal()` (`sp_portal`) API.

> Source-of-truth note: several release-note claims are not corroborated by the installed package and were treated as corrections — "dependent questions" are a **dynamic default value**, not visibility or option control (and the property is not new, only its type widened); `runServerSideScript` "surface support" already shipped in 4.9.0; and the `add_message` inference change is an internal transform fix with no authoring-surface change. The overview guide also lists `StateModel`, `AliasTemplate`, `InboundEmailAction`, `CatalogItem`, `CatalogItemRecordProducer`, and the instance-scan checks as accepting `$meta.useEsLatest`, but their declarations carry no `$meta`. See `.mosey/upgrade-sdk-4.10.1.md`.

### Previously (4.9.x)

This release of the MCP server tracks `@servicenow/sdk` 4.9.0 — a maintenance and bug-fix release (Flow, ClientScript, ImportSet, SLA transform/build reliability) with select authoring-surface additions:

- **New metadata type**: `atf-ui-test-script` — the `atf.uiTestScript.runTest()` ATF step runs a TestingLibrary test body in the client test runner to test custom UI components (Angular/React widgets, embedded SPAs, custom workspaces, `now-*` web components) that the standard `atf.form.*` / `atf.catalog.*` steps cannot reach.
- **Multi-language choice labels** — a choice field's `choices` value may be an array of `ChoiceConfig` objects, each with a `language` (BCP 47) key, producing one translated `sys_choice` record per language.
- **`protectionPolicy` on AI Agent & AI Agentic Workflow** — `AiAgent` and `AiAgenticWorkflow` accept `protectionPolicy: 'read' | 'protected'` for post-install access control.
- **`Role.federatedId`** — optional identifier to match a role to an externally federated role during identity federation.
- **Table index platform columns** — a table `index` entry's `element` may reference platform default columns (for example, `sys_created_on`).
- **Now Assist Skill Kit providers** — new LLM providers selectable by name: `Now LLM LTS Generic`, `Google Cloud Vertex AI`, `Amazon Bedrock`.

> Source-of-truth note: two release-note claims are not corroborated by the installed package and were treated as corrections — Form `table_field.field` is documented as a schema column name (not loosened to "any string"), and the four named NASK model strings appear nowhere in the package (`model` is a free string). See `.mosey/upgrade-sdk-4.9.0.md`.

### Previously (4.8.x)

This release of the MCP server tracks `@servicenow/sdk` 4.8.0 and adds support for the following Fluent APIs and SDK enhancements:

- **New metadata type**: `playbook` — the `PlaybookDefinition` API (`sys_pd_process_definition`, from `@servicenow/sdk/automation`) for guided, record-driven multi-step processes with lanes, activities, triggers, and inputs/outputs.
- **New metadata type**: `rest-message` — the `RestMessage` API (`sys_rest_message`) for outbound HTTP integrations with shared auth/headers and callable functions.
- **New metadata types**: `alias` and `alias-template` — the `Alias` (`sys_alias`) and `AliasTemplate` (`sys_alias_templates`) APIs for Connection & Credential aliases and reusable connection-setup templates.
- **New metadata type**: `retry-policy` — the `RetryPolicy` API (`sys_retry_policy`) controlling transient-failure handling for connections (fixed-interval, exponential-backoff, or `Retry-After`).
- **New metadata type**: `data-lookup` — the `DataLookup` API (`dl_definition`) that auto-copies field values from a matcher table to a source record.
- **Declarative deletion (`Now.del()`)** — top-level statement to remove records by coalesce keys or sys_id.
- **Type enhancements** — `$override` on `DataPolicy`/`UserPreference`; `$meta.installMethod` on `Record`/`Acl`/`Alias`/`UserPreference`; ACL `field` accepts known field names, system columns, or `'*'`; `Table` `accessibleFrom` now defaults to `'public'`.
- **New CLI tool** — `query_fluent_records` wraps `now-sdk query` for read-only Table REST queries (JSON envelope output).

### Previously (4.7.x)

This release of the MCP server tracked `@servicenow/sdk` 4.7.x and added support for the following Fluent APIs and SDK enhancements:

- **New metadata type**: `data-policy` — the `DataPolicy` API (`sys_data_policy2`) for server-side mandatory/read-only field enforcement that cannot be bypassed via API, import, or web service.
- **Flow error handling & parallelism** — `wfa.flowLogic.tryCatch`, `wfa.flowLogic.doInParallel`, and `wfa.flowLogic.appendToFlowVariables` (append to `Array.Object` flow variables).
- **Flow stages** — declare `stages` with `FlowStage({ label, value, … })` and activate them in the body via `wfa.stage(...)` for progress tracking.
- **Table augments** — add columns to an existing platform/cross-scope table via `Table({ augments: '<table>', schema })`; added columns must use the current app's ownership prefix: `<scope>_` in a named custom scope (for example, `x_acme_`), or `u_` in global and Store-app contexts.
- **AI Agent** — new `agentDescriptor`; `dataAccess` accepts `roleMap` (role names) or `roleList` (role sys_ids).
- **NASK** — `securityControls` accepts `roleMap` (role names) alongside `roleRestrictions` (role sys_ids).
- **Universal field override (`$override`)** — escape hatch on Fluent constructors to set unmodeled columns by DB column name.
- **Protection policy** — `protectionPolicy` documented on `sys_policy`-backed APIs (Action, Subflow, business rules, scripted REST, etc.).
- **CLI** — `fluent_transform` gains `--table`/`--id` (transform by table hierarchy); `init` gains the `typescript.vue` template; OAuth `client_credentials` for CI/CD via `SN_SDK_*` env vars (see Configuration).
- **MCP** — read tools now return `structuredContent` (with declared `outputSchema`); long-running commands emit progress notifications.

### Previously (4.6.0)

Added `custom-action`, `inbound-email-action`, `sp-header-footer`, and `sp-page-route-map` metadata types; the declarative `Form` API; subflow-of-subflow and custom actions in flows; AIAF auto-ACL generation; NASK output/input-type enhancements; `Table` dictionary overrides; and a project-free `explain` command with tag search, `--list`, `--peek`, and `--format=raw`.

## Configuration

**Requirements:** Node.js 20.18.0+, npm 11.4.1+, `@servicenow/sdk` 4.11.2

### MCP Client Setup

Add to your MCP client configuration file:

```json
{
  "mcpServers": {
    "fluent-mcp": {
      "command": "npx",
      "args": ["-y", "@modesty/fluent-mcp"],
      "env": {
        "FLUENT_MCP_WORKING_DIR": "/absolute/path/to/your/fluent-project",
        "SN_INSTANCE_URL": "https://your-instance.service-now.com",
        "SN_AUTH_TYPE": "basic",
        "SN_USER_NAME": "local-username",
        "SN_PASSWORD": "local-password"
      }
    }
  }
}
```

**Client-Specific Locations:**

- **Claude Desktop / macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **VSCode Copilot:** `.vscode/mcp.json` (use Command Palette: `MCP: Add Server...`)
- **Cursor:** Settings → Features → MCP Settings
- **Windsurf:** Settings → Cascade → MCP Servers → View raw config
- **Gemini CLI:** `~/.gemini/settings.json`

> **VSCode note:** For VSCode, the JSON structure uses `"mcp": { "servers": { ... } }` instead of `"mcpServers"`.

**Environment Variables:**

| Variable | Description | Default |
|----------|-------------|---------|
| `FLUENT_MCP_WORKING_DIR` | Absolute Fluent project path used after the per-call and initialized-session sources; when it is also absent, project commands fail with actionable guidance | - |
| `SN_INSTANCE_URL` | ServiceNow instance URL for auto-auth validation | - |
| `SN_AUTH_TYPE` | Authentication method: `basic` or `oauth` | `oauth` |
| `SN_USER_NAME` | Username for basic auth (informational) | - |
| `SN_PASSWORD` | Password for basic auth (informational) | - |
| `FLUENT_MCP_LOG_LEVEL` | Minimum stderr log severity (`debug`, `info`, `notice`, `warning`, `error`, etc.) | `info` |

> **Note:** On the first auth-requiring command (or `check_auth_status`), the server detects an existing auth profile matching `SN_INSTANCE_URL`, stores it in the session, and auto-injects it. Concurrent first calls share one validation promise. A new profile is added automatically only when setup can complete non-interactively (basic auth with `SN_USER_NAME`/`SN_USERNAME` + `SN_PASSWORD`); otherwise the server emits a single notice with the manual `auth --add` command to run.

#### Logging

The server writes its complete structured log stream to stderr so stdout remains reserved for MCP protocol traffic. Configure the minimum severity before launch with `FLUENT_MCP_LOG_LEVEL` (default `info`; use `debug` to include raw SDK CLI output). Runtime `logging/setLevel` and `notifications/message` are intentionally not used.

#### CI/CD (non-interactive) authentication — SDK v4.7.0+

For headless pipelines, the ServiceNow SDK CLI reads credentials directly from `SN_SDK_*` environment variables (the MCP server inherits and passes these through to spawned commands — no extra configuration needed). Set `SN_SDK_NODE_ENV=SN_SDK_CI_INSTALL` to enable CI mode, then:

| Variable | Required | Value |
|----------|----------|-------|
| `SN_SDK_NODE_ENV` | yes | `SN_SDK_CI_INSTALL` |
| `SN_SDK_AUTH_TYPE` | for oauth | `basic` (default) or `oauth` |
| `SN_SDK_INSTANCE_URL` | yes | Full instance URL |
| `SN_SDK_USER` / `SN_SDK_USER_PWD` | basic | Username / password |
| `SN_SDK_OAUTH_CLIENT_ID` / `SN_SDK_OAUTH_CLIENT_SECRET` | oauth | OAuth `client_credentials` app credentials |

OAuth uses the `client_credentials` grant against `/oauth_token.do`. See the SDK's `ci-integration` guide (via `explain_fluent_api`) for instance setup details.

## Usage Examples

### Typical Workflow

1. **Initialize Project**

   ```text
   Create a new Fluent app in ~/projects/asset-tracker for IT asset management
   ```

2. **Develop with Resources**

   ```text
   Show me the business-rule API specification and provide an example snippet
   ```

3. **Build and Deploy**

   ```text
   Build the app with debug output, then deploy it
   ```

> **Note:** Authentication is validated lazily using `SN_INSTANCE_URL` and `SN_AUTH_TYPE`; those settings do not replace an SDK auth profile unless non-interactive setup can complete. If you need to set up a new profile, run: `npx @servicenow/sdk auth --add <instance-url> --type <basic|oauth> --alias <alias>`

## Testing with MCP Inspector

The [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector) provides a web interface for testing MCP servers.

### Launch Inspector

```bash
# Test published package
npx @modelcontextprotocol/inspector npx @modesty/fluent-mcp

# Or for local development (built server)
npm run build && npm run inspect

# Or against the TypeScript entry point, no build required
npm run inspect:dev
```

### What to verify

- The Tools tab shows all 17 tools in deterministic name order.
- Optional parameters render with their normal types rather than as nullable union forms.
- Structured server logs appear on the server process stderr/terminal output; stdout remains reserved for MCP protocol traffic.

### Test Scenarios

#### Scenario 1: Explore Business Rule Resources

**Objective:** Access API specs and code snippets for business rules

**Steps:**

1. Launch Inspector and wait for server connection
2. Navigate to **Resources** tab
3. Find and click `sn-spec://business-rule` in the resource list
4. Review the API specification showing all available methods and parameters
5. Go back and search for `sn-snippet://business-rule/0001`
6. Click the snippet to view a complete TypeScript example
7. Verify content includes proper imports and follows Fluent patterns

**Expected Results:**

- API spec displays structured documentation with method signatures
- Snippet shows runnable TypeScript code with ServiceNow metadata patterns
- Content is properly formatted and readable

#### Scenario 2: Test SDK Info Command

**Objective:** Verify SDK version and help information retrieval

**Steps:**

1. Navigate to **Tools** tab
2. Select `sdk_info` from the tool list
3. **Test Version:**
   - Set `flag` parameter to `-v`
   - Click **Execute**
   - Verify response shows the SDK version (e.g., `4.11.2`)
4. **Test Help:**
   - Set `flag` parameter to `-h`
   - Set `command` parameter to `build`
   - Click **Execute**
   - Verify response shows build command documentation with options
5. Monitor the server process **stderr/terminal output** for command execution logs (set `FLUENT_MCP_LOG_LEVEL=debug` before launch for verbose output)

**Expected Results:**

- Version command returns SDK version string
- Help command returns detailed command documentation
- List metadata (`-lm`) returns available Fluent metadata types
- No unexpected protocol errors; command logs are emitted on stderr rather than through MCP `notifications/message`
- Commands execute within 2-3 seconds

## License

MIT

TDQS

A3.9/5.0

Scored across 17 tools

Disambiguation3/5

Most lifecycle tools are clearly distinct (init, build, pack, deploy, clean), but the documentation/help cluster—explain_fluent_api, get-api-spec, get-instruct, get-snippet, and sdk_info—has overlapping purposes that could cause misselection. The descriptions do include cross-references, which helps, but an agent still has to choose among several similar look-up tools.

Naming Consistency2/5

The core lifecycle tools mostly follow a verb_fluent_noun pattern (build_fluent_app, deploy_fluent_app, download_fluent_app), but conventions are mixed across the set: several get-* tools use hyphens with no 'fluent' component, fluent_transform reverses the pattern, check_auth_status omits 'fluent', and sdk_info is a bare noun. This mixing of underscore, hyphen, and noun-only names is inconsistent.

Tool Count4/5

At 17 tools, this sits slightly above the ideal 3-15 range, but the server covers a broad domain: app initialization, building, packaging, deployment, downloads, transforms, CI/CD, testing, authentication, and documentation. The count feels justified by the scope rather than padded.

Completeness5/5

The tool surface covers the full Fluent/ServiceNow app development lifecycle: init, dependencies, build, pack, deploy, clean, download, transform, query, CI/CD, test, and auth. There are no obvious dead ends, and documentation/help tools round out the workflow. The set appears complete for its stated domain.

Maintenance

ActivityActive
ResponsivenessUnresponsive