MCP profiles

Package: agentrouter.mcp.v1 Service: MCPProfilesService

Endpoints

Create an MCP profile

Changed in v0.11.0 (behaviour changes): Creating an MCP profile with a security type other than oauth, api_key or none returns invalid_argument, and so does an update that changes the type to such a value. Spellings such as OAuth and oauth2 were accepted before and served with no token check. An update that leaves the type unset, or sends the type the profile already has, is accepted, so a profile stored with another type can still be renamed.

Changed in v0.11.0 (behaviour changes): Creating an MCP profile of type oauth returns invalid_argument unless security_policy_value sets issuer and remote_jwks, an absolute http or https URL. An update returns the same error when it changes the type to oauth, the issuer or the key set URL and leaves either missing or invalid. An update that changes none of them is accepted, so a profile saved without them can still be renamed.

Changed in v0.10.0 (behaviour changes): MCP profile audit entries name the person who acted. When an API key makes the call, the key is in metadata.via_key; when an admin acts for another user, that user is in metadata.subject_user_id.

Changed in v0.8.0 (bug fixes): Deleting an MCP profile frees its name for a new or renamed profile.

Changed in v0.1.5 (bug fixes): An MCP profile created or changed through the MCPProfilesService API now becomes routable within seconds, the same as one changed from the dashboard. Where profiles are served on the shared URL rather than a per-project gateway hostname, the API path refreshed only part of the routing configuration, so a new profile's /mcp/ address returned 404 until the next periodic full sync (up to ~38 minutes) during which an app given that address silently had none of its tools. Every profile mutation on the API now fires the same per-user refresh the dashboard does.

What it does: Registers a new MCP server for a user.

Request fields:

FieldRequiredDescription
user_idnoDefaults to the caller's session user when empty.
nameyesRequired: human-friendly profile name.
descriptionnoOptional description.
security_policy_typeyesRequired: security policy type ("oauth""api_key""none").
security_policy_valuenoOptional: JSON-encoded security policy value. Empty for "none". Required for "oauth": it must set "issuer" and "remote_jwks", or the create is refused with INVALID_ARGUMENT.
customer_idnoDefaults to the caller's session customer when empty.
project_idnoDefaults to the caller's session project when empty.

Response fields:

FieldRequiredDescription
idoutput-onlyServer-assigned uuid row id. Output-only.
user_idnoOwning user id (authn.user.id). Defaults to the caller's session user when empty; immutable once set.
customer_idnoOwning customer scope. Defaults to the caller's session customer when empty; immutable once set. A profile is only visible to (user_id, customer_id, project_id) tuples that match.
project_idnoOwning project scope. Defaults to the caller's session project when empty; immutable once set.
nameyesHuman-friendly display name. Unique per user.
descriptionnoOptional freeform description.
urloutput-onlyURL PATH the data plane exposes for this profile, e.g. "/mcp/<user-hash>-<profile-hash>". NOT an absolute URL -- it carries no scheme or host. Server-assigned on create. Use endpoints below for the addresses a client actually connects to.
endpointsoutput-onlyAbsolute endpoints this profile answers on, resolved server-side from the project's Project Gateway attachment. Output-only. A profile is served by EVERY Project Gateway attached to its project, so this can hold more than one entry; a project with no attached gateway resolves to its data plane's shared URL, a single entry. An EMPTY list means no gateway URL is configured yet -- that is a valid answer to ask an operator about, not an error and not something to retry. Prefer this over joining url onto a host yourself. On a data plane that hosts Project Gateways, strict isolation (#4637 / #5005) stops the shared workspace URL from serving /mcp/* at all, so a hand-built join reaches a host that 404s -- and some hosts answer 200 with an empty body for unmatched /mcp/* paths, so the failure does not even look like one.
statusoutput-onlyLifecycle status: "active""pending""error".
error_messageoutput-onlyLast error from the reconciler when status is "error".
security_policy_typeyesSecurity policy type: "oauth""api_key""none". Any other value is refused with INVALID_ARGUMENT on create, and on an update that sets it.
security_policy_valuenoJSON-encoded security policy value. Shape depends on security_policy_type -- see schema docs on the mcp_profiles table. Sensitive material (raw api keys, oauth issuer secrets) is stored server-side; responses redact secret bytes. For "oauth" it must set "issuer" and "remote_jwks" (an absolute http or https URL of the issuer's key set); the API refuses to create an oauth profile without them with INVALID_ARGUMENT. The gateway serves one saved earlier without them with no token check while the data plane setting MCP_OAUTH_STRICT_PROFILES is off (the 0.11 default) and serves nothing while it is on (the default from 0.12).
serversoutput-onlyMCP servers (backends) attached to this profile, with the per-server enabled tool set. Output-only on the profile resource: servers are managed through the AddMCPProfileServer / RemoveMCPProfileServer / SetMCPProfileServerTools sub-resource RPCs, mirroring mcp_profile_backends.
created_atoutput-onlyRow creation time. Output-only.
updated_atoutput-onlyLast mutation time. Output-only.
{"signatures":{"go":"func (x *MCPProfilesClient) CreateMCPProfile(ctx context.Context, req *mcpv1.CreateMCPProfileRequest) (*mcpv1.MCPProfile, error)","python":"create_mcp_profile(req: mcp_pb2.CreateMCPProfileRequest) -\u003e MCPProfile","typescript":"createMCPProfile(req: MessageInitShape\u003ctypeof tars_mcp_v1_mcp_pb.CreateMCPProfileRequestSchema\u003e): Promise\u003cMCPProfile\u003e","cli":"tare api mcp profiles create --name $NAME --security-policy-type $SECURITY_POLICY_TYPE","curl":"curl -X POST \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../mcp-profiles\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"name\": \"...\",\n    \"description\": \"...\",\n    \"security_policy_type\": \"...\",\n    \"security_policy_value\": \"...\"\n  }'"},"examples":{"go":{"files":[{"name":"main.go","content":"// Command example is a runnable example for the AgentRouter Go SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then `go run .`.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tagentrouter \"github.com/tetrateio/agentrouter-go\"\n\tmcpv1 \"github.com/tetrateio/agentrouter-go/genapi/api/tars/mcp/v1\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\tclient, err := agentrouter.New(ctx,\n\t\tagentrouter.WithBaseURL(os.Getenv(\"AGENTROUTER_BASE_URL\")),\n\t\tagentrouter.WithAPIKey(os.Getenv(\"AGENTROUTER_API_KEY\")),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"client: %v\", err)\n\t}\n\n\t// Populate the request fields -- see the \"Request fields\" table above for\n\t// the available fields and which are required.\n\treq := \u0026mcpv1.CreateMCPProfileRequest{}\n\n\tresp, err := client.MCPProfiles().CreateMCPProfile(ctx, req)\n\tif err != nil {\n\t\tlog.Fatalf(\"call: %v\", err)\n\t}\n\n\tfmt.Printf(\"%+v\\n\", resp)\n}\n"},{"name":"go.mod","content":"module github.com/tetrateio/agentrouter-go-examples/mcpprofiles/createmcpprofile\n\ngo 1.26\n\nrequire github.com/tetrateio/agentrouter-go v0.1.1\n\n// Point this at the directory you extracted the downloaded Go SDK tarball into.\n// The directory name matches the tarball stem on the Download SDK page.\nreplace github.com/tetrateio/agentrouter-go =\u003e ./third_party/agentrouter-go-0.1.1\n"}]},"python":{"files":[{"name":"main.py","content":"\"\"\"Runnable example for the AgentRouter Python SDK.\n\nSet AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `python main.py`.\n\"\"\"\nimport os\n\nfrom tars.mcp.v1 import mcp_pb2\n\nfrom agentrouter_sdk import Client\n\nclient = Client(\n    base_url=os.environ[\"AGENTROUTER_BASE_URL\"],\n    api_key=os.environ[\"AGENTROUTER_API_KEY\"],\n)\n\n# Populate the request fields -- see the \"Request fields\" table above\n# for the available fields and which are required.\nreq = mcp_pb2.CreateMCPProfileRequest()\ntry:\n    result = client.mcp_profiles.create_mcp_profile(req)\n    print(result)\nexcept Exception as err:\n    print(\"Error:\", err)\n"},{"name":"requirements.txt","content":"# Point this at the directory you extracted the downloaded Python SDK tarball\n# into. The directory name matches the tarball stem on the Download SDK page.\n# To install instead from PyPI once published, replace the line below with:\n#   agentrouter-sdk\u003e=0.1.0\nagentrouter-sdk @ file:./third_party/agentrouter-python-0.1.1\n"}]},"typescript":{"files":[{"name":"index.ts","content":"// Runnable example for the AgentRouter TypeScript SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `npm install \u0026\u0026 npx tsx index.ts`.\nimport { Client } from '@tetrate/agentrouter-sdk'\n\nconst client = new Client({\n  baseUrl: process.env.AGENTROUTER_BASE_URL,\n  apiKey: process.env.AGENTROUTER_API_KEY,\n})\n\n// Populate the request fields -- see the \"Request fields\" table above\n// for the available fields and which are required.\nconst req = {}\ntry {\n  const result = await client.mcpProfiles.createMCPProfile(req)\n  console.log(result)\n} catch (err) {\n  console.error('Error:', err)\n}\n"},{"name":"package.json","content":"{\n  \"name\": \"mcpprofiles\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@tetrate/agentrouter-sdk\": \"file:./third_party/agentrouter-typescript-0.1.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^20.0.0\",\n    \"typescript\": \"^5.4.0\"\n  }\n}\n"},{"name":"tsconfig.json","content":"{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true\n  }\n}\n"}]},"cli":"tare api mcp profiles create --name $NAME --security-policy-type $SECURITY_POLICY_TYPE","curl":"curl -X POST \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../mcp-profiles\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"name\": \"...\",\n    \"description\": \"...\",\n    \"security_policy_type\": \"...\",\n    \"security_policy_value\": \"...\"\n  }'"},"persona":"Authenticated (API key or session token)","httpVerb":"POST","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/users/{user_id}/mcp-profiles","slug":"create-an-mcp-profile"}

Get an MCP profile

Changed in v0.10.0 (new features): MCP profile reads can span every project you belong to (all_projects, CLI --all-projects) and can include each attached server's name, icon and tools (include_tools).

What it does: Returns a single profile by uuid.

Request fields:

FieldRequiredDescription
user_idnoDefaults to the caller's session user when empty.
profile_idyesRequired: uuid of the profile to fetch (MCPProfile.id).
customer_idnoDefaults to the caller's session customer when empty.
project_idnoDefaults to the caller's session project when empty.
all_projectsnoWhen true, the profile may be in any project of the customer where the caller is a member: project_id must be empty. Needs a signed-in session acting for itself.
include_toolsnoWhen true, each attached server carries the tools of its catalog entry.

Response fields:

FieldRequiredDescription
idoutput-onlyServer-assigned uuid row id. Output-only.
user_idnoOwning user id (authn.user.id). Defaults to the caller's session user when empty; immutable once set.
customer_idnoOwning customer scope. Defaults to the caller's session customer when empty; immutable once set. A profile is only visible to (user_id, customer_id, project_id) tuples that match.
project_idnoOwning project scope. Defaults to the caller's session project when empty; immutable once set.
nameyesHuman-friendly display name. Unique per user.
descriptionnoOptional freeform description.
urloutput-onlyURL PATH the data plane exposes for this profile, e.g. "/mcp/<user-hash>-<profile-hash>". NOT an absolute URL -- it carries no scheme or host. Server-assigned on create. Use endpoints below for the addresses a client actually connects to.
endpointsoutput-onlyAbsolute endpoints this profile answers on, resolved server-side from the project's Project Gateway attachment. Output-only. A profile is served by EVERY Project Gateway attached to its project, so this can hold more than one entry; a project with no attached gateway resolves to its data plane's shared URL, a single entry. An EMPTY list means no gateway URL is configured yet -- that is a valid answer to ask an operator about, not an error and not something to retry. Prefer this over joining url onto a host yourself. On a data plane that hosts Project Gateways, strict isolation (#4637 / #5005) stops the shared workspace URL from serving /mcp/* at all, so a hand-built join reaches a host that 404s -- and some hosts answer 200 with an empty body for unmatched /mcp/* paths, so the failure does not even look like one.
statusoutput-onlyLifecycle status: "active""pending""error".
error_messageoutput-onlyLast error from the reconciler when status is "error".
security_policy_typeyesSecurity policy type: "oauth""api_key""none". Any other value is refused with INVALID_ARGUMENT on create, and on an update that sets it.
security_policy_valuenoJSON-encoded security policy value. Shape depends on security_policy_type -- see schema docs on the mcp_profiles table. Sensitive material (raw api keys, oauth issuer secrets) is stored server-side; responses redact secret bytes. For "oauth" it must set "issuer" and "remote_jwks" (an absolute http or https URL of the issuer's key set); the API refuses to create an oauth profile without them with INVALID_ARGUMENT. The gateway serves one saved earlier without them with no token check while the data plane setting MCP_OAUTH_STRICT_PROFILES is off (the 0.11 default) and serves nothing while it is on (the default from 0.12).
serversoutput-onlyMCP servers (backends) attached to this profile, with the per-server enabled tool set. Output-only on the profile resource: servers are managed through the AddMCPProfileServer / RemoveMCPProfileServer / SetMCPProfileServerTools sub-resource RPCs, mirroring mcp_profile_backends.
created_atoutput-onlyRow creation time. Output-only.
updated_atoutput-onlyLast mutation time. Output-only.
{"signatures":{"go":"func (x *MCPProfilesClient) GetMCPProfile(ctx context.Context, req *mcpv1.GetMCPProfileRequest) (*mcpv1.MCPProfile, error)","python":"get_mcp_profile(req: mcp_pb2.GetMCPProfileRequest) -\u003e MCPProfile","typescript":"getMCPProfile(req: MessageInitShape\u003ctypeof tars_mcp_v1_mcp_pb.GetMCPProfileRequestSchema\u003e): Promise\u003cMCPProfile\u003e","cli":"tare api mcp profiles get --profile-id $PROFILE_ID","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../mcp-profiles/01H...\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\""},"examples":{"go":{"files":[{"name":"main.go","content":"// Command example is a runnable example for the AgentRouter Go SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then `go run .`.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tagentrouter \"github.com/tetrateio/agentrouter-go\"\n\tmcpv1 \"github.com/tetrateio/agentrouter-go/genapi/api/tars/mcp/v1\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\tclient, err := agentrouter.New(ctx,\n\t\tagentrouter.WithBaseURL(os.Getenv(\"AGENTROUTER_BASE_URL\")),\n\t\tagentrouter.WithAPIKey(os.Getenv(\"AGENTROUTER_API_KEY\")),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"client: %v\", err)\n\t}\n\n\t// Populate the request fields -- see the \"Request fields\" table above for\n\t// the available fields and which are required.\n\treq := \u0026mcpv1.GetMCPProfileRequest{}\n\n\tresp, err := client.MCPProfiles().GetMCPProfile(ctx, req)\n\tif err != nil {\n\t\tlog.Fatalf(\"call: %v\", err)\n\t}\n\n\tfmt.Printf(\"%+v\\n\", resp)\n}\n"},{"name":"go.mod","content":"module github.com/tetrateio/agentrouter-go-examples/mcpprofiles/getmcpprofile\n\ngo 1.26\n\nrequire github.com/tetrateio/agentrouter-go v0.1.1\n\n// Point this at the directory you extracted the downloaded Go SDK tarball into.\n// The directory name matches the tarball stem on the Download SDK page.\nreplace github.com/tetrateio/agentrouter-go =\u003e ./third_party/agentrouter-go-0.1.1\n"}]},"python":{"files":[{"name":"main.py","content":"\"\"\"Runnable example for the AgentRouter Python SDK.\n\nSet AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `python main.py`.\n\"\"\"\nimport os\n\nfrom tars.mcp.v1 import mcp_pb2\n\nfrom agentrouter_sdk import Client\n\nclient = Client(\n    base_url=os.environ[\"AGENTROUTER_BASE_URL\"],\n    api_key=os.environ[\"AGENTROUTER_API_KEY\"],\n)\n\n# Populate the request fields -- see the \"Request fields\" table above\n# for the available fields and which are required.\nreq = mcp_pb2.GetMCPProfileRequest()\ntry:\n    result = client.mcp_profiles.get_mcp_profile(req)\n    print(result)\nexcept Exception as err:\n    print(\"Error:\", err)\n"},{"name":"requirements.txt","content":"# Point this at the directory you extracted the downloaded Python SDK tarball\n# into. The directory name matches the tarball stem on the Download SDK page.\n# To install instead from PyPI once published, replace the line below with:\n#   agentrouter-sdk\u003e=0.1.0\nagentrouter-sdk @ file:./third_party/agentrouter-python-0.1.1\n"}]},"typescript":{"files":[{"name":"index.ts","content":"// Runnable example for the AgentRouter TypeScript SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `npm install \u0026\u0026 npx tsx index.ts`.\nimport { Client } from '@tetrate/agentrouter-sdk'\n\nconst client = new Client({\n  baseUrl: process.env.AGENTROUTER_BASE_URL,\n  apiKey: process.env.AGENTROUTER_API_KEY,\n})\n\n// Populate the request fields -- see the \"Request fields\" table above\n// for the available fields and which are required.\nconst req = {}\ntry {\n  const result = await client.mcpProfiles.getMCPProfile(req)\n  console.log(result)\n} catch (err) {\n  console.error('Error:', err)\n}\n"},{"name":"package.json","content":"{\n  \"name\": \"mcpprofiles\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@tetrate/agentrouter-sdk\": \"file:./third_party/agentrouter-typescript-0.1.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^20.0.0\",\n    \"typescript\": \"^5.4.0\"\n  }\n}\n"},{"name":"tsconfig.json","content":"{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true\n  }\n}\n"}]},"cli":"tare api mcp profiles get --profile-id $PROFILE_ID","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../mcp-profiles/01H...\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\""},"persona":"Authenticated (API key or session token)","httpVerb":"GET","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/users/{user_id}/mcp-profiles/{profile_id}","slug":"get-an-mcp-profile"}

List MCP profiles

Changed in v0.10.0 (new features): MCP profile reads can span every project you belong to (all_projects, CLI --all-projects) and can include each attached server's name, icon and tools (include_tools).

What it does: Lists every profile owned by the given (user_id, customer_id, project_id) scope.

Request fields:

FieldRequiredDescription
user_idnoDefaults to the caller's session user when empty.
pagenoCursor-pagination inputs (page size + continuation token).
customer_idnoDefaults to the caller's session customer when empty.
project_idnoDefaults to the caller's session project when empty.
all_projectsnoWhen true, list the caller's profiles in every project of the customer where the caller is a member: project_id must be empty, and user_id empty or the caller. Needs a signed-in session acting for itself.
include_toolsnoWhen true, each attached server carries the tools of its catalog entry.

Response fields:

FieldRequiredDescription
profilesnoProfiles owned by the requested scope, one page's worth.
pagenoCursor-pagination outputs (next-page token).
{"signatures":{"go":"func (x *MCPProfilesClient) ListMCPProfiles(ctx context.Context, req *mcpv1.ListMCPProfilesRequest) (*mcpv1.ListMCPProfilesResponse, error)","python":"list_mcp_profiles(req: mcp_pb2.ListMCPProfilesRequest) -\u003e ListMCPProfilesResponse","typescript":"listMCPProfiles(req: MessageInitShape\u003ctypeof tars_mcp_v1_mcp_pb.ListMCPProfilesRequestSchema\u003e): Promise\u003cListMCPProfilesResponse\u003e","cli":"tare api mcp profiles list","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../mcp-profiles\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\""},"examples":{"go":{"files":[{"name":"main.go","content":"// Command example is a runnable example for the AgentRouter Go SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then `go run .`.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tagentrouter \"github.com/tetrateio/agentrouter-go\"\n\tmcpv1 \"github.com/tetrateio/agentrouter-go/genapi/api/tars/mcp/v1\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\tclient, err := agentrouter.New(ctx,\n\t\tagentrouter.WithBaseURL(os.Getenv(\"AGENTROUTER_BASE_URL\")),\n\t\tagentrouter.WithAPIKey(os.Getenv(\"AGENTROUTER_API_KEY\")),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"client: %v\", err)\n\t}\n\n\t// Populate the request fields -- see the \"Request fields\" table above for\n\t// the available fields and which are required.\n\treq := \u0026mcpv1.ListMCPProfilesRequest{}\n\n\tresp, err := client.MCPProfiles().ListMCPProfiles(ctx, req)\n\tif err != nil {\n\t\tlog.Fatalf(\"call: %v\", err)\n\t}\n\n\tfmt.Printf(\"%+v\\n\", resp)\n}\n"},{"name":"go.mod","content":"module github.com/tetrateio/agentrouter-go-examples/mcpprofiles/listmcpprofiles\n\ngo 1.26\n\nrequire github.com/tetrateio/agentrouter-go v0.1.1\n\n// Point this at the directory you extracted the downloaded Go SDK tarball into.\n// The directory name matches the tarball stem on the Download SDK page.\nreplace github.com/tetrateio/agentrouter-go =\u003e ./third_party/agentrouter-go-0.1.1\n"}]},"python":{"files":[{"name":"main.py","content":"\"\"\"Runnable example for the AgentRouter Python SDK.\n\nSet AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `python main.py`.\n\"\"\"\nimport os\n\nfrom tars.mcp.v1 import mcp_pb2\n\nfrom agentrouter_sdk import Client\n\nclient = Client(\n    base_url=os.environ[\"AGENTROUTER_BASE_URL\"],\n    api_key=os.environ[\"AGENTROUTER_API_KEY\"],\n)\n\n# Populate the request fields -- see the \"Request fields\" table above\n# for the available fields and which are required.\nreq = mcp_pb2.ListMCPProfilesRequest()\ntry:\n    result = client.mcp_profiles.list_mcp_profiles(req)\n    print(result)\nexcept Exception as err:\n    print(\"Error:\", err)\n"},{"name":"requirements.txt","content":"# Point this at the directory you extracted the downloaded Python SDK tarball\n# into. The directory name matches the tarball stem on the Download SDK page.\n# To install instead from PyPI once published, replace the line below with:\n#   agentrouter-sdk\u003e=0.1.0\nagentrouter-sdk @ file:./third_party/agentrouter-python-0.1.1\n"}]},"typescript":{"files":[{"name":"index.ts","content":"// Runnable example for the AgentRouter TypeScript SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `npm install \u0026\u0026 npx tsx index.ts`.\nimport { Client } from '@tetrate/agentrouter-sdk'\n\nconst client = new Client({\n  baseUrl: process.env.AGENTROUTER_BASE_URL,\n  apiKey: process.env.AGENTROUTER_API_KEY,\n})\n\n// Populate the request fields -- see the \"Request fields\" table above\n// for the available fields and which are required.\nconst req = {}\ntry {\n  const result = await client.mcpProfiles.listMCPProfiles(req)\n  console.log(result)\n} catch (err) {\n  console.error('Error:', err)\n}\n"},{"name":"package.json","content":"{\n  \"name\": \"mcpprofiles\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@tetrate/agentrouter-sdk\": \"file:./third_party/agentrouter-typescript-0.1.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^20.0.0\",\n    \"typescript\": \"^5.4.0\"\n  }\n}\n"},{"name":"tsconfig.json","content":"{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true\n  }\n}\n"}]},"cli":"tare api mcp profiles list","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../mcp-profiles\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\""},"persona":"Authenticated (API key or session token)","httpVerb":"GET","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/users/{user_id}/mcp-profiles","slug":"list-mcp-profiles"}

Update an MCP profile

Changed in v0.11.0 (behaviour changes): Updating an MCP profile of type none or api_key to type oauth returns failed_precondition and names the MCP server when an attached MCP server has a tool list an oauth profile refuses, such as an empty list. The profile keeps its type. Tool names and regex: patterns, including regex:*, do not block the update. A profile that is already oauth is not checked by this rule.

Changed in v0.11.0 (behaviour changes): Creating an MCP profile with a security type other than oauth, api_key or none returns invalid_argument, and so does an update that changes the type to such a value. Spellings such as OAuth and oauth2 were accepted before and served with no token check. An update that leaves the type unset, or sends the type the profile already has, is accepted, so a profile stored with another type can still be renamed.

Changed in v0.11.0 (behaviour changes): Creating an MCP profile of type oauth returns invalid_argument unless security_policy_value sets issuer and remote_jwks, an absolute http or https URL. An update returns the same error when it changes the type to oauth, the issuer or the key set URL and leaves either missing or invalid. An update that changes none of them is accepted, so a profile saved without them can still be renamed.

Changed in v0.11.0 (bug fixes): A request with a NUL character in a name, description or filter field now returns 400 invalid_argument. It returned 500 internal before, which clients retry and which counted as a server failure. This applies when the management plane uses the extended query protocol, which is the default. A deployment that sets global.useSimpleProtocol (USE_QUERY_EXEC_MODE_SIMPLE_PROTOCOL=true, used with pgbouncer) still returns 500 for these requests.

Changed in v0.10.0 (behaviour changes): MCP profile audit entries name the person who acted. When an API key makes the call, the key is in metadata.via_key; when an admin acts for another user, that user is in metadata.subject_user_id.

Changed in v0.10.0 (bug fixes): UpdateMCPProfile clears a profile's description when the request sends a blank description, as the API reference says. Before, the blank was stored.

Changed in v0.8.0 (bug fixes): Deleting an MCP profile frees its name for a new or renamed profile.

Changed in v0.1.5 (bug fixes): An MCP profile created or changed through the MCPProfilesService API now becomes routable within seconds, the same as one changed from the dashboard. Where profiles are served on the shared URL rather than a per-project gateway hostname, the API path refreshed only part of the routing configuration, so a new profile's /mcp/ address returned 404 until the next periodic full sync (up to ~38 minutes) during which an app given that address silently had none of its tools. Every profile mutation on the API now fires the same per-user refresh the dashboard does.

What it does: Updates mutable profile fields. Omitted scalar strings ("") leave the existing value untouched.

Request fields:

FieldRequiredDescription
user_idnoDefaults to the caller's session user when empty.
profile_idyesRequired: uuid of the profile to update (MCPProfile.id).
namenoMutable scalar fields. Empty string leaves the existing value untouched -- callers explicitly pass " " when they want to clear a free-form description (the server trims that to "").
descriptionnoundocumented
security_policy_typenoSwitching a profile of another type to "oauth" returns failed_precondition while any attached server has a tool list an oauth profile cannot use, such as an empty stored list (a row saved before attach stored ["regex:*"]). Exact tool names and "regex:" selectors, including "regex:*", do not block the switch. Set such a server's tools to ["regex:*"] or to tool names first. A type that differs from the stored one must be "oauth", "api_key" or "none", or the update is refused with INVALID_ARGUMENT. Re-sending the stored type is accepted, even when it is another value, so a client that sends the stored type on every update can still rename the profile.
security_policy_valuenoWhen the patch changes the type, the issuer or remote_jwks and the result is "oauth", the resulting value must set "issuer" and "remote_jwks", or the update is refused with INVALID_ARGUMENT. A patch that changes none of them is accepted, even on a profile saved earlier without them.
customer_idnoDefaults to the caller's session customer when empty.
project_idnoDefaults to the caller's session project when empty.

Response fields:

FieldRequiredDescription
idoutput-onlyServer-assigned uuid row id. Output-only.
user_idnoOwning user id (authn.user.id). Defaults to the caller's session user when empty; immutable once set.
customer_idnoOwning customer scope. Defaults to the caller's session customer when empty; immutable once set. A profile is only visible to (user_id, customer_id, project_id) tuples that match.
project_idnoOwning project scope. Defaults to the caller's session project when empty; immutable once set.
nameyesHuman-friendly display name. Unique per user.
descriptionnoOptional freeform description.
urloutput-onlyURL PATH the data plane exposes for this profile, e.g. "/mcp/<user-hash>-<profile-hash>". NOT an absolute URL -- it carries no scheme or host. Server-assigned on create. Use endpoints below for the addresses a client actually connects to.
endpointsoutput-onlyAbsolute endpoints this profile answers on, resolved server-side from the project's Project Gateway attachment. Output-only. A profile is served by EVERY Project Gateway attached to its project, so this can hold more than one entry; a project with no attached gateway resolves to its data plane's shared URL, a single entry. An EMPTY list means no gateway URL is configured yet -- that is a valid answer to ask an operator about, not an error and not something to retry. Prefer this over joining url onto a host yourself. On a data plane that hosts Project Gateways, strict isolation (#4637 / #5005) stops the shared workspace URL from serving /mcp/* at all, so a hand-built join reaches a host that 404s -- and some hosts answer 200 with an empty body for unmatched /mcp/* paths, so the failure does not even look like one.
statusoutput-onlyLifecycle status: "active""pending""error".
error_messageoutput-onlyLast error from the reconciler when status is "error".
security_policy_typeyesSecurity policy type: "oauth""api_key""none". Any other value is refused with INVALID_ARGUMENT on create, and on an update that sets it.
security_policy_valuenoJSON-encoded security policy value. Shape depends on security_policy_type -- see schema docs on the mcp_profiles table. Sensitive material (raw api keys, oauth issuer secrets) is stored server-side; responses redact secret bytes. For "oauth" it must set "issuer" and "remote_jwks" (an absolute http or https URL of the issuer's key set); the API refuses to create an oauth profile without them with INVALID_ARGUMENT. The gateway serves one saved earlier without them with no token check while the data plane setting MCP_OAUTH_STRICT_PROFILES is off (the 0.11 default) and serves nothing while it is on (the default from 0.12).
serversoutput-onlyMCP servers (backends) attached to this profile, with the per-server enabled tool set. Output-only on the profile resource: servers are managed through the AddMCPProfileServer / RemoveMCPProfileServer / SetMCPProfileServerTools sub-resource RPCs, mirroring mcp_profile_backends.
created_atoutput-onlyRow creation time. Output-only.
updated_atoutput-onlyLast mutation time. Output-only.
{"signatures":{"go":"func (x *MCPProfilesClient) UpdateMCPProfile(ctx context.Context, req *mcpv1.UpdateMCPProfileRequest) (*mcpv1.MCPProfile, error)","python":"update_mcp_profile(req: mcp_pb2.UpdateMCPProfileRequest) -\u003e MCPProfile","typescript":"updateMCPProfile(req: MessageInitShape\u003ctypeof tars_mcp_v1_mcp_pb.UpdateMCPProfileRequestSchema\u003e): Promise\u003cMCPProfile\u003e","cli":"tare api mcp profiles update --profile-id $PROFILE_ID","curl":"curl -X PATCH \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../mcp-profiles/01H...\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"name\": \"...\",\n    \"description\": \"...\",\n    \"security_policy_type\": \"...\",\n    \"security_policy_value\": \"...\"\n  }'"},"examples":{"go":{"files":[{"name":"main.go","content":"// Command example is a runnable example for the AgentRouter Go SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then `go run .`.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tagentrouter \"github.com/tetrateio/agentrouter-go\"\n\tmcpv1 \"github.com/tetrateio/agentrouter-go/genapi/api/tars/mcp/v1\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\tclient, err := agentrouter.New(ctx,\n\t\tagentrouter.WithBaseURL(os.Getenv(\"AGENTROUTER_BASE_URL\")),\n\t\tagentrouter.WithAPIKey(os.Getenv(\"AGENTROUTER_API_KEY\")),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"client: %v\", err)\n\t}\n\n\t// Populate the request fields -- see the \"Request fields\" table above for\n\t// the available fields and which are required.\n\treq := \u0026mcpv1.UpdateMCPProfileRequest{}\n\n\tresp, err := client.MCPProfiles().UpdateMCPProfile(ctx, req)\n\tif err != nil {\n\t\tlog.Fatalf(\"call: %v\", err)\n\t}\n\n\tfmt.Printf(\"%+v\\n\", resp)\n}\n"},{"name":"go.mod","content":"module github.com/tetrateio/agentrouter-go-examples/mcpprofiles/updatemcpprofile\n\ngo 1.26\n\nrequire github.com/tetrateio/agentrouter-go v0.1.1\n\n// Point this at the directory you extracted the downloaded Go SDK tarball into.\n// The directory name matches the tarball stem on the Download SDK page.\nreplace github.com/tetrateio/agentrouter-go =\u003e ./third_party/agentrouter-go-0.1.1\n"}]},"python":{"files":[{"name":"main.py","content":"\"\"\"Runnable example for the AgentRouter Python SDK.\n\nSet AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `python main.py`.\n\"\"\"\nimport os\n\nfrom tars.mcp.v1 import mcp_pb2\n\nfrom agentrouter_sdk import Client\n\nclient = Client(\n    base_url=os.environ[\"AGENTROUTER_BASE_URL\"],\n    api_key=os.environ[\"AGENTROUTER_API_KEY\"],\n)\n\n# Populate the request fields -- see the \"Request fields\" table above\n# for the available fields and which are required.\nreq = mcp_pb2.UpdateMCPProfileRequest()\ntry:\n    result = client.mcp_profiles.update_mcp_profile(req)\n    print(result)\nexcept Exception as err:\n    print(\"Error:\", err)\n"},{"name":"requirements.txt","content":"# Point this at the directory you extracted the downloaded Python SDK tarball\n# into. The directory name matches the tarball stem on the Download SDK page.\n# To install instead from PyPI once published, replace the line below with:\n#   agentrouter-sdk\u003e=0.1.0\nagentrouter-sdk @ file:./third_party/agentrouter-python-0.1.1\n"}]},"typescript":{"files":[{"name":"index.ts","content":"// Runnable example for the AgentRouter TypeScript SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `npm install \u0026\u0026 npx tsx index.ts`.\nimport { Client } from '@tetrate/agentrouter-sdk'\n\nconst client = new Client({\n  baseUrl: process.env.AGENTROUTER_BASE_URL,\n  apiKey: process.env.AGENTROUTER_API_KEY,\n})\n\n// Populate the request fields -- see the \"Request fields\" table above\n// for the available fields and which are required.\nconst req = {}\ntry {\n  const result = await client.mcpProfiles.updateMCPProfile(req)\n  console.log(result)\n} catch (err) {\n  console.error('Error:', err)\n}\n"},{"name":"package.json","content":"{\n  \"name\": \"mcpprofiles\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@tetrate/agentrouter-sdk\": \"file:./third_party/agentrouter-typescript-0.1.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^20.0.0\",\n    \"typescript\": \"^5.4.0\"\n  }\n}\n"},{"name":"tsconfig.json","content":"{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true\n  }\n}\n"}]},"cli":"tare api mcp profiles update --profile-id $PROFILE_ID","curl":"curl -X PATCH \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../mcp-profiles/01H...\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"name\": \"...\",\n    \"description\": \"...\",\n    \"security_policy_type\": \"...\",\n    \"security_policy_value\": \"...\"\n  }'"},"persona":"Authenticated (API key or session token)","httpVerb":"PATCH","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/users/{user_id}/mcp-profiles/{profile_id}","slug":"update-an-mcp-profile"}

Delete an MCP profile

Changed in v0.10.0 (behaviour changes): MCP profile audit entries name the person who acted. When an API key makes the call, the key is in metadata.via_key; when an admin acts for another user, that user is in metadata.subject_user_id.

Changed in v0.8.0 (bug fixes): Deleting an MCP profile frees its name for a new or renamed profile.

Changed in v0.1.5 (bug fixes): An MCP profile created or changed through the MCPProfilesService API now becomes routable within seconds, the same as one changed from the dashboard. Where profiles are served on the shared URL rather than a per-project gateway hostname, the API path refreshed only part of the routing configuration, so a new profile's /mcp/ address returned 404 until the next periodic full sync (up to ~38 minutes) during which an app given that address silently had none of its tools. Every profile mutation on the API now fires the same per-user refresh the dashboard does.

What it does: Soft-deletes a profile (deleted_at set; row kept for FK integrity against historical request logs).

Request fields:

FieldRequiredDescription
user_idnoDefaults to the caller's session user when empty.
profile_idyesRequired: uuid of the profile to soft-delete (MCPProfile.id).
customer_idnoDefaults to the caller's session customer when empty.
project_idnoDefaults to the caller's session project when empty.
{"signatures":{"go":"func (x *MCPProfilesClient) DeleteMCPProfile(ctx context.Context, req *mcpv1.DeleteMCPProfileRequest) error","python":"delete_mcp_profile(req: mcp_pb2.DeleteMCPProfileRequest) -\u003e None","typescript":"deleteMCPProfile(req: MessageInitShape\u003ctypeof tars_mcp_v1_mcp_pb.DeleteMCPProfileRequestSchema\u003e): Promise\u003cvoid\u003e","cli":"tare api mcp profiles delete --profile-id $PROFILE_ID","curl":"curl -X DELETE \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../mcp-profiles/01H...\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\""},"examples":{"go":{"files":[{"name":"main.go","content":"// Command example is a runnable example for the AgentRouter Go SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then `go run .`.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tagentrouter \"github.com/tetrateio/agentrouter-go\"\n\tmcpv1 \"github.com/tetrateio/agentrouter-go/genapi/api/tars/mcp/v1\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\tclient, err := agentrouter.New(ctx,\n\t\tagentrouter.WithBaseURL(os.Getenv(\"AGENTROUTER_BASE_URL\")),\n\t\tagentrouter.WithAPIKey(os.Getenv(\"AGENTROUTER_API_KEY\")),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"client: %v\", err)\n\t}\n\n\t// Populate the request fields -- see the \"Request fields\" table above for\n\t// the available fields and which are required.\n\treq := \u0026mcpv1.DeleteMCPProfileRequest{}\n\n\tif err := client.MCPProfiles().DeleteMCPProfile(ctx, req); err != nil {\n\t\tlog.Fatalf(\"call: %v\", err)\n\t}\n\n\tfmt.Println(\"ok\")\n}\n"},{"name":"go.mod","content":"module github.com/tetrateio/agentrouter-go-examples/mcpprofiles/deletemcpprofile\n\ngo 1.26\n\nrequire github.com/tetrateio/agentrouter-go v0.1.1\n\n// Point this at the directory you extracted the downloaded Go SDK tarball into.\n// The directory name matches the tarball stem on the Download SDK page.\nreplace github.com/tetrateio/agentrouter-go =\u003e ./third_party/agentrouter-go-0.1.1\n"}]},"python":{"files":[{"name":"main.py","content":"\"\"\"Runnable example for the AgentRouter Python SDK.\n\nSet AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `python main.py`.\n\"\"\"\nimport os\n\nfrom tars.mcp.v1 import mcp_pb2\n\nfrom agentrouter_sdk import Client\n\nclient = Client(\n    base_url=os.environ[\"AGENTROUTER_BASE_URL\"],\n    api_key=os.environ[\"AGENTROUTER_API_KEY\"],\n)\n\n# Populate the request fields -- see the \"Request fields\" table above\n# for the available fields and which are required.\nreq = mcp_pb2.DeleteMCPProfileRequest()\ntry:\n    result = client.mcp_profiles.delete_mcp_profile(req)\n    print(result)\nexcept Exception as err:\n    print(\"Error:\", err)\n"},{"name":"requirements.txt","content":"# Point this at the directory you extracted the downloaded Python SDK tarball\n# into. The directory name matches the tarball stem on the Download SDK page.\n# To install instead from PyPI once published, replace the line below with:\n#   agentrouter-sdk\u003e=0.1.0\nagentrouter-sdk @ file:./third_party/agentrouter-python-0.1.1\n"}]},"typescript":{"files":[{"name":"index.ts","content":"// Runnable example for the AgentRouter TypeScript SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `npm install \u0026\u0026 npx tsx index.ts`.\nimport { Client } from '@tetrate/agentrouter-sdk'\n\nconst client = new Client({\n  baseUrl: process.env.AGENTROUTER_BASE_URL,\n  apiKey: process.env.AGENTROUTER_API_KEY,\n})\n\n// Populate the request fields -- see the \"Request fields\" table above\n// for the available fields and which are required.\nconst req = {}\ntry {\n  const result = await client.mcpProfiles.deleteMCPProfile(req)\n  console.log(result)\n} catch (err) {\n  console.error('Error:', err)\n}\n"},{"name":"package.json","content":"{\n  \"name\": \"mcpprofiles\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@tetrate/agentrouter-sdk\": \"file:./third_party/agentrouter-typescript-0.1.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^20.0.0\",\n    \"typescript\": \"^5.4.0\"\n  }\n}\n"},{"name":"tsconfig.json","content":"{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true\n  }\n}\n"}]},"cli":"tare api mcp profiles delete --profile-id $PROFILE_ID","curl":"curl -X DELETE \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../mcp-profiles/01H...\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\""},"persona":"Authenticated (API key or session token)","httpVerb":"DELETE","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/users/{user_id}/mcp-profiles/{profile_id}","slug":"delete-an-mcp-profile"}

Add an MCP server to a profile

Changed in v0.11.0 (behaviour changes): Attaching an MCP server to an oauth MCP profile returns invalid_argument unless the request lists 1 to 32 distinct tool names or regex: patterns, with regex:* for every tool. An empty list and blank, padded or repeated entries are refused. A request that repeats the MCP server's current tools on that profile is accepted, so the token of an MCP server attached before this rule can still be rotated. Profiles of type none and api_key keep the empty list meaning every tool.

Changed in v0.10.0 (behaviour changes): MCP profile audit entries name the person who acted. When an API key makes the call, the key is in metadata.via_key; when an admin acts for another user, that user is in metadata.subject_user_id.

Changed in v0.10.0 (bug fixes): A server attached to an MCP profile through the API reaches every data plane at once. A failed attach keeps the server's previous token.

Changed in v0.1.5 (bug fixes): An MCP profile created or changed through the MCPProfilesService API now becomes routable within seconds, the same as one changed from the dashboard. Where profiles are served on the shared URL rather than a per-project gateway hostname, the API path refreshed only part of the routing configuration, so a new profile's /mcp/ address returned 404 until the next periodic full sync (up to ~38 minutes) during which an app given that address silently had none of its tools. Every profile mutation on the API now fires the same per-user refresh the dashboard does.

What it does: Attaches an MCP server to a profile with all of its tools enabled by default. Pass --tools in the CLI, or tools in the SDK/REST request, to enable a subset; a profile of type oauth requires it (["regex:*"] for all tools). Creates a row in mcp_profile_backends with an optional per-server credential; the server must be enabled in the catalog and granted to the profile's project (project_mcp_servers), and re-adding an already-attached server updates its tools/credential in place.

Request fields:

FieldRequiredDescription
user_idnoDefaults to the caller's session user when empty.
profile_idyesRequired: uuid of the profile to attach the server to (MCPProfile.id).
server_idyesRequired: catalog/backend server id to attach, such as "github".
toolsnoNames the tools to enable, each an exact tool name or a regex:-prefixed selector; a profile of type oauth takes 1 to 32 entries (regex:* for every tool), and omitting this enables every tool on other profile types. These are the initial enabled-tool selectors (mcp_profile_backends.selectors.tools). The CLI flag is --tools, repeated or comma-separated. - Enable ALL tools: omit this field, send an empty list, or send ["regex:*"]. All three are equivalent and stored/returned as ["regex:*"] (include-all). On a profile whose security_policy_type is "oauth", send ["regex:*"]; an empty list is refused there. - Enable a SUBSET: list the exact tool names (a "regex:"-prefixed entry is a regex selector). - On a profile whose security_policy_type is "oauth", list at least one and at most 32 distinct entries, exact tool names and "regex:"-prefixed selectors counted together. An empty list, a blank or padded entry, a repeated entry and more than 32 entries are refused with invalid_argument. A request that repeats the list the server already has on that profile is accepted, so a token can be rotated on a server attached before this rule. There is no selector for "zero tools" -- detach the server to expose none. See MCPProfileServer.enabled_tools. On an "oauth" profile: 1 to 32 distinct entries, or INVALID_ARGUMENT, unless the request repeats the stored list.
api_tokennoOptional API-key credential for the upstream server. Stored in the secret store; never returned in any response.
bearer_tokennoOptional bearer-token credential for the upstream server. Stored in the secret store; never returned in any response.
customer_idnoDefaults to the caller's session customer when empty.
project_idnoDefaults to the caller's session project when empty.

Response fields:

FieldRequiredDescription
server_idnoCatalog/backend server id (mcp_profile_backends.backend_name), e.g. "github". Unique per profile -- re-adding the same server updates it.
statusoutput-onlyLifecycle status: "active""pending""error". Output-only.
enabled_toolsnoEnabled tool selectors (mcp_profile_backends.selectors.tools). Each entry is a tool name; a "regex:"-prefixed entry is a regex selector. NOTE: "regex:*" means include-all (canonical form written by attach/ set-tools when tools is empty). Legacy rows may return an EMPTY list, which also means include-all at the gateway; there is no selector for "zero tools" -- detach the server instead. On a profile whose security_policy_type is "oauth", the list holds 1 to 32 distinct entries, exact tool names and "regex:" selectors counted together: the API refuses an empty list, a blank or padded entry, a repeated entry and more than 32 entries. The data plane setting MCP_OAUTH_STRICT_PROFILES (the default from 0.12) decides which "regex:" entries the gateway serves on such a profile.
has_credentialoutput-onlyTrue when a per-server credential (api/bearer token) is stored for this attachment. The token bytes live in the secret store and are never returned; only this flag is surfaced. Output-only.
nameoutput-onlyDisplay name of the catalog server. Empty when the server is no longer in the catalog. Output-only.
icon_urloutput-onlyIcon URL of the catalog server. Output-only.
toolsoutput-onlyEvery tool the catalog server exposes, not only the enabled ones. Set only when the read sets include_tools. Output-only.
created_atoutput-onlyRow creation time. Output-only.
updated_atoutput-onlyLast mutation time. Output-only.
{"signatures":{"go":"func (x *MCPProfilesClient) AddMCPProfileServer(ctx context.Context, req *mcpv1.AddMCPProfileServerRequest) (*mcpv1.MCPProfileServer, error)","python":"add_mcp_profile_server(req: mcp_pb2.AddMCPProfileServerRequest) -\u003e MCPProfileServer","typescript":"addMCPProfileServer(req: MessageInitShape\u003ctypeof tars_mcp_v1_mcp_pb.AddMCPProfileServerRequestSchema\u003e): Promise\u003cMCPProfileServer\u003e","cli":"tare api mcp profiles servers add --profile-id $PROFILE_ID --server-id $SERVER_ID","curl":"curl -X POST \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../mcp-profiles/01H.../servers\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"server_id\": \"...\",\n    \"tools\": [],\n    \"api_token\": \"...\",\n    \"bearer_token\": \"...\"\n  }'"},"examples":{"go":{"files":[{"name":"main.go","content":"// Command example is a runnable example for the AgentRouter Go SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then `go run .`.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tagentrouter \"github.com/tetrateio/agentrouter-go\"\n\tmcpv1 \"github.com/tetrateio/agentrouter-go/genapi/api/tars/mcp/v1\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\tclient, err := agentrouter.New(ctx,\n\t\tagentrouter.WithBaseURL(os.Getenv(\"AGENTROUTER_BASE_URL\")),\n\t\tagentrouter.WithAPIKey(os.Getenv(\"AGENTROUTER_API_KEY\")),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"client: %v\", err)\n\t}\n\n\t// Populate the request fields -- see the \"Request fields\" table above for\n\t// the available fields and which are required.\n\treq := \u0026mcpv1.AddMCPProfileServerRequest{}\n\n\tresp, err := client.MCPProfiles().AddMCPProfileServer(ctx, req)\n\tif err != nil {\n\t\tlog.Fatalf(\"call: %v\", err)\n\t}\n\n\tfmt.Printf(\"%+v\\n\", resp)\n}\n"},{"name":"go.mod","content":"module github.com/tetrateio/agentrouter-go-examples/mcpprofiles/addmcpprofileserver\n\ngo 1.26\n\nrequire github.com/tetrateio/agentrouter-go v0.1.1\n\n// Point this at the directory you extracted the downloaded Go SDK tarball into.\n// The directory name matches the tarball stem on the Download SDK page.\nreplace github.com/tetrateio/agentrouter-go =\u003e ./third_party/agentrouter-go-0.1.1\n"}]},"python":{"files":[{"name":"main.py","content":"\"\"\"Runnable example for the AgentRouter Python SDK.\n\nSet AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `python main.py`.\n\"\"\"\nimport os\n\nfrom tars.mcp.v1 import mcp_pb2\n\nfrom agentrouter_sdk import Client\n\nclient = Client(\n    base_url=os.environ[\"AGENTROUTER_BASE_URL\"],\n    api_key=os.environ[\"AGENTROUTER_API_KEY\"],\n)\n\n# Populate the request fields -- see the \"Request fields\" table above\n# for the available fields and which are required.\nreq = mcp_pb2.AddMCPProfileServerRequest()\ntry:\n    result = client.mcp_profiles.add_mcp_profile_server(req)\n    print(result)\nexcept Exception as err:\n    print(\"Error:\", err)\n"},{"name":"requirements.txt","content":"# Point this at the directory you extracted the downloaded Python SDK tarball\n# into. The directory name matches the tarball stem on the Download SDK page.\n# To install instead from PyPI once published, replace the line below with:\n#   agentrouter-sdk\u003e=0.1.0\nagentrouter-sdk @ file:./third_party/agentrouter-python-0.1.1\n"}]},"typescript":{"files":[{"name":"index.ts","content":"// Runnable example for the AgentRouter TypeScript SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `npm install \u0026\u0026 npx tsx index.ts`.\nimport { Client } from '@tetrate/agentrouter-sdk'\n\nconst client = new Client({\n  baseUrl: process.env.AGENTROUTER_BASE_URL,\n  apiKey: process.env.AGENTROUTER_API_KEY,\n})\n\n// Populate the request fields -- see the \"Request fields\" table above\n// for the available fields and which are required.\nconst req = {}\ntry {\n  const result = await client.mcpProfiles.addMCPProfileServer(req)\n  console.log(result)\n} catch (err) {\n  console.error('Error:', err)\n}\n"},{"name":"package.json","content":"{\n  \"name\": \"mcpprofiles\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@tetrate/agentrouter-sdk\": \"file:./third_party/agentrouter-typescript-0.1.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^20.0.0\",\n    \"typescript\": \"^5.4.0\"\n  }\n}\n"},{"name":"tsconfig.json","content":"{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true\n  }\n}\n"}]},"cli":"tare api mcp profiles servers add --profile-id $PROFILE_ID --server-id $SERVER_ID","curl":"curl -X POST \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../mcp-profiles/01H.../servers\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"server_id\": \"...\",\n    \"tools\": [],\n    \"api_token\": \"...\",\n    \"bearer_token\": \"...\"\n  }'"},"persona":"Authenticated (API key or session token)","httpVerb":"POST","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/users/{user_id}/mcp-profiles/{profile_id}/servers","slug":"add-an-mcp-server-to-a-profile"}

Remove an MCP server from a profile

Changed in v0.10.0 (behaviour changes): MCP profile audit entries name the person who acted. When an API key makes the call, the key is in metadata.via_key; when an admin acts for another user, that user is in metadata.subject_user_id.

Changed in v0.1.5 (bug fixes): An MCP profile created or changed through the MCPProfilesService API now becomes routable within seconds, the same as one changed from the dashboard. Where profiles are served on the shared URL rather than a per-project gateway hostname, the API path refreshed only part of the routing configuration, so a new profile's /mcp/ address returned 404 until the next periodic full sync (up to ~38 minutes) during which an app given that address silently had none of its tools. Every profile mutation on the API now fires the same per-user refresh the dashboard does.

What it does: Detaches an MCP server from a profile, deleting the mcp_profile_backends row and any per-server credential. Idempotent: removing an already-detached server succeeds.

Request fields:

FieldRequiredDescription
user_idnoDefaults to the caller's session user when empty.
profile_idyesRequired: uuid of the profile (MCPProfile.id).
server_idyesRequired: catalog/backend server id to detach, such as "github".
customer_idnoDefaults to the caller's session customer when empty.
project_idnoDefaults to the caller's session project when empty.
{"signatures":{"go":"func (x *MCPProfilesClient) RemoveMCPProfileServer(ctx context.Context, req *mcpv1.RemoveMCPProfileServerRequest) error","python":"remove_mcp_profile_server(req: mcp_pb2.RemoveMCPProfileServerRequest) -\u003e None","typescript":"removeMCPProfileServer(req: MessageInitShape\u003ctypeof tars_mcp_v1_mcp_pb.RemoveMCPProfileServerRequestSchema\u003e): Promise\u003cvoid\u003e","cli":"tare api mcp profiles servers remove --profile-id $PROFILE_ID --server-id $SERVER_ID","curl":"curl -X DELETE \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../mcp-profiles/01H.../servers/01H...\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\""},"examples":{"go":{"files":[{"name":"main.go","content":"// Command example is a runnable example for the AgentRouter Go SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then `go run .`.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tagentrouter \"github.com/tetrateio/agentrouter-go\"\n\tmcpv1 \"github.com/tetrateio/agentrouter-go/genapi/api/tars/mcp/v1\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\tclient, err := agentrouter.New(ctx,\n\t\tagentrouter.WithBaseURL(os.Getenv(\"AGENTROUTER_BASE_URL\")),\n\t\tagentrouter.WithAPIKey(os.Getenv(\"AGENTROUTER_API_KEY\")),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"client: %v\", err)\n\t}\n\n\t// Populate the request fields -- see the \"Request fields\" table above for\n\t// the available fields and which are required.\n\treq := \u0026mcpv1.RemoveMCPProfileServerRequest{}\n\n\tif err := client.MCPProfiles().RemoveMCPProfileServer(ctx, req); err != nil {\n\t\tlog.Fatalf(\"call: %v\", err)\n\t}\n\n\tfmt.Println(\"ok\")\n}\n"},{"name":"go.mod","content":"module github.com/tetrateio/agentrouter-go-examples/mcpprofiles/removemcpprofileserver\n\ngo 1.26\n\nrequire github.com/tetrateio/agentrouter-go v0.1.1\n\n// Point this at the directory you extracted the downloaded Go SDK tarball into.\n// The directory name matches the tarball stem on the Download SDK page.\nreplace github.com/tetrateio/agentrouter-go =\u003e ./third_party/agentrouter-go-0.1.1\n"}]},"python":{"files":[{"name":"main.py","content":"\"\"\"Runnable example for the AgentRouter Python SDK.\n\nSet AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `python main.py`.\n\"\"\"\nimport os\n\nfrom tars.mcp.v1 import mcp_pb2\n\nfrom agentrouter_sdk import Client\n\nclient = Client(\n    base_url=os.environ[\"AGENTROUTER_BASE_URL\"],\n    api_key=os.environ[\"AGENTROUTER_API_KEY\"],\n)\n\n# Populate the request fields -- see the \"Request fields\" table above\n# for the available fields and which are required.\nreq = mcp_pb2.RemoveMCPProfileServerRequest()\ntry:\n    result = client.mcp_profiles.remove_mcp_profile_server(req)\n    print(result)\nexcept Exception as err:\n    print(\"Error:\", err)\n"},{"name":"requirements.txt","content":"# Point this at the directory you extracted the downloaded Python SDK tarball\n# into. The directory name matches the tarball stem on the Download SDK page.\n# To install instead from PyPI once published, replace the line below with:\n#   agentrouter-sdk\u003e=0.1.0\nagentrouter-sdk @ file:./third_party/agentrouter-python-0.1.1\n"}]},"typescript":{"files":[{"name":"index.ts","content":"// Runnable example for the AgentRouter TypeScript SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `npm install \u0026\u0026 npx tsx index.ts`.\nimport { Client } from '@tetrate/agentrouter-sdk'\n\nconst client = new Client({\n  baseUrl: process.env.AGENTROUTER_BASE_URL,\n  apiKey: process.env.AGENTROUTER_API_KEY,\n})\n\n// Populate the request fields -- see the \"Request fields\" table above\n// for the available fields and which are required.\nconst req = {}\ntry {\n  const result = await client.mcpProfiles.removeMCPProfileServer(req)\n  console.log(result)\n} catch (err) {\n  console.error('Error:', err)\n}\n"},{"name":"package.json","content":"{\n  \"name\": \"mcpprofiles\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@tetrate/agentrouter-sdk\": \"file:./third_party/agentrouter-typescript-0.1.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^20.0.0\",\n    \"typescript\": \"^5.4.0\"\n  }\n}\n"},{"name":"tsconfig.json","content":"{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true\n  }\n}\n"}]},"cli":"tare api mcp profiles servers remove --profile-id $PROFILE_ID --server-id $SERVER_ID","curl":"curl -X DELETE \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../mcp-profiles/01H.../servers/01H...\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\""},"persona":"Authenticated (API key or session token)","httpVerb":"DELETE","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/users/{user_id}/mcp-profiles/{profile_id}/servers/{server_id}","slug":"remove-an-mcp-server-from-a-profile"}

Set the enabled tools for a profile's MCP server

Changed in v0.11.0 (behaviour changes): Setting the tools of a server attached to an oauth MCP profile returns invalid_argument unless the request lists 1 to 32 distinct tool names or regex: patterns, with regex:* for every tool. An empty list and blank, padded or repeated entries are refused, and the stored list stays as it was. Profiles of type none and api_key keep the empty list meaning every tool.

Changed in v0.10.0 (behaviour changes): MCP profile audit entries name the person who acted. When an API key makes the call, the key is in metadata.via_key; when an admin acts for another user, that user is in metadata.subject_user_id.

Changed in v0.10.0 (security updates): Removing a catalog MCP server from a project now also detaches it from the legacy MCP profiles of users in the project, and editing the tools of a server that the project no longer grants is refused with PERMISSION_DENIED. Before, a legacy profile kept serving a server after its grant was removed.

Changed in v0.1.5 (bug fixes): An MCP profile created or changed through the MCPProfilesService API now becomes routable within seconds, the same as one changed from the dashboard. Where profiles are served on the shared URL rather than a per-project gateway hostname, the API path refreshed only part of the routing configuration, so a new profile's /mcp/ address returned 404 until the next periodic full sync (up to ~38 minutes) during which an app given that address silently had none of its tools. Every profile mutation on the API now fires the same per-user refresh the dashboard does.

What it does: Replaces the enabled-tool set for an attached server (mcp_profile_backends.selectors.tools). Full-replacement (PUT) semantics. An EMPTY list stores/returns regex:* (include-all) -- to expose none, remove the server. On an "oauth" profile the list must hold 1 to 32 distinct entries, exact tool names or "regex:" selectors; an empty list and anything else is INVALID_ARGUMENT.

Request fields:

FieldRequiredDescription
user_idnoDefaults to the caller's session user when empty.
profile_idyesRequired: uuid of the profile (MCPProfile.id).
server_idyesRequired: catalog/backend server id, such as "github".
toolsnoNames the tools to enable, each an exact tool name or a regex:-prefixed selector; a profile of type oauth takes 1 to 32 entries, and the CLI requires this flag, so pass regex:* to enable every tool. These are the full-replacement enabled-tool selectors (PUT semantics). The CLI flag is --tools, repeated or comma-separated. - Enable ALL tools: send an empty list (or ["regex:*"]). Both are stored/returned as ["regex:*"] (include-all). On a profile whose security_policy_type is "oauth", send ["regex:*"]; an empty list is refused there. - Enable a SUBSET: list the exact tool names (a "regex:"-prefixed entry is a regex selector). - On a profile whose security_policy_type is "oauth", list at least one and at most 32 distinct entries, exact tool names and "regex:"-prefixed selectors counted together. An empty list, a blank or padded entry, a repeated entry and more than 32 entries are refused with invalid_argument. There is no selector for "zero tools" -- detach the server to expose none. On an "oauth" profile: 1 to 32 distinct entries, or INVALID_ARGUMENT.
customer_idnoDefaults to the caller's session customer when empty.
project_idnoDefaults to the caller's session project when empty.

Response fields:

FieldRequiredDescription
server_idnoCatalog/backend server id (mcp_profile_backends.backend_name), e.g. "github". Unique per profile -- re-adding the same server updates it.
statusoutput-onlyLifecycle status: "active""pending""error". Output-only.
enabled_toolsnoEnabled tool selectors (mcp_profile_backends.selectors.tools). Each entry is a tool name; a "regex:"-prefixed entry is a regex selector. NOTE: "regex:*" means include-all (canonical form written by attach/ set-tools when tools is empty). Legacy rows may return an EMPTY list, which also means include-all at the gateway; there is no selector for "zero tools" -- detach the server instead. On a profile whose security_policy_type is "oauth", the list holds 1 to 32 distinct entries, exact tool names and "regex:" selectors counted together: the API refuses an empty list, a blank or padded entry, a repeated entry and more than 32 entries. The data plane setting MCP_OAUTH_STRICT_PROFILES (the default from 0.12) decides which "regex:" entries the gateway serves on such a profile.
has_credentialoutput-onlyTrue when a per-server credential (api/bearer token) is stored for this attachment. The token bytes live in the secret store and are never returned; only this flag is surfaced. Output-only.
nameoutput-onlyDisplay name of the catalog server. Empty when the server is no longer in the catalog. Output-only.
icon_urloutput-onlyIcon URL of the catalog server. Output-only.
toolsoutput-onlyEvery tool the catalog server exposes, not only the enabled ones. Set only when the read sets include_tools. Output-only.
created_atoutput-onlyRow creation time. Output-only.
updated_atoutput-onlyLast mutation time. Output-only.
{"signatures":{"go":"func (x *MCPProfilesClient) SetMCPProfileServerTools(ctx context.Context, req *mcpv1.SetMCPProfileServerToolsRequest) (*mcpv1.MCPProfileServer, error)","python":"set_mcp_profile_server_tools(req: mcp_pb2.SetMCPProfileServerToolsRequest) -\u003e MCPProfileServer","typescript":"setMCPProfileServerTools(req: MessageInitShape\u003ctypeof tars_mcp_v1_mcp_pb.SetMCPProfileServerToolsRequestSchema\u003e): Promise\u003cMCPProfileServer\u003e","cli":"tare api mcp profiles servers set-tools --profile-id $PROFILE_ID --server-id $SERVER_ID","curl":"curl -X PUT \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../mcp-profiles/01H.../servers/01H.../tools\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"tools\": []\n  }'"},"examples":{"go":{"files":[{"name":"main.go","content":"// Command example is a runnable example for the AgentRouter Go SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then `go run .`.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tagentrouter \"github.com/tetrateio/agentrouter-go\"\n\tmcpv1 \"github.com/tetrateio/agentrouter-go/genapi/api/tars/mcp/v1\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\tclient, err := agentrouter.New(ctx,\n\t\tagentrouter.WithBaseURL(os.Getenv(\"AGENTROUTER_BASE_URL\")),\n\t\tagentrouter.WithAPIKey(os.Getenv(\"AGENTROUTER_API_KEY\")),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"client: %v\", err)\n\t}\n\n\t// Populate the request fields -- see the \"Request fields\" table above for\n\t// the available fields and which are required.\n\treq := \u0026mcpv1.SetMCPProfileServerToolsRequest{}\n\n\tresp, err := client.MCPProfiles().SetMCPProfileServerTools(ctx, req)\n\tif err != nil {\n\t\tlog.Fatalf(\"call: %v\", err)\n\t}\n\n\tfmt.Printf(\"%+v\\n\", resp)\n}\n"},{"name":"go.mod","content":"module github.com/tetrateio/agentrouter-go-examples/mcpprofiles/setmcpprofileservertools\n\ngo 1.26\n\nrequire github.com/tetrateio/agentrouter-go v0.1.1\n\n// Point this at the directory you extracted the downloaded Go SDK tarball into.\n// The directory name matches the tarball stem on the Download SDK page.\nreplace github.com/tetrateio/agentrouter-go =\u003e ./third_party/agentrouter-go-0.1.1\n"}]},"python":{"files":[{"name":"main.py","content":"\"\"\"Runnable example for the AgentRouter Python SDK.\n\nSet AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `python main.py`.\n\"\"\"\nimport os\n\nfrom tars.mcp.v1 import mcp_pb2\n\nfrom agentrouter_sdk import Client\n\nclient = Client(\n    base_url=os.environ[\"AGENTROUTER_BASE_URL\"],\n    api_key=os.environ[\"AGENTROUTER_API_KEY\"],\n)\n\n# Populate the request fields -- see the \"Request fields\" table above\n# for the available fields and which are required.\nreq = mcp_pb2.SetMCPProfileServerToolsRequest()\ntry:\n    result = client.mcp_profiles.set_mcp_profile_server_tools(req)\n    print(result)\nexcept Exception as err:\n    print(\"Error:\", err)\n"},{"name":"requirements.txt","content":"# Point this at the directory you extracted the downloaded Python SDK tarball\n# into. The directory name matches the tarball stem on the Download SDK page.\n# To install instead from PyPI once published, replace the line below with:\n#   agentrouter-sdk\u003e=0.1.0\nagentrouter-sdk @ file:./third_party/agentrouter-python-0.1.1\n"}]},"typescript":{"files":[{"name":"index.ts","content":"// Runnable example for the AgentRouter TypeScript SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `npm install \u0026\u0026 npx tsx index.ts`.\nimport { Client } from '@tetrate/agentrouter-sdk'\n\nconst client = new Client({\n  baseUrl: process.env.AGENTROUTER_BASE_URL,\n  apiKey: process.env.AGENTROUTER_API_KEY,\n})\n\n// Populate the request fields -- see the \"Request fields\" table above\n// for the available fields and which are required.\nconst req = {}\ntry {\n  const result = await client.mcpProfiles.setMCPProfileServerTools(req)\n  console.log(result)\n} catch (err) {\n  console.error('Error:', err)\n}\n"},{"name":"package.json","content":"{\n  \"name\": \"mcpprofiles\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@tetrate/agentrouter-sdk\": \"file:./third_party/agentrouter-typescript-0.1.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^20.0.0\",\n    \"typescript\": \"^5.4.0\"\n  }\n}\n"},{"name":"tsconfig.json","content":"{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true\n  }\n}\n"}]},"cli":"tare api mcp profiles servers set-tools --profile-id $PROFILE_ID --server-id $SERVER_ID","curl":"curl -X PUT \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../mcp-profiles/01H.../servers/01H.../tools\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"tools\": []\n  }'"},"persona":"Authenticated (API key or session token)","httpVerb":"PUT","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/users/{user_id}/mcp-profiles/{profile_id}/servers/{server_id}/tools","slug":"set-the-enabled-tools-for-a-profiles-mcp-server"}

List MCP servers available to a project

What it does: Lists the MCP servers a user may attach to a profile in the given project: enabled catalog servers granted to the project (project_mcp_servers), each with its tool catalog so the client can pick which tools to enable on attach.

Request fields:

FieldRequiredDescription
user_idnoDefaults to the caller's session user when empty.
customer_idnoDefaults to the caller's session customer when empty.
project_idnoDefaults to the caller's session project when empty.

Response fields:

FieldRequiredDescription
serversnoServers the caller may attach to a profile in this project (enabled catalog servers granted to the project), each with its tool catalog.
{"signatures":{"go":"func (x *MCPProfilesClient) ListAvailableMCPServers(ctx context.Context, req *mcpv1.ListAvailableMCPServersRequest) (*mcpv1.ListAvailableMCPServersResponse, error)","python":"list_available_mcp_servers(req: mcp_pb2.ListAvailableMCPServersRequest) -\u003e ListAvailableMCPServersResponse","typescript":"listAvailableMCPServers(req: MessageInitShape\u003ctypeof tars_mcp_v1_mcp_pb.ListAvailableMCPServersRequestSchema\u003e): Promise\u003cListAvailableMCPServersResponse\u003e","cli":"tare api mcp servers available","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../available-mcp-servers\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\""},"examples":{"go":{"files":[{"name":"main.go","content":"// Command example is a runnable example for the AgentRouter Go SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then `go run .`.\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\n\tagentrouter \"github.com/tetrateio/agentrouter-go\"\n\tmcpv1 \"github.com/tetrateio/agentrouter-go/genapi/api/tars/mcp/v1\"\n)\n\nfunc main() {\n\tctx := context.Background()\n\n\tclient, err := agentrouter.New(ctx,\n\t\tagentrouter.WithBaseURL(os.Getenv(\"AGENTROUTER_BASE_URL\")),\n\t\tagentrouter.WithAPIKey(os.Getenv(\"AGENTROUTER_API_KEY\")),\n\t)\n\tif err != nil {\n\t\tlog.Fatalf(\"client: %v\", err)\n\t}\n\n\t// Populate the request fields -- see the \"Request fields\" table above for\n\t// the available fields and which are required.\n\treq := \u0026mcpv1.ListAvailableMCPServersRequest{}\n\n\tresp, err := client.MCPProfiles().ListAvailableMCPServers(ctx, req)\n\tif err != nil {\n\t\tlog.Fatalf(\"call: %v\", err)\n\t}\n\n\tfmt.Printf(\"%+v\\n\", resp)\n}\n"},{"name":"go.mod","content":"module github.com/tetrateio/agentrouter-go-examples/mcpprofiles/listavailablemcpservers\n\ngo 1.26\n\nrequire github.com/tetrateio/agentrouter-go v0.1.1\n\n// Point this at the directory you extracted the downloaded Go SDK tarball into.\n// The directory name matches the tarball stem on the Download SDK page.\nreplace github.com/tetrateio/agentrouter-go =\u003e ./third_party/agentrouter-go-0.1.1\n"}]},"python":{"files":[{"name":"main.py","content":"\"\"\"Runnable example for the AgentRouter Python SDK.\n\nSet AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `python main.py`.\n\"\"\"\nimport os\n\nfrom tars.mcp.v1 import mcp_pb2\n\nfrom agentrouter_sdk import Client\n\nclient = Client(\n    base_url=os.environ[\"AGENTROUTER_BASE_URL\"],\n    api_key=os.environ[\"AGENTROUTER_API_KEY\"],\n)\n\n# Populate the request fields -- see the \"Request fields\" table above\n# for the available fields and which are required.\nreq = mcp_pb2.ListAvailableMCPServersRequest()\ntry:\n    result = client.mcp_profiles.list_available_mcp_servers(req)\n    print(result)\nexcept Exception as err:\n    print(\"Error:\", err)\n"},{"name":"requirements.txt","content":"# Point this at the directory you extracted the downloaded Python SDK tarball\n# into. The directory name matches the tarball stem on the Download SDK page.\n# To install instead from PyPI once published, replace the line below with:\n#   agentrouter-sdk\u003e=0.1.0\nagentrouter-sdk @ file:./third_party/agentrouter-python-0.1.1\n"}]},"typescript":{"files":[{"name":"index.ts","content":"// Runnable example for the AgentRouter TypeScript SDK.\n// Set AGENTROUTER_BASE_URL and AGENTROUTER_API_KEY in the environment, then run `npm install \u0026\u0026 npx tsx index.ts`.\nimport { Client } from '@tetrate/agentrouter-sdk'\n\nconst client = new Client({\n  baseUrl: process.env.AGENTROUTER_BASE_URL,\n  apiKey: process.env.AGENTROUTER_API_KEY,\n})\n\n// Populate the request fields -- see the \"Request fields\" table above\n// for the available fields and which are required.\nconst req = {}\ntry {\n  const result = await client.mcpProfiles.listAvailableMCPServers(req)\n  console.log(result)\n} catch (err) {\n  console.error('Error:', err)\n}\n"},{"name":"package.json","content":"{\n  \"name\": \"mcpprofiles\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"type\": \"module\",\n  \"dependencies\": {\n    \"@tetrate/agentrouter-sdk\": \"file:./third_party/agentrouter-typescript-0.1.1\"\n  },\n  \"devDependencies\": {\n    \"@types/node\": \"^20.0.0\",\n    \"typescript\": \"^5.4.0\"\n  }\n}\n"},{"name":"tsconfig.json","content":"{\n  \"compilerOptions\": {\n    \"target\": \"ES2020\",\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\",\n    \"strict\": true,\n    \"esModuleInterop\": true,\n    \"skipLibCheck\": true\n  }\n}\n"}]},"cli":"tare api mcp servers available","curl":"curl \"${AGENTROUTER_BASE_URL}/v1/customers/cust_01H.../projects/proj_01H.../users/01H.../available-mcp-servers\" \\\n  -H \"Authorization: Bearer ${AGENTROUTER_API_KEY}\""},"persona":"Authenticated (API key or session token)","httpVerb":"GET","httpPath":"/v1/customers/{customer_id}/projects/{project_id}/users/{user_id}/available-mcp-servers","slug":"list-mcp-servers-available-to-a-project"}