> ## Documentation Index
> Fetch the complete documentation index at: https://developers.semji.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Toolsets & scopes

> Scope the Semji MCP server to specific toolsets and an optional read-only mode using the connection URL.

The Semji MCP server exposes a growing catalogue of tools. You can scope a
connection to just the toolsets you need — and optionally make it read-only —
directly from the server URL. This keeps the assistant's tool list focused and
lets you hand out narrower connections for governance.

The scope lives in the URL, so it is read on every request. To change scope,
update the connector URL and reconnect (see [Connect to Semji](/mcp/connecting)).
You can also register several connectors, each with a different scope.

## Build your URL

export const McpUrlBuilder = () => {
  const TOOLSETS = [{
    name: "planning",
    label: "Planning",
    desc: "Drafts, folders, keywords"
  }, {
    name: "content",
    label: "Content Hub",
    desc: "Pages & performance"
  }, {
    name: "geo",
    label: "Intelligence Hub GEO",
    desc: "Prompts, prompt responses & sources"
  }, {
    name: "seo",
    label: "Intelligence Hub SEO",
    desc: "Pages Data Explorer"
  }, {
    name: "ideas",
    label: "Content Ideas",
    desc: "Search & results"
  }, {
    name: "brand-voice",
    label: "Brand Voices",
    desc: "Tone & style"
  }, {
    name: "editor",
    label: "Editor",
    desc: "Comments"
  }, {
    name: "agents",
    label: "Agents",
    desc: "Runs & outputs"
  }, {
    name: "settings",
    label: "Settings",
    desc: "Users, roles & statuses"
  }, {
    name: "knowledge",
    label: "Knowledge Base",
    desc: "Entries & content"
  }];
  const [selected, setSelected] = useState({
    planning: true
  });
  const [readOnly, setReadOnly] = useState(false);
  const [open, setOpen] = useState(false);
  const [copied, setCopied] = useState(false);
  const chosen = TOOLSETS.filter(t => selected[t.name]);
  const chosenNames = chosen.map(t => t.name);
  const isDefault = chosenNames.length === 1 && chosenNames[0] === "planning";
  const params = [];
  if (chosenNames.length > 0 && !isDefault) params.push("toolsets=" + chosenNames.join(","));
  if (readOnly) params.push("read_only=true");
  const url = "https://mcp.semji.com/mcp" + (params.length ? "?" + params.join("&") : "");
  const toggle = name => setSelected(s => ({
    ...s,
    [name]: !s[name]
  }));
  const copy = () => {
    navigator.clipboard.writeText(url);
    setCopied(true);
    setTimeout(() => setCopied(false), 1500);
  };
  return <div className="mcpb">
      <div className="mcpb-row">
        <div style={{
    flex: "0 0 auto"
  }}>
          <div className="mcpb-label">Read-only</div>
          <button className="mcpb-toggle" role="switch" aria-checked={readOnly} aria-label="Read-only" onClick={() => setReadOnly(v => !v)}>
            <span className="mcpb-knob" />
          </button>
        </div>

        <div className="mcpb-toolsets">
          <div className="mcpb-label">Toolsets</div>
          <button className="mcpb-control" aria-haspopup="listbox" aria-expanded={open} onClick={() => setOpen(o => !o)}>
            <span className="mcpb-chips">
              {chosen.length === 0 ? <span className="mcpb-placeholder">planning (default)</span> : chosen.map(t => <span key={t.name} className="mcpb-chip">
                    {t.label}
                    <span className="mcpb-chip-x" role="button" aria-label={"Remove " + t.label} onClick={e => {
    e.stopPropagation();
    toggle(t.name);
  }}>
                      ×
                    </span>
                  </span>)}
            </span>
            <svg className="mcpb-caret" width="14" height="14" viewBox="0 0 256 256">
              <path d="M80 176l48 48 48-48M80 80l48-48 48 48" fill="none" stroke="currentColor" strokeWidth="20" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          </button>

          {open && <>
              <div className="mcpb-backdrop" onClick={() => setOpen(false)} />
              <div className="mcpb-pop" role="listbox">
                {TOOLSETS.map(t => <label key={t.name} className="mcpb-opt" data-selected={selected[t.name] ? "true" : "false"}>
                    <span className="mcpb-opt-title">
                      <input type="checkbox" checked={!!selected[t.name]} onChange={() => toggle(t.name)} />
                      <strong>{t.label}</strong>
                    </span>
                    <span className="mcpb-opt-desc">{t.desc}</span>
                  </label>)}
              </div>
            </>}
        </div>
      </div>

      <div className="mcpb-block">
        <div className="mcpb-label">Server URL</div>
        <div className="mcpb-urlrow">
          <input className="mcpb-input" readOnly value={url} />
          <button className="mcpb-copy" onClick={copy}>
            {copied ? "Copied" : "Copy"}
          </button>
        </div>
        {chosen.length === 0 && <p className="mcpb-note">
            No toolset selected — the URL defaults to the <code>planning</code> toolset.
          </p>}
      </div>
    </div>;
};

<McpUrlBuilder />

## Query parameters

| Param       | Values                                                                                                                    | Default    | Behaviour                                                                                                                                            |
| ----------- | ------------------------------------------------------------------------------------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `toolsets`  | CSV of `planning`, `content`, `geo`, `seo`, `ideas`, `brand-voice`, `editor`, `agents`, `settings`, `knowledge`, or `all` | `planning` | Only the tools of the listed toolsets appear in the tool list and are callable. Unknown names are ignored; an empty result falls back to `planning`. |
| `read_only` | `true` / `false`                                                                                                          | `false`    | When `true`, every write tool is removed and refused. Orthogonal to `toolsets`. Any value other than `true` means `false`.                           |

The URL can only restrict access — it never grants more than your Semji account
already allows. Identity, organization, and permissions come from sign-in, not
from the URL.

## Examples

```text Default (planning only) theme={null}
https://mcp.semji.com/mcp
```

```text GEO + SEO analytics theme={null}
https://mcp.semji.com/mcp?toolsets=geo,seo
```

```text Everything, read-only theme={null}
https://mcp.semji.com/mcp?toolsets=all&read_only=true
```

<Note>
  Changing scope means updating the connector URL and reconnecting. Connections
  do not re-prompt on their own. You can keep several connectors side by side,
  each scoped differently.
</Note>

Use the URL above wherever [Connect to Semji](/mcp/connecting) tells you to paste
`https://mcp.semji.com/mcp` — for example in Claude Code:

```bash theme={null}
claude mcp add --transport http semji "https://mcp.semji.com/mcp?toolsets=geo,seo"
```
