Key points
- The team list is a tree with
childrenpopulated, so one call gives the whole hierarchy. - Moving a team changes its path, and the path is what scopes, grants, and notifications refer to.
- Moving an application is expressed by the team in the URL, not a field in the body.
- An application is a team whose kind is
application: it owns a repository rather than other teams. - Team defaults decide what a pipeline resolves to when it names no model or agent role; they never override one that does.
defaultis a literal path segment on the models and agent-roles routes, so a profile cannot be nameddefault.- The collection PUT on models replaces the set — anything omitted is removed. The single-profile PUT does not.
- Teams choose which events they hear about; the platform decides how they are delivered.
Operations
GET/v1/teamsAuthorized
Lists the team tree.
Notes
Returns a tree rather than a flat list, so a client walks children instead of joining on parent_id.
Call it
curl -s -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/teams" | jqResponses
The team tree the caller may see.
[
{
"id": 12,
"name": "platform",
"kind": "team",
"parent_id": null,
"children": [
{ "id": 18, "name": "payments", "kind": "team", "parent_id": 12, "children": [] }
]
}
]Side effects
- None.
Proven by
services/nopsai/team_handlers_test.goservices/nopsai/team_handlers.gopkg/models/types.go
POST/v1/teamsAuthorized
Creates a team.
Notes
The team path is built from the hierarchy, so a team’s position is part of its identity for scopes, grants, and notifications.
Call it
curl -sX POST "$NOPSAI_URL/v1/teams" \
-H "Authorization: Bearer $NOPSAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"payments","parent_id":12}' | jqResponses
Team created.
{
"id": 18,
"name": "payments",
"kind": "team",
"parent_id": 12,
"children": []
}When it fails
| Status | Cause | What to do |
|---|---|---|
| 400 | A missing name, an unusable name, or a parent that does not exist. | The message names the field. |
Side effects
- Creates an ownership boundary other resources can be assigned to.
- Writes an audit record.
Proven by
services/nopsai/team_handlers_test.goservices/nopsai/team_handlers.go
GET/v1/teams/{teamID}Authorized
Reads one team.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
Call it
curl -s -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/teams/$TEAM_ID" | jqResponses
The team.
{
"id": 18,
"name": "payments",
"kind": "team",
"parent_id": 12,
"children": []
}When it fails
| Status | Cause | What to do |
|---|---|---|
| 500 | The team could not be loaded. | Platform fault. |
Side effects
- None.
Proven by
services/nopsai/team_handlers_test.goservices/nopsai/team_handlers.go
PUT/v1/teams/{teamID}Authorized
Renames or moves a team.
Notes
Moving a team is not a cosmetic rename: the path is the identity other resources refer to.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team to update. |
Call it
curl -sX PUT "$NOPSAI_URL/v1/teams/$TEAM_ID" \
-H "Authorization: Bearer $NOPSAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"payments","parent_id":null}' | jqResponses
Team updated.
{
"id": 18,
"name": "payments",
"kind": "team",
"parent_id": null,
"children": []
}When it fails
| Status | Cause | What to do |
|---|---|---|
| 400 | A name collision, or a move that would make the tree cyclic. | A team cannot become its own descendant. |
Side effects
- Moving a team changes its path, and with it every scope, grant, and notification that referenced the old path.
- Writes an audit record.
Proven by
services/nopsai/team_handlers_test.goservices/nopsai/team_handlers.go
DELETE/v1/teams/{teamID}Authorized
Deletes a team.
Notes
Check what the team owns first — pipelines, scopes, dashboards, and grants all hang off its path.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team to delete. |
Call it
curl -sX DELETE -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/teams/$TEAM_ID" -w "%{http_code}\n"Responses
Team deleted.
When it fails
| Status | Cause | What to do |
|---|---|---|
| 500 | The delete failed. | Retry. |
Side effects
- Resources that referenced the team path stop resolving their owner.
- Writes an audit record.
Proven by
services/nopsai/team_handlers_test.goservices/nopsai/team_handlers.go
GET/v1/teams/{teamID}/applicationsAuthorized
Lists applications under a team.
Notes
An application is a team whose kind is application: it owns a repository rather than other teams.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
Call it
curl -s -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/teams/$TEAM_ID/applications" | jqResponses
Applications under the team.
[{
"id": 31,
"name": "payments-api",
"kind": "application",
"parent_id": 18,
"repository_full_name": "acme/payments",
"repo_url": "https://git.example.com/acme/payments"
}]Side effects
- None.
Proven by
services/nopsai/team_handlers_test.goservices/nopsai/team_handlers.go
POST/v1/teams/{teamID}/applicationsAuthorized
Creates an application under a team.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Parent team. |
Call it
curl -sX POST "$NOPSAI_URL/v1/teams/$TEAM_ID/applications" \
-H "Authorization: Bearer $NOPSAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"payments-api","repository_full_name":"acme/payments"}' | jqResponses
Application created.
{
"id": 31,
"name": "payments-api",
"kind": "application",
"parent_id": 18,
"repository_full_name": "acme/payments",
"repo_url": "https://git.example.com/acme/payments"
}When it fails
| Status | Cause | What to do |
|---|---|---|
| 400 | A missing name or an unusable repository reference. | The message names the field. |
| 500 | The application could not be created. | Retry. |
Side effects
- Runs triggered from the repository resolve their owner to this application.
- Writes an audit record.
Proven by
services/nopsai/team_handlers_test.goservices/nopsai/team_handlers.go
PUT/v1/teams/{teamID}/applications/{applicationID}Authorized
Updates or moves an application.
Notes
The target parent is the team in the URL. Sending a parent in the body does not move anything.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Target parent team — moving an application means calling this under the new parent. |
applicationID | path | integer | Required | Application identifier. |
Call it
curl -sX PUT "$NOPSAI_URL/v1/teams/$NEW_TEAM_ID/applications/$APPLICATION_ID" \
-H "Authorization: Bearer $NOPSAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"payments-api"}' | jqResponses
Application updated.
{
"id": 31,
"name": "payments-api",
"kind": "application",
"parent_id": 18,
"repository_full_name": "acme/payments",
"repo_url": "https://git.example.com/acme/payments"
}When it fails
| Status | Cause | What to do |
|---|---|---|
| 400 | An unusable name or repository reference. | The message names the field. |
| 500 | The update failed. | Retry. |
Side effects
- Changes which team owns runs from the repository.
- Writes an audit record.
Proven by
services/nopsai/team_handlers_test.goservices/nopsai/team_handlers.go
DELETE/v1/teams/{teamID}/applications/{applicationID}Authorized
Deletes an application.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Parent team. |
applicationID | path | integer | Required | Application to delete. |
Call it
curl -sX DELETE -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/teams/$TEAM_ID/applications/$APPLICATION_ID" -w "%{http_code}\n"Responses
Application deleted.
When it fails
| Status | Cause | What to do |
|---|---|---|
| 500 | The delete failed. | Retry. |
Side effects
- Repository events lose their owner resolution until another application claims the repository.
- Writes an audit record.
Proven by
services/nopsai/team_handlers_test.goservices/nopsai/team_handlers.go
GET/v1/teams/{teamID}/defaultsAuthorized
Reads a team’s default AI resources.
Notes
Defaults are what a pipeline resolves to when it names no model or agent role. They do not override a pipeline that names one.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
Call it
curl -s -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/teams/$TEAM_ID/defaults" | jqResponses
Team defaults.
{
"default_model": "reasoning-large",
"default_agent_role": "senior-release-engineer"
}When it fails
| Status | Cause | What to do |
|---|---|---|
| 405 | A method other than GET or PUT. | Use GET to read, PUT to set. |
| 500 | Defaults could not be loaded. | Platform fault. |
Side effects
- None.
Proven by
services/nopsai/team_profile_resolution_test.goservices/nopsai/team_handlers.go
PUT/v1/teams/{teamID}/defaultsAuthorized
Sets a team’s default AI resources.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
Call it
curl -sX PUT "$NOPSAI_URL/v1/teams/$TEAM_ID/defaults" \
-H "Authorization: Bearer $NOPSAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"default_model":"reasoning-large"}' | jqResponses
Defaults stored.
{
"default_model": "reasoning-large"
}When it fails
| Status | Cause | What to do |
|---|---|---|
| 400 | A profile that does not exist or is not allowed for the team. | List the team’s models first. |
| 500 | The defaults could not be stored. | Retry. |
Side effects
- Changes what pipelines in this team resolve to when they name nothing.
- Writes an audit record.
Proven by
services/nopsai/team_profile_resolution_test.goservices/nopsai/team_handlers.go
GET/v1/teams/{teamID}/notificationsAuthorized
Reads a team’s notification settings.
Notes
Teams choose what they hear about; the platform decides how it is delivered. The two are configured in different places on purpose.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
Call it
curl -s -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/teams/$TEAM_ID/notifications" | jqResponses
Notification settings for the team.
{
"recipients": ["[email protected]"],
"events": ["run.failure", "approval.requested"]
}When it fails
| Status | Cause | What to do |
|---|---|---|
| 405 | A method other than GET, PUT, or DELETE. | Those three are supported. |
Side effects
- None.
Proven by
services/nopsai/team_handlers_test.goservices/nopsai/team_handlers.go
PUT/v1/teams/{teamID}/notificationsAuthorized
Sets a team’s notification settings.
Notes
Test platform mail settings before trusting a subscription: a valid subscription with broken delivery looks identical to no subscription.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
Call it
curl -sX PUT "$NOPSAI_URL/v1/teams/$TEAM_ID/notifications" \
-H "Authorization: Bearer $NOPSAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"recipients":["[email protected]"],"events":["run.failure"]}' | jqResponses
Settings stored.
{
"recipients": ["[email protected]"],
"events": ["run.failure"]
}When it fails
| Status | Cause | What to do |
|---|---|---|
| 400 | An unusable recipient or unknown event. | The message names the value. |
| 405 | An unsupported method. | Use GET, PUT, or DELETE. |
Side effects
- Changes who is emailed about this team’s runs.
- Writes an audit record.
Proven by
services/nopsai/team_handlers_test.goservices/nopsai/team_handlers.go
DELETE/v1/teams/{teamID}/notificationsAuthorized
Clears a team’s notification settings.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
Call it
curl -sX DELETE -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/teams/$TEAM_ID/notifications" -w "%{http_code}\n"Responses
Settings cleared.
When it fails
| Status | Cause | What to do |
|---|---|---|
| 405 | An unsupported method. | Use GET, PUT, or DELETE. |
Side effects
- The team stops receiving notifications.
- Writes an audit record.
Proven by
services/nopsai/team_handlers_test.goservices/nopsai/team_handlers.go
GET/v1/teams/{teamID}/modelsAuthorized
Lists a team’s model profiles.
Notes
The list includes cached team-owned profiles and what the team inherits, which is why a profile can appear here without being defined here.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
Call it
curl -s -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/teams/$TEAM_ID/models" | jqResponses
Model profiles available to the team.
[
{
"name": "reasoning-large",
"provider": "anthropic",
"enabled": true,
"is_default": true
}
]When it fails
| Status | Cause | What to do |
|---|---|---|
| 500 | The query failed. | Platform fault. |
Side effects
- None.
Proven by
services/nopsai/team_profile_handlers_test.goservices/nopsai/team_profile_handlers.go
PUT/v1/teams/{teamID}/modelsAuthorized
Replaces a team’s model profile set.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
Call it
curl -sX PUT "$NOPSAI_URL/v1/teams/$TEAM_ID/models" \
-H "Authorization: Bearer $NOPSAI_TOKEN" \
-H "Content-Type: application/json" \
--data @models.json | jqResponses
Profiles stored.
[
{ "name": "reasoning-large", "provider": "anthropic", "enabled": true }
]When it fails
| Status | Cause | What to do |
|---|---|---|
| 400 | An invalid profile or a credential reference that does not resolve. | The message names the profile. |
| 500 | The profiles could not be stored. | Retry. |
Side effects
- Pipelines naming a removed profile fail authorization on their next run.
- Writes an audit record.
Proven by
services/nopsai/team_profile_handlers_test.goservices/nopsai/team_profile_handlers.go
PUT/v1/teams/{teamID}/models/defaultAuthorized
Sets the team’s default model profile.
Notes
The path segment is the literal word default, which is why a profile may not be named default.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
Call it
curl -sX PUT "$NOPSAI_URL/v1/teams/$TEAM_ID/models/default" \
-H "Authorization: Bearer $NOPSAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"reasoning-large"}' | jqResponses
Default set.
{ "name": "reasoning-large", "is_default": true }When it fails
| Status | Cause | What to do |
|---|---|---|
| 400 | The profile does not exist or is disabled. | List the team’s models first. |
| 500 | The default could not be stored. | Retry. |
Side effects
- Changes what unnamed model references resolve to.
- Writes an audit record.
Proven by
services/nopsai/team_profile_resolution_test.goservices/nopsai/team_profile_handlers.go
PUT/v1/teams/{teamID}/models/{profileName}Authorized
Creates or replaces one team model profile.
Notes
Use this rather than the collection PUT when changing one profile: the collection form removes anything it omits.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
profileName | path | string | Required | Profile name. |
Call it
curl -sX PUT "$NOPSAI_URL/v1/teams/$TEAM_ID/models/reasoning-large" \
-H "Authorization: Bearer $NOPSAI_TOKEN" \
-H "Content-Type: application/json" \
--data @profile.json | jqResponses
Profile stored.
{ "name": "reasoning-large", "provider": "anthropic", "enabled": true }When it fails
| Status | Cause | What to do |
|---|---|---|
| 400 | An invalid profile or unresolvable credential. | The message names the field. |
| 500 | The profile could not be stored. | Retry. |
Side effects
- Writes an audit record.
Proven by
services/nopsai/team_profile_handlers_test.goservices/nopsai/team_profile_handlers.go
DELETE/v1/teams/{teamID}/models/{profileName}Authorized
Deletes a team model profile.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
profileName | path | string | Required | Profile to delete. |
Call it
curl -sX DELETE -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/teams/$TEAM_ID/models/reasoning-large" -w "%{http_code}\n"Responses
Profile deleted.
When it fails
| Status | Cause | What to do |
|---|---|---|
| 500 | The delete failed. | Retry. |
Side effects
- Pipelines referencing the profile stop resolving it.
- Writes an audit record.
Proven by
services/nopsai/team_profile_handlers_test.goservices/nopsai/team_profile_handlers.go
GET/v1/teams/{teamID}/agent-rolesAuthorized
Lists a team’s agent roles.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
Call it
curl -s -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/teams/$TEAM_ID/agent-roles" | jqResponses
Agent roles available to the team.
[
{ "id": "senior-release-engineer", "name": "Senior release engineer", "enabled": true }
]When it fails
| Status | Cause | What to do |
|---|---|---|
| 500 | The query failed. | Platform fault. |
Side effects
- None.
Proven by
services/nopsai/team_profile_handlers_test.goservices/nopsai/team_profile_handlers.go
POST/v1/teams/{teamID}/agent-rolesAuthorized
Creates a team agent role.
Notes
A task cannot set agent_role; it comes from the pipeline or the step. Creating one here makes it nameable at those two levels.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
Call it
curl -sX POST "$NOPSAI_URL/v1/teams/$TEAM_ID/agent-roles" \
-H "Authorization: Bearer $NOPSAI_TOKEN" \
-H "Content-Type: application/json" \
--data @role.json | jq -r .idResponses
Agent role created.
{ "id": "senior-release-engineer", "name": "Senior release engineer", "enabled": true }When it fails
| Status | Cause | What to do |
|---|---|---|
| 400 | A missing name or instructions. | The message names the field. |
| 500 | The role could not be created. | Retry. |
Side effects
- Writes an audit record.
Proven by
services/nopsai/team_profile_handlers_test.goservices/nopsai/team_profile_handlers.go
GET/v1/teams/{teamID}/agent-roles/{profileID}Authorized
Reads one team agent role.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
profileID | path | string | Required | Agent role identifier. |
Call it
curl -s -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/teams/$TEAM_ID/agent-roles/senior-release-engineer" | jqResponses
The agent role.
{ "id": "senior-release-engineer", "name": "Senior release engineer", "enabled": true }When it fails
| Status | Cause | What to do |
|---|---|---|
| 500 | The role could not be loaded. | Platform fault. |
Side effects
- None.
Proven by
services/nopsai/team_profile_handlers_test.goservices/nopsai/team_profile_handlers.go
PUT/v1/teams/{teamID}/agent-roles/{profileID}Authorized
Replaces a team agent role.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
profileID | path | string | Required | Agent role identifier. |
Call it
curl -sX PUT "$NOPSAI_URL/v1/teams/$TEAM_ID/agent-roles/senior-release-engineer" \
-H "Authorization: Bearer $NOPSAI_TOKEN" \
-H "Content-Type: application/json" \
--data @role.json | jqResponses
Role stored.
{ "id": "senior-release-engineer", "name": "Senior release engineer", "enabled": true }When it fails
| Status | Cause | What to do |
|---|---|---|
| 400 | Invalid instructions or a disabled state that conflicts with the team default. | The message names the field. |
| 500 | The update failed. | Retry. |
Side effects
- Changes the prompt for every future step naming this role.
- Writes an audit record.
Proven by
services/nopsai/team_profile_handlers_test.goservices/nopsai/team_profile_handlers.go
PUT/v1/teams/{teamID}/agent-roles/defaultAuthorized
Sets the team’s default agent role.
Notes
As with models, default is a literal path segment rather than a role id.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
Call it
curl -sX PUT "$NOPSAI_URL/v1/teams/$TEAM_ID/agent-roles/default" \
-H "Authorization: Bearer $NOPSAI_TOKEN" \
-H "Content-Type: application/json" \
-d '{"id":"senior-release-engineer"}' | jqResponses
Default set.
{ "id": "senior-release-engineer", "is_default": true }When it fails
| Status | Cause | What to do |
|---|---|---|
| 400 | The role does not exist or is disabled. | List the team’s agent roles first. |
| 500 | The default could not be stored. | Retry. |
Side effects
- Changes what unnamed agent role references resolve to.
- Writes an audit record.
Proven by
services/nopsai/team_profile_resolution_test.goservices/nopsai/team_profile_handlers.go
DELETE/v1/teams/{teamID}/agent-roles/{profileID}Authorized
Deletes a team agent role.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
profileID | path | string | Required | Agent role to delete. |
Call it
curl -sX DELETE -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/teams/$TEAM_ID/agent-roles/senior-release-engineer" -w "%{http_code}\n"Responses
Role deleted.
When it fails
| Status | Cause | What to do |
|---|---|---|
| 500 | The delete failed. | Retry. |
Side effects
- Pipelines referencing the role stop resolving it.
- Writes an audit record.
Proven by
services/nopsai/team_profile_handlers_test.goservices/nopsai/team_profile_handlers.go
GET/v1/teams/{teamID}/mcp-profilesAuthorized
Lists a team’s MCP profiles.
Notes
A profile names servers and the tools allowed from them. Pipeline YAML cannot declare a server URL directly, which is why this list is the boundary.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
Call it
curl -s -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/teams/$TEAM_ID/mcp-profiles" | jqResponses
MCP profiles available to the team.
[{
"name": "jira-readonly",
"enabled": true,
"allowed_scopes": ["platform/production"],
"servers": [{ "server": "jira", "tools": ["search"] }]
}]When it fails
| Status | Cause | What to do |
|---|---|---|
| 500 | The query failed. | Platform fault. |
Side effects
- None.
Proven by
services/nopsai/team_profile_handlers_test.goservices/nopsai/team_profile_handlers.go
POST/v1/teams/{teamID}/mcp-profilesAuthorized
Creates a team MCP profile.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
Call it
curl -sX POST "$NOPSAI_URL/v1/teams/$TEAM_ID/mcp-profiles" \
-H "Authorization: Bearer $NOPSAI_TOKEN" \
-H "Content-Type: application/json" \
--data @profile.json | jqResponses
Profile created.
{
"name": "jira-readonly",
"enabled": true,
"allowed_scopes": ["platform/production"],
"servers": [{ "server": "jira", "tools": ["search"] }]
}When it fails
| Status | Cause | What to do |
|---|---|---|
| 400 | An unknown server, an empty tool list, or a scope the team may not use. | The message names the field. |
| 500 | The profile could not be created. | Retry. |
Side effects
- Widens what LLM steps in this team can reach.
- Writes an audit record.
Proven by
services/nopsai/team_profile_handlers_test.goservices/nopsai/team_profile_handlers.go
GET/v1/teams/{teamID}/mcp-profiles/{profileName}Authorized
Reads one team MCP profile.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
profileName | path | string | Required | Profile name. |
Call it
curl -s -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/teams/$TEAM_ID/mcp-profiles/jira-readonly" | jqResponses
The profile.
{
"name": "jira-readonly",
"enabled": true,
"allowed_scopes": ["platform/production"],
"servers": [{ "server": "jira", "tools": ["search"] }]
}When it fails
| Status | Cause | What to do |
|---|---|---|
| 500 | The profile could not be loaded. | Platform fault. |
Side effects
- None.
Proven by
services/nopsai/team_profile_handlers_test.goservices/nopsai/team_profile_handlers.go
PUT/v1/teams/{teamID}/mcp-profiles/{profileName}Authorized
Creates or replaces a team MCP profile.
Notes
Profiles are additive at run time: a step cannot narrow what the pipeline granted. Narrowing happens here.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
profileName | path | string | Required | Profile name. |
Call it
curl -sX PUT "$NOPSAI_URL/v1/teams/$TEAM_ID/mcp-profiles/jira-readonly" \
-H "Authorization: Bearer $NOPSAI_TOKEN" \
-H "Content-Type: application/json" \
--data @profile.json | jqResponses
Profile stored.
{
"name": "jira-readonly",
"enabled": true,
"allowed_scopes": ["platform/production"],
"servers": [{ "server": "jira", "tools": ["search"] }]
}When it fails
| Status | Cause | What to do |
|---|---|---|
| 400 | An invalid server or tool list. | The message names the field. |
| 500 | The profile could not be stored. | Retry. |
Side effects
- Changes what every pipeline naming this profile can reach.
- Writes an audit record.
Proven by
services/nopsai/team_profile_handlers_test.goservices/nopsai/team_profile_handlers.go
DELETE/v1/teams/{teamID}/mcp-profiles/{profileName}Authorized
Deletes a team MCP profile.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
teamID | path | integer | Required | Team identifier. |
profileName | path | string | Required | Profile to delete. |
Call it
curl -sX DELETE -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/teams/$TEAM_ID/mcp-profiles/jira-readonly" -w "%{http_code}\n"Responses
Profile deleted.
When it fails
| Status | Cause | What to do |
|---|---|---|
| 500 | The delete failed. | Retry. |
Side effects
- LLM steps naming the profile lose those tools.
- Writes an audit record.
Proven by
services/nopsai/team_profile_handlers_test.goservices/nopsai/team_profile_handlers.go
GET/v1/teams/{teamID}/mcp/profilesAuthorized
Compatibility path for listing team MCP profiles.
Notes
Same handler as /v1/teams/{teamID}/mcp-profiles; prefer the hyphenated form.
POST/v1/teams/{teamID}/mcp/profilesAuthorized
Compatibility path for creating a team MCP profile.
Notes
Same handler as the hyphenated form.
GET/v1/teams/{teamID}/mcp/profiles/{profileName}Authorized
Compatibility path for reading a team MCP profile.
Notes
Same handler as the hyphenated form.
PUT/v1/teams/{teamID}/mcp/profiles/{profileName}Authorized
Compatibility path for replacing a team MCP profile.
Notes
Same handler as the hyphenated form.
DELETE/v1/teams/{teamID}/mcp/profiles/{profileName}Authorized
Compatibility path for deleting a team MCP profile.
Notes
Same handler as the hyphenated form.
How it works
Everything in this area exists so a resource can answer "who owns this?". A team path is not a label — it is the key that access grants, scope resolution, notification routing, and GitOps ownership all join on. That is why moving a team is a bigger operation than renaming one.
The AI resources hang off teams rather than the platform so two teams can hold different models and tool sets without one being able to use the other’s. A profile listed for a team may be inherited rather than defined there, which is why the list can show more than the team owns.
The mcp/profiles paths are compatibility aliases for the hyphenated mcp-profiles routes and reach the same handlers. Prefer the hyphenated form in new integrations.
Implementation evidence
services/nopsai/team_handlers.goTeam, application, defaults, and notification handlers.
services/nopsai/team_profile_handlers.goTeam-owned model, agent role, and MCP profile handlers.
pkg/models/types.goTeam and application record shape.

