How to Manage Projects Using MCP Tools in OpenSEO: A Complete Guide

Use the list_projects, create_project, and project_context MCP tools via JSON-RPC POST requests to /mcp to programmatically manage OpenSEO projects and their shared memory.

Projects in OpenSEO serve as the core container for all SEO data, and the Model-Connect-Protocol (MCP) server exposes a unified interface for AI agents to manage them. According to the every-app/open-seo source code, these tools delegate to the same internal services used by the dashboard UI, ensuring consistent behavior across all clients.

MCP Architecture for Project Management

The MCP implementation follows a layered architecture that separates transport concerns from business logic. Understanding these components helps diagnose issues and extend functionality.

Transport and Authentication Layer

The MCP Transport Layer (src/server/mcp/transport.ts) handles request validation, CORS, and injects the authenticated user or organization scope into every request. This ensures that all subsequent tool executions respect the caller's permissions before reaching business logic.

Core Services

All MCP tools delegate to two primary services:

Tool Registration

The MCP Tool Registry (src/server/mcp/server.ts) exposes the available methods to clients. Each tool is stateless: it receives a JSON-RPC request, delegates to the appropriate service, and returns a structured response containing human-readable text, metadata URLs, and machine-readable content.

Available MCP Tools for Project Operations

The OpenSEO MCP server exposes three primary tools for project management, each implemented in dedicated files under src/server/mcp/tools/.

list_projects

File: src/server/mcp/tools/list-projects.ts

Returns every project visible to the caller, scoped by organization or user. This tool accepts no arguments ({}) and returns an array of project objects containing id, name, domain, locationCode, languageCode, and url. When called with a user-scoped token, the response includes projects from all organizations the user belongs to, annotated with organization and organizationId fields.

create_project

File: src/server/mcp/tools/create-project.ts

Creates a new project within the caller's organization. The tool validates input using createProjectSchema, requiring name and optionally accepting domain, locationCode, and languageCode. The implementation mirrors the UI's server function exactly, ensuring data quality through shared validation logic.

project_context

File: src/server/mcp/tools/project-context.ts

Provides read/write access to per-project memory through two sub-operations:

  • get_project_context — Retrieves current context for a specified projectId
  • update_project_context — Applies structured updates using projectContextUpdateSchema, supporting operations like upsert on sections such as tags

Both operations route through ProjectContextService, maintaining consistency with the dashboard's state management.

Practical Implementation

All MCP calls follow JSON-RPC 2.0 over HTTP POST to the /mcp endpoint at https://app.openseo.so/mcp.

Request Format

Every request requires:

  • Authorization: Bearer <MCP-TOKEN> header
  • Content-Type: application/json header
  • A JSON body with jsonrpc: "2.0", a unique id, the method name, and a params object

The response always contains three keys:

  • text — Human-readable summary suitable for displaying to end users
  • meta — Optional UI links, including dashboard URLs
  • structuredContent — Machine-parseable data for programmatic consumption

Listing Accessible Projects

Use list_projects to retrieve available project IDs before performing operations:

curl -X POST https://app.openseo.so/mcp \
  -H "Authorization: Bearer <MCP-TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
        "jsonrpc":"2.0",
        "id":"list-001",
        "method":"list_projects",
        "params":{}
      }'

Sample response:

{
  "jsonrpc":"2.0",
  "id":"list-001",
  "result":{
    "text":"Projects (2):\n- proj_123  Acme (acme.com)  market:2704/en",
    "meta":{"url":"https://app.openseo.so/"},
    "structuredContent":{
      "projects":[
        {
          "id":"proj_123",
          "name":"Acme",
          "domain":"acme.com",
          "locationCode":2704,
          "languageCode":"en",
          "url":"https://app.openseo.so/p/proj_123"
        }
      ]
    }
  }
}

Creating a New Project

Invoke create_project with the required schema fields:

curl -X POST https://app.openseo.so/mcp \
  -H "Authorization: Bearer <MCP-TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{
        "jsonrpc":"2.0",
        "id":"create-001",
        "method":"create_project",
        "params":{
          "name":"New Brand",
          "domain":"newbrand.com",
          "locationCode":2704,
          "languageCode":"en"
        }
      }'

The response includes the newly created project's ID and a direct dashboard URL in meta.url, allowing agents to immediately reference the project in the UI.

Managing Project Context

Read the current context state:

{
  "jsonrpc":"2.0",
  "id":"ctx-001",
  "method":"get_project_context",
  "params":{"projectId":"proj_123"}
}

Update the context by applying structured operations:

{
  "jsonrpc":"2.0",
  "id":"ctx-002",
  "method":"update_project_context",
  "params":{
    "projectId":"proj_123",
    "updates":[
      {"section":"tags","operation":"upsert","payload":{"tag":"high-intent"}}
    ]
  }
}

Both calls guarantee consistency with the SAM (Search Agent Manager) interface and dashboard UI because they share the ProjectContextService implementation.

Node.js Integration Example

The following snippet demonstrates production-ready patterns for managing projects using the MCP tools:

import fetch from 'node-fetch';

const MCP_ENDPOINT = 'https://app.openseo.so/mcp';
const TOKEN = process.env.MCP_TOKEN;

async function mcpCall(method, params = {}) {
  const body = {
    jsonrpc: '2.0',
    id: `${method}-${Date.now()}`,
    method,
    params,
  };
  
  const res = await fetch(MCP_ENDPOINT, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${TOKEN}`,
    },
    body: JSON.stringify(body),
  });
  
  const json = await res.json();
  return json.result;
}

// List all accessible projects
const list = await mcpCall('list_projects');
console.log('Projects:', list.structuredContent.projects);

// Create a project if none exist
if (list.structuredContent.projects.length === 0) {
  const created = await mcpCall('create_project', {
    name: 'Demo Project',
    domain: 'demo.com',
    locationCode: 2704,
    languageCode: 'en',
  });
  console.log('Created:', created.structuredContent.project);
}

// Read project context
const ctx = await mcpCall('get_project_context', { projectId: 'proj_123' });
console.log('Context:', ctx.structuredContent);

This implementation references the same source files (src/server/mcp/tools/list-projects.ts, src/server/mcp/tools/create-project.ts, and src/server/mcp/tools/project-context.ts) that power the OpenSEO dashboard, ensuring that changes to server logic propagate immediately to MCP clients.

Summary

  • MCP tools delegate to shared services — list_projects and create_project use src/server/features/projects/services/projects.ts, while context operations use ProjectContextService, ensuring UI and API consistency.
  • JSON-RPC 2.0 over HTTP POST — All interactions use the /mcp endpoint with standard JSON-RPC framing and Bearer token authentication.
  • Three core operations — List existing projects, create new ones using createProjectSchema validation, and read/write project memory via get_project_context and update_project_context.
  • Structured responses — Every tool returns text for humans, meta for UI links (built via src/server/mcp/urls.ts), and structuredContent for programmatic consumption.
  • Stateless architecture — The transport layer (src/server/mcp/transport.ts) handles auth injection, while tools remain stateless and idempotent where possible.

Frequently Asked Questions

How does authentication work for MCP tools in OpenSEO?

The transport layer in src/server/mcp/transport.ts validates the Bearer token from the Authorization header and injects the authenticated user or organization scope into the request context. MCP tokens can be user-scoped (accessing projects across all organizations) or organization-scoped (restricted to a single organization), and this scope determines the visibility of projects in list_projects responses.

What data can be stored in project context?

The project_context tool stores arbitrary structured data defined by projectContextUpdateSchema, commonly including tags, saved keywords, research notes, and campaign configurations. Since ProjectContextService backs both the MCP tools and the SAM dashboard interface, any data written by an AI agent is immediately visible to human users in the UI, and vice versa.

Why do MCP tools return both text and structuredContent?

The dual-response format supports both human-in-the-loop workflows and fully automated pipelines. The text field provides a human-readable summary suitable for displaying in chat interfaces or logs, while structuredContent delivers machine-parseable JSON that clients can process without string parsing. The optional meta field contains dashboard URLs generated by src/server/mcp/urls.ts, allowing agents to link users directly to relevant UI views.

Can I use the same validation schemas as the OpenSEO UI?

Yes. The create_project tool explicitly uses createProjectSchema for input validation, ensuring that MCP-created projects meet the same data quality standards as those created through the dashboard. This shared validation layer prevents malformed entries and maintains database integrity across all entry points.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →