Compare commits
No commits in common. "main" and "dev" have entirely different histories.
5 changed files with 129 additions and 143 deletions
|
|
@ -8,31 +8,29 @@ return new class extends Migration
|
|||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('mcp_api_requests')) {
|
||||
Schema::create('mcp_api_requests', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('request_id', 32)->unique();
|
||||
$table->foreignId('workspace_id')->nullable()->constrained('workspaces')->nullOnDelete();
|
||||
$table->foreignId('api_key_id')->nullable()->constrained('api_keys')->nullOnDelete();
|
||||
$table->string('method', 10);
|
||||
$table->string('path', 255);
|
||||
$table->json('headers')->nullable();
|
||||
$table->json('request_body')->nullable();
|
||||
$table->unsignedSmallInteger('response_status');
|
||||
$table->json('response_body')->nullable();
|
||||
$table->unsignedInteger('duration_ms')->default(0);
|
||||
$table->string('server_id', 64)->nullable();
|
||||
$table->string('tool_name', 128)->nullable();
|
||||
$table->text('error_message')->nullable();
|
||||
$table->string('ip_address', 45)->nullable();
|
||||
$table->timestamps();
|
||||
Schema::create('mcp_api_requests', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('request_id', 32)->unique();
|
||||
$table->foreignId('workspace_id')->nullable()->constrained('workspaces')->nullOnDelete();
|
||||
$table->foreignId('api_key_id')->nullable()->constrained('api_keys')->nullOnDelete();
|
||||
$table->string('method', 10);
|
||||
$table->string('path', 255);
|
||||
$table->json('headers')->nullable();
|
||||
$table->json('request_body')->nullable();
|
||||
$table->unsignedSmallInteger('response_status');
|
||||
$table->json('response_body')->nullable();
|
||||
$table->unsignedInteger('duration_ms')->default(0);
|
||||
$table->string('server_id', 64)->nullable();
|
||||
$table->string('tool_name', 128)->nullable();
|
||||
$table->text('error_message')->nullable();
|
||||
$table->string('ip_address', 45)->nullable();
|
||||
$table->timestamps();
|
||||
|
||||
$table->index(['workspace_id', 'created_at']);
|
||||
$table->index(['server_id', 'tool_name']);
|
||||
$table->index('created_at');
|
||||
$table->index('response_status');
|
||||
});
|
||||
}
|
||||
$table->index(['workspace_id', 'created_at']);
|
||||
$table->index(['server_id', 'tool_name']);
|
||||
$table->index('created_at');
|
||||
$table->index('response_status');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
|
|
|
|||
|
|
@ -8,40 +8,36 @@ return new class extends Migration
|
|||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('mcp_tool_metrics')) {
|
||||
Schema::create('mcp_tool_metrics', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('tool_name');
|
||||
$table->string('workspace_id')->nullable();
|
||||
$table->unsignedInteger('call_count')->default(0);
|
||||
$table->unsignedInteger('error_count')->default(0);
|
||||
$table->unsignedInteger('total_duration_ms')->default(0);
|
||||
$table->unsignedInteger('min_duration_ms')->nullable();
|
||||
$table->unsignedInteger('max_duration_ms')->nullable();
|
||||
$table->date('date');
|
||||
$table->timestamps();
|
||||
Schema::create('mcp_tool_metrics', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('tool_name');
|
||||
$table->string('workspace_id')->nullable();
|
||||
$table->unsignedInteger('call_count')->default(0);
|
||||
$table->unsignedInteger('error_count')->default(0);
|
||||
$table->unsignedInteger('total_duration_ms')->default(0);
|
||||
$table->unsignedInteger('min_duration_ms')->nullable();
|
||||
$table->unsignedInteger('max_duration_ms')->nullable();
|
||||
$table->date('date');
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['tool_name', 'workspace_id', 'date']);
|
||||
$table->index(['date', 'tool_name']);
|
||||
$table->index('workspace_id');
|
||||
});
|
||||
}
|
||||
$table->unique(['tool_name', 'workspace_id', 'date']);
|
||||
$table->index(['date', 'tool_name']);
|
||||
$table->index('workspace_id');
|
||||
});
|
||||
|
||||
// Table for tracking tool combinations (tools used together in sessions)
|
||||
if (! Schema::hasTable('mcp_tool_combinations')) {
|
||||
Schema::create('mcp_tool_combinations', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('tool_a');
|
||||
$table->string('tool_b');
|
||||
$table->string('workspace_id')->nullable();
|
||||
$table->unsignedInteger('occurrence_count')->default(0);
|
||||
$table->date('date');
|
||||
$table->timestamps();
|
||||
Schema::create('mcp_tool_combinations', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('tool_a');
|
||||
$table->string('tool_b');
|
||||
$table->string('workspace_id')->nullable();
|
||||
$table->unsignedInteger('occurrence_count')->default(0);
|
||||
$table->date('date');
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['tool_a', 'tool_b', 'workspace_id', 'date']);
|
||||
$table->index(['date', 'occurrence_count']);
|
||||
});
|
||||
}
|
||||
$table->unique(['tool_a', 'tool_b', 'workspace_id', 'date']);
|
||||
$table->index(['date', 'occurrence_count']);
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
|
|
|
|||
|
|
@ -8,20 +8,18 @@ return new class extends Migration
|
|||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('mcp_usage_quotas')) {
|
||||
Schema::create('mcp_usage_quotas', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('workspace_id')->constrained('workspaces')->cascadeOnDelete();
|
||||
$table->string('month', 7); // YYYY-MM format
|
||||
$table->unsignedBigInteger('tool_calls_count')->default(0);
|
||||
$table->unsignedBigInteger('input_tokens')->default(0);
|
||||
$table->unsignedBigInteger('output_tokens')->default(0);
|
||||
$table->timestamps();
|
||||
Schema::create('mcp_usage_quotas', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->foreignId('workspace_id')->constrained('workspaces')->cascadeOnDelete();
|
||||
$table->string('month', 7); // YYYY-MM format
|
||||
$table->unsignedBigInteger('tool_calls_count')->default(0);
|
||||
$table->unsignedBigInteger('input_tokens')->default(0);
|
||||
$table->unsignedBigInteger('output_tokens')->default(0);
|
||||
$table->timestamps();
|
||||
|
||||
$table->unique(['workspace_id', 'month']);
|
||||
$table->index('month');
|
||||
});
|
||||
}
|
||||
$table->unique(['workspace_id', 'month']);
|
||||
$table->index('month');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
|
|
|
|||
|
|
@ -8,70 +8,66 @@ return new class extends Migration
|
|||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('mcp_audit_logs')) {
|
||||
Schema::create('mcp_audit_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
Schema::create('mcp_audit_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
|
||||
// Tool execution details
|
||||
$table->string('server_id')->index();
|
||||
$table->string('tool_name')->index();
|
||||
$table->unsignedBigInteger('workspace_id')->nullable()->index();
|
||||
$table->string('session_id')->nullable()->index();
|
||||
// Tool execution details
|
||||
$table->string('server_id')->index();
|
||||
$table->string('tool_name')->index();
|
||||
$table->unsignedBigInteger('workspace_id')->nullable()->index();
|
||||
$table->string('session_id')->nullable()->index();
|
||||
|
||||
// Input/output (stored as JSON, may be redacted)
|
||||
$table->json('input_params')->nullable();
|
||||
$table->json('output_summary')->nullable();
|
||||
$table->boolean('success')->default(true);
|
||||
$table->unsignedInteger('duration_ms')->nullable();
|
||||
$table->string('error_code')->nullable();
|
||||
$table->text('error_message')->nullable();
|
||||
// Input/output (stored as JSON, may be redacted)
|
||||
$table->json('input_params')->nullable();
|
||||
$table->json('output_summary')->nullable();
|
||||
$table->boolean('success')->default(true);
|
||||
$table->unsignedInteger('duration_ms')->nullable();
|
||||
$table->string('error_code')->nullable();
|
||||
$table->text('error_message')->nullable();
|
||||
|
||||
// Actor information
|
||||
$table->string('actor_type')->nullable(); // user, api_key, system
|
||||
$table->unsignedBigInteger('actor_id')->nullable();
|
||||
$table->string('actor_ip', 45)->nullable(); // IPv4 or IPv6
|
||||
// Actor information
|
||||
$table->string('actor_type')->nullable(); // user, api_key, system
|
||||
$table->unsignedBigInteger('actor_id')->nullable();
|
||||
$table->string('actor_ip', 45)->nullable(); // IPv4 or IPv6
|
||||
|
||||
// Sensitive tool flagging
|
||||
$table->boolean('is_sensitive')->default(false)->index();
|
||||
$table->string('sensitivity_reason')->nullable();
|
||||
// Sensitive tool flagging
|
||||
$table->boolean('is_sensitive')->default(false)->index();
|
||||
$table->string('sensitivity_reason')->nullable();
|
||||
|
||||
// Hash chain for tamper detection
|
||||
$table->string('previous_hash', 64)->nullable(); // SHA-256 of previous entry
|
||||
$table->string('entry_hash', 64)->index(); // SHA-256 of this entry
|
||||
// Hash chain for tamper detection
|
||||
$table->string('previous_hash', 64)->nullable(); // SHA-256 of previous entry
|
||||
$table->string('entry_hash', 64)->index(); // SHA-256 of this entry
|
||||
|
||||
// Agent context
|
||||
$table->string('agent_type')->nullable();
|
||||
$table->string('plan_slug')->nullable();
|
||||
// Agent context
|
||||
$table->string('agent_type')->nullable();
|
||||
$table->string('plan_slug')->nullable();
|
||||
|
||||
// Timestamps (immutable - no updated_at updates after creation)
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
$table->timestamp('updated_at')->nullable();
|
||||
// Timestamps (immutable - no updated_at updates after creation)
|
||||
$table->timestamp('created_at')->useCurrent();
|
||||
$table->timestamp('updated_at')->nullable();
|
||||
|
||||
// Foreign key constraint
|
||||
$table->foreign('workspace_id')
|
||||
->references('id')
|
||||
->on('workspaces')
|
||||
->nullOnDelete();
|
||||
// Foreign key constraint
|
||||
$table->foreign('workspace_id')
|
||||
->references('id')
|
||||
->on('workspaces')
|
||||
->nullOnDelete();
|
||||
|
||||
// Composite indexes for common queries
|
||||
$table->index(['workspace_id', 'created_at']);
|
||||
$table->index(['tool_name', 'created_at']);
|
||||
$table->index(['is_sensitive', 'created_at']);
|
||||
$table->index(['actor_type', 'actor_id']);
|
||||
});
|
||||
}
|
||||
// Composite indexes for common queries
|
||||
$table->index(['workspace_id', 'created_at']);
|
||||
$table->index(['tool_name', 'created_at']);
|
||||
$table->index(['is_sensitive', 'created_at']);
|
||||
$table->index(['actor_type', 'actor_id']);
|
||||
});
|
||||
|
||||
// Table for tracking sensitive tool definitions
|
||||
if (! Schema::hasTable('mcp_sensitive_tools')) {
|
||||
Schema::create('mcp_sensitive_tools', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('tool_name')->unique();
|
||||
$table->string('reason');
|
||||
$table->json('redact_fields')->nullable(); // Fields to redact in audit logs
|
||||
$table->boolean('require_explicit_consent')->default(false);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
Schema::create('mcp_sensitive_tools', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('tool_name')->unique();
|
||||
$table->string('reason');
|
||||
$table->json('redact_fields')->nullable(); // Fields to redact in audit logs
|
||||
$table->boolean('require_explicit_consent')->default(false);
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
|
|
|
|||
|
|
@ -8,32 +8,30 @@ return new class extends Migration
|
|||
{
|
||||
public function up(): void
|
||||
{
|
||||
if (! Schema::hasTable('mcp_tool_versions')) {
|
||||
Schema::create('mcp_tool_versions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('server_id', 64)->index();
|
||||
$table->string('tool_name', 128);
|
||||
$table->string('version', 32); // semver: 1.0.0, 2.1.0-beta, etc.
|
||||
$table->json('input_schema')->nullable();
|
||||
$table->json('output_schema')->nullable();
|
||||
$table->text('description')->nullable();
|
||||
$table->text('changelog')->nullable();
|
||||
$table->text('migration_notes')->nullable(); // guidance for upgrading from previous version
|
||||
$table->boolean('is_latest')->default(false);
|
||||
$table->timestamp('deprecated_at')->nullable();
|
||||
$table->timestamp('sunset_at')->nullable(); // after this date, version is blocked
|
||||
$table->timestamps();
|
||||
Schema::create('mcp_tool_versions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('server_id', 64)->index();
|
||||
$table->string('tool_name', 128);
|
||||
$table->string('version', 32); // semver: 1.0.0, 2.1.0-beta, etc.
|
||||
$table->json('input_schema')->nullable();
|
||||
$table->json('output_schema')->nullable();
|
||||
$table->text('description')->nullable();
|
||||
$table->text('changelog')->nullable();
|
||||
$table->text('migration_notes')->nullable(); // guidance for upgrading from previous version
|
||||
$table->boolean('is_latest')->default(false);
|
||||
$table->timestamp('deprecated_at')->nullable();
|
||||
$table->timestamp('sunset_at')->nullable(); // after this date, version is blocked
|
||||
$table->timestamps();
|
||||
|
||||
// Unique constraint: one version per tool per server
|
||||
$table->unique(['server_id', 'tool_name', 'version'], 'mcp_tool_versions_unique');
|
||||
// Unique constraint: one version per tool per server
|
||||
$table->unique(['server_id', 'tool_name', 'version'], 'mcp_tool_versions_unique');
|
||||
|
||||
// Index for finding latest versions
|
||||
$table->index(['server_id', 'tool_name', 'is_latest'], 'mcp_tool_versions_latest');
|
||||
// Index for finding latest versions
|
||||
$table->index(['server_id', 'tool_name', 'is_latest'], 'mcp_tool_versions_latest');
|
||||
|
||||
// Index for finding deprecated/sunset versions
|
||||
$table->index(['deprecated_at', 'sunset_at'], 'mcp_tool_versions_lifecycle');
|
||||
});
|
||||
}
|
||||
// Index for finding deprecated/sunset versions
|
||||
$table->index(['deprecated_at', 'sunset_at'], 'mcp_tool_versions_lifecycle');
|
||||
});
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue