The MCP server is a Beta feature for environments with UnqorkAI. Test each published tool and verify its results before relying on it.
The MCP server lets AI agents that run outside Unqork call API modules as tools. Each environment has one Model Context Protocol (MCP) endpoint, and a Creator chooses which API modules to publish through it.
An agent signs in with an Express API credential, and the credential's Express role decides which tools the agent can see and call. Every call is rate-limited and logged. To publish a module as a tool and connect an agent, see Publish API Modules as MCP Tools.
Key Terms
Readers must understand the following terms to use the MCP articles.
| Term | Definition |
|---|---|
| AI agent | Software outside Unqork that uses an AI model to decide which tools to call and when. |
| Express API credential | A Client ID and Client Secret that software uses to sign in to an environment instead of a person. An agent signs in with one, and the credential's Express role decides what the agent can reach. |
| Express role | A set of permissions that controls what end-users, or an agent that signs in with a credential, can access in an environment. An agent's role must have Default Permission No Access and Write on each module the agent calls. |
| MCP | Model Context Protocol, an open standard that lets AI agents find and call tools in other systems. |
| MCP client | The software that connects to an MCP server for an agent, like a client SDK or Claude Code. |
| MCP endpoint | The address where an MCP client connects. Each environment has one, on the Express host. |
| MCP server | The part of an environment that answers MCP requests. It lists the tools that an agent's role can call and runs a tool when the agent calls it. Each environment has one MCP server, which agents reach at its MCP endpoint. |
| Tool | An API module that a Creator has published for agents to call. A tool has a name, a description, inputs, and outputs. |
How the MCP Server Works
A tool is an API module that a Creator has published to the environment's MCP endpoint. The tool's settings are stored on the module, so the tool versions and promotes with the module. Deleting the module removes only its tool.
Publishing a tool has two parts. The Build Agent writes the first setup. It reads the module and proposes the tool's name, description, inputs, and outputs in wording an agent can read. A Creator reviews and approves that setup, then edits the tool afterward on the MCP Settings page of the module's settings.
What Happens When an Agent Calls a Tool
The following steps describe one complete call, from sign-in to result:
- The agent requests an access token from the environment's token endpoint, using its credential's Client ID and Client Secret. The request names the MCP endpoint, so the token works only there.
- The agent sends the token with each request to the MCP endpoint. The server checks the request's origin, the credential's request allowance, and the credential itself. It rejects Creator accounts and roles that bypass module permissions.
- The agent asks for its list of tools. The server returns only the tools whose modules grant the credential's role Write.
- The agent calls a tool with arguments. The server rejects arguments that the tool does not declare or that have the wrong type.
- The server runs the module and applies its validation rules. If the module's own rules fail, the agent receives the field and the rule it broke, so the agent can correct the call.
- The server returns only the outputs that the tool declares. It also records the call in Service Logs and the audit trail.
Who Does What
The Build Agent handles the module side. An environment administrator keeps control of the agent's identity.
| Task | Who | Where |
|---|---|---|
| Create the agent's Express role. | An environment administrator. | Express Role Administration |
| Grant the role Write on the module. | A Creator, or the Build Agent after asking. | Module settings, User Permissions |
| Set up the tool. | The Build Agent for the first setup. A Creator can edit it afterward. | Module settings, MCP Settings |
| Publish the tool or switch it off. | A Creator, or the Build Agent after asking each time. | Module settings, MCP Settings |
| Create the agent's API credential. | An environment administrator. The Build Agent cannot. | API Access Management, Express tab |
| Get tokens and connect. | The agent's own code, or whoever runs the MCP client. | The token endpoint and the MCP endpoint |
The Build Agent can read the environment's Express roles to suggest one. It cannot create a role, create or change a credential, or issue a token. When it tests a tool, it runs the module directly to check the module's logic. That run does not go through MCP, so it does not test the agent's credential or access.
How an Agent Gets Access
An agent signs in as an Express API credential, never as a person. The credential's Express role decides which tools the agent can call:
- The role must have Default Permission No Access. MCP rejects any other default, because the agent could otherwise run every module that does not name the role.
- The role must not have Designer Access or Full Submission Access. Either one bypasses module permissions.
- The role must have Write on the User Permissions page of each module the agent calls. Customize RBAC for This Module must be ON. Read-Only does not work, because the module ignores the agent's inputs.
- Every role on the credential must meet these rules, and the credential must have no application role mapping. Give each credential one role, so an agent's reach is clear.
A Creator's sign-in or a password-grant token is never accepted. The server checks these rules on every request, so a change to a role or a module applies on the agent's next call.
Endpoint for Each Environment
Each environment has one MCP endpoint, https://{express-host}/api/1.0/mcp. Agents always use the environment's Express host. The Designer host rejects API credentials with 403 Designer Access Denied.
| Environment | Designer Host | Express Host |
|---|---|---|
| Non-production | {environment}.unqork.io |
{environment}x.unqork.io |
| Production | {environment}-designer.unqork.io |
{environment}.unqork.io |
| Government cloud | The same patterns on unqorkgov.io. |
The same patterns on unqorkgov.io. |
The MCP Settings page displays the exact address for the environment.
How Clients Connect
- Transport: The endpoint uses Streamable HTTP over
https://. It acceptsPOSTonly and keeps no sessions. - Protocol revisions: The server supports revisions
2026-07-28,2025-11-25, and2025-06-18. A request that names another revision receives a400response that lists the supported revisions. - Capabilities: The server provides tools only. It publishes no resources or prompts, and it does not notify a client when its tools change.
Current client SDKs connect without changes, including the official TypeScript SDK and Claude Code.
Tool Settings
Each tool has a name, a description, the inputs an agent sends, the outputs it receives, and optional call limits. A Creator sets them on the MCP Settings page, and the Build Agent proposes them during the first setup. See MCP Settings for every setting.
- Name and description: Agents read these to decide when to use the tool, so both state what the tool does. A tool name is unique in the environment. If two modules claim the same name, the first module keeps it, and the second is not served until it is renamed.
- Inputs: The information an agent sends when it calls the tool, like an order number. An agent can send only the inputs that the tool lists.
- Outputs: The information the tool returns to the agent, like the status of an order. The result converts a value to its declared type when it plainly fits, like the text
"12"to the number 12. It leaves out a value that cannot be that type. - Call limits: Optional limits on how often one agent can call the tool. A tool limit can only be lower than the environment limit.
Leaving an input out of a tool restricts only agents that connect through MCP. A direct API call to the module can still set that field, so enforce any value that must not change in the module's logic.
When Changes Take Effect
In an application without versioning, a save takes effect on the next call. In a versioned application, the tool is saved in a draft and goes live with that draft's release. Publish tools in a development environment, then promote them. Until the application is released, it serves no tools.
A later edit can break a published tool, for example by turning off Customize RBAC for This Module or removing an exposed field. Agents then cannot call the tool. The MCP Settings page displays Agents can't call this tool right now with the reasons.
An agent that is already connected does not learn that its tools changed. A client sees a new, edited, or switched-off tool only when it lists its tools again, and most clients list tools only when they connect. After a change, reconnect or restart the client.
Promote Tools to Another Environment
A tool promotes with its module. The tool's settings and the module's User Permissions are part of the module. They move when a Creator promotes the module or its application version, and the switch that publishes the tool moves with them. Each environment keeps its own roles and credentials. An agent needs its own setup in the target environment before it can call the promoted tool.
| Item | In the Target Environment |
|---|---|
| Tool settings | Promote with the module, including the switch that publishes the tool. |
| Module User Permissions | Promote with the module. They name Express roles, so each role must exist in the target environment. |
| Express roles | Promote separately with Promote Roles in Express Role Administration, which overwrites a role with the same name, or create the role in the target environment. Confirm that the role has Default Permission No Access and that Designer Access and Full Submission Access are off. |
| API credentials | Are not promoted. Create a credential for the role in each environment. A Client ID and Client Secret work only in the environment that created them. |
| Access tokens | Cannot move between environments. A token works only at the MCP endpoint of the environment that issued it. |
| Endpoint address | Differs for each environment. The agent connects to the Express host of the target environment. |
If the module's role does not exist in the target environment, the MCP Settings page displays No role can call this tool yet.
In a versioned application, a Creator publishes the tool in a development environment, releases the version, and promotes it. The target environment serves the tool from the application's active version, and it serves no tools until a version is released.
A tool name is unique in an environment. If a module in the target environment already uses the name, the promoted tool is not served until a Creator renames it.
Authentication and Tokens
An agent requests a token from the token endpoint on the environment's Express host, using its credential's Client ID and Client Secret. Store the Client Secret in a secrets manager, never in code or source control.
Token Behavior
- Bound to the endpoint: The request includes a
resourcevalue that must name the environment's MCP endpoint exactly. The MCP endpoint rejects a token requested without it, and every other API route rejects a token requested with it. - Lifetime: Every token lasts 60 minutes, for every credential and environment. The lifetime cannot be changed.
- No refresh token: The client credentials grant does not issue one. An agent requests a new token about a minute before expiry, and again whenever a call is rejected because of its token.
- Expired tokens: An expired token receives
440 Login Timeoutinstead of401. Treat both the same way by requesting a new token and retrying once. - No scopes: A token reaches exactly what its role reaches, which is the tools whose modules grant that role Write.
The token endpoint rejects a request with 400 and an invalid_target message in the following cases:
- The request uses
resourcewith a grant other thanclient_credentials. - The
resourcevalue is not an absolute address, names a different environment, includes a query or fragment, or does not name the MCP endpoint. - The environment does not have UnqorkAI.
A token does not confine the credential. The same credential can still call the role's modules through the regular API with an ordinary token. MCP adds the call limits and the per-call audit to the MCP route only. Set a value that must never be caller-controlled in the module's logic.
Handle Tokens Securely
- Keep the token in memory and send it only in the
Authorization: Bearerheader. Never place it in a URL. - Do not log tokens, request bodies, or authorization headers.
- Load the Client Secret from the secrets manager when the agent begins, and never type it on a command line.
- Connect only over
https://.
Revoke an Agent's Access
An individual token cannot be revoked, and Express credentials have no Revoke action. Use the following controls instead:
| To Stop | Do This | Takes Effect |
|---|---|---|
| One tool for one role | Set the role to No Access on the module's User Permissions page, or switch the tool off on MCP Settings. | On the next call, even with a live token. The tool leaves the agent's list. |
| Everything for one agent | Remove the role from the credential. | On the next call. |
| The credential for good | Delete the credential in API Access Management. | The credential cannot get another token. |
| A leaked secret | Generate a new secret or delete the credential, then rotate the secret in the secrets manager. | Tokens already issued stay valid for up to 60 minutes unless the role or credential is also removed. |
Limits and Issues
Call Limits
| Limit | Default | When Reached |
|---|---|---|
| Requests | 120 each minute, for each credential. | The endpoint returns HTTP 429 with the seconds until the minute resets. |
| Calls running simultaneously | 2, for each credential. | The extra call returns immediately as a failed result and is not queued. |
| Per tool (optional) | Set on MCP Settings. It can only be lower than the environment limits. | That tool returns a failed result, and the agent's other tools keep working. |
Every message an agent sends to the endpoint counts as a request. The count includes the connection handshake (two messages), each list of tools, each tool call, and each ping. A request that the endpoint rejects after the request-limit check also counts, like a refused credential or an unknown tool. A request rejected before the check does not count. Examples are a request with an Origin header, a method other than POST, and a body that is not a JSON-RPC request. Getting a token does not count.
The allowance belongs to the API credential. Every copy of an agent that shares one credential shares one allowance, across every conversation and end-user it serves. Use separate credentials for separate deployments.
The minute is a fixed window. It begins with the credential's first request and resets 60 seconds later. Retrying before the reset returns another 429 and does not move the reset. The wait time displays in the message only, and the response has no Retry-After header.
Listing tools and the handshake do not use one of the two call slots. A call that takes a long time holds its slot until the module finishes. Each server instance counts its own slots, so an environment that runs several instances can allow more calls in total. Models often request several tools in one turn, so queue calls in the client two at a time.
The environment limits are the same for every agent and are not settings in the platform. A per-tool limit is the part that a Creator controls.
Responses an Agent Can Receive
The server answers a request that fails a check with an HTTP status and a JSON-RPC error. It answers a tool call that reaches the module with a result, even when the call fails.
HTTP Responses
| Response | Cause | What to Do |
|---|---|---|
202 with no body |
The agent sent a notification, which is a message with no id. This response is a success. |
No action is required. |
400 with -32700 or -32600 |
The request body is not a JSON-RPC 2.0 request object, or the agent sent a JSON-RPC response. | Send a JSON-RPC 2.0 request. |
400 with -32600 and a list of versions |
The request names a protocol revision that the server does not support. | Use one of the listed revisions. |
400 with -32602 |
The arguments do not match the tool's schema because of a wrong type, a missing required field, or an undeclared field. The same response applies when a tool call has no tool name. | Correct the arguments. |
400 with -32020 |
A protocol header is missing or disagrees with the request body, like the method header, the tool name header, or the protocol version in _meta. |
Send headers that match the request body. |
400 Bad Token |
The token is not a valid token. | Request a new token. |
401 |
The token is missing, or it is not bound to this endpoint. The WWW-Authenticate header points to discovery. |
Request a token with resource set. |
403 Origin not allowed |
The request carries an Origin header. The endpoint accepts no browser origins, so a client that runs in a web page cannot connect. Server-side clients send none. |
Send the request from server-side code. |
403 with a credential message |
The credential is not an acceptable agent. The message names the setting to change. See Credential Refusals. | Correct the role or the credential. |
404 Method not found |
The method is not supported. The server supports the connection handshake, ping, tools/list, and tools/call. It also answers resources/list and resources/templates/list with an empty list. |
Call a supported method. |
404 Unknown tool |
The tool does not exist, or the credential cannot call it. The two cases look the same by design. The message lists the tools that the credential can call. | Check the module's User Permissions page and confirm the tool is on. |
404 No MCP server is published at this address |
No module in the environment is published as a tool, or the applications that publish tools have no released version. | Publish a tool, or release the application's version. |
405 |
The agent used a method other than POST. The response carries Allow: POST. |
Use POST. |
429 |
The credential used its requests for the minute. | Wait the seconds that the message states. |
440 |
The token expired. | Request a new token. |
500 |
The server hit an issue while handling the request. The response hides the detail on purpose. | Retry. If the issue continues, contact Unqork Support. |
Credential Refusals
A 403 response from the endpoint names the first rule that the credential fails. Each message includes the setting to change.
| Cause | What to Do |
|---|---|
| The token belongs to a Creator account, or the authorization service treats the credential as a Creator. | Create an Express API credential in API Access Management. |
| The token resolves to an internal Unqork identity with unrestricted access. | Use an Express API credential. |
| The role has Designer Access or Full Submission Access enabled. | Turn both off in Express Role Administration, or use another role. |
| The token comes from a person's sign-in instead of the client credentials grant. | Request the token with the client credentials grant. |
| The credential maps applications to other Express roles. | Use a credential with a single Express role and no application role mapping. |
| The credential has no Express role. | Give the credential a role in API Access Management. |
| The credential has only the Anonymous role. | Give the credential a role other than Anonymous. |
| A role has a Default Permission other than No Access. The message names the role. | Change the Default Permission in Express Role Administration, or use a role that has No Access. |
| The server could not confirm that the credential is not a Creator. | Try the request again. |
Tool Results
A tool result has isError: true when the module ran or was blocked. The message in the result tells the agent what to do next.
| Message | Cause | What to Do |
|---|---|---|
| The module rejected these values | The module's own validation failed on the tool's inputs. The result lists each field and the rule it broke in structuredContent.details. |
Correct the listed values and call again. |
| The module rejected the call on fields this tool doesn't expose | Validation failed only on fields that the tool leaves out. | A Creator must add the field to the tool or change the module. |
| The module failed to complete | The module's logic reported an issue. The message omits internal detail. | Check the module's logs in Service Logs. |
| The module could not be executed | The module returned an HTTP error status, or its execution failed. The message includes the status when one is available. | Check the module's logs in Service Logs. |
| This credential is not permitted to run this tool | The module's access check refused the credential. | Check the role's permission on the module's User Permissions page. |
Tool {name}: Rate limit exceeded |
The tool's own call limit was reached. The message states the limit and how long to wait. | Wait, then call again. |
| Too many calls are already in progress for this credential | The credential, or the tool's own limit, already has its maximum number of calls running simultaneously. | Wait for one call to finish, then retry. |
Validation
Every MCP call runs the module with validation on, and validation cannot be switched off. The rules are each component's own settings, like Required, a minimum or maximum length, or a pattern. They run after the module's logic, on the values it leaves. An empty value, a value of only spaces, or null counts as missing.
The engine does not validate a field that uses the Hidden component or is hidden on the form. For those fields, only the tool's own checks hold: the field's type and whether the tool marks it required. A minimum length or a pattern on such a field is not enforced. Use a visible component for a rule that must be enforced, or check the value in the module's logic.
When the module's own rules fail, the agent receives a tool result that names the field and the rule it broke. For example, an empty lastName field that is required returns "The module rejected these values: data.lastName Last Name is required. Correct them and try again."
Logging and Audit
Service Logs hold an entry for each tool call and each request for the tool list that passes the request limit. The audit trail records every tool call except one that the request limit stops. Neither location stores the tool's argument values or results, except for the module's own Remote Execute entry.
| Entry | When Recorded | Contents |
|---|---|---|
| MCP Tool Call | Every tool call that passes the request limit, including calls rejected before the module ran. | The tool, module, application, and version. The outcome, which is success, validation-error, execution-error, refused, or limited. The names of the arguments sent and their count, or only the count when the call was rejected before a tool was found. The duration of the request. |
| MCP Tool List | Every time an agent lists its tools. | The outcome and the count of tools listed. |
| Remote Execute | Each call that ran its module. | The module's run, as for a direct API execute. It is nested under the MCP Tool Call entry. |
Each response carries the entry's identifier in the x-service-log-id header. Keep it in the agent's own logs to find a call later. Entries follow the usual workspace filter for logs. Entries with no module, like tool lists and calls rejected before a tool resolved, are visible only to people with environment-wide access. Retention is the same as for all Service Logs.
The Remote Execute entry holds request and response bodies as the environment's Server Side Execution Request/Response Body Log setting directs. The setting captures no bodies, the bodies of failed calls only (the default), or all bodies. It also follows the module's Capture Only Certain Fields in SSE Logs setting. See Module Settings for the setting. Agents often get a call wrong and retry, so expect more of these entries than a hand-written API client produces.
If a tool takes sensitive values, review the Server Side Execution Request/Response Body Log setting and the module's Capture Only Certain Fields in SSE Logs setting. Confirm that what is stored meets your organization's data-handling requirements.
In the audit trail, each tool call is recorded as an execute-module-as-agent event, including rejected calls, but not a call that the request limit stops. The event holds the credential, tool, module, and outcome, and never argument values or results. Publishing, changing, or switching off a tool writes the module's normal settings-save audit event.
Changelog
| Date | Change |
|---|---|
| 2026-11-06 | Added a See Also link to MCP in Unqork. |
| 2026-11-05 | Initial draft for 9.2. The steps to publish a tool and connect an agent are in Publish API Modules as MCP Tools. |
| 2026-11-05 | Reorganized the article, added the call walkthrough, protocol details, and every response the server returns, and checked the article against the server code. |