From 6cccc2f4aafa9ffdaa64ea366cc910240789f08c Mon Sep 17 00:00:00 2001 From: Casey Brooks Date: Fri, 13 Mar 2026 13:12:31 +0000 Subject: [PATCH 1/2] feat(teams): add variables and tool filter --- .../v1/components/schemas/EntityType.yaml | 1 + .../components/schemas/McpServerConfig.yaml | 15 +++ .../schemas/PaginatedVariables.yaml | 9 ++ .../team/v1/components/schemas/Variable.yaml | 7 ++ .../schemas/VariableCreateRequest.yaml | 6 ++ .../schemas/VariableUpdateRequest.yaml | 6 ++ openapi/team/v1/openapi.yaml | 15 +++ openapi/team/v1/paths/variable-by-id.yaml | 44 +++++++++ openapi/team/v1/paths/variable-resolve.yaml | 23 +++++ openapi/team/v1/paths/variables.yaml | 49 ++++++++++ proto/agynio/api/teams/v1/teams.proto | 93 ++++++++++++++++++- 11 files changed, 267 insertions(+), 1 deletion(-) create mode 100644 openapi/team/v1/components/schemas/PaginatedVariables.yaml create mode 100644 openapi/team/v1/components/schemas/Variable.yaml create mode 100644 openapi/team/v1/components/schemas/VariableCreateRequest.yaml create mode 100644 openapi/team/v1/components/schemas/VariableUpdateRequest.yaml create mode 100644 openapi/team/v1/paths/variable-by-id.yaml create mode 100644 openapi/team/v1/paths/variable-resolve.yaml create mode 100644 openapi/team/v1/paths/variables.yaml diff --git a/openapi/team/v1/components/schemas/EntityType.yaml b/openapi/team/v1/components/schemas/EntityType.yaml index 3c919a1..78b199f 100644 --- a/openapi/team/v1/components/schemas/EntityType.yaml +++ b/openapi/team/v1/components/schemas/EntityType.yaml @@ -5,3 +5,4 @@ enum: - mcpServer - workspaceConfiguration - memoryBucket + - variable diff --git a/openapi/team/v1/components/schemas/McpServerConfig.yaml b/openapi/team/v1/components/schemas/McpServerConfig.yaml index 888a04d..41ec662 100644 --- a/openapi/team/v1/components/schemas/McpServerConfig.yaml +++ b/openapi/team/v1/components/schemas/McpServerConfig.yaml @@ -16,4 +16,19 @@ properties: maxAttempts: { type: integer, minimum: 1 } backoffMs: { type: integer, minimum: 1 } additionalProperties: false + toolFilter: + type: object + properties: + mode: + type: string + enum: [allow, deny] + rules: + type: array + items: + type: object + properties: + pattern: { type: string, minLength: 1 } + required: [pattern] + additionalProperties: false + additionalProperties: false additionalProperties: false diff --git a/openapi/team/v1/components/schemas/PaginatedVariables.yaml b/openapi/team/v1/components/schemas/PaginatedVariables.yaml new file mode 100644 index 0000000..34ddd27 --- /dev/null +++ b/openapi/team/v1/components/schemas/PaginatedVariables.yaml @@ -0,0 +1,9 @@ +type: object +properties: + items: + type: array + items: { $ref: './Variable.yaml' } + page: { type: integer } + perPage: { type: integer } + total: { type: integer } +required: [items, page, perPage, total] diff --git a/openapi/team/v1/components/schemas/Variable.yaml b/openapi/team/v1/components/schemas/Variable.yaml new file mode 100644 index 0000000..ade714c --- /dev/null +++ b/openapi/team/v1/components/schemas/Variable.yaml @@ -0,0 +1,7 @@ +type: object +properties: + meta: { $ref: './EntityMeta.yaml' } + key: { type: string } + value: { type: string } + description: { type: string } +required: [meta, key, value] diff --git a/openapi/team/v1/components/schemas/VariableCreateRequest.yaml b/openapi/team/v1/components/schemas/VariableCreateRequest.yaml new file mode 100644 index 0000000..75a6aca --- /dev/null +++ b/openapi/team/v1/components/schemas/VariableCreateRequest.yaml @@ -0,0 +1,6 @@ +type: object +properties: + key: { type: string, minLength: 1 } + value: { type: string } + description: { type: string } +required: [key, value] diff --git a/openapi/team/v1/components/schemas/VariableUpdateRequest.yaml b/openapi/team/v1/components/schemas/VariableUpdateRequest.yaml new file mode 100644 index 0000000..40470d9 --- /dev/null +++ b/openapi/team/v1/components/schemas/VariableUpdateRequest.yaml @@ -0,0 +1,6 @@ +type: object +properties: + key: { type: string, minLength: 1 } + value: { type: string } + description: { type: string } +additionalProperties: false diff --git a/openapi/team/v1/openapi.yaml b/openapi/team/v1/openapi.yaml index 2a8c68d..95ae28a 100644 --- a/openapi/team/v1/openapi.yaml +++ b/openapi/team/v1/openapi.yaml @@ -10,6 +10,7 @@ tags: - name: MCP Servers - name: WorkspaceConfigurations - name: MemoryBuckets + - name: Variables - name: Attachments paths: /agents: @@ -32,6 +33,12 @@ paths: $ref: './paths/memory-buckets.yaml' /memory-buckets/{id}: $ref: './paths/memory-bucket-by-id.yaml' + /variables: + $ref: './paths/variables.yaml' + /variables/{id}: + $ref: './paths/variable-by-id.yaml' + /variables/resolve/{key}: + $ref: './paths/variable-resolve.yaml' /attachments: $ref: './paths/attachments.yaml' /attachments/{id}: @@ -108,6 +115,14 @@ components: $ref: './components/schemas/MemoryBucketUpdateRequest.yaml' PaginatedMemoryBuckets: $ref: './components/schemas/PaginatedMemoryBuckets.yaml' + Variable: + $ref: './components/schemas/Variable.yaml' + VariableCreateRequest: + $ref: './components/schemas/VariableCreateRequest.yaml' + VariableUpdateRequest: + $ref: './components/schemas/VariableUpdateRequest.yaml' + PaginatedVariables: + $ref: './components/schemas/PaginatedVariables.yaml' EntityType: $ref: './components/schemas/EntityType.yaml' AttachmentKind: diff --git a/openapi/team/v1/paths/variable-by-id.yaml b/openapi/team/v1/paths/variable-by-id.yaml new file mode 100644 index 0000000..86354bd --- /dev/null +++ b/openapi/team/v1/paths/variable-by-id.yaml @@ -0,0 +1,44 @@ +get: + tags: [Variables] + summary: Get variable by ID + parameters: + - $ref: '../components/parameters/IdPath.yaml' + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '../components/schemas/Variable.yaml' + default: + $ref: '../components/responses/ProblemResponse.yaml' +patch: + tags: [Variables] + summary: Update variable (partial) + parameters: + - $ref: '../components/parameters/IdPath.yaml' + requestBody: + required: true + content: + application/json: + schema: + $ref: '../components/schemas/VariableUpdateRequest.yaml' + responses: + '200': + description: Updated + content: + application/json: + schema: + $ref: '../components/schemas/Variable.yaml' + default: + $ref: '../components/responses/ProblemResponse.yaml' +delete: + tags: [Variables] + summary: Delete variable + parameters: + - $ref: '../components/parameters/IdPath.yaml' + responses: + '204': + description: No Content + default: + $ref: '../components/responses/ProblemResponse.yaml' diff --git a/openapi/team/v1/paths/variable-resolve.yaml b/openapi/team/v1/paths/variable-resolve.yaml new file mode 100644 index 0000000..c6630f3 --- /dev/null +++ b/openapi/team/v1/paths/variable-resolve.yaml @@ -0,0 +1,23 @@ +get: + tags: [Variables] + summary: Resolve variable by key + parameters: + - in: path + name: key + required: true + schema: + type: string + responses: + '200': + description: OK + content: + application/json: + schema: + type: object + properties: + value: { type: string } + found: { type: boolean } + required: [value, found] + additionalProperties: false + default: + $ref: '../components/responses/ProblemResponse.yaml' diff --git a/openapi/team/v1/paths/variables.yaml b/openapi/team/v1/paths/variables.yaml new file mode 100644 index 0000000..afc2613 --- /dev/null +++ b/openapi/team/v1/paths/variables.yaml @@ -0,0 +1,49 @@ +get: + tags: [Variables] + summary: List variables + parameters: + - in: query + name: q + schema: + type: string + description: Free-text search (key/description). + - in: query + name: page + schema: + type: integer + minimum: 1 + default: 1 + - in: query + name: perPage + schema: + type: integer + minimum: 1 + maximum: 100 + default: 20 + responses: + '200': + description: OK + content: + application/json: + schema: + $ref: '../components/schemas/PaginatedVariables.yaml' + default: + $ref: '../components/responses/ProblemResponse.yaml' +post: + tags: [Variables] + summary: Create variable + requestBody: + required: true + content: + application/json: + schema: + $ref: '../components/schemas/VariableCreateRequest.yaml' + responses: + '201': + description: Created + content: + application/json: + schema: + $ref: '../components/schemas/Variable.yaml' + default: + $ref: '../components/responses/ProblemResponse.yaml' diff --git a/proto/agynio/api/teams/v1/teams.proto b/proto/agynio/api/teams/v1/teams.proto index bb0b930..aecd74f 100644 --- a/proto/agynio/api/teams/v1/teams.proto +++ b/proto/agynio/api/teams/v1/teams.proto @@ -8,7 +8,7 @@ import "google/protobuf/timestamp.proto"; option go_package = "github.com/agynio/api/gen/agynio/api/teams/v1;teamsv1"; // TeamsService manages team resources: agents, tools, MCP servers, -// workspace configurations, memory buckets, and attachments (relations). +// workspace configurations, memory buckets, variables, and attachments (relations). // // This is a control-plane service. It stores desired state; // other services reconcile toward it. @@ -48,6 +48,14 @@ service TeamsService { rpc DeleteMemoryBucket(DeleteMemoryBucketRequest) returns (DeleteMemoryBucketResponse); rpc ListMemoryBuckets(ListMemoryBucketsRequest) returns (ListMemoryBucketsResponse); + // --- Variables --- + rpc CreateVariable(CreateVariableRequest) returns (CreateVariableResponse); + rpc GetVariable(GetVariableRequest) returns (GetVariableResponse); + rpc UpdateVariable(UpdateVariableRequest) returns (UpdateVariableResponse); + rpc DeleteVariable(DeleteVariableRequest) returns (DeleteVariableResponse); + rpc ListVariables(ListVariablesRequest) returns (ListVariablesResponse); + rpc ResolveVariable(ResolveVariableRequest) returns (ResolveVariableResponse); + // --- Attachments (no Update) --- rpc CreateAttachment(CreateAttachmentRequest) returns (CreateAttachmentResponse); rpc GetAttachment(GetAttachmentRequest) returns (GetAttachmentResponse); @@ -89,6 +97,7 @@ enum EntityType { ENTITY_TYPE_MCP_SERVER = 3; ENTITY_TYPE_WORKSPACE_CONFIGURATION = 4; ENTITY_TYPE_MEMORY_BUCKET = 5; + ENTITY_TYPE_VARIABLE = 6; } enum AttachmentKind { @@ -125,6 +134,12 @@ enum AgentProcessBuffer { AGENT_PROCESS_BUFFER_ONE_BY_ONE = 2; } +enum McpToolFilterMode { + MCP_TOOL_FILTER_MODE_UNSPECIFIED = 0; + MCP_TOOL_FILTER_MODE_ALLOW = 1; + MCP_TOOL_FILTER_MODE_DENY = 2; +} + // =========================================================================== // Agent // =========================================================================== @@ -266,6 +281,15 @@ message McpEnvItem { string value = 2; } +message McpToolFilterRule { + string pattern = 1; +} + +message McpToolFilter { + McpToolFilterMode mode = 1; + repeated McpToolFilterRule rules = 2; +} + message McpServerRestartConfig { int32 max_attempts = 1; int32 backoff_ms = 2; @@ -281,6 +305,7 @@ message McpServerConfig { int32 heartbeat_interval_ms = 7; int32 stale_timeout_ms = 8; McpServerRestartConfig restart = 9; + McpToolFilter tool_filter = 10; } message McpServer { @@ -475,6 +500,72 @@ message ListMemoryBucketsResponse { string next_page_token = 2; } +// =========================================================================== +// Variable +// =========================================================================== + +message Variable { + EntityMeta meta = 1; + string key = 2; + string value = 3; + string description = 4; +} + +message CreateVariableRequest { + string key = 1; + string value = 2; + string description = 3; +} + +message CreateVariableResponse { + Variable variable = 1; +} + +message GetVariableRequest { + string id = 1; +} + +message GetVariableResponse { + Variable variable = 1; +} + +message UpdateVariableRequest { + string id = 1; + optional string key = 2; + optional string value = 3; + optional string description = 4; +} + +message UpdateVariableResponse { + Variable variable = 1; +} + +message DeleteVariableRequest { + string id = 1; +} + +message DeleteVariableResponse {} + +message ListVariablesRequest { + int32 page_size = 1; + string page_token = 2; + string query = 3; +} + +message ListVariablesResponse { + repeated Variable variables = 1; + string next_page_token = 2; +} + +message ResolveVariableRequest { + string key = 1; +} + +message ResolveVariableResponse { + string value = 1; + bool found = 2; +} + // =========================================================================== // Attachment (relation between entities; no Update) // =========================================================================== From 8a8dfaf0df16b4abf49bdacd43557303ac76a692 Mon Sep 17 00:00:00 2001 From: Casey Brooks Date: Fri, 13 Mar 2026 13:27:32 +0000 Subject: [PATCH 2/2] fix(openapi): address review feedback --- .../v1/components/schemas/McpServerConfig.yaml | 1 + openapi/team/v1/components/schemas/Variable.yaml | 15 ++++++++------- openapi/team/v1/paths/variable-resolve.yaml | 6 ++++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/openapi/team/v1/components/schemas/McpServerConfig.yaml b/openapi/team/v1/components/schemas/McpServerConfig.yaml index 41ec662..7bb4865 100644 --- a/openapi/team/v1/components/schemas/McpServerConfig.yaml +++ b/openapi/team/v1/components/schemas/McpServerConfig.yaml @@ -30,5 +30,6 @@ properties: pattern: { type: string, minLength: 1 } required: [pattern] additionalProperties: false + required: [mode] additionalProperties: false additionalProperties: false diff --git a/openapi/team/v1/components/schemas/Variable.yaml b/openapi/team/v1/components/schemas/Variable.yaml index ade714c..411fd90 100644 --- a/openapi/team/v1/components/schemas/Variable.yaml +++ b/openapi/team/v1/components/schemas/Variable.yaml @@ -1,7 +1,8 @@ -type: object -properties: - meta: { $ref: './EntityMeta.yaml' } - key: { type: string } - value: { type: string } - description: { type: string } -required: [meta, key, value] +allOf: + - $ref: './EntityMeta.yaml' + - type: object + properties: + key: { type: string } + value: { type: string } + description: { type: string } + required: [key, value] diff --git a/openapi/team/v1/paths/variable-resolve.yaml b/openapi/team/v1/paths/variable-resolve.yaml index c6630f3..2ac5dda 100644 --- a/openapi/team/v1/paths/variable-resolve.yaml +++ b/openapi/team/v1/paths/variable-resolve.yaml @@ -15,9 +15,11 @@ get: schema: type: object properties: - value: { type: string } + value: + type: string + description: Only present when found is true. found: { type: boolean } - required: [value, found] + required: [found] additionalProperties: false default: $ref: '../components/responses/ProblemResponse.yaml'