Grouper MCP server - administrator guide

Grouper MCP server - administrator guide

Introduction

This guide is for Grouper administrators and operators who want to enable, configure, and manage the built-in MCP server. It covers enabling MCP, all configuration properties, authorization groups that control who can use MCP, registration security, and multi-container deployment considerations.

For a high-level introduction to the Grouper MCP server, see the overview. For end-user setup instructions and tool documentation, see the user guide. For architecture and protocol details, see the technical reference.

Enabling the MCP server

The MCP server and OAuth authentication are controlled by two separate configuration properties in grouper.hibernate.properties:

  • grouper.is.mcp – Enables the MCP protocol.

    • On a WS environment (grouper.is.ws = true): loads the MCP protocol servlet.

    • On a UI environment (grouper.is.ui = true): enables the MCP info page.

  • grouper.is.oauth – Enables OAuth 2.1 with PKCE authentication.

    • On a WS environment (grouper.is.ws = true): loads the OAuth token and registration servlets.

    • On a UI environment (grouper.is.ui = true): enables the OAuth consent page.

Both properties must be set to true on both the WS and UI containers for full MCP-with-OAuth functionality. If you only need MCP with WS authentication (HTTP Basic or container auth) and no OAuth, you can enable grouper.is.mcp alone on the WS container.

To enable MCP with OAuth, set the following in your Grouper configuration or as environment variables:

# In grouper.hibernate.properties (set on both UI and WS containers) grouper.is.mcp = true grouper.is.oauth = true

Or via environment variables (which the EL config expressions read automatically):

GROUPER_MCP=true GROUPER_OAUTH=true

The MCP protocol servlet requires grouper.is.ws = true because it is registered inside the WS servlet initialization block. The OAuth servlets also require grouper.is.ws = true. Both the WS module and the UI module must be running for the OAuth flow to work (WS handles token exchange; UI handles user authentication and consent). If using normal WS authentication (HTTP Basic or container auth) instead of OAuth, only the WS module with grouper.is.mcp = true is required.

Configuration

grouper.hibernate.properties

Property

Default

Description

grouper.is.mcp

false (via GROUPER_MCP env var)

Enable MCP. On a WS environment this loads the MCP protocol servlet. On a UI environment this enables the MCP info page.

grouper.is.oauth

false (via GROUPER_OAUTH env var)

Enable OAuth 2.1 with PKCE authentication. On a WS environment this loads the OAuth token and registration servlets. On a UI environment this enables the OAuth consent page.

MCP settings (grouper.properties)

Property

Default

Description

grouper.mcp.auth.oauth

true

Allow OAuth JWT Bearer authentication for MCP.

grouper.mcp.auth.httpBasic

false

Allow HTTP Basic authentication for MCP. Requires grouper.is.ws.basicAuthn = true in grouper.hibernate.properties.

grouper.mcp.auth.container

false

Allow container-managed authentication for MCP (e.g. Tomcat valve, Apache module).

grouper.mcp.auth.customAuthClass

false

Allow custom authentication class for MCP (ws.security.non-rampart.authentication.class).

grouper.ws.url

(blank)

Base URL of the WS (used for MCP and other WS operations), e.g. https://grouper.example.edu/grouper-ws. Displayed on the MCP info page in the UI. Configured at the top of grouper.base.properties below grouper.ui.url. The MCP endpoint URL will be this value with /mcp appended.

grouper.mcp.logClientErrors

false

Log MCP client errors at WARN level. Enable when debugging MCP connection issues.

grouper.mcp.sqlGrouperExternalSystem

grouper

The database connection name used when the AI queries the Grouper database (i.e. when externalSystemId is "grouper" or not specified). Defaults to grouper (the main Grouper database connection). Administrators can set this to a different external system that points to a read-only database user or a read replica for additional security. The external system must be configured under grouperClient.jdbc.{name}.* in grouper.client.properties.

grouper.mcp.tools.allow

(empty)

Comma-separated list of MCP tool names to allow. If blank (the default), all tools are allowed (subject to the user's group membership and consent scopes). If set, only the listed tools are available. Deny list takes precedence over allow list (effective tools = allow minus deny). Example: group_find, group_get_members, group_has_member, group_save

grouper.mcp.tools.deny

(empty)

Comma-separated list of MCP tool names to deny. If blank (the default), no tools are denied. Deny list takes precedence over allow list (effective tools = allow minus deny). Tools on the deny list will not appear in tools/list and will return an access-denied error if called directly. Example: sql_select, sql_get_schema, admin_daemon_job_run

grouper.mcp.instructions

Grouper is an enterprise access management system for managing groups, folders, memberships, privileges, and attributes. Use the doc_search tool to find institutional documentation before attempting operations you are unsure about.

Instructions sent to the AI client in the MCP initialize response. Customize this to give the AI client guidance specific to your institution — for example, highlighting that documentation should be consulted early and often, describing your folder naming conventions, or noting institutional policies. This text appears as the instructions field in the initialize response and is typically displayed as a system prompt by the AI client. Newlines can be embedded with \n.

OAuth settings (grouper.properties)

These properties control the OAuth 2.1 token lifecycle used by MCP clients that authenticate via the OAuth flow.

Property

Default

Description

grouper.oauth.accessToken.expirationSeconds

14400 (4 hours)

JWT access token lifetime in seconds

grouper.oauth.authorizationCode.expirationSeconds

600 (10 minutes)

Authorization code lifetime in seconds

grouper.oauth.logAuthDebug

false

Log OAuth authentication debug info at WARN level. When enabled, logs the authorization header type and remote address on every MCP request, and the public key hash when the OAuth signing key is loaded from config. Useful for diagnosing OAuth/MCP connection and authentication issues in multi-container deployments. Disable (default) in normal operation to reduce log volume.

grouper.mcp.oauth.requireReadwriteDataScope

true

Whether to require users to specify data scope restrictions (folders, groups, and/or subjects) when granting read-write access on the OAuth consent page. When true (default), at least one folder, group, or subject must be entered. When false, the data scope fields are optional and users can grant unrestricted read-write access.

OAuth registration settings (grouper.properties)

These properties control how MCP clients register as OAuth clients via dynamic client registration (RFC 7591). Registration is anonymous (no authentication required) and is protected by the redirect URI allowlist, IP-based rate limiting, and the fact that registration alone grants zero access — the user must still complete the OAuth consent flow and be in the proper MCP authorization groups.

Property

Default

Description

grouper.oauth.registration.enabled

true

If false, dynamic client registration is disabled entirely. The /mcp/oauth/register endpoint returns 403.

grouper.oauth.registration.rateLimitPerIpPerHour

20

Maximum number of registration requests allowed per IP address per hour. Set to 0 to disable rate limiting.

grouper.oauth.redrectUri.<configId>.regex

(none)

Regex pattern that registered redirect URIs must match. Multiple patterns can be configured with different configId values. A redirect URI is allowed if it matches any configured pattern. If no patterns are configured, all redirect URIs are rejected (secure-by-default). Validated at both client registration time and at the authorization/consent endpoint.

Redirect URI patterns are required. If no grouper.oauth.redrectUri.*.regex patterns are configured, all OAuth client registrations will be rejected. For development, start with a localhost pattern:

# Allow localhost redirect URIs for development grouper.oauth.redrectUri.localhost.regex = ^http://localhost(:\\d+)?/.*$ # Allow a production application grouper.oauth.redrectUri.myApp.regex = ^https://myapp\\.example\\.edu/.*$

MCP authorization groups (grouper.properties)

See the Authorization groups section below for the full list of MCP authorization group properties and their defaults.

Auto-managed configuration (database-stored)

The following properties are automatically generated and stored in the database-backed grouper.properties configuration. They should not normally be set manually.

Property

Description

grouper.oauth.signingKey.privateKey

RSA private key (Base64-encoded, auto-encrypted by Morph framework)

grouper.oauth.signingKey.publicKey

RSA public key (Base64-encoded)

Authorization groups

MCP access is controlled by Grouper groups that are autocreated at startup. Membership in these groups determines what each user can do via MCP. Note that wheel group membership does not automatically grant MCP access — users must be explicitly added to the appropriate MCP groups.

Property

Default Group

Purpose

grouper.mcp.users.wsAuthnAllowed

etc:mcp:mcpUsersWsAuthnAllowed

Members can use MCP via WS authentication (HTTP Basic, container auth). Not required for OAuth users.

grouper.mcp.users.readonly

etc:mcp:mcpUsersReadonly

Members can use MCP tools with read-only access

grouper.mcp.users.readwrite

etc:mcp:mcpUsersReadwrite

Members can use MCP tools with read-write access

grouper.mcp.users.canRunSqlReadonly

etc:mcp:mcpUsersCanRunSqlReadonly

Members can run read-only SQL queries via MCP

grouper.mcp.users.adminReadonly

etc:mcp:mcpUsersAdminReadonly

Members can run admin commands readonly via MCP. Must also be a Grouper sysadmin or readonly sysadmin.

grouper.mcp.users.adminReadWrite

etc:mcp:mcpUsersAdminReadWrite

Members can run admin commands readwrite via MCP. Must also be a Grouper sysadmin.

grouper.mcp.users.canRegisterConfidentialOAuthClient

etc:mcp:mcpUsersCanRegisterConfidentialOAuthClient

Members can register confidential OAuth clients (with client secret) from the MCP info page in the UI. Useful for server-side applications like LibreChat that can securely store a client secret. Grouper sysadmins can always register confidential clients regardless of this group.

Note: These groups are autocreated by Grouper at startup (when configuration.autocreate.system.groups = true, which is the default). Administrators populate these groups to grant MCP access to individual users or other groups.

OAuth provides additional consent-based restriction. When users authenticate via OAuth, the consent page only shows scope checkboxes for groups the user is actually a member of (read-write membership also shows the read-only scope, and admin read-write also shows admin read-only), and the user can choose to grant fewer scopes than their group memberships would allow. These consent choices are enforced on every MCP request in addition to group membership. For example, a user in the readwrite group can choose to grant only readonly access to a particular MCP client. With WS authentication (HTTP Basic, container auth) there is no consent flow, so authorization is based solely on group membership. This makes OAuth the preferred authentication method for interactive AI use.

Read-write scope restrictions. When a user selects the read-write scope on the OAuth consent page, they can specify scope restrictions: folder paths (limiting which folders the client can modify groups in, maximum 10), group paths (limiting which specific groups can be modified, maximum 10), or subject IDs/identifiers (limiting which subjects can be managed, maximum 50). Folders are validated for existence and the total number of groups across all specified folders must be less than 500. These restrictions are encoded in the JWT access token and enforced on every read-write tool call. Categories left blank are unrestricted — for example, if a user only enters folder paths but leaves subjects blank, the client can modify groups in those folders for any subject. Conversely, if a user only enters subject IDs, those subjects can be operated on with any group. At least one category must have a value; if all categories are left blank, no read-write operations are permitted. By default (grouper.mcp.oauth.requireReadwriteDataScope = true), at least one folder, group, or subject must be specified. Set to false to make data scope restrictions optional, allowing users to grant unrestricted read-write access.

Scope enforcement for assignment-on-assignment. When a read-write tool call uses an _asgn attribute assign type (e.g. group_asgn, stem_asgn), the MCP server resolves the owner attribute assignment to determine the underlying group, stem, or subject. Scope restrictions are then checked against that underlying owner, not just the assignment ID. This ensures that, for example, an OAuth client scoped to folder school:departments cannot assign metadata on a marker attribute that belongs to a group in school:clubs.

Trailing colon tolerance. Folder scope values entered with a trailing colon (e.g. school:departments:) are handled correctly — the trailing colon is stripped before matching. This prevents user confusion when entering folder paths.

Summary of tool access for authorization groups

Tool name

mcpUsersAdminReadWrite

mcpUsersAdminReadonly

mcpUsersCanRunSqlReadonly

mcpUsersReadonly

mcpUsersReadwrite

admin_config_search

 

 

 

admin_daemon_job_message

 

 

 

admin_daemon_job_run

 

 

 

 

admin_daemon_logs

 

 

 

admin_daemon_names

 

 

 

admin_external_system_get

 

 

 

ldap

 

 

 

sql_get_schema

 

 

 

 

sql_select

 

 

 

 

attribute_assignment_get

 

 

 

attribute_assignment_save

 

 

 

 

attribute_def_name_find

 

 

 

audit_get

 

 

 

doc_search

 

 

 

entity_get

 

 

 

entity_get_groups

 

 

 

folder_delete

 

 

 

 

folder_find

 

 

 

group_add_member

 

 

 

 

group_delete

 

 

 

 

group_find

 

 

 

group_get_members

 

 

 

group_has_member