mirror of
https://github.com/n8n-io/n8n.git
synced 2026-08-29 01:39:24 +08:00
feat(core): Add availableInMCP column to agents (#34665)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -21,7 +21,7 @@ Auto-generated from the PostgreSQL migrations in @n8n/db. Do not edit by hand.
|
||||
| [public.agent_task_definition](public.agent_task_definition.md) | 7 | | BASE TABLE |
|
||||
| [public.agent_task_run_lock](public.agent_task_run_lock.md) | 6 | | BASE TABLE |
|
||||
| [public.agent_task_snapshot](public.agent_task_snapshot.md) | 8 | | BASE TABLE |
|
||||
| [public.agents](public.agents.md) | 11 | | BASE TABLE |
|
||||
| [public.agents](public.agents.md) | 12 | | BASE TABLE |
|
||||
| [public.agents_memory_entries](public.agents_memory_entries.md) | 13 | | BASE TABLE |
|
||||
| [public.agents_memory_entry_cursors](public.agents_memory_entry_cursors.md) | 6 | | BASE TABLE |
|
||||
| [public.agents_memory_entry_locks](public.agents_memory_entry_locks.md) | 6 | | BASE TABLE |
|
||||
@@ -489,6 +489,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -48,6 +48,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -46,6 +46,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -61,6 +61,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -82,6 +82,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -56,6 +56,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -58,6 +58,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -51,6 +51,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -47,6 +47,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
| Name | Type | Default | Nullable | Children | Parents | Comment |
|
||||
| ---- | ---- | ------- | -------- | -------- | ------- | ------- |
|
||||
| activeVersionId | varchar(36) | | true | | [public.agent_history](public.agent_history.md) | |
|
||||
| availableInMCP | boolean | false | false | | | Whether MCP clients granted agent scopes may operate on this agent |
|
||||
| createdAt | timestamp(3) with time zone | CURRENT_TIMESTAMP(3) | false | | | |
|
||||
| id | varchar(36) | | false | [public.agent_chat_subscriptions](public.agent_chat_subscriptions.md) [public.agent_checkpoints](public.agent_checkpoints.md) [public.agent_eval_dataset](public.agent_eval_dataset.md) [public.agent_execution_threads](public.agent_execution_threads.md) [public.agent_files](public.agent_files.md) [public.agent_history](public.agent_history.md) [public.agent_task_definition](public.agent_task_definition.md) [public.agent_task_run_lock](public.agent_task_run_lock.md) [public.agents_memory_entries](public.agents_memory_entries.md) [public.agents_memory_entry_cursors](public.agents_memory_entry_cursors.md) [public.agents_memory_entry_locks](public.agents_memory_entry_locks.md) [public.agents_memory_entry_sources](public.agents_memory_entry_sources.md) [public.agents_observation_cursors](public.agents_observation_cursors.md) [public.agents_observation_locks](public.agents_observation_locks.md) [public.agents_observations](public.agents_observations.md) | | |
|
||||
| integrations | json | '[]'::json | false | | | |
|
||||
@@ -23,6 +24,7 @@
|
||||
| FK_940597dfe9753375309ce6aeea0 | FOREIGN KEY | FOREIGN KEY ("activeVersionId") REFERENCES agent_history("versionId") ON DELETE SET NULL |
|
||||
| FK_a30d560207c4071d98aa03c179c | FOREIGN KEY | FOREIGN KEY ("projectId") REFERENCES project(id) ON DELETE CASCADE |
|
||||
| PK_9c653f28ae19c5884d5baf6a1d9 | PRIMARY KEY | PRIMARY KEY (id) |
|
||||
| agents_availableInMCP_not_null | n | NOT NULL "availableInMCP" |
|
||||
| agents_createdAt_not_null | n | NOT NULL "createdAt" |
|
||||
| agents_id_not_null | n | NOT NULL id |
|
||||
| agents_integrations_not_null | n | NOT NULL integrations |
|
||||
@@ -65,6 +67,7 @@ erDiagram
|
||||
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -74,6 +74,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -50,6 +50,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -50,6 +50,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -66,6 +66,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -50,6 +50,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -54,6 +54,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -73,6 +73,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -102,6 +102,7 @@ erDiagram
|
||||
}
|
||||
"public.agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
timestamp_3__with_time_zone createdAt
|
||||
varchar_36_ id
|
||||
json integrations
|
||||
|
||||
@@ -21,7 +21,7 @@ Auto-generated from the SQLite migrations in @n8n/db. Do not edit by hand.
|
||||
| [agent_task_definition](agent_task_definition.md) | 7 | | table |
|
||||
| [agent_task_run_lock](agent_task_run_lock.md) | 6 | | table |
|
||||
| [agent_task_snapshot](agent_task_snapshot.md) | 8 | | table |
|
||||
| [agents](agents.md) | 11 | | table |
|
||||
| [agents](agents.md) | 12 | | table |
|
||||
| [agents_memory_entries](agents_memory_entries.md) | 13 | | table |
|
||||
| [agents_memory_entry_cursors](agents_memory_entry_cursors.md) | 6 | | table |
|
||||
| [agents_memory_entry_locks](agents_memory_entry_locks.md) | 6 | | table |
|
||||
@@ -155,8 +155,8 @@ erDiagram
|
||||
"agent_task_definition" }o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE"
|
||||
"agent_task_run_lock" |o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE"
|
||||
"agent_task_snapshot" |o--|| "agent_history" : "FOREIGN KEY (versionId) REFERENCES agent_history (versionId) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE"
|
||||
"agents" }o--|| "project" : "FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE"
|
||||
"agents" }o--o| "agent_history" : "FOREIGN KEY (activeVersionId) REFERENCES agent_history (versionId) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE"
|
||||
"agents" }o--|| "project" : "FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE"
|
||||
"agents_memory_entries" }o--o| "agents_memory_entries" : "FOREIGN KEY (supersededBy) REFERENCES agents_memory_entries (id) ON UPDATE NO ACTION ON DELETE NO ACTION MATCH NONE"
|
||||
"agents_memory_entries" }o--|| "agents_resources" : "FOREIGN KEY (resourceId) REFERENCES agents_resources (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE"
|
||||
"agents_memory_entries" }o--|| "agents" : "FOREIGN KEY (agentId) REFERENCES agents (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE"
|
||||
@@ -476,6 +476,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -57,6 +57,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -54,6 +54,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -66,6 +66,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -83,6 +83,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -60,6 +60,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -65,6 +65,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -56,6 +56,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -54,6 +54,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<summary><strong>Table Definition</strong></summary>
|
||||
|
||||
```sql
|
||||
CREATE TABLE "agents" ("id" varchar(36) PRIMARY KEY NOT NULL, "name" varchar(128) NOT NULL, "projectId" varchar(255) NOT NULL, "integrations" text NOT NULL DEFAULT ('[]'), "schema" text, "tools" text NOT NULL DEFAULT ('{}'), "skills" text NOT NULL DEFAULT ('{}'), "versionId" varchar(36), "createdAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "updatedAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "activeVersionId" varchar(36), CONSTRAINT "FK_940597dfe9753375309ce6aeea0" FOREIGN KEY ("activeVersionId") REFERENCES "agent_history" ("versionId") ON DELETE SET NULL ON UPDATE NO ACTION, CONSTRAINT "FK_a30d560207c4071d98aa03c179c" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)
|
||||
CREATE TABLE "agents" ("id" varchar(36) PRIMARY KEY NOT NULL, "name" varchar(128) NOT NULL, "projectId" varchar(255) NOT NULL, "integrations" text NOT NULL DEFAULT ('[]'), "schema" text, "tools" text NOT NULL DEFAULT ('{}'), "skills" text NOT NULL DEFAULT ('{}'), "versionId" varchar(36), "createdAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "updatedAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "activeVersionId" varchar(36), "availableInMCP" boolean NOT NULL DEFAULT (false), CONSTRAINT "FK_a30d560207c4071d98aa03c179c" FOREIGN KEY ("projectId") REFERENCES "project" ("id") ON DELETE CASCADE ON UPDATE NO ACTION, CONSTRAINT "FK_940597dfe9753375309ce6aeea0" FOREIGN KEY ("activeVersionId") REFERENCES "agent_history" ("versionId") ON DELETE SET NULL ON UPDATE NO ACTION)
|
||||
```
|
||||
|
||||
</details>
|
||||
@@ -16,6 +16,7 @@ CREATE TABLE "agents" ("id" varchar(36) PRIMARY KEY NOT NULL, "name" varchar(128
|
||||
| Name | Type | Default | Nullable | Children | Parents | Comment |
|
||||
| ---- | ---- | ------- | -------- | -------- | ------- | ------- |
|
||||
| activeVersionId | varchar(36) | | true | | [agent_history](agent_history.md) | |
|
||||
| availableInMCP | boolean | false | false | | | |
|
||||
| createdAt | datetime(3) | STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW') | false | | | |
|
||||
| id | varchar(36) | | false | [agent_chat_subscriptions](agent_chat_subscriptions.md) [agent_checkpoints](agent_checkpoints.md) [agent_eval_dataset](agent_eval_dataset.md) [agent_execution_threads](agent_execution_threads.md) [agent_files](agent_files.md) [agent_history](agent_history.md) [agent_task_definition](agent_task_definition.md) [agent_task_run_lock](agent_task_run_lock.md) [agents_memory_entries](agents_memory_entries.md) [agents_memory_entry_cursors](agents_memory_entry_cursors.md) [agents_memory_entry_locks](agents_memory_entry_locks.md) [agents_memory_entry_sources](agents_memory_entry_sources.md) [agents_observation_cursors](agents_observation_cursors.md) [agents_observation_locks](agents_observation_locks.md) [agents_observations](agents_observations.md) | | |
|
||||
| integrations | TEXT | '[]' | false | | | |
|
||||
@@ -31,8 +32,8 @@ CREATE TABLE "agents" ("id" varchar(36) PRIMARY KEY NOT NULL, "name" varchar(128
|
||||
|
||||
| Name | Type | Definition |
|
||||
| ---- | ---- | ---------- |
|
||||
| - (Foreign key ID: 0) | FOREIGN KEY | FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE |
|
||||
| - (Foreign key ID: 1) | FOREIGN KEY | FOREIGN KEY (activeVersionId) REFERENCES agent_history (versionId) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE |
|
||||
| - (Foreign key ID: 0) | FOREIGN KEY | FOREIGN KEY (activeVersionId) REFERENCES agent_history (versionId) ON UPDATE NO ACTION ON DELETE SET NULL MATCH NONE |
|
||||
| - (Foreign key ID: 1) | FOREIGN KEY | FOREIGN KEY (projectId) REFERENCES project (id) ON UPDATE NO ACTION ON DELETE CASCADE MATCH NONE |
|
||||
| id | PRIMARY KEY | PRIMARY KEY (id) |
|
||||
| sqlite_autoindex_agents_1 | PRIMARY KEY | PRIMARY KEY (id) |
|
||||
|
||||
@@ -69,6 +70,7 @@ erDiagram
|
||||
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -77,6 +77,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -57,6 +57,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -57,6 +57,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -69,6 +69,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -57,6 +57,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -61,6 +61,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -76,6 +76,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -108,6 +108,7 @@ erDiagram
|
||||
}
|
||||
"agents" {
|
||||
varchar_36_ activeVersionId FK
|
||||
boolean availableInMCP
|
||||
datetime_3_ createdAt
|
||||
varchar_36_ id PK
|
||||
TEXT integrations
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import type { MigrationContext, ReversibleMigration } from '../migration-types';
|
||||
|
||||
export class AddAvailableInMcpToAgents1784897791636 implements ReversibleMigration {
|
||||
async up({ schemaBuilder: { addColumns, column } }: MigrationContext) {
|
||||
await addColumns(
|
||||
'agents',
|
||||
[
|
||||
column('availableInMCP')
|
||||
.bool.notNull.default(false)
|
||||
.comment('Whether MCP clients granted agent scopes may operate on this agent'),
|
||||
],
|
||||
{ recreatesOnSqlite: true },
|
||||
);
|
||||
}
|
||||
|
||||
async down({ schemaBuilder: { dropColumns } }: MigrationContext) {
|
||||
await dropColumns('agents', ['availableInMCP'], { recreatesOnSqlite: true });
|
||||
}
|
||||
}
|
||||
@@ -229,6 +229,7 @@ import { CreateWorkflowReviewRequestTables1784000000052 } from '../common/178400
|
||||
import { AddStoredAtToAgentExecution1784815940110 } from '../common/1784815940110-AddStoredAtToAgentExecution';
|
||||
import { AddInstanceCredentials1784815940111 } from '../common/1784815940111-AddInstanceCredentials';
|
||||
import { CreateAgentEvalTables1784815940112 } from '../common/1784815940112-CreateAgentEvalTables';
|
||||
import { AddAvailableInMcpToAgents1784897791636 } from '../common/1784897791636-AddAvailableInMcpToAgents';
|
||||
import type { Migration } from '../migration-types';
|
||||
|
||||
export const postgresMigrations: Migration[] = [
|
||||
@@ -463,4 +464,5 @@ export const postgresMigrations: Migration[] = [
|
||||
AddStoredAtToAgentExecution1784815940110,
|
||||
AddInstanceCredentials1784815940111,
|
||||
CreateAgentEvalTables1784815940112,
|
||||
AddAvailableInMcpToAgents1784897791636,
|
||||
];
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import { AddAvailableInMcpToAgents1784897791636 as BaseMigration } from '../common/1784897791636-AddAvailableInMcpToAgents';
|
||||
|
||||
/**
|
||||
* Adding a column recreates `agents` on SQLite, and several agent tables have
|
||||
* CASCADE FKs to it. Disable FKs for the migration's duration.
|
||||
*/
|
||||
export class AddAvailableInMcpToAgents1784897791636 extends BaseMigration {
|
||||
withFKsDisabled = true as const;
|
||||
}
|
||||
@@ -58,6 +58,7 @@ import { AddProjectIdToInstanceAiThread1784000000028 } from './1784000000028-Add
|
||||
import { AllowAzureStoredAt1784000000034 } from './1784000000034-AllowAzureStoredAt';
|
||||
import { DropAgentDescriptionFromAgents1784000000037 } from './1784000000037-DropAgentDescriptionFromAgents';
|
||||
import { AddRecurringCronScheduleKind1784000000045 } from './1784000000045-AddRecurringCronScheduleKind';
|
||||
import { AddAvailableInMcpToAgents1784897791636 } from './1784897791636-AddAvailableInMcpToAgents';
|
||||
import { UniqueWorkflowNames1620821879465 } from '../common/1620821879465-UniqueWorkflowNames';
|
||||
import { UpdateWorkflowCredentials1630330987096 } from '../common/1630330987096-UpdateWorkflowCredentials';
|
||||
import { AddNodeIds1658930531669 } from '../common/1658930531669-AddNodeIds';
|
||||
@@ -445,6 +446,7 @@ const sqliteMigrations: Migration[] = [
|
||||
AddStoredAtToAgentExecution1784815940110,
|
||||
AddInstanceCredentials1784815940111,
|
||||
CreateAgentEvalTables1784815940112,
|
||||
AddAvailableInMcpToAgents1784897791636,
|
||||
];
|
||||
|
||||
export { sqliteMigrations };
|
||||
|
||||
@@ -0,0 +1,235 @@
|
||||
import {
|
||||
createTestMigrationContext,
|
||||
initDbUpToMigration,
|
||||
runSingleMigration,
|
||||
undoLastSingleMigration,
|
||||
type TestMigrationContext,
|
||||
} from '@n8n/backend-test-utils';
|
||||
import { DbConnection } from '@n8n/db';
|
||||
import { Container } from '@n8n/di';
|
||||
import { DataSource } from '@n8n/typeorm';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
|
||||
const MIGRATION_NAME = 'AddAvailableInMcpToAgents1784897791636';
|
||||
|
||||
describe('AddAvailableInMcpToAgents Migration', () => {
|
||||
let dataSource: DataSource;
|
||||
|
||||
async function withContext<T>(fn: (context: TestMigrationContext) => Promise<T>): Promise<T> {
|
||||
const context = createTestMigrationContext(dataSource);
|
||||
try {
|
||||
return await fn(context);
|
||||
} finally {
|
||||
await context.queryRunner.release();
|
||||
}
|
||||
}
|
||||
|
||||
beforeAll(async () => {
|
||||
const dbConnection = Container.get(DbConnection);
|
||||
await dbConnection.init();
|
||||
dataSource = Container.get(DataSource);
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await withContext(async (context) => {
|
||||
await context.queryRunner.clearDatabase();
|
||||
});
|
||||
await initDbUpToMigration(MIGRATION_NAME);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
const dbConnection = Container.get(DbConnection);
|
||||
await dbConnection.close();
|
||||
});
|
||||
|
||||
async function insertProject(context: TestMigrationContext, id: string): Promise<void> {
|
||||
const tableName = context.escape.tableName('project');
|
||||
await context.runQuery(
|
||||
`INSERT INTO ${tableName} ("id", "name", "type", "createdAt", "updatedAt")
|
||||
VALUES (:id, :name, :type, :createdAt, :updatedAt)`,
|
||||
{
|
||||
id,
|
||||
name: `project-${id.slice(0, 8)}`,
|
||||
type: 'personal',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
async function insertAgent(
|
||||
context: TestMigrationContext,
|
||||
data: { id: string; projectId: string },
|
||||
): Promise<void> {
|
||||
const tableName = context.escape.tableName('agents');
|
||||
await context.runQuery(
|
||||
`INSERT INTO ${tableName}
|
||||
("id", "name", "projectId", "integrations", "tools", "skills", "createdAt", "updatedAt")
|
||||
VALUES (:id, :name, :projectId, :integrations, :tools, :skills, :createdAt, :updatedAt)`,
|
||||
{
|
||||
id: data.id,
|
||||
name: `agent-${data.id.slice(0, 8)}`,
|
||||
projectId: data.projectId,
|
||||
integrations: '[]',
|
||||
tools: '{}',
|
||||
skills: '{}',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
async function insertAgentHistory(
|
||||
context: TestMigrationContext,
|
||||
data: { versionId: string; agentId: string },
|
||||
): Promise<void> {
|
||||
const tableName = context.escape.tableName('agent_history');
|
||||
await context.runQuery(
|
||||
`INSERT INTO ${tableName} ("versionId", "agentId", "author", "createdAt", "updatedAt")
|
||||
VALUES (:versionId, :agentId, :author, :createdAt, :updatedAt)`,
|
||||
{
|
||||
versionId: data.versionId,
|
||||
agentId: data.agentId,
|
||||
author: 'Test User',
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
async function getColumnMeta(context: TestMigrationContext, columnName: string) {
|
||||
if (context.isSqlite) {
|
||||
const rows: Array<{ name: string; notnull: number; dflt_value: string | null }> =
|
||||
await context.queryRunner.query(`PRAGMA table_info(${context.escape.tableName('agents')})`);
|
||||
return rows.find((r) => r.name === columnName);
|
||||
}
|
||||
const rows: Array<{
|
||||
column_name: string;
|
||||
is_nullable: string;
|
||||
column_default: string | null;
|
||||
}> = await context.queryRunner.query(
|
||||
'SELECT column_name, is_nullable, column_default FROM information_schema.columns WHERE table_name = $1 AND column_name = $2',
|
||||
[`${context.tablePrefix}agents`, columnName],
|
||||
);
|
||||
return rows[0];
|
||||
}
|
||||
|
||||
describe('up', () => {
|
||||
it('should add availableInMCP as NOT NULL with default false', async () => {
|
||||
await runSingleMigration(MIGRATION_NAME);
|
||||
dataSource = Container.get(DataSource);
|
||||
|
||||
await withContext(async (context) => {
|
||||
const col = await getColumnMeta(context, 'availableInMCP');
|
||||
expect(col).toBeDefined();
|
||||
if (context.isSqlite) {
|
||||
expect((col as { notnull: number }).notnull).toBe(1);
|
||||
} else {
|
||||
expect((col as { is_nullable: string }).is_nullable).toBe('NO');
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should backfill false on existing agents', async () => {
|
||||
const projectId = randomUUID();
|
||||
const agentId = randomUUID();
|
||||
|
||||
await withContext(async (context) => {
|
||||
await insertProject(context, projectId);
|
||||
await insertAgent(context, { id: agentId, projectId });
|
||||
});
|
||||
|
||||
await runSingleMigration(MIGRATION_NAME);
|
||||
dataSource = Container.get(DataSource);
|
||||
|
||||
await withContext(async (context) => {
|
||||
const rows = await context.runQuery<Array<{ availableInMCP: boolean | number }>>(
|
||||
`SELECT "availableInMCP" FROM ${context.escape.tableName('agents')} WHERE "id" = :id`,
|
||||
{ id: agentId },
|
||||
);
|
||||
expect(rows).toHaveLength(1);
|
||||
expect(Boolean(rows[0].availableInMCP)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('should default availableInMCP to false on inserts that omit it', async () => {
|
||||
await runSingleMigration(MIGRATION_NAME);
|
||||
dataSource = Container.get(DataSource);
|
||||
|
||||
const projectId = randomUUID();
|
||||
const agentId = randomUUID();
|
||||
|
||||
await withContext(async (context) => {
|
||||
await insertProject(context, projectId);
|
||||
await insertAgent(context, { id: agentId, projectId });
|
||||
|
||||
const rows = await context.runQuery<Array<{ availableInMCP: boolean | number }>>(
|
||||
`SELECT "availableInMCP" FROM ${context.escape.tableName('agents')} WHERE "id" = :id`,
|
||||
{ id: agentId },
|
||||
);
|
||||
expect(Boolean(rows[0].availableInMCP)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve rows in tables with CASCADE FKs to agents', async () => {
|
||||
// On SQLite the migration recreates `agents` (drop + rename), which
|
||||
// would cascade-delete child rows unless FKs are disabled for the
|
||||
// migration's duration (withFKsDisabled on the sqlite subclass).
|
||||
const projectId = randomUUID();
|
||||
const agentId = randomUUID();
|
||||
const versionId = randomUUID();
|
||||
|
||||
await withContext(async (context) => {
|
||||
await insertProject(context, projectId);
|
||||
await insertAgent(context, { id: agentId, projectId });
|
||||
await insertAgentHistory(context, { versionId, agentId });
|
||||
});
|
||||
|
||||
await runSingleMigration(MIGRATION_NAME);
|
||||
dataSource = Container.get(DataSource);
|
||||
|
||||
await withContext(async (context) => {
|
||||
const agentRows = await context.runQuery<Array<{ id: string }>>(
|
||||
`SELECT "id" FROM ${context.escape.tableName('agents')} WHERE "id" = :id`,
|
||||
{ id: agentId },
|
||||
);
|
||||
expect(agentRows).toHaveLength(1);
|
||||
|
||||
const historyRows = await context.runQuery<Array<{ versionId: string }>>(
|
||||
`SELECT "versionId" FROM ${context.escape.tableName('agent_history')} WHERE "agentId" = :id`,
|
||||
{ id: agentId },
|
||||
);
|
||||
expect(historyRows).toHaveLength(1);
|
||||
expect(historyRows[0].versionId).toBe(versionId);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('down', () => {
|
||||
it('should remove the column and preserve child rows', async () => {
|
||||
const projectId = randomUUID();
|
||||
const agentId = randomUUID();
|
||||
const versionId = randomUUID();
|
||||
|
||||
await withContext(async (context) => {
|
||||
await insertProject(context, projectId);
|
||||
await insertAgent(context, { id: agentId, projectId });
|
||||
await insertAgentHistory(context, { versionId, agentId });
|
||||
});
|
||||
|
||||
await runSingleMigration(MIGRATION_NAME);
|
||||
await undoLastSingleMigration();
|
||||
dataSource = Container.get(DataSource);
|
||||
|
||||
await withContext(async (context) => {
|
||||
expect(await getColumnMeta(context, 'availableInMCP')).toBeUndefined();
|
||||
|
||||
const historyRows = await context.runQuery<Array<{ versionId: string }>>(
|
||||
`SELECT "versionId" FROM ${context.escape.tableName('agent_history')} WHERE "agentId" = :id`,
|
||||
{ id: agentId },
|
||||
);
|
||||
expect(historyRows).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user