mcpField
F
fluent-sdk

fluent-sdk

github.com/happy-technologies-llc開発4142 回インストール2 日前に更新
リポジトリ

fluent-sdk について

NowSDK Fluent、MCP REST、Fix Scriptを使い分けるServiceNow開発スキルです。ServiceNowアプリの開発者向けに、メタデータ、実行時データ、他の方法で扱えない処理を適切な手段に振り分け、バージョン管理に基づくデプロイを説明します。

主な機能

  1. 01Fluent、MCP REST、Fix Scriptへの処理の振り分け
  2. 02TypeScriptによるアプリメタデータの定義
  3. 03スコープアプリのビルドとデプロイ
  4. 04MCP経由での実行時レコードの照会と更新
  5. 05フローのコンパイルなどをFix Scriptで処理

活用シーン

  1. 01テーブル、ビジネスルール、フローを含むスコープアプリの作成
  2. 02メタデータ変更のバージョン管理とデプロイ
  3. 03デプロイ後にインスタンスを照会して変更を検証

MCP 対応

MCP RESTは、実行時データの照会・変更、Update Setの管理、バックグラウンドスクリプトの実行を担う手段の一つです。Fluentでのデプロイ結果の検証にも使います。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/happy-technologies-llc/happy-platform-skills --skill fluent-sdk

インストール後、Claude Code で/fluent-sdkを入力して読み込まれたか確認します。

同梱ファイルvendor/now-sdk-explain.mdvendor/now-sdk-setup.md

詳細

NowSDK Fluent を使用したハイブリッドな ServiceNow 開発

概要

このスキルは、ServiceNow 向けの3 層開発戦略を実装し、各操作を最も適したツールに振り分けます。

TIER 1: NowSDK Fluent (metadata-as-code)
  Flows, tables, business rules, catalog items, ACLs, scoped apps
  TypeScript → build → deploy as scoped application
  ↓ falls through when...
  - Runtime data operations needed
  - Live instance queries required
  - Existing record manipulation

TIER 2: MCP REST Tools (runtime operations)
  CRUD on live data, queries, update set management, background scripts
  Direct REST API calls to instance
  ↓ falls through when...
  - REST API has documented limitations
  - UI-only operations (Flow compilation, UI Policy action linking)
  - Complex server-side operations not exposed via REST

TIER 3: Fix Scripts (manual fallback)
  SN-Create-Fix-Script for operations neither tier can handle
  Generated scripts for manual execution in instance
  Used for: Flow compilation, UI Policy setValue(), complex GlideRecord ops

このスキルを使用する場面:

  • 「インシデントのエスカレーション用に新しいフローを作成する」
  • 「テーブルとビジネスルールを備えたスコープアプリを作成する」
  • 「承認ワークフロー付きのカタログアイテムを設定する」
  • 「バージョン管理を使ってメタデータの変更をデプロイする」
  • 「フローが必要ですが、REST ではフローを作成できません」

基盤:ServiceNow 公式 Fluent スキル

このスキルは、github.com/ServiceNow/sdk の ServiceNow 公式 AI スキルを基盤としています。

  • vendor/now-sdk-setup.md — 環境の設定(Node 20 以降、SDK のインストール、認証)。now-sdk コマンドが失敗する場合は、まずこれを実行してください。
  • vendor/now-sdk-explain.md — npx @servicenow/sdk explain を使用した、自己文書化型の SDK リファレンス。Fluent コードを書く前に必ず参照してください。すべてのメタデータ型、規約、プロジェクト構造の詳細が記載されています。

Fluent コードを書く前に、explain スキルの手順に従ってください。

  1. npx @servicenow/sdk explain <search-term> --list --format=raw — 関連するトピックを探します
  2. npx @servicenow/sdk explain <topic> --peek --format=raw — 採用する前に内容を確認します
  3. npx @servicenow/sdk explain <topic> --format=raw — トピック全体を読みます

これにより、古いサンプルではなく、最新の API シグネチャと規約を確実に使用できます。

前提条件

  • Node.js: v20 以降(node --version)
  • NowSDK: v4.6.0 以降(npm install -g @servicenow/sdk@latest)
  • インスタンス: ServiceNow SDK プラグインが有効で、ユーザーに admin または sn_sdk.user ロールが付与されていること
  • MCP サーバー: happy-platform-mcp が設定され、接続されていること
  • 認証: 対象のインスタンスで now-sdk auth が完了していること
  • 関連スキル: MCP ツールのリファレンスは development/mcp-server、Fluent API のドキュメントは vendor/now-sdk-explain.md

層の判断マトリックス

各操作をどの層で処理するか判断するには、このマトリックスを使用してください。

操作Tier 1(Fluent)Tier 2(MCP REST)Tier 3(Fix Script)
ロジックを含むフローの作成はい - 完全な Flow DSLいいえ - フローを作成できませんいいえ
フローのコンパイル/公開デプロイ時に自動実行いいえはい - UI で手動実行
テーブルとスキーマの作成はい - 型付きカラムを使用する Table()はい - ただしバージョン管理なしいいえ
ビジネスルールはい - スクリプトを含む BusinessRule()はい - sys_script に対する SN-Create-Recordいいえ
カタログアイテムはい - 変数を含む CatalogItem()はい - ただし UI ポリシーには制限あり一部対応
UI ポリシーのアクションはい - アプリとともにデプロイいいえ - REST ではアクションをリンクできませんはい - setValue() スクリプト
ACLはい - Acl() 定義はい - sys_security_acl に対する SN-Create-Recordいいえ
スクリプトインクルードはい - サーバーモジュールを使用はい - sys_script_include に対する SN-Create-Recordいいえ
稼働中のデータのクエリいいえ - ランタイム用ではありませんはい - SN-Query-Tableいいえ
既存レコードの更新いいえ - 新しいメタデータを作成しますはい - SN-Update-Recordいいえ
更新セットの管理デプロイ時に自動実行はい - SN-Set-Update-Set、検査、移動いいえ
バックグラウンドスクリプトの実行いいえはい - SN-Execute-Background-Scriptいいえ
スコープアプリの作成はい - now.config.json でスコープを定義はい - sys_app に対する SN-Create-Recordいいえ
インスタンスへのデプロイはい - now-sdk deployいいえ - レコードを個別に作成しますいいえ
複雑な GlideRecord 操作いいえ一部対応はい - サーバー側 API をすべて使用可能

手順

ステップ 1:環境の設定

vendor/now-sdk-setup.md に従って、NowSDK がインストールされ、動作していることを確認してください。

# Check Node version (must be 20+)
node --version

# Check SDK version (must be 4.6.0+)
npx @servicenow/sdk --version

# If not installed or outdated:
npm install -g @servicenow/sdk@latest

# Authenticate to your instance
now-sdk auth
# Follow prompts: instance URL, credentials

explain コマンドで確認します:

npx @servicenow/sdk explain quickstart --list --format=raw

次に、これから作成するものに応じた Fluent API に慣れておきます。

# Example: about to create flows
npx @servicenow/sdk explain Flow --list --peek --format=raw
npx @servicenow/sdk explain Flow --format=raw
ステップ 2:適切なティアを選択する

コードを書く前に、リクエストを分類します。

ティア 1(Fluent)を選択する場合:

  • メタデータをゼロから作成する場合(フロー、テーブル、ビジネスルール、カタログアイテム)
  • スコープアプリケーションを構築する場合
  • バージョン管理された再現可能なデプロイが必要な場合
  • Flow Designer の操作(REST API ではフローを作成できません)
  • 変数セット、価格設定、アクセス制御を含む複雑なカタログアイテム

ティア 2(MCP REST)を選択する場合:

  • ライブデータをクエリまたは変更する場合
  • 更新セットを管理する場合(調査、移動、複製)
  • 既存のレコードを一度だけ更新する場合
  • バックグラウンドスクリプトを実行する場合
  • ティア 1 のデプロイを検証する場合

ティア 3(Fix Script)を選択する場合:

  • フローのコンパイル(デプロイ後に UI で実行する必要があります)
  • setValue() による UI ポリシーアクションのリンク
  • REST では公開されていない複雑な GlideRecord 操作
  • サーバー側のパフォーマンスが必要な一括データ操作
ステップ 3:Fluent プロジェクトのひな形を作成する(ティア 1)

新しいスコープアプリケーションのプロジェクト構造を作成します。

プロジェクト構造:

my-sn-app/
├── now.config.json          # Scope and instance config
├── package.json             # Dependencies
├── tsconfig.json            # TypeScript config (optional)
├── src/
│   └── fluent/
│       ├── generated/
│       │   └── keys.ts      # Auto-generated sys_id mappings
│       ├── tables.now.ts    # Table definitions
│       ├── rules.now.ts     # Business rules
│       ├── flows.now.ts     # Flow definitions
│       ├── catalog.now.ts   # Catalog items
│       ├── acls.now.ts      # Access controls
│       └── *.server.js      # External script files
└── src/
    └── server/              # Server-side TypeScript modules

now.config.json:

{
  "scope": "x_myapp",
  "scopeId": "<sys_id from instance or generated on first deploy>"
}

package.json:

{
  "name": "my-sn-app",
  "version": "1.0.0",
  "scripts": {
    "build": "now-sdk build",
    "deploy": "now-sdk deploy",
    "explain": "now-sdk explain"
  },
  "devDependencies": {
    "@servicenow/glide": "catalog:",
    "@servicenow/sdk": "catalog:",
    "typescript": "catalog:"
  }
}
ステップ 4:Fluent 定義を作成する
テーブル
// src/fluent/tables.now.ts
import {
  Table, StringColumn, IntegerColumn, BooleanColumn,
  DateColumn, ReferenceColumn
} from '@servicenow/sdk/core'

export const x_myapp_request = Table({
  name: 'x_myapp_request',
  schema: {
    title: StringColumn({ mandatory: true, label: 'Title', maxLength: 200 }),
    priority: IntegerColumn({ mandatory: true, label: 'Priority' }),
    active: BooleanColumn({ mandatory: true, label: 'Active', default: true }),
    due_date: DateColumn({ label: 'Due Date' }),
    assigned_to: ReferenceColumn({
      label: 'Assigned To',
      referenceTable: 'sys_user',
    }),
  },
})
ビジネスルール
// src/fluent/rules.now.ts
import { BusinessRule } from '@servicenow/sdk/core'

export const validatePriority = BusinessRule({
  $id: Now.ID['validate_priority'],
  name: 'Validate Priority on Create',
  active: true,
  table: 'x_myapp_request',
  when: 'before',
  insert: true,
  script: Now.include('./validate-priority.server.js'),
})
// src/fluent/validate-priority.server.js
(function executeRule(current, previous) {
  if (!current.priority || current.priority < 1 || current.priority > 5) {
    current.priority = 3; // Default to medium
  }
  if (!current.assigned_to && current.priority == 1) {
    gs.addErrorMessage('Critical requests must have an assignee');
    current.setAbortAction(true);
  }
})(current, previous);
フロー
// src/fluent/flows.now.ts
import { action, Flow, wfa, trigger } from '@servicenow/sdk/automation'

export const escalationFlow = Flow(
  {
    $id: Now.ID['request_escalation_flow'],
    name: 'Request Escalation Flow',
    description: 'Escalates high-priority requests when unassigned after creation',
  },
  wfa.trigger(
    trigger.record.created,
    { $id: Now.ID['new_request_trigger'] },
    {
      table: 'x_myapp_request',
      condition: 'priority=1^assigned_toISEMPTY',
      run_flow_in: 'background',
      run_on_extended: 'false',
      run_when_setting: 'both',
      run_when_user_setting: 'any',
      run_when_user_list: [],
    }
  ),
  (params) => {
    // Log the escalation
    wfa.action(
      action.core.log,
      { $id: Now.ID['log_escalation'] },
      {
        log_level: 'warn',
        log_message: `Escalating unassigned critical request: ${wfa.dataPill(params.trigger.current.title, 'string')}`,
      }
    )

    // Look up the on-call manager
    const manager = wfa.action(
      action.core.lookUpRecord,
      { $id: Now.ID['lookup_oncall_manager'] },
      {
        table: 'sys_user',
        conditions: 'active=true^roles=manager',
        sort_type: 'sort_asc',
        if_multiple_records_are_found_action: 'use_first_record',
      }
    )

    // Auto-assign to manager
    wfa.action(
      action.core.updateRecord,
      { $id: Now.ID['assign_to_manager'] },
      {
        table_name: 'x_myapp_request',
        record: wfa.dataPill(params.trigger.current.sys_id, 'reference'),
        values: TemplateValue({
          assigned_to: wfa.dataPill(manager.Record.sys_id, 'reference'),
        }),
      }
    )

    // Send notification
    wfa.action(
      action.core.sendEmail,
      { $id: Now.ID['notify_manager'] },
      {
        table_name: 'x_myapp_request',
        watermark_email: true,
        ah_subject: `Critical Request Escalation: ${wfa.dataPill(params.trigger.current.title, 'string')}`,
        ah_body: `A critical request has been auto-assigned to you.`,
        record: wfa.dataPill(params.trigger.current.sys_id, 'reference'),
        ah_to: wfa.dataPill(manager.Record.email, 'string'),
      }
    )
  }
)
カタログアイテム
// src/fluent/catalog.now.ts
import {
  CatalogItem, VariableSet, SingleLineTextVariable,
  MultiLineTextVariable, SelectBoxVariable, ReferenceVariable,
  RequestedForVariable
} from '@servicenow/sdk/core'

const requestInfoVarSet = VariableSet({
  $id: Now.ID['request_info_varset'],
  title: 'Request Details',
  description: 'Core information for the request',
  internalName: 'request_info_varset',
  type: 'singleRow',
  layout: 'normal',
  order: 100,
  displayTitle: true,
  version: 1,
  variables: {
    requestTitle: SingleLineTextVariable({
      question: 'Request Title',
      mandatory: true,
      order: 100,
    }),
    requestDescription: MultiLineTextVariable({
      question: 'Description',
      mandatory: true,
      order: 200,
    }),
    requestPriority: SelectBoxVariable({
      question: 'Priority',
      mandatory: true,
      order: 300,
      choices: {
        critical: { label: '1 - Critical' },
        high: { label: '2 - High' },
        medium: { label: '3 - Medium' },
        low: { label: '4 - Low' },
      },
      defaultValue: 'medium',
    }),
  },
  name: 'Request Details',
})

export const newRequestCatalogItem = CatalogItem({
  $id: Now.ID['new_request_catalog_item'],
  name: 'New Service Request',
  shortDescription: 'Submit a new service request',
  description: 'Use this form to submit a service request. Critical requests trigger automatic escalation.',
  catalogs: ['e0d08b13c3330100c8b837659bba8fb4'], // Service Catalog
  categories: ['d258b953c611227a0146101fb1be7c31'], // Hardware (or your category)
  variableSets: [{ variableSet: requestInfoVarSet, order: 100 }],
  executionPlan: '523da512c611228900811a37c97c2014',
  variables: {
    requestedFor: RequestedForVariable({
      order: 1,
      question: 'Requested For',
    }),
    assignmentGroup: ReferenceVariable({
      order: 2,
      question: 'Assignment Group',
      referenceTable: 'sys_user_group',
    }),
  },
})
ステップ 5:ビルドしてデプロイする(ティア 1)
# Build the project (validates TypeScript, generates metadata)
now-sdk build

# Deploy to instance (creates/updates scoped app and all metadata)
now-sdk deploy
ステップ 6:MCP ツールで検証する(ティア 2)

Fluent のデプロイ後、MCP ツールを使用してすべてが正しく反映されたことを確認します。

Tool: SN-Query-Table
Parameters:
  table_name: sys_update_xml
  query: application=<app_sys_id>
  fields: sys_id,type,name,sys_created_on
  limit: 50
Tool: SN-Get-Table-Schema
Parameters:
  table_name: x_myapp_request
Tool: SN-Query-Table
Parameters:
  table_name: sys_script
  query: collection=x_myapp_request^active=true
  fields: name,when,active
ステップ 7:Fix Script へのフォールスルーに対応する(ティア 3)

Fluent でも REST でも対応できない操作には、修正スクリプトを生成します。

フローのコンパイル(デプロイ後):

Tool: SN-Create-Fix-Script
Parameters:
  name: "Compile Escalation Flow"
  description: "Compile the request escalation flow after Fluent deployment"
  script: |
    // Navigate to Flow Designer and compile:
    // 1. Open Flow Designer
    // 2. Find "Request Escalation Flow"
    // 3. Click "Activate" to compile and enable
    //
    // This step cannot be automated - Flow Designer compilation
    // requires the UI runtime environment.
    gs.info('Manual step: Compile flow in Flow Designer UI');

UI ポリシーアクションのリンク(必要な場合):

Tool: SN-Execute-Background-Script
Parameters:
  script: |
    var gr = new GlideRecord('sys_ui_policy_action');
    gr.addQuery('ui_policy', '<ui_policy_sys_id>');
    gr.addQuery('catalog_variable', '');
    gr.query();
    while (gr.next()) {
      gr.catalog_variable = 'IO:<variable_sys_id>';
      gr.update();
    }
  description: "Link UI Policy actions to catalog variables"
  execution_method: trigger

一括データ操作:

Tool: SN-Create-Fix-Script
Parameters:
  name: "Seed Sample Data"
  description: "Create initial sample records for testing"
  script: |
    var records = [
      { title: 'Test Request 1', priority: 1 },
      { title: 'Test Request 2', priority: 3 },
      { title: 'Test Request 3', priority: 5 }
    ];
    records.forEach(function(data) {
      var gr = new GlideRecord('x_myapp_request');
      gr.initialize();
      gr.title = data.title;
      gr.priority = data.priority;
      gr.active = true;
      gr.insert();
    });
    gs.info('Created ' + records.length + ' sample records');

ハイブリッドワークフローの例

3 つのティアすべてを組み合わせた、エンドツーエンドの完全な例です。

GOAL: Build a scoped app with escalation flow, catalog item, and seed data

TIER 1 (Fluent):
  1. Create now.config.json with scope
  2. Define table schema in tables.now.ts
  3. Define business rules in rules.now.ts
  4. Define escalation flow in flows.now.ts
  5. Define catalog item in catalog.now.ts
  6. now-sdk build && now-sdk deploy

TIER 2 (MCP REST):
  7. SN-Query-Table → verify all records in update set
  8. SN-Get-Table-Schema → confirm table columns created
  9. SN-Query-Table on sys_script → verify business rules active
  10. SN-Execute-Background-Script → seed sample data

TIER 3 (Fix Script):
  11. SN-Create-Fix-Script → flow compilation instructions
  12. SN-Create-Fix-Script → any UI Policy action linking
  13. Manual: compile flow in Flow Designer UI

NowSDK Explain リファレンス

SDK の組み込みドキュメントには、CLI からアクセスできます。

# List all available topics
npx @servicenow/sdk explain --list --format=raw

# Search for a topic
npx @servicenow/sdk explain flow --list --peek --format=raw

# Read full topic (only after previewing)
npx @servicenow/sdk explain flow --format=raw

# Key topics:
#   quickstart  - Getting started
#   Table       - Table definitions
#   Flow        - Flow automation
#   BusinessRule - Business rule definitions
#   CatalogItem - Service catalog items
#   Acl         - Access control lists
#   ScriptInclude - Script includes
#   naming      - Naming conventions
#   structure   - Project structure

重要: 無関係な内容でコンテキストを浪費しないよう、トピック全体を読む前に必ず --peek を使用してください。

Fluent API クイックリファレンス

モジュール別のインポート
// Core metadata
import {
  Table, StringColumn, IntegerColumn, BooleanColumn,
  DateColumn, ReferenceColumn, Record, BusinessRule,
  ScriptInclude, ClientScript, Acl, Role
} from '@servicenow/sdk/core'

// Flow automation
import {
  Flow, Subflow, action, wfa, trigger
} from '@servicenow/sdk/automation'

// Catalog
import {
  CatalogItem, VariableSet, SingleLineTextVariable,
  MultiLineTextVariable, SelectBoxVariable, ReferenceVariable,
  CheckBoxVariable, DateTimeVariable, RequestedForVariable,
  EmailVariable
} from '@servicenow/sdk/core'
主なヘルパー
ヘルパー目的例
Now.ID['key']キー名でレコードを参照する$id: Now.ID['my_rule']
Now.include('./file.js')外部スクリプトファイルを含めるscript: Now.include('./rule.server.js')
Now.ref(export)別の Fluent エクスポートを相互参照するtable: Now.ref(myTable)
Now.attach('./file')ファイルをレコードに添付するattachment: Now.attach('./logo.png')
TemplateValue({})フローアクションのフィールド値を設定するvalues: TemplateValue({ state: '2' })
wfa.dataPill(ref, type)フローデータピルを参照するwfa.dataPill(params.trigger.current.sys_id, 'reference')
フローロジックブロック
// Conditional
wfa.flowLogic.if({ $id, condition, annotation }, () => { ... })
wfa.flowLogic.elseIf({ $id, condition, annotation }, () => { ... })
wfa.flowLogic.else({ $id }, () => { ... })

// Loops
wfa.flowLogic.forEach(dataPill, { $id }, () => { ... })

// Subflow outputs
wfa.flowLogic.assignSubflowOutputs({ $id }, params.outputs, { ... })
フローアクション(action.core.*)
アクション目的
action.core.logレベルを指定してメッセージをログに記録する
action.core.lookUpRecord単一レコードをクエリする
action.core.updateRecordレコードを更新する
action.core.createRecord新しいレコードを作成する
action.core.sendEmailメール通知を送信する
action.core.sendSmsSMS を送信する
action.core.sendNotificationテンプレートを使用して通知を送信する
フロートリガー(trigger.record.*)
トリガー実行されるタイミング
trigger.record.createdレコードが作成されたとき
trigger.record.updatedレコードが更新されたとき
trigger.record.createdOrUpdatedレコードが作成または更新されたとき
trigger.record.deletedレコードが削除されたとき

ベストプラクティス

  • Fluent メタデータを書く前に、vendor/now-sdk-explain.md を参照してください。
  • 生成されたメタデータをソース管理に保管し、プラットフォームに反映された変更を確認してください。
  • 明確な理由がない限りデプロイモデルを混在させないよう、ティアの選択基準を使用してください。

トラブルシューティング

NowSDK が見つからない場合
npm install -g @servicenow/sdk@latest
# Verify: npx @servicenow/sdk --version (must be 4.6.0+)
認証エラー
# Re-authenticate
now-sdk auth
# Ensure instance has SDK plugin enabled
# Ensure user has admin or sn_sdk.user role
ビルドエラー
# Check explain docs for the specific type
npx @servicenow/sdk explain <TypeName> --format=raw

# Common issues:
# - Missing $id on records → add Now.ID['unique_key']
# - Invalid column types → check Table column type imports
# - Script file not found → verify Now.include() path is relative to .now.ts file
デプロイで誤ったスコープが作成される

now.config.json の scope と scopeId が正しいことを確認してください。scopeId は、インスタンス上の sys_app レコードの sys_id と一致している必要があります。

フォールスルー:Fluent が失敗した場合

特定のレコードタイプで now-sdk deploy が失敗した場合は、次の手順に進みます。

  1. MCP REST でレコードを直接作成できるか確認します(SN-Create-Record)
  2. REST でも失敗する場合は、修正スクリプトを生成します(SN-Create-Fix-Script)
  3. 今後の参照用に制限事項を記録します

コメント