MCP server

Connect Claude Code and other MCP clients to Fishcamp. Endpoint, setup, and every tool with its arguments and an example.

Updated

New in November 2026

Fishcamp has a built-in Model Context Protocol server. Connect an AI agent such as Claude Code and it can read channels, search messages, check audio rooms and transcripts, and post, all inside your workspace and under the name of an API key.

  • Endpoint: https://api.fishcamp.space/api/mcp
  • Transport: Streamable HTTP, stateless: every request stands alone.
  • Authentication: Authorization: Bearer cwk_… on every request.

Set it up

1. Create an API key

An admin creates the key in Settings → API keys: read lets the agent look around, write also lets it post messages and create channels. The MCP server needs read: a key with only write gets 403. An AI agent's key works too. See API keys.

2. Connect Claude Code

claude mcp add --transport http fishcamp https://api.fishcamp.space/api/mcp --header "Authorization: Bearer cwk_YOUR_KEY"
  • Add --scope user to use Fishcamp in all your projects, not only the current one.
  • In Claude Code, run /mcp to check that fishcamp is connected.
  • To disconnect, run claude mcp remove fishcamp (and revoke the key if you won't use it again).

Other MCP clients

Clients that support remote servers take an entry like this one. The file and the top-level key depend on the client: .mcp.json (Claude Code) and mcp.json (Cursor) use mcpServers; .vscode/mcp.json (VS Code) uses servers.

{
  "mcpServers": {
    "fishcamp": {
      "type": "http",
      "url": "https://api.fishcamp.space/api/mcp",
      "headers": { "Authorization": "Bearer cwk_YOUR_KEY" }
    }
  }
}

For clients that only start local (stdio) servers, such as Claude Desktop, bridge with mcp-remote:

{
  "mcpServers": {
    "fishcamp": {
      "command": "npx",
      "args": ["-y", "mcp-remote", "https://api.fishcamp.space/api/mcp", "--header", "Authorization:${FISHCAMP_AUTH}"],
      "env": { "FISHCAMP_AUTH": "Bearer cwk_YOUR_KEY" }
    }
  }
}

Chat apps whose connectors only sign in with OAuth, such as ChatGPT, can't use API keys.

Things to ask

Who's in the audio room in #platform right now?
Read the last 30 messages in #design-crit and list the open questions with who asked them.
Search for "rate limit" in #incidents and summarize what we decided.
Read yesterday's transcript from #planning and draft the follow-up message, but don't post it.
Create a channel called release-2-5 and post the checklist from RELEASE.md there.

Messages the agent posts appear under the key's name with an AI label.

Tools

ToolWhat it doesScope
whoamiShows the key's name and scopes, the workspace and who the key acts forread
list_channelsLists the channels the key can seeread
read_messagesReads a channel's messagesread
search_messagesSearches messagesread
post_messagePosts a messagewrite
create_channelCreates a channelwrite
list_membersLists the people in the workspaceread
get_audio_roomShows who's in a channel's audio roomread
list_transcriptsLists transcriptsread
read_transcriptReads one transcriptread

Where a tool takes a channel, pass the channel's ID or its name, for example design-crit.

With an AI agent's key, the tools only see the agent's channels: list_channels, search_messages and list_transcripts leave the others out, and any other channel answers "not found". list_members still lists everyone in the workspace.

whoami

Returns the workspace the key belongs to, the person it acts for (the admin who created it) and the key's name and scopes. Call it first to check the connection. No arguments.

{}

list_channels

Lists the channels the key can see, with their IDs, names and descriptions. No arguments.

{}

read_messages

Reads the latest messages of a channel. To go further back, pass the cursor from the previous result as before.

ArgumentTypeRequiredDescription
channelstringYesChannel ID or name.
limitintegerNoHow many messages, from 1 to 100.
beforestringNoCursor from a previous call, to read older messages.
{ "channel": "design-crit", "limit": 20 }

search_messages

Searches message text in the channels the key can see.

ArgumentTypeRequiredDescription
querystringYesWords to look for.
channelstringNoOnly search this channel (ID or name).
limitintegerNoMaximum number of results.
{ "query": "rate limit", "channel": "incidents", "limit": 10 }

post_message

Posts a message to a channel, under the key's name with an AI label. Needs write.

ArgumentTypeRequiredDescription
channelstringYesChannel ID or name.
textstringYesThe message, up to 4,000 characters.
{ "channel": "general", "text": "Release 2.5 is out. Notes: https://example.com/releases/2.5" }

create_channel

Creates a channel. Names follow the same rules as in the app: lowercase, hyphens instead of spaces, other punctuation dropped, up to 60 characters, unique among active channels. Needs write.

ArgumentTypeRequiredDescription
namestringYesChannel name.
descriptionstringNoWhat the channel is for, up to 250 characters.
privatebooleanNotrue creates a private channel. Default: public.
{ "name": "release-2-5", "description": "Checklist and status for release 2.5", "private": false }

list_members

Lists the people in the workspace with their names, emails and roles. No arguments.

{}

get_audio_room

Shows whether the channel's audio room is open, since when, who's in it and who's sharing a screen.

ArgumentTypeRequiredDescription
channelstringYesChannel ID or name.
{ "channel": "platform" }

list_transcripts

Lists recent transcripts, with when the call happened and what was decided for it.

ArgumentTypeRequiredDescription
channelstringNoOnly transcripts from this channel (ID or name).
limitintegerNoMaximum number of transcripts.
{ "channel": "planning", "limit": 5 }

read_transcript

Reads one transcript: every line with its speaker, and the routing decision (discard, save to OpenSync or send to agents).

ArgumentTypeRequiredDescription
idstringYesTranscript ID, from list_transcripts.
{ "id": "3f2d9c1e-5b7a-4c2e-9a0b-6d8e1f4a2c7b" }

Call it without a client

The server speaks JSON-RPC over HTTP, so you can test it with curl. List the tools:

curl -sS https://api.fishcamp.space/api/mcp \
  -H "Authorization: Bearer cwk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

Call one:

curl -sS https://api.fishcamp.space/api/mcp \
  -H "Authorization: Bearer cwk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"read_messages","arguments":{"channel":"general","limit":5}}}'

The answer is a JSON-RPC message; depending on the server's choice it arrives as plain JSON or as a server-sent event (a data: {…} line).

Troubleshooting

SymptomFix
401 or "unauthorized"The key is missing, mistyped or revoked. Check the header is exactly Authorization: Bearer cwk_….
A write tool failsThe key only has read. Create a key with write.
403 on every requestThe key has no read scope. Create a key with read.
"not found" for a channelCheck the name or ID with list_channels. Private channels the key can't see look like they don't exist, and an agent's key only sees the agent's channels.
Claude Code doesn't list fishcampRun claude mcp list. If you added it with the default scope, it only exists in the project where you ran the command.

On this page