php-mcp/src/Mod/Mcp/Tools/Concerns/RequiresWorkspaceContext.php
2026-01-26 20:57:41 +00:00

135 lines
3.8 KiB
PHP

<?php
declare(strict_types=1);
namespace Mod\Mcp\Tools\Concerns;
use Core\Mod\Tenant\Models\Workspace;
use Mod\Mcp\Context\WorkspaceContext;
use Mod\Mcp\Exceptions\MissingWorkspaceContextException;
/**
* Trait for MCP tools that require workspace context.
*
* This trait provides methods for validating and retrieving workspace context
* from the MCP request. Tools using this trait will throw
* MissingWorkspaceContextException if called without proper context.
*
* SECURITY: Workspace context must come from authentication (API key or session),
* never from user-supplied request parameters.
*/
trait RequiresWorkspaceContext
{
/**
* The current workspace context.
*/
protected ?WorkspaceContext $workspaceContext = null;
/**
* Get the tool name for error messages.
*/
protected function getToolName(): string
{
return property_exists($this, 'name') && $this->name
? $this->name
: class_basename(static::class);
}
/**
* Get the workspace context, throwing if not available.
*
* @throws MissingWorkspaceContextException
*/
protected function getWorkspaceContext(): WorkspaceContext
{
if ($this->workspaceContext) {
return $this->workspaceContext;
}
throw new MissingWorkspaceContextException($this->getToolName());
}
/**
* Get the workspace ID from context.
*
* @throws MissingWorkspaceContextException
*/
protected function getWorkspaceId(): int
{
return $this->getWorkspaceContext()->workspaceId;
}
/**
* Get the workspace model from context.
*
* @throws MissingWorkspaceContextException
*/
protected function getWorkspace(): Workspace
{
return $this->getWorkspaceContext()->getWorkspace();
}
/**
* Set the workspace context for this tool execution.
*/
public function setWorkspaceContext(WorkspaceContext $context): void
{
$this->workspaceContext = $context;
}
/**
* Set workspace context from a workspace model.
*/
public function setWorkspace(Workspace $workspace): void
{
$this->workspaceContext = WorkspaceContext::fromWorkspace($workspace);
}
/**
* Set workspace context from a workspace ID.
*/
public function setWorkspaceId(int $workspaceId): void
{
$this->workspaceContext = WorkspaceContext::fromId($workspaceId);
}
/**
* Check if workspace context is available.
*/
protected function hasWorkspaceContext(): bool
{
return $this->workspaceContext !== null;
}
/**
* Validate that a resource belongs to the current workspace.
*
* @throws \RuntimeException If the resource doesn't belong to this workspace
* @throws MissingWorkspaceContextException If no workspace context
*/
protected function validateResourceOwnership(int $resourceWorkspaceId, string $resourceType = 'resource'): void
{
$this->getWorkspaceContext()->validateOwnership($resourceWorkspaceId, $resourceType);
}
/**
* Require workspace context, throwing with a custom message if not available.
*
* @throws MissingWorkspaceContextException
*/
protected function requireWorkspaceContext(string $operation = 'this operation'): WorkspaceContext
{
if (! $this->workspaceContext) {
throw new MissingWorkspaceContextException(
$this->getToolName(),
sprintf(
"Workspace context is required for %s in tool '%s'. Authenticate with an API key or user session.",
$operation,
$this->getToolName()
)
);
}
return $this->workspaceContext;
}
}