ABDULKADERSAFI.COM
Back to Projects
Laravel Blade Tailwindcss FilamentPHP

Portfolio MCP Server: Giving AI a Safe, Typed API Into My Portfolio

A Model Context Protocol (MCP) server built on top of my Laravel + Filament portfolio, exposing every admin-managed resource — blogs, projects, services, experiences, education, contacts, and inquiries — as typed, ability-scoped tools that an AI assistant like Claude can call directly. I built it not to hand my site over to AI, but to learn the MCP integration patterns I now bring to client projects.

Project Overview

The Portfolio MCP Server is a Model Context Protocol server bolted directly onto this Laravel 12 + Filament portfolio. It turns the same data my admin panel manages into a set of typed, permission-scoped tools that any MCP-capable AI client — Claude Desktop, Claude Code, or my own agents — can discover and call over a single authenticated endpoint.

I want to be clear about the motivation up front: I did not build this to let an AI run my website. I built it to learn how MCP servers actually work — auth, tool design, scoping, structured output — so I can confidently design these integrations for client products. The portfolio was simply the safest, most familiar codebase to experiment on. You can read the full reasoning in the companion write-up: I Built an MCP Server for My Portfolio — Here's Why It Matters.

What it exposes

  • Blogs — list, read, create, update, publish/unpublish, delete, and attach categories.
  • Projects — full CRUD plus case-study fields, FAQ structured data, and category/stack attachment.
  • Services & Service Inquiries — manage offerings and the leads that come in against them.
  • Experiences, Education, Contacts — the rest of the CV/contact surface the Filament panel controls.

Core capabilities

  • One server, many resources — built with laravel/mcp, every Filament-managed model is surfaced through consistent list-*, get-*, create-*, update-*, and delete-* tools.
  • Ability-scoped access — tools are gated behind mcp:read, mcp:write, and mcp:delete abilities via Laravel Sanctum, so a token can be read-only by design.
  • Typed inputs & structured output — each tool ships a JSON schema, so the AI gets validated parameters and predictable, parseable responses instead of scraped HTML.
  • Discovery-first design — relationship helpers (list-categories before attach-categories) guide the model toward correct multi-step flows.
  • Media stays human — image/media fields are intentionally read-only over MCP; uploads remain a deliberate action in the Filament UI.

The Challenge

The hard part was never "can an AI edit a database row." It was building something I'd actually trust enough to point at a real, public-facing site — and learning the patterns well enough to repeat them for clients who will ask for exactly this.

That surfaced several concrete problems:

  1. AI should not have unbounded control. The whole point was not to let a model freely mutate or delete my live content. I needed a permission model where a token's blast radius is decided at issue time, not at call time — read-only by default, write and delete as explicit, separate grants.

  2. MCP is young, and "do it right" examples are scarce. Model Context Protocol tooling moves fast. I had to learn idiomatic server design — tool granularity, naming, schemas, error shapes — rather than copy a finished blueprint, because the patterns I land on here are the ones I'll hand to clients.

  3. Tools have to be safe and legible to a model. A badly designed tool surface invites the AI to guess: attaching categories that don't exist, creating inquiries against missing services, or destructively "fixing" data. The schema and discovery flow had to actively steer the model toward correct sequences.

  4. One auth story across many resources. Blogs, projects, services, experiences, education, contacts, and inquiries all needed to live behind the same endpoint and the same Sanctum-backed ability checks, without bolting bespoke auth onto each tool.

  5. Some actions must stay human. Media uploads, in particular, shouldn't be automatable over a text protocol — they're a judgment call. The challenge was drawing that line cleanly instead of exposing everything just because I could.

  6. It runs on a production portfolio. This isn't a throwaway sandbox. Whatever I shipped had to coexist with a live Laravel + Filament app, real caching, and real SEO-critical content without putting any of it at risk.

The Solution

I built the MCP server inside the existing portfolio using laravel/mcp, reusing the same Eloquent models and authorization that power the Filament admin panel — so there's one source of truth for both the human UI and the AI interface.

1. Ability-scoped tools over Sanctum

Every tool declares which ability it requires:

  • mcp:read — all list-* and get-* tools.
  • mcp:writecreate-*, update-*, publish-*/unpublish-*, and attach-*/detach-*.
  • mcp:delete — only the destructive delete-* tools.

Tokens are minted with exactly the abilities they need. A read-only token physically cannot mutate data, because the capability was never granted — control is decided at the token, not trusted to the model at runtime. This directly answers the "I don't want AI controlling my site" requirement: the AI's power is whatever I chose to issue, and nothing more.

2. Consistent, discoverable tool surface

Each resource follows the same verb pattern (list, get, create, update, delete, plus resource-specific actions like publish or attach-categories). Predictable naming means a model can generalize from one resource to the next instead of re-learning each one.

3. Schemas that prevent guessing

Tools expose JSON schemas with descriptions and a documented discovery flow — e.g. call list-categories before attach-categories-to-project, or list-services before creating a service inquiry. The model is nudged toward valid IDs and valid sequences rather than hallucinating them.

4. Structured output, not scraping

Responses are typed JSON (ids, slugs, statuses, relationships) so the AI consumes clean data and returns parseable results — the same data the Filament resources operate on, never a brittle scrape of the rendered site.

5. A deliberate human boundary

Image and media fields are read-only over MCP. Uploads stay in the Filament UI on purpose: it's the one place where a human's judgment about brand assets matters more than automation convenience.

6. Reuse, not reinvention

Because the server sits on the existing models, policies, and caching strategy, it inherited the portfolio's security headers, rate limiting, and cache invalidation for free — no parallel data layer, no duplicated business rules.

Results

The portfolio now speaks MCP: an AI client can read and (with the right token) manage real content through one authenticated, ability-scoped endpoint — while destructive power stays opt-in and media stays human. More importantly, it became my reference implementation. The auth model, tool granularity, schema discipline, and human-in-the-loop boundaries I worked out here are exactly the patterns I now reach for when a client asks, "can our product talk to AI safely?" The full rationale lives in the blog post: I Built an MCP Server for My Portfolio — Here's Why It Matters.

Project Info

ROLE Solo Developer
TIMELINE 2 Weeks
YEAR 2026
STATUS
Completed

Tech Stack

Laravel
Blade
Tailwindcss
FilamentPHP
NEXT PROJECT KIF: A modern, dark-aesthetic rebrand of Kuwait International Fair's web presence
View Project
FAQ

Frequently Asked Questions

What is the Portfolio MCP Server?

It is a Model Context Protocol (MCP) server built into Abdulkader Safi's Laravel 12 and Filament portfolio. It exposes the site's admin-managed resources — blogs, projects, services, experiences, education, contacts, and service inquiries — as typed, permission-scoped tools that an MCP-capable AI client such as Claude can discover and call over a single authenticated endpoint. It reuses the same Eloquent models and authorization that power the Filament admin panel, so there is one source of truth for both the human UI and the AI interface.

Why build an MCP server for your portfolio — doesn't that mean letting AI control your site?

No. It was built to learn how MCP servers work in practice — authentication, tool design, scoping, and structured output — not to hand control of the site to an AI. The portfolio was simply the safest and most familiar codebase to experiment on. The goal was to develop reliable MCP integration patterns that can then be applied to client products, where the question 'can our product talk to AI safely?' comes up often.

How is the AI prevented from doing damage?

Access is controlled with Laravel Sanctum abilities. Read tools require mcp:read, write tools require mcp:write, and destructive delete tools require mcp:delete. Tokens are issued with only the abilities they need, so a read-only token physically cannot mutate or delete data because the capability was never granted. Control is decided at the token level rather than trusted to the model at runtime, and destructive power is always opt-in.

What can the AI actually do through it?

With the right token it can list, read, create, update, publish or unpublish, and delete blogs, projects, services, experiences, education entries, contacts, and service inquiries, plus attach categories and technology stacks. Image and media fields are intentionally read-only over MCP — uploads remain a deliberate human action in the Filament admin UI.

What was used to build it?

It is built with the laravel/mcp package on top of the existing Laravel 12 and Filament v3 portfolio, with Laravel Sanctum providing the ability-scoped token authentication. Because the server sits on the existing models, policies, and caching strategy, it inherited the portfolio's security headers, rate limiting, and cache invalidation without a parallel data layer.

Where can I read more about the reasoning behind it?

There is a companion article that explains the full motivation and approach: 'I Built an MCP Server for My Portfolio — Here's Why It Matters', available at https://abdulkadersafi.com/blog/i-built-an-mcp-server-for-my-portfolio-heres-why-it-matters.

GET IN TOUCH

Let's Build Something Together

Have a project in mind, want to collaborate on a web or mobile app, or just want to say hi? My inbox is open.

Get in Touch
safi.abdulkader@gmail.com +965 60787763 Based in Kuwait & Lebanon