> For the complete documentation index, see [llms.txt](https://docs.inrupt.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.inrupt.com/guides/integrating-with-ess-mcp.md).

# Integrating an AI Agent with ESS using MCP

{% hint style="success" %}
Added in version 3.0.0
{% endhint %}

This guide walks through building a client application that integrates with ESS's Model Context Protocol (MCP) Service. The MCP Service enables AI agents and applications to securely access, manage, and interact with personal data stored in ESS.

## Overview

The ESS MCP integration uses the [MCP Resource Service](https://docs.inrupt.com/ess/latest/services/service-mcp/mcp-resource), which provides MCP tools for managing and accessing resources. Clients authenticate using ESS Access Tokens obtained through the [Platform Management service](https://docs.inrupt.com/ess/latest/services/service-platform-management/token-exchange).

A typical MCP client workflow involves:

1. Authenticating with your Identity Provider and exchanging for an ESS Access Token
2. Using MCP tools to request access to resources
3. Retrieving resource content using Access Grants

## Quickstart

Before setting up a proper MCP client, it is possible to try the ESS MCP service using [MCP Inspector](https://modelcontextprotocol.io/docs/tools/inspector).

### Step 1: Get an ESS Access Token

1. Authenticate with your external Identity Provider to obtain an ID token.
2. Exchange the ID token for an ESS Access Token via the [Platform Management service](https://docs.inrupt.com/ess/latest/services/service-platform-management/token-exchange):

```http
POST /access/token HTTP/1.1
Host: platform.YOUR-ESS-DOMAIN
Content-Type: application/x-www-form-urlencoded
 
grant_type=urn:ietf:params:oauth:grant-type:token-exchange&subject_token=<idp-id-token>&subject_token_type=urn:ietf:params:oauth:token-type:id_token
```

Using cURL, the command would look like

```bash
curl -X POST https://platform.YOUR-ESS-DOMAIN/access/token -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange&subject_token=<idp-id-token>&subject_token_type=urn:ietf:params:oauth:token-type:id_token"
```

A successful response will include an ESS Access Token.

### Step 2: Set up the MCP Inspector

1. Save the following configuration in an `mcp.json` file:

```json
{
  "mcpServers": {
    "ess": {
        "type": "streamable-http",
        "url": "https://mcp.YOUR-ESS-DOMAIN/api"
    }
  }
}
```

2. Start the MCP inspector using this configuration:

```bash
npx @modelcontextprotocol/inspector --config mcp.json --server ess
```

3. In the MCP inspector browser window which should have opened, in the "Authentication" section, add a custom `Authorization` header with the value `Bearer your-access-token`, using the ESS Access Token obtained at the previous step.
4. Click connect. You should now be successfully connected.

### Step 3: Interact with the MCP tools

Now that you have successfully connected, you can interact with the different tools, such as `requestAccess` or `checkAccessRequestStatus`. The access control restrictions listed in the [MCP Resource Service](https://docs.inrupt.com/ess/latest/services/service-mcp/mcp-resource) documentation apply.

## Setup a proper MCP client

The MCP inspector is a nice debug/starting point, but the point of the MCP Service is to support an AI Agent using an MCP client to enrich its context when interacting with a user. The following guide describes how to setup such MCP client with the AI Agent of your choice.

### Prerequisites

Before you begin, ensure you have:

* An ESS deployment with MCP services enabled (version 3.0.0 or later)
* An external Identity Provider configured as a trusted issuer in the Platform Management service
* Client credentials for authenticating with your Identity Provider

### Step 1: Configure Identity Provider

Ensure your external Identity Provider is configured as a trusted issuer in ESS's Platform Management service. Contact your ESS administrator to add your IdP's issuer URL to the trusted issuers list.

### Step 2: Obtain an ESS Access Token

Authenticate with your Identity Provider and exchange the resulting ID token for an ESS Access Token:

```js
import { Client } from '@modelcontextprotocol/sdk/client';
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';

// Step 1: Authenticate with your IdP (implementation depends on your IdP)
const idToken = await authenticateWithIdP();

// Step 2: Exchange for ESS Access Token
const tokenResponse = await fetch(`${process.env.TOKEN_EXCHANGE_URL}/token`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
  body: new URLSearchParams({
    grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',
    subject_token: idToken,
    subject_token_type: 'urn:ietf:params:oauth:token-type:id_token',
  }),
});

const { access_token } = await tokenResponse.json();

// Step 3: Connect to MCP Resource Service
const transport = new StreamableHTTPClientTransport(
  process.env.MCP_SERVER, {
    requestInit: {
      headers: {
        'Authorization': `Bearer ${access_token}`,
      },
    },
  }
);

const client = new Client(
  {
    name: 'my-ai-agent',
    version: '1.0.0',
  },
  {
    capabilities: {},
  }
);

await client.connect(transport);
```

### Step 3: Client Uses MCP Tools to Get Access to the User Resources

#### 3.1 Client Checks for an Access Grant

The client may use the `hasMatchingAccessGrant` tool to confirm a valid Access Grant exists. If such Access Grant exists, the Agent may directly go read the resource (See [Step 4](#4-client-retrieves-user-resource-content)).

**Note:** The agent can only verify Access Grants where the grantor is the current authenticated user.

#### 3.2 Client Requests Access to Resource

The client may use the `requestAccess` tool to create an Access Request. The Access Request is automatically attributed to the authenticated user. The client receives an Access Request URL with status `pending`.

#### 3.3 Client Monitors Request Status

The client may use the `checkAccessRequestStatus` tool with the Access Request URL to monitor its status. Continue checking until the status changes from `pending` to one of:

* `granted` - Request approved by Resource Owner
* `denied` - Request rejected
* `cancelled` - Request cancelled

**Note:** The agent can only check the status of Access Requests issued to the current authenticated user.

#### 3.4 User Approves Client Request

The end user who received the Access Request will now need to approve it using a separate interface to manage access. Reviewing and approving Access Requests cannot be done via the MCP service.

#### 4. Client Retrieves User Resource Content

The client may use the `getResource` tool to retrieve the actual resource data using the Access Grant.

**Note:** The client can only retrieve resources using Access Grants issued by the current authenticated user.

## Security Considerations

### Token Management

* ESS Access Tokens have a default TTL of 5 minutes
* Use the `expires_in` value from the token exchange response to proactively re-authenticate before the token expires
* Handle `401` responses by performing a new token exchange and retrying the request
* Store tokens securely and never expose them in client-side code or logs

### Access Grant Validation

The Resource Service performs comprehensive validation for `getResource` operations:

* The Access Grant must exist and not be revoked
* The Access Grant must not have expired
* The Access Grant must authorize access to the requested resource
* The Access Grant must have been issued to the agent
* The Access Grant must include the required access modes

## Error Handling

Handle common error scenarios gracefully.

### Authentication Errors

* **Invalid Token**: ID token from the external IdP is invalid or expired
* **Untrusted IdP**: The IdP issuer is not in the trusted issuers list

### Access Request Errors

* **Denied**: Resource owner rejected the access request
* **Cancelled**: Access Request was cancelled before approval
* **Expired**: Access Grant has expired

### Resource Access Errors

* **Authorization Error**: Token expired or invalid
* **Grant Not Found**: Access Grant ID is invalid or has been revoked
* **Resource Not Found**: Resource URI is invalid or inaccessible

## Best Practices

1. **Check Existing Grants First**: Before creating new Access Requests, check if valid grants already exist to avoid duplicate requests
2. **Provide Clear Purpose Statements**: When requesting access, include descriptive purpose text to help Resource Owners make informed decisions
3. **Handle Asynchronous Approval**: Access Requests require human approval, so implement polling with appropriate backoff strategies
4. **Handle Token Expiry**: Use `expires_in` from the token exchange response to re-authenticate before expiry, and retry on `401` responses
5. **Use Canonical URIs**: When referencing resources in Access Requests, use canonical URIs (`/sc/` form) for durable references
6. **Validate All Inputs**: Validate resource URIs, access modes, and other parameters before making tool calls
7. **Log All Operations**: Maintain audit logs of all Access Requests and resource retrievals for compliance and debugging
8. **Respect User Context**: Always ensure your agent operates within the boundaries of the authenticated user's access rights

## Additional Resources

* [MCP Resource Service Documentation](https://docs.inrupt.com/ess/latest/services/service-mcp/mcp-resource)
* [MCP Service Overview](https://docs.inrupt.com/ess/latest/services/service-mcp/)
* [Platform Management service](https://docs.inrupt.com/ess/latest/services/service-platform-management/token-exchange)
* [Model Context Protocol Specification](https://modelcontextprotocol.io/)
* [OAuth 2.0 Token Exchange (RFC 8693)](https://datatracker.ietf.org/doc/html/rfc8693)
