Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
C
clawphone
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lisa
clawphone
Commits
1d2b20ab
Commit
1d2b20ab
authored
Mar 12, 2026
by
Lisa (AI Assistant)
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add self-registration: agent sends own token, capability_prompt and skill_prompt
parent
f196c0da
Pipeline
#274
canceled with stages
Changes
1
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
33 additions
and
12 deletions
+33
-12
mcp_server.py
mcp_server.py
+33
-12
No files found.
mcp_server.py
View file @
1d2b20ab
...
@@ -14,7 +14,8 @@ from pathlib import Path
...
@@ -14,7 +14,8 @@ from pathlib import Path
from
contextlib
import
asynccontextmanager
from
contextlib
import
asynccontextmanager
from
typing
import
Optional
from
typing
import
Optional
from
fastapi
import
FastAPI
,
HTTPException
,
Header
from
fastapi
import
FastAPI
,
HTTPException
,
Header
,
Body
from
fastapi.responses
import
PlainTextResponse
import
uvicorn
import
uvicorn
import
httpx
import
httpx
from
cryptography
import
x509
from
cryptography
import
x509
...
@@ -42,7 +43,7 @@ AGENTS = {}
...
@@ -42,7 +43,7 @@ AGENTS = {}
async
def
init_db
():
async
def
init_db
():
"""Initialize database"""
"""Initialize database"""
async
with
aiosqlite
.
connect
(
DB_PATH
)
as
db
:
async
with
aiosqlite
.
connect
(
DB_PATH
)
as
db
:
# Agents table with
skill
prompts
# Agents table with
large text fields for
prompts
await
db
.
execute
(
"""
await
db
.
execute
(
"""
CREATE TABLE IF NOT EXISTS agents (
CREATE TABLE IF NOT EXISTS agents (
name TEXT PRIMARY KEY,
name TEXT PRIMARY KEY,
...
@@ -216,11 +217,13 @@ app = FastAPI(lifespan=lifespan)
...
@@ -216,11 +217,13 @@ app = FastAPI(lifespan=lifespan)
async
def
list_tools
(
authorization
:
str
=
Header
(
None
)):
async
def
list_tools
(
authorization
:
str
=
Header
(
None
)):
verify_token
(
authorization
)
verify_token
(
authorization
)
return
{
"tools"
:
[
return
{
"tools"
:
[
{
"name"
:
"register
_agent"
,
"description"
:
"Register an agent with its webhook URL and skill prompts
"
,
{
"name"
:
"register
"
,
"description"
:
"Register this agent with the MCP server. Sends own token, hook URL, capability_prompt and skill_prompt
"
,
"inputSchema"
:
{
"type"
:
"object"
,
"properties"
:
{
"inputSchema"
:
{
"type"
:
"object"
,
"properties"
:
{
"name"
:
{},
"hook"
:
{},
"token"
:
{},
"hook"
:
{
"type"
:
"string"
,
"description"
:
"Your webhook URL (https://your-server/hooks/agent)"
},
"capability_prompt"
:
{},
"skill_prompt"
:
{}
"token"
:
{
"type"
:
"string"
,
"description"
:
"Your OpenClaw hook token"
},
},
"required"
:
[
"name"
,
"hook"
]}},
"capability_prompt"
:
{
"type"
:
"string"
,
"description"
:
"Short description of what this agent can do"
},
"skill_prompt"
:
{
"type"
:
"string"
,
"description"
:
"Detailed instructions on how to make requests to this agent (can be large)"
}
},
"required"
:
[
"hook"
,
"token"
]}},
{
"name"
:
"list_hosts"
,
"description"
:
"List all registered agents with their capability prompts"
,
{
"name"
:
"list_hosts"
,
"description"
:
"List all registered agents with their capability prompts"
,
"inputSchema"
:
{
"type"
:
"object"
,
"properties"
:
{}}},
"inputSchema"
:
{
"type"
:
"object"
,
"properties"
:
{}}},
{
"name"
:
"get_host_info"
,
"description"
:
"Get detailed info about a specific agent including skill prompt"
,
{
"name"
:
"get_host_info"
,
"description"
:
"Get detailed info about a specific agent including skill prompt"
,
...
@@ -275,19 +278,37 @@ async def get_host_info(name: str, authorization: str = Header(None)):
...
@@ -275,19 +278,37 @@ async def get_host_info(name: str, authorization: str = Header(None)):
}
}
@
app
.
post
(
"/tools/register_agent"
)
@
app
.
post
(
"/tools/register"
)
async
def
tool_register_agent
(
data
:
dict
,
authorization
:
str
=
Header
(
None
)):
async
def
tool_register
(
data
:
dict
=
Body
(
...
),
authorization
:
str
=
Header
(
None
)):
"""Register an agent with its webhook URL and skill prompts"""
"""
Agent self-registration. The agent sends:
- hook: its webhook URL
- token: its own hook token for callbacks
- capability_prompt: short description of capabilities
- skill_prompt: detailed instructions (can be large)
"""
verify_token
(
authorization
)
verify_token
(
authorization
)
name
=
data
.
get
(
"name"
)
hook
=
data
.
get
(
"hook"
)
hook
=
data
.
get
(
"hook"
)
token
=
data
.
get
(
"token"
,
""
)
token
=
data
.
get
(
"token"
,
""
)
capability_prompt
=
data
.
get
(
"capability_prompt"
,
""
)
capability_prompt
=
data
.
get
(
"capability_prompt"
,
""
)
skill_prompt
=
data
.
get
(
"skill_prompt"
,
""
)
skill_prompt
=
data
.
get
(
"skill_prompt"
,
""
)
if
not
name
or
not
hook
:
if
not
hook
:
return
{
"success"
:
False
,
"error"
:
"name and hook are required"
}
return
{
"success"
:
False
,
"error"
:
"hook URL is required"
}
# Extract agent name from hook URL path or use a default
# The agent identifies itself - we'll use the hook URL's hostname as name if not provided
# Or we can require a "name" field
name
=
data
.
get
(
"name"
)
if
not
name
:
# Try to extract from hook URL
import
urllib.parse
try
:
parsed
=
urllib
.
parse
.
urlparse
(
hook
)
name
=
parsed
.
netloc
.
split
(
'.'
)[
0
]
# e.g., "lisa" from "lisa.nexlab.net"
except
:
name
=
"unknown"
# Ensure HTTPS
# Ensure HTTPS
if
not
hook
.
startswith
(
"https://"
):
if
not
hook
.
startswith
(
"https://"
):
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment