MCP, AI Coding Agent Integration

NativeBlade ships a built-in Model Context Protocol server so AI coding agents (Claude Code, Cursor, Windsurf, Cline, and anything MCP-compliant) can introspect the live state of your project instead of guessing from stale documentation.

Without MCP, an agent suggesting NativeBlade code is working blind. It paraphrases what it saw in training data, hallucinates methods that never existed, and references plugins the user hasn’t installed. With MCP, the agent calls the framework on demand and gets exact answers grounded in the version of NativeBlade actually installed in your vendor/.

Start the server

From your project root:

php artisan nativeblade:mcp

The server speaks JSON-RPC 2.0 over stdin/stdout. You normally don’t run it by hand. Your agent’s MCP client launches it for you when configured (see below).

Agent configuration

Claude Code

Add to ~/.claude/mcp_servers.json (global) or .mcp.json at the project root (per-project):

{
    "mcpServers": {
        "nativeblade": {
            "command": "php",
            "args": ["artisan", "nativeblade:mcp"]
        }
    }
}

Cursor

~/.cursor/mcp.json:

{
    "mcpServers": {
        "nativeblade": {
            "command": "php",
            "args": ["artisan", "nativeblade:mcp"]
        }
    }
}

Windsurf

~/.codeium/windsurf/mcp_config.json:

{
    "mcpServers": {
        "nativeblade": {
            "command": "php",
            "args": ["artisan", "nativeblade:mcp"]
        }
    }
}

Any other MCP client

Any client that speaks the standard stdio transport works. Point it at php artisan nativeblade:mcp and that’s it.

What the agent gets

Nine tools, called on demand. Nothing is loaded into context until the agent decides it needs it.

list_facade_methods

Returns every method on the NativeBlade and NativeBladeConfig facades, each with its signature and a one-line summary. The agent calls this first to discover what is available.

[
    {
        "facade": "NativeBlade",
        "purpose": "Runtime / native action builders...",
        "methods": [
            {"name": "notification", "signature": "NativeResponse notification(Closure $callback)", "static": true},
            {"name": "biometric",    "signature": "NativeResponse biometric(Closure $callback)",    "static": true},
            ...
        ]
    }
]

describe_facade_method

Full signature, summary, parameter list, return type, and (where available) a code example for one specific method. The agent calls this after finding the method it wants via list_facade_methods.

{
    "found": true,
    "name": "notification",
    "facade": "NativeBlade\\Facades\\NativeBlade",
    "signature": "NativeResponse notification(Closure $callback)",
    "summary": "Queue a system notification built via a fluent Notification builder.",
    "description": "Fire-and-forget, no result is returned to PHP.",
    "params": [{"name": "callback", "type": "Closure(Notification): void", "description": ""}],
    "source": "NativeBlade\\NativeResponse::notification()"
}

Reflection-based, so it works against the exact version of NativeBlade installed in your vendor/, not whatever was current when the agent’s training data was frozen.

publish_android and publish_ios

Guide an AI host through Google Play or App Store publication. Each tool reads the
configuration loaded by AppServiceProvider, resolves the effective plugins
(including all plugins when no selection is declared), and returns a dated guide,
official policy links, missing configuration and questions for the developer.
Always-on core plugins and custom plugin permission declarations are included.

{"release_type":"first_release","answers":{"account":"Organization account, verified","distribution":"Internal testing"}}

Start without arguments when the release type is unknown. Ask no more than three
questions per turn, explain choices, then pass confirmed answers by the returned
question ids to continue. Answers are not stored on the server. Do not pass secrets.
The host AI uses its project tools to inspect app behavior and its browser to
recheck official policies. Without browsing it must disclose the bundled review
date. Plugin inclusion is not a privacy declaration or proof of a user feature.

The tools prepare a publication plan; they do not authenticate, build, upload,
submit or release an app. See the Android guide and
iOS guide for the complete workflow and sources.

store_listing

Prepare one locale at a time, for Android, iOS or both. Supply confirmed product
facts and release changes. The tool assembles an initial draft; the AI host writes
the final copy and calls the tool again with metadata overrides for validation.

{
  "platform": "both",
  "locale": "pt-BR",
  "release_type": "update",
  "name": "Minha Agenda",
  "summary": "Organize seus compromissos em um só lugar.",
  "audience": "Pessoas que organizam compromissos pessoais",
  "features": ["Consulte os compromissos do dia."],
  "changes": ["Agora você pode editar lembretes."],
  "metadata": {"ios": {"subtitle": "Seus compromissos organizados", "keywords": "agenda,lembretes,calendário"}}
}

Results separate product descriptions, release notes and review notes. Validation
counts Unicode characters for normal fields and UTF-8 bytes for iOS keywords and
review notes. It flags missing text, excessive length, HTML and long dash
punctuation. It never silently truncates text. Passing text checks does not mean
the app is ready for submission. Required URLs, assets and console declarations
are covered by the publication guides. The guidance asks the AI to use clear
language and no em dash or en dash.

project_state

The NativeBlade configuration registered in the running Laravel process by the
application and package service providers: app name, declared and effective
plugins, custom plugins, platform configs, permissions, transition and framework
version. The version comes from Composer’s installed package metadata when available.

{
    "nativeblade_version": "1.7.8",
    "plugins": {
        "declared": ["media", "push", "biometric"],
        "all_available": ["media", "push", "geolocation", "biometric", ...],
        "effective": ["media", "push", "biometric", "dialog", "os", "process", "store", "fs", "opener"],
        "always_on": ["dialog", "os", "process", "store", "fs", "opener"],
        "mode": "explicit (declared plugins plus always-on core plugins)"
    },
    "transition": "slide",
    "app_configs": { "android": {...}, "ios": {...}, "desktop": {...} }
}

Use plugins.effective to decide which built-in capabilities are configured.
all_available is the framework catalog, not the app’s selection. A null
declared means all built-in plugins; an empty array means only the always-on
core set. Third-party plugins are listed separately under custom_plugins.

platform_status distinguishes an unconfigured platform from a configured one
with missing version fields. diagnostics reports an empty app configuration,
and project.base_path helps identify a client launched in the wrong project.
Unexpected read or serialization errors return an MCP tool error instead of
silently becoming null.

This tool does not watch PHP files or verify the compiled binary. After editing
AppServiceProvider or environment values, reconnect the MCP client so Laravel
boots again. If applicable, clear Laravel’s configuration cache first. Provider
code skipped during console execution will also be skipped by the MCP command.
configuration_source includes these limitations in every result.

list_docs

Returns the list of documentation pages with their topic and a short summary.
Each name is a path under the docs directory. The agent uses this to figure out
which page to read for a given question.

{
    "docs": [
        {"name": "core/animations.md", "title": "Animations", "summary": "..."},
        {"name": "core/plugins.md",    "title": "Plugins", "summary": "..."},
        ...
    ]
}

read_doc

Returns the full Markdown content of one page. Pass the path from list_docs. Only files inside the framework docs directory are readable, path traversal is blocked.

{ "name": "mobile/media.md" }

architecture_recipe

Returns the canonical NativeBlade pattern for a specific use case: component-controller, form-validation, global-state, push-handler, deep-link, biometric-flow, multiple-http-pool, repository-vs-eloquent, http-client, file-organization, enums-and-constants, i18n, debugging, anti-patterns. Call with no arguments to list every available recipe; call with use_case=<name> for the full text plus example code.

This is the opinionated tool. The other five describe what NativeBlade IS; this one tells the agent how to USE it. Agents that follow these recipes produce code that fits the framework’s architecture out of the box (thin Livewire controllers, services for business logic, typed state wrappers, push handlers as classes, etc.).

{ "use_case": "push-handler" }

The agent typically calls architecture_recipe() (no args) once to discover all recipes, then architecture_recipe(use_case='X') whenever generating code that touches X.

Typical agent flow

For a request like “add a camera button that uploads the photo to /api/uploads”, a well-behaved agent does:

  1. project_state(), confirms media plugin is declared and what permissions are set.
  2. list_facade_methods(), finds pickCamera, upload.
  3. describe_facade_method("pickCamera") + describe_facade_method("upload"), gets exact signatures.
  4. Generates code that compiles against the installed framework version on the first try.

Total tokens consumed: a few hundred. No 17 markdown files loaded up front.

Implementation notes

  • Transport: stdio. No HTTP server, no port, no auth surface. Each agent client spawns its own server process.
  • Reflection-based. When you add a method to NativeResponse or a case to the Plugin enum, the agent sees it on the next call. No manual sync.
  • Zero-config. No env vars, no setup script. Run the Artisan command and it works.
  • Sandboxed file access. read_doc only opens files inside the framework root, validated by regex and basename().
  • Protocol version negotiation. Server speaks 2025-11-25 (latest) and negotiates down to any of 2025-06-18, 2025-03-26, 2024-11-05 if the client requests an older one. Compatible with current Claude Code, Cursor, Windsurf, Cline releases.

Troubleshooting

Agent says it can’t find the server. Make sure php is on your PATH and the working directory in your MCP client config points at the project root (where artisan lives). Some clients let you set cwd explicitly in the config object.

Tool calls return errors. Make sure NativeBlade is fully installed (composer install) and the autoloader knows about the NativeBlade\Facades\* classes. The server reflects on real classes; if they aren’t loadable, the tool fails gracefully and reports the error back.

Want to verify the server works. Run the self-test:

php artisan nativeblade:mcp --test

You should see five green checkmarks confirming initialize, tools/list, and each of the live tools (project_state, list_docs, list_facade_methods) returning sane data.

Or pipe a JSON-RPC handshake by hand:

echo '{"jsonrpc":"2.0","id":1,"method":"initialize"}' | php artisan nativeblade:mcp

You should get back a single JSON line with serverInfo.name = "nativeblade".

Running it without arguments shows nothing? That’s actually a feature, not a bug, when you run php artisan nativeblade:mcp directly in a terminal, the command detects the interactive TTY and prints setup instructions to stderr instead of starting the JSON-RPC loop (which would just sit there waiting for messages no human would type). Run --test to verify, or pipe input as shown above.