1. Go to this page and download the library: Download padosoft/askmydocs-mcp-pack library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
padosoft / askmydocs-mcp-pack example snippets
namespace App\Mcp;
use App\Ai\AiManager;
use Padosoft\AskMyDocsMcpPack\Contracts\McpHostBridgeContract;
use Padosoft\AskMyDocsMcpPack\Support\HostChatResponse;
use Padosoft\AskMyDocsMcpPack\Support\HostChatTurn;
final class MyHostBridge implements McpHostBridgeContract
{
public function __construct(private readonly AiManager $ai) {}
public function chat(HostChatTurn $turn): HostChatResponse
{
// Translate $turn->tools into your provider's tool-calling shape.
$providerTools = array_map(
fn($tool) => [
'type' => 'function',
'function' => [
'name' => $tool->name(),
'description' => $tool->description(),
'parameters' => $tool->schema(),
],
],
$turn->tools,
);
$response = $this->ai->chatWithHistory('', $turn->messages, [
'tools' => $providerTools,
'tool_choice' => 'auto',
] + $turn->extras);
return new HostChatResponse(
content: $response->content,
toolCalls: $this->normalizeToolCalls($response->toolCalls),
provider: $response->provider,
model: $response->model,
);
}
public function supportsToolCalling(): bool
{
return in_array($this->ai->provider()->name(), ['openai', 'openrouter'], true);
}
private function normalizeToolCalls(?array $raw): array
{
return collect($raw ?? [])->map(fn($c) => [
'id' => $c['id'],
'name' => $c['function']['name'] ?? $c['name'],
'arguments' => is_string($c['function']['arguments'] ?? '')
? json_decode($c['function']['arguments'], true) ?? []
: ($c['arguments'] ?? []),
])->all();
}
}
use Padosoft\AskMyDocsMcpPack\Contracts\McpHostBridgeContract;
$this->app->singleton(McpHostBridgeContract::class, App\Mcp\MyHostBridge::class);
use Padosoft\AskMyDocsMcpPack\Contracts\McpServerRegistryContract;
use Padosoft\AskMyDocsMcpPack\Defaults\InMemoryMcpServer;
use Padosoft\AskMyDocsMcpPack\Defaults\InMemoryMcpServerRegistry;
$this->app->singleton(McpServerRegistryContract::class, function () {
$registry = new InMemoryMcpServerRegistry();
$registry->add(new InMemoryMcpServer(
id: 'fs',
name: 'Filesystem',
transport: 'stdio',
tenantId: null, // platform-global
transportConfig: [
'command' => 'npx',
'args' => ['-y', '@modelcontextprotocol/server-filesystem', '/data'],
'timeout_ms' => 10_000,
],
allowedTools: ['read_file', 'list_directory'],
));
return $registry;
});
use Padosoft\AskMyDocsMcpPack\Services\McpToolCallingService;
use Padosoft\AskMyDocsMcpPack\Support\HostMessage;
$svc = app(McpToolCallingService::class);
$response = $svc->chatWithTools(
messages: [
HostMessage::system('You are AskMyDocs. Use tools when grounded retrieval helps.'),
HostMessage::user('What did the deploy runbook change in March?'),
],
tenantId: 'acme',
actor: auth()->id(),
context: ['conversation_id' => 42, 'message_id' => 7],
);
return $response->content;
final class EloquentMcpServerRegistry implements McpServerRegistryContract
{
public function forTenant(?string $tenantId): array
{
return McpServer::query()
->where('tenant_id', $tenantId)
->where('enabled', true)
->get()
->map(fn($m) => new InMemoryMcpServer(
id: (string) $m->id,
name: $m->name,
transport: $m->transport,
tenantId: $m->tenant_id,
transportConfig: $m->transport_config ?? [],
allowedTools: $m->allowed_tools ?? [],
))
->all();
}
public function find(string $id): ?McpServerContract
{
$m = McpServer::query()->where('id', $id)->where('enabled', true)->first();
return $m === null ? null : new InMemoryMcpServer(/* same wrap as above */);
}
}
$this->app->singleton(McpServerRegistryContract::class, EloquentMcpServerRegistry::class);
final class SpatieMcpToolAuthorizer implements McpToolAuthorizerContract
{
public function authorize(mixed $actor, ?string $tenantId, McpToolContract $tool): bool
{
if (! $actor instanceof User) { return false; }
if (! $actor->hasAnyRole(['admin', 'super-admin'])) { return false; }
$permission = $tool->isReadOnly() ? "mcp.{$tool->name()}.read" : "mcp.{$tool->name()}.write";
return $actor->hasPermissionTo($permission);
}
}
// config/mcp-pack.php — point the package at the host subclass
return ['audit_model' => \App\Models\McpToolCallAudit::class];
// app/Providers/AppServiceProvider.php — wire alerting to the events
use Illuminate\Support\Facades\Event;
use Padosoft\AskMyDocsMcpPack\Resilience\Events\CircuitOpened;
use Padosoft\AskMyDocsMcpPack\Resilience\Events\RetryExhausted;
Event::listen(CircuitOpened::class, function (CircuitOpened $e): void {
// Page on-call: a server's tool is failing fast.
});
Event::listen(RetryExhausted::class, function (RetryExhausted $e): void {
// Dashboard tile: which (tenant, server) is burning its budget.
});
use Padosoft\AskMyDocsMcpPack\Services\McpClient;
use Padosoft\AskMyDocsMcpPack\Tests\Support\StubMcpTransport;
$transport = (new StubMcpTransport())
->scriptInitialize()
->scriptListTools([['name' => 'kb_search', 'description' => '...', 'inputSchema' => []]])
->scriptToolCall('kb_search', ['hits' => [['title' => 'Doc A']]]);
McpClient::useTransportResolver(fn() => $transport);
// drive your chat flow — every JSON-RPC call hits the stub.