Agentic Data Plane
Preview

ServiceNow Managed MCP Server

The ServiceNow managed MCP server lets agents work with a ServiceNow instance: search, create, update, and transition incidents, append work notes, order items from the service catalog, search the knowledge base, look up users and assignment groups, search the configuration management database (CMDB) for configuration items, discover table schema and field choices, and read allow-listed tables.

After reading this page, you will be able to:

  • Configure the ServiceNow managed MCP server with Basic authentication, OAuth client credentials, or User OAuth

  • Use projections and hierarchies to shape responses and gate table reads

  • Manage incidents, order service catalog items, and read allow-listed records from the Inspector or an agent

What this MCP server does

Wraps the ServiceNow REST Table API, plus the Service Catalog API for catalog submissions. The MCP is vendor-generic: ServiceNow records are returned as opaque JSON objects (their field set varies by instance), and the agent learns each table’s shape and valid field values at runtime through the discovery tools (get_table_schema, get_field_choices).

Customer-specific structure is supplied as configuration, not code:

  • Projections set the default field list returned per table (a ServiceNow incident carries about 100 fields, so projections keep responses small) and gate which tables the generic query_records tool may read.

  • Hierarchies declare dependent-field chains (for example, service area, then category, then subcategory). The agent reads the chain order with describe_field_hierarchies and resolves each field’s valid values at runtime with get_field_choices. No field values are stored in the configuration.

It is not a general SQL interface, and it does not delete records. Writes are limited to the typed incident tools and the two catalog submission tools; everything else reads.

Schema discovery and write verification together reduce the risk of a write that looks like it succeeded but changed nothing. The get_table_schema tool reports which fields the data dictionary marks read-only or filtered, so an agent can avoid setting them. The incident write tools then compare the values they sent against the record ServiceNow returned from the write, and submit_record_producer re-reads the record it created. Both attach a report of what the instance held. See Confirm what a write stored.

Prerequisites

Before you create the server, make sure you have:

  • A ServiceNow instance and its URL (for example, https://acme.service-now.com).

  • A ServiceNow service account, or an OAuth client, with the roles your workflows need (typically itil for incidents, knowledge for the knowledge base, and read access to sys_dictionary and sys_choice for schema discovery). For the catalog tools, add read access to sc_cat_item and item_option_new. Without it, a catalog search skips its option-value pass, a request form comes back partial, and the server refuses a submission rather than sending it blind.

  • For User-OAuth mode: an OAuth Provider configured in Redpanda Agentic Data Plane. See Configure an OAuth Provider.

Choose an authentication method

The MCP authenticates to ServiceNow as a single principal; it does not impersonate end-users. When creating an incident, the agent passes the requesting user’s sys_id in caller_id. Pick one of three methods:

  • Basic authentication (simplest): A dedicated ServiceNow user (for example, svc_redpanda) and its password. The username is plaintext; the password lives in the Agentic Data Plane secret store.

  • OAuth client credentials (service account): An OAuth API client registered under System OAuth > Application Registry. ServiceNow’s token endpoint is https://<instance>.service-now.com/oauth_token.do.

  • User OAuth: Per-user delegation through an OAuth Provider. ServiceNow’s recommended integration model is the service account, so prefer Basic authentication or OAuth client credentials unless you specifically need per-user attribution.

Configure

Create a new ServiceNow MCP server in Agentic Data Plane:

  1. Open MCP Servers > Add MCP server.

  2. Pick ServiceNow from the marketplace picker.

  3. Fill in identity fields (name, description).

  4. In the ServiceNow configuration form:

Field Notes

instance_url

Base URL of your ServiceNow instance (for example, https://acme.service-now.com). Must be an https:// URL.

auth

basic_auth, oauth, or user_oauth.

basic_auth (Basic-auth mode)

username (ServiceNow service-account username, for example svc_redpanda) and password_secret_ref (secret-store reference, UPPER_SNAKE_CASE).

oauth (OAuth mode)

client_id, client_secret_ref (secret-store reference), and token_url (https://<instance>.service-now.com/oauth_token.do).

user_oauth (User-OAuth mode)

provider_name (the OAuth Provider you configured) and the minimum required scopes.

projections

Per-table default field lists and the read allow-list for query_records.

hierarchies

Dependent-field chains the agent resolves at runtime.

exposed_tools (optional)

The subset of tool names this server exposes, matched exactly and case-sensitively (for example, get_table_schema or search_incidents). Leave it empty to expose every tool. An omitted tool is not offered to the agent and cannot be called. A name that matches no tool is logged rather than rejected, so the server still starts when a stored configuration names a tool from a newer release.

incident_state_requirements (optional)

Companion fields an incident must be written with when it moves to a named state, for example a close code when closing. Give each entry a state, by the label your instance shows or by the value it stores, and the required_fields that state needs. Leave it empty to enforce nothing.

incident_state_field (optional)

The incident column that transition_incident writes. Leave it empty to write the state column. On an instance where a write to state doesn’t stick, set this to the column that drives state instead, commonly incident_state. Use lowercase letters, digits, and underscores, starting with a letter.

+ . Click Create.

Configure from the CLI

For a managed server, set the authentication method inside the --managed.config JSON. The auth field is required.

  • Basic authentication

  • OAuth client credentials

  • User OAuth

rpk ai mcp-server create acme-servicenow --enabled --managed.config '{
  "@type": "type.googleapis.com/redpanda.mcps.servicenow.v1.ServiceNowMCPConfig",
  "instance_url": "https://acme.service-now.com",
  "basic_auth": {
    "username": "svc_redpanda",
    "password_secret_ref": "SERVICENOW_PASSWORD"
  },
  "projections": [
    {
      "table": "incident",
      "default_fields": ["number", "short_description", "state", "priority", "assignment_group", "caller_id"],
      "queryable": true
    },
    { "table": "change_request", "queryable": true }
  ],
  "hierarchies": [
    {
      "table": "incident",
      "name": "service",
      "fields": ["u_service_area", "u_service_category", "u_service_subcategory"]
    }
  ]
}'
rpk ai mcp-server create acme-servicenow-oauth --enabled --managed.config '{
  "@type": "type.googleapis.com/redpanda.mcps.servicenow.v1.ServiceNowMCPConfig",
  "instance_url": "https://acme.service-now.com",
  "oauth": {
    "client_id": "<oauth-client-id>",
    "client_secret_ref": "SERVICENOW_CLIENT_SECRET",
    "token_url": "https://acme.service-now.com/oauth_token.do"
  }
}'
rpk ai mcp-server create acme-servicenow-user --enabled --managed.config '{
  "@type": "type.googleapis.com/redpanda.mcps.servicenow.v1.ServiceNowMCPConfig",
  "instance_url": "https://acme.service-now.com",
  "user_oauth": {
    "provider_name": "servicenow-prod"
  }
}'

Replace <oauth-client-id> with the client ID from your ServiceNow OAuth application registry, and servicenow-prod with the name of the OAuth Provider you configured.

Tools

The ServiceNow MCP exposes tools across incidents, the service catalog, knowledge, schema discovery, lookups, and generic reads:

Tool Description

search_incidents

Search incidents with a ServiceNow encoded query.

get_incident

Fetch one incident by sys_id.

create_incident

Create an incident (typed fields plus an additional_fields map for custom fields).

update_incident

Update assignment, notes, urgency, impact, or resolution details on an incident. It can’t change the state: use transition_incident. A state argument passed here is refused, and nothing is sent.

transition_incident

Move an incident to a state named in words, such as Resolved, Canceled, or On Hold. See Transition an incident.

add_work_note

Append a work note (internal) or comment (customer-visible) to an incident.

search_knowledge

Full-text search over published knowledge articles.

get_article

Fetch one knowledge article by sys_id or number.

search_catalog_items

Find orderable service catalog items from the words a user used, matching both the item’s own text and the option values on its request form. See Order from the service catalog.

get_catalog_item

Return one catalog item’s request form: its variables, which of them are mandatory, and the values each one allows.

submit_catalog_request

Order a catalog item with the values for its request form, and return the requested-item number.

submit_record_producer

Submit a record producer, a catalog form that writes a record directly instead of raising a request.

get_table_schema

Field metadata for a table, from sys_dictionary: name, type, whether the field is mandatory, what it references, whether the dictionary marks it read-only, and whether a reference field is filtered by a reference qualifier.

get_field_choices

Valid choice values for a field from sys_choice, optionally scoped to a parent value.

describe_field_hierarchies

Declared dependent-field chains for a table, from the server configuration.

lookup_user

Find users by name, email, or username; returns their sys_id.

lookup_group

Find assignment groups by name; returns their sys_id.

search_cmdb_ci

Search configuration items (cmdb_ci) with a ServiceNow encoded query; the sys_class_name field distinguishes CI classes such as servers, computers, applications, and services.

query_records

Read any allow-listed table with an encoded query.

Example: Search open incidents

curl -s https://aigw.<cluster-id>.clusters.rdpa.co/mcp/v1/acme-servicenow \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "search_incidents",
      "arguments": {
        "query": "active=true^priority=1"
      }
    }
  }'

Replace <cluster-id> with your cluster ID and $TOKEN with a gateway access token.

Example: Create an incident

The agent typically calls lookup_user and get_field_choices first to resolve caller_id and a valid category value.

curl -s https://aigw.<cluster-id>.clusters.rdpa.co/mcp/v1/acme-servicenow \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/call",
    "params": {
      "name": "create_incident",
      "arguments": {
        "short_description": "VPN drops every few minutes in Dresden",
        "caller_id": "a1b2c3d4e5f6...",
        "urgency": 2,
        "impact": 2,
        "category": "network"
      }
    }
  }'

Transition an incident

State changes go through transition_incident, which takes the target state by name, such as Resolved, Canceled, or On Hold. The server matches names case-insensitively against the state labels your instance defines, so nothing has to know a state number in advance, and a renumbered state can’t send an incident to the wrong place.

Pass the name, not the stored number. The server refuses a numeric value and names the state that value belongs to, so an agent can retry with the name. It refuses a name that matches nothing and lists the states your instance offers. Run get_field_choices on the incident table’s state field for the exact names, or read them from a record that get_incident or search_incidents returned.

The tool also carries a close code, close notes, a work note, a comment, and an additional_fields map for anything else the transition needs, such as a hold reason.

Require companion fields for a state

Instances commonly require a close code before an incident can be resolved or closed. That requirement isn’t part of the table schema get_table_schema reads, so the server can’t discover it. Declare it in incident_state_requirements instead. An unconfigured requirement isn’t enforced.

A declared requirement is checked before anything is sent, so a missing field comes back naming the field, and the agent can ask a person for it instead of interpreting an upstream rejection. The check has a wider reach than one tool, and it is forgiving about case:

  • The requirement applies to the state column, not to a single tool. A state that reaches update_incident through additional_fields is checked the same way, so the requirement can’t be bypassed by the call that follows a refused transition. On that path the state matches by stored value only, because no choice list is read there.

  • The server matches names case-insensitively on both sides: the state matches either its label or its stored value, and a required field name matches whatever case the write used.

Write to a different state column

Some instances don’t use state as the column that actually drives an incident’s state. On those, a write to state can report success while the incident doesn’t move. Set incident_state_field to the column that does drive state, commonly incident_state, and transition_incident writes that column instead.

Only the column changes. The agent still passes a state name in words, and the name resolves against the choices that column defines. Because a state can still reach the server as a raw state key in additional_fields, a configured requirement covers both column names, and transition_incident drops every state key from additional_fields before it assigns the resolved value, so one call can’t carry two states.

A misspelled column doesn’t fail quietly. Write verification treats the configured column like any other incident field, so a returned record that holds the write’s other fields but not that column reports the state under not_applied.

Order from the service catalog

Ordering an item takes three calls, in order. Skipping the middle call means collecting values for a form that the submission then rejects.

  1. Run search_catalog_items with the words the user used, such as laptop or Adobe Acrobat. Pass product or service words rather than a sentence, because the server matches substrings.

  2. Run get_catalog_item on the chosen item to read its request form. Every item asks for something different.

  3. Submit the form with submit_catalog_request for an ordinary item, or with submit_record_producer for a record producer, which writes a record such as an incident or an idea directly instead of raising a request.

Search the catalog

The search runs two passes: one over each item’s name, short description, and category, and one over the option values on items' request forms. The second pass is what reaches a product that is a choice on a general item rather than an item of its own. A result found that way carries the matching option, so an agent can pre-fill it instead of asking again.

Treat the results as candidates rather than as the whole catalog. The response caps them (10 by default, 50 at most) and sets results_truncated when more items matched than it returned, so an item missing from a truncated result is not an item the catalog lacks. Narrow the query to a product name, or pass a category to scope a second pass the way the portal’s own navigation does.

A separate flag, option_search_unavailable, reports that the option-value pass couldn’t run at all. A false value there is weaker than it looks: an instance that filters rows out by permission answers the query normally, which looks the same as nothing matching.

Read the request form

The form that get_catalog_item returns lists each variable with its name, the question the form asks, its type, whether it’s mandatory, its default value, help text, the table a reference value must come from, its allowed values, and its position on the form. Asking in that order follows the form the user would otherwise have filled in.

The mandatory flag comes from the variable’s definition, so a UI policy can make a further variable mandatory once the form is being filled in. An unexpected rejection doesn’t mean the list was wrong.

The response also reports whether the item is still active. A retired item keeps a readable form but can’t be ordered, so check this before collecting values. Search only ever returns live items, so it matters when a sys_id came from somewhere else, or the item retired since.

Submit the form

Key every submitted value by the variable’s name rather than by the label the form shows, and pass the stored value rather than its display label. A mandatory variable that has a default value still needs that value passed explicitly, so the form that reaches ServiceNow is the form the agent reasoned about.

Both submission tools check the values against the form before sending anything, so a missing mandatory value or a name the form doesn’t carry comes back naming the variable, rather than as a rejection that identifies no field. A submission refused this way sent nothing, so correcting the arguments and calling again is safe.

When the form came back partial, only the mandatory-value half of that check runs. An unrecognized name then reaches ServiceNow, because refusing it would block a submission that the item would have accepted.

To order more than one of an item, pass a quantity with the submission. It defaults to 1, and 100 is the most you can order in a single call.

Neither submission tool is safe to retry. A repeat call raises a second request, or writes a second record, under a second number that someone has to cancel. When a submission reports that it couldn’t read back what it created, the request or record exists: have the agent report that the number isn’t available yet rather than submitting again.

What a submission returns

The submit_catalog_request tool returns the requested-item numbers, which begin with RITM. Those are the identifiers to give the user. The response also carries the request number, which begins with REQ, but that’s the container the requested items hang off, and isn’t what a user is asking for.

The submit_record_producer tool returns the table the producer wrote to, along with the created record and its number. Check the table before describing what was created, because a producer chooses its own target, and an idea and an incident reach different teams.

Two limits apply before you rely on either result. A catalog request confirms only that the request and its items exist. It says nothing about whether the form holds the values that were sent, because those live on separate option rows that this server doesn’t read. A record producer does compare the values it sent against the record it read back, because it writes a real record whose columns come back on a read. Even then, a producer script can map a variable to a different column, and the report marks a variable remapped that way as unconfirmed rather than as stored.

When a form couldn’t be read completely, get_catalog_item marks the response as incomplete. A variable missing from an incomplete form isn’t a variable the item doesn’t ask for, and an empty allowed-value list isn’t evidence that a value is invalid. The same applies to a catalog search whose option-value pass couldn’t run: the result is partial, not proof that the catalog holds no such thing.

Confirm what a write stored

An accepted write doesn’t always mean a stored value. Schema discovery tells you which fields to leave alone, and write verification tells you what the instance kept.

Before a write, get_table_schema reports what the data dictionary holds for each field, including:

  • Whether the dictionary marks the field read-only. An agent should report that such a field can’t be set, rather than trying to set it.

  • Whether a reference field is filtered by a reference qualifier, and which of the three qualifier kinds it declares (Simple, Dynamic, or Advanced). For a filtered field, resolve a value that satisfies the filter, and read an emptied field as the filter rejecting the value rather than as a bad identifier. The qualifier’s own condition, script, or filter record isn’t returned, so ask an administrator about the construct the field names.

A false value on either attribute doesn’t guarantee that the field is writable. Write access control lists, ServiceNow data policies, and business rules aren’t read here, and aren’t in the data dictionary at all. A sys_dictionary_override row is in the data dictionary but still isn’t read here, so an inherited field made read-only on one child table reports false.

After a write, the incident write tools compare the values they sent against the record that ServiceNow returned from the write itself, and attach a report to that record under _redpanda_write_verification. The submit_record_producer tool re-reads the record it created and reports on that instead. A write response is synchronous, so a confirmed value is what the instance held at that moment. Business rules, flows, and scheduled jobs that run afterwards can still change it.

The report always carries a plain-language summary. It adds applied and not_applied as lists of field names, for the values the response held and the values the instance didn’t store, and unconfirmed for fields it can’t settle either way, where each entry pairs the field with the reason. Journal fields such as work notes and comments are never echoed back, so they arrive unconfirmed. Each of the three is left out when it’s empty. Have an agent read the report before it tells a user what changed. A state that appears under not_applied after transition_incident means the transition didn’t happen.

The submit_catalog_request tool attaches no such report. Its response carries the request and requested-item numbers rather than the record, so nothing confirms the values that the request stored.

Troubleshooting

Common symptoms and fixes:

Symptom What to check

401 Unauthorized

Confirm the service-account credentials. For Basic authentication, check the username and SERVICENOW_PASSWORD; for OAuth, check the client ID, SERVICENOW_CLIENT_SECRET, and token URL.

403 Forbidden

The service account lacks the role for the operation (for example, itil for incidents or read access to sys_dictionary for get_table_schema). Grant the role in ServiceNow.

query_records rejects a table

The table is not listed in projections with queryable set to true. Add a projection entry for it.

update_incident refuses a state argument

It can’t change an incident’s state, and nothing was sent. Call transition_incident and pass the state by name.

transition_incident succeeds but the state reports under not_applied

The instance didn’t store the state. If another column drives state on this instance, set incident_state_field to that column. See Write to a different state column.

transition_incident refuses a transition for a missing field

A configured incident_state_requirements entry covers the target state. Supply the named fields, or change the entry. Nothing was sent, so calling again with the fields is safe. See Require companion fields for a state.

A catalog search or request form comes back partial

The account can’t read item_option_new on this instance. Grant read access, and until then treat the result as incomplete rather than as evidence that an item or variable doesn’t exist.

A submission is refused naming a variable

The refusal is local, so nothing was sent. Supply the named variable’s value (a mandatory variable needs its value even when the form has a default), or drop a name the form doesn’t carry, then call again.

A write reports a field under not_applied

The instance didn’t store that field. Check the field with get_table_schema: a read-only field can’t be set, and a filtered reference field needs a value that satisfies its qualifier. See Confirm what a write stored.

OAuthConnectionRequired (User-OAuth mode)

First call from a user with no stored token. The user completes the ServiceNow OAuth consent flow, the token lands in the vault, and later calls reuse it. See User-delegated OAuth.

Limitations

This MCP server does not cover:

  • Record deletion: Writes are limited to the typed incident tools and the two catalog submission tools; the MCP never deletes records.

  • Arbitrary SQL: Reads go through the REST Table API and encoded queries, not a SQL interface. Use query_records against allow-listed tables instead.

  • Order guides, content items, and order wizards: The server refuses these three classes rather than submitting one, and refuses a record producer on the ordering path, because submit_record_producer is what submits it. Any other class is submitted, including an item whose class couldn’t be read, because most orderable items belong to a subclass rather than to the base class. A catalog search reports each item’s class, so an agent can tell a user that a given item can’t be ordered here.

  • Ordering on behalf of someone else: Neither submission tool takes an argument naming a different requester. You can still set a requester through a form’s own requester variable, where the item has one.

  • Two-step checkout: The server detects an instance configured to place an ordered item in a cart instead of raising a request, rather than working around it. The submission then reports an error saying the item is already submitted, so don’t submit it again.