ChatGPT and Claude are becoming a real traffic source. People ask an AI "where should I launch my SaaS?" instead of Googling it. If the AI can't read your data, you're not in the answer.
So I gave my launch platform, Noonlaunch, an MCP server. Any AI agent can now search the product directory, pull weekly launch winners, and query my curated list of 333 launch directories, live at https://noonlaunch.com/mcp. It took an afternoon. Here's the whole thing.
What MCP is, in one paragraph
Model Context Protocol is a standard that lets AI clients (Claude, Cursor, and a growing list) call tools you define over HTTP. You describe each tool with a name, a description, and a JSON schema for its inputs. The AI decides when to call them and gets structured data back. Think "API endpoints, but the consumer is a language model that reads your descriptions to decide what to call."
The setup
Laravel has an official package for this:
composer require laravel/mcp
Requires Laravel 12 / PHP 8.2+. I'm on laravel/mcp ^0.9.3.
Registering a server is one line in routes/ai.php:
use App\Mcp\NoonlaunchServer;
use Laravel\Mcp\Facades\Mcp;
Mcp::web('/mcp', NoonlaunchServer::class)
->middleware('throttle:60,1')
->name('mcp.noonlaunch');
Note the throttle. Agents can be enthusiastic; rate limiting is not optional.
The server class
The server declares its tools and, crucially, its instructions. The instructions are your prompt to every AI that connects, so treat them like documentation:
#[Name('Noonlaunch')]
#[Version('1.0.0')]
#[Instructions('Noonlaunch is a product launch platform: makers launch products, the community votes, and the weekly top 3 win a badge and a dofollow backlink. Use search-directory to find products, get-weekly-winners for a week\'s launch board... All data is public and read-only.')]
class NoonlaunchServer extends Server
{
protected array $tools = [
SearchDirectory::class,
GetProduct::class,
GetWeeklyWinners::class,
ListLaunchDirectories::class,
];
}
A tool is just a class
Here's the search tool, trimmed. Two things to notice: inputs go through Laravel's normal validate(), and the schema descriptions are written for an AI reader:
#[Description('Search the Noonlaunch product directory. Returns approved products matching the query, ordered by community votes.')]
class SearchDirectory extends Tool
{
public function handle(Request $request): Response
{
$args = $request->validate([
'query' => ['required', 'string', 'min:2', 'max:100'],
'limit' => ['nullable', 'integer', 'min:1', 'max:25'],
]);
$products = Product::approved()
->where('name', 'like', "%{$args['query']}%")
->orderByDesc('vote_count')
->limit($args['limit'] ?? 10)
->get();
return Response::json($products->map(fn ($p) => [
'name' => $p->name,
'tagline' => $p->tagline,
'votes' => $p->vote_count,
'noonlaunch_url' => route('product.show', $p),
])->values()->all());
}
public function schema(JsonSchema $schema): array
{
return [
'query' => $schema->string()->description('Search term matched against product names, taglines and descriptions.'),
'limit' => $schema->integer()->description('Max results to return (1-25, default 10).'),
];
}
}
Lessons from doing it
- Keep it read-only until you have real auth. My four tools only ever SELECT. An MCP endpoint is a public API; every rule about exposing APIs applies, plus your consumer is a very persuadable robot.
- Validate like it's user input, because it is. The AI constructs the arguments. Min/max lengths, capped limits, no raw input near a query.
- Return URLs in every payload. I include noonlaunch_url on every product. When an AI cites your data, you want it linking back to you. That's the whole growth loop.
- Empty results deserve words, not []. Returning "No products found, try a broader query" teaches the agent to retry sensibly. An empty array teaches it nothing.
- Add a discovery card. I serve /.well-known/mcp/server-card.json describing the server, so agents and registries can find it without reading my docs.
Try it
If you use Claude Code:
claude mcp add --transport http noonlaunch
Then ask it "what won on Noonlaunch last week?"
Is anyone else exposing their app's data over MCP? I'm especially curious what write operations people are comfortable allowing.
Top comments (0)